-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathMain.hs
164 lines (141 loc) · 4.58 KB
/
Main.hs
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
-- | Simple Miso app with some buttons, some text, but most importantly: a
-- component that encapsulates the flatpickr widget. Uses the component pattern
-- described in this example: https://github.com/FPtje/miso-component-example
module Main where
import Control.Concurrent ( forkIO )
import qualified Control.Concurrent.STM.TChan as STM
import Control.Lens ( (^.), (.=), (%=), makeLenses, zoom, use )
import Control.Monad ( forever, void )
import qualified Control.Monad.STM as STM
import Data.Monoid ( (<>) )
import qualified Data.Time.Calendar as Time
import qualified Data.Time.Clock as Time
import Data.Time.LocalTime ( LocalTime(..) )
import qualified Data.Time.LocalTime as Time
import qualified Data.Time.Format as Time
import qualified Flatpickr
import Flatpickr ( Interface(..), Opts(..) )
import Miso ( App(..), Transition )
import qualified Miso
import Miso.Html
import qualified Miso.String as Miso
data Model
= Model
{ _mFlatpickr :: !Flatpickr.Model
-- ^ The JS widget component.
, _mFlatpickrVisible :: !Bool
-- ^ Toggled by the "Toggle calendar visibility" button
, _mDate :: !Time.Day
-- ^ The currently selected date
}
deriving ( Eq )
makeLenses ''Model
data Action
= FlatpickrAction !Flatpickr.Action
-- ^ Passes Actions to the Flatpickr widget component.
| ToggleCalendarVisibility
| PreviousDay
| NextDay
| DateChange !Time.Day
-- ^ Thrown when the date is changed by the widget.
| NoOp
main :: IO ()
main = do
initModel <- initialModel
Miso.startApp App
{ initialAction = NoOp
, model = initModel
, update = Miso.fromTransition . updateModel
, view = viewModel
, events = Miso.defaultEvents
, subs = []
, mountPoint = Nothing
}
initialModel :: IO Model
initialModel = do
-- Initialise starting date to today
curTime <- Time.getCurrentTime
timeZone <- Time.getCurrentTimeZone
let day :: Time.Day
(LocalTime day _timeOfDay) = Time.utcToLocalTime timeZone curTime
pure Model
{ _mFlatpickr = Flatpickr.initialModel flatpickrOptions
, _mFlatpickrVisible = True
, _mDate = day
}
updateModel :: Action -> Transition Action Model ()
updateModel action = case action of
NoOp -> pure ()
FlatpickrAction act -> do
date <- use mDate
zoom mFlatpickr $
Flatpickr.updateModel (flatpickrIface date) act
ToggleCalendarVisibility ->
mFlatpickrVisible %= not
PreviousDay -> do
mDate %= Time.addDays (-1)
date <- use mDate
-- Update the widget with the new date
zoom mFlatpickr $
Flatpickr.updateModel
(flatpickrIface date)
(Flatpickr.SetDate date)
NextDay -> do
mDate %= Time.addDays 1
date <- use mDate
-- Update the widget with the new date
zoom mFlatpickr $
Flatpickr.updateModel
(flatpickrIface date)
(Flatpickr.SetDate date)
DateChange day ->
mDate .= day
viewModel :: Model -> View Action
viewModel m =
div_ []
( viewCalendar m ++
[ div_[]
[ button_ [ onClick PreviousDay ] [ text "Previous day" ]
, button_ [ onClick NextDay ] [ text "Next day" ]
]
, div_ []
[ h1_ []
[ text $ "Selected date: " <> Miso.toMisoString selectedDate
]
]
, div_ []
[ button_
[ onClick ToggleCalendarVisibility ]
[ text "Toggle calendar visibility" ]
]
]
)
where
selectedDate = Time.formatTime Time.defaultTimeLocale "%F" $ m ^. mDate
-- | Show the calendar, but only when it's been set to be visible.
viewCalendar :: Model -> [View Action]
viewCalendar m
| not (m ^. mFlatpickrVisible) = []
| otherwise =
[ Flatpickr.viewModel (flatpickrIface $ m ^. mDate) $ m ^. mFlatpickr
]
flatpickrOptions :: Opts
flatpickrOptions =
Opts
{ weekNumbers = True
, inline = True
}
-- | The Flatpickr component needs to know some things about the parent that
-- includes it. With the parent being this module, that information has to be
-- provided here.
flatpickrIface :: Time.Day -> Interface Action
flatpickrIface date =
Interface
{ uniqueId = "topLevelCalendar"
, passAction = FlatpickrAction
, onChanged = DateChange
, noop = NoOp
, initialDate = date
}