|
1 | | -import { Field, SingleSelect, SingleSelectOption } from '@strapi/design-system'; |
2 | | -import { useEffect, useState } from 'react'; |
| 1 | +import { Combobox, ComboboxOption, Field } from '@strapi/design-system'; |
| 2 | +import { Clock } from '@strapi/icons'; |
| 3 | +import { useField, type FieldValue, type InputProps } from '@strapi/strapi/admin'; |
| 4 | +import React from 'react'; |
3 | 5 | import { useIntl } from 'react-intl'; |
4 | | -import moment from 'moment-timezone'; |
| 6 | +import { getTranslation } from '../utils/getTranslation'; |
5 | 7 |
|
6 | | -export const TimezoneSelect = ({ |
7 | | - value, |
8 | | - onChange, |
9 | | - name, |
10 | | - intlLabel, |
11 | | - error, |
12 | | - }: { |
13 | | - value: string | null; |
14 | | - onChange: (name: string, value: string | null) => void; |
15 | | - name: string; |
16 | | - intlLabel: { id: string; defaultMessage: string }; |
17 | | - error?: string; |
18 | | - }) => { |
19 | | - const { formatMessage } = useIntl(); |
20 | | - const label = formatMessage(intlLabel); |
21 | | - const errorMessage = error ? formatMessage({ id: error, defaultMessage: error }) : ''; |
| 8 | +const timezones = Intl.supportedValuesOf('timeZone'); // Outputs: ["Africa/Abidjan", "Africa/Accra", ...] |
| 9 | +const currentTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; |
22 | 10 |
|
23 | | - const [timezones, setTimezones] = useState<Array<{ value: string; label: string }>>([]); |
| 11 | +type TimezoneSelectProps = InputProps & FieldValue; |
24 | 12 |
|
25 | | - useEffect(() => { |
26 | | - const zones = moment.tz.names().map((zone) => ({ |
27 | | - value: zone, |
28 | | - label: `${zone} (${moment.tz(zone).format('Z')})`, |
29 | | - })); |
30 | | - setTimezones(zones.sort((a, b) => a.label.localeCompare(b.label))); |
31 | | - }, []); |
| 13 | +const TimezoneSelect = React.forwardRef<HTMLDivElement, TimezoneSelectProps>( |
| 14 | + ({ |
| 15 | + name, |
| 16 | + value, |
| 17 | + hint, |
| 18 | + required, |
| 19 | + disabled, |
| 20 | + error, |
| 21 | + }, forwardedRef) => { |
| 22 | + const { formatMessage } = useIntl(); |
| 23 | + const field = useField(name); |
32 | 24 |
|
33 | | - return ( |
34 | | - <Field.Root error={errorMessage} name={name}> |
35 | | - <Field.Label>{label}</Field.Label> |
36 | | - <SingleSelect |
37 | | - onChange={(timezone: string) => onChange(name, timezones.find((tz) => tz.value === timezone)?.value || null)} |
38 | | - onClear={() => onChange(name, null)} |
39 | | - value={value || ''} |
| 25 | + return ( |
| 26 | + <Field.Root |
| 27 | + id={name} |
| 28 | + name={name} |
| 29 | + error={error} |
| 30 | + required={required} |
| 31 | + hint={hint} |
40 | 32 | > |
41 | | - {timezones.map(({ value, label }) => ( |
42 | | - <SingleSelectOption key={value} value={value}> |
43 | | - {label} |
44 | | - </SingleSelectOption> |
45 | | - ))} |
46 | | - </SingleSelect> |
47 | | - <Field.Error /> |
48 | | - </Field.Root> |
49 | | - ); |
50 | | -}; |
| 33 | + <Field.Label> |
| 34 | + {name} |
| 35 | + </Field.Label> |
| 36 | + <Combobox |
| 37 | + label={formatMessage({ |
| 38 | + id: getTranslation('label'), |
| 39 | + defaultMessage: 'Select a time zone', |
| 40 | + })} |
| 41 | + placeholder={formatMessage({ |
| 42 | + id: getTranslation('placeholder'), |
| 43 | + defaultMessage: 'Select a time zone or start typing the name of a city', |
| 44 | + })} |
| 45 | + aria-label={formatMessage({ |
| 46 | + id: getTranslation('aria-label'), |
| 47 | + defaultMessage: 'Select a time zone', |
| 48 | + })} |
| 49 | + aria-disabled={disabled} |
| 50 | + disabled={disabled} |
| 51 | + startIcon={<Clock />} |
| 52 | + value={value ?? currentTimeZone} |
| 53 | + clearLabel="Clear" |
| 54 | + onClear={() => { field.onChange(name, "") }} |
| 55 | + onChange={(timezone: string) => { field.onChange(name, timezone) }} |
| 56 | + autocomplete={{ type: 'list', filter: 'contains' }} |
| 57 | + > |
| 58 | + {timezones.map((timezone) => ( |
| 59 | + <ComboboxOption key={timezone} value={timezone}>{timezone}</ComboboxOption> |
| 60 | + ))} |
| 61 | + </Combobox> |
| 62 | + <Field.Error /> |
| 63 | + <Field.Hint /> |
| 64 | + </Field.Root> |
| 65 | + ) |
| 66 | + }) |
| 67 | + |
| 68 | +export default TimezoneSelect; |
0 commit comments