cronofy-elements 1.44.1 → 1.47.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 (42) hide show
  1. package/build/CronofyElements.v1.47.0.js +2 -0
  2. package/build/{CronofyElements.v1.44.1.js.LICENSE.txt → CronofyElements.v1.47.0.js.LICENSE.txt} +0 -0
  3. package/build/npm/CronofyElements.js +2 -2
  4. package/demo/date-time-picker.ejs +5 -32
  5. package/demo/rules.ejs +7 -1
  6. package/package.json +1 -1
  7. package/src/js/components/AvailabilityRules/AvailabilityRules.js +15 -1
  8. package/src/js/components/AvailabilityRules/CalendarSelector.js +1 -1
  9. package/src/js/components/AvailabilityRules/Calendars.js +1 -1
  10. package/src/js/components/AvailabilityRules/TimeZoneDisplay.js +13 -2
  11. package/src/js/components/AvailabilityRules/Wrapper.js +45 -34
  12. package/src/js/components/AvailabilityRules/scss/_base.buttons.scss +58 -0
  13. package/src/js/components/AvailabilityRules/scss/_base.theme.scss +4 -0
  14. package/src/js/components/AvailabilityRules/scss/_components.timezoneselector.scss +74 -0
  15. package/src/js/components/AvailabilityRules/scss/_generic.reset.scss +13 -0
  16. package/src/js/components/AvailabilityRules/scss/_settings.colours.scss +12 -0
  17. package/src/js/components/AvailabilityRules/scss/availabilityrules.scss +5 -0
  18. package/src/js/components/AvailabilityRules/utils/tz-utils.js +44 -0
  19. package/src/js/components/DateTimePicker/Calendar.js +1 -1
  20. package/src/js/components/DateTimePicker/CalendarHeader.js +1 -1
  21. package/src/js/components/DateTimePicker/Confirm.js +38 -2
  22. package/src/js/components/DateTimePicker/DateTimePicker.js +1 -4
  23. package/src/js/components/DateTimePicker/DayButton.js +1 -1
  24. package/src/js/components/DateTimePicker/Details.js +5 -2
  25. package/src/js/components/DateTimePicker/SequencedSlotButton.js +1 -1
  26. package/src/js/components/DateTimePicker/SlotButton.js +1 -1
  27. package/src/js/components/DateTimePicker/Wrapper.js +115 -38
  28. package/src/js/components/DateTimePicker/contexts/status-reducer.js +29 -8
  29. package/src/js/components/DateTimePicker/scss/_components.confirm.scss +10 -0
  30. package/src/js/components/DateTimePicker/utils/slots.js +23 -78
  31. package/src/js/components/{DateTimePicker → generic}/TimeZoneSelector.js +10 -16
  32. package/src/js/{components/DateTimePicker/contexts → contexts}/tz-context.js +0 -0
  33. package/src/js/helpers/init.DateTimePicker.js +17 -0
  34. package/src/js/{components/DateTimePicker/utils → helpers}/tz-list.js +0 -0
  35. package/tests/AvailabilityRules/__snapshots__/AvailabilityRules.test.js.snap +37 -6
  36. package/tests/DateTimePicker/SequencedSlotButton.test.js +1 -1
  37. package/tests/DateTimePicker/SlotButton.test.js +1 -1
  38. package/tests/DateTimePicker/contexts/status-reducer.test.js +180 -24
  39. package/tests/DateTimePicker/dummy-data.js +186 -1
  40. package/tests/DateTimePicker/utils.test.js +32 -3
  41. package/tests/components/TimezoneSelector.test.js +124 -0
  42. package/build/CronofyElements.v1.44.1.js +0 -2
