From 7c050fe2d2c3e8f190e019e1613d37b9d8ef22b9 Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 27 Mar 2016 20:41:59 +0200 Subject: Regroup account modules --- src/client/elm/LoggedIn/Account/Action.elm | 17 ++++ src/client/elm/LoggedIn/Account/Model.elm | 64 ++++++++++++ src/client/elm/LoggedIn/Account/Update.elm | 75 ++++++++++++++ src/client/elm/LoggedIn/Account/View.elm | 131 +++++++++++++++++++++++++ src/client/elm/LoggedIn/Action.elm | 5 +- src/client/elm/LoggedIn/Model.elm | 7 +- src/client/elm/LoggedIn/Update.elm | 7 +- src/client/elm/LoggedIn/View.elm | 5 +- src/client/elm/Model/Action/AccountAction.elm | 17 ---- src/client/elm/Model/View/LoggedIn/Account.elm | 64 ------------ src/client/elm/Update/LoggedIn/Account.elm | 75 -------------- src/client/elm/View/LoggedIn/Account.elm | 131 ------------------------- 12 files changed, 301 insertions(+), 297 deletions(-) create mode 100644 src/client/elm/LoggedIn/Account/Action.elm create mode 100644 src/client/elm/LoggedIn/Account/Model.elm create mode 100644 src/client/elm/LoggedIn/Account/Update.elm create mode 100644 src/client/elm/LoggedIn/Account/View.elm delete mode 100644 src/client/elm/Model/Action/AccountAction.elm delete mode 100644 src/client/elm/Model/View/LoggedIn/Account.elm delete mode 100644 src/client/elm/Update/LoggedIn/Account.elm delete mode 100644 src/client/elm/View/LoggedIn/Account.elm diff --git a/src/client/elm/LoggedIn/Account/Action.elm b/src/client/elm/LoggedIn/Account/Action.elm new file mode 100644 index 0000000..66ccfaa --- /dev/null +++ b/src/client/elm/LoggedIn/Account/Action.elm @@ -0,0 +1,17 @@ +module LoggedIn.Account.Action + ( Action(..) + ) where + +import Time exposing (Time) + +import Model.User exposing (UserId) +import Model.Income exposing (IncomeId) + +type Action = + NoOp + | ToggleDetail + | ToggleIncomeEdition + | UpdateIncomeEdition String + | UpdateEditionError String + | UpdateIncome Time Int + | ValidateUpdateIncome IncomeId Time Int diff --git a/src/client/elm/LoggedIn/Account/Model.elm b/src/client/elm/LoggedIn/Account/Model.elm new file mode 100644 index 0000000..2d0c4a3 --- /dev/null +++ b/src/client/elm/LoggedIn/Account/Model.elm @@ -0,0 +1,64 @@ +module LoggedIn.Account.Model + ( Model + , IncomeEdition + , init + , initIncomeEdition + , getCurrentIncome + , validateIncome + ) where + +import Result as Result exposing (Result(..)) +import Dict +import String + +import Utils.Dict exposing (mapValues) + +import Model.Translations exposing (..) +import Model.Income exposing (..) +import Model.User exposing (UserId) + +type alias Model = + { me : UserId + , incomes : Incomes + , visibleDetail : Bool + , incomeEdition : Maybe IncomeEdition + } + +init : UserId -> Incomes -> Model +init me incomes = + { me = me + , incomes = incomes + , visibleDetail = False + , incomeEdition = Nothing + } + +getCurrentIncome : Model -> Maybe Int +getCurrentIncome account = + account.incomes + |> Dict.filter (\_ income -> income.userId == account.me) + |> Dict.values + |> List.sortBy .creation + |> List.reverse + |> List.head + |> Maybe.map .amount + +type alias IncomeEdition = + { income : String + , error : Maybe String + } + +initIncomeEdition : Int -> IncomeEdition +initIncomeEdition income = + { income = toString income + , error = Nothing + } + +validateIncome : String -> Translations -> Result String Int +validateIncome amount translations = + case String.toInt amount of + Ok number -> + if number > 0 + then Ok number + else Err <| getMessage "IncomeMustBePositiveNumber" translations + Err _ -> + Err <| getMessage "IncomeRequired" translations diff --git a/src/client/elm/LoggedIn/Account/Update.elm b/src/client/elm/LoggedIn/Account/Update.elm new file mode 100644 index 0000000..a3d9745 --- /dev/null +++ b/src/client/elm/LoggedIn/Account/Update.elm @@ -0,0 +1,75 @@ +module LoggedIn.Account.Update + ( update + ) where + +import Maybe +import Dict +import Task + +import Effects exposing (Effects) + +import Server + +import LoggedIn.Account.Action as AccountAction +import LoggedIn.Account.Model as AccountModel + +import Utils.Maybe exposing (isJust) + +update : AccountAction.Action -> AccountModel.Model -> (AccountModel.Model, Effects AccountAction.Action) +update action account = + case action of + + AccountAction.NoOp -> + (account, Effects.none) + + AccountAction.ToggleDetail -> + ( { account | visibleDetail = not account.visibleDetail } + , Effects.none + ) + + AccountAction.ToggleIncomeEdition -> + ( { account | incomeEdition = + if isJust account.incomeEdition + then Nothing + else Just (AccountModel.initIncomeEdition (Maybe.withDefault 0 (AccountModel.getCurrentIncome account))) + } + , Effects.none + ) + + AccountAction.UpdateIncomeEdition income -> + case account.incomeEdition of + Just incomeEdition -> + ( { account | incomeEdition = Just { incomeEdition | income = income } } + , Effects.none + ) + Nothing -> + ( account + , Effects.none + ) + + AccountAction.UpdateEditionError error -> + case account.incomeEdition of + Just incomeEdition -> + ( { account | incomeEdition = Just { incomeEdition | error = Just error } } + , Effects.none + ) + Nothing -> + ( account + , Effects.none + ) + + AccountAction.UpdateIncome currentTime amount -> + ( account + , Server.setIncome currentTime amount + |> Task.map (\incomeId -> (AccountAction.ValidateUpdateIncome incomeId currentTime amount)) + |> flip Task.onError (always <| Task.succeed AccountAction.NoOp) + |> Effects.task + ) + + AccountAction.ValidateUpdateIncome incomeId currentTime amount -> + ( { account + | incomes = Dict.insert incomeId { userId = account.me, creation = currentTime, amount = amount } account.incomes + , incomeEdition = Nothing + } + , Effects.none + ) diff --git a/src/client/elm/LoggedIn/Account/View.elm b/src/client/elm/LoggedIn/Account/View.elm new file mode 100644 index 0000000..deee627 --- /dev/null +++ b/src/client/elm/LoggedIn/Account/View.elm @@ -0,0 +1,131 @@ +module LoggedIn.Account.View + ( view + ) where + +import List +import Signal exposing (Address) + +import Html exposing (..) +import Html as H exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) + +import LoggedIn.Action as LoggedInAction +import LoggedIn.Model as LoggedInModel + +import LoggedIn.Account.Action as AccountAction +import LoggedIn.Account.Model as AccountModel + +import Model exposing (Model) +import Model.User exposing (getUserName) +import Model.Payer exposing (..) +import Model.Translations exposing (getParamMessage, getMessage) +import Model.Action exposing (..) + +import View.Expand exposing (..) +import View.Price exposing (price) +import View.Events exposing (onSubmitPrevDefault) + +import Utils.Either exposing (toMaybeError) + +view : Address Action -> Model -> LoggedInModel.Model -> Html +view address model loggedInModel = + let account = loggedInModel.account + in div + [ classList + [ ("account", True) + , ("detail", account.visibleDetail) + ] + ] + [ exceedingPayers address model loggedInModel + , if account.visibleDetail + then income address model account + else text "" + ] + +exceedingPayers : Address Action -> Model -> LoggedInModel.Model -> Html +exceedingPayers address model loggedInModel = + button + [ class "header" + , onClick address (UpdateLoggedIn << LoggedInAction.UpdateAccount <| AccountAction.ToggleDetail) + ] + ( (List.map (exceedingPayer model loggedInModel) (getOrderedExceedingPayers model.currentTime loggedInModel.users loggedInModel.account.incomes loggedInModel.payments)) + ++ [ expand ExpandDown loggedInModel.account.visibleDetail ] + ) + +exceedingPayer : Model -> LoggedInModel.Model -> ExceedingPayer -> Html +exceedingPayer model loggedInModel payer = + div + [ class "exceedingPayer" ] + [ span + [ class "userName" ] + [ payer.userId + |> getUserName loggedInModel.users + |> Maybe.withDefault "−" + |> text + ] + , span + [ class "amount" ] + [ text ("+ " ++ (price model payer.amount)) ] + ] + +income : Address Action -> Model -> AccountModel.Model -> Html +income address model account = + case account.incomeEdition of + Nothing -> + incomeRead address model account + Just edition -> + incomeEdition address model account edition + +incomeRead : Address Action -> Model -> AccountModel.Model -> Html +incomeRead address model account = + div + [ class "income" ] + [ ( case AccountModel.getCurrentIncome account of + Nothing -> + text (getMessage "NoIncome" model.translations) + Just income -> + text (getParamMessage [price model income] "Income" model.translations) + ) + , toggleIncomeEdition address "editIncomeEdition" (getMessage "Edit" model.translations) + ] + +incomeEdition : Address Action -> Model -> AccountModel.Model -> AccountModel.IncomeEdition -> Html +incomeEdition address model account edition = + H.form + [ case AccountModel.validateIncome edition.income model.translations of + Ok validatedAmount -> + onSubmitPrevDefault address (UpdateLoggedIn << LoggedInAction.UpdateAccount <| AccountAction.UpdateIncome model.currentTime validatedAmount) + Err error -> + onSubmitPrevDefault address (UpdateLoggedIn << LoggedInAction.UpdateAccount << AccountAction.UpdateEditionError <| error) + , class "income" + ] + [ label + [ for "incomeInput" ] + [ text (getMessage "NewIncome" model.translations) ] + , input + [ id "incomeInput" + , value edition.income + , on "input" targetValue (Signal.message address << UpdateLoggedIn << LoggedInAction.UpdateAccount << AccountAction.UpdateIncomeEdition) + , maxlength 10 + ] + [] + , button + [ type' "submit" + , class "validateIncomeEdition" + ] + [ text (getMessage "Validate" model.translations) ] + , toggleIncomeEdition address "undoIncomeEdition" (getMessage "Undo" model.translations) + , case edition.error of + Just error -> div [ class "error" ] [ text error ] + Nothing -> text "" + ] + +toggleIncomeEdition : Address Action -> String -> String -> Html +toggleIncomeEdition address className name = + button + [ type' "button" + , class className + , onClick address (UpdateLoggedIn << LoggedInAction.UpdateAccount <| AccountAction.ToggleIncomeEdition) + ] + [ text name ] diff --git a/src/client/elm/LoggedIn/Action.elm b/src/client/elm/LoggedIn/Action.elm index db69e2b..bd224cd 100644 --- a/src/client/elm/LoggedIn/Action.elm +++ b/src/client/elm/LoggedIn/Action.elm @@ -4,9 +4,10 @@ module LoggedIn.Action import Model.Payment exposing (Payments, Payment, PaymentId, PaymentFrequency) import Model.Action.MonthlyAction exposing (MonthlyAction) -import Model.Action.AccountAction exposing (AccountAction) import Model.Action.AddPaymentAction exposing (AddPaymentAction) +import LoggedIn.Account.Action as AccountAction + type Action = NoOp | UpdateAdd AddPaymentAction @@ -18,4 +19,4 @@ type Action = | ToggleEdit PaymentId | UpdatePage Int | UpdateMonthly MonthlyAction - | UpdateAccount AccountAction + | UpdateAccount AccountAction.Action diff --git a/src/client/elm/LoggedIn/Model.elm b/src/client/elm/LoggedIn/Model.elm index 5ab5e01..0f677c1 100644 --- a/src/client/elm/LoggedIn/Model.elm +++ b/src/client/elm/LoggedIn/Model.elm @@ -11,13 +11,14 @@ import Model.Init exposing (..) import Model.View.LoggedIn.AddPayment exposing (..) import Model.View.LoggedIn.Edition exposing (..) import Model.View.LoggedIn.Monthly exposing (..) -import Model.View.LoggedIn.Account exposing (..) + +import LoggedIn.Account.Model as AccountModel type alias Model = { users : Users , add : AddPayment , monthly : Monthly - , account : Account + , account : AccountModel.Model , payments : Payments , paymentsCount : Int , paymentEdition : Maybe Edition @@ -29,7 +30,7 @@ init initData = { users = initData.users , add = initAddPayment Punctual , monthly = initMonthly initData.monthlyPayments - , account = initAccount initData.me initData.incomes + , account = AccountModel.init initData.me initData.incomes , payments = initData.payments , paymentsCount = initData.paymentsCount , paymentEdition = Nothing diff --git a/src/client/elm/LoggedIn/Update.elm b/src/client/elm/LoggedIn/Update.elm index aac046d..e017423 100644 --- a/src/client/elm/LoggedIn/Update.elm +++ b/src/client/elm/LoggedIn/Update.elm @@ -16,10 +16,12 @@ import Server import LoggedIn.Action as LoggedInAction import LoggedIn.Model as LoggedInModel +import LoggedIn.Account.Action as AccountAction +import LoggedIn.Account.Update as AccountUpdate + import Model exposing (Model) import Model.User exposing (UserId) import Model.Payment exposing (..) -import Model.Action.AccountAction as Account import Model.Action.MonthlyAction as Monthly import Model.Action.AddPaymentAction as AddPayment import Model.View.LoggedIn.AddPayment exposing (..) @@ -27,7 +29,6 @@ import Model.Translations exposing (Translations, getMessage) import Update.LoggedIn.AddPayment exposing (updateAddPayment, addPaymentError) import Update.LoggedIn.Monthly exposing (updateMonthly) -import Update.LoggedIn.Account exposing (updateAccount) update : Model -> LoggedInAction.Action -> LoggedInModel.Model -> (LoggedInModel.Model, Effects LoggedInAction.Action) update model action loggedInView = @@ -130,7 +131,7 @@ update model action loggedInView = ) LoggedInAction.UpdateAccount accountAction -> - let (newAccount, accountEffects) = updateAccount accountAction loggedInView.account + let (newAccount, accountEffects) = AccountUpdate.update accountAction loggedInView.account in ( { loggedInView | account = newAccount } , Effects.map LoggedInAction.UpdateAccount accountEffects ) diff --git a/src/client/elm/LoggedIn/View.elm b/src/client/elm/LoggedIn/View.elm index 8d4bdbb..8817dd2 100644 --- a/src/client/elm/LoggedIn/View.elm +++ b/src/client/elm/LoggedIn/View.elm @@ -9,13 +9,14 @@ import Html.Attributes exposing (..) import LoggedIn.Model as LoggedInModel +import LoggedIn.Account.View as AccountView + import Model exposing (Model) import Model.Payment exposing (Payments) import Model.Action exposing (Action) import View.LoggedIn.AddPayment exposing (addPayment) import View.LoggedIn.Monthly exposing (monthlyPayments) -import View.LoggedIn.Account exposing (account) import View.LoggedIn.Table exposing (paymentsTable) import View.LoggedIn.Paging exposing (paymentsPaging) @@ -26,7 +27,7 @@ view address model loggedInModel = [ addPayment address model loggedInModel , div [ class "expandables" ] - [ account address model loggedInModel + [ AccountView.view address model loggedInModel , monthlyPayments address model loggedInModel ] , paymentsTable address model loggedInModel diff --git a/src/client/elm/Model/Action/AccountAction.elm b/src/client/elm/Model/Action/AccountAction.elm deleted file mode 100644 index 3e156a5..0000000 --- a/src/client/elm/Model/Action/AccountAction.elm +++ /dev/null @@ -1,17 +0,0 @@ -module Model.Action.AccountAction - ( AccountAction(..) - ) where - -import Time exposing (Time) - -import Model.User exposing (UserId) -import Model.Income exposing (IncomeId) - -type AccountAction = - NoOp - | ToggleDetail - | ToggleIncomeEdition - | UpdateIncomeEdition String - | UpdateEditionError String - | UpdateIncome Time Int - | ValidateUpdateIncome IncomeId Time Int diff --git a/src/client/elm/Model/View/LoggedIn/Account.elm b/src/client/elm/Model/View/LoggedIn/Account.elm deleted file mode 100644 index ec75397..0000000 --- a/src/client/elm/Model/View/LoggedIn/Account.elm +++ /dev/null @@ -1,64 +0,0 @@ -module Model.View.LoggedIn.Account - ( Account - , IncomeEdition - , initAccount - , initIncomeEdition - , getCurrentIncome - , validateIncome - ) where - -import Result as Result exposing (Result(..)) -import Dict -import String - -import Utils.Dict exposing (mapValues) - -import Model.Translations exposing (..) -import Model.Income exposing (..) -import Model.User exposing (UserId) - -type alias Account = - { me : UserId - , incomes : Incomes - , visibleDetail : Bool - , incomeEdition : Maybe IncomeEdition - } - -initAccount : UserId -> Incomes -> Account -initAccount me incomes = - { me = me - , incomes = incomes - , visibleDetail = False - , incomeEdition = Nothing - } - -getCurrentIncome : Account -> Maybe Int -getCurrentIncome account = - account.incomes - |> Dict.filter (\_ income -> income.userId == account.me) - |> Dict.values - |> List.sortBy .creation - |> List.reverse - |> List.head - |> Maybe.map .amount - -type alias IncomeEdition = - { income : String - , error : Maybe String - } - -initIncomeEdition : Int -> IncomeEdition -initIncomeEdition income = - { income = toString income - , error = Nothing - } - -validateIncome : String -> Translations -> Result String Int -validateIncome amount translations = - case String.toInt amount of - Ok number -> - if number > 0 - then Ok number - else Err <| getMessage "IncomeMustBePositiveNumber" translations - Err _ -> - Err <| getMessage "IncomeRequired" translations diff --git a/src/client/elm/Update/LoggedIn/Account.elm b/src/client/elm/Update/LoggedIn/Account.elm deleted file mode 100644 index 233efa9..0000000 --- a/src/client/elm/Update/LoggedIn/Account.elm +++ /dev/null @@ -1,75 +0,0 @@ -module Update.LoggedIn.Account - ( updateAccount - ) where - -import Maybe -import Dict -import Task - -import Effects exposing (Effects) - -import Server - -import Model.Action.AccountAction exposing (..) -import Model.View.LoggedIn.Account exposing (..) - -import Utils.Maybe exposing (isJust) - -updateAccount : AccountAction -> Account -> (Account, Effects AccountAction) -updateAccount action account = - case action of - - NoOp -> - (account, Effects.none) - - ToggleDetail -> - ( { account | visibleDetail = not account.visibleDetail } - , Effects.none - ) - - ToggleIncomeEdition -> - ( { account | incomeEdition = - if isJust account.incomeEdition - then Nothing - else Just (initIncomeEdition (Maybe.withDefault 0 (getCurrentIncome account))) - } - , Effects.none - ) - - UpdateIncomeEdition income -> - case account.incomeEdition of - Just incomeEdition -> - ( { account | incomeEdition = Just { incomeEdition | income = income } } - , Effects.none - ) - Nothing -> - ( account - , Effects.none - ) - - UpdateEditionError error -> - case account.incomeEdition of - Just incomeEdition -> - ( { account | incomeEdition = Just { incomeEdition | error = Just error } } - , Effects.none - ) - Nothing -> - ( account - , Effects.none - ) - - UpdateIncome currentTime amount -> - ( account - , Server.setIncome currentTime amount - |> Task.map (\incomeId -> (ValidateUpdateIncome incomeId currentTime amount)) - |> flip Task.onError (always <| Task.succeed NoOp) - |> Effects.task - ) - - ValidateUpdateIncome incomeId currentTime amount -> - ( { account - | incomes = Dict.insert incomeId { userId = account.me, creation = currentTime, amount = amount } account.incomes - , incomeEdition = Nothing - } - , Effects.none - ) diff --git a/src/client/elm/View/LoggedIn/Account.elm b/src/client/elm/View/LoggedIn/Account.elm deleted file mode 100644 index 66d8582..0000000 --- a/src/client/elm/View/LoggedIn/Account.elm +++ /dev/null @@ -1,131 +0,0 @@ -module View.LoggedIn.Account - ( account - ) where - -import List -import Signal exposing (Address) - -import Html exposing (..) -import Html as H exposing (..) -import Html.Attributes exposing (..) -import Html.Events exposing (..) - -import LoggedIn.Action as LoggedInAction -import LoggedIn.Model as LoggedInModel - -import Model exposing (Model) -import Model.User exposing (getUserName) -import Model.Payer exposing (..) -import Model.Translations exposing (getParamMessage, getMessage) -import Model.Action exposing (..) -import Model.Action.AccountAction exposing (..) - -import Model.View.LoggedIn.Account exposing (..) - -import View.Expand exposing (..) -import View.Price exposing (price) -import View.Events exposing (onSubmitPrevDefault) - -import Utils.Either exposing (toMaybeError) - -account : Address Action -> Model -> LoggedInModel.Model -> Html -account address model loggedInModel = - let account = loggedInModel.account - in div - [ classList - [ ("account", True) - , ("detail", account.visibleDetail) - ] - ] - [ exceedingPayers address model loggedInModel - , if account.visibleDetail - then income address model account - else text "" - ] - -exceedingPayers : Address Action -> Model -> LoggedInModel.Model -> Html -exceedingPayers address model loggedInModel = - button - [ class "header" - , onClick address (UpdateLoggedIn << LoggedInAction.UpdateAccount <| ToggleDetail) - ] - ( (List.map (exceedingPayer model loggedInModel) (getOrderedExceedingPayers model.currentTime loggedInModel.users loggedInModel.account.incomes loggedInModel.payments)) - ++ [ expand ExpandDown loggedInModel.account.visibleDetail ] - ) - -exceedingPayer : Model -> LoggedInModel.Model -> ExceedingPayer -> Html -exceedingPayer model loggedInModel payer = - div - [ class "exceedingPayer" ] - [ span - [ class "userName" ] - [ payer.userId - |> getUserName loggedInModel.users - |> Maybe.withDefault "−" - |> text - ] - , span - [ class "amount" ] - [ text ("+ " ++ (price model payer.amount)) ] - ] - -income : Address Action -> Model -> Account -> Html -income address model account = - case account.incomeEdition of - Nothing -> - incomeRead address model account - Just edition -> - incomeEdition address model account edition - -incomeRead : Address Action -> Model -> Account -> Html -incomeRead address model account = - div - [ class "income" ] - [ ( case getCurrentIncome account of - Nothing -> - text (getMessage "NoIncome" model.translations) - Just income -> - text (getParamMessage [price model income] "Income" model.translations) - ) - , toggleIncomeEdition address "editIncomeEdition" (getMessage "Edit" model.translations) - ] - -incomeEdition : Address Action -> Model -> Account -> IncomeEdition -> Html -incomeEdition address model account edition = - H.form - [ case validateIncome edition.income model.translations of - Ok validatedAmount -> - onSubmitPrevDefault address (UpdateLoggedIn << LoggedInAction.UpdateAccount <| UpdateIncome model.currentTime validatedAmount) - Err error -> - onSubmitPrevDefault address (UpdateLoggedIn << LoggedInAction.UpdateAccount << UpdateEditionError <| error) - , class "income" - ] - [ label - [ for "incomeInput" ] - [ text (getMessage "NewIncome" model.translations) ] - , input - [ id "incomeInput" - , value edition.income - , on "input" targetValue (Signal.message address << UpdateLoggedIn << LoggedInAction.UpdateAccount << UpdateIncomeEdition) - , maxlength 10 - ] - [] - , button - [ type' "submit" - , class "validateIncomeEdition" - ] - [ text (getMessage "Validate" model.translations) ] - , toggleIncomeEdition address "undoIncomeEdition" (getMessage "Undo" model.translations) - , case edition.error of - Just error -> div [ class "error" ] [ text error ] - Nothing -> text "" - ] - -toggleIncomeEdition : Address Action -> String -> String -> Html -toggleIncomeEdition address className name = - button - [ type' "button" - , class className - , onClick address (UpdateLoggedIn << LoggedInAction.UpdateAccount <| ToggleIncomeEdition) - ] - [ text name ] -- cgit v1.2.3