@@ -6,6 +6,7 @@ module Ocelot.DateTimePicker
66 , ComponentM
77 , ComponentRender
88 , Input
9+ , Interval
910 , Output (..)
1011 , Query (..)
1112 , Slot
@@ -14,8 +15,11 @@ module Ocelot.DateTimePicker
1415 ) where
1516
1617import Prelude
17- import Data.DateTime (Date , DateTime (..), Month , Time , Year , date , time )
18+ import Data.DateTime (Date , DateTime (..), Month , Time , Year )
19+ import Data.DateTime as Date.DateTime
20+ import Data.Foldable as Data.Foldable
1821import Data.Maybe (Maybe (..))
22+ import Data.Maybe as Data.Maybe
1923import Data.Tuple.Nested (type (/\))
2024import Effect.Aff.Class (class MonadAff )
2125import Halogen as H
@@ -31,6 +35,7 @@ import Type.Proxy (Proxy(..))
3135data Action
3236 = HandleDate DatePicker.Output
3337 | HandleTime TimePicker.Output
38+ | Receive Input
3439
3540type ChildSlots =
3641 ( datepicker :: DatePicker.Slot Unit
@@ -46,9 +51,15 @@ type ComponentM m a = H.HalogenM State Action ChildSlots Output m a
4651type ComponentRender m = State -> ComponentHTML m
4752
4853type Input =
49- { selection :: Maybe DateTime
54+ { disabled :: Boolean
55+ , interval :: Maybe Interval
56+ , selection :: Maybe DateTime
5057 , targetDate :: Maybe (Year /\ Month )
51- , disabled :: Boolean
58+ }
59+
60+ type Interval =
61+ { start :: Maybe DateTime
62+ , end :: Maybe DateTime
5263 }
5364
5465data Output
@@ -67,9 +78,10 @@ type Slot = H.Slot Query Output
6778
6879type State =
6980 { date :: Maybe Date
70- , time :: Maybe Time
71- , targetDate :: Maybe (Year /\ Month )
7281 , disabled :: Boolean
82+ , interval :: Maybe Interval
83+ , targetDate :: Maybe (Year /\ Month )
84+ , time :: Maybe Time
7385 }
7486
7587-- ----------
@@ -82,6 +94,7 @@ component = H.mkComponent
8294 , eval: H .mkEval H .defaultEval
8395 { handleAction = handleAction
8496 , handleQuery = handleQuery
97+ , receive = Just <<< Receive
8598 }
8699 }
87100
@@ -95,16 +108,18 @@ handleAction :: forall m. Action -> ComponentM m Unit
95108handleAction = case _ of
96109 HandleDate msg -> case msg of
97110 DatePicker.SelectionChanged date' -> do
98- time' <- H .gets _.time
99- H .raise $ SelectionChanged ( DateTime <$> date' <*> time')
111+ state <- H .get
112+ raiseSelectionChanged state.interval date' state. time
100113 H .modify_ _ { date = date' }
101114 _ -> H .raise $ DateOutput msg
102115 HandleTime msg -> case msg of
103116 TimePicker.SelectionChanged time' -> do
104- date' <- H .gets _.date
105- H .raise $ SelectionChanged ( DateTime <$> date' <*> time')
117+ state <- H .get
118+ raiseSelectionChanged state.interval state. date time'
106119 H .modify_ _ { time = time' }
107120 _ -> H .raise $ TimeOutput msg
121+ Receive input -> do
122+ H .modify_ _ { interval = input.interval }
108123
109124handleQuery :: forall m a . Query a -> ComponentM m (Maybe a )
110125handleQuery = case _ of
@@ -116,42 +131,87 @@ handleQuery = case _ of
116131 void $ H .tell _datepicker unit $ DatePicker.SetDisabled disabled
117132 void $ H .tell _timepicker unit $ TimePicker.SetDisabled disabled
118133 SetSelection dateTime a -> Just a <$ do
119- let date' = date <$> dateTime
120- time' = time <$> dateTime
134+ let date' = dateTime <#> Date.DateTime .date
135+ time' = dateTime <#> Date.DateTime .time
121136 void $ H .tell _datepicker unit $ DatePicker.SetSelection date'
122137 void $ H .tell _timepicker unit $ TimePicker.SetSelection time'
123138 H .modify_ _ { date = date', time = time' }
124139 SendDateQuery q a -> Just a <$ H .query _datepicker unit q
125140 SendTimeQuery q a -> Just a <$ H .query _timepicker unit q
126141
127142initialState :: Input -> State
128- initialState { selection, targetDate, disabled } =
129- { date: date <$> selection
130- , time: time <$> selection
131- , targetDate
132- , disabled
143+ initialState input =
144+ { date: input.selection <#> Date.DateTime .date
145+ , disabled: input.disabled
146+ , interval: input.interval
147+ , targetDate: input.targetDate
148+ , time: input.selection <#> Date.DateTime .time
133149 }
134150
151+ -- check if a datetime is within a **closed** interval
152+ isWithinInterval :: Interval -> DateTime -> Boolean
153+ isWithinInterval interval x =
154+ Data.Foldable .and
155+ [ Data.Maybe .maybe true (_ <= x) interval.start
156+ , Data.Maybe .maybe true (x <= _) interval.end
157+ ]
158+
159+ raiseSelectionChanged ::
160+ forall m .
161+ Maybe Interval ->
162+ Maybe Date ->
163+ Maybe Time ->
164+ ComponentM m Unit
165+ raiseSelectionChanged mInterval mDate mTime = case mInterval of
166+ Nothing -> H .raise $ SelectionChanged mDateTime
167+ Just interval -> case mDateTime of
168+ Nothing -> H .raise $ SelectionChanged mDateTime
169+ Just dateTime
170+ | isWithinInterval interval dateTime -> H .raise $ SelectionChanged mDateTime
171+ | otherwise -> pure unit -- NOTE transient state during parent-child synchronization
172+ where
173+ mDateTime :: Maybe DateTime
174+ mDateTime = DateTime <$> mDate <*> mTime
175+
176+
135177render :: forall m . MonadAff m => ComponentRender m
136- render { date, time, targetDate, disabled } =
178+ render state =
137179 HH .div
138180 [ css " flex" ]
139181 [ HH .div
140182 [ css " w-1/2 mr-2" ]
141183 [ HH .slot _datepicker unit DatePicker .component
142- { disabled
143- , interval: Nothing -- TODO AS-1344
144- , selection: date
145- , targetDate
184+ { disabled: state.disabled
185+ , interval: do
186+ interval <- state.interval
187+ pure
188+ { start: interval.start <#> Date.DateTime .date
189+ , end: interval.end <#> Date.DateTime .date
190+ }
191+ , selection: state.date
192+ , targetDate: state.targetDate
146193 }
147194 HandleDate
148195 ]
149196 , HH .div
150197 [ css " flex-1" ]
151198 [ HH .slot _timepicker unit TimePicker .component
152- { disabled
153- , interval: Nothing -- TODO AS-1344
154- , selection: time
199+ { disabled: state.disabled
200+ , interval: do
201+ interval <- state.interval
202+ pure
203+ { start:
204+ if (interval.start <#> Date.DateTime .date) == state.date then
205+ interval.start <#> Date.DateTime .time
206+ else
207+ Nothing
208+ , end:
209+ if (interval.end <#> Date.DateTime .date) == state.date then
210+ interval.end <#> Date.DateTime .time
211+ else
212+ Nothing
213+ }
214+ , selection: state.time
155215 }
156216 HandleTime
157217 ]
0 commit comments