cronofy-elements 1.44.1 → 1.45.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 (35) hide show
  1. package/build/CronofyElements.v1.45.0.js +2 -0
  2. package/build/{CronofyElements.v1.44.1.js.LICENSE.txt → CronofyElements.v1.45.0.js.LICENSE.txt} +0 -0
  3. package/build/npm/CronofyElements.js +2 -2
  4. package/demo/rules.ejs +7 -1
  5. package/package.json +1 -1
  6. package/src/js/components/AvailabilityRules/AvailabilityRules.js +15 -1
  7. package/src/js/components/AvailabilityRules/CalendarSelector.js +1 -1
  8. package/src/js/components/AvailabilityRules/Calendars.js +1 -1
  9. package/src/js/components/AvailabilityRules/TimeZoneDisplay.js +13 -2
  10. package/src/js/components/AvailabilityRules/Wrapper.js +41 -16
  11. package/src/js/components/AvailabilityRules/scss/_base.buttons.scss +58 -0
  12. package/src/js/components/AvailabilityRules/scss/_base.theme.scss +4 -0
  13. package/src/js/components/AvailabilityRules/scss/_components.timezoneselector.scss +74 -0
  14. package/src/js/components/AvailabilityRules/scss/_generic.reset.scss +13 -0
  15. package/src/js/components/AvailabilityRules/scss/_settings.colours.scss +12 -0
  16. package/src/js/components/AvailabilityRules/scss/availabilityrules.scss +5 -0
  17. package/src/js/components/AvailabilityRules/utils/tz-utils.js +44 -0
  18. package/src/js/components/DateTimePicker/Calendar.js +1 -1
  19. package/src/js/components/DateTimePicker/CalendarHeader.js +1 -1
  20. package/src/js/components/DateTimePicker/Confirm.js +1 -1
  21. package/src/js/components/DateTimePicker/DateTimePicker.js +1 -1
  22. package/src/js/components/DateTimePicker/DayButton.js +1 -1
  23. package/src/js/components/DateTimePicker/Details.js +5 -2
  24. package/src/js/components/DateTimePicker/SequencedSlotButton.js +1 -1
  25. package/src/js/components/DateTimePicker/SlotButton.js +1 -1
  26. package/src/js/components/DateTimePicker/Wrapper.js +1 -1
  27. package/src/js/components/DateTimePicker/utils/slots.js +1 -1
  28. package/src/js/components/{DateTimePicker → generic}/TimeZoneSelector.js +9 -16
  29. package/src/js/{components/DateTimePicker/contexts → contexts}/tz-context.js +0 -0
  30. package/src/js/{components/DateTimePicker/utils → helpers}/tz-list.js +0 -0
  31. package/tests/AvailabilityRules/__snapshots__/AvailabilityRules.test.js.snap +36 -6
  32. package/tests/DateTimePicker/SequencedSlotButton.test.js +1 -1
  33. package/tests/DateTimePicker/SlotButton.test.js +1 -1
  34. package/tests/components/TimezoneSelector.test.js +124 -0
  35. package/build/CronofyElements.v1.44.1.js +0 -2
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.45.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";
@@ -173,7 +180,7 @@ const Wrapper = ({ options }) => {
173
180
  .then(res => {
174
181
  const isNewRule = res[0].type === 404;
175
182
  const rulesResponse = isNewRule
176
- ? buildRuleTemplate(options.config.defaultWeeklyPeriods, options.tzid)
183
+ ? buildRuleTemplate(options.config.defaultWeeklyPeriods, tz.selectedTzid.tzid)
177
184
  : res[0];
178
185
 
179
186
  if (isNewRule) {
@@ -198,6 +205,15 @@ const Wrapper = ({ options }) => {
198
205
  tzid: rulesResponse.availability_rule.tzid,
199
206
  }));
200
207
 
208
+ const selectedTzid = getInitialSelectedTzid(
209
+ tz.list,
210
+ rulesResponse.availability_rule.tzid
211
+ );
212
+ setTz({
213
+ list: tz.list,
214
+ selectedTzid: selectedTzid,
215
+ });
216
+
201
217
  setSlots(slots => {
202
218
  const hydratedSlots = checkSlotAvailability(
203
219
  rulesResponse.availability_rule.weekly_periods,
@@ -269,6 +285,15 @@ const Wrapper = ({ options }) => {
269
285
  }
270
286
  }, [status]);
271
287
 
288
+ useEffect(() => {
289
+ if (tz.selectedTzid.tzid) {
290
+ setAccount(account => ({
291
+ ...account,
292
+ tzid: tz.selectedTzid.tzid,
293
+ }));
294
+ }
295
+ }, [tz.selectedTzid.tzid]);
296
+
272
297
  const generateRules = () => {
273
298
  const newRules = buildNewRules(slots);
274
299
 
@@ -373,7 +398,7 @@ const Wrapper = ({ options }) => {
373
398
  overflow: hidden;
374
399
  }
375
400
  `}
376
- className={`${theme.prefix}`}
401
+ className={theme.classBuilder()}
377
402
  >
378
403
  <ThemeContext.Provider value={[theme, setTheme]}>
379
404
  <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();
@@ -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 Confirm = ({ confirmButtonRef }) => {
10
10
  const i18n = useI18n();
@@ -18,7 +18,7 @@ import { I18nProvider } from "../../contexts/i18n-context";
18
18
  import { LogProvider } from "../../contexts/log-context";
19
19
  import { ThemeProvider } from "./contexts/theme-context";
20
20
  import { StatusProvider } from "./contexts/status-context";
21
- import { TzProvider } from "./contexts/tz-context";
21
+ import { TzProvider } from "../../contexts/tz-context";
22
22
 
23
23
  const DateTimePicker = ({ options }) => {
24
24
  const statusOptions = useMemo(() => {
@@ -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 DayButton = ({ day, selected = false, focused = false }) => {
10
10
  const i18n = useI18n();
@@ -2,11 +2,14 @@ import React, { memo } from "react";
2
2
 
3
3
  import { useI18n } from "../../contexts/i18n-context";
4
4
  import { useTheme } from "./contexts/theme-context";
5
- import TimeZoneSelector from "./TimeZoneSelector";
5
+ import TimeZoneSelector from "../generic/TimeZoneSelector";
6
+
7
+ import { useTz } from "../../contexts/tz-context";
6
8
 
7
9
  const Details = ({ duration, locale }) => {
8
10
  const i18n = useI18n();
9
11
  const theme = useTheme();
12
+ const [tz, setTz] = useTz();
10
13
 
11
14
  return (
12
15
  <div className={theme.classBuilder("details")}>
@@ -14,7 +17,7 @@ const Details = ({ duration, locale }) => {
14
17
  <p className={theme.classBuilder("details--tz-label")}>
15
18
  <strong>{i18n.t("time_zone")}:</strong>
16
19
  </p>
17
- <TimeZoneSelector locale={locale} />
20
+ <TimeZoneSelector locale={locale} theme={theme} tz={tz} setTz={setTz} />
18
21
  </div>
19
22
  <div className={theme.classBuilder("details--duration")}>
20
23
  {duration && (
@@ -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 SequencedSlotButton = ({ slot }) => {
10
10
  const i18n = useI18n();
@@ -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 SlotButton = ({ slot }) => {
10
10
  const i18n = useI18n();
@@ -14,7 +14,7 @@ import SlotsList from "./SlotsList";
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 Wrapper = () => {
20
20
  const [status, dispatchStatus] = useStatus();
@@ -4,7 +4,7 @@ import { getAvailability, getSequencedAvailability } from "../../../helpers/conn
4
4
  import { uniqueItems, humanizeTzName } from "../../../helpers/utils";
5
5
  import { errorMessages } from "../../../helpers/logging";
6
6
 
7
- import { defaultTimeZones } from "./tz-list";
7
+ import { defaultTimeZones } from "../../../helpers/tz-list";
8
8
 
9
9
  export const getMonthsCoveredByPeriod = (period, tzid) => {
10
10
  const start = moment
@@ -1,14 +1,8 @@
1
1
  import React, { useEffect, useRef, useState } from "react";
2
2
 
3
- import { useTheme } from "./contexts/theme-context";
4
-
5
3
  import { tzi18n } from "../../helpers/i18n";
6
- import { useTz } from "./contexts/tz-context";
7
-
8
- const TimeZoneSelector = ({ locale }) => {
9
- const theme = useTheme();
10
- const [tz, setTz] = useTz();
11
4
 
5
+ const TimeZoneSelector = ({ locale, theme, tz, setTz }) => {
12
6
  const [showList, setShowList] = useState(() => false);
13
7
  const [focused, setFocused] = useState(() => false);
14
8
 
@@ -31,27 +25,26 @@ const TimeZoneSelector = ({ locale }) => {
31
25
  };
32
26
 
33
27
  const handleKeyDown = e => {
28
+ const list = tz.list;
34
29
  switch (e.key) {
35
30
  case "ArrowDown":
36
31
  e.preventDefault();
37
- const nextFocusedItemIndex = tz.list.findIndex(item => focused === item.tzid) + 1;
38
- const nextItem =
39
- nextFocusedItemIndex > tz.list.length - 1 ? 0 : nextFocusedItemIndex;
32
+ const nextFocusedItemIndex = list.findIndex(item => focused === item.tzid) + 1;
33
+ const nextItem = nextFocusedItemIndex > list.length - 1 ? 0 : nextFocusedItemIndex;
40
34
 
41
- setFocused(tz.list[nextItem].tzid);
35
+ setFocused(list[nextItem].tzid);
42
36
 
43
37
  break;
44
38
  case "ArrowUp":
45
39
  e.preventDefault();
46
- const prevFocusedItemIndex = tz.list.findIndex(item => focused === item.tzid) - 1;
47
- const prevItem =
48
- prevFocusedItemIndex < 0 ? tz.list.length - 1 : prevFocusedItemIndex;
40
+ const prevFocusedItemIndex = list.findIndex(item => focused === item.tzid) - 1;
41
+ const prevItem = prevFocusedItemIndex < 0 ? list.length - 1 : prevFocusedItemIndex;
49
42
 
50
- setFocused(tz.list[prevItem].tzid);
43
+ setFocused(list[prevItem].tzid);
51
44
 
52
45
  break;
53
46
  case "Enter":
54
- const tz = tz.list.find(item => focused === item.tzid);
47
+ const tz = list.find(item => focused === item.tzid);
55
48
  handleOptionSelect(tz);
56
49
  break;
57
50
  case "Escape":