cronofy-elements 1.38.1 → 1.40.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/Makefile +1 -1
- package/build/CronofyElements.v1.40.0.js +2 -0
- package/build/{CronofyElements.v1.38.1.js.LICENSE.txt → CronofyElements.v1.40.0.js.LICENSE.txt} +0 -0
- package/build/npm/CronofyElements.js +2 -2
- package/demo/availability-viewer.ejs +8 -0
- package/demo/date-time-picker.ejs +1 -0
- package/demo/rules.ejs +2 -1
- package/package.json +1 -1
- package/src/js/components/AvailabilityRules/Slot.js +78 -4
- package/src/js/components/AvailabilityRules/Slots.js +3 -2
- package/src/js/components/AvailabilityRules/Week.js +7 -6
- package/src/js/components/AvailabilityRules/contexts/drag-context.js +15 -0
- package/src/js/components/AvailabilityViewer/AvailabilityViewer.js +14 -15
- package/src/js/components/AvailabilityViewer/Navigation.js +23 -37
- package/src/js/components/AvailabilityViewer/WeekWrapper.js +3 -8
- package/src/js/components/AvailabilityViewer/contexts/page-context.js +17 -0
- package/src/js/components/AvailabilityViewer/contexts/page-reducer.js +28 -0
- package/src/js/components/DateTimePicker/Confirm.js +1 -1
- package/src/js/components/DateTimePicker/SlotButton.js +9 -3
- package/src/js/components/DateTimePicker/contexts/status-reducer.js +27 -10
- package/src/js/components/DateTimePicker/scss/_components.slotslist.scss +7 -0
- package/src/js/components/DateTimePicker/utils/slots.js +5 -1
- package/src/js/helpers/init.AvailabilityRules.js +24 -0
- package/src/js/helpers/utils.AvailabilityRules.js +6 -0
- package/src/js/helpers/utils.AvailabilityViewer.js +7 -2
- package/src/js/main.js +17 -1
- package/tests/AvailabilityViewer/Navigation.test.js +130 -0
- package/tests/AvailabilityViewer/contexts/page-reducer.test.js +87 -0
- package/tests/CalendarSync/Active.test.js +1 -1
- package/tests/CalendarSync/AddToggle.test.js +1 -1
- package/tests/CalendarSync/EditToggle.test.js +1 -1
- package/tests/CalendarSync/Inactive.test.js +1 -1
- package/tests/CalendarSync/Pending.test.js +1 -1
- package/tests/DateTimePicker/SlotButton.test.js +107 -0
- package/tests/DateTimePicker/contexts/status-reducer.test.js +106 -0
- package/tests/DateTimePicker/dummy-data.js +16 -0
- package/tests/DateTimePicker/utils.test.js +166 -0
- package/tests/components/main.test.js +8 -1
- package/tests/init.AvailabilityRules.test.js +30 -0
- package/tests/{CalendarSync/mocks → mocks}/i18n.js +0 -0
- package/tests/mocks/theme.js +3 -0
- package/tests/utils.AvailabilityRules.test.js +3 -0
- package/tests/utils.AvailabilityViewer.test.js +8 -0
- package/build/CronofyElements.v1.38.1.js +0 -2
- package/yarn.lock +0 -8098
|
@@ -49,7 +49,11 @@ export const getMonthObjectsFromQuery = (query, tzid, current = false) => {
|
|
|
49
49
|
return {
|
|
50
50
|
month,
|
|
51
51
|
current: currentMonth === month,
|
|
52
|
-
query: {
|
|
52
|
+
query: {
|
|
53
|
+
...query,
|
|
54
|
+
query_periods: croppedQueryPeriods,
|
|
55
|
+
max_results: query.max_results ?? 512,
|
|
56
|
+
},
|
|
53
57
|
};
|
|
54
58
|
});
|
|
55
59
|
return monthObjects;
|
|
@@ -140,6 +140,28 @@ export const parseAvailabilityRulesOptions = (options = {}) => {
|
|
|
140
140
|
|
|
141
141
|
const tzid = parseTimezone(options.tzid, "availability-rules", log);
|
|
142
142
|
|
|
143
|
+
const keyboardSupportedValues = ["basic"];
|
|
144
|
+
|
|
145
|
+
const validateKeyBoardSupport = keyboard_support => {
|
|
146
|
+
const validKeyboardSupport = keyboardSupportedValues.includes(keyboard_support);
|
|
147
|
+
if (!validKeyboardSupport) {
|
|
148
|
+
log.error(
|
|
149
|
+
`Please provide a valid \`config.keyboard_support\`. \`${keyboard_support}\` is not a supported value.`,
|
|
150
|
+
{
|
|
151
|
+
docsSlug: "availability-rules/#config.keyboard_support",
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
return false;
|
|
155
|
+
} else {
|
|
156
|
+
return keyboard_support;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const keyboardSupport =
|
|
161
|
+
typeof config.keyboard_support === "undefined"
|
|
162
|
+
? false
|
|
163
|
+
: validateKeyBoardSupport(config.keyboard_support);
|
|
164
|
+
|
|
143
165
|
const domains = parseConnectionDomains(
|
|
144
166
|
options.data_center,
|
|
145
167
|
options.api_domain,
|
|
@@ -152,6 +174,7 @@ export const parseAvailabilityRulesOptions = (options = {}) => {
|
|
|
152
174
|
delete config.week_start_day;
|
|
153
175
|
delete config.default_weekly_periods;
|
|
154
176
|
delete config.auto_create_rules;
|
|
177
|
+
delete config.keyboard_support;
|
|
155
178
|
|
|
156
179
|
return {
|
|
157
180
|
...options,
|
|
@@ -165,6 +188,7 @@ export const parseAvailabilityRulesOptions = (options = {}) => {
|
|
|
165
188
|
startDay,
|
|
166
189
|
defaultWeeklyPeriods,
|
|
167
190
|
autoCreateRulesMode,
|
|
191
|
+
keyboardSupport,
|
|
168
192
|
},
|
|
169
193
|
translations,
|
|
170
194
|
};
|
|
@@ -69,6 +69,11 @@ export const parseExtras = (options = {}) => {
|
|
|
69
69
|
const slotsPerDay = calculateSlotsPerDay(duration, end, start);
|
|
70
70
|
const slotsOffset = calculateSlotsPerDay(duration, start, "00:00");
|
|
71
71
|
|
|
72
|
+
let keyboardSupport = false;
|
|
73
|
+
if (options.config && typeof options.config.keyboardSupport !== "undefined") {
|
|
74
|
+
keyboardSupport = options.config.keyboardSupport;
|
|
75
|
+
}
|
|
76
|
+
|
|
72
77
|
return {
|
|
73
78
|
limits: {
|
|
74
79
|
duration,
|
|
@@ -79,6 +84,7 @@ export const parseExtras = (options = {}) => {
|
|
|
79
84
|
slotsOffset,
|
|
80
85
|
},
|
|
81
86
|
slotHeight,
|
|
87
|
+
keyboardSupport,
|
|
82
88
|
};
|
|
83
89
|
};
|
|
84
90
|
|
|
@@ -145,11 +145,16 @@ export const getAllWeekDays = ({ startDate, endDate, startDay = "sunday", tzid }
|
|
|
145
145
|
};
|
|
146
146
|
|
|
147
147
|
export const getWeeksInfo = weekdays => {
|
|
148
|
+
const current = 1;
|
|
149
|
+
const total = Math.ceil(weekdays.length / 7);
|
|
150
|
+
|
|
148
151
|
return {
|
|
149
152
|
set: true,
|
|
150
|
-
current: 1,
|
|
151
153
|
days: weekdays,
|
|
152
|
-
total
|
|
154
|
+
total,
|
|
155
|
+
current,
|
|
156
|
+
hasNext: current < total,
|
|
157
|
+
hasPrev: false,
|
|
153
158
|
};
|
|
154
159
|
};
|
|
155
160
|
|
package/src/js/main.js
CHANGED
|
@@ -50,23 +50,39 @@ export const SlotPicker = options => {
|
|
|
50
50
|
};
|
|
51
51
|
|
|
52
52
|
export const AvailabilityViewer = options => {
|
|
53
|
+
let cb;
|
|
54
|
+
|
|
53
55
|
// Make sure the correct props are passed to the component
|
|
54
56
|
const renderElement = (key, options) => (
|
|
55
57
|
<AvailabilityViewerApp
|
|
56
58
|
key={key}
|
|
57
59
|
options={{ ...globalOptionFallbacks, ...options }}
|
|
58
60
|
error={options.error}
|
|
61
|
+
eventCallback={ecb => (cb = ecb)}
|
|
59
62
|
/>
|
|
60
63
|
);
|
|
61
64
|
// Generate and render the component. The `return` is important
|
|
62
65
|
// here, as it exposes the `update` method (which can be used
|
|
63
66
|
// after the inital page-load).
|
|
64
|
-
|
|
67
|
+
|
|
68
|
+
const elementApi = generateElementAPI(
|
|
65
69
|
renderElement,
|
|
66
70
|
options,
|
|
67
71
|
parseAvailabilityViewerOptions,
|
|
68
72
|
"Availability Viewer"
|
|
69
73
|
);
|
|
74
|
+
|
|
75
|
+
if (!elementApi) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
...elementApi,
|
|
81
|
+
navigate: {
|
|
82
|
+
next: () => cb("SET_NEXT_PAGE"),
|
|
83
|
+
prev: () => cb("SET_PREV_PAGE"),
|
|
84
|
+
},
|
|
85
|
+
};
|
|
70
86
|
};
|
|
71
87
|
|
|
72
88
|
export const AvailabilityRules = options => {
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render, fireEvent } from "@testing-library/react";
|
|
3
|
+
|
|
4
|
+
import { i18n } from "../mocks/i18n";
|
|
5
|
+
import { theme } from "../mocks/theme";
|
|
6
|
+
|
|
7
|
+
import { PagesProvider } from "../../src/js/components/AvailabilityViewer/contexts/page-context";
|
|
8
|
+
import {
|
|
9
|
+
I18nContext,
|
|
10
|
+
LoggingContext,
|
|
11
|
+
StatusContext,
|
|
12
|
+
ThemeContext,
|
|
13
|
+
} from "../../src/js/components/AvailabilityViewer/AvailabilityViewer";
|
|
14
|
+
|
|
15
|
+
import Navigation from "../../src/js/components/AvailabilityViewer/Navigation";
|
|
16
|
+
|
|
17
|
+
const wrapper = ({ children, log, status, pages }) => (
|
|
18
|
+
<LoggingContext.Provider value={log ?? { warn: () => undefined }}>
|
|
19
|
+
<I18nContext.Provider value={i18n}>
|
|
20
|
+
<ThemeContext.Provider value={[theme("AvailabilityViewer")]}>
|
|
21
|
+
<StatusContext.Provider
|
|
22
|
+
value={
|
|
23
|
+
status ?? [
|
|
24
|
+
{ pagesLoaded: [], notificationCallback: () => undefined },
|
|
25
|
+
() => undefined,
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
>
|
|
29
|
+
<PagesProvider
|
|
30
|
+
{...(pages
|
|
31
|
+
? { value: pages[0], dispatch: pages[1] }
|
|
32
|
+
: { value: {}, dispatch: () => undefined })}
|
|
33
|
+
>
|
|
34
|
+
{children}
|
|
35
|
+
</PagesProvider>
|
|
36
|
+
</StatusContext.Provider>
|
|
37
|
+
</ThemeContext.Provider>
|
|
38
|
+
</I18nContext.Provider>
|
|
39
|
+
</LoggingContext.Provider>
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
describe("Navigation", () => {
|
|
43
|
+
it("displays nothing if pages.total is empty", () => {
|
|
44
|
+
const pages = [{ total: 0 }];
|
|
45
|
+
|
|
46
|
+
const { container } = render(<Navigation />, { wrapper: e => wrapper({ ...e, pages }) });
|
|
47
|
+
|
|
48
|
+
expect(container).toBeEmptyDOMElement();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("displays navigation if pages.total > 0", () => {
|
|
52
|
+
const pages = [{ total: 1 }];
|
|
53
|
+
|
|
54
|
+
const { container } = render(<Navigation />, { wrapper: e => wrapper({ ...e, pages }) });
|
|
55
|
+
|
|
56
|
+
const buttonWrapper = container.querySelector(".AvailabilityViewer__navigation");
|
|
57
|
+
|
|
58
|
+
expect(buttonWrapper).toBeInTheDocument();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("disables button is hasNext is false", () => {
|
|
62
|
+
const pages = [{ total: 10, hasNext: false }];
|
|
63
|
+
|
|
64
|
+
const { container } = render(<Navigation />, { wrapper: e => wrapper({ ...e, pages }) });
|
|
65
|
+
|
|
66
|
+
const nextButton = container.querySelector(".AvailabilityViewer__button--next");
|
|
67
|
+
|
|
68
|
+
expect(nextButton).toBeDisabled();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("enables next button if hasNext is true", () => {
|
|
72
|
+
const pages = [{ total: 10, hasNext: true }];
|
|
73
|
+
|
|
74
|
+
const { container } = render(<Navigation />, { wrapper: e => wrapper({ ...e, pages }) });
|
|
75
|
+
|
|
76
|
+
const nextButton = container.querySelector(".AvailabilityViewer__button--next");
|
|
77
|
+
|
|
78
|
+
expect(nextButton).toBeEnabled();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("calls dispatch to set the next page", () => {
|
|
82
|
+
const pagesDispatch = jest.fn();
|
|
83
|
+
const pages = [{ total: 10, hasNext: true }, pagesDispatch];
|
|
84
|
+
|
|
85
|
+
const { container } = render(<Navigation />, { wrapper: e => wrapper({ ...e, pages }) });
|
|
86
|
+
|
|
87
|
+
const nextButton = container.querySelector(".AvailabilityViewer__button--next");
|
|
88
|
+
|
|
89
|
+
fireEvent.click(nextButton);
|
|
90
|
+
|
|
91
|
+
expect(pagesDispatch).toHaveBeenCalledWith({
|
|
92
|
+
type: "SET_NEXT_PAGE",
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("disables button if hasPrev is false", () => {
|
|
97
|
+
const pages = [{ total: 10, hasPrev: false }];
|
|
98
|
+
|
|
99
|
+
const { container } = render(<Navigation />, { wrapper: e => wrapper({ ...e, pages }) });
|
|
100
|
+
|
|
101
|
+
const prevButton = container.querySelector(".AvailabilityViewer__button--prev");
|
|
102
|
+
|
|
103
|
+
expect(prevButton).toBeDisabled();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("enables button if hasPrev is true", () => {
|
|
107
|
+
const pages = [{ total: 10, hasPrev: true }];
|
|
108
|
+
|
|
109
|
+
const { container } = render(<Navigation />, { wrapper: e => wrapper({ ...e, pages }) });
|
|
110
|
+
|
|
111
|
+
const prevButton = container.querySelector(".AvailabilityViewer__button--prev");
|
|
112
|
+
|
|
113
|
+
expect(prevButton).toBeEnabled();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("calls dispatch to set the prev page", () => {
|
|
117
|
+
const pagesDispatch = jest.fn();
|
|
118
|
+
const pages = [{ total: 10, hasPrev: true }, pagesDispatch];
|
|
119
|
+
|
|
120
|
+
const { container } = render(<Navigation />, { wrapper: e => wrapper({ ...e, pages }) });
|
|
121
|
+
|
|
122
|
+
const prevButton = container.querySelector(".AvailabilityViewer__button--prev");
|
|
123
|
+
|
|
124
|
+
fireEvent.click(prevButton);
|
|
125
|
+
|
|
126
|
+
expect(pagesDispatch).toHaveBeenCalledWith({
|
|
127
|
+
type: "SET_PREV_PAGE",
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { pageReducer } from "../../../src/js/components/AvailabilityViewer/contexts/page-reducer";
|
|
2
|
+
|
|
3
|
+
describe("pageReducer", () => {
|
|
4
|
+
describe("SET_PREV_PAGE", () => {
|
|
5
|
+
it("sets prev page", () => {
|
|
6
|
+
const initialState = {
|
|
7
|
+
current: 5,
|
|
8
|
+
total: 10,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const action = {
|
|
12
|
+
type: "SET_PREV_PAGE",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const actual = pageReducer(initialState, action);
|
|
16
|
+
|
|
17
|
+
expect(actual).toEqual({
|
|
18
|
+
current: 4,
|
|
19
|
+
total: 10,
|
|
20
|
+
hasNext: true,
|
|
21
|
+
hasPrev: true,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("sets page to 1 if calculated page is less than it", () => {
|
|
26
|
+
const initialState = {
|
|
27
|
+
current: 1,
|
|
28
|
+
total: 10,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const action = {
|
|
32
|
+
type: "SET_PREV_PAGE",
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const actual = pageReducer(initialState, action);
|
|
36
|
+
|
|
37
|
+
expect(actual).toEqual({
|
|
38
|
+
current: 1,
|
|
39
|
+
total: 10,
|
|
40
|
+
hasNext: true,
|
|
41
|
+
hasPrev: false,
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("SET_NEXT_PAGE", () => {
|
|
47
|
+
it("sets next page", () => {
|
|
48
|
+
const initialState = {
|
|
49
|
+
current: 3,
|
|
50
|
+
total: 15,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const action = {
|
|
54
|
+
type: "SET_NEXT_PAGE",
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const actual = pageReducer(initialState, action);
|
|
58
|
+
|
|
59
|
+
expect(actual).toEqual({
|
|
60
|
+
current: 4,
|
|
61
|
+
total: 15,
|
|
62
|
+
hasNext: true,
|
|
63
|
+
hasPrev: true,
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("sets page to the total if calculated page is greater than it", () => {
|
|
68
|
+
const initialState = {
|
|
69
|
+
current: 15,
|
|
70
|
+
total: 15,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const action = {
|
|
74
|
+
type: "SET_NEXT_PAGE",
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const actual = pageReducer(initialState, action);
|
|
78
|
+
|
|
79
|
+
expect(actual).toEqual({
|
|
80
|
+
current: 15,
|
|
81
|
+
total: 15,
|
|
82
|
+
hasNext: false,
|
|
83
|
+
hasPrev: true,
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { render } from "@testing-library/react";
|
|
3
3
|
import "@testing-library/jest-dom";
|
|
4
4
|
|
|
5
|
-
import { i18n } from "
|
|
5
|
+
import { i18n } from "../mocks/i18n";
|
|
6
6
|
import { theme } from "./mocks/theme";
|
|
7
7
|
import { I18nContext, ThemeContext } from "../../src/js/components/CalendarSync/CalendarSync";
|
|
8
8
|
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
ThemeContext,
|
|
6
6
|
} from "../../src/js/components/CalendarSync/CalendarSync";
|
|
7
7
|
|
|
8
|
-
import { i18n } from "
|
|
8
|
+
import { i18n } from "../mocks/i18n";
|
|
9
9
|
import { theme } from "./mocks/theme";
|
|
10
10
|
|
|
11
11
|
import AddToggle from "../../src/js/components/CalendarSync/AddToggle";
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
ThemeContext,
|
|
6
6
|
} from "../../src/js/components/CalendarSync/CalendarSync";
|
|
7
7
|
|
|
8
|
-
import { i18n } from "
|
|
8
|
+
import { i18n } from "../mocks/i18n";
|
|
9
9
|
import { theme } from "./mocks/theme";
|
|
10
10
|
|
|
11
11
|
import EditToggle from "../../src/js/components/CalendarSync/EditToggle";
|
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { render } from "@testing-library/react";
|
|
3
3
|
import "@testing-library/jest-dom";
|
|
4
4
|
|
|
5
|
-
import { i18n } from "
|
|
5
|
+
import { i18n } from "../mocks/i18n";
|
|
6
6
|
import { theme } from "./mocks/theme";
|
|
7
7
|
import { I18nContext, ThemeContext } from "../../src/js/components/CalendarSync/CalendarSync";
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { render } from "@testing-library/react";
|
|
3
3
|
import "@testing-library/jest-dom";
|
|
4
4
|
|
|
5
|
-
import { i18n } from "
|
|
5
|
+
import { i18n } from "../mocks/i18n";
|
|
6
6
|
import { theme } from "./mocks/theme";
|
|
7
7
|
import { I18nContext, ThemeContext } from "../../src/js/components/CalendarSync/CalendarSync";
|
|
8
8
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render, fireEvent } from "@testing-library/react";
|
|
3
|
+
import "@testing-library/jest-dom";
|
|
4
|
+
|
|
5
|
+
import SlotButton from "../../src/js/components/DateTimePicker/SlotButton";
|
|
6
|
+
|
|
7
|
+
import { I18nProvider } from "../../src/js/contexts/i18n-context";
|
|
8
|
+
import { ThemeProvider } from "../../src/js/components/DateTimePicker/contexts/theme-context";
|
|
9
|
+
import { StatusProvider } from "../../src/js/components/DateTimePicker/contexts/status-context";
|
|
10
|
+
|
|
11
|
+
const wrapper = ({ children, status }) => (
|
|
12
|
+
<ThemeProvider options={{ name: "DTP" }}>
|
|
13
|
+
<I18nProvider
|
|
14
|
+
options={{
|
|
15
|
+
locale: "en",
|
|
16
|
+
slug: "date_time_picker",
|
|
17
|
+
tzid: "Europe/London",
|
|
18
|
+
}}
|
|
19
|
+
>
|
|
20
|
+
<StatusProvider
|
|
21
|
+
options={{
|
|
22
|
+
selected: false,
|
|
23
|
+
selectedTzid: {
|
|
24
|
+
tzid: "Europe/London",
|
|
25
|
+
},
|
|
26
|
+
...status,
|
|
27
|
+
}}
|
|
28
|
+
>
|
|
29
|
+
{children}
|
|
30
|
+
</StatusProvider>
|
|
31
|
+
</I18nProvider>
|
|
32
|
+
</ThemeProvider>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
describe("SlotButton", () => {
|
|
36
|
+
const slot = {
|
|
37
|
+
start: "2020-10-05T09:30:00Z",
|
|
38
|
+
end: "2020-10-05T10:00:00Z",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
it("displays slot button with time in BST", () => {
|
|
42
|
+
const { container } = render(<SlotButton slot={slot} />, { wrapper });
|
|
43
|
+
|
|
44
|
+
const button = container.querySelector(".DTP__time-slot");
|
|
45
|
+
|
|
46
|
+
expect(button).toBeInTheDocument();
|
|
47
|
+
expect(button.innerHTML).toEqual(expect.stringContaining("10:30 AM - 11:00 AM (BST)"));
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("displays slot button with time in GMT", () => {
|
|
51
|
+
const slot = {
|
|
52
|
+
start: "2020-11-05T09:30:00Z",
|
|
53
|
+
end: "2020-11-05T10:00:00Z",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const { container } = render(<SlotButton slot={slot} />, { wrapper });
|
|
57
|
+
|
|
58
|
+
const button = container.querySelector(".DTP__time-slot");
|
|
59
|
+
|
|
60
|
+
expect(button).toBeInTheDocument();
|
|
61
|
+
expect(button.innerHTML).toEqual(expect.stringContaining("9:30 AM - 10:00 AM (GMT)"));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("focuses if slot start time matches status.focusedSlot", () => {
|
|
65
|
+
const status = {
|
|
66
|
+
focusedSlot: slot.start,
|
|
67
|
+
selected: false,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const { container } = render(<SlotButton slot={slot} />, {
|
|
71
|
+
wrapper: e => wrapper({ ...e, status }),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const button = container.querySelector("button");
|
|
75
|
+
|
|
76
|
+
expect(button).toHaveFocus();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("sets the slot to selected when button is clicked", () => {
|
|
80
|
+
const { container } = render(<SlotButton slot={slot} />, { wrapper });
|
|
81
|
+
|
|
82
|
+
const button = container.querySelector("button");
|
|
83
|
+
|
|
84
|
+
expect(button).not.toHaveClass("DTP_time-slot--selected");
|
|
85
|
+
|
|
86
|
+
fireEvent.click(button);
|
|
87
|
+
|
|
88
|
+
expect(button).toHaveFocus();
|
|
89
|
+
expect(button.classList).toContain("DTP__time-slot--selected");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("shows selected className if preselected slot exists", () => {
|
|
93
|
+
const status = {
|
|
94
|
+
focusedSlot: slot.start,
|
|
95
|
+
selected: slot,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const { container } = render(<SlotButton slot={slot} />, {
|
|
99
|
+
wrapper: e => wrapper({ ...e, status }),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const button = container.querySelector("button");
|
|
103
|
+
|
|
104
|
+
expect(button).toHaveFocus();
|
|
105
|
+
expect(button.classList).toContain("DTP__time-slot--selected");
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { statusReducer } from "../../../src/js/components/DateTimePicker/contexts/status-reducer";
|
|
2
2
|
import {
|
|
3
|
+
testSingleSlotsArray,
|
|
4
|
+
testSingleSlotsObject,
|
|
3
5
|
testSlotsObject,
|
|
4
6
|
testSlotsObjectPartial,
|
|
5
7
|
testSlotsArray,
|
|
@@ -212,6 +214,46 @@ describe("Date Time Picker status reducer", () => {
|
|
|
212
214
|
expect(newState).toStrictEqual(oldState);
|
|
213
215
|
});
|
|
214
216
|
|
|
217
|
+
it("SET_INITIAL_SLOTS when there is only one available slot", async () => {
|
|
218
|
+
const oldState = {
|
|
219
|
+
...startingState,
|
|
220
|
+
selectedDay: false,
|
|
221
|
+
focusedDay: false,
|
|
222
|
+
slots: {},
|
|
223
|
+
availableDays: [],
|
|
224
|
+
slotFetchCount: 0,
|
|
225
|
+
};
|
|
226
|
+
const result = statusReducer(oldState, {
|
|
227
|
+
type: "SET_INITIAL_SLOTS",
|
|
228
|
+
slots: testSingleSlotsArray,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
delete oldState.selectedDay;
|
|
232
|
+
delete oldState.focusedDay;
|
|
233
|
+
delete oldState.slots;
|
|
234
|
+
delete oldState.availableDays;
|
|
235
|
+
delete oldState.slotFetchCount;
|
|
236
|
+
|
|
237
|
+
const {
|
|
238
|
+
selectedDay,
|
|
239
|
+
focusedDay,
|
|
240
|
+
slots,
|
|
241
|
+
availableDays,
|
|
242
|
+
slotFetchCount,
|
|
243
|
+
...newState
|
|
244
|
+
} = result;
|
|
245
|
+
|
|
246
|
+
// These values have been updated
|
|
247
|
+
expect(selectedDay).toBe("2021-09-29");
|
|
248
|
+
expect(focusedDay).toBe("2021-09-29");
|
|
249
|
+
expect(slots).toStrictEqual(testSingleSlotsObject);
|
|
250
|
+
expect(availableDays).toStrictEqual(["2021-09-29"]);
|
|
251
|
+
expect(slotFetchCount).toBe(1);
|
|
252
|
+
|
|
253
|
+
// All other values are unchanged
|
|
254
|
+
expect(newState).toStrictEqual(oldState);
|
|
255
|
+
});
|
|
256
|
+
|
|
215
257
|
it("SET_DEFAULT_SLOTS", async () => {
|
|
216
258
|
const oldState = {
|
|
217
259
|
...startingState,
|
|
@@ -243,6 +285,36 @@ describe("Date Time Picker status reducer", () => {
|
|
|
243
285
|
expect(newState).toStrictEqual(oldState);
|
|
244
286
|
});
|
|
245
287
|
|
|
288
|
+
it("SET_DEFAULT_SLOTS when there is only one available slot", async () => {
|
|
289
|
+
const oldState = {
|
|
290
|
+
...startingState,
|
|
291
|
+
selectedDay: false,
|
|
292
|
+
focusedDay: false,
|
|
293
|
+
slots: {},
|
|
294
|
+
slotFetchCount: 0,
|
|
295
|
+
};
|
|
296
|
+
const result = statusReducer(oldState, {
|
|
297
|
+
type: "SET_DEFAULT_SLOTS",
|
|
298
|
+
slots: testSingleSlotsArray,
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
delete oldState.selectedDay;
|
|
302
|
+
delete oldState.focusedDay;
|
|
303
|
+
delete oldState.slots;
|
|
304
|
+
delete oldState.slotFetchCount;
|
|
305
|
+
|
|
306
|
+
const { selectedDay, focusedDay, slots, slotFetchCount, ...newState } = result;
|
|
307
|
+
|
|
308
|
+
// These values have been updated
|
|
309
|
+
expect(selectedDay).toBe("2021-09-29");
|
|
310
|
+
expect(focusedDay).toBe("2021-09-29");
|
|
311
|
+
expect(slots).toStrictEqual(testSingleSlotsObject);
|
|
312
|
+
expect(slotFetchCount).toBe(1);
|
|
313
|
+
|
|
314
|
+
// All other values are unchanged
|
|
315
|
+
expect(newState).toStrictEqual(oldState);
|
|
316
|
+
});
|
|
317
|
+
|
|
246
318
|
it("SET_ADDITIONAL_SLOTS", async () => {
|
|
247
319
|
const oldState = {
|
|
248
320
|
...startingState,
|
|
@@ -270,6 +342,36 @@ describe("Date Time Picker status reducer", () => {
|
|
|
270
342
|
expect(newState).toStrictEqual(oldState);
|
|
271
343
|
});
|
|
272
344
|
|
|
345
|
+
it("SET_ADDITIONAL_SLOTS when there is only one available slot", async () => {
|
|
346
|
+
const oldState = {
|
|
347
|
+
...startingState,
|
|
348
|
+
selectedDay: false,
|
|
349
|
+
focusedDay: false,
|
|
350
|
+
slots: {},
|
|
351
|
+
slotFetchCount: 0,
|
|
352
|
+
};
|
|
353
|
+
const result = statusReducer(oldState, {
|
|
354
|
+
type: "SET_ADDITIONAL_SLOTS",
|
|
355
|
+
slots: testSingleSlotsArray,
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
delete oldState.selectedDay;
|
|
359
|
+
delete oldState.focusedDay;
|
|
360
|
+
delete oldState.slots;
|
|
361
|
+
delete oldState.slotFetchCount;
|
|
362
|
+
|
|
363
|
+
const { selectedDay, focusedDay, slots, slotFetchCount, ...newState } = result;
|
|
364
|
+
|
|
365
|
+
// These values have been updated
|
|
366
|
+
expect(selectedDay).toBe("2021-09-29");
|
|
367
|
+
expect(focusedDay).toBe("2021-09-29");
|
|
368
|
+
expect(slots).toStrictEqual(testSingleSlotsObject);
|
|
369
|
+
expect(slotFetchCount).toBe(1);
|
|
370
|
+
|
|
371
|
+
// All other values are unchanged
|
|
372
|
+
expect(newState).toStrictEqual(oldState);
|
|
373
|
+
});
|
|
374
|
+
|
|
273
375
|
it("SET_FOCUS", async () => {
|
|
274
376
|
const oldState = { ...startingState };
|
|
275
377
|
const date = "2021-09-29";
|
|
@@ -311,6 +413,7 @@ describe("Date Time Picker status reducer", () => {
|
|
|
311
413
|
},
|
|
312
414
|
],
|
|
313
415
|
required_duration: { minutes: 60 },
|
|
416
|
+
max_results: 512,
|
|
314
417
|
},
|
|
315
418
|
},
|
|
316
419
|
{
|
|
@@ -325,6 +428,7 @@ describe("Date Time Picker status reducer", () => {
|
|
|
325
428
|
},
|
|
326
429
|
],
|
|
327
430
|
required_duration: { minutes: 60 },
|
|
431
|
+
max_results: 512,
|
|
328
432
|
},
|
|
329
433
|
},
|
|
330
434
|
];
|
|
@@ -408,6 +512,7 @@ describe("Date Time Picker status reducer", () => {
|
|
|
408
512
|
month: "2021-09",
|
|
409
513
|
current: false,
|
|
410
514
|
query: {
|
|
515
|
+
max_results: 512,
|
|
411
516
|
participants: [{ sub: "acc_5f35432b3f07d06753082354" }],
|
|
412
517
|
query_periods: [
|
|
413
518
|
{
|
|
@@ -422,6 +527,7 @@ describe("Date Time Picker status reducer", () => {
|
|
|
422
527
|
month: "2021-10",
|
|
423
528
|
current: true,
|
|
424
529
|
query: {
|
|
530
|
+
max_results: 512,
|
|
425
531
|
participants: [{ sub: "acc_5f35432b3f07d06753082354" }],
|
|
426
532
|
query_periods: [
|
|
427
533
|
{
|