diff options
Diffstat (limited to 'src/client/View/LoggedIn')
-rw-r--r-- | src/client/View/LoggedIn/Add.elm | 105 | ||||
-rw-r--r-- | src/client/View/LoggedIn/ExceedingPayer.elm | 35 | ||||
-rw-r--r-- | src/client/View/LoggedIn/Monthly.elm | 72 | ||||
-rw-r--r-- | src/client/View/LoggedIn/Paging.elm | 97 | ||||
-rw-r--r-- | src/client/View/LoggedIn/Table.elm | 86 |
5 files changed, 395 insertions, 0 deletions
diff --git a/src/client/View/LoggedIn/Add.elm b/src/client/View/LoggedIn/Add.elm new file mode 100644 index 0000000..acdda2d --- /dev/null +++ b/src/client/View/LoggedIn/Add.elm @@ -0,0 +1,105 @@ +module View.LoggedIn.Add + ( addPayment + ) where + +import Html as H exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) +import Reads exposing (readInt) +import Result exposing (..) + +import ServerCommunication as SC exposing (serverCommunications) + +import Update exposing (..) +import Update.LoggedIn exposing (..) +import Update.LoggedIn.Add exposing (..) + +import Model exposing (Model) +import Model.View.LoggedIn.Add exposing (..) +import Model.Translations exposing (getMessage) +import Model.View.LoggedInView exposing (LoggedInView) + +import View.Events exposing (onSubmitPrevDefault) +import View.Icon exposing (renderIcon) + +import Utils.Maybe exposing (isJust) +import Utils.Either exposing (toMaybeError) + +addPayment : Model -> LoggedInView -> Html +addPayment model loggedInView = + H.form + [ case (validateName loggedInView.add.name model.translations, validateCost loggedInView.add.cost model.translations) of + (Ok name, Ok cost) -> + let action = + case loggedInView.add.frequency of + Punctual -> SC.AddPayment loggedInView.me name cost + Monthly -> SC.AddMonthlyPayment name cost + in onSubmitPrevDefault serverCommunications.address action + (resName, resCost) -> + onSubmitPrevDefault actions.address (UpdateLoggedIn <| UpdateAdd <| AddError (toMaybeError resName) (toMaybeError resCost)) + ] + [ addPaymentName loggedInView.add + , addPaymentCost model loggedInView.add + , paymentFrequency model loggedInView.add + , button + [ type' "submit" + , class "add" ] + [ text (getMessage "Add" model.translations)] + ] + +addPaymentName : AddPayment -> Html +addPaymentName addPayment = + div + [ class ("name " ++ (if isJust addPayment.nameError then "error" else "")) ] + [ input + [ id "nameInput" + , value addPayment.name + , on "input" targetValue (Signal.message actions.address << UpdateLoggedIn << UpdateAdd << UpdateName) + , maxlength 20 + ] + [] + , label + [ for "nameInput" ] + [ renderIcon "shopping-cart" ] + , case addPayment.nameError of + Just error -> + div [ class "errorMessage" ] [ text error ] + Nothing -> + text "" + ] + +addPaymentCost : Model -> AddPayment -> Html +addPaymentCost model addPayment = + div + [ class ("cost " ++ (if isJust addPayment.costError then "error" else "")) ] + [ input + [ id "costInput" + , value addPayment.cost + , on "input" targetValue (Signal.message actions.address << UpdateLoggedIn << UpdateAdd << UpdateCost) + , maxlength 7 + ] + [] + , label + [ for "costInput" ] + [ text (getMessage "MoneySymbol" model.translations) ] + , case addPayment.costError of + Just error -> + div [ class "errorMessage" ] [ text error ] + Nothing -> + text "" + ] + +paymentFrequency : Model -> AddPayment -> Html +paymentFrequency model addPayment = + button + [ type' "button" + , class "frequency" + , onClick actions.address (UpdateLoggedIn << UpdateAdd <| ToggleFrequency) + ] + [ div + [ class ("punctual" ++ if addPayment.frequency == Punctual then " selected" else "") ] + [ text (getMessage "Punctual" model.translations) ] + , div + [ class ("monthly" ++ if addPayment.frequency == Monthly then " selected" else "") ] + [ text (getMessage "Monthly" model.translations) ] + ] diff --git a/src/client/View/LoggedIn/ExceedingPayer.elm b/src/client/View/LoggedIn/ExceedingPayer.elm new file mode 100644 index 0000000..ea848b6 --- /dev/null +++ b/src/client/View/LoggedIn/ExceedingPayer.elm @@ -0,0 +1,35 @@ +module View.LoggedIn.ExceedingPayer + ( exceedingPayers + ) where + +import Html exposing (..) +import Html.Attributes exposing (..) +import List + +import Model exposing (Model) +import Model.User exposing (getUserName) +import Model.Payers exposing (..) +import Model.View.LoggedInView exposing (LoggedInView) +import Model.Translations exposing (getMessage) + +exceedingPayers : Model -> LoggedInView -> Html +exceedingPayers model loggedInView = + div + [ class "exceedingPayers" ] + (List.map (exceedingPayer model loggedInView) (getOrderedExceedingPayers loggedInView.payers)) + +exceedingPayer : Model -> LoggedInView -> ExceedingPayer -> Html +exceedingPayer model loggedInView payer = + div + [ class "exceedingPayer" ] + [ span + [ class "userName" ] + [ payer.userId + |> getUserName loggedInView.users + |> Maybe.withDefault "−" + |> text + ] + , span + [ class "amount" ] + [ text ("+ " ++ (toString payer.amount) ++ " " ++ (getMessage "MoneySymbol" model.translations)) ] + ] diff --git a/src/client/View/LoggedIn/Monthly.elm b/src/client/View/LoggedIn/Monthly.elm new file mode 100644 index 0000000..14c3de7 --- /dev/null +++ b/src/client/View/LoggedIn/Monthly.elm @@ -0,0 +1,72 @@ +module View.LoggedIn.Monthly + ( monthlyPayments + ) where + +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) + +import Update exposing (..) +import Update.LoggedIn exposing (..) +import Update.LoggedIn.Monthly exposing (..) + +import Model exposing (Model) +import Model.View.LoggedIn.Monthly exposing (Monthly) +import Model.Payment exposing (Payments, Payment) +import Model.View.LoggedInView exposing (LoggedInView) +import Model.Translations exposing (getMessage, getParamMessage) + +import ServerCommunication as SC exposing (serverCommunications) + +import View.Icon exposing (renderIcon) + +monthlyPayments : Model -> LoggedInView -> Html +monthlyPayments model loggedInView = + let monthly = loggedInView.monthly + in if List.isEmpty monthly.payments + then + text "" + else + div + [ class ("monthlyPayments" ++ if monthly.visibleDetail then " detail" else "") ] + [ monthlyCount model monthly + , if monthly.visibleDetail then paymentsTable model loggedInView monthly else text "" + ] + +monthlyCount : Model -> Monthly -> Html +monthlyCount model monthly = + let count = List.length monthly.payments + key = if count > 1 then "PluralMonthlyCount" else "SingularMonthlyCount" + in button + [ class "count" + , onClick actions.address (UpdateLoggedIn << UpdateMonthly <| ToggleDetail) + ] + [ text (getParamMessage [toString count] key model.translations) + , div + [ class "expand" ] + [ if monthly.visibleDetail + then renderIcon "chevron-up" + else renderIcon "chevron-down" + ] + ] + +paymentsTable : Model -> LoggedInView -> Monthly -> Html +paymentsTable model loggedInView monthly = + div + [ class "table" ] + ( List.map (paymentLine model loggedInView) monthly.payments ) + +paymentLine : Model -> LoggedInView -> Payment -> Html +paymentLine model loggedInView payment = + a + [ class ("row" ++ (if loggedInView.paymentEdition == Just payment.id then " edition" else "")) + , onClick actions.address (UpdateLoggedIn (ToggleEdit payment.id)) + ] + [ div [ class "cell" ] [ text (payment.name) ] + , div [ class "cell" ] [ text (toString payment.cost ++ " " ++ getMessage "MoneySymbol" model.translations) ] + , div + [ class "cell delete" + , onClick serverCommunications.address (SC.DeleteMonthlyPayment payment.id) + ] + [ renderIcon "times" ] + ] diff --git a/src/client/View/LoggedIn/Paging.elm b/src/client/View/LoggedIn/Paging.elm new file mode 100644 index 0000000..5d5f2db --- /dev/null +++ b/src/client/View/LoggedIn/Paging.elm @@ -0,0 +1,97 @@ +module View.LoggedIn.Paging + ( paymentsPaging + ) where + +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) + +import Model.View.LoggedInView exposing (..) +import Model.Payment exposing (perPage) + +import ServerCommunication as SC exposing (serverCommunications) + +import Update exposing (..) +import Update.LoggedIn exposing (..) + +import View.Icon exposing (renderIcon) + +showedPages : Int +showedPages = 5 + +paymentsPaging : LoggedInView -> Html +paymentsPaging loggedInView = + let maxPage = ceiling (toFloat loggedInView.paymentsCount / toFloat perPage) + pages = truncatePages loggedInView.currentPage [1..maxPage] + in if maxPage == 1 + then + text "" + else + div + [ class "pages" ] + ( ( if loggedInView.currentPage > 1 + then [ firstPage, previousPage loggedInView ] + else [] + ) + ++ ( List.map (paymentsPage loggedInView) pages) + ++ ( if loggedInView.currentPage < maxPage + then [ nextPage loggedInView, lastPage maxPage ] + else [] + ) + ) + +truncatePages : Int -> List Int -> List Int +truncatePages currentPage pages = + let totalPages = List.length pages + showedLeftPages = ceiling ((toFloat showedPages - 1) / 2) + showedRightPages = floor ((toFloat showedPages - 1) / 2) + truncatedPages = + if | currentPage < showedLeftPages -> + [1..showedPages] + | currentPage > totalPages - showedRightPages -> + [(totalPages - showedPages)..totalPages] + | otherwise -> + [(currentPage - showedLeftPages)..(currentPage + showedRightPages)] + in List.filter (flip List.member pages) truncatedPages + +firstPage : Html +firstPage = + button + [ class "page" + , onClick serverCommunications.address (SC.UpdatePage 1) + ] + [ renderIcon "fast-backward" ] + +previousPage : LoggedInView -> Html +previousPage loggedInView = + button + [ class "page" + , onClick serverCommunications.address (SC.UpdatePage (loggedInView.currentPage - 1)) + ] + [ renderIcon "backward" ] + +nextPage : LoggedInView -> Html +nextPage loggedInView = + button + [ class "page" + , onClick serverCommunications.address (SC.UpdatePage (loggedInView.currentPage + 1)) + ] + [ renderIcon "forward" ] + +lastPage : Int -> Html +lastPage maxPage = + button + [ class "page" + , onClick serverCommunications.address (SC.UpdatePage maxPage) + ] + [ renderIcon "fast-forward" ] + +paymentsPage : LoggedInView -> Int -> Html +paymentsPage loggedInView page = + let onCurrentPage = page == loggedInView.currentPage + in button + [ class ("page" ++ (if onCurrentPage then " current" else "")) + , onClick serverCommunications.address <| + if onCurrentPage then SC.NoCommunication else SC.UpdatePage page + ] + [ text (toString page) ] diff --git a/src/client/View/LoggedIn/Table.elm b/src/client/View/LoggedIn/Table.elm new file mode 100644 index 0000000..6342369 --- /dev/null +++ b/src/client/View/LoggedIn/Table.elm @@ -0,0 +1,86 @@ +module View.LoggedIn.Table + ( paymentsTable + ) where + +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) +import Dict exposing (..) + +import Date +import Date exposing (Date) + +import String exposing (append) + +import Model exposing (Model) +import Model.User exposing (getUserName) +import Model.Payment exposing (..) +import Model.View.LoggedInView exposing (LoggedInView) +import Model.Translations exposing (getMessage) + +import ServerCommunication as SC exposing (serverCommunications) + +import Update exposing (..) +import Update.LoggedIn exposing (..) + +import View.Icon exposing (renderIcon) +import View.Date exposing (..) + +paymentsTable : Model -> LoggedInView -> Html +paymentsTable model loggedInView = + div + [ class "table" ] + ( headerLine model :: paymentLines model loggedInView) + +headerLine : Model -> Html +headerLine model = + div + [ class "header" ] + [ div [ class "cell category" ] [ renderIcon "shopping-cart" ] + , div [ class "cell cost" ] [ text (getMessage "MoneySymbol" model.translations) ] + , div [ class "cell user" ] [ renderIcon "user" ] + , div [ class "cell date" ] [ renderIcon "calendar" ] + , div [ class "cell" ] [] + ] + +paymentLines : Model -> LoggedInView -> List Html +paymentLines model loggedInView = + loggedInView.payments + |> List.sortBy (Date.toTime << .creation) + |> List.reverse + |> List.map (paymentLine model loggedInView) + +paymentLine : Model -> LoggedInView -> Payment -> Html +paymentLine model loggedInView payment = + a + [ class ("row" ++ (if loggedInView.paymentEdition == Just payment.id then " edition" else "")) + , onClick actions.address (UpdateLoggedIn (ToggleEdit payment.id)) + ] + [ div [ class "cell category" ] [ text payment.name ] + , div [ class "cell cost" ] [ text ((toString payment.cost) ++ " " ++ (getMessage "MoneySymbol" model.translations)) ] + , div + [ class "cell user" ] + [ payment.userId + |> getUserName loggedInView.users + |> Maybe.withDefault "−" + |> text + ] + , div + [ class "cell date" ] + [ span + [ class "shortDate" ] + [ text (renderShortDate payment.creation model.translations) ] + , span + [ class "longDate" ] + [ text (renderLongDate payment.creation model.translations) ] + ] + , if loggedInView.me == payment.userId + then + div + [ class "cell delete" + , onClick serverCommunications.address (SC.DeletePayment payment.id payment.userId payment.cost loggedInView.currentPage) + ] + [ renderIcon "times" ] + else + div [ class "cell" ] [] + ] |