From cfca18262c1ff48dcb683ddab7d03cf8e55573ff Mon Sep 17 00:00:00 2001 From: Joris Date: Fri, 24 Mar 2017 09:21:04 +0000 Subject: Features/categories --- src/client/elm/LoggedIn/Category/Model.elm | 36 +++++++ src/client/elm/LoggedIn/Category/Msg.elm | 9 ++ src/client/elm/LoggedIn/Category/Table/View.elm | 124 ++++++++++++++++++++++++ src/client/elm/LoggedIn/Category/Update.elm | 24 +++++ src/client/elm/LoggedIn/Category/View.elm | 35 +++++++ src/client/elm/LoggedIn/Home/Header/View.elm | 7 +- src/client/elm/LoggedIn/Home/Model.elm | 15 +-- src/client/elm/LoggedIn/Home/Update.elm | 4 +- src/client/elm/LoggedIn/Home/View.elm | 21 ++-- src/client/elm/LoggedIn/Home/View/Paging.elm | 74 +++++++------- src/client/elm/LoggedIn/Home/View/Table.elm | 42 +++++--- src/client/elm/LoggedIn/Income/Model.elm | 15 +-- src/client/elm/LoggedIn/Income/Update.elm | 12 +-- src/client/elm/LoggedIn/Income/View.elm | 33 ++++--- src/client/elm/LoggedIn/Income/View/Table.elm | 6 +- src/client/elm/LoggedIn/Model.elm | 21 ++-- src/client/elm/LoggedIn/Msg.elm | 18 ++-- src/client/elm/LoggedIn/Stat/View.elm | 4 +- src/client/elm/LoggedIn/Update.elm | 80 ++++++++++----- src/client/elm/LoggedIn/View.elm | 16 +-- 20 files changed, 445 insertions(+), 151 deletions(-) create mode 100644 src/client/elm/LoggedIn/Category/Model.elm create mode 100644 src/client/elm/LoggedIn/Category/Msg.elm create mode 100644 src/client/elm/LoggedIn/Category/Table/View.elm create mode 100644 src/client/elm/LoggedIn/Category/Update.elm create mode 100644 src/client/elm/LoggedIn/Category/View.elm (limited to 'src/client/elm/LoggedIn') diff --git a/src/client/elm/LoggedIn/Category/Model.elm b/src/client/elm/LoggedIn/Category/Model.elm new file mode 100644 index 0000000..7092fc4 --- /dev/null +++ b/src/client/elm/LoggedIn/Category/Model.elm @@ -0,0 +1,36 @@ +module LoggedIn.Category.Model exposing + ( Model + , AddCategory + , init + , initForm + , validation + ) + +import Date exposing (Date) + +import Form exposing (Form) +import Form.Validate as Validate exposing (Validation) +import Validation + +type alias Model = + { addCategory : Form String AddCategory + } + +type alias AddCategory = + { amount : Int + , date : Date + } + +init : Model +init = + { addCategory = initForm + } + +initForm : Form String AddCategory +initForm = Form.initial [] validation + +validation : Validation String AddCategory +validation = + Validate.map2 AddCategory + (Validate.field "amount" (Validate.int |> Validate.andThen (Validate.minInt 1))) + (Validate.field "date" Validation.date) diff --git a/src/client/elm/LoggedIn/Category/Msg.elm b/src/client/elm/LoggedIn/Category/Msg.elm new file mode 100644 index 0000000..3184297 --- /dev/null +++ b/src/client/elm/LoggedIn/Category/Msg.elm @@ -0,0 +1,9 @@ +module LoggedIn.Category.Msg exposing + ( Msg(..) + ) + +import Form exposing (Form) + +type Msg = + NoOp + | AddCategoryMsg Form.Msg diff --git a/src/client/elm/LoggedIn/Category/Table/View.elm b/src/client/elm/LoggedIn/Category/Table/View.elm new file mode 100644 index 0000000..fa7a7b1 --- /dev/null +++ b/src/client/elm/LoggedIn/Category/Table/View.elm @@ -0,0 +1,124 @@ +module LoggedIn.Category.Table.View exposing + ( view + ) + +import Dict exposing (..) +import Date exposing (Date) +import String exposing (append) + +import FontAwesome +import View.Color as Color + +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) + +import Dialog +import Dialog.AddCategory.Model as AddCategory +import Dialog.AddCategory.View as AddCategory + +import Tooltip + +import Msg exposing (Msg) + +import LoggedData exposing (LoggedData) + +import LoggedIn.Msg as LoggedInMsg + +import LoggedIn.Category.Model as Category +import View.Date as Date +import LoggedIn.View.Format as Format + +import Model.User exposing (getUserName) +import Model.Category as Category exposing (CategoryId, Category) +import Model.PaymentCategory as PaymentCategory +import Model.Translations exposing (getMessage) + +view : LoggedData -> Category.Model -> Html Msg +view loggedData categoryModel = + let categories = + loggedData.categories + |> Dict.toList + |> List.sortBy (.name << Tuple.second) + in div + [ class "table" ] + [ div + [ class "lines" ] + ( headerLine loggedData :: List.map (paymentLine loggedData categoryModel) categories) + , if List.isEmpty (Dict.toList loggedData.categories) + then + div + [ class "emptyTableMsg" ] + [ text <| getMessage loggedData.translations "NoCategories" ] + else + text "" + ] + +headerLine : LoggedData -> Html Msg +headerLine loggedData = + div + [ class "header" ] + [ div [ class "cell name" ] [ text <| getMessage loggedData.translations "Name" ] + , div [ class "cell category" ] [ text <| getMessage loggedData.translations "Color" ] + , div [ class "cell" ] [] + , div [ class "cell" ] [] + , div [ class "cell" ] [] + ] + +paymentLine : LoggedData -> Category.Model -> (CategoryId, Category) -> Html Msg +paymentLine loggedData categoryModel (categoryId, category) = + div + [ class "row" ] + [ div + [ class "cell category" ] + [ text category.name ] + , div + [ class "cell category" ] + [ span + [ class "tag" + , style [("background-color", category.color)] + ] + [ text category.color ] + ] + , div + [ class "cell button" ] + [ let currentDate = Date.fromTime loggedData.currentTime + in AddCategory.button + loggedData + (AddCategory.initialClone loggedData.translations category) + "CloneCategory" + (FontAwesome.clone Color.chestnutRose 18) + (Just (getMessage loggedData.translations "Clone")) + ] + , div + [ class "cell button" ] + [ AddCategory.button + loggedData + (AddCategory.initialEdit loggedData.translations categoryId category) + "EditCategory" + (FontAwesome.pencil Color.chestnutRose 18) + (Just (getMessage loggedData.translations "Edit")) + ] + , div + [ class "cell button" ] + [ if PaymentCategory.isCategoryUnused categoryId loggedData.paymentCategories + then + let dialogConfig = + { className = "deleteCategoryDialog" + , title = getMessage loggedData.translations "ConfirmCategoryDelete" + , body = always <| text "" + , confirm = getMessage loggedData.translations "Confirm" + , confirmMsg = always <| Msg.Dialog <| Dialog.UpdateAndClose <| Msg.DeleteCategory categoryId + , undo = getMessage loggedData.translations "Undo" + } + in button + ( Tooltip.show Msg.Tooltip (getMessage loggedData.translations "Delete") + ++ [ onClick (Msg.Dialog <| Dialog.Open dialogConfig) ] + ) + [ FontAwesome.trash Color.chestnutRose 18 ] + else + span + ( Tooltip.show Msg.Tooltip (getMessage loggedData.translations "UsedCategory") ) + [ FontAwesome.trash Color.silver 18 ] + ] + ] diff --git a/src/client/elm/LoggedIn/Category/Update.elm b/src/client/elm/LoggedIn/Category/Update.elm new file mode 100644 index 0000000..1072ef0 --- /dev/null +++ b/src/client/elm/LoggedIn/Category/Update.elm @@ -0,0 +1,24 @@ +module LoggedIn.Category.Update exposing + ( update + ) + +import Form exposing (Form) + +import LoggedData exposing (LoggedData) + +import LoggedIn.Category.Model as Category +import LoggedIn.Category.Msg as Category + +update : LoggedData -> Category.Msg -> Category.Model -> (Category.Model, Cmd Category.Msg) +update loggedData msg model = + case msg of + + Category.NoOp -> + ( model + , Cmd.none + ) + + Category.AddCategoryMsg formMsg -> + ( { model | addCategory = Form.update Category.validation formMsg model.addCategory } + , Cmd.none + ) diff --git a/src/client/elm/LoggedIn/Category/View.elm b/src/client/elm/LoggedIn/Category/View.elm new file mode 100644 index 0000000..4e04fa2 --- /dev/null +++ b/src/client/elm/LoggedIn/Category/View.elm @@ -0,0 +1,35 @@ +module LoggedIn.Category.View exposing + ( view + ) + +import Html exposing (..) +import Html.Attributes exposing (..) + +import LoggedData exposing (LoggedData) + +import Msg exposing (Msg) + +import Dialog.AddCategory.Model as AddCategory +import Dialog.AddCategory.View as AddCategory + +import LoggedIn.Category.Model as Category +import LoggedIn.Category.Table.View as Table + +import Model.Translations exposing (getMessage, getParamMessage) + +view : LoggedData -> Category.Model -> Html Msg +view loggedData categoryModel = + div + [ class "categories" ] + [ div + [ class "titleButton withMargin" ] + [ h1 [] [ text <| getMessage loggedData.translations "Categories" ] + , AddCategory.button + loggedData + (AddCategory.initialAdd loggedData.translations) + "AddCategory" + (text (getMessage loggedData.translations "AddCategory")) + Nothing + ] + , Table.view loggedData categoryModel + ] diff --git a/src/client/elm/LoggedIn/Home/Header/View.elm b/src/client/elm/LoggedIn/Home/Header/View.elm index b67fb3b..3f8a320 100644 --- a/src/client/elm/LoggedIn/Home/Header/View.elm +++ b/src/client/elm/LoggedIn/Home/Header/View.elm @@ -5,7 +5,6 @@ module LoggedIn.Home.Header.View exposing import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (..) -import Html.App as Html import String import Dict import Date @@ -32,8 +31,6 @@ import LoggedIn.Home.View.ExceedingPayers as ExceedingPayers import LoggedIn.View.Format as Format import View.Plural exposing (plural) -import Utils.Tuple as Tuple - view : LoggedData -> Home.Model -> Payments -> Frequency -> Html Msg view loggedData { search } payments frequency = let currentDate = Date.fromTime loggedData.currentTime @@ -90,9 +87,9 @@ paymentsPartition loggedData payments = ", " ( loggedData.users |> Dict.toList - |> List.map (Tuple.mapFst (\userId -> Payment.totalPayments (always True) userId payments)) + |> List.map (Tuple.mapFirst (\userId -> Payment.totalPayments (always True) userId payments)) |> List.filter (\(sum, _) -> sum > 0) - |> List.sortBy fst + |> List.sortBy Tuple.first |> List.reverse |> List.map (\(sum, user) -> getParamMessage [ user.name, Format.price loggedData.conf sum ] loggedData.translations "By" diff --git a/src/client/elm/LoggedIn/Home/Model.elm b/src/client/elm/LoggedIn/Home/Model.elm index caedc29..ace1593 100644 --- a/src/client/elm/LoggedIn/Home/Model.elm +++ b/src/client/elm/LoggedIn/Home/Model.elm @@ -3,6 +3,7 @@ module LoggedIn.Home.Model exposing , Search , init , searchInitial + , validation ) import Form exposing (Form) @@ -26,14 +27,14 @@ type alias Search = init : Model init = { currentPage = 1 - , search = Form.initial (searchInitial Punctual) searchValidation + , search = Form.initial (searchInitial Punctual) validation } searchInitial : Frequency -> List (String, Field) -searchInitial frequency = [ ("frequency", Field.Radio (toString frequency)) ] +searchInitial frequency = [ ("frequency", Field.string (toString frequency)) ] -searchValidation : Validation String Search -searchValidation = - Validate.form2 Search - (Validate.get "name" (Validate.maybe Validate.string)) - (Validate.get "frequency" Payment.validateFrequency) +validation : Validation String Search +validation = + Validate.map2 Search + (Validate.field "name" (Validate.maybe Validate.string)) + (Validate.field "frequency" Payment.validateFrequency) diff --git a/src/client/elm/LoggedIn/Home/Update.elm b/src/client/elm/LoggedIn/Home/Update.elm index d1a3239..b0ce256 100644 --- a/src/client/elm/LoggedIn/Home/Update.elm +++ b/src/client/elm/LoggedIn/Home/Update.elm @@ -25,10 +25,10 @@ update loggedData msg model = Home.SearchMsg formMsg -> ( { model - | search = Form.update formMsg model.search + | search = Form.update Home.validation formMsg model.search , currentPage = case formMsg of - Form.Input "name" _ -> 1 + Form.Input "name" _ _ -> 1 _ -> model.currentPage } , Cmd.none diff --git a/src/client/elm/LoggedIn/Home/View.elm b/src/client/elm/LoggedIn/Home/View.elm index 0def64e..0b90e67 100644 --- a/src/client/elm/LoggedIn/Home/View.elm +++ b/src/client/elm/LoggedIn/Home/View.elm @@ -2,23 +2,22 @@ module LoggedIn.Home.View exposing ( view ) +import Date import Html exposing (..) import Html.Attributes exposing (..) -import Date import Form import Utils.Form as Form -import Msg exposing (Msg) - import LoggedData exposing (LoggedData) -import Model.Payment as Payment exposing (Frequency(..)) - -import LoggedIn.Home.Model as Home import LoggedIn.Home.Header.View as Header - -import LoggedIn.Home.View.Table as Table +import LoggedIn.Home.Model as Home +import LoggedIn.Home.Msg as HomeMsg import LoggedIn.Home.View.Paging as Paging +import LoggedIn.Home.View.Table as Table +import LoggedIn.Msg as LoggedInMsg +import Model.Payment as Payment exposing (Frequency(..)) +import Msg exposing (Msg) view : LoggedData -> Home.Model -> Html Msg view loggedData home = @@ -31,5 +30,9 @@ view loggedData home = [ class "home" ] [ Header.view loggedData home payments frequency , Table.view loggedData home payments frequency - , Paging.view home payments + , Paging.view + home.currentPage + (List.length payments) + Msg.NoOp + (Msg.UpdateLoggedIn << LoggedInMsg.HomeMsg << HomeMsg.UpdatePage) ] diff --git a/src/client/elm/LoggedIn/Home/View/Paging.elm b/src/client/elm/LoggedIn/Home/View/Paging.elm index 5bcb827..dffe061 100644 --- a/src/client/elm/LoggedIn/Home/View/Paging.elm +++ b/src/client/elm/LoggedIn/Home/View/Paging.elm @@ -10,31 +10,29 @@ import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (..) -import LoggedIn.Msg as LoggedInMsg - -import LoggedIn.Home.Msg as HomeMsg -import LoggedIn.Home.Model as HomeModel - -import Msg exposing (Msg) import LoggedData exposing (LoggedData) import Model.Payment as Payment exposing (Payments, perPage) showedPages : Int showedPages = 5 -view : HomeModel.Model -> Payments -> Html Msg -view homeModel payments = - let maxPage = ceiling (toFloat (List.length payments) / toFloat perPage) - pages = truncatePages homeModel.currentPage [1..maxPage] +view : Int -> Int -> msg -> (Int -> msg) -> Html msg +view currentPage payments noOp pageMsg = + let maxPage = ceiling (toFloat payments / toFloat perPage) + pages = truncatePages currentPage (List.range 1 maxPage) in if maxPage <= 1 then text "" else div [ class "pages" ] - ( [ firstPage homeModel, previousPage homeModel ] - ++ ( List.map (paymentsPage homeModel) pages) - ++ [ nextPage homeModel maxPage, lastPage homeModel maxPage ] + ( [ firstPage currentPage pageMsg + , previousPage currentPage noOp pageMsg + ] + ++ ( List.map (paymentsPage currentPage noOp pageMsg) pages) + ++ [ nextPage currentPage maxPage noOp pageMsg + , lastPage currentPage maxPage pageMsg + ] ) truncatePages : Int -> List Int -> List Int @@ -44,57 +42,57 @@ truncatePages currentPage pages = showedRightPages = floor ((toFloat showedPages - 1) / 2) truncatedPages = if currentPage <= showedLeftPages then - [1..showedPages] + (List.range 1 showedPages) else if currentPage > totalPages - showedRightPages then - [(totalPages - showedPages + 1)..totalPages] + (List.range (totalPages - showedPages + 1) totalPages) else - [(currentPage - showedLeftPages)..(currentPage + showedRightPages)] + (List.range (currentPage - showedLeftPages) (currentPage + showedRightPages)) in List.filter (flip List.member pages) truncatedPages -firstPage : HomeModel.Model -> Html Msg -firstPage homeModel = +firstPage : Int -> (Int -> msg) -> Html msg +firstPage currentPage pageMsg = button [ classList [ ("page", True) - , ("disable", homeModel.currentPage <= 1) + , ("disable", currentPage <= 1) ] - , onClick (Msg.UpdateLoggedIn << LoggedInMsg.HomeMsg << HomeMsg.UpdatePage <| 1) + , onClick (pageMsg 1) ] [ FontAwesome.fast_backward grey 13 ] -previousPage : HomeModel.Model -> Html Msg -previousPage homeModel = +previousPage : Int -> msg -> (Int -> msg) -> Html msg +previousPage currentPage noOp pageMsg = button [ class "page" , onClick <| - if homeModel.currentPage > 1 - then (Msg.UpdateLoggedIn << LoggedInMsg.HomeMsg << HomeMsg.UpdatePage <| homeModel.currentPage - 1) - else Msg.NoOp + if currentPage > 1 + then (pageMsg <| currentPage - 1) + else noOp ] [ FontAwesome.backward grey 13 ] -nextPage : HomeModel.Model -> Int -> Html Msg -nextPage homeModel maxPage = +nextPage : Int -> Int -> msg -> (Int -> msg) -> Html msg +nextPage currentPage maxPage noOp pageMsg = button [ class "page" , onClick <| - if homeModel.currentPage < maxPage - then (Msg.UpdateLoggedIn << LoggedInMsg.HomeMsg << HomeMsg.UpdatePage <| homeModel.currentPage + 1) - else Msg.NoOp + if currentPage < maxPage + then (pageMsg <| currentPage + 1) + else noOp ] [ FontAwesome.forward grey 13 ] -lastPage : HomeModel.Model -> Int -> Html Msg -lastPage homeModel maxPage = +lastPage : Int -> Int -> (Int -> msg) -> Html msg +lastPage currentPage maxPage pageMsg = button [ class "page" - , onClick (Msg.UpdateLoggedIn << LoggedInMsg.HomeMsg << HomeMsg.UpdatePage <| maxPage) + , onClick (pageMsg maxPage) ] [ FontAwesome.fast_forward grey 13 ] -paymentsPage : HomeModel.Model -> Int -> Html Msg -paymentsPage homeModel page = - let onCurrentPage = page == homeModel.currentPage +paymentsPage : Int -> msg -> (Int -> msg) -> Int -> Html msg +paymentsPage currentPage noOp pageMsg page = + let onCurrentPage = page == currentPage in button [ classList [ ("page", True) @@ -102,8 +100,8 @@ paymentsPage homeModel page = ] , onClick <| if onCurrentPage - then Msg.NoOp - else Msg.UpdateLoggedIn << LoggedInMsg.HomeMsg << HomeMsg.UpdatePage <| page + then noOp + else pageMsg page ] [ text (toString page) ] diff --git a/src/client/elm/LoggedIn/Home/View/Table.elm b/src/client/elm/LoggedIn/Home/View/Table.elm index 6423bf9..8828488 100644 --- a/src/client/elm/LoggedIn/Home/View/Table.elm +++ b/src/client/elm/LoggedIn/Home/View/Table.elm @@ -2,8 +2,8 @@ module LoggedIn.Home.View.Table exposing ( view ) -import Dict exposing (..) import Date exposing (Date) +import Dict exposing (..) import String exposing (append) import FontAwesome @@ -26,12 +26,13 @@ import LoggedData exposing (LoggedData) import LoggedIn.Msg as LoggedInMsg import LoggedIn.Home.Model as Home -import View.Date as Date import LoggedIn.View.Format as Format +import View.Date as Date -import Model.User exposing (getUserName) import Model.Payment as Payment exposing (..) +import Model.PaymentCategory as PaymentCategory import Model.Translations exposing (getMessage) +import Model.User exposing (getUserName) view : LoggedData -> Home.Model -> Payments -> Frequency -> Html Msg view loggedData homeModel payments frequency = @@ -60,6 +61,7 @@ headerLine loggedData frequency = [ div [ class "cell category" ] [ text <| getMessage loggedData.translations "Name" ] , div [ class "cell cost" ] [ text <| getMessage loggedData.translations "Cost" ] , div [ class "cell user" ] [ text <| getMessage loggedData.translations "Payer" ] + , div [ class "cell user" ] [ text <| getMessage loggedData.translations "PaymentCategory" ] , case frequency of Punctual -> div [ class "cell date" ] [ text <| getMessage loggedData.translations "Date" ] Monthly -> text "" @@ -72,7 +74,7 @@ paymentLine : LoggedData -> Home.Model -> Frequency -> Payment -> Html Msg paymentLine loggedData homeModel frequency payment = div [ class "row" ] - [ div [ class "cell category" ] [ text payment.name ] + [ div [ class "cell name" ] [ text payment.name ] , div [ classList [ ("cell cost", True) @@ -87,6 +89,22 @@ paymentLine loggedData homeModel frequency payment = |> Maybe.withDefault "−" |> text ] + , div + [ class "cell category" ] + ( let mbCategory = + PaymentCategory.search payment.name loggedData.paymentCategories + |> Maybe.andThen (\category -> Dict.get category loggedData.categories) + in case mbCategory of + Just category -> + [ span + [ class "tag" + , style [("background-color", category.color)] + ] + [ text category.name ] + ] + Nothing -> + [] + ) , case frequency of Punctual -> div @@ -103,9 +121,10 @@ paymentLine loggedData homeModel frequency payment = , div [ class "cell button" ] [ let currentDate = Date.fromTime loggedData.currentTime + category = PaymentCategory.search payment.name loggedData.paymentCategories in AddPayment.button loggedData - (AddPayment.initialClone loggedData.translations currentDate payment) + (AddPayment.initialClone loggedData.translations currentDate category payment) "ClonePayment" (FontAwesome.clone Color.chestnutRose 18) (Just (getMessage loggedData.translations "Clone")) @@ -116,12 +135,13 @@ paymentLine loggedData homeModel frequency payment = then text "" else - AddPayment.button - loggedData - (AddPayment.initialEdit loggedData.translations payment) - "EditPayment" - (FontAwesome.pencil Color.chestnutRose 18) - (Just (getMessage loggedData.translations "Edit")) + let category = PaymentCategory.search payment.name loggedData.paymentCategories + in AddPayment.button + loggedData + (AddPayment.initialEdit loggedData.translations category payment) + "EditPayment" + (FontAwesome.pencil Color.chestnutRose 18) + (Just (getMessage loggedData.translations "Edit")) ] , div [ class "cell button" ] diff --git a/src/client/elm/LoggedIn/Income/Model.elm b/src/client/elm/LoggedIn/Income/Model.elm index cf1bf57..7d852b9 100644 --- a/src/client/elm/LoggedIn/Income/Model.elm +++ b/src/client/elm/LoggedIn/Income/Model.elm @@ -3,12 +3,13 @@ module LoggedIn.Income.Model exposing , AddIncome , init , initForm + , validation ) import Date exposing (Date) import Form exposing (Form) -import Form.Validate as Validate exposing (..) +import Form.Validate as Validate exposing (Validation) import Validation type alias Model = @@ -26,10 +27,10 @@ init = } initForm : Form String AddIncome -initForm = Form.initial [] validate +initForm = Form.initial [] validation -validate : Validation String AddIncome -validate = - form2 AddIncome - (get "amount" (int `andThen` (minInt 1))) - (get "date" Validation.date) +validation : Validation String AddIncome +validation = + Validate.map2 AddIncome + (Validate.field "amount" (Validate.int |> Validate.andThen (Validate.minInt 1))) + (Validate.field "date" Validation.date) diff --git a/src/client/elm/LoggedIn/Income/Update.elm b/src/client/elm/LoggedIn/Income/Update.elm index ec6a0c1..0023c76 100644 --- a/src/client/elm/LoggedIn/Income/Update.elm +++ b/src/client/elm/LoggedIn/Income/Update.elm @@ -6,19 +6,19 @@ import Form exposing (Form) import LoggedData exposing (LoggedData) -import LoggedIn.Income.Model as IncomeModel -import LoggedIn.Income.Msg as IncomeMsg +import LoggedIn.Income.Model as Income +import LoggedIn.Income.Msg as Income -update : LoggedData -> IncomeMsg.Msg -> IncomeModel.Model -> (IncomeModel.Model, Cmd IncomeMsg.Msg) +update : LoggedData -> Income.Msg -> Income.Model -> (Income.Model, Cmd Income.Msg) update loggedData msg model = case msg of - IncomeMsg.NoOp -> + Income.NoOp -> ( model , Cmd.none ) - IncomeMsg.AddIncomeMsg formMsg -> - ( { model | addIncome = Form.update formMsg model.addIncome } + Income.AddIncomeMsg formMsg -> + ( { model | addIncome = Form.update Income.validation formMsg model.addIncome } , Cmd.none ) diff --git a/src/client/elm/LoggedIn/Income/View.elm b/src/client/elm/LoggedIn/Income/View.elm index 2c5bcaf..00a1646 100644 --- a/src/client/elm/LoggedIn/Income/View.elm +++ b/src/client/elm/LoggedIn/Income/View.elm @@ -12,7 +12,6 @@ import FontAwesome import Html exposing (..) import Html.Events exposing (..) import Html.Attributes exposing (..) -import Html.App as Html import Form exposing (Form) import View.Form as Form @@ -45,19 +44,21 @@ view : LoggedData -> Income.Model -> Html Msg view loggedData incomeModel = div [ class "income" ] - [ case useIncomesFrom loggedData.users loggedData.incomes loggedData.payments of - Just since -> cumulativeIncomesView loggedData since - Nothing -> text "" - , div - [ class "textual monthlyNetIncomes" ] - [ h1 [] [ text <| getMessage loggedData.translations "MonthlyNetIncomes" ] - , AddIncome.button - "addIncome" - loggedData - (AddIncome.initialAdd loggedData.translations (Date.fromTime loggedData.currentTime)) - "AddIncome" - (text (getMessage loggedData.translations "AddIncome")) - Nothing + [ div + [ class "withMargin" ] + [ case useIncomesFrom loggedData.users loggedData.incomes loggedData.payments of + Just since -> cumulativeIncomesView loggedData since + Nothing -> text "" + , div + [ class "titleButton" ] + [ h1 [] [ text <| getMessage loggedData.translations "MonthlyNetIncomes" ] + , AddIncome.button + loggedData + (AddIncome.initialAdd loggedData.translations (Date.fromTime loggedData.currentTime)) + "AddIncome" + (text (getMessage loggedData.translations "AddIncome")) + Nothing + ] ] , Table.view loggedData incomeModel ] @@ -66,7 +67,7 @@ cumulativeIncomesView : LoggedData -> Time -> Html Msg cumulativeIncomesView loggedData since = let longDate = Date.longView (Date.fromTime since) loggedData.translations in div - [ class "textual" ] + [] [ h1 [] [ text <| getParamMessage [longDate] loggedData.translations "CumulativeIncomesSince" ] , ul [] @@ -74,7 +75,7 @@ cumulativeIncomesView loggedData since = |> List.map (\(userId, user) -> (user.name, userCumulativeIncomeSince loggedData.currentTime since loggedData.incomes userId) ) - |> List.sortBy snd + |> List.sortBy Tuple.second |> List.map (\(userName, cumulativeIncome) -> li [] diff --git a/src/client/elm/LoggedIn/Income/View/Table.elm b/src/client/elm/LoggedIn/Income/View/Table.elm index dcf6d78..aa5e392 100644 --- a/src/client/elm/LoggedIn/Income/View/Table.elm +++ b/src/client/elm/LoggedIn/Income/View/Table.elm @@ -38,7 +38,7 @@ view loggedData incomeModel = let incomes = loggedData.incomes |> Dict.toList - |> List.sortBy (.time << snd) + |> List.sortBy (.time << Tuple.second) |> List.reverse in div [ class "table" ] @@ -49,7 +49,7 @@ view loggedData incomeModel = then div [ class "emptyTableMsg" ] - [ text <| getMessage loggedData.translations "NoPayment" ] + [ text <| getMessage loggedData.translations "NoIncome" ] else text "" ] @@ -87,7 +87,6 @@ paymentLine loggedData incomeModel (incomeId, income) = [ class "cell button" ] [ let currentDate = Date.fromTime loggedData.currentTime in AddIncome.button - "" loggedData (AddIncome.initialClone loggedData.translations currentDate income) "CloneIncome" @@ -101,7 +100,6 @@ paymentLine loggedData incomeModel (incomeId, income) = text "" else AddIncome.button - "" loggedData (AddIncome.initialEdit loggedData.translations incomeId income) "EditIncome" diff --git a/src/client/elm/LoggedIn/Model.elm b/src/client/elm/LoggedIn/Model.elm index 11386d5..6bcb0b2 100644 --- a/src/client/elm/LoggedIn/Model.elm +++ b/src/client/elm/LoggedIn/Model.elm @@ -9,25 +9,34 @@ import Model.Init exposing (..) import Model.Payment exposing (Payments) import Model.User exposing (Users, UserId) import Model.Income exposing (Incomes) +import Model.Category exposing (Categories) +import Model.PaymentCategory exposing (PaymentCategories) -import LoggedIn.Home.Model as HomeModel -import LoggedIn.Income.Model as IncomeModel +import LoggedIn.Home.Model as Home +import LoggedIn.Income.Model as Income +import LoggedIn.Category.Model as Categories type alias Model = - { home : HomeModel.Model - , income : IncomeModel.Model + { home : Home.Model + , income : Income.Model + , category : Categories.Model , users : Users , me : UserId , payments : Payments , incomes : Incomes + , categories : Categories + , paymentCategories : PaymentCategories } init : Init -> Model init initData = - { home = HomeModel.init - , income = IncomeModel.init + { home = Home.init + , income = Income.init + , category = Categories.init , users = initData.users , me = initData.me , payments = initData.payments , incomes = initData.incomes + , categories = initData.categories + , paymentCategories = initData.paymentCategories } diff --git a/src/client/elm/LoggedIn/Msg.elm b/src/client/elm/LoggedIn/Msg.elm index ff275e2..a1379a6 100644 --- a/src/client/elm/LoggedIn/Msg.elm +++ b/src/client/elm/LoggedIn/Msg.elm @@ -6,17 +6,23 @@ import Date exposing (Date) import Model.Payment exposing (PaymentId, Frequency) import Model.Income exposing (IncomeId) +import Model.Category exposing (CategoryId) -import LoggedIn.Home.Msg as HomeMsg -import LoggedIn.Income.Msg as IncomeMsg +import LoggedIn.Home.Msg as Home +import LoggedIn.Income.Msg as Income +import LoggedIn.Category.Msg as Categories type Msg = NoOp - | HomeMsg HomeMsg.Msg - | IncomeMsg IncomeMsg.Msg - | ValidateCreatePayment PaymentId String Int Date Frequency - | ValidateEditPayment PaymentId String Int Date Frequency + | HomeMsg Home.Msg + | IncomeMsg Income.Msg + | CategoriesMsg Categories.Msg + | ValidateCreatePayment PaymentId String Int Date CategoryId Frequency + | ValidateEditPayment PaymentId String Int Date CategoryId Frequency | ValidateDeletePayment PaymentId | ValidateCreateIncome IncomeId Int Date | ValidateEditIncome IncomeId Int Date | ValidateDeleteIncome IncomeId + | ValidateCreateCategory CategoryId String String + | ValidateEditCategory CategoryId String String + | ValidateDeleteCategory CategoryId diff --git a/src/client/elm/LoggedIn/Stat/View.elm b/src/client/elm/LoggedIn/Stat/View.elm index 946005a..f57316a 100644 --- a/src/client/elm/LoggedIn/Stat/View.elm +++ b/src/client/elm/LoggedIn/Stat/View.elm @@ -26,7 +26,7 @@ view loggedData = let paymentsByMonth = Payment.groupAndSortByMonth (Payment.punctual loggedData.payments) monthPaymentMean = getMonthPaymentMean loggedData paymentsByMonth in div - [ class "stat textual" ] + [ class "stat withMargin" ] [ h1 [] [ text (getParamMessage [ Format.price loggedData.conf monthPaymentMean ] loggedData.translations "ByMonthsAndMean") ] , ul [] @@ -40,7 +40,7 @@ getMonthPaymentMean loggedData paymentsByMonth = let currentDate = Date.fromTime loggedData.currentTime in not (Date.month currentDate == month && Date.year currentDate == year) ) - |> List.map (List.sum << List.map .cost << snd) + |> List.map (List.sum << List.map .cost << Tuple.second) |> List.mean monthDetail : LoggedData -> ((Month, Int), Payments) -> Html Msg diff --git a/src/client/elm/LoggedIn/Update.elm b/src/client/elm/LoggedIn/Update.elm index 06cd623..9e6d6ee 100644 --- a/src/client/elm/LoggedIn/Update.elm +++ b/src/client/elm/LoggedIn/Update.elm @@ -15,6 +15,8 @@ import Form import Model exposing (Model) import Model.Payment as Payment exposing (Payment, Frequency(..)) import Model.Income as Income exposing (Income) +import Model.Category exposing (Category) +import Model.PaymentCategory as PaymentCategory import Server import LoggedData @@ -22,16 +24,16 @@ import LoggedData import LoggedIn.Msg as LoggedInMsg import LoggedIn.Model as LoggedInModel -import LoggedIn.Home.Msg as HomeMsg -import LoggedIn.Home.Update as HomeUpdate -import LoggedIn.Home.Model as HomeModel +import LoggedIn.Home.Msg as Home +import LoggedIn.Home.Update as Home +import LoggedIn.Home.Model as Home -import LoggedIn.Income.Msg as IncomeMsg -import LoggedIn.Income.Update as IncomeUpdate +import LoggedIn.Income.Update as Income +import LoggedIn.Income.Model as Income -import LoggedIn.Income.Model as IncomeModel +import LoggedIn.Category.Update as Categories +import LoggedIn.Category.Model as Categories -import Utils.Tuple as Tuple import Utils.Cmd exposing ((:>)) update : Model -> LoggedInMsg.Msg -> LoggedInModel.Model -> (LoggedInModel.Model, Cmd LoggedInMsg.Msg) @@ -45,32 +47,51 @@ update model msg loggedIn = ) LoggedInMsg.HomeMsg homeMsg -> - case HomeUpdate.update loggedData homeMsg loggedIn.home of + case Home.update loggedData homeMsg loggedIn.home of (home, effects) -> ( { loggedIn | home = home } , Cmd.map LoggedInMsg.HomeMsg effects ) LoggedInMsg.IncomeMsg incomeMsg -> - case IncomeUpdate.update loggedData incomeMsg loggedIn.income of + case Income.update loggedData incomeMsg loggedIn.income of (income, cmd) -> ( { loggedIn | income = income } , Cmd.map LoggedInMsg.IncomeMsg cmd ) - LoggedInMsg.ValidateCreatePayment paymentId name cost date frequency -> - update model (LoggedInMsg.HomeMsg <| HomeMsg.SearchMsg (Form.Reset (HomeModel.searchInitial frequency))) loggedIn - :> update model (LoggedInMsg.HomeMsg <| HomeMsg.UpdatePage 1) + LoggedInMsg.CategoriesMsg categoriesMsg -> + case Categories.update loggedData categoriesMsg loggedIn.category of + (category, cmd) -> + ( { loggedIn | category = category } + , Cmd.map LoggedInMsg.CategoriesMsg cmd + ) + + LoggedInMsg.ValidateCreatePayment paymentId name cost date category frequency -> + update model (LoggedInMsg.HomeMsg <| Home.SearchMsg (Form.Reset (Home.searchInitial frequency))) loggedIn + :> update model (LoggedInMsg.HomeMsg <| Home.UpdatePage 1) :> (\loggedIn -> let newPayment = Payment paymentId name cost date loggedIn.me frequency - in ( { loggedIn | payments = newPayment :: loggedIn.payments } + in ( { loggedIn + | payments = newPayment :: loggedIn.payments + , paymentCategories = PaymentCategory.set name category loggedIn.paymentCategories + } , Cmd.none ) ) - LoggedInMsg.ValidateEditPayment paymentId name cost date frequency -> + LoggedInMsg.ValidateEditPayment paymentId name cost date category frequency -> let updatedPayment = Payment paymentId name cost date loggedIn.me frequency - in ( { loggedIn | payments = Payment.edit updatedPayment loggedIn.payments } + mbOldPayment = Payment.find paymentId loggedIn.payments + in ( { loggedIn + | payments = Payment.edit updatedPayment loggedIn.payments + , paymentCategories = + case mbOldPayment of + Just oldPayment -> + PaymentCategory.update oldPayment.name name category loggedIn.paymentCategories + Nothing -> + loggedData.paymentCategories + } , Cmd.none ) @@ -86,7 +107,7 @@ update model msg loggedIn = ) in if switchToPunctual then - update model (LoggedInMsg.HomeMsg <| HomeMsg.SearchMsg (Form.Reset (HomeModel.searchInitial Punctual))) loggedIn + update model (LoggedInMsg.HomeMsg <| Home.SearchMsg (Form.Reset (Home.searchInitial Punctual))) loggedIn :> (\loggedIn -> ( { loggedIn | payments = payments } , Cmd.none @@ -99,20 +120,12 @@ update model msg loggedIn = LoggedInMsg.ValidateCreateIncome incomeId amount date -> let newIncome = { userId = loggedIn.me, amount = amount, time = Date.toTime date } - loggedInIncome = loggedIn.income - in ( { loggedIn - | incomes = Dict.insert incomeId newIncome loggedIn.incomes - , income = { loggedInIncome | addIncome = IncomeModel.initForm } - } + in ( { loggedIn | incomes = Dict.insert incomeId newIncome loggedIn.incomes } , Cmd.none ) LoggedInMsg.ValidateEditIncome incomeId amount date -> - let updatedIncome = Income loggedIn.me (Date.toTime date) amount - updateIncome mbIncome = - case mbIncome of - Just _ -> Just updatedIncome - Nothing -> Just updatedIncome + let updateIncome _ = Just <| Income loggedIn.me (Date.toTime date) amount in ( { loggedIn | incomes = Dict.update incomeId updateIncome loggedIn.incomes } , Cmd.none ) @@ -121,3 +134,18 @@ update model msg loggedIn = ( { loggedIn | incomes = Dict.remove incomeId loggedIn.incomes } , Cmd.none ) + + LoggedInMsg.ValidateCreateCategory categoryId name color -> + let newCategory = { name = name, color = color } + in ( { loggedIn | categories = Dict.insert categoryId newCategory loggedIn.categories } + , Cmd.none + ) + + LoggedInMsg.ValidateEditCategory categoryId name color -> + let updateCategory _ = Just <| Category name color + in ( { loggedIn | categories = Dict.update categoryId updateCategory loggedIn.categories } , Cmd.none) + + LoggedInMsg.ValidateDeleteCategory categoryId -> + ( { loggedIn | categories = Dict.remove categoryId loggedIn.categories } + , Cmd.none + ) diff --git a/src/client/elm/LoggedIn/View.elm b/src/client/elm/LoggedIn/View.elm index a1fa3f0..2e42a73 100644 --- a/src/client/elm/LoggedIn/View.elm +++ b/src/client/elm/LoggedIn/View.elm @@ -9,13 +9,15 @@ import Page import Msg exposing (Msg) import Model exposing (Model) +import Model.Translations exposing (getMessage) import LoggedData import LoggedIn.Model as LoggedInModel -import LoggedIn.Home.View as HomeView -import LoggedIn.Income.View as UserView -import LoggedIn.Stat.View as StatView +import LoggedIn.Home.View as Home +import LoggedIn.Income.View as Income +import LoggedIn.Category.View as Categories +import LoggedIn.Stat.View as Stat view : Model -> LoggedInModel.Model -> Html Msg view model loggedIn = @@ -23,7 +25,9 @@ view model loggedIn = [ class "loggedIn" ] [ let loggedData = LoggedData.build model loggedIn in case model.page of - Page.Home -> HomeView.view loggedData loggedIn.home - Page.Income -> UserView.view loggedData loggedIn.income - Page.Statistics -> StatView.view loggedData + Page.Home -> Home.view loggedData loggedIn.home + Page.Income -> Income.view loggedData loggedIn.income + Page.Categories -> Categories.view loggedData loggedIn.category + Page.Statistics -> Stat.view loggedData + Page.NotFound -> div [] [ text (getMessage model.translations "PageNotFound") ] ] -- cgit v1.2.3