@@ -49,6 +49,7 @@
49
49
  sequence: [
50
50
  {
51
51
  sequence_id: "test",
52
+ sequence_title: "Test Event One",
52
53
  ordinal: 1,
53
54
  participants: [
54
55
  {
@@ -66,6 +67,7 @@
66
67
  },
67
68
  {
68
69
  sequence_id: "test-1",
70
+ sequence_title: "Test Event Two",
69
71
  ordinal: 2,
70
72
  participants: [
71
73
  {
@@ -86,31 +88,7 @@
86
88
  minimum: { minutes: 15 }
87
89
  }
88
90
  }
89
- },
90
- {
91
- sequence_id: "test-2",
92
- ordinal: 3,
93
- participants: [
94
- {
95
- required: "all",
96
- members: [
97
- {
98
- sub: "<%= sub %>",
99
- // managed_availability: true,
100
- // availability_rule_ids: ["weekly_work_hours"]
101
- }
102
- ]
103
- }
104
- ],
105
- required_duration: { minutes: 30 },
106
- start_interval: { minutes: 10 },
107
- buffer: {
108
- before: {
109
- minimum: { minutes: 15 }
110
- }
111
- }
112
- },
113
-
91
+ },
114
92
  ],
115
93
  query_periods: [
116
94
  { start: slotTimes(01,"08:00"), end: slotTimes(31,"17:00") }
@@ -136,15 +114,10 @@
136
114
  ]
137
115
  }
138
116
  ],
139
- required_duration: { minutes: 60 },
117
+ required_duration: { minutes: 15 },
140
118
  //start_interval: { minutes: 15 },
141
119
  query_periods: [
142
- { start: slotTimes(31,"03:00"), end: slotTimes(31,"12:00") },
143
- { start: slotTimes(32,"09:00"), end: slotTimes(32,"13:00") },
144
- { start: slotTimes(32,"14:00"), end: slotTimes(32,"17:00") },
145
- { start: slotTimes(35,"09:00"), end: slotTimes(35,"13:00") },
146
- { start: slotTimes(36,"14:00"), end: slotTimes(36,"17:00") },
147
- { start: slotTimes(38,"09:00"), end: slotTimes(65,"22:00") }
120
+ { start: slotTimes(31,"03:00"), end: slotTimes(150,"12:00") },
148
121
  ]
149
122
  },
150
123
  // tzid: "America/Mexico_City",
package/demo/rules.ejs CHANGED
@@ -77,7 +77,13 @@
77
77
  // start_time: "09:00",
78
78
  // end_time: "13:00"
79
79
  // }],
80
- // auto_create_rules: true
80
+ // auto_create_rules: true,
81
+ // tz_list: [
82
+ // "America/Sao_Paulo",
83
+ // "Etc/UTC",
84
+ // "Pacific/Fakaofo",
85
+ // "Europe/London",
86
+ // ],
81
87
  },
82
88
  callback: cb => console.log('rules callback',cb),
83
89
  styles: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cronofy-elements",
3
- "version": "1.44.1",
3
+ "version": "1.47.0",
4
4
  "description": "Fast track scheduling with Cronofy's embeddable UI Elements",
5
5
  "main": "build/npm/CronofyElements.js",
