diff options
Diffstat (limited to 'Handler')
-rw-r--r-- | Handler/Common.hs | 64 | ||||
-rw-r--r-- | Handler/Common/Types.hs | 23 | ||||
-rw-r--r-- | Handler/DeleteRefItem.hs | 10 | ||||
-rw-r--r-- | Handler/InventoryListing.hs | 2 | ||||
-rw-r--r-- | Handler/Item.hs | 10 | ||||
-rw-r--r-- | Handler/Kinds.hs | 8 | ||||
-rw-r--r-- | Handler/List.hs | 71 | ||||
-rw-r--r-- | Handler/ReferenceItem.hs | 25 | ||||
-rw-r--r-- | Handler/ReferenceListing.hs | 27 | ||||
-rw-r--r-- | Handler/UpdateItem.hs | 20 |
10 files changed, 235 insertions, 25 deletions
diff --git a/Handler/Common.hs b/Handler/Common.hs index 38fb1ce..2416d15 100644 --- a/Handler/Common.hs +++ b/Handler/Common.hs | |||
@@ -3,8 +3,13 @@ | |||
3 | module Handler.Common | 3 | module Handler.Common |
4 | ( inventoryListing | 4 | ( inventoryListing |
5 | , itemForm | 5 | , itemForm |
6 | , referenceListing | ||
7 | , referenceForm | ||
8 | , kinds | ||
6 | , InventoryState(..) | 9 | , InventoryState(..) |
10 | , ReferenceState(..) | ||
7 | , FormState(..) | 11 | , FormState(..) |
12 | , HasFormState(..) | ||
8 | ) where | 13 | ) where |
9 | 14 | ||
10 | import Import | 15 | import Import |
@@ -25,7 +30,7 @@ itemForm :: Maybe Item -- ^ Update existing item or insert new? | |||
25 | itemForm proto identView = do | 30 | itemForm proto identView = do |
26 | today <- utctDay <$> liftIO getCurrentTime | 31 | today <- utctDay <$> liftIO getCurrentTime |
27 | 32 | ||
28 | (kindRes, kindView) <- mreq textField "" $ itemKind <$> proto | 33 | (kindRes, kindWidget) <- kindField $ itemKind <$> proto |
29 | (boughtRes, boughtWidget) <- dayForm (maybe (Just $ Just today) Just $ fmap itemBought proto) "Unknown" | 34 | (boughtRes, boughtWidget) <- dayForm (maybe (Just $ Just today) Just $ fmap itemBought proto) "Unknown" |
30 | (expiresRes, expiresWidget) <- dayForm (fmap itemExpires proto) "Never" | 35 | (expiresRes, expiresWidget) <- dayForm (fmap itemExpires proto) "Never" |
31 | (openedRes, openedWidget) <- dayForm (fmap itemOpened proto) "Never" | 36 | (openedRes, openedWidget) <- dayForm (fmap itemOpened proto) "Never" |
@@ -41,7 +46,7 @@ itemForm proto identView = do | |||
41 | [whamlet| | 46 | [whamlet| |
42 | $newline never | 47 | $newline never |
43 | #{identView} | 48 | #{identView} |
44 | <div .td>^{fvInput kindView} | 49 | <div .td>^{kindWidget} |
45 | <div .td>^{boughtWidget} | 50 | <div .td>^{boughtWidget} |
46 | <div .td>^{expiresWidget} | 51 | <div .td>^{expiresWidget} |
47 | <div .td>^{openedWidget} | 52 | <div .td>^{openedWidget} |
@@ -73,6 +78,55 @@ itemForm proto identView = do | |||
73 | |] | 78 | |] |
74 | 79 | ||
75 | inventoryListing :: InventoryState -> Widget | 80 | inventoryListing :: InventoryState -> Widget |
76 | inventoryListing InventoryState{..} = do | 81 | inventoryListing InventoryState{ invFormState = formState, ..} = $(widgetFile "inventoryListing") |
77 | setTitle "Bar Inventory" | 82 | |
78 | $(widgetFile "inventoryListing") | 83 | referenceForm :: Maybe Reference -- ^ Update existing item or insert new? |
84 | -> Html -> MForm Handler (FormResult Reference, Widget) | ||
85 | referenceForm proto identView = do | ||
86 | (kindRes, kindWidget) <- kindField $ referenceKind <$> proto | ||
87 | |||
88 | let referenceRes = do | ||
89 | referenceKind <- kindRes | ||
90 | return Reference{ referenceNormKind = normalizeKind referenceKind, .. } | ||
91 | |||
92 | return . (referenceRes, ) $ | ||
93 | [whamlet| | ||
94 | $newline never | ||
95 | #{identView} | ||
96 | <div .td>^{kindWidget} | ||
97 | |] | ||
98 | |||
99 | referenceListing :: ReferenceState -> Widget | ||
100 | referenceListing ReferenceState{ refFormState = formState, ..} = $(widgetFile "referenceListing") | ||
101 | |||
102 | kindField :: Maybe Text -> MForm Handler (FormResult Text, Widget) | ||
103 | kindField proto = do | ||
104 | optionId <- ("options" <>) . tshow . hashUnique <$> liftIO newUnique | ||
105 | |||
106 | let | ||
107 | attrs = [ ("list", optionId) | ||
108 | , ("autocomplete", "off") | ||
109 | ] | ||
110 | |||
111 | (kindRes, kindView) <- mreq textField ("" { fsAttrs = attrs }) proto | ||
112 | |||
113 | options <- lift kinds | ||
114 | |||
115 | return . (kindRes, ) $ | ||
116 | [whamlet| | ||
117 | $newline never | ||
118 | ^{fvInput kindView} | ||
119 | <datalist ##{optionId}> | ||
120 | $forall opt <- options | ||
121 | <option value=#{opt}> | ||
122 | |] | ||
123 | |||
124 | kinds :: Handler [Text] | ||
125 | kinds = do | ||
126 | stock <- runDB $ selectList [] [] | ||
127 | reference <- runDB $ selectList [] [] | ||
128 | |||
129 | return $ concat | ||
130 | [ [ itemKind | Entity _ Item{..} <- stock ] | ||
131 | , [ referenceKind | Entity _ Reference{..} <- reference ] | ||
132 | ] | ||
diff --git a/Handler/Common/Types.hs b/Handler/Common/Types.hs index ca7cb8d..08653af 100644 --- a/Handler/Common/Types.hs +++ b/Handler/Common/Types.hs | |||
@@ -8,15 +8,32 @@ import Control.Lens | |||
8 | 8 | ||
9 | data InventoryState = InventoryState | 9 | data InventoryState = InventoryState |
10 | { stock :: [Entity Item] | 10 | { stock :: [Entity Item] |
11 | , formState :: Maybe FormState | 11 | , invFormState :: Maybe (FormState ItemId) |
12 | } | 12 | } |
13 | 13 | ||
14 | data FormState = InsertForm | 14 | data ReferenceState = ReferenceState |
15 | { reference :: [Entity Reference] | ||
16 | , refFormState :: Maybe (FormState ReferenceId) | ||
17 | } | ||
18 | |||
19 | class HasFormState a where | ||
20 | type family UpdateId a :: * | ||
21 | formState :: a -> Maybe (FormState (UpdateId a)) | ||
22 | |||
23 | instance HasFormState InventoryState where | ||
24 | type UpdateId InventoryState = ItemId | ||
25 | formState = invFormState | ||
26 | |||
27 | instance HasFormState ReferenceState where | ||
28 | type UpdateId ReferenceState = ReferenceId | ||
29 | formState = refFormState | ||
30 | |||
31 | data FormState id = InsertForm | ||
15 | { fsInsertForm :: Widget | 32 | { fsInsertForm :: Widget |
16 | , fsInsertEncoding :: Enctype | 33 | , fsInsertEncoding :: Enctype |
17 | } | 34 | } |
18 | | UpdateForm | 35 | | UpdateForm |
19 | { fsUpdateItem :: ItemId | 36 | { fsUpdateId :: id |
20 | , fsUpdateForm :: Widget | 37 | , fsUpdateForm :: Widget |
21 | , fsUpdateEncoding :: Enctype | 38 | , fsUpdateEncoding :: Enctype |
22 | } | 39 | } |
diff --git a/Handler/DeleteRefItem.hs b/Handler/DeleteRefItem.hs new file mode 100644 index 0000000..c4ff519 --- /dev/null +++ b/Handler/DeleteRefItem.hs | |||
@@ -0,0 +1,10 @@ | |||
1 | module Handler.DeleteRefItem where | ||
2 | |||
3 | import Import | ||
4 | |||
5 | postDeleteRefItemR :: ReferenceId -> Handler TypedContent | ||
6 | postDeleteRefItemR referenceId = do | ||
7 | runDB $ delete referenceId | ||
8 | selectRep $ do | ||
9 | provideJson () | ||
10 | provideRep (redirect $ ReferenceListingR :: Handler Html) | ||
diff --git a/Handler/InventoryListing.hs b/Handler/InventoryListing.hs index e3c062e..12f36ba 100644 --- a/Handler/InventoryListing.hs +++ b/Handler/InventoryListing.hs | |||
@@ -18,7 +18,7 @@ postInventoryListingR = do | |||
18 | selectRep $ do | 18 | selectRep $ do |
19 | provideJson (stock :: [Entity Item]) | 19 | provideJson (stock :: [Entity Item]) |
20 | provideRep . defaultLayout $ inventoryListing InventoryState | 20 | provideRep . defaultLayout $ inventoryListing InventoryState |
21 | { formState = Just InsertForm{..} | 21 | { invFormState = Just InsertForm{..} |
22 | , .. | 22 | , .. |
23 | } | 23 | } |
24 | 24 | ||
diff --git a/Handler/Item.hs b/Handler/Item.hs index 87030bb..0f48261 100644 --- a/Handler/Item.hs +++ b/Handler/Item.hs | |||
@@ -4,12 +4,10 @@ import Import | |||
4 | 4 | ||
5 | getItemR :: ItemId -> Handler TypedContent | 5 | getItemR :: ItemId -> Handler TypedContent |
6 | getItemR itemId = do | 6 | getItemR itemId = do |
7 | eLookup <- runDB $ fmap (Entity itemId) <$> get itemId | 7 | entity <- runDB $ Entity itemId <$> get404 itemId |
8 | case eLookup of | 8 | selectRep $ do |
9 | Nothing -> notFound | 9 | provideJson entity |
10 | Just entity -> selectRep $ do | 10 | provideRep (redirect $ InventoryListingR :#: itemId :: Handler Html) |
11 | provideJson entity | ||
12 | provideRep (redirect $ InventoryListingR :#: itemId :: Handler Html) | ||
13 | 11 | ||
14 | putItemR :: ItemId -> Handler Value | 12 | putItemR :: ItemId -> Handler Value |
15 | putItemR itemId = do | 13 | putItemR itemId = do |
diff --git a/Handler/Kinds.hs b/Handler/Kinds.hs new file mode 100644 index 0000000..0843c70 --- /dev/null +++ b/Handler/Kinds.hs | |||
@@ -0,0 +1,8 @@ | |||
1 | module Handler.Kinds where | ||
2 | |||
3 | import Import | ||
4 | |||
5 | import Handler.Common | ||
6 | |||
7 | getKindsR :: Handler Value | ||
8 | getKindsR = returnJson =<< kinds | ||
diff --git a/Handler/List.hs b/Handler/List.hs new file mode 100644 index 0000000..cfd3f7c --- /dev/null +++ b/Handler/List.hs | |||
@@ -0,0 +1,71 @@ | |||
1 | {-# LANGUAGE ApplicativeDo #-} | ||
2 | {-# LANGUAGE OverloadedLists #-} | ||
3 | |||
4 | module Handler.List where | ||
5 | |||
6 | import Import | ||
7 | |||
8 | import Data.Set (Set) | ||
9 | import qualified Data.Set as Set | ||
10 | |||
11 | import Data.Map (Map) | ||
12 | import qualified Data.Map as Map | ||
13 | |||
14 | import qualified Data.Text as Text | ||
15 | import qualified Data.Text.Lazy as Lazy.Text | ||
16 | |||
17 | import Database.Persist.Sql (Single(..), rawSql) | ||
18 | |||
19 | import Thermoprint.Client | ||
20 | |||
21 | list :: Handler (Set Text) | ||
22 | list = do | ||
23 | (map unSingle -> kinds) <- runDB $ rawSql "select reference.kind from reference where not exists (select * from item where COALESCE(item.expires >= CURRENT_DATE, TRUE) and (item.norm_kind = reference.norm_kind)) " [] | ||
24 | return $ Set.fromList kinds | ||
25 | |||
26 | mkPrintout :: Set Text -> Printout | ||
27 | mkPrintout list = Printout | ||
28 | [ Paragraph | ||
29 | [Cooked . either id Line . text . Lazy.Text.fromStrict . Text.unlines . map (" - " <>) $ Set.toAscList list | ||
30 | ] | ||
31 | ] | ||
32 | |||
33 | getListR, postListR :: Handler TypedContent | ||
34 | getListR = postListR | ||
35 | postListR = do | ||
36 | Client{..} <- mkClient' . appThermoprintBase . appSettings <$> getYesod | ||
37 | let | ||
38 | formatPrinter (pId@(PrinterId num), pStatus) = | ||
39 | ("Printer #" <> tshow num <> " – " <> tshow pStatus, pId) | ||
40 | printers' <- map formatPrinter . Map.toAscList <$> printers | ||
41 | list <- list | ||
42 | |||
43 | ((printResult, printView), printEnc) <- runFormPost . renderDivsNoLabels $ do | ||
44 | pId <- case printers' of | ||
45 | [(_, pId)] -> pure pId | ||
46 | _ -> areq (selectFieldList printers') "Printer" . listToMaybe $ map snd printers' | ||
47 | pure pId | ||
48 | |||
49 | case printResult of | ||
50 | FormSuccess pId -> do | ||
51 | (JobId jId) <- jobCreate (Just pId) $ mkPrintout list | ||
52 | addMessage "printSuccess" . toHtml $ "List is printing as job #" <> tshow jId | ||
53 | FormFailure errors -> mapM_ (addMessage "formError" . toHtml) errors | ||
54 | _ -> return () | ||
55 | |||
56 | selectRep $ do | ||
57 | provideJson list | ||
58 | provideRep . defaultLayout $ | ||
59 | [whamlet| | ||
60 | <div .table .main> | ||
61 | <div .tr .sepBelow> | ||
62 | <div .th>Item | ||
63 | $forall item <- Set.toAscList list | ||
64 | <div .tr .color> | ||
65 | <div .kind>#{item} | ||
66 | <form .tr .sepAbove method=post action=@{ListR} enctype=#{printEnc}> | ||
67 | <div .td> | ||
68 | ^{printView} | ||
69 | <button type=submit :Set.null list:disabled> | ||
70 | |||
71 | |] | ||
diff --git a/Handler/ReferenceItem.hs b/Handler/ReferenceItem.hs new file mode 100644 index 0000000..738c9f3 --- /dev/null +++ b/Handler/ReferenceItem.hs | |||
@@ -0,0 +1,25 @@ | |||
1 | module Handler.ReferenceItem where | ||
2 | |||
3 | import Import | ||
4 | |||
5 | getReferenceItemR :: ReferenceId -> Handler TypedContent | ||
6 | getReferenceItemR referenceId = do | ||
7 | entity <- runDB $ Entity referenceId <$> get404 referenceId | ||
8 | selectRep $ do | ||
9 | provideJson entity | ||
10 | provideRep (redirect $ ReferenceListingR :#: referenceId :: Handler Html) | ||
11 | |||
12 | |||
13 | putReferenceItemR :: ReferenceId -> Handler Value | ||
14 | putReferenceItemR referenceId = do | ||
15 | Reference{..} <- requireCheckJsonBody | ||
16 | returnJson . Entity referenceId =<< runDB | ||
17 | (updateGet referenceId [ ReferenceKind =. referenceKind | ||
18 | , ReferenceNormKind =. referenceNormKind | ||
19 | ]) | ||
20 | |||
21 | patchReferenceItemR :: ReferenceId -> Handler Value | ||
22 | patchReferenceItemR = putReferenceItemR -- Just one field | ||
23 | |||
24 | deleteReferenceItemR :: ReferenceId -> Handler () | ||
25 | deleteReferenceItemR = runDB . delete | ||
diff --git a/Handler/ReferenceListing.hs b/Handler/ReferenceListing.hs new file mode 100644 index 0000000..0f777ee --- /dev/null +++ b/Handler/ReferenceListing.hs | |||
@@ -0,0 +1,27 @@ | |||
1 | module Handler.ReferenceListing where | ||
2 | |||
3 | import Import | ||
4 | |||
5 | import Handler.Common | ||
6 | |||
7 | getReferenceListingR, postReferenceListingR :: Handler TypedContent | ||
8 | getReferenceListingR = postReferenceListingR | ||
9 | postReferenceListingR = do | ||
10 | ((insertResult, fsInsertForm), fsInsertEncoding) <- runFormPost $ referenceForm Nothing | ||
11 | |||
12 | mapM_ (addMessage "formError" . toHtml) =<< case insertResult of | ||
13 | FormSuccess newReference -> [] <$ runDB (insert newReference) | ||
14 | FormFailure errors -> return errors | ||
15 | _ -> return [] | ||
16 | |||
17 | reference <- runDB $ selectList [] [Asc ReferenceKind] | ||
18 | |||
19 | selectRep $ do | ||
20 | provideJson (reference :: [Entity Reference]) | ||
21 | provideRep . defaultLayout $ referenceListing ReferenceState | ||
22 | { refFormState = Just InsertForm{..} | ||
23 | , .. | ||
24 | } | ||
25 | |||
26 | putReferenceListingR :: Handler Value | ||
27 | putReferenceListingR = returnJson =<< runDB . insertEntity =<< (requireCheckJsonBody :: Handler Reference) | ||
diff --git a/Handler/UpdateItem.hs b/Handler/UpdateItem.hs index 353572b..a4a29c2 100644 --- a/Handler/UpdateItem.hs +++ b/Handler/UpdateItem.hs | |||
@@ -6,28 +6,28 @@ import Handler.Common | |||
6 | 6 | ||
7 | getUpdateItemR, postUpdateItemR :: ItemId -> Handler TypedContent | 7 | getUpdateItemR, postUpdateItemR :: ItemId -> Handler TypedContent |
8 | getUpdateItemR = postUpdateItemR | 8 | getUpdateItemR = postUpdateItemR |
9 | postUpdateItemR fsUpdateItem = do | 9 | postUpdateItemR fsUpdateId = do |
10 | Just entity <- fmap (Entity fsUpdateItem) <$> runDB (get fsUpdateItem) | 10 | Just entity <- fmap (Entity fsUpdateId) <$> runDB (get fsUpdateId) |
11 | 11 | ||
12 | ((updateResult, fsUpdateForm), fsUpdateEncoding) <- runFormPost . itemForm . Just $ entityVal entity | 12 | ((updateResult, fsUpdateForm), fsUpdateEncoding) <- runFormPost . itemForm . Just $ entityVal entity |
13 | 13 | ||
14 | mapM_ (addMessage "formError" . toHtml) =<< case updateResult of | 14 | mapM_ (addMessage "formError" . toHtml) =<< case updateResult of |
15 | FormSuccess Item{..} -> [] <$ runDB (update fsUpdateItem [ ItemKind =. itemKind | 15 | FormSuccess Item{..} -> [] <$ runDB (update fsUpdateId [ ItemKind =. itemKind |
16 | , ItemNormKind =. normalizeKind itemKind | 16 | , ItemNormKind =. normalizeKind itemKind |
17 | , ItemBought =. itemBought | 17 | , ItemBought =. itemBought |
18 | , ItemExpires =. itemExpires | 18 | , ItemExpires =. itemExpires |
19 | , ItemOpened =. itemOpened | 19 | , ItemOpened =. itemOpened |
20 | ]) | 20 | ]) |
21 | FormFailure errors -> return errors | 21 | FormFailure errors -> return errors |
22 | _ -> return [] | 22 | _ -> return [] |
23 | 23 | ||
24 | selectRep $ do | 24 | selectRep $ do |
25 | provideRep $ case updateResult of | 25 | provideRep $ case updateResult of |
26 | FormSuccess _ -> redirect $ InventoryListingR :#: fsUpdateItem :: Handler Html | 26 | FormSuccess _ -> redirect $ InventoryListingR :#: fsUpdateId :: Handler Html |
27 | _ -> do | 27 | _ -> do |
28 | (sortOn entityVal -> stock) <- runDB $ selectList [] [] | 28 | (sortOn entityVal -> stock) <- runDB $ selectList [] [] |
29 | defaultLayout $ inventoryListing InventoryState | 29 | defaultLayout $ inventoryListing InventoryState |
30 | { formState = Just UpdateForm{..} | 30 | { invFormState = Just UpdateForm{..} |
31 | , .. | 31 | , .. |
32 | } | 32 | } |
33 | provideJson () | 33 | provideJson () |