@colisweb/rescript-toolkit 4.9.2 → 4.10.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.
package/package.json
CHANGED
package/src/ui/Toolkit__Ui.res
CHANGED
|
@@ -17,21 +17,33 @@ let make = (~coordinates: Toolkit__Decoders.Coordinates.t, ~copyWrapperClassName
|
|
|
17
17
|
"lat": _ =>
|
|
18
18
|
<FormattedNumberParts value={coordinates.latitude} maximumFractionDigits={10}>
|
|
19
19
|
{(~formattedNumberParts) => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
switch formattedNumberParts {
|
|
21
|
+
| [{value}] => value->React.string
|
|
22
|
+
| [{value}, _] => value->React.string
|
|
23
|
+
| [val1, _, val2] =>
|
|
24
|
+
<>
|
|
25
|
+
{val1.value->React.string}
|
|
26
|
+
{"."->React.string}
|
|
27
|
+
{val2.value->React.string}
|
|
28
|
+
</>
|
|
29
|
+
| _ => React.null
|
|
30
|
+
}
|
|
25
31
|
}}
|
|
26
32
|
</FormattedNumberParts>,
|
|
27
33
|
"lng": _ =>
|
|
28
34
|
<FormattedNumberParts value={coordinates.longitude} maximumFractionDigits={10}>
|
|
29
35
|
{(~formattedNumberParts) => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
switch formattedNumberParts {
|
|
37
|
+
| [{value}] => value->React.string
|
|
38
|
+
| [{value}, _] => value->React.string
|
|
39
|
+
| [val1, _, val2] =>
|
|
40
|
+
<>
|
|
41
|
+
{val1.value->React.string}
|
|
42
|
+
{"."->React.string}
|
|
43
|
+
{val2.value->React.string}
|
|
44
|
+
</>
|
|
45
|
+
| _ => React.null
|
|
46
|
+
}
|
|
35
47
|
}}
|
|
36
48
|
</FormattedNumberParts>,
|
|
37
49
|
}}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
open ReactIntl
|
|
2
|
+
|
|
3
|
+
type rec state = {
|
|
4
|
+
period: period,
|
|
5
|
+
selectedDay: option<Js.Date.t>,
|
|
6
|
+
}
|
|
7
|
+
and period = {
|
|
8
|
+
start: Js.Date.t,
|
|
9
|
+
end_: Js.Date.t,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type action =
|
|
13
|
+
| PreviousPeriod
|
|
14
|
+
| NextPeriod
|
|
15
|
+
| UpdateSelectedDay(option<Js.Date.t>)
|
|
16
|
+
|
|
17
|
+
let updateQueryParams = (state: state) => {
|
|
18
|
+
RescriptReactRouter.replace(
|
|
19
|
+
Qs.stringifyWithParams(
|
|
20
|
+
{
|
|
21
|
+
"start": Some(state.period.start),
|
|
22
|
+
"selectedDay": state.selectedDay,
|
|
23
|
+
}->Obj.magic,
|
|
24
|
+
Qs.makeParams(
|
|
25
|
+
~addQueryPrefix=true,
|
|
26
|
+
~serializeDate=d => d->DateFns.formatWithPattern("yyyy-MM-dd"),
|
|
27
|
+
(),
|
|
28
|
+
),
|
|
29
|
+
),
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/*
|
|
34
|
+
* The key is a formatted date
|
|
35
|
+
* ex:
|
|
36
|
+
* {
|
|
37
|
+
* "2023-03-03": 2
|
|
38
|
+
* }
|
|
39
|
+
*/
|
|
40
|
+
type dayCounter = Js.Dict.t<int>
|
|
41
|
+
|
|
42
|
+
@react.component
|
|
43
|
+
let make = (
|
|
44
|
+
~startOfWeek: option<Js.Date.t>=?,
|
|
45
|
+
~selectedDay: option<Js.Date.t>=?,
|
|
46
|
+
~className="",
|
|
47
|
+
~counters: option<dayCounter>=?,
|
|
48
|
+
~children,
|
|
49
|
+
) => {
|
|
50
|
+
let {isSm} = Toolkit__Hooks.useMediaQuery()
|
|
51
|
+
|
|
52
|
+
let periodLength = isSm ? 7 : 3
|
|
53
|
+
let ({period, selectedDay}, dispatch) = ReactUpdate.useReducerWithMapState(
|
|
54
|
+
(state, action) =>
|
|
55
|
+
switch action {
|
|
56
|
+
| PreviousPeriod =>
|
|
57
|
+
UpdateWithSideEffects(
|
|
58
|
+
{
|
|
59
|
+
period: {
|
|
60
|
+
start: state.period.start->DateFns.subDays(periodLength)->DateFns.startOfDay,
|
|
61
|
+
end_: state.period.start->DateFns.subDays(1),
|
|
62
|
+
},
|
|
63
|
+
selectedDay: state.selectedDay->Option.map(_ =>
|
|
64
|
+
state.period.start->DateFns.subDays(periodLength)->DateFns.startOfDay
|
|
65
|
+
),
|
|
66
|
+
},
|
|
67
|
+
({state}) => {
|
|
68
|
+
updateQueryParams(state)
|
|
69
|
+
|
|
70
|
+
None
|
|
71
|
+
},
|
|
72
|
+
)
|
|
73
|
+
| NextPeriod =>
|
|
74
|
+
UpdateWithSideEffects(
|
|
75
|
+
{
|
|
76
|
+
period: {
|
|
77
|
+
start: state.period.end_->DateFns.addDays(1),
|
|
78
|
+
end_: state.period.end_->DateFns.addDays(periodLength),
|
|
79
|
+
},
|
|
80
|
+
selectedDay: state.selectedDay->Option.map(_ => state.period.end_->DateFns.addDays(1)),
|
|
81
|
+
},
|
|
82
|
+
({state}) => {
|
|
83
|
+
updateQueryParams(state)
|
|
84
|
+
|
|
85
|
+
None
|
|
86
|
+
},
|
|
87
|
+
)
|
|
88
|
+
| UpdateSelectedDay(date) =>
|
|
89
|
+
UpdateWithSideEffects(
|
|
90
|
+
{...state, selectedDay: date},
|
|
91
|
+
({state}) => {
|
|
92
|
+
updateQueryParams(state)
|
|
93
|
+
None
|
|
94
|
+
},
|
|
95
|
+
)
|
|
96
|
+
},
|
|
97
|
+
() => {
|
|
98
|
+
let defaultPeriod: period = {
|
|
99
|
+
let today = Js.Date.make()
|
|
100
|
+
let timeSlotStart = isSm ? DateFns.startOfWeek(today, {weekStartsOn: 1}) : today
|
|
101
|
+
|
|
102
|
+
let timeSlotEnd = isSm
|
|
103
|
+
? DateFns.endOfWeek(today, {weekStartsOn: 1})
|
|
104
|
+
: today->DateFns.addDays(2)
|
|
105
|
+
{
|
|
106
|
+
start: timeSlotStart,
|
|
107
|
+
end_: timeSlotEnd,
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
{
|
|
112
|
+
period: startOfWeek->Option.mapWithDefault(defaultPeriod, start => {
|
|
113
|
+
start,
|
|
114
|
+
end_: start->DateFns.addDays(periodLength - 1),
|
|
115
|
+
}),
|
|
116
|
+
selectedDay: selectedDay->Option.isSome
|
|
117
|
+
? selectedDay
|
|
118
|
+
: isSm
|
|
119
|
+
? None
|
|
120
|
+
: Some(startOfWeek->Option.getWithDefault(defaultPeriod.start)),
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
)
|
|
124
|
+
let intl = useIntl()
|
|
125
|
+
|
|
126
|
+
<div className>
|
|
127
|
+
<div className="border-neutral-300 flex justify-center items-center py-3">
|
|
128
|
+
<Toolkit__Ui_IconButton
|
|
129
|
+
size=#xs
|
|
130
|
+
variant=#outline
|
|
131
|
+
color=#neutral
|
|
132
|
+
onClick={_ => dispatch(PreviousPeriod)}
|
|
133
|
+
ariaLabel="previous week"
|
|
134
|
+
icon={<ReactIcons.MdKeyboardArrowLeft size=30 />}
|
|
135
|
+
/>
|
|
136
|
+
<div className="flex items-center mx-2">
|
|
137
|
+
{DateFns.eachDayOfInterval({
|
|
138
|
+
start: period.start,
|
|
139
|
+
end_: period.end_,
|
|
140
|
+
})
|
|
141
|
+
->Array.mapWithIndex((i, day) => {
|
|
142
|
+
let formattedDay =
|
|
143
|
+
intl->Intl.formatDateWithOptions(day, dateTimeFormatOptions(~weekday=#long, ()))
|
|
144
|
+
|
|
145
|
+
let isSelected =
|
|
146
|
+
selectedDay->Option.mapWithDefault(false, sDay => DateFns.isSameDay(sDay, day))
|
|
147
|
+
<React.Fragment key={i->Int.toString ++ "-day"}>
|
|
148
|
+
{i == 0 || day->DateFns.isFirstDayOfMonth
|
|
149
|
+
? <p className="text-xs text-neutral-700 uppercase">
|
|
150
|
+
<FormattedDate value=day month=#short />
|
|
151
|
+
</p>
|
|
152
|
+
: React.null}
|
|
153
|
+
<div
|
|
154
|
+
onClick={_ => dispatch(UpdateSelectedDay(isSm && isSelected ? None : Some(day)))}
|
|
155
|
+
className="flex flex-col items-stretch w-16 mx-1 font-display">
|
|
156
|
+
<p
|
|
157
|
+
className={cx([
|
|
158
|
+
"flex flex-col items-center justify-center uppercase text-xs w-full rounded-sm leading-tight py-1",
|
|
159
|
+
isSelected ? "text-white bg-primary-700" : "text-primary-700 bg-primary-50",
|
|
160
|
+
])}>
|
|
161
|
+
<span>
|
|
162
|
+
{formattedDay
|
|
163
|
+
->Js.String2.slice(~from=0, ~to_=4)
|
|
164
|
+
->Js.String2.concat(formattedDay->Js.String2.length > 4 ? "." : "")
|
|
165
|
+
->React.string}
|
|
166
|
+
</span>
|
|
167
|
+
<span className="text-sm font-semibold">
|
|
168
|
+
<FormattedDate value=day day=#"2-digit" />
|
|
169
|
+
</span>
|
|
170
|
+
</p>
|
|
171
|
+
<p
|
|
172
|
+
className="text-xs text-info-500 bg-info-50 text-center mt-1 font-semibold rounded-sm">
|
|
173
|
+
{counters
|
|
174
|
+
->Option.flatMap(counters =>
|
|
175
|
+
counters->Js.Dict.get(day->DateFns.formatWithPattern("yyyy-MM-dd"))
|
|
176
|
+
)
|
|
177
|
+
->Option.mapWithDefault(React.null, React.int)}
|
|
178
|
+
</p>
|
|
179
|
+
</div>
|
|
180
|
+
</React.Fragment>
|
|
181
|
+
})
|
|
182
|
+
->React.array}
|
|
183
|
+
</div>
|
|
184
|
+
<Toolkit__Ui_IconButton
|
|
185
|
+
size=#xs
|
|
186
|
+
variant=#outline
|
|
187
|
+
color=#neutral
|
|
188
|
+
onClick={_ => dispatch(NextPeriod)}
|
|
189
|
+
ariaLabel="next week"
|
|
190
|
+
icon={<ReactIcons.MdKeyboardArrowRight size=30 />}
|
|
191
|
+
/>
|
|
192
|
+
</div>
|
|
193
|
+
{children({period, selectedDay})}
|
|
194
|
+
</div>
|
|
195
|
+
}
|