6
6
  "scripts": {
@@ -2,9 +2,14 @@ import React from "react";
2
2
 
3
3
  import { I18nProvider } from "../../contexts/i18n-context";
4
4
  import { LogProvider } from "../../contexts/log-context";
5
+ import { TzProvider } from "../../contexts/tz-context";
6
+
7
+ import { parseTzList, getInitialSelectedTzid } from "./utils/tz-utils";
5
8
 
6
9
  import Wrapper from "./Wrapper";
7
10
 
11
+ import "./scss/availabilityrules.scss";
12
+
8
13
  const AvailabilityRules = ({ options }) => {
9
14
  const logOptions = {
10
15
  mode: options.config.logs,
@@ -19,10 +24,19 @@ const AvailabilityRules = ({ options }) => {
19
24
  tzid: options.tzid,
20
25
  };
21
26
 
27
+ const tzList = parseTzList(options.config.tz_list, options.tzid);
28
+ const selectedTzid = getInitialSelectedTzid(tzList, options.tzid);
29
+ const tzOptions = {
30
+ selectedTzid: selectedTzid,
31
+ list: tzList,
32
+ };
33
+
22
34
  return (
23
35
  <LogProvider options={logOptions}>
24
36
  <I18nProvider options={i18nOptions}>
25
- <Wrapper options={options} />
37
+ <TzProvider options={tzOptions}>
38
+ <Wrapper options={options} />
39
+ </TzProvider>
26
40
  </I18nProvider>
27
41
  </LogProvider>
28
42
  );
@@ -50,7 +50,7 @@ const CalendarSelector = ({ calendars, done, add, remove }) => {
50
50
  ref={wrapperRef}
51
51
  css={css`
52
52
  position: absolute;
53
- z-index: 6;
53
+ z-index: 10;
54
54
  top: 100%;
55
55
  left: 0;
56
56
  transform: translateY(10px);
@@ -79,7 +79,7 @@ const Calendars = ({ loading }) => {
79
79
  return (
80
80
  <div
81
81
  css={css`
82
- z-index: 2;
82
+ z-index: 5;
83
83
  position: relative;
84
84
  width: 100%;
85
85
  display: flex;
@@ -2,27 +2,38 @@ import React, { useContext } from "react";
2
2
  import { css } from "@emotion/core";
3
3
 
4
4
  import { ExtrasContext, StatusContext, ThemeContext } from "./Wrapper";
5
+ import { useTz } from "../../contexts/tz-context";
5
6
  import { useI18n } from "../../contexts/i18n-context";
6
- import { tzi18n } from "../../helpers/i18n";
7
+ import TimeZoneSelector from "../generic/TimeZoneSelector";
7
8
 
8
9
  const TimeZoneDisplay = () => {
9
10
  const [extras, setExtras] = useContext(ExtrasContext);
10
11
  const [status, setStatus] = useContext(StatusContext);
11
12
  const i18n = useI18n();
12
13
  const [theme, setTheme] = useContext(ThemeContext);
14
+ const [tz, setTz] = useTz();
13
15
  return (
14
16
  <div
15
17
  css={css`
16
18
  flex-grow: 1;
17
19
  display: flex;
18
20
  width: 100%;
21
+ padding-right: 1em;
19
22
  @media (max-width: ${theme.sizes.breakpoints.small}px) {
20
23
  margin-bottom: 16px;
21
24
  }
22
25
  `}
23
26
  className={`${theme.prefix}__timezone`}
24
27
  >
25
- {i18n.t("time_zone")}: {tzi18n(extras.limits.tzid, status.locale)}
28
+ <p
29
+ css={css`
30
+ padding: 0.3em 0.6em 0 0;
31
+ margin: 0;
32
+ `}
33
+ >
34
+ {i18n.t("time_zone")}
35
+ </p>
36
+ <TimeZoneSelector locale={status.locale} theme={theme} tz={tz} setTz={setTz} />
26
37
  </div>
27
38
  );
28
39
  };
@@ -14,10 +14,12 @@ import {
14
14
  parseAccountOptions,
15
15
  buildRuleTemplate,
16
16
  } from "../../helpers/utils.AvailabilityRules";
17
- import { parseStyleOptions } from "../../helpers/theming";
17
+ import { getInitialSelectedTzid } from "./utils/tz-utils";
18
+ import { parseStyleOptions, classBuilder } from "../../helpers/theming";
18
19
  import { globals } from "../../styles/utils";
19
20
  import { useI18n } from "../../contexts/i18n-context";
20
21
  import { useLog } from "../../contexts/log-context";
22
+ import { useTz } from "../../contexts/tz-context";
21
23
 
22
24
  import Calendars from "./Calendars";
23
25
  import Container from "../generic/Container";
@@ -37,6 +39,7 @@ export const ThemeContext = React.createContext();
37
39
  const Wrapper = ({ options }) => {
38
40
  const i18n = useI18n();
39
41
  const log = useLog();
42
+ const [tz, setTz] = useTz();
40
43
 
41
44
  const [account, setAccount] = useState(() => parseAccountOptions(options));
42
45
  const [calendars, setCalendars] = useState(() => ({
@@ -52,7 +55,7 @@ const Wrapper = ({ options }) => {
52
55
  saved: false,
53
56
  savedSuccess: false,
54
57
  locale: options.locale,
55
- tzid: options.tzid,
58
+ tzid: tz.selectedTzid.tzid,
56
59
  callback: options.callback ? options.callback : cb => {},
57
60
  startDay: options.config.startDay,
58
61
  defaultWeeklyPeriods: options.config.defaultWeeklyPeriods,
@@ -83,19 +86,23 @@ const Wrapper = ({ options }) => {
83
86
  )
84
87
  );
85
88
 
86
- const [theme, setTheme] = useState(() => ({
87
- ...parseStyleOptions(options.styles, "AvailabilityViewer"),
88
- sizes: {
89
- breakpoints: {
90
- small: 650,
89
+ const [theme, setTheme] = useState(() => {
90
+ const styles = parseStyleOptions(options.styles, "AvailabilityViewer");
91
+ return {
92
+ ...styles,
93
+ classBuilder: classBuilder(styles.prefix, "AR"),
94
+ sizes: {
95
+ breakpoints: {
96
+ small: 650,
97
+ },
98
+ labelWidth: 60,
99
+ labelWidthSmall: 24,
100
+ columnWidth: 100,
101
+ wrapperWidth: false,
102
+ wrapperUnderflow: 0,
91
103
  },
92
- labelWidth: 60,
93
- labelWidthSmall: 24,
94
- columnWidth: 100,
95
- wrapperWidth: false,
96
- wrapperUnderflow: 0,
97
- },
98
- }));
104
+ };
105
+ });
99
106
 
100
107
  const handleRuleChange = (IDs, toggleStatus) => {
101
108
  const availability = toggleStatus === "available";
@@ -108,17 +115,7 @@ const Wrapper = ({ options }) => {
108
115
  const allSlots = { ...slots, ...newSlots };
109
116
  setSlots(allSlots);
110
117
  const newRules = buildNewRules(allSlots);
111
- const callbackContent = {
112
- notification: {
113
- type: "availability_rule_edited",
114
- },
115
- availability_rule: {
116
- ...account,
117
- calendar_ids: calendars.active,
118
- weekly_periods: newRules,
119
- },
120
- };
121
- status.callback(callbackContent);
118
+ setRules(newRules);
122
119
  };
123
120
 
124
121
  useEffect(() => {
@@ -141,7 +138,6 @@ const Wrapper = ({ options }) => {
141
138
 
142
139
  useEffect(() => {
143
140
  if (!status.loading && !status.error) {
144
- const newRules = buildNewRules(slots);
145
141
  const callbackContent = {
146
142
  notification: {
147
143
  type: "availability_rule_edited",
@@ -149,12 +145,12 @@ const Wrapper = ({ options }) => {
149
145
  availability_rule: {
150
146
  ...account,
151
147
  calendar_ids: calendars.active,
152
- weekly_periods: newRules,
148
+ weekly_periods: rules,
153
149
  },
154
150
  };
155
151
  status.callback(callbackContent);
156
152
  }
157
- }, [calendars]);
153
+ }, [calendars, account, rules]);
158
154
 
159
155
  useEffect(() => {
160
156
  // Query the API for rules and calendars, but don't do anything until
@@ -173,7 +169,7 @@ const Wrapper = ({ options }) => {
173
169
  .then(res => {
174
170
  const isNewRule = res[0].type === 404;
175
171
  const rulesResponse = isNewRule
176
- ? buildRuleTemplate(options.config.defaultWeeklyPeriods, options.tzid)
172
+ ? buildRuleTemplate(options.config.defaultWeeklyPeriods, tz.selectedTzid.tzid)
177
173
  : res[0];
178
174
 
179
175
  if (isNewRule) {
@@ -198,6 +194,15 @@ const Wrapper = ({ options }) => {
198
194
  tzid: rulesResponse.availability_rule.tzid,
199
195
  }));
200
196
 
197
+ const selectedTzid = getInitialSelectedTzid(
198
+ tz.list,
199
+ rulesResponse.availability_rule.tzid
200
+ );
201
+ setTz({
202
+ list: tz.list,
203
+ selectedTzid: selectedTzid,
204
+ });
205
+
201
206
  setSlots(slots => {
202
207
  const hydratedSlots = checkSlotAvailability(
203
208
  rulesResponse.availability_rule.weekly_periods,
@@ -269,11 +274,17 @@ const Wrapper = ({ options }) => {
269
274
  }
270
275
  }, [status]);
271
276
 
272
- const generateRules = () => {
273
- const newRules = buildNewRules(slots);
277
+ useEffect(() => {
278
+ if (tz.selectedTzid.tzid) {
279
+ setAccount(account => ({
280
+ ...account,
281
+ tzid: tz.selectedTzid.tzid,
282
+ }));
283
+ }
284
+ }, [tz.selectedTzid.tzid]);
274
285
 
275
- setRules(newRules);
276
- const rulesRequest = { ...account, weekly_periods: newRules };
286
+ const generateRules = () => {
287
+ const rulesRequest = { ...account, weekly_periods: rules };
277
288
 
278
289
  let tempStatus = status;
279
290
 
@@ -373,7 +384,7 @@ const Wrapper = ({ options }) => {
373
384
  overflow: hidden;
374
385
  }
375
386
  `}
376
- className={`${theme.prefix}`}
387
+ className={theme.classBuilder()}
377
388
  >
378
389
  <ThemeContext.Provider value={[theme, setTheme]}>
379
390
  <StatusContext.Provider value={[status, setStatus]}>
@@ -0,0 +1,58 @@
1
+ .AR__button {
2
+ appearance: none;
3
+ background: none;
4
+ border: none;
5
+ border-radius: 0;
6
+ font-family: inherit;
7
+ position: relative;
8
+ display: block;
9
+ cursor: pointer;
10
+ font-size: 1em;
11
+ border: 0.1em solid var(--greyMid);
12
+ background-color: var(--white);
13
+
14
+ &:focus {
15
+ border-color: var(--availableActive);
16
+ box-shadow: inset var(--availableActive) 0 0 0 0.1em;
17
+ box-shadow: inset var(--availableActive) 0 0 0 0.1em;
18
+ outline: none;
19
+ }
20
+ &:hover {
21
+ border-color: var(--availableActive);
22
+ box-shadow: inset var(--availableActive) 0 0 0 0.1em;
23
+ background-color: var(--availableHover);
24
+ color: var(--black);
25
+ outline: none;
26
+ }
27
+
28
+ &:active {
29
+ background-color: var(--availableActive);
30
+ color: var(--black);
31
+ outline: none;
32
+ }
33
+ }
34
+
35
+ .AR__disabled-button {
36
+ pointer-events: none;
37
+ border: unset;
38
+ background-color: unset;
39
+
40
+ &:focus {
41
+ border-color: unset;
42
+ box-shadow: unset;
43
+ outline: none;
44
+ background-color: unset;
45
+ }
46
+ &:hover {
47
+ border-color: unset;
48
+ box-shadow: unset;
49
+ outline: none;
50
+ }
51
+
52
+ &:active {
53
+ border-color: unset;
54
+ box-shadow: unset;
55
+ outline: none;
56
+ background-color: unset;
57
+ }
58
+ }
@@ -0,0 +1,4 @@
1
+ .AR {
2
+ @import "base.buttons";
3
+ @import "components.timezoneselector";
4
+ }
@@ -0,0 +1,74 @@
1
+ .AR__timezone-selector {
2
+ position: relative;
3
+ flex-grow: 1;
4
+ max-width: 16rem;
5
+ }
6
+
7
+ .AR__timezone-selector--button {
8
+ @extend .AR__button;
9
+ display: inline-block;
10
+ border: 0.1em solid var(--greyMid);
11
+ background: var(--white);
12
+ padding: 0.3em 1em;
13
+ text-align: left;
14
+ width: 100%;
15
+ border-radius: 0.4em;
16
+ z-index: 4;
17
+ }
18
+
19
+ .AR__timezone-selector--icon {
20
+ width: 1em;
21
+ height: 1em;
22
+ margin-top: 0.2em;
23
+ fill: var(--grey);
24
+ float: right;
25
+ }
26
+
27
+ .AR__timezone-selector--icon-open {
28
+ transform: scaleY(-1);
29
+ }
30
+
31
+ .AR__timezone-selector--listbox-wrapper {
32
+ @extend %unset;
33
+ position: absolute;
34
+ width: 100%;
35
+ border: 0.1em solid var(--greyMid);
36
+ background-color: var(--white);
37
+ border-top: 0;
38
+ padding-top: 1.15em;
39
+ top: 1em;
40
+ z-index: 3;
41
+ border-radius: 0 0 0.4em 0.4em;
42
+ }
43
+
44
+ .AR__timezone-selector--listbox {
45
+ @extend %unset;
46
+ width: 100%;
47
+ max-height: 15em;
48
+ overflow-y: auto;
49
+ }
50
+
51
+ .AR__timezone-selector--option {
52
+ @extend %unset;
53
+ display: block;
54
+ cursor: pointer;
55
+ padding: 0.5em 1em;
56
+ position: relative;
57
+ line-height: 1.8em;
58
+
59
+ &:hover {
60
+ background-color: var(--availableHover);
61
+ color: var(--black);
62
+ }
63
+ }
64
+
65
+ .AR__timezone-selector--focused {
66
+ border-color: var(--availableActive);
67
+ box-shadow: inset var(--availableActive) 0 0 0 0.1em;
68
+ outline: none;
69
+ }
70
+
71
+ .AR__timezone-selector--selected {
72
+ background-color: var(--availableHover);
73
+ color: var(--black);
74
+ }
@@ -0,0 +1,13 @@
1
+ //Unsetting styles to avoid clashes with styles outside the component
2
+ %unset {
3
+ padding: unset;
4
+ margin-top: unset;
5
+ margin-bottom: unset;
6
+ margin-left: unset;
7
+ margin-right: unset;
8
+ border: unset;
9
+ background: unset;
10
+ border-spacing: 0;
11
+ font-style: unset;
12
+ list-style: unset;
13
+ }
@@ -0,0 +1,12 @@
1
+ .AR {
2
+ // Fallbacks
3
+ --black: #000000;
4
+ --white: #ffffff;
5
+
6
+ --grey: #6f6f6f;
7
+ --greyMid: #999999;
8
+ --greyLight: #e4ebf2;
9
+
10
+ --availableHover: #c0e992;
11
+ --availableActive: #7ed321;
12
+ }
@@ -0,0 +1,5 @@
1
+ @import "../../../styles/settings.utils";
2
+ @import "settings.colours";
3
+
4
+ @import "generic.reset";
5
+ @import "base.theme";
@@ -0,0 +1,44 @@
1
+ import moment from "moment-timezone";
2
+ import { humanizeTzName } from "../../../helpers/utils";
3
+ import { defaultTimeZones } from "../../../helpers/tz-list";
4
+
5
+ export const createTzObject = tzid => {
6
+ const name = humanizeTzName(tzid);
7
+
8
+ const zone = moment.tz(tzid);
9
+
10
+ return {
11
+ tzid: tzid,
12
+ offset: zone.format("Z"),
13
+ offsetMins: zone.utcOffset(),
14
+ name: name,
15
+ abbr: zone.zoneAbbr(),
16
+ };
17
+ };
18
+
19
+ export const parseTzList = (timezones, tzid) => {
20
+ const tzList = timezones ? timezones : moment.tz.names();
21
+ const filtered = timezones ? timezones : tzList.filter(item => defaultTimeZones.includes(item));
22
+
23
+ const result = [];
24
+
25
+ filtered.map(tz => {
26
+ const item = createTzObject(tz);
27
+ result.push(item);
28
+ });
29
+
30
+ const isInList = result.findIndex(item => tzid === item.tzid);
31
+
32
+ if (isInList <= -1) {
33
+ const item = createTzObject(tzid);
34
+ result.push(item);
35
+ }
36
+
37
+ result.sort((tzA, tzB) => tzA.offsetMins - tzB.offsetMins);
38
+ return result;
39
+ };
40
+
41
+ export const getInitialSelectedTzid = (tzList, tzid) => {
42
+ const result = tzList.find(tz => tzid === tz.tzid);
43
+ return result;
44
+ };
@@ -14,7 +14,7 @@ import DayHeadings from "./DayHeadings";
14
14
 
15
15
  import { useStatus } from "./contexts/status-context";
16
16
  import { useTheme } from "./contexts/theme-context";
17
- import { useTz } from "./contexts/tz-context";
17
+ import { useTz } from "../../contexts/tz-context";
18
18
 
19
19
  const Calendar = () => {
20
20
  const [status, dispatchStatus] = useStatus();
@@ -4,7 +4,7 @@ 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
+ import { useTz } from "../../contexts/tz-context";
8
8
 
9
9
  const CalendarHeader = () => {
10
10
  const i18n = useI18n();
@@ -1,10 +1,10 @@
1
- import React from "react";
1
+ import React, { useState } from "react";
2
2
  import moment from "moment-timezone";
3
3
 
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
+ import { useTz } from "../../contexts/tz-context";
8
8
 
9
9
  const Confirm = ({ confirmButtonRef }) => {
10
10
  const i18n = useI18n();
@@ -12,6 +12,12 @@ const Confirm = ({ confirmButtonRef }) => {
12
12
  const theme = useTheme();
13
13
  const [tz] = useTz();
14
14
 
15
+ const [sequenceTitlePresent, setSequenceTitlePresent] = useState(
16
+ () =>
17
+ status.selected.sequence &&
18
+ status.selected.sequence.every(obj => Object.keys(obj).includes("sequence_title"))
19
+ );
20
+
15
21
  const handleCancel = () => {
16
22
  dispatchStatus({ type: "CANCEL_SLOT_SELECTION" });
17
23
  };
@@ -52,6 +58,36 @@ const Confirm = ({ confirmButtonRef }) => {
52
58
  )}{" "}
53
59
  {`(${moment.tz(tz.selectedTzid.tzid).format("z")})`}
54
60
  </p>
61
+ {status.selected.sequence && sequenceTitlePresent && (
62
+ <dl className={theme.classBuilder("confirm-details--sequence")}>
63
+ {status.selected.sequence.map((slot, k) => (
64
+ <div key={k}>
65
+ <dt
66
+ className={theme.classBuilder(
67
+ "confirm-details--sequence-title"
68
+ )}
69
+ >
70
+ {slot.sequence_title}
71
+ </dt>
72
+ <dd
73
+ className={theme.classBuilder("confirm-details--sequence-time")}
74
+ >
75
+ {i18n.customFormatedTimeZone(
76
+ moment(slot.start, "YYYY-MM-DDTHH:mm:00Z"),
77
+ tz.selectedTzid.tzid,
78
+ "LT"
79
+ )}
80
+ {" - "}
81
+ {i18n.customFormatedTimeZone(
82
+ moment(slot.end, "YYYY-MM-DDTHH:mm:00Z"),
83
+ tz.selectedTzid.tzid,
84
+ "LT"
85
+ )}
86
+ </dd>
87
+ </div>
88
+ ))}
89
+ </dl>
90
+ )}
55
91
  </div>
56
92
  <button
57
93
  className={theme.classBuilder("confirm-button")}