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.
Files changed (45) hide show
  1. package/Makefile +1 -1
  2. package/build/CronofyElements.v1.40.0.js +2 -0
  3. package/build/{CronofyElements.v1.38.1.js.LICENSE.txt → CronofyElements.v1.40.0.js.LICENSE.txt} +0 -0
  4. package/build/npm/CronofyElements.js +2 -2
  5. package/demo/availability-viewer.ejs +8 -0
  6. package/demo/date-time-picker.ejs +1 -0
  7. package/demo/rules.ejs +2 -1
  8. package/package.json +1 -1
  9. package/src/js/components/AvailabilityRules/Slot.js +78 -4
  10. package/src/js/components/AvailabilityRules/Slots.js +3 -2
  11. package/src/js/components/AvailabilityRules/Week.js +7 -6
  12. package/src/js/components/AvailabilityRules/contexts/drag-context.js +15 -0
  13. package/src/js/components/AvailabilityViewer/AvailabilityViewer.js +14 -15
  14. package/src/js/components/AvailabilityViewer/Navigation.js +23 -37
  15. package/src/js/components/AvailabilityViewer/WeekWrapper.js +3 -8
  16. package/src/js/components/AvailabilityViewer/contexts/page-context.js +17 -0
  17. package/src/js/components/AvailabilityViewer/contexts/page-reducer.js +28 -0
  18. package/src/js/components/DateTimePicker/Confirm.js +1 -1
  19. package/src/js/components/DateTimePicker/SlotButton.js +9 -3
  20. package/src/js/components/DateTimePicker/contexts/status-reducer.js +27 -10
  21. package/src/js/components/DateTimePicker/scss/_components.slotslist.scss +7 -0
  22. package/src/js/components/DateTimePicker/utils/slots.js +5 -1
  23. package/src/js/helpers/init.AvailabilityRules.js +24 -0
  24. package/src/js/helpers/utils.AvailabilityRules.js +6 -0
  25. package/src/js/helpers/utils.AvailabilityViewer.js +7 -2
  26. package/src/js/main.js +17 -1
  27. package/tests/AvailabilityViewer/Navigation.test.js +130 -0
  28. package/tests/AvailabilityViewer/contexts/page-reducer.test.js +87 -0
  29. package/tests/CalendarSync/Active.test.js +1 -1
  30. package/tests/CalendarSync/AddToggle.test.js +1 -1
  31. package/tests/CalendarSync/EditToggle.test.js +1 -1
  32. package/tests/CalendarSync/Inactive.test.js +1 -1
  33. package/tests/CalendarSync/Pending.test.js +1 -1
  34. package/tests/DateTimePicker/SlotButton.test.js +107 -0
  35. package/tests/DateTimePicker/contexts/status-reducer.test.js +106 -0
  36. package/tests/DateTimePicker/dummy-data.js +16 -0
  37. package/tests/DateTimePicker/utils.test.js +166 -0
  38. package/tests/components/main.test.js +8 -1
  39. package/tests/init.AvailabilityRules.test.js +30 -0
  40. package/tests/{CalendarSync/mocks → mocks}/i18n.js +0 -0
  41. package/tests/mocks/theme.js +3 -0
  42. package/tests/utils.AvailabilityRules.test.js +3 -0
  43. package/tests/utils.AvailabilityViewer.test.js +8 -0
  44. package/build/CronofyElements.v1.38.1.js +0 -2
  45. 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: { ...query, query_periods: croppedQueryPeriods },
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: Math.ceil(weekdays.length / 7),
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
- return generateElementAPI(
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 "./mocks/i18n";
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 "./mocks/i18n";
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 "./mocks/i18n";
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 "./mocks/i18n";
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 "./mocks/i18n";
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
  {