summaryrefslogtreecommitdiff
path: root/Handler
diff options
context:
space:
mode:
Diffstat (limited to 'Handler')
-rw-r--r--Handler/Common.hs78
-rw-r--r--Handler/Common/Types.hs23
-rw-r--r--Handler/DeleteItem.hs10
-rw-r--r--Handler/InventoryListing.hs26
-rw-r--r--Handler/Item.hs31
-rw-r--r--Handler/OpenItem.hs12
-rw-r--r--Handler/UpdateItem.hs33
7 files changed, 213 insertions, 0 deletions
diff --git a/Handler/Common.hs b/Handler/Common.hs
new file mode 100644
index 0000000..38fb1ce
--- /dev/null
+++ b/Handler/Common.hs
@@ -0,0 +1,78 @@
1{-# LANGUAGE ApplicativeDo #-}
2
3module Handler.Common
4 ( inventoryListing
5 , itemForm
6 , InventoryState(..)
7 , FormState(..)
8 ) where
9
10import Import
11
12import Data.Unique
13
14import qualified Data.Text as Text (pack)
15
16import Control.Lens
17
18import Handler.Common.Types
19
20dayFormat :: Day -> String
21dayFormat = formatTime defaultTimeLocale "%e. %b %y"
22
23itemForm :: Maybe Item -- ^ Update existing item or insert new?
24 -> Html -> MForm Handler (FormResult Item, Widget)
25itemForm proto identView = do
26 today <- utctDay <$> liftIO getCurrentTime
27
28 (kindRes, kindView) <- mreq textField "" $ itemKind <$> proto
29 (boughtRes, boughtWidget) <- dayForm (maybe (Just $ Just today) Just $ fmap itemBought proto) "Unknown"
30 (expiresRes, expiresWidget) <- dayForm (fmap itemExpires proto) "Never"
31 (openedRes, openedWidget) <- dayForm (fmap itemOpened proto) "Never"
32
33 let itemRes = do
34 itemKind <- kindRes
35 itemBought <- boughtRes
36 itemExpires <- expiresRes
37 itemOpened <- openedRes
38 return Item{ itemNormKind = normalizeKind itemKind, ..}
39
40 return . (itemRes, ) $
41 [whamlet|
42 $newline never
43 #{identView}
44 <div .td>^{fvInput kindView}
45 <div .td>^{boughtWidget}
46 <div .td>^{expiresWidget}
47 <div .td>^{openedWidget}
48 |]
49 where
50 dayForm :: Maybe (Maybe Day) -> String -> MForm Handler (FormResult (Maybe Day), Widget)
51 dayForm proto label = do
52 today <- utctDay <$> liftIO getCurrentTime
53
54 checkboxId <- ("check" <>) . show . hashUnique <$> liftIO newUnique
55
56 (fmap (fromMaybe False) -> isNothingRes, isNothingView) <-
57 mopt checkBoxField ("" { fsId = Just $ Text.pack checkboxId }) . Just . Just . fromMaybe True $ fmap isNothing proto
58 (dayRes, dayView) <-
59 mreq dayField "" . Just . fromMaybe today $ join proto
60
61 let res = (bool Just (const Nothing) <$> isNothingRes) <*> dayRes
62 return . (res, ) $ do
63 [whamlet|
64 $newline never
65 <div .table>
66 <div .tr>
67 <label for=#{checkboxId} .checkbox .td>
68 ^{fvInput isNothingView}
69 <span>
70 #{label}
71 <div .tr>
72 <div .td .dayInput>^{fvInput dayView}
73 |]
74
75inventoryListing :: InventoryState -> Widget
76inventoryListing InventoryState{..} = do
77 setTitle "Bar Inventory"
78 $(widgetFile "inventoryListing")
diff --git a/Handler/Common/Types.hs b/Handler/Common/Types.hs
new file mode 100644
index 0000000..ca7cb8d
--- /dev/null
+++ b/Handler/Common/Types.hs
@@ -0,0 +1,23 @@
1{-# LANGUAGE FunctionalDependencies #-}
2
3module Handler.Common.Types where
4
5import Import
6
7import Control.Lens
8
9data InventoryState = InventoryState
10 { stock :: [Entity Item]
11 , formState :: Maybe FormState
12 }
13
14data FormState = InsertForm
15 { fsInsertForm :: Widget
16 , fsInsertEncoding :: Enctype
17 }
18 | UpdateForm
19 { fsUpdateItem :: ItemId
20 , fsUpdateForm :: Widget
21 , fsUpdateEncoding :: Enctype
22 }
23makeLensesWith abbreviatedFields ''FormState
diff --git a/Handler/DeleteItem.hs b/Handler/DeleteItem.hs
new file mode 100644
index 0000000..ee6d9d3
--- /dev/null
+++ b/Handler/DeleteItem.hs
@@ -0,0 +1,10 @@
1module Handler.DeleteItem where
2
3import Import
4
5postDeleteItemR :: ItemId -> Handler TypedContent
6postDeleteItemR itemId = do
7 runDB $ delete itemId
8 selectRep $ do
9 provideJson ()
10 provideRep (redirect $ InventoryListingR :: Handler Html)
diff --git a/Handler/InventoryListing.hs b/Handler/InventoryListing.hs
new file mode 100644
index 0000000..e3c062e
--- /dev/null
+++ b/Handler/InventoryListing.hs
@@ -0,0 +1,26 @@
1module Handler.InventoryListing where
2
3import Import
4import Handler.Common
5
6getInventoryListingR, postInventoryListingR :: Handler TypedContent
7getInventoryListingR = postInventoryListingR
8postInventoryListingR = do
9 ((insertResult, fsInsertForm), fsInsertEncoding) <- runFormPost $ itemForm Nothing
10
11 mapM_ (addMessage "formError" . toHtml) =<< case insertResult of
12 FormSuccess newItem -> [] <$ runDB (insert newItem)
13 FormFailure errors -> return errors
14 _ -> return []
15
16 (sortOn entityVal -> stock) <- runDB $ selectList [] []
17
18 selectRep $ do
19 provideJson (stock :: [Entity Item])
20 provideRep . defaultLayout $ inventoryListing InventoryState
21 { formState = Just InsertForm{..}
22 , ..
23 }
24
25putInventoryListingR :: Handler Value
26putInventoryListingR = returnJson =<< runDB . insertEntity =<< (requireCheckJsonBody :: Handler Item)
diff --git a/Handler/Item.hs b/Handler/Item.hs
new file mode 100644
index 0000000..87030bb
--- /dev/null
+++ b/Handler/Item.hs
@@ -0,0 +1,31 @@
1module Handler.Item where
2
3import Import
4
5getItemR :: ItemId -> Handler TypedContent
6getItemR itemId = do
7 eLookup <- runDB $ fmap (Entity itemId) <$> get itemId
8 case eLookup of
9 Nothing -> notFound
10 Just entity -> selectRep $ do
11 provideJson entity
12 provideRep (redirect $ InventoryListingR :#: itemId :: Handler Html)
13
14putItemR :: ItemId -> Handler Value
15putItemR itemId = do
16 Item{..} <- requireCheckJsonBody
17 returnJson . Entity itemId =<< runDB
18 (updateGet itemId [ ItemKind =. itemKind
19 , ItemNormKind =. itemNormKind
20 , ItemBought =. itemBought
21 , ItemExpires =. itemExpires
22 , ItemOpened =. itemOpened
23 ])
24
25patchItemR :: ItemId -> Handler Value
26patchItemR itemId = do
27 diffs <- (requireCheckJsonBody :: Handler ItemDiffs)
28 returnJson . Entity itemId =<< runDB (updateGet itemId $ toUpdate diffs)
29
30deleteItemR :: ItemId -> Handler ()
31deleteItemR = runDB . delete
diff --git a/Handler/OpenItem.hs b/Handler/OpenItem.hs
new file mode 100644
index 0000000..468c6ec
--- /dev/null
+++ b/Handler/OpenItem.hs
@@ -0,0 +1,12 @@
1module Handler.OpenItem where
2
3import Import
4
5postOpenItemR :: ItemId -> Handler TypedContent
6postOpenItemR itemId = do
7 today <- utctDay <$> liftIO getCurrentTime
8 result <- fmap (Entity itemId) . runDB $ updateGet itemId [ ItemOpened =. Just today
9 ]
10 selectRep $ do
11 provideJson result
12 provideRep (redirect $ InventoryListingR :#: itemId :: Handler Html)
diff --git a/Handler/UpdateItem.hs b/Handler/UpdateItem.hs
new file mode 100644
index 0000000..353572b
--- /dev/null
+++ b/Handler/UpdateItem.hs
@@ -0,0 +1,33 @@
1module Handler.UpdateItem where
2
3import Import
4
5import Handler.Common
6
7getUpdateItemR, postUpdateItemR :: ItemId -> Handler TypedContent
8getUpdateItemR = postUpdateItemR
9postUpdateItemR fsUpdateItem = do
10 Just entity <- fmap (Entity fsUpdateItem) <$> runDB (get fsUpdateItem)
11
12 ((updateResult, fsUpdateForm), fsUpdateEncoding) <- runFormPost . itemForm . Just $ entityVal entity
13
14 mapM_ (addMessage "formError" . toHtml) =<< case updateResult of
15 FormSuccess Item{..} -> [] <$ runDB (update fsUpdateItem [ ItemKind =. itemKind
16 , ItemNormKind =. normalizeKind itemKind
17 , ItemBought =. itemBought
18 , ItemExpires =. itemExpires
19 , ItemOpened =. itemOpened
20 ])
21 FormFailure errors -> return errors
22 _ -> return []
23
24 selectRep $ do
25 provideRep $ case updateResult of
26 FormSuccess _ -> redirect $ InventoryListingR :#: fsUpdateItem :: Handler Html
27 _ -> do
28 (sortOn entityVal -> stock) <- runDB $ selectList [] []
29 defaultLayout $ inventoryListing InventoryState
30 { formState = Just UpdateForm{..}
31 , ..
32 }
33 provideJson ()