From 902acfbdbcc1d59941399753e887479e586e2748 Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 26 Mar 2017 23:16:28 +0200 Subject: Improve form validation - Trim names - Income amount accepted from 0 - Validate colors --- src/client/Dialog/AddCategory/Model.elm | 8 +- src/client/Dialog/AddCategory/View.elm | 6 +- src/client/Dialog/AddIncome/Model.elm | 2 +- src/client/Dialog/AddPayment/View.elm | 4 +- src/client/LoggedIn/Category/Model.elm | 36 -------- src/client/LoggedIn/Category/Msg.elm | 9 -- src/client/LoggedIn/Category/Table.elm | 123 ++++++++++++++++++++++++++ src/client/LoggedIn/Category/Table/View.elm | 124 -------------------------- src/client/LoggedIn/Category/Update.elm | 24 ------ src/client/LoggedIn/Category/View.elm | 9 +- src/client/LoggedIn/Income/Model.elm | 36 -------- src/client/LoggedIn/Income/Msg.elm | 9 -- src/client/LoggedIn/Income/Table.elm | 128 +++++++++++++++++++++++++++ src/client/LoggedIn/Income/Update.elm | 24 ------ src/client/LoggedIn/Income/View.elm | 12 +-- src/client/LoggedIn/Income/View/Table.elm | 129 ---------------------------- src/client/LoggedIn/Model.elm | 6 -- src/client/LoggedIn/Msg.elm | 4 - src/client/LoggedIn/Update.elm | 20 ----- src/client/LoggedIn/View.elm | 4 +- src/client/Validation.elm | 18 ++++ src/server/Model/Message/Key.hs | 2 + src/server/Model/Message/Translations.hs | 12 ++- 23 files changed, 303 insertions(+), 446 deletions(-) delete mode 100644 src/client/LoggedIn/Category/Model.elm delete mode 100644 src/client/LoggedIn/Category/Msg.elm create mode 100644 src/client/LoggedIn/Category/Table.elm delete mode 100644 src/client/LoggedIn/Category/Table/View.elm delete mode 100644 src/client/LoggedIn/Category/Update.elm delete mode 100644 src/client/LoggedIn/Income/Model.elm delete mode 100644 src/client/LoggedIn/Income/Msg.elm create mode 100644 src/client/LoggedIn/Income/Table.elm delete mode 100644 src/client/LoggedIn/Income/Update.elm delete mode 100644 src/client/LoggedIn/Income/View/Table.elm diff --git a/src/client/Dialog/AddCategory/Model.elm b/src/client/Dialog/AddCategory/Model.elm index 7496c2b..3b70482 100644 --- a/src/client/Dialog/AddCategory/Model.elm +++ b/src/client/Dialog/AddCategory/Model.elm @@ -8,14 +8,16 @@ module Dialog.AddCategory.Model exposing ) import Date exposing (Date) -import View.Date as Date +import Dict import Form exposing (Form) import Form.Field as Field exposing (Field) import Form.Validate as Validate exposing (Validation) +import Model.Category exposing (Categories, Category, CategoryId) import Model.Translations exposing (Translations) -import Model.Category exposing (Category, CategoryId) +import Validation +import View.Date as Date type alias Model = { id : Maybe CategoryId @@ -49,4 +51,4 @@ validation = Validate.map3 Model (Validate.field "id" (Validate.maybe Validate.int)) (Validate.field "name" (Validate.string |> Validate.andThen Validate.nonEmpty)) - (Validate.field "color" (Validate.string |> Validate.andThen Validate.nonEmpty)) + (Validate.field "color" Validation.color) diff --git a/src/client/Dialog/AddCategory/View.elm b/src/client/Dialog/AddCategory/View.elm index 6c02351..dc55b60 100644 --- a/src/client/Dialog/AddCategory/View.elm +++ b/src/client/Dialog/AddCategory/View.elm @@ -45,7 +45,7 @@ button loggedData initialForm title buttonContent tooltip = Just message -> Tooltip.show Msg.Tooltip message Nothing -> [] ) - ++ [ onClick (Msg.Dialog <| Dialog.OpenWithUpdate dialogConfig (DialogMsg.Init "categoryname" (DialogMsg.AddCategoryMsg <| Form.Reset initialForm))) ] + ++ [ onClick (Msg.Dialog <| Dialog.OpenWithUpdate dialogConfig (DialogMsg.Init "categoryname" (DialogMsg.AddCategoryMsg (Form.Reset initialForm)))) ] ) [ buttonContent ] @@ -65,8 +65,8 @@ submitForm addCategory = Just data -> case data.id of Just categoryId -> - Msg.Dialog <| Dialog.UpdateAndClose <| Msg.EditCategory categoryId data.name data.color + Msg.Dialog <| Dialog.UpdateAndClose <| Msg.EditCategory categoryId (String.trim data.name) data.color Nothing -> - Msg.Dialog <| Dialog.UpdateAndClose <| Msg.CreateCategory data.name data.color + Msg.Dialog <| Dialog.UpdateAndClose <| Msg.CreateCategory (String.trim data.name) data.color Nothing -> Msg.Dialog <| Dialog.Update <| DialogMsg.AddCategoryMsg <| Form.Submit diff --git a/src/client/Dialog/AddIncome/Model.elm b/src/client/Dialog/AddIncome/Model.elm index ad7b25a..5e2ccf1 100644 --- a/src/client/Dialog/AddIncome/Model.elm +++ b/src/client/Dialog/AddIncome/Model.elm @@ -49,5 +49,5 @@ validation : Validation String Model validation = Validate.map3 Model (Validate.field "id" (Validate.maybe Validate.int)) - (Validate.field "amount" (Validate.int |> Validate.andThen (Validate.minInt 1))) + (Validate.field "amount" (Validate.int |> Validate.andThen (Validate.minInt 0))) (Validate.field "date" Validation.date) diff --git a/src/client/Dialog/AddPayment/View.elm b/src/client/Dialog/AddPayment/View.elm index 078d5b7..66c9f00 100644 --- a/src/client/Dialog/AddPayment/View.elm +++ b/src/client/Dialog/AddPayment/View.elm @@ -86,10 +86,10 @@ submitForm categories paymentCategories addPayment = Just paymentId -> Msg.Dialog <| Dialog.UpdateAndClose - <| Msg.EditPayment paymentId data.name data.cost data.date data.category data.frequency + <| Msg.EditPayment paymentId (String.trim data.name) data.cost data.date data.category data.frequency Nothing -> Msg.Dialog <| Dialog.UpdateAndClose - <| Msg.CreatePayment data.name data.cost data.date data.category data.frequency + <| Msg.CreatePayment (String.trim data.name) data.cost data.date data.category data.frequency Nothing -> Msg.Dialog <| Dialog.Update <| DialogMsg.AddPaymentMsg categories paymentCategories <| Form.Submit diff --git a/src/client/LoggedIn/Category/Model.elm b/src/client/LoggedIn/Category/Model.elm deleted file mode 100644 index 7092fc4..0000000 --- a/src/client/LoggedIn/Category/Model.elm +++ /dev/null @@ -1,36 +0,0 @@ -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/LoggedIn/Category/Msg.elm b/src/client/LoggedIn/Category/Msg.elm deleted file mode 100644 index 3184297..0000000 --- a/src/client/LoggedIn/Category/Msg.elm +++ /dev/null @@ -1,9 +0,0 @@ -module LoggedIn.Category.Msg exposing - ( Msg(..) - ) - -import Form exposing (Form) - -type Msg = - NoOp - | AddCategoryMsg Form.Msg diff --git a/src/client/LoggedIn/Category/Table.elm b/src/client/LoggedIn/Category/Table.elm new file mode 100644 index 0000000..9405e57 --- /dev/null +++ b/src/client/LoggedIn/Category/Table.elm @@ -0,0 +1,123 @@ +module LoggedIn.Category.Table 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 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 -> Html Msg +view loggedData = + let categories = + loggedData.categories + |> Dict.toList + |> List.sortBy (.name << Tuple.second) + in div + [ class "table" ] + [ div + [ class "lines" ] + ( headerLine loggedData :: List.map (paymentLine loggedData) 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 -> (CategoryId, Category) -> Html Msg +paymentLine loggedData (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/LoggedIn/Category/Table/View.elm b/src/client/LoggedIn/Category/Table/View.elm deleted file mode 100644 index fa7a7b1..0000000 --- a/src/client/LoggedIn/Category/Table/View.elm +++ /dev/null @@ -1,124 +0,0 @@ -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/LoggedIn/Category/Update.elm b/src/client/LoggedIn/Category/Update.elm deleted file mode 100644 index 1072ef0..0000000 --- a/src/client/LoggedIn/Category/Update.elm +++ /dev/null @@ -1,24 +0,0 @@ -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/LoggedIn/Category/View.elm b/src/client/LoggedIn/Category/View.elm index 4e04fa2..bba51b7 100644 --- a/src/client/LoggedIn/Category/View.elm +++ b/src/client/LoggedIn/Category/View.elm @@ -12,13 +12,12 @@ 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 LoggedIn.Category.Table as Table import Model.Translations exposing (getMessage, getParamMessage) -view : LoggedData -> Category.Model -> Html Msg -view loggedData categoryModel = +view : LoggedData -> Html Msg +view loggedData = div [ class "categories" ] [ div @@ -31,5 +30,5 @@ view loggedData categoryModel = (text (getMessage loggedData.translations "AddCategory")) Nothing ] - , Table.view loggedData categoryModel + , Table.view loggedData ] diff --git a/src/client/LoggedIn/Income/Model.elm b/src/client/LoggedIn/Income/Model.elm deleted file mode 100644 index 7d852b9..0000000 --- a/src/client/LoggedIn/Income/Model.elm +++ /dev/null @@ -1,36 +0,0 @@ -module LoggedIn.Income.Model exposing - ( Model - , AddIncome - , init - , initForm - , validation - ) - -import Date exposing (Date) - -import Form exposing (Form) -import Form.Validate as Validate exposing (Validation) -import Validation - -type alias Model = - { addIncome : Form String AddIncome - } - -type alias AddIncome = - { amount : Int - , date : Date - } - -init : Model -init = - { addIncome = initForm - } - -initForm : Form String AddIncome -initForm = Form.initial [] validation - -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/LoggedIn/Income/Msg.elm b/src/client/LoggedIn/Income/Msg.elm deleted file mode 100644 index 0a09dad..0000000 --- a/src/client/LoggedIn/Income/Msg.elm +++ /dev/null @@ -1,9 +0,0 @@ -module LoggedIn.Income.Msg exposing - ( Msg(..) - ) - -import Form exposing (Form) - -type Msg = - NoOp - | AddIncomeMsg Form.Msg diff --git a/src/client/LoggedIn/Income/Table.elm b/src/client/LoggedIn/Income/Table.elm new file mode 100644 index 0000000..f10a552 --- /dev/null +++ b/src/client/LoggedIn/Income/Table.elm @@ -0,0 +1,128 @@ +module LoggedIn.Income.Table 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.AddIncome.Model as AddIncome +import Dialog.AddIncome.View as AddIncome + +import Tooltip + +import Msg exposing (Msg) + +import LoggedData exposing (LoggedData) + +import LoggedIn.Msg as LoggedInMsg + +import View.Date as Date +import LoggedIn.View.Format as Format + +import Model.User exposing (getUserName) +import Model.Income as Income exposing (..) +import Model.Translations exposing (getMessage) + +view : LoggedData -> Html Msg +view loggedData = + let incomes = + loggedData.incomes + |> Dict.toList + |> List.sortBy (.time << Tuple.second) + |> List.reverse + in div + [ class "table" ] + [ div + [ class "lines" ] + ( headerLine loggedData :: List.map (paymentLine loggedData) incomes) + , if List.isEmpty (Dict.toList loggedData.incomes) + then + div + [ class "emptyTableMsg" ] + [ text <| getMessage loggedData.translations "NoIncome" ] + else + text "" + ] + +headerLine : LoggedData -> Html Msg +headerLine loggedData = + div + [ class "header" ] + [ div [ class "cell name" ] [ text <| getMessage loggedData.translations "Name" ] + , div [ class "cell income" ] [ text <| getMessage loggedData.translations "Income" ] + , div [ class "cell date" ] [ text <| getMessage loggedData.translations "Date" ] + , div [ class "cell" ] [] + , div [ class "cell" ] [] + , div [ class "cell" ] [] + ] + +paymentLine : LoggedData -> (IncomeId, Income) -> Html Msg +paymentLine loggedData (incomeId, income) = + div + [ class "row" ] + [ div + [ class "cell name" ] + [ income.userId + |> getUserName loggedData.users + |> Maybe.withDefault "−" + |> text + ] + , div + [ class "cell income" ] + [ text (Format.price loggedData.conf income.amount) ] + , div + [ class "cell date" ] + [ text (Date.longView (Date.fromTime income.time) loggedData.translations) ] + , div + [ class "cell button" ] + [ let currentDate = Date.fromTime loggedData.currentTime + in AddIncome.button + loggedData + (AddIncome.initialClone loggedData.translations currentDate income) + "CloneIncome" + (FontAwesome.clone Color.chestnutRose 18) + (Just (getMessage loggedData.translations "Clone")) + ] + , div + [ class "cell button" ] + [ if loggedData.me /= income.userId + then + text "" + else + AddIncome.button + loggedData + (AddIncome.initialEdit loggedData.translations incomeId income) + "EditIncome" + (FontAwesome.pencil Color.chestnutRose 18) + (Just (getMessage loggedData.translations "Edit")) + ] + , div + [ class "cell button" ] + [ if loggedData.me /= income.userId + then + text "" + else + let dialogConfig = + { className = "deleteIncomeDialog" + , title = getMessage loggedData.translations "ConfirmIncomeDelete" + , body = always <| text "" + , confirm = getMessage loggedData.translations "Confirm" + , confirmMsg = always <| Msg.Dialog <| Dialog.UpdateAndClose <| Msg.DeleteIncome incomeId + , 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 ] + ] + ] diff --git a/src/client/LoggedIn/Income/Update.elm b/src/client/LoggedIn/Income/Update.elm deleted file mode 100644 index 0023c76..0000000 --- a/src/client/LoggedIn/Income/Update.elm +++ /dev/null @@ -1,24 +0,0 @@ -module LoggedIn.Income.Update exposing - ( update - ) - -import Form exposing (Form) - -import LoggedData exposing (LoggedData) - -import LoggedIn.Income.Model as Income -import LoggedIn.Income.Msg as Income - -update : LoggedData -> Income.Msg -> Income.Model -> (Income.Model, Cmd Income.Msg) -update loggedData msg model = - case msg of - - Income.NoOp -> - ( model - , Cmd.none - ) - - Income.AddIncomeMsg formMsg -> - ( { model | addIncome = Form.update Income.validation formMsg model.addIncome } - , Cmd.none - ) diff --git a/src/client/LoggedIn/Income/View.elm b/src/client/LoggedIn/Income/View.elm index 00a1646..85b0dc3 100644 --- a/src/client/LoggedIn/Income/View.elm +++ b/src/client/LoggedIn/Income/View.elm @@ -30,18 +30,14 @@ import Model.Translations exposing (getMessage, getParamMessage) import Model.Payer exposing (useIncomesFrom) import Model.User exposing (UserId, User) import Model.View as View -import LoggedIn.Income.Model as Income - -import LoggedIn.Msg as LoggedInMsg -import LoggedIn.Income.Msg as IncomeMsg import View.Date as Date import LoggedIn.View.Format as Format import View.Color as Color -import LoggedIn.Income.View.Table as Table +import LoggedIn.Income.Table as Table -view : LoggedData -> Income.Model -> Html Msg -view loggedData incomeModel = +view : LoggedData -> Html Msg +view loggedData = div [ class "income" ] [ div @@ -60,7 +56,7 @@ view loggedData incomeModel = Nothing ] ] - , Table.view loggedData incomeModel + , Table.view loggedData ] cumulativeIncomesView : LoggedData -> Time -> Html Msg diff --git a/src/client/LoggedIn/Income/View/Table.elm b/src/client/LoggedIn/Income/View/Table.elm deleted file mode 100644 index aa5e392..0000000 --- a/src/client/LoggedIn/Income/View/Table.elm +++ /dev/null @@ -1,129 +0,0 @@ -module LoggedIn.Income.View.Table 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.AddIncome.Model as AddIncome -import Dialog.AddIncome.View as AddIncome - -import Tooltip - -import Msg exposing (Msg) - -import LoggedData exposing (LoggedData) - -import LoggedIn.Msg as LoggedInMsg - -import LoggedIn.Income.Model as Income -import View.Date as Date -import LoggedIn.View.Format as Format - -import Model.User exposing (getUserName) -import Model.Income as Income exposing (..) -import Model.Translations exposing (getMessage) - -view : LoggedData -> Income.Model -> Html Msg -view loggedData incomeModel = - let incomes = - loggedData.incomes - |> Dict.toList - |> List.sortBy (.time << Tuple.second) - |> List.reverse - in div - [ class "table" ] - [ div - [ class "lines" ] - ( headerLine loggedData :: List.map (paymentLine loggedData incomeModel) incomes) - , if List.isEmpty (Dict.toList loggedData.incomes) - then - div - [ class "emptyTableMsg" ] - [ text <| getMessage loggedData.translations "NoIncome" ] - else - text "" - ] - -headerLine : LoggedData -> Html Msg -headerLine loggedData = - div - [ class "header" ] - [ div [ class "cell name" ] [ text <| getMessage loggedData.translations "Name" ] - , div [ class "cell income" ] [ text <| getMessage loggedData.translations "Income" ] - , div [ class "cell date" ] [ text <| getMessage loggedData.translations "Date" ] - , div [ class "cell" ] [] - , div [ class "cell" ] [] - , div [ class "cell" ] [] - ] - -paymentLine : LoggedData -> Income.Model -> (IncomeId, Income) -> Html Msg -paymentLine loggedData incomeModel (incomeId, income) = - div - [ class "row" ] - [ div - [ class "cell name" ] - [ income.userId - |> getUserName loggedData.users - |> Maybe.withDefault "−" - |> text - ] - , div - [ class "cell income" ] - [ text (Format.price loggedData.conf income.amount) ] - , div - [ class "cell date" ] - [ text (Date.longView (Date.fromTime income.time) loggedData.translations) ] - , div - [ class "cell button" ] - [ let currentDate = Date.fromTime loggedData.currentTime - in AddIncome.button - loggedData - (AddIncome.initialClone loggedData.translations currentDate income) - "CloneIncome" - (FontAwesome.clone Color.chestnutRose 18) - (Just (getMessage loggedData.translations "Clone")) - ] - , div - [ class "cell button" ] - [ if loggedData.me /= income.userId - then - text "" - else - AddIncome.button - loggedData - (AddIncome.initialEdit loggedData.translations incomeId income) - "EditIncome" - (FontAwesome.pencil Color.chestnutRose 18) - (Just (getMessage loggedData.translations "Edit")) - ] - , div - [ class "cell button" ] - [ if loggedData.me /= income.userId - then - text "" - else - let dialogConfig = - { className = "deleteIncomeDialog" - , title = getMessage loggedData.translations "ConfirmIncomeDelete" - , body = always <| text "" - , confirm = getMessage loggedData.translations "Confirm" - , confirmMsg = always <| Msg.Dialog <| Dialog.UpdateAndClose <| Msg.DeleteIncome incomeId - , 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 ] - ] - ] diff --git a/src/client/LoggedIn/Model.elm b/src/client/LoggedIn/Model.elm index 6bcb0b2..6c858a6 100644 --- a/src/client/LoggedIn/Model.elm +++ b/src/client/LoggedIn/Model.elm @@ -13,13 +13,9 @@ import Model.Category exposing (Categories) import Model.PaymentCategory exposing (PaymentCategories) import LoggedIn.Home.Model as Home -import LoggedIn.Income.Model as Income -import LoggedIn.Category.Model as Categories type alias Model = { home : Home.Model - , income : Income.Model - , category : Categories.Model , users : Users , me : UserId , payments : Payments @@ -31,8 +27,6 @@ type alias Model = init : Init -> Model init initData = { home = Home.init - , income = Income.init - , category = Categories.init , users = initData.users , me = initData.me , payments = initData.payments diff --git a/src/client/LoggedIn/Msg.elm b/src/client/LoggedIn/Msg.elm index a1379a6..a128cff 100644 --- a/src/client/LoggedIn/Msg.elm +++ b/src/client/LoggedIn/Msg.elm @@ -9,14 +9,10 @@ import Model.Income exposing (IncomeId) import Model.Category exposing (CategoryId) import LoggedIn.Home.Msg as Home -import LoggedIn.Income.Msg as Income -import LoggedIn.Category.Msg as Categories type Msg = NoOp | 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 diff --git a/src/client/LoggedIn/Update.elm b/src/client/LoggedIn/Update.elm index f5ce7ea..1359e1a 100644 --- a/src/client/LoggedIn/Update.elm +++ b/src/client/LoggedIn/Update.elm @@ -28,12 +28,6 @@ import LoggedIn.Home.Msg as Home import LoggedIn.Home.Update as Home import LoggedIn.Home.Model as Home -import LoggedIn.Income.Update as Income -import LoggedIn.Income.Model as Income - -import LoggedIn.Category.Update as Categories -import LoggedIn.Category.Model as Categories - import Utils.Cmd exposing ((:>)) update : Model -> LoggedInMsg.Msg -> LoggedInModel.Model -> (LoggedInModel.Model, Cmd LoggedInMsg.Msg) @@ -53,20 +47,6 @@ update model msg loggedIn = , Cmd.map LoggedInMsg.HomeMsg effects ) - LoggedInMsg.IncomeMsg incomeMsg -> - case Income.update loggedData incomeMsg loggedIn.income of - (income, cmd) -> - ( { loggedIn | income = income } - , Cmd.map LoggedInMsg.IncomeMsg cmd - ) - - 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) diff --git a/src/client/LoggedIn/View.elm b/src/client/LoggedIn/View.elm index 2e42a73..ddc85d5 100644 --- a/src/client/LoggedIn/View.elm +++ b/src/client/LoggedIn/View.elm @@ -26,8 +26,8 @@ view model loggedIn = [ let loggedData = LoggedData.build model loggedIn in case model.page of Page.Home -> Home.view loggedData loggedIn.home - Page.Income -> Income.view loggedData loggedIn.income - Page.Categories -> Categories.view loggedData loggedIn.category + Page.Income -> Income.view loggedData + Page.Categories -> Categories.view loggedData Page.Statistics -> Stat.view loggedData Page.NotFound -> div [] [ text (getMessage model.translations "PageNotFound") ] ] diff --git a/src/client/Validation.elm b/src/client/Validation.elm index 4781c3d..de27963 100644 --- a/src/client/Validation.elm +++ b/src/client/Validation.elm @@ -2,15 +2,19 @@ module Validation exposing ( cost , date , category + , color + , new ) import Date exposing (Date) import Date.Extra.Core exposing (intToMonth) import Date.Extra.Create exposing (dateFromFields) import Dict +import Regex import String exposing (toInt, split) import Form.Validate as Validate exposing (Validation) +import Form.Error as Error exposing (ErrorValue(CustomError)) import Model.Category exposing (Categories, CategoryId) @@ -45,3 +49,17 @@ category categories = Err _ -> Err (Validate.customError "InvalidCategory") ) + +color : Validation String String +color = + Validate.customValidation Validate.string (\str -> + if Regex.contains (Regex.regex "^#[0-9a-fA-F]{6}$") str + then Ok str + else Err (Validate.customError "InvalidColor") + ) + +new : List x -> x -> Validation String x +new xs x field = + if List.member x xs + then Err (Error.value <| CustomError "AlreadyExists") + else Ok x diff --git a/src/server/Model/Message/Key.hs b/src/server/Model/Message/Key.hs index 79ccf39..efe8aaa 100644 --- a/src/server/Model/Message/Key.hs +++ b/src/server/Model/Message/Key.hs @@ -130,6 +130,8 @@ data Key = | CostMustNotBeNull | InvalidInt | InvalidCategory + | InvalidColor + | AlreadyExists | SmallerIntThan | GreaterIntThan diff --git a/src/server/Model/Message/Translations.hs b/src/server/Model/Message/Translations.hs index 16fc3fd..90f509a 100644 --- a/src/server/Model/Message/Translations.hs +++ b/src/server/Model/Message/Translations.hs @@ -350,7 +350,7 @@ m l Color = m l UsedCategory = case l of English -> "This category is currently being used" - French -> "Cette catégorie est utilisée actuellement" + French -> "Cette catégorie est actuellement utilisée" -- Statistics @@ -513,6 +513,16 @@ m l InvalidCategory = English -> "Invalid category" French -> "Catégorie invalide" +m l InvalidColor = + case l of + English -> "Invalid color" + French -> "Couleur invalide" + +m l AlreadyExists = + case l of + English -> "Dupplicate field" + French -> "Doublon" + m l SmallerIntThan = case l of English -> "Integer bigger than {1} or equal required" -- cgit v1.2.3