aboutsummaryrefslogtreecommitdiff
path: root/client/src/View/Income/Form.hs
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/View/Income/Form.hs')
-rw-r--r--client/src/View/Income/Form.hs113
1 files changed, 113 insertions, 0 deletions
diff --git a/client/src/View/Income/Form.hs b/client/src/View/Income/Form.hs
new file mode 100644
index 0000000..b8a9094
--- /dev/null
+++ b/client/src/View/Income/Form.hs
@@ -0,0 +1,113 @@
+module View.Income.Form
+ ( view
+ , FormIn(..)
+ , HttpMethod(..)
+ , FormOut(..)
+ ) where
+
+import Data.Aeson (ToJSON)
+import Data.Text (Text)
+import qualified Data.Text as T
+import Data.Time.Calendar (Day)
+import qualified Data.Time.Calendar as Calendar
+import qualified Data.Validation as V
+import Reflex.Dom (Event, MonadWidget)
+import qualified Reflex.Dom as R
+
+import Common.Model (Income)
+import qualified Common.Msg as Msg
+import qualified Common.Validation.Income as IncomeValidation
+import Component (ButtonIn (..), InputIn (..),
+ InputOut (..))
+import qualified Component as Component
+import qualified Util.Ajax as Ajax
+import qualified Util.Either as EitherUtil
+import qualified Util.Validation as ValidationUtil
+import qualified Util.WaitFor as WaitFor
+
+data FormIn t i = FormIn
+ { _formIn_cancel :: Event t ()
+ , _formIn_headerLabel :: Text
+ , _formIn_amount :: Text
+ , _formIn_date :: Day
+ , _formIn_mkPayload :: Text -> Text -> i
+ , _formIn_httpMethod :: HttpMethod
+ }
+
+data HttpMethod = Put | Post
+
+data FormOut t = FormOut
+ { _formOut_hide :: Event t ()
+ , _formOut_addIncome :: Event t Income
+ }
+
+view :: forall t m i. (MonadWidget t m, ToJSON i) => FormIn t i -> m (FormOut t)
+view formIn = do
+ R.divClass "form" $ do
+ R.divClass "formHeader" $
+ R.text (_formIn_headerLabel formIn)
+
+ R.divClass "formContent" $ do
+ rec
+ let reset = R.leftmost
+ [ "" <$ cancel
+ , "" <$ addIncome
+ , "" <$ _formIn_cancel formIn
+ ]
+
+ amount <- _inputOut_raw <$> (Component.input
+ (Component.defaultInputIn
+ { _inputIn_label = Msg.get Msg.Income_Amount
+ , _inputIn_initialValue = _formIn_amount formIn
+ , _inputIn_validation = IncomeValidation.amount
+ })
+ (_formIn_amount formIn <$ reset)
+ confirm)
+
+ let initialDate = T.pack . Calendar.showGregorian . _formIn_date $ formIn
+
+ date <- _inputOut_raw <$> (Component.input
+ (Component.defaultInputIn
+ { _inputIn_label = Msg.get Msg.Income_Date
+ , _inputIn_initialValue = initialDate
+ , _inputIn_inputType = "date"
+ , _inputIn_hasResetButton = False
+ , _inputIn_validation = IncomeValidation.date
+ })
+ (initialDate <$ reset)
+ confirm)
+
+ let income = do
+ a <- amount
+ d <- date
+ return . V.Success $ (_formIn_mkPayload formIn) a d
+
+ (addIncome, cancel, confirm) <- R.divClass "buttons" $ do
+ rec
+ cancel <- Component._buttonOut_clic <$> (Component.button $
+ (Component.defaultButtonIn (R.text $ Msg.get Msg.Dialog_Undo))
+ { _buttonIn_class = R.constDyn "undo" })
+
+ confirm <- Component._buttonOut_clic <$> (Component.button $
+ (Component.defaultButtonIn (R.text $ Msg.get Msg.Dialog_Confirm))
+ { _buttonIn_class = R.constDyn "confirm"
+ , _buttonIn_waiting = waiting
+ , _buttonIn_submit = True
+ })
+
+ (addIncome, waiting) <- WaitFor.waitFor
+ (ajax "/api/income")
+ (ValidationUtil.fireValidation income confirm)
+
+ return (R.fmapMaybe EitherUtil.eitherToMaybe addIncome, cancel, confirm)
+
+ return FormOut
+ { _formOut_hide = R.leftmost [ cancel, () <$ addIncome ]
+ , _formOut_addIncome = addIncome
+ }
+
+ where
+ ajax =
+ case _formIn_httpMethod formIn of
+ Post -> Ajax.postJson
+ Put -> Ajax.putJson