@colisweb/rescript-toolkit 4.12.1 → 4.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,98 +1,614 @@
1
- module ReactDayPicker = {
2
- type range = {
3
- from: Js.Nullable.t<Js.Date.t>,
4
- @as("to")
5
- to_: Js.Nullable.t<Js.Date.t>,
6
- }
1
+ @@warning("-22")
2
+ @@warning("-27")
7
3
 
8
- type modifier = {
9
- start: Js.Nullable.t<Js.Date.t>,
10
- @as("end")
11
- end_: Js.Nullable.t<Js.Date.t>,
12
- }
4
+ type range = {
5
+ from?: Js.Date.t,
6
+ to?: Js.Date.t,
7
+ }
8
+ module DateUtils = {
9
+ @module("react-day-picker")
10
+ external addToRange: (Js.Date.t, range) => range = "addToRange"
11
+ }
13
12
 
14
- module DateUtils = {
15
- @module("@colisweb/react-day-picker") @scope("DateUtils")
16
- external addDayToRange: (Js.Date.t, range) => range = "addDayToRange"
17
- }
13
+ type classnames = {
14
+ container: string,
15
+ overlayWrapper: string,
16
+ overlay: string,
17
+ }
18
18
 
19
- type selectedDays
20
- type disabledDays
21
-
22
- external toSelectedDays: 'a => selectedDays = "%identity"
23
-
24
- let makeSelectedDays = (range: range) => [range.from, range->Obj.magic]->toSelectedDays
25
-
26
- @obj
27
- external makeDisabledDays: (
28
- ~after: option<Js.Date.t>=?,
29
- ~before: option<Js.Date.t>=?,
30
- unit,
31
- ) => disabledDays = ""
32
-
33
- type dayPickerProps
34
-
35
- @obj
36
- external makeDayPickerProps: (
37
- ~selectedDays: selectedDays=?,
38
- ~disabledDays: disabledDays=?,
39
- ~toMonth: option<Js.Date.t>=?,
40
- ~fromMonth: option<Js.Date.t>=?,
41
- ~month: option<Js.Date.t>=?,
42
- ~modifiers: modifier,
43
- ~numberOfMonths: int,
44
- ~onDayClick: unit => unit=?,
45
- ~locale: string=?,
46
- ~weekdaysShort: 'a=?,
47
- ~months: 'a=?,
48
- unit,
49
- ) => dayPickerProps = ""
50
-
51
- type classnames = {
52
- container: string,
53
- overlayWrapper: string,
54
- overlay: string,
55
- }
19
+ type mode = [#single | #multiple | #range | #default]
20
+
21
+ type formatters = {
22
+ formatCaption?: Js.Date.t => React.element,
23
+ formatDay?: Js.Date.t => React.element,
24
+ formatMonthCaption?: Js.Date.t => React.element,
25
+ formatWeekNumber?: int => React.element,
26
+ formatWeekdayName?: Js.Date.t => React.element,
27
+ formatYearCaption?: Js.Date.t => React.element,
28
+ }
29
+
30
+ type modifiersClassNames = {
31
+ disabled?: string,
32
+ hidden?: string,
33
+ outside?: string,
34
+ range_end?: string,
35
+ range_middle?: string,
36
+ range_start?: string,
37
+ selected?: string,
38
+ today?: string,
39
+ closed?: string,
40
+ clicked?: string,
41
+ }
42
+
43
+ type interval = {before?: Js.Date.t, after?: Js.Date.t}
44
+
45
+ module Matcher = {
46
+ @unboxed
47
+ type rec t = Any('a): t
48
+ and case = Date(Js.Date.t) | DayOfWeek(int) | Range(range) | Interval(interval) | Bool(bool)
49
+
50
+ let date = (v: Js.Date.t) => Any(v)
51
+ let dayOfWeek = (v: int) => Any({"dayOfWeek": v})
52
+ let range = (v: range) => Any(v)
53
+ let interval = (v: interval) => Any(v)
54
+ let bool = (v: bool) => Any(v)
56
55
 
57
- module DayPickerInput = {
58
- @module("@colisweb/react-day-picker") @react.component
56
+ let make = (case: case): t =>
57
+ switch case {
58
+ | Date(v) => v->date
59
+ | DayOfWeek(v) => v->dayOfWeek
60
+ | Range(v) => v->range
61
+ | Interval(v) => v->interval
62
+ | Bool(v) => v->bool
63
+ }
64
+ }
65
+
66
+ type modifiers = {
67
+ disabled?: array<Matcher.t>,
68
+ hidden?: array<Matcher.t>,
69
+ outside?: array<Matcher.t>,
70
+ range_end?: array<Matcher.t>,
71
+ range_middle?: array<Matcher.t>,
72
+ range_start?: array<Matcher.t>,
73
+ selected?: array<Matcher.t>,
74
+ today?: array<Matcher.t>,
75
+ closed?: array<Matcher.t>,
76
+ clicked?: array<Matcher.t>,
77
+ }
78
+
79
+ module Bindings = {
80
+ module SingleDayPicker = {
81
+ @module("react-day-picker") @react.component
59
82
  external make: (
60
- ~formatDate: Js.Date.t => string=?,
61
- ~format: string=?,
62
- ~placeholder: string=?,
63
- ~value: Js.Date.t=?,
64
- ~onDayChange: Js.Date.t => unit=?,
65
- ~selectedDays: (Js.Date.t, range)=?,
66
- ~modifiers: modifier=?,
67
- ~classNames: classnames=?,
68
- ~locale: string=?,
69
- ~weekdaysShort: 'a=?,
70
- ~firstDayOfWeek: 'b=?,
71
- ~months: 'a=?,
83
+ ~mode: mode,
84
+ ~selected: Js.Date.t=?,
85
+ ~onSelect: (option<Js.Date.t>, Js.Date.t) => unit=?,
86
+ ~formatters: formatters=?,
87
+ ~modifiers: modifiers=?,
88
+ ~modifiersClassNames: modifiersClassNames=?,
89
+ ~locale: DateFns.dateFnsLocale=?,
90
+ ~defaultMonth: Js.Date.t=?,
91
+ ~numberOfMonths: int=?,
72
92
  ~showOutsideDays: bool=?,
73
- ~dayPickerProps: dayPickerProps=?,
74
- ~ref: ReactDOM.Ref.t=?,
75
- ) => React.element = "DayPickerInput"
93
+ ~className: string=?,
94
+ ~placeholder: string=?,
95
+ ~footer: React.element=?,
96
+ ) => React.element = "DayPicker"
76
97
  }
77
- module DayPicker = {
78
- @module("@colisweb/react-day-picker") @react.component
98
+ module RangeDayPicker = {
99
+ @module("react-day-picker") @react.component
79
100
  external make: (
80
- ~formatDate: Js.Date.t => string=?,
81
- ~format: string=?,
82
- ~placeholder: string=?,
83
- ~value: string=?,
84
- ~onDayClick: Js.Date.t => unit=?,
85
- ~selectedDays: (Js.Date.t, range)=?,
86
- ~modifiers: modifier=?,
87
- ~className: string=?,
88
- ~disabledDays: disabledDays=?,
89
- ~locale: string=?,
90
- ~weekdaysShort: 'a=?,
91
- ~firstDayOfWeek: 'b=?,
92
- ~months: 'a=?,
101
+ ~mode: mode,
102
+ ~selected: range=?,
103
+ ~onSelect: (option<range>, Js.Date.t) => unit=?,
104
+ ~formatters: formatters=?,
105
+ ~modifiers: modifiers=?,
106
+ ~modifiersClassNames: modifiersClassNames=?,
107
+ ~locale: DateFns.dateFnsLocale=?,
93
108
  ~numberOfMonths: int=?,
94
- ~initialMonth: Js.Date.t=?,
109
+ ~defaultMonth: Js.Date.t=?,
95
110
  ~showOutsideDays: bool=?,
111
+ ~className: string=?,
112
+ ~placeholder: string=?,
113
+ ~footer: React.element=?,
96
114
  ) => React.element = "DayPicker"
97
115
  }
98
116
  }
117
+
118
+ let applyHoursToRange = (~rangeToUpdate, ~hoursToApply) => {
119
+ Some({
120
+ from: ?(
121
+ rangeToUpdate
122
+ ->Option.flatMap(e => e.from)
123
+ ->Option.map(fromToUpdate =>
124
+ hoursToApply
125
+ ->Option.flatMap(e => e.from)
126
+ ->Option.mapWithDefault(fromToUpdate, fromToApply => {
127
+ fromToUpdate
128
+ ->Js.Date.setHoursM(~hours=fromToApply->Js.Date.getHours, ~minutes=0., ())
129
+ ->Js.Date.fromFloat
130
+ })
131
+ )
132
+ ),
133
+ to: ?(
134
+ rangeToUpdate
135
+ ->Option.flatMap(e => e.to)
136
+ ->Option.map(toToUpdate =>
137
+ hoursToApply
138
+ ->Option.flatMap(e => e.to)
139
+ ->Option.mapWithDefault(toToUpdate, totoApply => {
140
+ toToUpdate
141
+ ->Js.Date.setHoursM(~hours=totoApply->Js.Date.getHours, ~minutes=0., ())
142
+ ->Js.Date.fromFloat
143
+ })
144
+ )
145
+ ),
146
+ })
147
+ }
148
+
149
+ // onSelect callback parameters :
150
+ // #1: selectedDay (computed by library) can be empty
151
+ // #2: clickedDay (direct output onDayClick) mandatory
152
+ module SingleDayPicker = {
153
+ @react.component
154
+ let make = (
155
+ ~selected: Js.Date.t=?,
156
+ ~onSelect: (option<Js.Date.t>, Js.Date.t) => unit=?,
157
+ ~formatters: formatters=?,
158
+ ~modifiers: modifiers=?,
159
+ ~modifiersClassNames: modifiersClassNames={},
160
+ ~numberOfMonths: int=?,
161
+ ~defaultMonth: Js.Date.t=?,
162
+ ~showOutsideDays: bool=true,
163
+ ~className: string=?,
164
+ ~placeholder: string=?,
165
+ ~footer: React.element=?,
166
+ ) => {
167
+ let locale = ReactIntl.useIntl()
168
+
169
+ <Bindings.SingleDayPicker
170
+ {...%raw(`props`)}
171
+ mode=#single
172
+ showOutsideDays
173
+ locale={locale->ReactIntl.Intl.locale === "fr" ? DateFns.frLocale : DateFns.enLocale}
174
+ modifiersClassNames={
175
+ ...modifiersClassNames,
176
+ closed: cx(["rdp-day_closed", modifiersClassNames.closed->Option.getWithDefault("")]),
177
+ }
178
+ />
179
+ }
180
+ }
181
+
182
+ // onSelect callback parameters :
183
+ // #1: selectedDay (computed by library) can be empty
184
+ // #2: clickedDay (direct output onDayClick) mandatory
185
+ module RangeDayPicker = {
186
+ @react.component
187
+ let make = (
188
+ ~selected: range=?,
189
+ ~onSelect: (option<range>, Js.Date.t) => unit=?,
190
+ ~formatters: formatters=?,
191
+ ~modifiers: modifiers=?,
192
+ ~modifiersClassNames: modifiersClassNames={},
193
+ ~numberOfMonths: int=?,
194
+ ~defaultMonth: Js.Date.t=?,
195
+ ~showOutsideDays: bool=true,
196
+ ~className: string=?,
197
+ ~placeholder: string=?,
198
+ ~footer: React.element=?,
199
+ ) => {
200
+ let locale = ReactIntl.useIntl()
201
+
202
+ <Bindings.RangeDayPicker
203
+ {...%raw(`props`)}
204
+ mode=#range
205
+ showOutsideDays
206
+ locale={locale->ReactIntl.Intl.locale === "fr" ? DateFns.frLocale : DateFns.enLocale}
207
+ modifiersClassNames={
208
+ ...modifiersClassNames,
209
+ closed: cx(["rdp-day_closed", modifiersClassNames.closed->Option.getWithDefault("")]),
210
+ }
211
+ />
212
+ }
213
+ }
214
+
215
+ module SingleDayPickerInput = {
216
+ @react.component
217
+ let make = (
218
+ ~labelFormatter: Js.Date.t => React.element=?,
219
+ ~labelClassName: string="",
220
+ ~dropdownClassName: string="",
221
+ ~buttonClassName: string="",
222
+ ~placeholder: React.element=?,
223
+ ~value: Js.Date.t=?,
224
+ ~onChange: option<Js.Date.t> => unit,
225
+ ~resetButton=false,
226
+ ~allowEmpty=false,
227
+ ~modifiers=?,
228
+ ~modifiersClassNames=?,
229
+ ~showOutsideDays: bool=true,
230
+ ~defaultMonth: Js.Date.t=?,
231
+ ) => {
232
+ let (validatedValue, setValidatedValue) = React.useState(() => value)
233
+ let (localValue, setLocalValue) = React.useState(() => validatedValue)
234
+
235
+ React.useEffect1(() => {
236
+ setLocalValue(_ => value)
237
+ setValidatedValue(_ => value)
238
+ None
239
+ }, [value])
240
+
241
+ let labelFormatter =
242
+ labelFormatter->Option.getWithDefault(date =>
243
+ <ReactIntl.FormattedDate value={date} day=#"2-digit" month=#"2-digit" year=#numeric />
244
+ )
245
+
246
+ <Toolkit__Ui_PortalDropdown
247
+ dropdownClassName
248
+ buttonClassName={cx(["min-w-[100px]", buttonClassName])}
249
+ label={<p className=labelClassName>
250
+ {validatedValue->Option.mapWithDefault(
251
+ placeholder->Option.getWithDefault("-"->React.string),
252
+ labelFormatter,
253
+ )}
254
+ </p>}>
255
+ {disclosure => {
256
+ <>
257
+ <SingleDayPicker
258
+ ?modifiers
259
+ ?modifiersClassNames
260
+ ?defaultMonth
261
+ selected=?{localValue}
262
+ onSelect={(date, _) => setLocalValue(_ => date)}
263
+ showOutsideDays
264
+ />
265
+ <div className="flex justify-end gap-2">
266
+ {resetButton
267
+ ? <Toolkit__Ui_Button
268
+ onClick={_ => {
269
+ setLocalValue(_ => None)
270
+ setValidatedValue(_ => None)
271
+ onChange(None)
272
+ disclosure.hide()
273
+ }}>
274
+ <ReactIntl.FormattedMessage defaultMessage="Réinitialiser" />
275
+ </Toolkit__Ui_Button>
276
+ : React.null}
277
+ <Toolkit__Ui_Button
278
+ onClick={_ => {
279
+ setLocalValue(_ => validatedValue)
280
+ disclosure.hide()
281
+ }}>
282
+ <ReactIntl.FormattedMessage defaultMessage="Annuler" />
283
+ </Toolkit__Ui_Button>
284
+ <Toolkit__Ui_Button
285
+ color=#success
286
+ disabled={localValue->Option.isNone}
287
+ onClick={_ => {
288
+ setValidatedValue(_ => localValue)
289
+ onChange(localValue)
290
+ disclosure.hide()
291
+ }}>
292
+ <ReactIntl.FormattedMessage defaultMessage="Valider" />
293
+ </Toolkit__Ui_Button>
294
+ </div>
295
+ </>
296
+ }}
297
+ </Toolkit__Ui_PortalDropdown>
298
+ }
299
+ }
300
+ module RangeDayPickerInput = {
301
+ let hours = Array.make(24, "")->Array.mapWithIndex((index, _) => {
302
+ let prefix = switch index {
303
+ | i if i < 10 => "0"
304
+ | _ => ""
305
+ }
306
+
307
+ {
308
+ Toolkit__Ui_Select.label: `${prefix}${index->Int.toString}:00`,
309
+ Toolkit__Ui_Select.value: index->Int.toString,
310
+ }
311
+ })
312
+
313
+ module PresetRanges = {
314
+ let now = Js.Date.make()
315
+ let currentDayRange: range = {
316
+ from: now->DateFns.startOfDay,
317
+ to: now->DateFns.endOfDay,
318
+ }
319
+ let currentWeekRange: range = {
320
+ from: now->DateFns.startOfWeek({weekStartsOn: 1}),
321
+ to: now->DateFns.endOfWeek({weekStartsOn: 1}),
322
+ }
323
+ let currentMonthRange: range = {
324
+ from: now->DateFns.startOfMonth,
325
+ to: now->DateFns.endOfMonth,
326
+ }
327
+ }
328
+
329
+ type state = {
330
+ range: option<range>,
331
+ startHour: float,
332
+ endHour: float,
333
+ }
334
+
335
+ type action =
336
+ | UpdateRange(option<range>)
337
+ | UpdateStartHour(float)
338
+ | UpdateEndHour(float)
339
+ | ResetRange
340
+
341
+ @react.component
342
+ let make = (
343
+ ~labelFormatter: range => React.element=?,
344
+ ~labelClassName="",
345
+ ~dropdownClassName="",
346
+ ~buttonClassName="",
347
+ ~value: option<range>=?,
348
+ ~onChange: option<range> => unit,
349
+ ~placeholder=?,
350
+ ~withHours=false,
351
+ ~resetButton=false,
352
+ ~allowEmpty=false,
353
+ ~withPresetRanges=false,
354
+ ~showOutsideDays: bool=true,
355
+ ~modifiers: modifiers=?,
356
+ ~modifiersClassNames: modifiersClassNames=?,
357
+ ~defaultMonth: Js.Date.t=?,
358
+ ) => {
359
+ let (validatedRange, setValidatedRange) = React.useState(() => value)
360
+
361
+ let (state, dispatch) = ReactUpdate.useReducerWithMapState(
362
+ (state, action) =>
363
+ switch action {
364
+ | UpdateRange(range) =>
365
+ UpdateWithSideEffects(
366
+ {...state, range},
367
+ ({state, send}) => {
368
+ if withHours {
369
+ send(UpdateStartHour(state.startHour))
370
+ send(UpdateEndHour(state.endHour))
371
+ }
372
+ None
373
+ },
374
+ )
375
+ | ResetRange =>
376
+ Update({
377
+ ...state,
378
+ range: None,
379
+ })
380
+ | UpdateStartHour(startHour) =>
381
+ Update({
382
+ ...state,
383
+ startHour,
384
+ range: Some({
385
+ to: ?state.range->Option.flatMap(v => v.to),
386
+ from: ?(
387
+ state.range
388
+ ->Option.flatMap(v => v.from)
389
+ ->Option.map(v =>
390
+ v->Js.Date.setHoursM(~hours=startHour, ~minutes=0., ())->Js.Date.fromFloat
391
+ )
392
+ ),
393
+ }),
394
+ })
395
+ | UpdateEndHour(endHour) =>
396
+ Update({
397
+ ...state,
398
+ endHour,
399
+ range: Some({
400
+ from: ?state.range->Option.flatMap(v => v.from),
401
+ to: ?(
402
+ state.range
403
+ ->Option.flatMap(v => v.to)
404
+ ->Option.map(v =>
405
+ v->Js.Date.setHoursM(~hours=endHour, ~minutes=0., ())->Js.Date.fromFloat
406
+ )
407
+ ),
408
+ }),
409
+ })
410
+ },
411
+ () => {
412
+ range: value,
413
+ startHour: value
414
+ ->Option.flatMap(v => v.from)
415
+ ->Option.mapWithDefault(6., v => v->Js.Date.getHours),
416
+ endHour: value
417
+ ->Option.flatMap(v => v.to)
418
+ ->Option.mapWithDefault(23., v => v->Js.Date.getHours),
419
+ },
420
+ )
421
+
422
+ React.useEffect1(() => {
423
+ dispatch(UpdateRange(value))
424
+ None
425
+ }, [value])
426
+
427
+ let labelFormatter = labelFormatter->Option.getWithDefault(range =>
428
+ <div>
429
+ <p className="text-xs leading-4">
430
+ {range.from->Option.mapWithDefault("-"->React.string, date => {
431
+ <ReactIntl.FormattedDate
432
+ value={date}
433
+ day=#"2-digit"
434
+ month=#"2-digit"
435
+ year=#numeric
436
+ hour=?{withHours ? Some(#"2-digit") : None}
437
+ minute=?{withHours ? Some(#"2-digit") : None}
438
+ />
439
+ })}
440
+ </p>
441
+ <p className="text-xs leading-4">
442
+ {range.to->Option.mapWithDefault("-"->React.string, date => {
443
+ <ReactIntl.FormattedDate
444
+ value={date}
445
+ day=#"2-digit"
446
+ month=#"2-digit"
447
+ year=#numeric
448
+ hour=?{withHours ? Some(#"2-digit") : None}
449
+ minute=?{withHours ? Some(#"2-digit") : None}
450
+ />
451
+ })}
452
+ </p>
453
+ </div>
454
+ )
455
+
456
+ <Toolkit__Ui_PortalDropdown
457
+ dropdownClassName
458
+ buttonClassName={cx(["min-w-[100px] h-[38px]", buttonClassName])}
459
+ label={<div className={cx(["absolute", labelClassName])}>
460
+ {validatedRange->Option.mapWithDefault(
461
+ placeholder->Option.getWithDefault("-"->React.string),
462
+ labelFormatter,
463
+ )}
464
+ </div>}>
465
+ {disclosure => {
466
+ <div className="flex flex-col items-center">
467
+ {withPresetRanges
468
+ ? <div className="w-full flex flex-col pb-2 border-b-2 mb-2">
469
+ <div
470
+ className="flex flex-row flex-nowrap items-center justify-start pb-2 border-b mb-2">
471
+ <Toolkit__Ui_Button
472
+ onClick={_ => dispatch(UpdateRange(Some(PresetRanges.currentDayRange)))}
473
+ size=#sm
474
+ color=#primary
475
+ variant=#outline
476
+ className="w-1/2">
477
+ <ReactIntl.FormattedMessage defaultMessage="Aujourd'hui" />
478
+ </Toolkit__Ui_Button>
479
+ <p className="ml-4">
480
+ <ReactIntl.FormattedDate
481
+ value={Js.Date.make()} day=#"2-digit" month=#"2-digit" year=#numeric
482
+ />
483
+ </p>
484
+ </div>
485
+ <div
486
+ className="flex flex-row flex-nowrap pb-2 border-b mb-2 items-center justify-start">
487
+ <Toolkit__Ui_Button
488
+ onClick={_ => dispatch(UpdateRange(Some(PresetRanges.currentWeekRange)))}
489
+ size=#sm
490
+ color=#primary
491
+ variant=#outline
492
+ className="w-1/2">
493
+ <ReactIntl.FormattedMessage defaultMessage="Cette semaine" />
494
+ </Toolkit__Ui_Button>
495
+ <p className="ml-4">
496
+ <ReactIntl.FormattedMessage
497
+ defaultMessage="Semaine {number}"
498
+ values={"number": DateFns.getWeekNumber(Js.Date.make(), {weekStartsOn: 1})}
499
+ />
500
+ </p>
501
+ </div>
502
+ <div className="flex flex-row flex-nowrap items-center justify-start">
503
+ <Toolkit__Ui_Button
504
+ onClick={_ => dispatch(UpdateRange(Some(PresetRanges.currentMonthRange)))}
505
+ size=#sm
506
+ color=#primary
507
+ variant=#outline
508
+ className="w-1/2">
509
+ <ReactIntl.FormattedMessage defaultMessage="Ce mois" />
510
+ </Toolkit__Ui_Button>
511
+ <p className="ml-4 capitalize">
512
+ <ReactIntl.FormattedDate value={Js.Date.make()} month=#long />
513
+ </p>
514
+ </div>
515
+ </div>
516
+ : React.null}
517
+ {withHours
518
+ ? <div className="flex flex-row flex-nowrap justify-between px-2 gap-2">
519
+ {state.range
520
+ ->Option.flatMap(e => e.from)
521
+ ->Option.mapWithDefault(React.null, from =>
522
+ <div className="flex flex-row items-center">
523
+ <div className="mr-2">
524
+ <p>
525
+ <ReactIntl.FormattedMessage defaultMessage="Début" />
526
+ </p>
527
+ <p className="text-xs">
528
+ <ReactIntl.FormattedDate
529
+ value=from day=#"2-digit" month=#"2-digit" year=#numeric
530
+ />
531
+ </p>
532
+ </div>
533
+ <Toolkit__Ui_Select
534
+ value={from->Js.Date.getHours->Float.toString}
535
+ onChange={value => {
536
+ dispatch(UpdateStartHour(value->Float.fromString->Option.getExn))
537
+ }}
538
+ options=hours
539
+ />
540
+ </div>
541
+ )}
542
+ {state.range
543
+ ->Option.flatMap(e => e.to)
544
+ ->Option.mapWithDefault(React.null, to =>
545
+ <div className="flex flex-row items-center">
546
+ <div className="mr-2">
547
+ <p>
548
+ <ReactIntl.FormattedMessage defaultMessage="Fin" />
549
+ </p>
550
+ <p className="text-xs">
551
+ <ReactIntl.FormattedDate
552
+ value=to day=#"2-digit" month=#"2-digit" year=#numeric
553
+ />
554
+ </p>
555
+ </div>
556
+ <Toolkit__Ui_Select
557
+ value={to->Js.Date.getHours->Float.toString}
558
+ onChange={value => {
559
+ dispatch(UpdateEndHour(value->Float.fromString->Option.getExn))
560
+ }}
561
+ options=hours
562
+ />
563
+ </div>
564
+ )}
565
+ </div>
566
+ : React.null}
567
+ <RangeDayPicker
568
+ ?modifiers
569
+ ?modifiersClassNames
570
+ ?defaultMonth
571
+ selected=?{state.range}
572
+ onSelect={(newValue, _) => {
573
+ dispatch(UpdateRange(newValue))
574
+ }}
575
+ showOutsideDays
576
+ />
577
+ <div className="w-full flex justify-end gap-2">
578
+ {resetButton
579
+ ? <Toolkit__Ui_Button
580
+ onClick={_ => {
581
+ dispatch(ResetRange)
582
+ setValidatedRange(_ => None)
583
+ onChange(None)
584
+ disclosure.hide()
585
+ }}>
586
+ <ReactIntl.FormattedMessage defaultMessage="Réinitialiser" />
587
+ </Toolkit__Ui_Button>
588
+ : React.null}
589
+ <Toolkit__Ui_Button
590
+ onClick={_ => {
591
+ dispatch(UpdateRange(validatedRange))
592
+ disclosure.hide()
593
+ }}>
594
+ <ReactIntl.FormattedMessage defaultMessage="Annuler" />
595
+ </Toolkit__Ui_Button>
596
+ <Toolkit__Ui_Button
597
+ color=#success
598
+ disabled={allowEmpty
599
+ ? false
600
+ : state.range->Option.flatMap(e => e.from)->Option.isNone ||
601
+ state.range->Option.flatMap(e => e.to)->Option.isNone}
602
+ onClick={_ => {
603
+ setValidatedRange(_ => state.range)
604
+ onChange(state.range)
605
+ disclosure.hide()
606
+ }}>
607
+ <ReactIntl.FormattedMessage defaultMessage="Valider" />
608
+ </Toolkit__Ui_Button>
609
+ </div>
610
+ </div>
611
+ }}
612
+ </Toolkit__Ui_PortalDropdown>
613
+ }
614
+ }