cronofy-elements 1.40.0 → 1.40.1
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/build/CronofyElements.v1.40.1.js +2 -0
- package/build/{CronofyElements.v1.40.0.js.LICENSE.txt → CronofyElements.v1.40.1.js.LICENSE.txt} +0 -0
- package/build/npm/CronofyElements.js +2 -2
- package/demo/date-time-picker.ejs +1 -0
- package/package.json +1 -1
- package/src/js/components/DateTimePicker/Confirm.js +7 -5
- package/src/js/components/DateTimePicker/DateTimePicker.js +14 -7
- package/src/js/components/DateTimePicker/DayButton.js +3 -1
- package/src/js/components/DateTimePicker/Details.js +5 -8
- package/src/js/components/DateTimePicker/SlotButton.js +6 -6
- package/src/js/components/DateTimePicker/TimeZoneSelector.js +25 -29
- package/src/js/components/DateTimePicker/Wrapper.js +16 -3
- package/src/js/components/DateTimePicker/contexts/status-reducer.js +15 -16
- package/src/js/components/DateTimePicker/contexts/tz-context.js +18 -0
- package/tests/DateTimePicker/SlotButton.test.js +16 -5
- package/tests/DateTimePicker/contexts/status-reducer.test.js +10 -13
- package/build/CronofyElements.v1.40.0.js +0 -2
package/package.json
CHANGED
|
@@ -4,18 +4,20 @@ import moment from "moment-timezone";
|
|
|
4
4
|
import { useI18n } from "../../contexts/i18n-context";
|
|
5
5
|
import { useStatus } from "./contexts/status-context";
|
|
6
6
|
import { useTheme } from "./contexts/theme-context";
|
|
7
|
+
import { useTz } from "./contexts/tz-context";
|
|
7
8
|
|
|
8
9
|
const Confirm = ({ confirmButtonRef }) => {
|
|
9
10
|
const i18n = useI18n();
|
|
10
11
|
const [status, dispatchStatus] = useStatus();
|
|
11
12
|
const theme = useTheme();
|
|
13
|
+
const [tz] = useTz();
|
|
12
14
|
|
|
13
15
|
const handleCancel = () => {
|
|
14
16
|
dispatchStatus({ type: "CANCEL_SLOT_SELECTION" });
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
const handleConfirmation = () => {
|
|
18
|
-
dispatchStatus({ type: "CONFIRM_SELECTION" });
|
|
20
|
+
dispatchStatus({ type: "CONFIRM_SELECTION", tzid: tz.selectedTzid.tzid });
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
return (
|
|
@@ -32,23 +34,23 @@ const Confirm = ({ confirmButtonRef }) => {
|
|
|
32
34
|
<p className={theme.classBuilder("confirm-details--info")}>
|
|
33
35
|
{i18n.customFormatedTimeZone(
|
|
34
36
|
moment(status.selected.start, "YYYY-MM-DD"),
|
|
35
|
-
|
|
37
|
+
tz.selectedTzid.tzid,
|
|
36
38
|
"dddd, MMMM Do YYYY"
|
|
37
39
|
)}
|
|
38
40
|
</p>
|
|
39
41
|
<p className={theme.classBuilder("confirm-details--info")}>
|
|
40
42
|
{i18n.customFormatedTimeZone(
|
|
41
43
|
moment(status.selected.start, "YYYY-MM-DDTHH:mm:00Z"),
|
|
42
|
-
|
|
44
|
+
tz.selectedTzid.tzid,
|
|
43
45
|
"LT"
|
|
44
46
|
)}
|
|
45
47
|
{" - "}
|
|
46
48
|
{i18n.customFormatedTimeZone(
|
|
47
49
|
moment(status.selected.end, "YYYY-MM-DDTHH:mm:00Z"),
|
|
48
|
-
|
|
50
|
+
tz.selectedTzid.tzid,
|
|
49
51
|
"LT"
|
|
50
52
|
)}{" "}
|
|
51
|
-
{`(${moment.tz(
|
|
53
|
+
{`(${moment.tz(tz.selectedTzid.tzid).format("z")})`}
|
|
52
54
|
</p>
|
|
53
55
|
</div>
|
|
54
56
|
<button
|
|
@@ -17,6 +17,7 @@ import { I18nProvider } from "../../contexts/i18n-context";
|
|
|
17
17
|
import { LogProvider } from "../../contexts/log-context";
|
|
18
18
|
import { ThemeProvider } from "./contexts/theme-context";
|
|
19
19
|
import { StatusProvider } from "./contexts/status-context";
|
|
20
|
+
import { TzProvider } from "./contexts/tz-context";
|
|
20
21
|
|
|
21
22
|
const DateTimePicker = ({ options }) => {
|
|
22
23
|
const [statusOptions] = useState(() => {
|
|
@@ -31,8 +32,6 @@ const DateTimePicker = ({ options }) => {
|
|
|
31
32
|
startDay: options.config.startDay,
|
|
32
33
|
}),
|
|
33
34
|
}));
|
|
34
|
-
const tzList = parseTzList(options.config.tzList, options.tzid);
|
|
35
|
-
const selectedTzid = getInitialSelectedTzid(tzList, options.tzid);
|
|
36
35
|
return {
|
|
37
36
|
auth: {
|
|
38
37
|
token: options.token,
|
|
@@ -58,8 +57,6 @@ const DateTimePicker = ({ options }) => {
|
|
|
58
57
|
slots: {},
|
|
59
58
|
slotFetchCount: 0,
|
|
60
59
|
tzid: options.tzid,
|
|
61
|
-
selectedTzid: selectedTzid,
|
|
62
|
-
tzList: tzList,
|
|
63
60
|
populated: false,
|
|
64
61
|
};
|
|
65
62
|
});
|
|
@@ -83,13 +80,23 @@ const DateTimePicker = ({ options }) => {
|
|
|
83
80
|
tzid: options.tzid,
|
|
84
81
|
};
|
|
85
82
|
|
|
83
|
+
const tzList = parseTzList(options.config.tzList, options.tzid);
|
|
84
|
+
const selectedTzid = getInitialSelectedTzid(tzList, options.tzid);
|
|
85
|
+
|
|
86
|
+
const tzOptions = {
|
|
87
|
+
selectedTzid: selectedTzid,
|
|
88
|
+
list: tzList,
|
|
89
|
+
};
|
|
90
|
+
|
|
86
91
|
return (
|
|
87
92
|
<ThemeProvider options={themeOptions}>
|
|
88
93
|
<LogProvider options={logOptions}>
|
|
89
94
|
<I18nProvider options={i18nOptions}>
|
|
90
|
-
<
|
|
91
|
-
<
|
|
92
|
-
|
|
95
|
+
<TzProvider options={tzOptions}>
|
|
96
|
+
<StatusProvider options={statusOptions}>
|
|
97
|
+
<Wrapper />
|
|
98
|
+
</StatusProvider>
|
|
99
|
+
</TzProvider>
|
|
93
100
|
</I18nProvider>
|
|
94
101
|
</LogProvider>
|
|
95
102
|
</ThemeProvider>
|
|
@@ -4,11 +4,13 @@ import moment from "moment-timezone";
|
|
|
4
4
|
import { useI18n } from "../../contexts/i18n-context";
|
|
5
5
|
import { useStatus } from "./contexts/status-context";
|
|
6
6
|
import { useTheme } from "./contexts/theme-context";
|
|
7
|
+
import { useTz } from "./contexts/tz-context";
|
|
7
8
|
|
|
8
9
|
const DayButton = ({ day, selected = false, focused = false }) => {
|
|
9
10
|
const i18n = useI18n();
|
|
10
11
|
const [status, dispatchStatus] = useStatus();
|
|
11
12
|
const theme = useTheme();
|
|
13
|
+
const [tz] = useTz();
|
|
12
14
|
|
|
13
15
|
let classStub = "calendar-grid--button";
|
|
14
16
|
if (day.isAvailable) classStub = classStub + " calendar-grid--available";
|
|
@@ -17,7 +19,7 @@ const DayButton = ({ day, selected = false, focused = false }) => {
|
|
|
17
19
|
if (focused) classStub = classStub + " calendar-grid--focused";
|
|
18
20
|
|
|
19
21
|
const handleClick = () => {
|
|
20
|
-
dispatchStatus({ type: "SELECT_DAY", day: day.date });
|
|
22
|
+
dispatchStatus({ type: "SELECT_DAY", day: day.date, tzid: tz.selectedTzid.tzid });
|
|
21
23
|
};
|
|
22
24
|
|
|
23
25
|
return (
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { memo } from "react";
|
|
2
2
|
|
|
3
3
|
import { useI18n } from "../../contexts/i18n-context";
|
|
4
|
-
import { useStatus } from "./contexts/status-context";
|
|
5
4
|
import { useTheme } from "./contexts/theme-context";
|
|
6
5
|
import TimeZoneSelector from "./TimeZoneSelector";
|
|
7
6
|
|
|
8
|
-
const Details = () => {
|
|
7
|
+
const Details = ({ duration, locale }) => {
|
|
9
8
|
const i18n = useI18n();
|
|
10
|
-
const [status, _dispatchStatus] = useStatus();
|
|
11
9
|
const theme = useTheme();
|
|
12
10
|
|
|
13
11
|
return (
|
|
@@ -16,16 +14,15 @@ const Details = () => {
|
|
|
16
14
|
<p className={theme.classBuilder("details--tz-label")}>
|
|
17
15
|
<strong>{i18n.t("time_zone")}:</strong>
|
|
18
16
|
</p>
|
|
19
|
-
<TimeZoneSelector />
|
|
17
|
+
<TimeZoneSelector locale={locale} />
|
|
20
18
|
</div>
|
|
21
19
|
<div className={theme.classBuilder("details--duration")}>
|
|
22
20
|
<p>
|
|
23
|
-
<strong>{i18n.t("duration_label")}:</strong>{
|
|
24
|
-
{status.query.required_duration.minutes} {i18n.t("minutes")}
|
|
21
|
+
<strong>{i18n.t("duration_label")}:</strong> {duration} {i18n.t("minutes")}
|
|
25
22
|
</p>
|
|
26
23
|
</div>
|
|
27
24
|
</div>
|
|
28
25
|
);
|
|
29
26
|
};
|
|
30
27
|
|
|
31
|
-
export default Details;
|
|
28
|
+
export default memo(Details);
|
|
@@ -4,16 +4,18 @@ import moment from "moment-timezone";
|
|
|
4
4
|
import { useI18n } from "../../contexts/i18n-context";
|
|
5
5
|
import { useStatus } from "./contexts/status-context";
|
|
6
6
|
import { useTheme } from "./contexts/theme-context";
|
|
7
|
+
import { useTz } from "./contexts/tz-context";
|
|
7
8
|
|
|
8
9
|
const SlotButton = ({ slot }) => {
|
|
9
10
|
const i18n = useI18n();
|
|
10
11
|
const theme = useTheme();
|
|
11
12
|
const [status, dispatchStatus] = useStatus();
|
|
13
|
+
const [tz] = useTz();
|
|
12
14
|
|
|
13
15
|
const slotButtonRef = useRef();
|
|
14
16
|
|
|
15
17
|
const handleSlotSelection = slot => {
|
|
16
|
-
dispatchStatus({ type: "SELECT_SLOT", slot });
|
|
18
|
+
dispatchStatus({ type: "SELECT_SLOT", slot, tzid: tz.selectedTzid.tzid });
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
useEffect(() => {
|
|
@@ -36,18 +38,16 @@ const SlotButton = ({ slot }) => {
|
|
|
36
38
|
</span>
|
|
37
39
|
{i18n.customFormatedTimeZone(
|
|
38
40
|
moment(slot.start, "YYYY-MM-DDTHH:mm:00Z"),
|
|
39
|
-
|
|
41
|
+
tz.selectedTzid.tzid,
|
|
40
42
|
"LT"
|
|
41
43
|
)}
|
|
42
44
|
{" - "}
|
|
43
45
|
{i18n.customFormatedTimeZone(
|
|
44
46
|
moment(slot.end, "YYYY-MM-DDTHH:mm:00Z"),
|
|
45
|
-
|
|
47
|
+
tz.selectedTzid.tzid,
|
|
46
48
|
"LT"
|
|
47
49
|
)}{" "}
|
|
48
|
-
{`(${moment(slot.start, "YYYY-MM-DDTHH:mm:00Z")
|
|
49
|
-
.tz(status.selectedTzid.tzid)
|
|
50
|
-
.format("z")})`}
|
|
50
|
+
{`(${moment(slot.start, "YYYY-MM-DDTHH:mm:00Z").tz(tz.selectedTzid.tzid).format("z")})`}
|
|
51
51
|
</button>
|
|
52
52
|
);
|
|
53
53
|
};
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from "react";
|
|
2
2
|
|
|
3
|
-
import { useStatus } from "./contexts/status-context";
|
|
4
3
|
import { useTheme } from "./contexts/theme-context";
|
|
5
|
-
import { useI18n } from "../../contexts/i18n-context";
|
|
6
4
|
|
|
7
5
|
import { tzi18n } from "../../helpers/i18n";
|
|
6
|
+
import { useTz } from "./contexts/tz-context";
|
|
8
7
|
|
|
9
|
-
const TimeZoneSelector = () => {
|
|
8
|
+
const TimeZoneSelector = ({ locale }) => {
|
|
10
9
|
const theme = useTheme();
|
|
11
|
-
const
|
|
10
|
+
const [tz, setTz] = useTz();
|
|
12
11
|
|
|
13
|
-
const [status, dispatchStatus] = useStatus();
|
|
14
12
|
const [showList, setShowList] = useState(() => false);
|
|
15
13
|
const [focused, setFocused] = useState(() => false);
|
|
16
14
|
|
|
@@ -27,8 +25,8 @@ const TimeZoneSelector = () => {
|
|
|
27
25
|
setShowList(showList ? false : true);
|
|
28
26
|
};
|
|
29
27
|
|
|
30
|
-
const handleOptionSelect =
|
|
31
|
-
|
|
28
|
+
const handleOptionSelect = selectedTz => {
|
|
29
|
+
setTz({ ...tz, selectedTzid: selectedTz });
|
|
32
30
|
setShowList(false);
|
|
33
31
|
};
|
|
34
32
|
|
|
@@ -36,26 +34,24 @@ const TimeZoneSelector = () => {
|
|
|
36
34
|
switch (e.key) {
|
|
37
35
|
case "ArrowDown":
|
|
38
36
|
e.preventDefault();
|
|
39
|
-
const nextFocusedItemIndex =
|
|
40
|
-
status.tzList.findIndex(item => focused === item.tzid) + 1;
|
|
37
|
+
const nextFocusedItemIndex = tz.list.findIndex(item => focused === item.tzid) + 1;
|
|
41
38
|
const nextItem =
|
|
42
|
-
nextFocusedItemIndex >
|
|
39
|
+
nextFocusedItemIndex > tz.list.length - 1 ? 0 : nextFocusedItemIndex;
|
|
43
40
|
|
|
44
|
-
setFocused(
|
|
41
|
+
setFocused(tz.list[nextItem].tzid);
|
|
45
42
|
|
|
46
43
|
break;
|
|
47
44
|
case "ArrowUp":
|
|
48
45
|
e.preventDefault();
|
|
49
|
-
const prevFocusedItemIndex =
|
|
50
|
-
status.tzList.findIndex(item => focused === item.tzid) - 1;
|
|
46
|
+
const prevFocusedItemIndex = tz.list.findIndex(item => focused === item.tzid) - 1;
|
|
51
47
|
const prevItem =
|
|
52
|
-
prevFocusedItemIndex < 0 ?
|
|
48
|
+
prevFocusedItemIndex < 0 ? tz.list.length - 1 : prevFocusedItemIndex;
|
|
53
49
|
|
|
54
|
-
setFocused(
|
|
50
|
+
setFocused(tz.list[prevItem].tzid);
|
|
55
51
|
|
|
56
52
|
break;
|
|
57
53
|
case "Enter":
|
|
58
|
-
const tz =
|
|
54
|
+
const tz = tz.list.find(item => focused === item.tzid);
|
|
59
55
|
handleOptionSelect(tz);
|
|
60
56
|
break;
|
|
61
57
|
case "Escape":
|
|
@@ -80,23 +76,23 @@ const TimeZoneSelector = () => {
|
|
|
80
76
|
useEffect(() => {
|
|
81
77
|
if (showList && tzListRef.current) {
|
|
82
78
|
tzListRef.current.focus();
|
|
83
|
-
setFocused(
|
|
79
|
+
setFocused(tz.selectedTzid.tzid);
|
|
84
80
|
}
|
|
85
81
|
}, [showList]);
|
|
86
82
|
|
|
87
83
|
useEffect(() => {
|
|
88
84
|
if (showList && tzListRef.current && focused) {
|
|
89
|
-
const focusItem =
|
|
85
|
+
const focusItem = tz.list.findIndex(item => focused === item.tzid);
|
|
90
86
|
tzListRef.current.children[focusItem].scrollIntoView(scrollIntoViewOptions);
|
|
91
87
|
}
|
|
92
88
|
}, [focused]);
|
|
93
89
|
|
|
94
90
|
const meaninglessAbbr = /^[+-][0-9]+$/;
|
|
95
91
|
|
|
96
|
-
const renderList =
|
|
92
|
+
const renderList = tz.list.map((timezone, key) => {
|
|
97
93
|
let abbr = "";
|
|
98
|
-
if (!
|
|
99
|
-
abbr = `${
|
|
94
|
+
if (!timezone.abbr.match(meaninglessAbbr)) {
|
|
95
|
+
abbr = `${timezone.abbr} `;
|
|
100
96
|
}
|
|
101
97
|
|
|
102
98
|
return (
|
|
@@ -105,20 +101,20 @@ const TimeZoneSelector = () => {
|
|
|
105
101
|
role="option"
|
|
106
102
|
className={
|
|
107
103
|
theme.classBuilder("timezone-selector--option") +
|
|
108
|
-
(focused ===
|
|
104
|
+
(focused === timezone.tzid
|
|
109
105
|
? " " + theme.classBuilder("timezone-selector--focused")
|
|
110
106
|
: "") +
|
|
111
|
-
(
|
|
107
|
+
(tz.selectedTzid.tzid === timezone.tzid
|
|
112
108
|
? " " + theme.classBuilder("timezone-selector--selected")
|
|
113
109
|
: "")
|
|
114
110
|
}
|
|
115
|
-
data-name={
|
|
116
|
-
aria-selected={
|
|
117
|
-
onClick={() => handleOptionSelect(
|
|
111
|
+
data-name={timezone.name}
|
|
112
|
+
aria-selected={timezone.tzid === tz.selectedTzid.tzid}
|
|
113
|
+
onClick={() => handleOptionSelect(timezone)}
|
|
118
114
|
onKeyDown={() => console.log("keydown on option")}
|
|
119
115
|
>
|
|
120
|
-
{`(${abbr}${
|
|
121
|
-
<strong>{tzi18n(
|
|
116
|
+
{`(${abbr}${timezone.offset}) `}
|
|
117
|
+
<strong>{tzi18n(timezone.tzid, locale)}</strong>
|
|
122
118
|
</li>
|
|
123
119
|
);
|
|
124
120
|
});
|
|
@@ -133,7 +129,7 @@ const TimeZoneSelector = () => {
|
|
|
133
129
|
aria-expanded={showList}
|
|
134
130
|
onClick={toggleShowList}
|
|
135
131
|
>
|
|
136
|
-
{tzi18n(
|
|
132
|
+
{tzi18n(tz.selectedTzid.tzid, locale)}
|
|
137
133
|
<svg
|
|
138
134
|
className={
|
|
139
135
|
theme.classBuilder("timezone-selector--icon") +
|
|
@@ -13,9 +13,11 @@ import SlotsList from "./SlotsList";
|
|
|
13
13
|
|
|
14
14
|
import { useStatus } from "./contexts/status-context";
|
|
15
15
|
import { useTheme } from "./contexts/theme-context";
|
|
16
|
+
import { useTz } from "./contexts/tz-context";
|
|
16
17
|
|
|
17
18
|
const Wrapper = () => {
|
|
18
19
|
const [status, dispatchStatus] = useStatus();
|
|
20
|
+
const [tz] = useTz();
|
|
19
21
|
const theme = useTheme();
|
|
20
22
|
const confirmButtonRef = useRef();
|
|
21
23
|
|
|
@@ -33,7 +35,11 @@ const Wrapper = () => {
|
|
|
33
35
|
tzid: status.tzid,
|
|
34
36
|
})
|
|
35
37
|
.then(res => {
|
|
36
|
-
dispatchStatus({
|
|
38
|
+
dispatchStatus({
|
|
39
|
+
type: "SET_INITIAL_SLOTS",
|
|
40
|
+
slots: res,
|
|
41
|
+
tzid: tz.selectedTzid.tzid,
|
|
42
|
+
});
|
|
37
43
|
const remainingMonths = status.months.filter(month => !month.current);
|
|
38
44
|
remainingMonths.forEach(month => {
|
|
39
45
|
getSlots({
|
|
@@ -45,6 +51,7 @@ const Wrapper = () => {
|
|
|
45
51
|
type: "SET_ADDITIONAL_SLOTS",
|
|
46
52
|
month: month.month,
|
|
47
53
|
slots: res,
|
|
54
|
+
tzid: tz.selectedTzid.tzid,
|
|
48
55
|
});
|
|
49
56
|
});
|
|
50
57
|
});
|
|
@@ -66,7 +73,7 @@ const Wrapper = () => {
|
|
|
66
73
|
|
|
67
74
|
// Set grid display if there are available slots
|
|
68
75
|
if (slotsCount > 0) {
|
|
69
|
-
dispatchStatus({ type: "RECALCULATE_MONTH_SLOTS" });
|
|
76
|
+
dispatchStatus({ type: "RECALCULATE_MONTH_SLOTS", tzid: tz.selectedTzid.tzid });
|
|
70
77
|
}
|
|
71
78
|
}, [status.slotFetchCount]);
|
|
72
79
|
|
|
@@ -94,9 +101,15 @@ const Wrapper = () => {
|
|
|
94
101
|
}
|
|
95
102
|
}, [status.columnView]);
|
|
96
103
|
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (tz.selectedTzid.tzid) {
|
|
106
|
+
dispatchStatus({ type: "SELECT_TZID", tzid: tz.selectedTzid.tzid });
|
|
107
|
+
}
|
|
108
|
+
}, [tz.selectedTzid.tzid]);
|
|
109
|
+
|
|
97
110
|
return (
|
|
98
111
|
<section className={theme.classBuilder()} style={theme.customProperties}>
|
|
99
|
-
<Details />
|
|
112
|
+
<Details duration={status.query.required_duration.minutes} locale={status.locale} />
|
|
100
113
|
<div className={theme.classBuilder("wrapper")}>
|
|
101
114
|
<div
|
|
102
115
|
className={
|
|
@@ -10,12 +10,12 @@ import { parseTimeSlots } from "../utils/calendar";
|
|
|
10
10
|
export const statusReducer = (state, action) => {
|
|
11
11
|
const { type, ...actionBody } = action;
|
|
12
12
|
|
|
13
|
-
const sendSlotNotification =
|
|
13
|
+
const sendSlotNotification = tzid => {
|
|
14
14
|
const notification = {
|
|
15
15
|
notification: {
|
|
16
16
|
type: "slot_selected",
|
|
17
17
|
slot: state.selected,
|
|
18
|
-
tzid:
|
|
18
|
+
tzid: tzid,
|
|
19
19
|
},
|
|
20
20
|
};
|
|
21
21
|
state.callback(notification);
|
|
@@ -31,7 +31,7 @@ export const statusReducer = (state, action) => {
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
case "CONFIRM_SELECTION": {
|
|
34
|
-
sendSlotNotification();
|
|
34
|
+
sendSlotNotification(action.tzid);
|
|
35
35
|
return state;
|
|
36
36
|
}
|
|
37
37
|
case "ERROR_GETTING_SLOTS": {
|
|
@@ -53,7 +53,7 @@ export const statusReducer = (state, action) => {
|
|
|
53
53
|
days: parseTimeSlots({
|
|
54
54
|
slots: state.slots,
|
|
55
55
|
month: month.month,
|
|
56
|
-
tzid:
|
|
56
|
+
tzid: action.tzid,
|
|
57
57
|
startDay: state.startDay,
|
|
58
58
|
}),
|
|
59
59
|
}));
|
|
@@ -66,7 +66,7 @@ export const statusReducer = (state, action) => {
|
|
|
66
66
|
: state.slots;
|
|
67
67
|
const hasAnySlots = Object.keys(slotsObject).length >= 1;
|
|
68
68
|
const selectedDay = hasAnySlots
|
|
69
|
-
? getFirstAvailableDay(slotsObject,
|
|
69
|
+
? getFirstAvailableDay(slotsObject, action.tzid)
|
|
70
70
|
: false;
|
|
71
71
|
const availableDays = hasAnySlots ? getAvailableDays(slotsObject, state.tzid) : false;
|
|
72
72
|
return {
|
|
@@ -87,7 +87,7 @@ export const statusReducer = (state, action) => {
|
|
|
87
87
|
const hasAnySlots = Object.keys(slotsObject).length >= 1;
|
|
88
88
|
const selectedDay =
|
|
89
89
|
hasAnySlots && !state.selectedDay
|
|
90
|
-
? getFirstAvailableDay(slotsObject,
|
|
90
|
+
? getFirstAvailableDay(slotsObject, action.tzid)
|
|
91
91
|
: state.selectedDay;
|
|
92
92
|
return {
|
|
93
93
|
...state,
|
|
@@ -108,7 +108,7 @@ export const statusReducer = (state, action) => {
|
|
|
108
108
|
return { ...state, months, focusedDay: action.focusedDay };
|
|
109
109
|
}
|
|
110
110
|
case "SELECT_DAY_INITIAL":
|
|
111
|
-
const initialDaySlots = getSlotsByDay(state.slots, action.day,
|
|
111
|
+
const initialDaySlots = getSlotsByDay(state.slots, action.day, action.tzid);
|
|
112
112
|
return {
|
|
113
113
|
...state,
|
|
114
114
|
selectedDay: action.day,
|
|
@@ -118,7 +118,7 @@ export const statusReducer = (state, action) => {
|
|
|
118
118
|
populated: true,
|
|
119
119
|
};
|
|
120
120
|
case "SELECT_DAY":
|
|
121
|
-
const daySlots = getSlotsByDay(state.slots, action.day,
|
|
121
|
+
const daySlots = getSlotsByDay(state.slots, action.day, action.tzid);
|
|
122
122
|
return {
|
|
123
123
|
...state,
|
|
124
124
|
selectedDay: action.day,
|
|
@@ -145,21 +145,21 @@ export const statusReducer = (state, action) => {
|
|
|
145
145
|
focusedSlot: action.slot.start,
|
|
146
146
|
};
|
|
147
147
|
if (state.mode === "no_confirm") {
|
|
148
|
-
sendSlotNotification();
|
|
148
|
+
sendSlotNotification(action.tzid);
|
|
149
149
|
} else {
|
|
150
150
|
state.columnView = "confirm";
|
|
151
151
|
}
|
|
152
152
|
return state;
|
|
153
153
|
}
|
|
154
154
|
case "SELECT_TZID": {
|
|
155
|
-
const availableDays = getAvailableDays(state.slots, action.
|
|
156
|
-
const daySlots = getSlotsByDay(state.slots, state.selectedDay, action.
|
|
155
|
+
const availableDays = getAvailableDays(state.slots, action.tzid);
|
|
156
|
+
const daySlots = getSlotsByDay(state.slots, state.selectedDay, action.tzid);
|
|
157
157
|
const monthlySlots = state.months.map(month => ({
|
|
158
158
|
month: month.month,
|
|
159
159
|
days: parseTimeSlots({
|
|
160
160
|
slots: state.slots,
|
|
161
161
|
month: month.month,
|
|
162
|
-
tzid: action.
|
|
162
|
+
tzid: action.tzid,
|
|
163
163
|
startDay: state.startDay,
|
|
164
164
|
}),
|
|
165
165
|
}));
|
|
@@ -169,12 +169,11 @@ export const statusReducer = (state, action) => {
|
|
|
169
169
|
availableDays,
|
|
170
170
|
daySlots,
|
|
171
171
|
monthlySlots,
|
|
172
|
-
selectedTzid: action.tz,
|
|
173
172
|
};
|
|
174
173
|
|
|
175
174
|
if (state.selected.start) {
|
|
176
|
-
const selectedDay = getLocalDayFromUtc(state.selected.start, action.
|
|
177
|
-
const daySlots = getSlotsByDay(state.slots, selectedDay, action.
|
|
175
|
+
const selectedDay = getLocalDayFromUtc(state.selected.start, action.tzid);
|
|
176
|
+
const daySlots = getSlotsByDay(state.slots, selectedDay, action.tzid);
|
|
178
177
|
|
|
179
178
|
state = {
|
|
180
179
|
...state,
|
|
@@ -183,7 +182,7 @@ export const statusReducer = (state, action) => {
|
|
|
183
182
|
focusedDay: selectedDay,
|
|
184
183
|
};
|
|
185
184
|
|
|
186
|
-
if (state.mode === "no_confirm") sendSlotNotification();
|
|
185
|
+
if (state.mode === "no_confirm") sendSlotNotification(action.tzid);
|
|
187
186
|
}
|
|
188
187
|
|
|
189
188
|
return state;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React, { createContext, useContext, useState } from "react";
|
|
2
|
+
|
|
3
|
+
const TzContext = createContext();
|
|
4
|
+
|
|
5
|
+
export const TzProvider = ({ children, options }) => {
|
|
6
|
+
const [tz, setTz] = useState({
|
|
7
|
+
selectedTzid: options.selectedTzid,
|
|
8
|
+
list: options.list,
|
|
9
|
+
});
|
|
10
|
+
return <TzContext.Provider value={[tz, setTz]}>{children}</TzContext.Provider>;
|
|
11
|
+
};
|
|
12
|
+
export const useTz = () => {
|
|
13
|
+
const context = useContext(TzContext);
|
|
14
|
+
if (context === undefined) {
|
|
15
|
+
throw new Error("useTz must be used within a TzProvider");
|
|
16
|
+
}
|
|
17
|
+
return context;
|
|
18
|
+
};
|
|
@@ -7,6 +7,7 @@ import SlotButton from "../../src/js/components/DateTimePicker/SlotButton";
|
|
|
7
7
|
import { I18nProvider } from "../../src/js/contexts/i18n-context";
|
|
8
8
|
import { ThemeProvider } from "../../src/js/components/DateTimePicker/contexts/theme-context";
|
|
9
9
|
import { StatusProvider } from "../../src/js/components/DateTimePicker/contexts/status-context";
|
|
10
|
+
import { TzProvider } from "../../src/js/components/DateTimePicker/contexts/tz-context";
|
|
10
11
|
|
|
11
12
|
const wrapper = ({ children, status }) => (
|
|
12
13
|
<ThemeProvider options={{ name: "DTP" }}>
|
|
@@ -17,17 +18,27 @@ const wrapper = ({ children, status }) => (
|
|
|
17
18
|
tzid: "Europe/London",
|
|
18
19
|
}}
|
|
19
20
|
>
|
|
20
|
-
<
|
|
21
|
+
<TzProvider
|
|
21
22
|
options={{
|
|
22
|
-
selected: false,
|
|
23
23
|
selectedTzid: {
|
|
24
24
|
tzid: "Europe/London",
|
|
25
|
+
offset: "+01:00",
|
|
26
|
+
offsetMins: 60,
|
|
27
|
+
name: "London",
|
|
28
|
+
abbr: "BST",
|
|
25
29
|
},
|
|
26
|
-
|
|
30
|
+
list: [],
|
|
27
31
|
}}
|
|
28
32
|
>
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
<StatusProvider
|
|
34
|
+
options={{
|
|
35
|
+
selected: false,
|
|
36
|
+
...status,
|
|
37
|
+
}}
|
|
38
|
+
>
|
|
39
|
+
{children}
|
|
40
|
+
</StatusProvider>
|
|
41
|
+
</TzProvider>
|
|
31
42
|
</I18nProvider>
|
|
32
43
|
</ThemeProvider>
|
|
33
44
|
);
|