1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
module Page
( component
, Query
, init
) where
import Control.Monad.Aff (Aff)
import Data.Array (sortBy, filter, reverse)
import Data.Maybe (Maybe(..))
import Data.String (contains, Pattern(..))
import DOM (DOM)
import Halogen as H
import Halogen.HTML as HH
import Halogen.HTML.Events as HE
import Halogen.HTML.Properties as HP
import Prelude
import Food (Aliment)
import Food as Food
import Format as Format
import Indicator as Indicator
import Order (Order, OrderKind)
import Order as Order
data Query a =
UpdateSearch String a
| SelectOrder OrderKind a
type State =
{ search :: String
, order :: Order
}
init :: State
init =
{ search: ""
, order: Order.init
}
type Message = Unit
component :: forall eff. H.Component HH.HTML Query State Message (Aff (dom :: DOM | eff))
component =
H.component
{ initialState: const init
, render
, eval
, receiver: const Nothing
}
where
render :: State -> H.ComponentHTML Query
render state =
HH.div
[ HP.class_ $ HH.ClassName "page" ]
[ renderHeader state.order.kind state.search
, HH.div
[ HP.class_ $ HH.ClassName "aliments" ]
( Food.all
# filter (\a -> contains (Pattern $ Format.string state.search) (Format.string a.name))
# sortBy compareAliments
# (if state.order.direction == Order.Ascending then id else reverse)
# map renderAliment
)
]
where
compareAliments :: Aliment -> Aliment -> Ordering
compareAliments a b =
case state.order.kind of
Order.Name -> compare (Format.string a.name) (Format.string b.name)
Order.GlycemicIndex -> compare a.glycemicIndex b.glycemicIndex
Order.Carbohydrates -> compare a.carbohydrates b.carbohydrates
Order.GlycemicLoad -> compare (Food.glycemicLoad a) (Food.glycemicLoad b)
eval :: Query ~> H.ComponentDSL State Query Message (Aff (dom :: DOM | eff))
eval = case _ of
UpdateSearch search next -> do
state <- H.get
H.put $ state { search = search }
pure next
SelectOrder kind next -> do
state <- H.get
H.put $ state { order = Order.select kind state.order }
pure next
renderHeader :: OrderKind -> String -> H.ComponentHTML Query
renderHeader orderKind search =
HH.div
[ HP.class_ $ HH.ClassName "header" ]
[ HH.div
[ HP.class_ $ HH.ClassName "title line" ]
[ button Order.Name "Aliment"
, button Order.GlycemicIndex "Index glycémique"
, button Order.Carbohydrates "Glucides pour 100 g"
, button Order.GlycemicLoad "Charge glycémique"
]
, HH.input
[ HP.class_ $ HH.ClassName "search line"
, HP.placeholder "Rechercher…"
, HE.onValueInput (HE.input UpdateSearch)
, HP.value search
]
]
where
button :: OrderKind -> String -> H.ComponentHTML Query
button kind label =
HH.button
[ HE.onClick (HE.input_ (SelectOrder kind))
, HP.class_ $ HH.ClassName (if orderKind == kind then "sorted" else "")
]
[ HH.text label ]
renderAliment :: Aliment -> H.ComponentHTML Query
renderAliment aliment =
HH.div
[ HP.class_ $ HH.ClassName "aliment line" ]
[ HH.div
[]
[ HH.text aliment.name ]
, HH.div
[ HP.class_ $ HH.ClassName "number" ]
[ HH.text (show aliment.glycemicIndex) ]
, HH.div
[ HP.class_ $ HH.ClassName "number" ]
[ HH.text (show aliment.carbohydrates <> " g") ]
, let glycemicLoad = Food.glycemicLoad aliment
in HH.div
[ HP.class_ $ HH.ClassName ("number " <> (Indicator.className $ Indicator.fromGlycemicLoad glycemicLoad)) ]
[ HH.text (Format.number 2 glycemicLoad) ]
]
|