From 04c59f08f100ba6a0658d1f2b357f7d8b1e14218 Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 13 Oct 2019 22:38:35 +0200 Subject: Show income table --- client/src/View/Income/Income.hs | 68 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 client/src/View/Income/Income.hs (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs new file mode 100644 index 0000000..5e9ce1d --- /dev/null +++ b/client/src/View/Income/Income.hs @@ -0,0 +1,68 @@ +module View.Income.Income + ( view + , IncomeIn(..) + ) where + +import qualified Data.List as L +import qualified Data.Maybe as Maybe +import Data.Text (Text) +import qualified Data.Text as T +import Reflex.Dom (MonadWidget) +import qualified Reflex.Dom as R + +import Common.Model (Income (..), Init (..), User (..)) +import qualified Common.Model as CM +import qualified Common.Msg as Msg +import qualified Common.View.Format as Format +import Component (TableIn (..)) +import qualified Component + +data IncomeIn = IncomeIn + { _incomeIn_init :: Init + } + +view :: forall t m. MonadWidget t m => IncomeIn -> m () +view incomeIn = + R.elClass "main" "income" $ do + + R.divClass "withMargin" $ + R.divClass "titleButton" $ + R.el "h1" $ + R.text $ + Msg.get Msg.Income_MonthlyNet + + Component.table $ TableIn + { _tableIn_headerLabel = headerLabel + , _tableIn_rows = + R.constDyn + . reverse + . L.sortOn _income_date + . _init_incomes + . _incomeIn_init + $ incomeIn + , _tableIn_cell = cell (_incomeIn_init incomeIn) + } + return () + +data Header + = UserHeader + | AmountHeader + | DateHeader + deriving (Eq, Show, Bounded, Enum) + +headerLabel :: Header -> Text +headerLabel UserHeader = Msg.get Msg.Income_Name +headerLabel DateHeader = Msg.get Msg.Income_Date +headerLabel AmountHeader = Msg.get Msg.Income_Amount + +cell :: Init -> Header -> Income -> Text +cell init header income = + case header of + UserHeader -> + Maybe.fromMaybe "" . fmap _user_name $ CM.findUser (_income_userId income) (_init_users init) + + DateHeader -> + Format.longDay . _income_date $ income + + AmountHeader -> + Format.price (_init_currency init) . _income_amount $ income -- cgit v1.2.3 From 284214d3af39143fdbeca57ffa4864389e7d517a Mon Sep 17 00:00:00 2001 From: Joris Date: Mon, 14 Oct 2019 09:10:33 +0200 Subject: Show cumulative incomes per user in income page --- client/src/View/Income/Income.hs | 71 ++++++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 17 deletions(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index 5e9ce1d..d0c0a45 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -3,19 +3,22 @@ module View.Income.Income , IncomeIn(..) ) where -import qualified Data.List as L -import qualified Data.Maybe as Maybe -import Data.Text (Text) -import qualified Data.Text as T -import Reflex.Dom (MonadWidget) -import qualified Reflex.Dom as R - -import Common.Model (Income (..), Init (..), User (..)) -import qualified Common.Model as CM -import qualified Common.Msg as Msg -import qualified Common.View.Format as Format -import Component (TableIn (..)) +import Control.Monad.IO.Class (liftIO) +import qualified Data.List as L +import qualified Data.Maybe as Maybe +import Data.Text (Text) +import qualified Data.Text as T +import qualified Data.Time.Clock as Clock +import Reflex.Dom (MonadWidget) +import qualified Reflex.Dom as R + +import Common.Model (Income (..), Init (..), User (..)) +import qualified Common.Model as CM +import qualified Common.Msg as Msg +import qualified Common.View.Format as Format +import Component (TableIn (..)) import qualified Component +import qualified Util.Date as DateUtil data IncomeIn = IncomeIn { _incomeIn_init :: Init @@ -25,11 +28,7 @@ view :: forall t m. MonadWidget t m => IncomeIn -> m () view incomeIn = R.elClass "main" "income" $ do - R.divClass "withMargin" $ - R.divClass "titleButton" $ - R.el "h1" $ - R.text $ - Msg.get Msg.Income_MonthlyNet + header (_incomeIn_init incomeIn) Component.table $ TableIn { _tableIn_headerLabel = headerLabel @@ -42,8 +41,46 @@ view incomeIn = $ incomeIn , _tableIn_cell = cell (_incomeIn_init incomeIn) } + return () +header :: forall t m. MonadWidget t m => Init -> m () +header init = + R.divClass "withMargin" $ do + + currentTime <- liftIO Clock.getCurrentTime + + Maybe.fromMaybe R.blank $ + flip fmap useIncomesFrom $ \since -> + R.el "div" $ do + + R.el "h1" $ do + day <- liftIO $ DateUtil.utcToLocalDay since + R.text $ Msg.get (Msg.Income_CumulativeSince (Format.longDay day)) + + R.el "ul" $ + flip mapM_ (_init_users init) $ \user -> + R.el "li" $ + R.text $ do + let incomes = filter ((==) (_user_id user) . _income_userId) (_init_incomes init) + T.intercalate " " + [ _user_name user + , "−" + , Format.price (_init_currency init) $ + CM.cumulativeIncomesSince currentTime since incomes + ] + + R.divClass "titleButton" $ + R.el "h1" $ + R.text $ + Msg.get Msg.Income_MonthlyNet + + where + useIncomesFrom = CM.useIncomesFrom + (map _user_id $_init_users init) + (_init_incomes init) + (_init_payments init) + data Header = UserHeader | AmountHeader -- cgit v1.2.3 From 0b40b6b5583b5c437f83e61bf8913f2b4c447b24 Mon Sep 17 00:00:00 2001 From: Joris Date: Sat, 19 Oct 2019 09:36:03 +0200 Subject: Include pages into table component --- client/src/View/Income/Income.hs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index d0c0a45..0fdd7d3 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -40,6 +40,8 @@ view incomeIn = . _incomeIn_init $ incomeIn , _tableIn_cell = cell (_incomeIn_init incomeIn) + , _tableIn_perPage = 7 + , _tableIn_resetPage = R.never } return () -- cgit v1.2.3 From 6e9e34e92a244ab6c38d135d46f9f5bb01391906 Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 20 Oct 2019 09:51:52 +0200 Subject: Move income header and income table views into separate components --- client/src/View/Income/Income.hs | 100 +++++---------------------------------- 1 file changed, 12 insertions(+), 88 deletions(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index 0fdd7d3..b0c6f0b 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -3,22 +3,14 @@ module View.Income.Income , IncomeIn(..) ) where -import Control.Monad.IO.Class (liftIO) -import qualified Data.List as L -import qualified Data.Maybe as Maybe -import Data.Text (Text) -import qualified Data.Text as T -import qualified Data.Time.Clock as Clock -import Reflex.Dom (MonadWidget) -import qualified Reflex.Dom as R +import Reflex.Dom (MonadWidget) +import qualified Reflex.Dom as R -import Common.Model (Income (..), Init (..), User (..)) -import qualified Common.Model as CM -import qualified Common.Msg as Msg -import qualified Common.View.Format as Format -import Component (TableIn (..)) -import qualified Component -import qualified Util.Date as DateUtil +import Common.Model (Init) +import View.Income.Header (HeaderIn (..)) +import qualified View.Income.Header as Header +import View.Income.Table (IncomeTableIn (..)) +import qualified View.Income.Table as Table data IncomeIn = IncomeIn { _incomeIn_init :: Init @@ -28,80 +20,12 @@ view :: forall t m. MonadWidget t m => IncomeIn -> m () view incomeIn = R.elClass "main" "income" $ do - header (_incomeIn_init incomeIn) + Header.view $ HeaderIn + { _headerIn_init = _incomeIn_init incomeIn + } - Component.table $ TableIn - { _tableIn_headerLabel = headerLabel - , _tableIn_rows = - R.constDyn - . reverse - . L.sortOn _income_date - . _init_incomes - . _incomeIn_init - $ incomeIn - , _tableIn_cell = cell (_incomeIn_init incomeIn) - , _tableIn_perPage = 7 - , _tableIn_resetPage = R.never + Table.view $ IncomeTableIn + { _tableIn_init = _incomeIn_init incomeIn } return () - -header :: forall t m. MonadWidget t m => Init -> m () -header init = - R.divClass "withMargin" $ do - - currentTime <- liftIO Clock.getCurrentTime - - Maybe.fromMaybe R.blank $ - flip fmap useIncomesFrom $ \since -> - R.el "div" $ do - - R.el "h1" $ do - day <- liftIO $ DateUtil.utcToLocalDay since - R.text $ Msg.get (Msg.Income_CumulativeSince (Format.longDay day)) - - R.el "ul" $ - flip mapM_ (_init_users init) $ \user -> - R.el "li" $ - R.text $ do - let incomes = filter ((==) (_user_id user) . _income_userId) (_init_incomes init) - T.intercalate " " - [ _user_name user - , "−" - , Format.price (_init_currency init) $ - CM.cumulativeIncomesSince currentTime since incomes - ] - - R.divClass "titleButton" $ - R.el "h1" $ - R.text $ - Msg.get Msg.Income_MonthlyNet - - where - useIncomesFrom = CM.useIncomesFrom - (map _user_id $_init_users init) - (_init_incomes init) - (_init_payments init) - -data Header - = UserHeader - | AmountHeader - | DateHeader - deriving (Eq, Show, Bounded, Enum) - -headerLabel :: Header -> Text -headerLabel UserHeader = Msg.get Msg.Income_Name -headerLabel DateHeader = Msg.get Msg.Income_Date -headerLabel AmountHeader = Msg.get Msg.Income_Amount - -cell :: Init -> Header -> Income -> Text -cell init header income = - case header of - UserHeader -> - Maybe.fromMaybe "" . fmap _user_name $ CM.findUser (_income_userId income) (_init_users init) - - DateHeader -> - Format.longDay . _income_date $ income - - AmountHeader -> - Format.price (_init_currency init) . _income_amount $ income -- cgit v1.2.3 From 7aadcc97f9df0e2daccbe8a8726d8bc6c63d67f4 Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 20 Oct 2019 12:02:21 +0200 Subject: Add income --- client/src/View/Income/Income.hs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index b0c6f0b..167aedf 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -3,11 +3,11 @@ module View.Income.Income , IncomeIn(..) ) where -import Reflex.Dom (MonadWidget) +import Reflex.Dom (Dynamic, MonadWidget) import qualified Reflex.Dom as R -import Common.Model (Init) -import View.Income.Header (HeaderIn (..)) +import Common.Model (Init (..)) +import View.Income.Header (HeaderIn (..), HeaderOut (..)) import qualified View.Income.Header as Header import View.Income.Table (IncomeTableIn (..)) import qualified View.Income.Table as Table @@ -20,12 +20,21 @@ view :: forall t m. MonadWidget t m => IncomeIn -> m () view incomeIn = R.elClass "main" "income" $ do - Header.view $ HeaderIn - { _headerIn_init = _incomeIn_init incomeIn - } + rec + + incomes <- R.foldDyn + (:) + (_init_incomes . _incomeIn_init $ incomeIn) + (_headerOut_addIncome header) + + header <- Header.view $ HeaderIn + { _headerIn_init = _incomeIn_init incomeIn + , _headerIn_incomes = incomes + } Table.view $ IncomeTableIn { _tableIn_init = _incomeIn_init incomeIn + , _tableIn_incomes = incomes } return () -- cgit v1.2.3 From 602c52acfcfa494b07fec05c20b317b60ea8a6f3 Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 20 Oct 2019 21:31:57 +0200 Subject: Load init data per page with AJAX --- client/src/View/Income/Income.hs | 73 +++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 20 deletions(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index 167aedf..91682a0 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -1,40 +1,73 @@ module View.Income.Income - ( view + ( init + , view , IncomeIn(..) ) where +import Prelude hiding (init) import Reflex.Dom (Dynamic, MonadWidget) import qualified Reflex.Dom as R -import Common.Model (Init (..)) +import Common.Model (Currency) + +import Model.Loadable (Loadable (..)) +import qualified Model.Loadable as Loadable +import qualified Util.Ajax as AjaxUtil import View.Income.Header (HeaderIn (..), HeaderOut (..)) import qualified View.Income.Header as Header +import View.Income.Init (Init (..)) import View.Income.Table (IncomeTableIn (..)) import qualified View.Income.Table as Table -data IncomeIn = IncomeIn - { _incomeIn_init :: Init +data IncomeIn t = IncomeIn + { _incomeIn_currency :: Currency + , _incomeIn_init :: Dynamic t (Loadable Init) } -view :: forall t m. MonadWidget t m => IncomeIn -> m () -view incomeIn = - R.elClass "main" "income" $ do +init :: forall t m. MonadWidget t m => m (Dynamic t (Loadable Init)) +init = do + postBuild <- R.getPostBuild + + usersEvent <- AjaxUtil.get (R.tag (R.constant "api/users") postBuild) + users <- Loadable.fromEvent usersEvent + + incomesEvent <- AjaxUtil.get (R.tag (R.constant "api/incomes") postBuild) + incomes <- Loadable.fromEvent incomesEvent + + paymentsEvent <- AjaxUtil.get (R.tag (R.constant "api/payments") postBuild) + payments <- Loadable.fromEvent paymentsEvent + + return $ do + us <- users + is <- incomes + ps <- payments + return $ Init <$> us <*> is <*> ps + +view :: forall t m. MonadWidget t m => IncomeIn t -> m () +view incomeIn = do + R.dyn . R.ffor (_incomeIn_init incomeIn) . Loadable.view $ \init -> + + R.elClass "main" "income" $ do + + rec - rec + incomes <- R.foldDyn + (:) + (_init_incomes init) + (_headerOut_addIncome header) - incomes <- R.foldDyn - (:) - (_init_incomes . _incomeIn_init $ incomeIn) - (_headerOut_addIncome header) + header <- Header.view $ HeaderIn + { _headerIn_init = init + , _headerIn_currency = _incomeIn_currency incomeIn + , _headerIn_incomes = incomes + } - header <- Header.view $ HeaderIn - { _headerIn_init = _incomeIn_init incomeIn - , _headerIn_incomes = incomes + Table.view $ IncomeTableIn + { _tableIn_init = init + , _tableIn_currency = _incomeIn_currency incomeIn + , _tableIn_incomes = incomes } - Table.view $ IncomeTableIn - { _tableIn_init = _incomeIn_init incomeIn - , _tableIn_incomes = incomes - } + return () - return () + return () -- cgit v1.2.3 From 33e78f2ebbf5bf7b40e7aa732cc7c019f6df3f12 Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 20 Oct 2019 22:08:31 +0200 Subject: Simplify page initialization --- client/src/View/Income/Income.hs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index 91682a0..18ebe7c 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -4,14 +4,15 @@ module View.Income.Income , IncomeIn(..) ) where +import Data.Aeson (FromJSON) import Prelude hiding (init) import Reflex.Dom (Dynamic, MonadWidget) import qualified Reflex.Dom as R import Common.Model (Currency) -import Model.Loadable (Loadable (..)) -import qualified Model.Loadable as Loadable +import Loadable (Loadable (..)) +import qualified Loadable import qualified Util.Ajax as AjaxUtil import View.Income.Header (HeaderIn (..), HeaderOut (..)) import qualified View.Income.Header as Header @@ -26,17 +27,9 @@ data IncomeIn t = IncomeIn init :: forall t m. MonadWidget t m => m (Dynamic t (Loadable Init)) init = do - postBuild <- R.getPostBuild - - usersEvent <- AjaxUtil.get (R.tag (R.constant "api/users") postBuild) - users <- Loadable.fromEvent usersEvent - - incomesEvent <- AjaxUtil.get (R.tag (R.constant "api/incomes") postBuild) - incomes <- Loadable.fromEvent incomesEvent - - paymentsEvent <- AjaxUtil.get (R.tag (R.constant "api/payments") postBuild) - payments <- Loadable.fromEvent paymentsEvent - + users <- AjaxUtil.getNow "api/users" + incomes <- AjaxUtil.getNow "api/incomes" + payments <- AjaxUtil.getNow "api/payments" return $ do us <- users is <- incomes -- cgit v1.2.3 From 613ffccac4b3ab25c6d4c631fab757da0b35acf6 Mon Sep 17 00:00:00 2001 From: Joris Date: Tue, 22 Oct 2019 22:26:38 +0200 Subject: Harmonize view component code style --- client/src/View/Income/Income.hs | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index 18ebe7c..f8359bb 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -1,7 +1,7 @@ module View.Income.Income ( init , view - , IncomeIn(..) + , In(..) ) where import Data.Aeson (FromJSON) @@ -14,15 +14,13 @@ import Common.Model (Currency) import Loadable (Loadable (..)) import qualified Loadable import qualified Util.Ajax as AjaxUtil -import View.Income.Header (HeaderIn (..), HeaderOut (..)) import qualified View.Income.Header as Header import View.Income.Init (Init (..)) -import View.Income.Table (IncomeTableIn (..)) import qualified View.Income.Table as Table -data IncomeIn t = IncomeIn - { _incomeIn_currency :: Currency - , _incomeIn_init :: Dynamic t (Loadable Init) +data In t = In + { _in_currency :: Currency + , _in_init :: Dynamic t (Loadable Init) } init :: forall t m. MonadWidget t m => m (Dynamic t (Loadable Init)) @@ -36,9 +34,9 @@ init = do ps <- payments return $ Init <$> us <*> is <*> ps -view :: forall t m. MonadWidget t m => IncomeIn t -> m () -view incomeIn = do - R.dyn . R.ffor (_incomeIn_init incomeIn) . Loadable.view $ \init -> +view :: forall t m. MonadWidget t m => In t -> m () +view input = do + R.dyn . R.ffor (_in_init input) . Loadable.view $ \init -> R.elClass "main" "income" $ do @@ -47,18 +45,18 @@ view incomeIn = do incomes <- R.foldDyn (:) (_init_incomes init) - (_headerOut_addIncome header) + (Header._out_addIncome header) - header <- Header.view $ HeaderIn - { _headerIn_init = init - , _headerIn_currency = _incomeIn_currency incomeIn - , _headerIn_incomes = incomes + header <- Header.view $ Header.In + { Header._in_init = init + , Header._in_currency = _in_currency input + , Header._in_incomes = incomes } - Table.view $ IncomeTableIn - { _tableIn_init = init - , _tableIn_currency = _incomeIn_currency incomeIn - , _tableIn_incomes = incomes + Table.view $ Table.In + { Table._in_init = init + , Table._in_currency = _in_currency input + , Table._in_incomes = incomes } return () -- cgit v1.2.3 From 61ff1443c42def5a09f624e3df2e2520e97610d0 Mon Sep 17 00:00:00 2001 From: Joris Date: Tue, 22 Oct 2019 23:25:05 +0200 Subject: Clone incomes --- client/src/View/Income/Income.hs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index f8359bb..b97613d 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -41,11 +41,14 @@ view input = do R.elClass "main" "income" $ do rec - + let addIncome = R.leftmost + [ Header._out_addIncome header + , Table._out_addIncome table + ] incomes <- R.foldDyn (:) (_init_incomes init) - (Header._out_addIncome header) + addIncome header <- Header.view $ Header.In { Header._in_init = init @@ -53,11 +56,11 @@ view input = do , Header._in_incomes = incomes } - Table.view $ Table.In - { Table._in_init = init - , Table._in_currency = _in_currency input - , Table._in_incomes = incomes - } + table <- Table.view $ Table.In + { Table._in_init = init + , Table._in_currency = _in_currency input + , Table._in_incomes = incomes + } return () -- cgit v1.2.3 From f968c8ce63e1aec119b1e6f414cf27e2c0294bcb Mon Sep 17 00:00:00 2001 From: Joris Date: Wed, 23 Oct 2019 21:09:54 +0200 Subject: Delete income --- client/src/View/Income/Income.hs | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index b97613d..2784cac 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -6,10 +6,10 @@ module View.Income.Income import Data.Aeson (FromJSON) import Prelude hiding (init) -import Reflex.Dom (Dynamic, MonadWidget) +import Reflex.Dom (Dynamic, Event, MonadWidget) import qualified Reflex.Dom as R -import Common.Model (Currency) +import Common.Model (Currency, Income (..), UserId) import Loadable (Loadable (..)) import qualified Loadable @@ -19,8 +19,9 @@ import View.Income.Init (Init (..)) import qualified View.Income.Table as Table data In t = In - { _in_currency :: Currency - , _in_init :: Dynamic t (Loadable Init) + { _in_currentUser :: UserId + , _in_currency :: Currency + , _in_init :: Dynamic t (Loadable Init) } init :: forall t m. MonadWidget t m => m (Dynamic t (Loadable Init)) @@ -42,13 +43,14 @@ view input = do rec let addIncome = R.leftmost - [ Header._out_addIncome header - , Table._out_addIncome table + [ Header._out_add header + , Table._out_add table ] - incomes <- R.foldDyn - (:) + + incomes <- reduceIncomes (_init_incomes init) addIncome + (Table._out_delete table) header <- Header.view $ Header.In { Header._in_init = init @@ -57,7 +59,8 @@ view input = do } table <- Table.view $ Table.In - { Table._in_init = init + { Table._in_currentUser = _in_currentUser input + , Table._in_init = init , Table._in_currency = _in_currency input , Table._in_incomes = incomes } @@ -65,3 +68,15 @@ view input = do return () return () + +reduceIncomes + :: forall t m. MonadWidget t m + => [Income] + -> Event t Income -- add income + -> Event t Income -- delete income + -> m (Dynamic t [Income]) +reduceIncomes initIncomes add delete = + R.foldDyn id initIncomes $ R.leftmost + [ (:) <$> add + , R.ffor delete (\p -> filter ((/= (_income_id p)) . _income_id)) + ] -- cgit v1.2.3 From e4b32ce15f8c92f3b477d3f3d4d301ba08f9b5e3 Mon Sep 17 00:00:00 2001 From: Joris Date: Wed, 23 Oct 2019 22:35:27 +0200 Subject: Edit an income --- client/src/View/Income/Income.hs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index 2784cac..90f1fde 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -50,6 +50,7 @@ view input = do incomes <- reduceIncomes (_init_incomes init) addIncome + (Table._out_edit table) (Table._out_delete table) header <- Header.view $ Header.In @@ -72,11 +73,13 @@ view input = do reduceIncomes :: forall t m. MonadWidget t m => [Income] - -> Event t Income -- add income - -> Event t Income -- delete income + -> Event t Income -- add + -> Event t Income -- edit + -> Event t Income -- delete -> m (Dynamic t [Income]) -reduceIncomes initIncomes add delete = +reduceIncomes initIncomes add edit delete = R.foldDyn id initIncomes $ R.leftmost [ (:) <$> add + , R.ffor edit (\p -> (p:) . filter ((/= (_income_id p)) . _income_id)) , R.ffor delete (\p -> filter ((/= (_income_id p)) . _income_id)) ] -- cgit v1.2.3 From c53198a7dd46f1575a33f823c29fa02126429e8f Mon Sep 17 00:00:00 2001 From: Joris Date: Wed, 23 Oct 2019 22:41:51 +0200 Subject: Go to initial page after adding an income --- client/src/View/Income/Income.hs | 1 + 1 file changed, 1 insertion(+) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index 90f1fde..2f0b8f5 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -64,6 +64,7 @@ view input = do , Table._in_init = init , Table._in_currency = _in_currency input , Table._in_incomes = incomes + , Table._in_resetPage = () <$ addIncome } return () -- cgit v1.2.3 From b97ad942495352c3fc1e0c820cfba82a9693ac7a Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 27 Oct 2019 20:26:29 +0100 Subject: WIP Set up server side paging for incomes --- client/src/View/Income/Income.hs | 101 +++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 51 deletions(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index 2f0b8f5..c48f325 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -4,19 +4,23 @@ module View.Income.Income , In(..) ) where -import Data.Aeson (FromJSON) -import Prelude hiding (init) -import Reflex.Dom (Dynamic, Event, MonadWidget) -import qualified Reflex.Dom as R +import Data.Aeson (FromJSON) +import Prelude hiding (init) +import Reflex.Dom (Dynamic, Event, MonadWidget) +import qualified Reflex.Dom as R -import Common.Model (Currency, Income (..), UserId) +import Common.Model (Currency, Income (..), + IncomesAndCount (..), UserId) -import Loadable (Loadable (..)) +import qualified Component.Pages as Pages +import Loadable (Loadable (..)) import qualified Loadable -import qualified Util.Ajax as AjaxUtil -import qualified View.Income.Header as Header -import View.Income.Init (Init (..)) -import qualified View.Income.Table as Table +import qualified Util.Ajax as AjaxUtil +import qualified Util.Reflex as ReflexUtil +-- import qualified View.Income.Header as Header +import View.Income.Init (Init (..)) +import qualified View.Income.Reducer as Reducer +import qualified View.Income.Table as Table data In t = In { _in_currentUser :: UserId @@ -37,50 +41,45 @@ init = do view :: forall t m. MonadWidget t m => In t -> m () view input = do - R.dyn . R.ffor (_in_init input) . Loadable.view $ \init -> + -- rec + -- incomes <- Reducer.reducer + -- { Reducer._in_newPage = ReflexUtil.flatten (Table._out_newPage <$> table) + -- , Reducer._in_currentPage = ReflexUtil.flatten (Table._out_currentPage <$> table) + -- , Reducer._in_addIncome = ReflexUtil.flatten (Table._out_add <$> table) + -- , Reducer._in_editIncome = ReflexUtil.flatten (Table._out_edit <$> table) + -- , Reducer._in_deleteIncome = ReflexUtil.flatten (Table._out_delete <$> table) + -- } - R.elClass "main" "income" $ do + rec + incomes <- Reducer.reducer $ Reducer.In + { Reducer._in_newPage = Pages._out_newPage pages + , Reducer._in_currentPage = Pages._out_currentPage pages + , Reducer._in_addIncome = Table._out_add table + , Reducer._in_editIncome = Table._out_edit table + , Reducer._in_deleteIncome = Table._out_delete table + } - rec - let addIncome = R.leftmost - [ Header._out_add header - , Table._out_add table - ] + table <- Table.view $ Table.In + { Table._in_currentUser = _in_currentUser input + , Table._in_currency = _in_currency input + , Table._in_incomes = R.ffor incomes $ \case + Loaded (IncomesAndCount xs _) -> xs + _ -> [] + } - incomes <- reduceIncomes - (_init_incomes init) - addIncome - (Table._out_edit table) - (Table._out_delete table) + pages <- Pages.view $ Pages.In + { Pages._in_total = R.ffor incomes $ \case + Loaded (IncomesAndCount _ n) -> n + _ -> 0 + , Pages._in_perPage = Reducer.perPage + } - header <- Header.view $ Header.In - { Header._in_init = init - , Header._in_currency = _in_currency input - , Header._in_incomes = incomes - } - - table <- Table.view $ Table.In - { Table._in_currentUser = _in_currentUser input - , Table._in_init = init - , Table._in_currency = _in_currency input - , Table._in_incomes = incomes - , Table._in_resetPage = () <$ addIncome - } - - return () + -- -- table :: Event t (Maybe (Table.Out t)) + -- table <- R.dyn . R.ffor incomes . Loadable.view $ \incomes -> + -- Table.view $ Table.In + -- { Table._in_currentUser = _in_currentUser input + -- , Table._in_currency = _in_currency input + -- , Table._in_incomes = incomes + -- } return () - -reduceIncomes - :: forall t m. MonadWidget t m - => [Income] - -> Event t Income -- add - -> Event t Income -- edit - -> Event t Income -- delete - -> m (Dynamic t [Income]) -reduceIncomes initIncomes add edit delete = - R.foldDyn id initIncomes $ R.leftmost - [ (:) <$> add - , R.ffor edit (\p -> (p:) . filter ((/= (_income_id p)) . _income_id)) - , R.ffor delete (\p -> filter ((/= (_income_id p)) . _income_id)) - ] -- cgit v1.2.3 From 227dcd4435b775d7dbc5ae5d3d81b589897253cc Mon Sep 17 00:00:00 2001 From: Joris Date: Sat, 2 Nov 2019 20:52:27 +0100 Subject: Implement incomes server side paging --- client/src/View/Income/Income.hs | 65 +++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 34 deletions(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index c48f325..fedf3d8 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -1,10 +1,14 @@ +{-# LANGUAGE ExplicitForAll #-} + module View.Income.Income ( init , view , In(..) ) where +import qualified Data.Text as T import Data.Aeson (FromJSON) +import qualified Data.Maybe as Maybe import Prelude hiding (init) import Reflex.Dom (Dynamic, Event, MonadWidget) import qualified Reflex.Dom as R @@ -41,45 +45,38 @@ init = do view :: forall t m. MonadWidget t m => In t -> m () view input = do - -- rec - -- incomes <- Reducer.reducer - -- { Reducer._in_newPage = ReflexUtil.flatten (Table._out_newPage <$> table) - -- , Reducer._in_currentPage = ReflexUtil.flatten (Table._out_currentPage <$> table) - -- , Reducer._in_addIncome = ReflexUtil.flatten (Table._out_add <$> table) - -- , Reducer._in_editIncome = ReflexUtil.flatten (Table._out_edit <$> table) - -- , Reducer._in_deleteIncome = ReflexUtil.flatten (Table._out_delete <$> table) - -- } - rec incomes <- Reducer.reducer $ Reducer.In - { Reducer._in_newPage = Pages._out_newPage pages - , Reducer._in_currentPage = Pages._out_currentPage pages - , Reducer._in_addIncome = Table._out_add table - , Reducer._in_editIncome = Table._out_edit table - , Reducer._in_deleteIncome = Table._out_delete table + { Reducer._in_newPage = newPage + , Reducer._in_currentPage = currentPage + , Reducer._in_addIncome = addIncome + , Reducer._in_editIncome = editIncome + , Reducer._in_deleteIncome = deleteIncome } - table <- Table.view $ Table.In - { Table._in_currentUser = _in_currentUser input - , Table._in_currency = _in_currency input - , Table._in_incomes = R.ffor incomes $ \case - Loaded (IncomesAndCount xs _) -> xs - _ -> [] - } + let eventFromResult :: forall a. ((Table.Out t, Pages.Out t) -> Event t a) -> m (Event t a) + eventFromResult op = ReflexUtil.flatten . fmap (Maybe.fromMaybe R.never . fmap op) $ result - pages <- Pages.view $ Pages.In - { Pages._in_total = R.ffor incomes $ \case - Loaded (IncomesAndCount _ n) -> n - _ -> 0 - , Pages._in_perPage = Reducer.perPage - } + newPage <- eventFromResult $ Pages._out_newPage . snd + currentPage <- R.holdDyn 1 newPage + addIncome <- eventFromResult $ Table._out_add . fst + editIncome <- eventFromResult $ Table._out_edit . fst + deleteIncome <- eventFromResult $ Table._out_delete . fst + + result <- R.dyn . R.ffor ((,) <$> incomes <*> currentPage) $ \(is, p) -> + flip Loadable.view is $ \(IncomesAndCount incomes count) -> do + table <- Table.view $ Table.In + { Table._in_currentUser = _in_currentUser input + , Table._in_currency = _in_currency input + , Table._in_incomes = incomes + } + + pages <- Pages.view $ Pages.In + { Pages._in_total = R.constDyn count + , Pages._in_perPage = Reducer.perPage + , Pages._in_page = p + } - -- -- table :: Event t (Maybe (Table.Out t)) - -- table <- R.dyn . R.ffor incomes . Loadable.view $ \incomes -> - -- Table.view $ Table.In - -- { Table._in_currentUser = _in_currentUser input - -- , Table._in_currency = _in_currency input - -- , Table._in_incomes = incomes - -- } + return (table, pages) return () -- cgit v1.2.3 From a267f0bb4566389342c3244d3c082dc2453f4615 Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 3 Nov 2019 09:22:12 +0100 Subject: Show users in income table --- client/src/View/Income/Income.hs | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index fedf3d8..d31775a 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -1,20 +1,18 @@ {-# LANGUAGE ExplicitForAll #-} module View.Income.Income - ( init - , view + ( view , In(..) ) where -import qualified Data.Text as T import Data.Aeson (FromJSON) import qualified Data.Maybe as Maybe -import Prelude hiding (init) +import qualified Data.Text as T import Reflex.Dom (Dynamic, Event, MonadWidget) import qualified Reflex.Dom as R import Common.Model (Currency, Income (..), - IncomesAndCount (..), UserId) + IncomesAndCount (..), User, UserId) import qualified Component.Pages as Pages import Loadable (Loadable (..)) @@ -27,22 +25,11 @@ import qualified View.Income.Reducer as Reducer import qualified View.Income.Table as Table data In t = In - { _in_currentUser :: UserId + { _in_users :: [User] + , _in_currentUser :: UserId , _in_currency :: Currency - , _in_init :: Dynamic t (Loadable Init) } -init :: forall t m. MonadWidget t m => m (Dynamic t (Loadable Init)) -init = do - users <- AjaxUtil.getNow "api/users" - incomes <- AjaxUtil.getNow "api/incomes" - payments <- AjaxUtil.getNow "api/payments" - return $ do - us <- users - is <- incomes - ps <- payments - return $ Init <$> us <*> is <*> ps - view :: forall t m. MonadWidget t m => In t -> m () view input = do rec @@ -69,6 +56,7 @@ view input = do { Table._in_currentUser = _in_currentUser input , Table._in_currency = _in_currency input , Table._in_incomes = incomes + , Table._in_users = _in_users input } pages <- Pages.view $ Pages.In -- cgit v1.2.3 From 9dbb4e6f7c2f0edc1126626e2ff498144c6b9947 Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 3 Nov 2019 11:28:42 +0100 Subject: Show income header --- client/src/View/Income/Income.hs | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index d31775a..d82ab4d 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -11,15 +11,15 @@ import qualified Data.Text as T import Reflex.Dom (Dynamic, Event, MonadWidget) import qualified Reflex.Dom as R -import Common.Model (Currency, Income (..), - IncomesAndCount (..), User, UserId) +import Common.Model (Currency, Income (..), IncomePage (..), + User, UserId) import qualified Component.Pages as Pages import Loadable (Loadable (..)) import qualified Loadable import qualified Util.Ajax as AjaxUtil import qualified Util.Reflex as ReflexUtil --- import qualified View.Income.Header as Header +import qualified View.Income.Header as Header import View.Income.Init (Init (..)) import qualified View.Income.Reducer as Reducer import qualified View.Income.Table as Table @@ -36,22 +36,29 @@ view input = do incomes <- Reducer.reducer $ Reducer.In { Reducer._in_newPage = newPage , Reducer._in_currentPage = currentPage - , Reducer._in_addIncome = addIncome + , Reducer._in_addIncome = R.leftmost [headerAddIncome, tableAddIncome] , Reducer._in_editIncome = editIncome , Reducer._in_deleteIncome = deleteIncome } - let eventFromResult :: forall a. ((Table.Out t, Pages.Out t) -> Event t a) -> m (Event t a) + let eventFromResult :: forall a. ((Header.Out t, Table.Out t, Pages.Out t) -> Event t a) -> m (Event t a) eventFromResult op = ReflexUtil.flatten . fmap (Maybe.fromMaybe R.never . fmap op) $ result - newPage <- eventFromResult $ Pages._out_newPage . snd + newPage <- eventFromResult $ Pages._out_newPage . (\(_, _, c) -> c) currentPage <- R.holdDyn 1 newPage - addIncome <- eventFromResult $ Table._out_add . fst - editIncome <- eventFromResult $ Table._out_edit . fst - deleteIncome <- eventFromResult $ Table._out_delete . fst + headerAddIncome <- eventFromResult $ Header._out_add . (\(a, _, _) -> a) + tableAddIncome <- eventFromResult $ Table._out_add . (\(_, b, _) -> b) + editIncome <- eventFromResult $ Table._out_edit . (\(_, b, _) -> b) + deleteIncome <- eventFromResult $ Table._out_delete . (\(_, b, _) -> b) result <- R.dyn . R.ffor ((,) <$> incomes <*> currentPage) $ \(is, p) -> - flip Loadable.view is $ \(IncomesAndCount incomes count) -> do + flip Loadable.view is $ \(IncomePage header incomes count) -> do + header <- Header.view $ Header.In + { Header._in_users = _in_users input + , Header._in_header = header + , Header._in_currency = _in_currency input + } + table <- Table.view $ Table.In { Table._in_currentUser = _in_currentUser input , Table._in_currency = _in_currency input @@ -65,6 +72,6 @@ view input = do , Pages._in_page = p } - return (table, pages) + return (header, table, pages) return () -- cgit v1.2.3 From 54628c70cb33de5e4309c35b9f6b57bbe9f7a07b Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 24 Nov 2019 16:19:53 +0100 Subject: Compute cumulative income with a DB query --- client/src/View/Income/Income.hs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index d82ab4d..fa2585d 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -19,6 +19,7 @@ import Loadable (Loadable (..)) import qualified Loadable import qualified Util.Ajax as AjaxUtil import qualified Util.Reflex as ReflexUtil +import qualified Util.Reflex as ReflexUtil import qualified View.Income.Header as Header import View.Income.Init (Init (..)) import qualified View.Income.Reducer as Reducer @@ -33,9 +34,8 @@ data In t = In view :: forall t m. MonadWidget t m => In t -> m () view input = do rec - incomes <- Reducer.reducer $ Reducer.In - { Reducer._in_newPage = newPage - , Reducer._in_currentPage = currentPage + incomePage <- Reducer.reducer $ Reducer.In + { Reducer._in_page = page , Reducer._in_addIncome = R.leftmost [headerAddIncome, tableAddIncome] , Reducer._in_editIncome = editIncome , Reducer._in_deleteIncome = deleteIncome @@ -44,15 +44,14 @@ view input = do let eventFromResult :: forall a. ((Header.Out t, Table.Out t, Pages.Out t) -> Event t a) -> m (Event t a) eventFromResult op = ReflexUtil.flatten . fmap (Maybe.fromMaybe R.never . fmap op) $ result - newPage <- eventFromResult $ Pages._out_newPage . (\(_, _, c) -> c) - currentPage <- R.holdDyn 1 newPage + page <- eventFromResult $ Pages._out_newPage . (\(_, _, c) -> c) headerAddIncome <- eventFromResult $ Header._out_add . (\(a, _, _) -> a) tableAddIncome <- eventFromResult $ Table._out_add . (\(_, b, _) -> b) editIncome <- eventFromResult $ Table._out_edit . (\(_, b, _) -> b) deleteIncome <- eventFromResult $ Table._out_delete . (\(_, b, _) -> b) - result <- R.dyn . R.ffor ((,) <$> incomes <*> currentPage) $ \(is, p) -> - flip Loadable.view is $ \(IncomePage header incomes count) -> do + result <- Loadable.view2 incomePage $ + \(IncomePage page header incomes count) -> do header <- Header.view $ Header.In { Header._in_users = _in_users input , Header._in_header = header @@ -69,7 +68,7 @@ view input = do pages <- Pages.view $ Pages.In { Pages._in_total = R.constDyn count , Pages._in_perPage = Reducer.perPage - , Pages._in_page = p + , Pages._in_page = page } return (header, table, pages) -- cgit v1.2.3 From e622e8fdd2e40b4306b5cc724d8dfb76bf976242 Mon Sep 17 00:00:00 2001 From: Joris Date: Mon, 25 Nov 2019 08:17:59 +0100 Subject: Remove Loadable2 --- client/src/View/Income/Income.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index fa2585d..e83ba80 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -50,7 +50,7 @@ view input = do editIncome <- eventFromResult $ Table._out_edit . (\(_, b, _) -> b) deleteIncome <- eventFromResult $ Table._out_delete . (\(_, b, _) -> b) - result <- Loadable.view2 incomePage $ + result <- Loadable.viewShowValueWhileLoading incomePage $ \(IncomePage page header incomes count) -> do header <- Header.view $ Header.In { Header._in_users = _in_users input -- cgit v1.2.3 From 316bda10c6bec8b5ccc9e23f1f677c076205f046 Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 8 Dec 2019 11:39:37 +0100 Subject: Add category page --- client/src/View/Income/Income.hs | 1 - 1 file changed, 1 deletion(-) (limited to 'client/src/View/Income/Income.hs') diff --git a/client/src/View/Income/Income.hs b/client/src/View/Income/Income.hs index e83ba80..7be8091 100644 --- a/client/src/View/Income/Income.hs +++ b/client/src/View/Income/Income.hs @@ -21,7 +21,6 @@ import qualified Util.Ajax as AjaxUtil import qualified Util.Reflex as ReflexUtil import qualified Util.Reflex as ReflexUtil import qualified View.Income.Header as Header -import View.Income.Init (Init (..)) import qualified View.Income.Reducer as Reducer import qualified View.Income.Table as Table -- cgit v1.2.3