From 7d3b7be76998d25ab16b86e347f24497079df350 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Wed, 15 Feb 2023 14:58:49 +0000 Subject: [PATCH 01/15] chore(release): cut 1.0.0-beta.22 [skip ci] # [1.0.0-beta.22](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.0-beta.21...v1.0.0-beta.22) (2023-02-15) ### Bug Fixes * change build process to emit cjs and es modules ([#10](https://github.com/dhis2/multi-calendar-dates/issues/10)) ([1102de8](https://github.com/dhis2/multi-calendar-dates/commit/1102de87fd99006e1d1e1bad29af3790f7b3bdc2)) * ensure ethiopic dates are in the correct era ([34061d9](https://github.com/dhis2/multi-calendar-dates/commit/34061d9c7d54f8343ede4f65c723b7ce03c57ef8)) * handle on-the-fly changes to selected calendar ([89f0427](https://github.com/dhis2/multi-calendar-dates/commit/89f04278aba25b131cbf57fe21809abd1a3fec9e)) * update useDatePicker to accept the calendar date rather than the iso one ([a65fc3d](https://github.com/dhis2/multi-calendar-dates/commit/a65fc3db33321c737c873bb5ef972f1e4a698da3)) --- CHANGELOG.md | 10 ++++++++++ package.json | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74b63f0..94a3e21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# [1.0.0-beta.22](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.0-beta.21...v1.0.0-beta.22) (2023-02-15) + + +### Bug Fixes + +* change build process to emit cjs and es modules ([#10](https://github.com/dhis2/multi-calendar-dates/issues/10)) ([1102de8](https://github.com/dhis2/multi-calendar-dates/commit/1102de87fd99006e1d1e1bad29af3790f7b3bdc2)) +* ensure ethiopic dates are in the correct era ([34061d9](https://github.com/dhis2/multi-calendar-dates/commit/34061d9c7d54f8343ede4f65c723b7ce03c57ef8)) +* handle on-the-fly changes to selected calendar ([89f0427](https://github.com/dhis2/multi-calendar-dates/commit/89f04278aba25b131cbf57fe21809abd1a3fec9e)) +* update useDatePicker to accept the calendar date rather than the iso one ([a65fc3d](https://github.com/dhis2/multi-calendar-dates/commit/a65fc3db33321c737c873bb5ef972f1e4a698da3)) + # [1.0.0-alpha.18](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.0-alpha.17...v1.0.0-alpha.18) (2023-02-14) diff --git a/package.json b/package.json index 35d99c9..0a67ec1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/multi-calendar-dates", - "version": "1.0.0-alpha.18", + "version": "1.0.0-beta.22", "license": "BSD-3-Clause", "publishConfig": { "access": "public" From ffa509ac462d0be44ca58cb2958592d26b19c416 Mon Sep 17 00:00:00 2001 From: mozafar Date: Wed, 15 Feb 2023 23:17:57 +0000 Subject: [PATCH 02/15] fix: update useDatePicker hook to resolve options with hook --- .../internal/useResolvedLocaleOptions.spec.ts | 212 ++++++++++++++++++ .../internal/useResolvedLocaleOptions.ts | 67 ++++++ src/hooks/useDatePicker.spec.tsx | 64 +++++- src/hooks/useDatePicker.ts | 46 ++-- src/utils/getValidLocale.ts | 25 +++ src/utils/localisationHelpers.ts | 4 +- 6 files changed, 390 insertions(+), 28 deletions(-) create mode 100644 src/hooks/internal/useResolvedLocaleOptions.spec.ts create mode 100644 src/hooks/internal/useResolvedLocaleOptions.ts create mode 100644 src/utils/getValidLocale.ts diff --git a/src/hooks/internal/useResolvedLocaleOptions.spec.ts b/src/hooks/internal/useResolvedLocaleOptions.spec.ts new file mode 100644 index 0000000..0c094bd --- /dev/null +++ b/src/hooks/internal/useResolvedLocaleOptions.spec.ts @@ -0,0 +1,212 @@ +import { Intl } from '@js-temporal/polyfill' +import { renderHook } from '@testing-library/react-hooks' +import getValidLocale from '../../utils/getValidLocale' +import { LocaleOptions } from '../useDatePicker' +import { useResolvedLocaleOptions } from './useResolvedLocaleOptions' + +jest.mock('@js-temporal/polyfill') +jest.mock('../../utils/getValidLocale') + +const renderResolvedLocaleHook = ({ + locale, + calendar, + timeZone, + numberingSystem, + weekDayFormat, +}: LocaleOptions) => { + const options = { + locale, + calendar, + numberingSystem, + timeZone, + weekDayFormat: weekDayFormat, + } + const { result } = renderHook(() => useResolvedLocaleOptions(options)) + return result.current +} + +describe('useResolvedLocaleOptions', () => { + const mockResolvedOptions = ({ + locale: mockLocale, + calendar, + numberingSystem, + timeZone, + }: Omit & { + calendar?: string + }) => { + jest.spyOn(Intl, 'DateTimeFormat').mockImplementation( + (locale, options) => + ({ + resolvedOptions: () => { + // when calling without options, i.e. Intl?.DateTimeFormat?.().resolvedOptions?.() + // we return system info + if (!locale) { + return { + locale: mockLocale, + calendar, + numberingSystem: numberingSystem, + timeZone: timeZone, + } + } else { + // otherwise it should return what was passed to it (provided it is valid) + return { + locale, + ...options, + } + } + }, + } as Intl.DateTimeFormat) + ) + } + + beforeEach(() => { + const mock = getValidLocale as jest.Mock + mock.mockImplementation((value) => value) + }) + afterEach(jest.clearAllMocks) + + describe('resolving locale', () => { + it('should return the passed locale if provided', () => { + mockResolvedOptions({ locale: 'fr-FR' }) + const overriddenLocale = 'es' + const result = renderResolvedLocaleHook({ + locale: overriddenLocale, + calendar: 'gregory', + numberingSystem: 'arab', + }) + expect(result.locale).toEqual(overriddenLocale) + }) + + it('should fall back to system locale otherwise', () => { + mockResolvedOptions({ locale: 'fr-FR' }) + const result = renderResolvedLocaleHook({ + calendar: 'gregory', + numberingSystem: 'arab', + }) + expect(result.locale).toEqual('fr-FR') + }) + + it('should fall back to hardcoded value when all fails', () => { + mockResolvedOptions({ locale: undefined }) + + const result = renderResolvedLocaleHook({ + calendar: 'gregory', + numberingSystem: 'arab', + }) + expect(result.locale).toEqual('en') + }) + + describe('when bad locale passed', () => { + beforeEach(() => { + const mock = getValidLocale as jest.Mock + mock.mockReturnValue(undefined) + }) + it('should return user locale', () => { + mockResolvedOptions({ locale: 'fr' }) + const result = renderResolvedLocaleHook({ + locale: 'xx-invalidlocale', + calendar: 'gregory', + numberingSystem: 'arab', + }) + expect(result.locale).toEqual('fr') + }) + it('should return hardcoded values if user locale not found (which should not really happen but being super-defensive!)', () => { + mockResolvedOptions({ locale: undefined }) + const result = renderResolvedLocaleHook({ + locale: 'xx-invalidlocale', + calendar: 'gregory', + numberingSystem: 'arab', + }) + expect(result.locale).toEqual('en') + }) + }) + }) + + describe('resolving numbering system', () => { + it('should return the passed locale if provided', () => { + mockResolvedOptions({ numberingSystem: 'hebr' }) + const result = renderResolvedLocaleHook({ + locale: 'en', + calendar: 'gregory', + numberingSystem: 'arab', + }) + expect(result.numberingSystem).toEqual('arab') + }) + + it('should fall back to system numbering system otherwise', () => { + mockResolvedOptions({ numberingSystem: 'hebr' }) + const result = renderResolvedLocaleHook({ + locale: 'en', + calendar: 'gregory', + }) + expect(result.numberingSystem).toEqual('hebr') + }) + + it('should fall back to hardcoded value when all fails', () => { + mockResolvedOptions({ numberingSystem: undefined }) + const result = renderResolvedLocaleHook({ + locale: 'en', + calendar: 'gregory', + }) + expect(result.numberingSystem).toEqual('latn') + }) + }) + + describe('resolving timeZone', () => { + it('should return the passed timeZone if provided', () => { + mockResolvedOptions({ timeZone: 'america/somewhere' }) + const result = renderResolvedLocaleHook({ + locale: 'en', + calendar: 'gregory', + numberingSystem: 'arab', + timeZone: 'africa', + }) + expect(result.timeZone).toEqual('africa') + }) + + it('should fall back to system timeZone if no value passed', () => { + mockResolvedOptions({ timeZone: 'america/somewhere' }) + const result = renderResolvedLocaleHook({ + locale: 'en', + calendar: 'gregory', + numberingSystem: 'arab', + // no timeZone + }) + expect(result.timeZone).toEqual('america/somewhere') + }) + + it('should fall back to UTC if all fails (we should not reach this state in reality because there is always a system timezone)', () => { + mockResolvedOptions({ timeZone: undefined }) + const result = renderResolvedLocaleHook({ + locale: 'en', + calendar: 'gregory', + numberingSystem: 'arab', + // no timeZone + }) + expect(result.timeZone).toEqual('UTC') + }) + }) + + describe('resolving weekDayFormat', () => { + it('should return the passed weekDayFormat if provided', () => { + mockResolvedOptions({}) + const result = renderResolvedLocaleHook({ + locale: 'en', + calendar: 'gregory', + numberingSystem: 'arab', + weekDayFormat: 'short', + }) + expect(result.weekDayFormat).toEqual('short') + }) + + it('should fall back to hardcoded value if nothing passed', () => { + mockResolvedOptions({}) + const result = renderResolvedLocaleHook({ + locale: 'en', + calendar: 'gregory', + numberingSystem: 'arab', + }) + expect(result.weekDayFormat).toEqual('narrow') + }) + }) +}) diff --git a/src/hooks/internal/useResolvedLocaleOptions.ts b/src/hooks/internal/useResolvedLocaleOptions.ts new file mode 100644 index 0000000..64d5247 --- /dev/null +++ b/src/hooks/internal/useResolvedLocaleOptions.ts @@ -0,0 +1,67 @@ +import { Intl } from '@js-temporal/polyfill' +import { useMemo } from 'react' +import getValidLocale from '../../utils/getValidLocale' +import { LocaleOptions } from '../useDatePicker' + +type UseResolvedLocaleOptionsHook = ( + options: LocaleOptions +) => LocaleOptions & { locale: string } + +/** + * A hook that returns the locale and locale options to be used by the calendar. + * + * The order of precedence of how the options are resolved should be: + * + * - Prop-values passed to the hook/component + * - Properties available from the system/user settings resource* (in the future) + * - Values coming from Intl.DateTimeFormat().resolvedOptions() + * - Some hardcoded defaults + * + * @param options + * @returns + */ +export const useResolvedLocaleOptions: UseResolvedLocaleOptionsHook = ( + userOptions +) => { + // validate that the passed locale is valid, use it if valid, otherwise, keep it undefined + const locale = getValidLocale(userOptions.locale) + + const defaultDateTimeOptions = Intl?.DateTimeFormat?.().resolvedOptions?.() + + const defaultUserOptions = useMemo( + () => ({ + timeZone: defaultDateTimeOptions.timeZone || 'UTC', + numberingSystem: defaultDateTimeOptions.numberingSystem || 'latn', + locale: defaultDateTimeOptions.locale || 'en', + weekDayFormat: 'narrow' as const, // resolvedOptions seems to not return a value in all major browsers + }), + [defaultDateTimeOptions] + ) + + return useMemo(() => { + /** + * If no options are provided this will use the values of the user browser + * If a locale identifier is provided it will use that to populate options + * If any options are provided these will override the options for the + * specified locale identifier or browser settings + */ + const { locale: resolvedLocale, ...resolvedOptions } = + new Intl.DateTimeFormat(locale, { + calendar: userOptions.calendar, + timeZone: userOptions.timeZone as string, + numberingSystem: userOptions.numberingSystem, + weekday: userOptions.weekDayFormat, + }).resolvedOptions() + + return { + calendar: userOptions.calendar, + locale: resolvedLocale || defaultUserOptions.locale, + timeZone: resolvedOptions.timeZone || defaultUserOptions.timeZone, + numberingSystem: + resolvedOptions.numberingSystem || + defaultUserOptions.numberingSystem, + weekDayFormat: + userOptions.weekDayFormat || defaultUserOptions.weekDayFormat, + } + }, [defaultUserOptions, locale, userOptions]) +} diff --git a/src/hooks/useDatePicker.spec.tsx b/src/hooks/useDatePicker.spec.tsx index fd2e029..6b58de8 100644 --- a/src/hooks/useDatePicker.spec.tsx +++ b/src/hooks/useDatePicker.spec.tsx @@ -1,3 +1,4 @@ +import { Intl } from '@js-temporal/polyfill' import { render } from '@testing-library/react' import { renderHook } from '@testing-library/react-hooks' import React from 'react' @@ -5,6 +6,13 @@ import { SupportedCalendar } from '../types' import localisationHelpers from '../utils/localisationHelpers' import { useDatePicker, UseDatePickerReturn } from './useDatePicker' +jest.mock('@js-temporal/polyfill', () => ({ + ...jest.requireActual('@js-temporal/polyfill'), + Intl: { + ...jest.requireActual('@js-temporal/polyfill').Intl, + }, // this is needed, otherwise jest spying fails with " Cannot assign to read only property 'DateTimeFormat'" +})) + const renderCalendar = ( weekDayFormat: 'long' | 'narrow' | 'short', locale: string, @@ -32,7 +40,7 @@ describe('useDatePicker hook', () => { const options = { locale: 'en-GB', timeZone: 'Africa/Khartoum', - // no calendar means it should default to gregory + calendar: 'gregory' as const, } const renderedHook = renderHook(() => useDatePicker({ onDateSelect, date, options }) @@ -491,3 +499,57 @@ describe('changing the calendar on the fly', () => { expect(getByText('Paush')).toBeDefined() }) }) + +describe('default options for hook', () => { + const originalDateTimeFormat = Intl.DateTimeFormat + afterEach(() => { + // eslint-disable-next-line @typescript-eslint/no-extra-semi + ;(Intl.DateTimeFormat as any) = originalDateTimeFormat + }) + + it('should infer default options from system if none passed', () => { + jest.spyOn(Intl, 'DateTimeFormat').mockReturnValue({ + resolvedOptions: () => { + return { + locale: 'ar-SD', + numberingSystem: 'arab', + } + }, + } as Intl.DateTimeFormat) + const onDateSelect = jest.fn() + const date = '2018-01-22' + const options = { + calendar: 'gregory' as const, + weekDayFormat: 'long' as const, + } + const renderedHook = renderHook(() => + useDatePicker({ onDateSelect, date, options }) + ) + + const result = renderedHook?.result?.current as UseDatePickerReturn + expect(result.weekDayLabels).toContain('الاثنين') + expect(result.weekDayLabels).not.toContain('Monday') + expect( + result.calendarWeekDays.flatMap((week) => + week.map((day) => day.label) + ) + ).toContain('١٥') + }) + it('should infer from system if part of the options are passed', () => { + jest.resetModules() + jest.resetAllMocks() + const onDateSelect = jest.fn() + const date = '2018-01-22' + const options = { + calendar: 'gregory' as const, + weekDayFormat: 'long' as const, + locale: 'es-ES', + } + const renderedHook = renderHook(() => + useDatePicker({ onDateSelect, date, options }) + ) + + const result = renderedHook?.result?.current as UseDatePickerReturn + expect(result.weekDayLabels).toContain('lunes') + }) +}) diff --git a/src/hooks/useDatePicker.ts b/src/hooks/useDatePicker.ts index a3b0cf9..0472277 100644 --- a/src/hooks/useDatePicker.ts +++ b/src/hooks/useDatePicker.ts @@ -10,6 +10,7 @@ import { useNavigation, UseNavigationReturnType, } from './internal/useNavigation' +import { useResolvedLocaleOptions } from './internal/useResolvedLocaleOptions' import { useWeekDayLabels } from './internal/useWeekDayLabels' type DatePickerOptions = { @@ -25,8 +26,8 @@ type DatePickerOptions = { } export type LocaleOptions = { - locale: string - calendar?: SupportedCalendar + calendar: SupportedCalendar + locale?: string timeZone?: Temporal.TimeZoneLike numberingSystem?: string weekDayFormat?: 'narrow' | 'short' | 'long' @@ -85,22 +86,28 @@ export const useDatePicker: UseDatePickerHookType = ({ date: dateParts, options, }) => { + const resolvedOptions = useResolvedLocaleOptions(options) const prevDateStringRef = useRef(dateParts) const todayZdt = useMemo( - () => getNowInCalendar(options.calendar, options.timeZone).startOfDay(), - [options] + () => + getNowInCalendar( + resolvedOptions.calendar, + resolvedOptions.timeZone + ).startOfDay(), + [resolvedOptions] ) const date = dateParts - ? (fromDateParts(dateParts, options) as Temporal.YearOrEraAndEraYear & + ? (fromDateParts( + dateParts, + resolvedOptions + ) as Temporal.YearOrEraAndEraYear & Temporal.MonthOrMonthCode & { day: number }) : todayZdt - const { calendar: calendarFromOptions = 'gregory', locale = 'en' } = options - const calendar: Temporal.CalendarLike = getCustomCalendarIfExists( - dhis2CalendarsMap[calendarFromOptions] ?? calendarFromOptions + dhis2CalendarsMap[resolvedOptions.calendar] ?? resolvedOptions.calendar ) const temporalCalendar = useMemo( @@ -108,13 +115,8 @@ export const useDatePicker: UseDatePickerHookType = ({ [calendar] ) const temporalTimeZone = useMemo( - () => - Temporal.TimeZone.from( - options.timeZone || - Intl?.DateTimeFormat?.().resolvedOptions?.()?.timeZone || - 'UTC' - ), - [options] + () => Temporal.TimeZone.from(resolvedOptions.timeZone!), + [resolvedOptions] ) const selectedDateZdt = useMemo( @@ -136,19 +138,13 @@ export const useDatePicker: UseDatePickerHookType = ({ const localeOptions = useMemo( () => ({ - locale, + locale: resolvedOptions.locale, calendar: temporalCalendar as unknown as SupportedCalendar, timeZone: temporalTimeZone, - weekDayFormat: options.weekDayFormat || 'narrow', - numberingSystem: options.numberingSystem, + weekDayFormat: resolvedOptions.weekDayFormat, + numberingSystem: resolvedOptions.numberingSystem, }), - [ - locale, - temporalCalendar, - temporalTimeZone, - options.weekDayFormat, - options.numberingSystem, - ] + [resolvedOptions, temporalCalendar, temporalTimeZone] ) const weekDayLabels = useWeekDayLabels(localeOptions) diff --git a/src/utils/getValidLocale.ts b/src/utils/getValidLocale.ts new file mode 100644 index 0000000..01083f3 --- /dev/null +++ b/src/utils/getValidLocale.ts @@ -0,0 +1,25 @@ +/** + * This method ensures that a locale is valid and supported by browser, and returns it if it is. + * + * It used Intl.DateTimeFormat.supportedLocalesOf to decide whether the locale is valid or not. + * Intl.DateTimeFormat.supportedLocalesOf takes a locale (or a list of locales) and returns: + * - an array with the locale if it's valid + * - an empty array if it's valid but not supported + * - throws an error if it's not valid + * @param locale locale to validate and return + * @returns the locale if it's valid, otherwise undefined + */ +const getValidLocale = (locale = '') => { + try { + const result = Intl.DateTimeFormat.supportedLocalesOf(locale) + if (result && result.length === 1) { + return locale + } else { + return undefined + } + } catch (err) { + return undefined + } +} + +export default getValidLocale diff --git a/src/utils/localisationHelpers.ts b/src/utils/localisationHelpers.ts index 587b089..2b685df 100644 --- a/src/utils/localisationHelpers.ts +++ b/src/utils/localisationHelpers.ts @@ -10,7 +10,7 @@ import { isCustomCalendar } from './helpers' const getCustomCalendarLocale = ( calendar: Temporal.CalendarLike, - locale: string + locale: string | undefined ): CalendarCustomLocale | undefined => { const customCalendar = customCalendars[calendar as CustomCalendarTypes] @@ -19,7 +19,7 @@ const getCustomCalendarLocale = ( } const customLocalisations = customCalendar.locales || {} const result = - customLocalisations?.[locale] ?? + (locale && customLocalisations?.[locale]) ?? customLocalisations?.[customCalendar.defaultLocale] if (!result) { From ad37d53dc22e0a5945417ff857b739147e114085 Mon Sep 17 00:00:00 2001 From: mozafar Date: Thu, 16 Feb 2023 11:56:49 +0000 Subject: [PATCH 03/15] refactor: update fallback logic per code review comments --- src/hooks/internal/useResolvedLocaleOptions.ts | 11 ++++++----- src/hooks/useDatePicker.ts | 4 +++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/hooks/internal/useResolvedLocaleOptions.ts b/src/hooks/internal/useResolvedLocaleOptions.ts index 64d5247..2d81c19 100644 --- a/src/hooks/internal/useResolvedLocaleOptions.ts +++ b/src/hooks/internal/useResolvedLocaleOptions.ts @@ -1,7 +1,7 @@ import { Intl } from '@js-temporal/polyfill' import { useMemo } from 'react' import getValidLocale from '../../utils/getValidLocale' -import { LocaleOptions } from '../useDatePicker' +import { LocaleOptions, WeekDayFormat } from '../useDatePicker' type UseResolvedLocaleOptionsHook = ( options: LocaleOptions @@ -30,10 +30,11 @@ export const useResolvedLocaleOptions: UseResolvedLocaleOptionsHook = ( const defaultUserOptions = useMemo( () => ({ - timeZone: defaultDateTimeOptions.timeZone || 'UTC', - numberingSystem: defaultDateTimeOptions.numberingSystem || 'latn', - locale: defaultDateTimeOptions.locale || 'en', - weekDayFormat: 'narrow' as const, // resolvedOptions seems to not return a value in all major browsers + timeZone: defaultDateTimeOptions?.timeZone ?? 'UTC', + numberingSystem: defaultDateTimeOptions?.numberingSystem ?? 'latn', + locale: defaultDateTimeOptions?.locale ?? 'en', + weekDayFormat: (defaultDateTimeOptions?.weekday ?? + 'narrow') as WeekDayFormat, }), [defaultDateTimeOptions] ) diff --git a/src/hooks/useDatePicker.ts b/src/hooks/useDatePicker.ts index 0472277..f645038 100644 --- a/src/hooks/useDatePicker.ts +++ b/src/hooks/useDatePicker.ts @@ -25,12 +25,14 @@ type DatePickerOptions = { }) => void } +export type WeekDayFormat = 'narrow' | 'short' | 'long' + export type LocaleOptions = { calendar: SupportedCalendar locale?: string timeZone?: Temporal.TimeZoneLike numberingSystem?: string - weekDayFormat?: 'narrow' | 'short' | 'long' + weekDayFormat?: WeekDayFormat } export type UseDatePickerReturn = UseNavigationReturnType & { From 09e4e0762481ff905b6c499baa3f1e4b7fc2a27e Mon Sep 17 00:00:00 2001 From: mozafar Date: Thu, 16 Feb 2023 15:56:45 +0000 Subject: [PATCH 04/15] refactor: make calendar default to gregory --- src/hooks/internal/useNavigation.ts | 4 +- .../internal/useResolvedLocaleOptions.spec.ts | 6 +-- .../internal/useResolvedLocaleOptions.ts | 13 +++-- src/hooks/internal/useWeekDayLabels.ts | 6 +-- src/hooks/useDatePicker.spec.tsx | 51 +++++++++++++++++-- src/hooks/useDatePicker.ts | 16 ++---- src/types.ts | 13 +++++ src/utils/localisationHelpers.ts | 12 ++--- 8 files changed, 87 insertions(+), 34 deletions(-) diff --git a/src/hooks/internal/useNavigation.ts b/src/hooks/internal/useNavigation.ts index 9afc2d5..3eeccd3 100644 --- a/src/hooks/internal/useNavigation.ts +++ b/src/hooks/internal/useNavigation.ts @@ -1,7 +1,7 @@ import { Temporal } from '@js-temporal/polyfill' import { Dispatch, SetStateAction, useMemo } from 'react' +import { PickerOptions } from '../../types' import localisationHelpers from '../../utils/localisationHelpers' -import { LocaleOptions } from '../useDatePicker' export type UseNavigationReturnType = { prevYear: { @@ -30,7 +30,7 @@ export type UseNavigationReturnType = { type UseNavigationHook = ( firstZdtOfVisibleMonth: Temporal.ZonedDateTime, setFirstZdtOfVisibleMonth: Dispatch>, - localeOptions: LocaleOptions + localeOptions: PickerOptions ) => UseNavigationReturnType /** * internal hook used by useDatePicker to build the navigation of the calendar diff --git a/src/hooks/internal/useResolvedLocaleOptions.spec.ts b/src/hooks/internal/useResolvedLocaleOptions.spec.ts index 0c094bd..9ee49a7 100644 --- a/src/hooks/internal/useResolvedLocaleOptions.spec.ts +++ b/src/hooks/internal/useResolvedLocaleOptions.spec.ts @@ -1,7 +1,7 @@ import { Intl } from '@js-temporal/polyfill' import { renderHook } from '@testing-library/react-hooks' +import { PickerOptions } from '../../types' import getValidLocale from '../../utils/getValidLocale' -import { LocaleOptions } from '../useDatePicker' import { useResolvedLocaleOptions } from './useResolvedLocaleOptions' jest.mock('@js-temporal/polyfill') @@ -13,7 +13,7 @@ const renderResolvedLocaleHook = ({ timeZone, numberingSystem, weekDayFormat, -}: LocaleOptions) => { +}: PickerOptions) => { const options = { locale, calendar, @@ -31,7 +31,7 @@ describe('useResolvedLocaleOptions', () => { calendar, numberingSystem, timeZone, - }: Omit & { + }: Omit & { calendar?: string }) => { jest.spyOn(Intl, 'DateTimeFormat').mockImplementation( diff --git a/src/hooks/internal/useResolvedLocaleOptions.ts b/src/hooks/internal/useResolvedLocaleOptions.ts index 2d81c19..53e762a 100644 --- a/src/hooks/internal/useResolvedLocaleOptions.ts +++ b/src/hooks/internal/useResolvedLocaleOptions.ts @@ -1,11 +1,15 @@ import { Intl } from '@js-temporal/polyfill' import { useMemo } from 'react' +import { + PickerOptions, + ResolvedLocaleOptions, + WeekDayFormat, +} from '../../types' import getValidLocale from '../../utils/getValidLocale' -import { LocaleOptions, WeekDayFormat } from '../useDatePicker' type UseResolvedLocaleOptionsHook = ( - options: LocaleOptions -) => LocaleOptions & { locale: string } + options: PickerOptions +) => ResolvedLocaleOptions /** * A hook that returns the locale and locale options to be used by the calendar. @@ -30,6 +34,7 @@ export const useResolvedLocaleOptions: UseResolvedLocaleOptionsHook = ( const defaultUserOptions = useMemo( () => ({ + calendar: 'gregory' as const, timeZone: defaultDateTimeOptions?.timeZone ?? 'UTC', numberingSystem: defaultDateTimeOptions?.numberingSystem ?? 'latn', locale: defaultDateTimeOptions?.locale ?? 'en', @@ -55,7 +60,7 @@ export const useResolvedLocaleOptions: UseResolvedLocaleOptionsHook = ( }).resolvedOptions() return { - calendar: userOptions.calendar, + calendar: userOptions.calendar || defaultUserOptions.calendar, locale: resolvedLocale || defaultUserOptions.locale, timeZone: resolvedOptions.timeZone || defaultUserOptions.timeZone, numberingSystem: diff --git a/src/hooks/internal/useWeekDayLabels.ts b/src/hooks/internal/useWeekDayLabels.ts index 676c0a0..491dd8f 100644 --- a/src/hooks/internal/useWeekDayLabels.ts +++ b/src/hooks/internal/useWeekDayLabels.ts @@ -1,9 +1,9 @@ import { Temporal } from '@js-temporal/polyfill' import { useMemo } from 'react' +import { PickerOptions } from '../../types' import localisationHelpers from '../../utils/localisationHelpers' -import { LocaleOptions } from '../useDatePicker' -export const useWeekDayLabels = (localeOptions: LocaleOptions) => +export const useWeekDayLabels = (localeOptions: PickerOptions) => useMemo(() => { if (!localeOptions.calendar) { throw new Error('a calendar must be provided to useWeekDayLabels') @@ -29,7 +29,7 @@ export const useWeekDayLabels = (localeOptions: LocaleOptions) => const getWeekDayString: ( date: Temporal.ZonedDateTime, - localeOptions: LocaleOptions + localeOptions: PickerOptions ) => string = (date, localeOptions) => { return localisationHelpers.localiseWeekDayLabel(date, localeOptions) } diff --git a/src/hooks/useDatePicker.spec.tsx b/src/hooks/useDatePicker.spec.tsx index 6b58de8..4b3d1f2 100644 --- a/src/hooks/useDatePicker.spec.tsx +++ b/src/hooks/useDatePicker.spec.tsx @@ -6,6 +6,13 @@ import { SupportedCalendar } from '../types' import localisationHelpers from '../utils/localisationHelpers' import { useDatePicker, UseDatePickerReturn } from './useDatePicker' +beforeEach(() => { + // 13 October 2021 UTC + jest.spyOn(Date, 'now').mockReturnValue(1634089600000) +}) + +afterEach(jest.clearAllMocks) + jest.mock('@js-temporal/polyfill', () => ({ ...jest.requireActual('@js-temporal/polyfill'), Intl: { @@ -40,7 +47,7 @@ describe('useDatePicker hook', () => { const options = { locale: 'en-GB', timeZone: 'Africa/Khartoum', - calendar: 'gregory' as const, + // no calendar should default to iso8601 } const renderedHook = renderHook(() => useDatePicker({ onDateSelect, date, options }) @@ -262,6 +269,46 @@ describe('useDatePicker hook', () => { expect(result.prevYear.label).toEqual('٢٠١٧') }) }) + describe('highlighting today', () => { + const getDayByDate: ( + calendarWeekDays: { calendarDate: string; isToday: boolean }[][], + dayToFind: string + ) => { calendarDate: string; isToday: boolean }[] = ( + calendarWeekDays, + dayToFind + ) => { + const days = calendarWeekDays.flatMap((week) => week) + + return days.filter((day) => day.calendarDate === dayToFind) + } + + it('should highlight today date in a an ethiopic calendar', () => { + const date = `2014-02-03` // today mock date in ethiopic + const options = { + calendar: 'ethiopic' as const, + } + const { result } = renderHook(() => + useDatePicker({ onDateSelect: jest.fn(), date, options }) + ) + const matches = getDayByDate(result.current.calendarWeekDays, date) + expect(matches[0]?.isToday).toEqual(true) + expect(matches.length).toEqual(1) + }) + + it('should highlight today date in a a nepali calendar', () => { + const date = `2078-06-27` // today mock date in nepali + const options = { + calendar: 'nepali' as const, + timeZone: 'UTC', + } + const { result } = renderHook(() => + useDatePicker({ onDateSelect: jest.fn(), date, options }) + ) + const matches = getDayByDate(result.current.calendarWeekDays, date) + expect(matches[0]?.isToday).toEqual(true) + expect(matches.length).toEqual(1) + }) + }) }) describe('custom calendars', () => { @@ -536,8 +583,6 @@ describe('default options for hook', () => { ).toContain('١٥') }) it('should infer from system if part of the options are passed', () => { - jest.resetModules() - jest.resetAllMocks() const onDateSelect = jest.fn() const date = '2018-01-22' const options = { diff --git a/src/hooks/useDatePicker.ts b/src/hooks/useDatePicker.ts index f645038..2ef7564 100644 --- a/src/hooks/useDatePicker.ts +++ b/src/hooks/useDatePicker.ts @@ -2,7 +2,7 @@ import { Temporal } from '@js-temporal/polyfill' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { dhis2CalendarsMap } from '../constants/dhis2CalendarsMap' import { getNowInCalendar } from '../index' -import { SupportedCalendar } from '../types' +import { PickerOptions, SupportedCalendar } from '../types' import { formatYyyyMmDD, getCustomCalendarIfExists } from '../utils/helpers' import localisationHelpers from '../utils/localisationHelpers' import { useCalendarWeekDays } from './internal/useCalendarWeekDays' @@ -15,7 +15,7 @@ import { useWeekDayLabels } from './internal/useWeekDayLabels' type DatePickerOptions = { date: string - options: LocaleOptions + options: PickerOptions onDateSelect: ({ calendarDate, calendarDateString, @@ -25,16 +25,6 @@ type DatePickerOptions = { }) => void } -export type WeekDayFormat = 'narrow' | 'short' | 'long' - -export type LocaleOptions = { - calendar: SupportedCalendar - locale?: string - timeZone?: Temporal.TimeZoneLike - numberingSystem?: string - weekDayFormat?: WeekDayFormat -} - export type UseDatePickerReturn = UseNavigationReturnType & { weekDayLabels: string[] calendarWeekDays: { @@ -50,7 +40,7 @@ export type UseDatePickerReturn = UseNavigationReturnType & { type UseDatePickerHookType = (options: DatePickerOptions) => UseDatePickerReturn -const fromDateParts = (date: string, options: LocaleOptions) => { +const fromDateParts = (date: string, options: PickerOptions) => { let result: Temporal.PlainDateLike try { diff --git a/src/types.ts b/src/types.ts index 334a915..148f5f0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,18 @@ +import { Temporal } from '@js-temporal/polyfill' import { calendars } from './constants/calendars' import { numberingSystems } from './constants/numberingSystems' export type SupportedCalendar = typeof calendars[number] export type SupportedNumberingSystem = typeof numberingSystems[number] + +export type WeekDayFormat = 'narrow' | 'short' | 'long' + +export type PickerOptions = Partial + +export type ResolvedLocaleOptions = { + calendar: SupportedCalendar + locale: string + timeZone: Temporal.TimeZoneLike + numberingSystem: string + weekDayFormat: WeekDayFormat +} diff --git a/src/utils/localisationHelpers.ts b/src/utils/localisationHelpers.ts index 2b685df..43dfa00 100644 --- a/src/utils/localisationHelpers.ts +++ b/src/utils/localisationHelpers.ts @@ -5,7 +5,7 @@ import { customCalendars, CustomCalendarTypes, } from '../custom-calendars' -import { LocaleOptions } from '../hooks/useDatePicker' +import { PickerOptions } from '../types' import { isCustomCalendar } from './helpers' const getCustomCalendarLocale = ( @@ -32,7 +32,7 @@ const getCustomCalendarLocale = ( const localiseDateLabel = ( selectedDateZdt: Temporal.ZonedDateTime | null, - localeOptions: LocaleOptions + localeOptions: PickerOptions ) => { if (!localeOptions.calendar) { throw new Error('no calendar provided to localise function') @@ -56,7 +56,7 @@ const localiseDateLabel = ( const localiseWeekLabel = ( zdt: Temporal.ZonedDateTime, - localeOptions: LocaleOptions + localeOptions: PickerOptions ) => { if (!localeOptions.calendar) { throw new Error('no calendar provided to localise function') @@ -82,7 +82,7 @@ const localiseWeekLabel = ( const localiseMonth = ( zdt: Temporal.ZonedDateTime | Temporal.PlainYearMonth | Temporal.PlainDate, - localeOptions: LocaleOptions, + localeOptions: PickerOptions, format: Intl.DateTimeFormatOptions ) => { if (!localeOptions.calendar) { @@ -101,7 +101,7 @@ const localiseMonth = ( export const localiseWeekDayLabel = ( zdt: Temporal.ZonedDateTime, - localeOptions: LocaleOptions + localeOptions: PickerOptions ) => { if (!localeOptions.calendar) { throw new Error('no calendar provided to localise function') @@ -124,7 +124,7 @@ export const localiseWeekDayLabel = ( export const localiseYear = ( zdt: Temporal.ZonedDateTime, - localeOptions: LocaleOptions, + localeOptions: PickerOptions, format: Intl.DateTimeFormatOptions ) => { if (!localeOptions.calendar) { From 98570f3e83e0cb4edf2af2b687516f04a4fd3fcd Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Fri, 17 Feb 2023 18:00:45 +0000 Subject: [PATCH 05/15] chore(release): cut 1.0.0-beta.23 [skip ci] # [1.0.0-beta.23](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.0-beta.22...v1.0.0-beta.23) (2023-02-17) ### Bug Fixes * update useDatePicker hook to resolve options with hook ([ffa509a](https://github.com/dhis2/multi-calendar-dates/commit/ffa509ac462d0be44ca58cb2958592d26b19c416)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94a3e21..ac38de0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.0.0-beta.23](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.0-beta.22...v1.0.0-beta.23) (2023-02-17) + + +### Bug Fixes + +* update useDatePicker hook to resolve options with hook ([ffa509a](https://github.com/dhis2/multi-calendar-dates/commit/ffa509ac462d0be44ca58cb2958592d26b19c416)) + # [1.0.0-beta.22](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.0-beta.21...v1.0.0-beta.22) (2023-02-15) diff --git a/package.json b/package.json index 0a67ec1..5abb13d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/multi-calendar-dates", - "version": "1.0.0-beta.22", + "version": "1.0.0-beta.23", "license": "BSD-3-Clause", "publishConfig": { "access": "public" From 668f6d8a3e881926a192c6065aa82cea473150e1 Mon Sep 17 00:00:00 2001 From: mozafar Date: Mon, 20 Feb 2023 14:10:01 +0000 Subject: [PATCH 06/15] fix: update localisation logic for fixed period generation --- .../fixed-periods.gregorian.spec.ts | 126 ++++++++++++++++++ src/period-calculation/fixed-periods.ts | 5 +- src/period-calculation/getMonthlyPeriods.ts | 17 ++- src/utils/getValidLocale.ts | 5 +- src/utils/helpers.ts | 8 +- 5 files changed, 152 insertions(+), 9 deletions(-) diff --git a/src/period-calculation/fixed-periods.gregorian.spec.ts b/src/period-calculation/fixed-periods.gregorian.spec.ts index 03db49a..790f227 100644 --- a/src/period-calculation/fixed-periods.gregorian.spec.ts +++ b/src/period-calculation/fixed-periods.gregorian.spec.ts @@ -209,4 +209,130 @@ describe('Gregorian Calendar fixed period calculation', () => { expect(periods[periods.length - 1]).toEqual('2015-11-01/2015-12-31') }) }) + + describe('localising the periods', () => { + const date = { + year: 2015, + calendar: 'gregory' as const, + startingDay: 1, + periodType: 'MONTHLY' as const, + } + it('should accept a locale without a region specifier', () => { + const periods = generateFixedPeriods({ + ...date, + locale: 'fr', + }) + expect(periods[0].name).toEqual('Janvier 2015') + }) + + it('should accept a locale with a region specifier', () => { + const colombianSpanishperiods = generateFixedPeriods({ + ...date, + locale: 'es-CO', + }) + const genericSpanishPeriods = generateFixedPeriods({ + ...date, + locale: 'es', + }) + expect(colombianSpanishperiods[0].name).toEqual('Enero de 2015') + expect(genericSpanishPeriods[0].name).toEqual('Enero de 2015') + }) + it('should accept a locale if it uses underscore instead of dash as DHIS does', () => { + const periods = generateFixedPeriods({ + ...date, + locale: 'ar_TN', // DHIS sends underscore instead of hyphen + }) + + expect(periods[0].name).toEqual('جانفي 2015') + }) + it('should fallback to english if a wrong locale is passed', () => { + const periods = generateFixedPeriods({ + ...date, + locale: 'xx_YY', + }) + + expect(periods[0].name).toEqual('January 2015') + }) + it('should fallback to english if a no locale is passed', () => { + const periods = generateFixedPeriods({ + ...date, + locale: undefined, + }) + + expect(periods[0].name).toEqual('January 2015') + }) + }) + + describe('capitalising first letter (when the language allows it)', () => { + const date = { + year: 2015, + calendar: 'gregory' as const, + startingDay: 1, + periodType: 'MONTHLY' as const, + } + it('should capitalise the first letter of a month', () => { + const frenchPeriods = generateFixedPeriods({ + ...date, + locale: 'fr', + }) + const englishPeriods = generateFixedPeriods({ + ...date, + locale: 'en', + }) + const arabicPeriods = generateFixedPeriods({ + ...date, + locale: 'ar-SD', // no capitals in Arabic + }) + expect(englishPeriods[0].name).toEqual('January 2015') + expect(frenchPeriods[0].name).toEqual('Janvier 2015') + expect(arabicPeriods[0].name).toEqual('يناير ٢٠١٥') + }) + + it('should capitalise the first letter of a SIXMONTHLY periods', () => { + const date = { + year: 2015, + calendar: 'gregory' as const, + startingDay: 1, + periodType: 'SIXMONTHLY' as const, + } + const frenchPeriods = generateFixedPeriods({ + ...date, + locale: 'fr', + }) + const englishPeriods = generateFixedPeriods({ + ...date, + locale: 'en', + }) + const arabicPeriods = generateFixedPeriods({ + ...date, + locale: 'ar-SD', // no capitals in Arabic + }) + expect(englishPeriods[0].name).toEqual('January - June 2015') + expect(frenchPeriods[0].name).toEqual('Janvier - Juin 2015') + expect(arabicPeriods[0].name).toEqual('يناير - يونيو ٢٠١٥') + }) + it('should capitalise the first letter of a QUARTERLY periods', () => { + const date = { + year: 2015, + calendar: 'gregory' as const, + startingDay: 1, + periodType: 'QUARTERLY' as const, + } + const frenchPeriods = generateFixedPeriods({ + ...date, + locale: 'fr', + }) + const englishPeriods = generateFixedPeriods({ + ...date, + locale: 'en', + }) + const arabicPeriods = generateFixedPeriods({ + ...date, + locale: 'ar-SD', // no capitals in Arabic + }) + expect(englishPeriods[0].name).toEqual('January - March 2015') + expect(frenchPeriods[0].name).toEqual('Janvier - Mars 2015') + expect(arabicPeriods[0].name).toEqual('يناير - مارس ٢٠١٥') + }) + }) }) diff --git a/src/period-calculation/fixed-periods.ts b/src/period-calculation/fixed-periods.ts index 1ad896e..b79dec2 100644 --- a/src/period-calculation/fixed-periods.ts +++ b/src/period-calculation/fixed-periods.ts @@ -1,5 +1,6 @@ import { dhis2CalendarsMap } from '../constants/dhis2CalendarsMap' import { SupportedCalendar } from '../types' +import getValidLocale from '../utils/getValidLocale' import { getCustomCalendarIfExists } from '../utils/helpers' import { getDailyPeriods } from './getDailyPeriods' import { getMonthlyPeriods } from './getMonthlyPeriods' @@ -52,7 +53,7 @@ const generateFixedPeriods: GeneratedPeriodsFunc = ({ year: yearString, periodType, calendar: requestedCalendar, - locale = 'en', + locale: requestedLocale = 'en', startingDay = 1, }) => { let year: number @@ -69,6 +70,8 @@ const generateFixedPeriods: GeneratedPeriodsFunc = ({ dhis2CalendarsMap[requestedCalendar] ?? requestedCalendar ) as SupportedCalendar + const locale = getValidLocale(requestedLocale) + if (periodType?.match('WEEKLY')) { return getWeeklyPeriods({ year, diff --git a/src/period-calculation/getMonthlyPeriods.ts b/src/period-calculation/getMonthlyPeriods.ts index aeca933..6558f6b 100644 --- a/src/period-calculation/getMonthlyPeriods.ts +++ b/src/period-calculation/getMonthlyPeriods.ts @@ -1,6 +1,7 @@ import { Temporal } from '@js-temporal/polyfill' import { SupportedCalendar } from '../types' import { + capitalize, formatYyyyMmDD, isCustomCalendar, padWithZeroes, @@ -134,12 +135,18 @@ const buildLabel: BuildLabelFunc = (options) => { ) { const format = month.year === nextMonth.year ? monthOnlyFormat : withYearFormat - result = `${month.toLocaleString( - locale, - format - )} - ${nextMonth.toLocaleString(locale, withYearFormat)}` + result = `${capitalize( + month.toLocaleString(locale, format), + locale + )} - ${capitalize( + nextMonth.toLocaleString(locale, withYearFormat), + locale + )}` } else { - result = `${month.toLocaleString(locale, withYearFormat)}` + result = `${capitalize( + month.toLocaleString(locale, withYearFormat), + locale + )}` } // needed for ethiopic calendar - the default formatter adds the era, which is not what we want in DHIS2 diff --git a/src/utils/getValidLocale.ts b/src/utils/getValidLocale.ts index 01083f3..facee18 100644 --- a/src/utils/getValidLocale.ts +++ b/src/utils/getValidLocale.ts @@ -9,7 +9,10 @@ * @param locale locale to validate and return * @returns the locale if it's valid, otherwise undefined */ -const getValidLocale = (locale = '') => { +const getValidLocale = (requestedLocale = '') => { + // this "replace" is to cater for DHIS2 locales using underscore as Java allows both hyphens and underscores + // while JavaScript expects a hyphen (which is the correct way according to RFC-5646 that both rely on) + const locale = requestedLocale.replace('_', '-') try { const result = Intl.DateTimeFormat.supportedLocalesOf(locale) if (result && result.length === 1) { diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index 3a0733a..e08f673 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -28,8 +28,12 @@ export const formatYyyyMmDD = ( return `${year}-${month}-${dayString}` } -export const capitalize = (string: string) => - string.charAt(0).toUpperCase() + string.slice(1).toLowerCase() +// capitalize method taking into account locales that have different way of lower/upper case +// based on https://stackoverflow.com/a/53930826 +export const capitalize = ( + [firstLetter = '', ...rest]: string, + locale = 'en' +) => [firstLetter.toLocaleUpperCase(locale), ...rest].join('') export const getCustomCalendarIfExists = ( calendar: Temporal.CalendarLike From 897242cc39b2239f71d7aae93f6dc39b563a8ef4 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Wed, 22 Feb 2023 12:50:54 +0000 Subject: [PATCH 07/15] chore(release): cut 1.0.0-beta.24 [skip ci] # [1.0.0-beta.24](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.0-beta.23...v1.0.0-beta.24) (2023-02-22) ### Bug Fixes * update localisation logic for fixed period generation ([668f6d8](https://github.com/dhis2/multi-calendar-dates/commit/668f6d8a3e881926a192c6065aa82cea473150e1)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac38de0..50acd76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [1.0.0-beta.24](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.0-beta.23...v1.0.0-beta.24) (2023-02-22) + + +### Bug Fixes + +* update localisation logic for fixed period generation ([668f6d8](https://github.com/dhis2/multi-calendar-dates/commit/668f6d8a3e881926a192c6065aa82cea473150e1)) + # [1.0.0-beta.23](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.0-beta.22...v1.0.0-beta.23) (2023-02-17) diff --git a/package.json b/package.json index 5abb13d..8d6e048 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/multi-calendar-dates", - "version": "1.0.0-beta.23", + "version": "1.0.0-beta.24", "license": "BSD-3-Clause", "publishConfig": { "access": "public" From 9e1157d776d3b85413cb355e36d6403629a62773 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Thu, 23 Feb 2023 08:17:47 +0000 Subject: [PATCH 08/15] chore(release): cut 1.0.0 [skip ci] # 1.0.0 (2023-02-23) ### Bug Fixes * add eraYear to nepali calendar ([c725d96](https://github.com/dhis2/multi-calendar-dates/commit/c725d96b0613c58567e1193e542d5f5eff58041c)) * change build process to emit cjs and es modules ([#10](https://github.com/dhis2/multi-calendar-dates/issues/10)) ([1102de8](https://github.com/dhis2/multi-calendar-dates/commit/1102de87fd99006e1d1e1bad29af3790f7b3bdc2)) * change english-nepal code to en-NP (not ne-EN) ([7e92aa4](https://github.com/dhis2/multi-calendar-dates/commit/7e92aa4efe7302aca3ad52ebd98d49a52141c15b)) * change getNowInCalendar to default to user timezone rather than utc ([03caf6d](https://github.com/dhis2/multi-calendar-dates/commit/03caf6d4a8c0b83924cf47e0aacecb7987168d80)) * change param for useDatePicker from initialDate to date ([429b2eb](https://github.com/dhis2/multi-calendar-dates/commit/429b2ebb660dfbaf77de9f1748dfa7e7fc0472ea)) * change react dependency to fix issue with docusaurus build ([c58d560](https://github.com/dhis2/multi-calendar-dates/commit/c58d5603f1d30667bcdf241c8a3b02cd06fffdb9)) * change react to be a peer dependency ([fbf106c](https://github.com/dhis2/multi-calendar-dates/commit/fbf106cab1ed0dad52d0877c2b61fb3bd6c2540d)) * change the api for nepali calendar to accept a string ([3a51a6f](https://github.com/dhis2/multi-calendar-dates/commit/3a51a6f6b8a48649c0588b0f7421529c3ce64eb0)) * change useWeekDayLabels to accept a custom format for day names ([0369006](https://github.com/dhis2/multi-calendar-dates/commit/036900694aad88ed88f9b8242c537f9e01847b40)) * default to user timezone or UTC if no timezone passed ([e9c34e1](https://github.com/dhis2/multi-calendar-dates/commit/e9c34e14e0c3f6a7ab59ba7ecdf74959ddf0cc95)) * ensure ethiopic dates are in the correct era ([34061d9](https://github.com/dhis2/multi-calendar-dates/commit/34061d9c7d54f8343ede4f65c723b7ce03c57ef8)) * ensure that direction is either rtl or ltr ([4a92e91](https://github.com/dhis2/multi-calendar-dates/commit/4a92e91b979c4791613f50ca88c1a4d72a45e9c3)) * fallback to default locale if passed a wrong locale ([785a1b9](https://github.com/dhis2/multi-calendar-dates/commit/785a1b94c134b0ff42613b71d673505816186cbd)) * fix period generation for Nepali ([157e6a7](https://github.com/dhis2/multi-calendar-dates/commit/157e6a7812ab7480f190413c60a66f4bb86f68c0)) * force a publish ([feec6c2](https://github.com/dhis2/multi-calendar-dates/commit/feec6c28fd7b49febaa6a8ed98a6fe92979a6704)) * force a unpublish for alpha channel ([c4bcb20](https://github.com/dhis2/multi-calendar-dates/commit/c4bcb20d03150909ea12d4ba596b3b0d0c390162)) * force npm publish ([571584c](https://github.com/dhis2/multi-calendar-dates/commit/571584c93e1a6fa9e8b0a02ad12cc8037e0f7c65)) * force npm publish ([f57733e](https://github.com/dhis2/multi-calendar-dates/commit/f57733eee2ba3c1421f3cab7bf4d179fffa4997f)) * force npm publish ([bacacf2](https://github.com/dhis2/multi-calendar-dates/commit/bacacf26327e1b36f0fed21859b67e7d87cfe7da)) * force npm publish ([ac2ab35](https://github.com/dhis2/multi-calendar-dates/commit/ac2ab35d7e976e82aa5f780e8b769b6e6e654e1a)) * force npm publish ([8021a97](https://github.com/dhis2/multi-calendar-dates/commit/8021a9739e85ee6bfc78c100acde66c5b78a7181)) * force npm publish ([d22e470](https://github.com/dhis2/multi-calendar-dates/commit/d22e4700511505fd699b0f1d1814064f885af8b5)) * force npm publish ([e5cb2ff](https://github.com/dhis2/multi-calendar-dates/commit/e5cb2ff91b9f72dd842af044aff64b8f5351554a)) * force npm publish ([39bd827](https://github.com/dhis2/multi-calendar-dates/commit/39bd827b7ff6a65cfb7e831b55dc8ded2716d509)) * force npm publish ([6f95463](https://github.com/dhis2/multi-calendar-dates/commit/6f95463988925465e09e90538b18f04ad1d09daf)) * force npm publish ([6b7fbf3](https://github.com/dhis2/multi-calendar-dates/commit/6b7fbf3227e1254b7fe651c49d118a258470a9f4)) * force npm publish ([2ce77b3](https://github.com/dhis2/multi-calendar-dates/commit/2ce77b3e920788b955dc243570e9b4816a3200db)) * force npm publish ([3e43ce4](https://github.com/dhis2/multi-calendar-dates/commit/3e43ce4592bd907ee0936ee81bc02949010ae50e)) * force publish to @dhis2/multi-calendar-dates ([0bc26f1](https://github.com/dhis2/multi-calendar-dates/commit/0bc26f15f8165febc3e60883bc1e6bde7fb0226b)) * handle on-the-fly changes to selected calendar ([89f0427](https://github.com/dhis2/multi-calendar-dates/commit/89f04278aba25b131cbf57fe21809abd1a3fec9e)) * make nepali calendar default to en-NP if no valid locale provided ([a074789](https://github.com/dhis2/multi-calendar-dates/commit/a074789125840bb349f581a4a70e0cf2b6dc928f)) * make sure period calculation works with non-standard dhis2 calendar IDs ([7c56b1a](https://github.com/dhis2/multi-calendar-dates/commit/7c56b1a219e95dce7b781a3642e5b486d028ab7c)) * put pack semantic-release config ([4ae3f4c](https://github.com/dhis2/multi-calendar-dates/commit/4ae3f4cf848a7c736b12809a2bc4cb1f41f8ad11)) * remove .only for tests ([72fa7e5](https://github.com/dhis2/multi-calendar-dates/commit/72fa7e5c34cf0ec4e9a2f2ccfd7e705c480d1257)) * remove .only from test ([c685e34](https://github.com/dhis2/multi-calendar-dates/commit/c685e3496ffc8a46155d8564327570ddfd1efc7d)) * remove test unpublish alpha ([f815e31](https://github.com/dhis2/multi-calendar-dates/commit/f815e310538e22133c88fb20aea3928bc83de3ab)) * respect startingDay for weekly period generation ([5f1196a](https://github.com/dhis2/multi-calendar-dates/commit/5f1196aff2bad6b77bdaa5fdd52b38bf720eea0b)) * test npm publish ([40de24f](https://github.com/dhis2/multi-calendar-dates/commit/40de24f05a0e3d8277c0d3f39e7295d0dbf11f23)) * test npm publish ([69eb402](https://github.com/dhis2/multi-calendar-dates/commit/69eb4026e06340c2a7e6f34e77da9e8e5a7887d4)) * throw error if non-supported locale is passed for a custom calendar ([293db88](https://github.com/dhis2/multi-calendar-dates/commit/293db88269a079d4b3977859d5f7c62a661fa0f7)) * update current day selection logic to use same calendar system ([adb0dc8](https://github.com/dhis2/multi-calendar-dates/commit/adb0dc8541cd995192441339e7c36ccf49977a07)) * update label for financial year periods ([c13a829](https://github.com/dhis2/multi-calendar-dates/commit/c13a829c8e6f11313f6ab3a6e8ec89e31d902efd)) * update labels for Financial Year period types ([f6c9b68](https://github.com/dhis2/multi-calendar-dates/commit/f6c9b68d2a15cfc1b6a2322b98524324cb319329)) * update localisation logic for fixed period generation ([668f6d8](https://github.com/dhis2/multi-calendar-dates/commit/668f6d8a3e881926a192c6065aa82cea473150e1)) * update useDatePicker hook to resolve options with hook ([ffa509a](https://github.com/dhis2/multi-calendar-dates/commit/ffa509ac462d0be44ca58cb2958592d26b19c416)) * update useDatePicker to accept the calendar date rather than the iso one ([a65fc3d](https://github.com/dhis2/multi-calendar-dates/commit/a65fc3db33321c737c873bb5ef972f1e4a698da3)) * update weekly period logic to match analytics tests ([2faf567](https://github.com/dhis2/multi-calendar-dates/commit/2faf567adcb5705d35f4d3d5930fb03aa7b343ef)) * use numberinSystem if provided ([b3e82fb](https://github.com/dhis2/multi-calendar-dates/commit/b3e82fba160839beeafdc78f77f601d05e48f345)) ### Features * expose a method to return today date in specific calendar ([1213b45](https://github.com/dhis2/multi-calendar-dates/commit/1213b453a71f4eef5393cd72f2204e7deea2b998)) * implement first iteration of the engine ([51526db](https://github.com/dhis2/multi-calendar-dates/commit/51526dbc08342c3ccaf59871f251af37aaf0b290)) * implement nepali calendar ([bcb66c6](https://github.com/dhis2/multi-calendar-dates/commit/bcb66c6b38db7ebab720c737d658ac0a0d67dcf5)) * implement nepali calendar from gregorian conversion ([4ee9173](https://github.com/dhis2/multi-calendar-dates/commit/4ee91733d6405b2ba53e8304c2dbabafff52e4a1)) * implement period calculation special cases for ethiopic calendar ([62b3de3](https://github.com/dhis2/multi-calendar-dates/commit/62b3de325450ab86d271b825d58ab2c83f18818c)) * implement rest of period calculations for gregrorian calendar ([9f83099](https://github.com/dhis2/multi-calendar-dates/commit/9f83099a4ad5361d6458be4606cfae8110ba44e1)) * implement some fixed period calculations for gregrorian calendar ([040bd8e](https://github.com/dhis2/multi-calendar-dates/commit/040bd8ed1afe9f9594513bace74b2ab23d35a80f)) * update period generation to add start and end date ([9adb0aa](https://github.com/dhis2/multi-calendar-dates/commit/9adb0aa8a5d14dc7d89a02382e391823638cde24)) --- CHANGELOG.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50acd76..f439526 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,69 @@ +# 1.0.0 (2023-02-23) + + +### Bug Fixes + +* add eraYear to nepali calendar ([c725d96](https://github.com/dhis2/multi-calendar-dates/commit/c725d96b0613c58567e1193e542d5f5eff58041c)) +* change build process to emit cjs and es modules ([#10](https://github.com/dhis2/multi-calendar-dates/issues/10)) ([1102de8](https://github.com/dhis2/multi-calendar-dates/commit/1102de87fd99006e1d1e1bad29af3790f7b3bdc2)) +* change english-nepal code to en-NP (not ne-EN) ([7e92aa4](https://github.com/dhis2/multi-calendar-dates/commit/7e92aa4efe7302aca3ad52ebd98d49a52141c15b)) +* change getNowInCalendar to default to user timezone rather than utc ([03caf6d](https://github.com/dhis2/multi-calendar-dates/commit/03caf6d4a8c0b83924cf47e0aacecb7987168d80)) +* change param for useDatePicker from initialDate to date ([429b2eb](https://github.com/dhis2/multi-calendar-dates/commit/429b2ebb660dfbaf77de9f1748dfa7e7fc0472ea)) +* change react dependency to fix issue with docusaurus build ([c58d560](https://github.com/dhis2/multi-calendar-dates/commit/c58d5603f1d30667bcdf241c8a3b02cd06fffdb9)) +* change react to be a peer dependency ([fbf106c](https://github.com/dhis2/multi-calendar-dates/commit/fbf106cab1ed0dad52d0877c2b61fb3bd6c2540d)) +* change the api for nepali calendar to accept a string ([3a51a6f](https://github.com/dhis2/multi-calendar-dates/commit/3a51a6f6b8a48649c0588b0f7421529c3ce64eb0)) +* change useWeekDayLabels to accept a custom format for day names ([0369006](https://github.com/dhis2/multi-calendar-dates/commit/036900694aad88ed88f9b8242c537f9e01847b40)) +* default to user timezone or UTC if no timezone passed ([e9c34e1](https://github.com/dhis2/multi-calendar-dates/commit/e9c34e14e0c3f6a7ab59ba7ecdf74959ddf0cc95)) +* ensure ethiopic dates are in the correct era ([34061d9](https://github.com/dhis2/multi-calendar-dates/commit/34061d9c7d54f8343ede4f65c723b7ce03c57ef8)) +* ensure that direction is either rtl or ltr ([4a92e91](https://github.com/dhis2/multi-calendar-dates/commit/4a92e91b979c4791613f50ca88c1a4d72a45e9c3)) +* fallback to default locale if passed a wrong locale ([785a1b9](https://github.com/dhis2/multi-calendar-dates/commit/785a1b94c134b0ff42613b71d673505816186cbd)) +* fix period generation for Nepali ([157e6a7](https://github.com/dhis2/multi-calendar-dates/commit/157e6a7812ab7480f190413c60a66f4bb86f68c0)) +* force a publish ([feec6c2](https://github.com/dhis2/multi-calendar-dates/commit/feec6c28fd7b49febaa6a8ed98a6fe92979a6704)) +* force a unpublish for alpha channel ([c4bcb20](https://github.com/dhis2/multi-calendar-dates/commit/c4bcb20d03150909ea12d4ba596b3b0d0c390162)) +* force npm publish ([571584c](https://github.com/dhis2/multi-calendar-dates/commit/571584c93e1a6fa9e8b0a02ad12cc8037e0f7c65)) +* force npm publish ([f57733e](https://github.com/dhis2/multi-calendar-dates/commit/f57733eee2ba3c1421f3cab7bf4d179fffa4997f)) +* force npm publish ([bacacf2](https://github.com/dhis2/multi-calendar-dates/commit/bacacf26327e1b36f0fed21859b67e7d87cfe7da)) +* force npm publish ([ac2ab35](https://github.com/dhis2/multi-calendar-dates/commit/ac2ab35d7e976e82aa5f780e8b769b6e6e654e1a)) +* force npm publish ([8021a97](https://github.com/dhis2/multi-calendar-dates/commit/8021a9739e85ee6bfc78c100acde66c5b78a7181)) +* force npm publish ([d22e470](https://github.com/dhis2/multi-calendar-dates/commit/d22e4700511505fd699b0f1d1814064f885af8b5)) +* force npm publish ([e5cb2ff](https://github.com/dhis2/multi-calendar-dates/commit/e5cb2ff91b9f72dd842af044aff64b8f5351554a)) +* force npm publish ([39bd827](https://github.com/dhis2/multi-calendar-dates/commit/39bd827b7ff6a65cfb7e831b55dc8ded2716d509)) +* force npm publish ([6f95463](https://github.com/dhis2/multi-calendar-dates/commit/6f95463988925465e09e90538b18f04ad1d09daf)) +* force npm publish ([6b7fbf3](https://github.com/dhis2/multi-calendar-dates/commit/6b7fbf3227e1254b7fe651c49d118a258470a9f4)) +* force npm publish ([2ce77b3](https://github.com/dhis2/multi-calendar-dates/commit/2ce77b3e920788b955dc243570e9b4816a3200db)) +* force npm publish ([3e43ce4](https://github.com/dhis2/multi-calendar-dates/commit/3e43ce4592bd907ee0936ee81bc02949010ae50e)) +* force publish to @dhis2/multi-calendar-dates ([0bc26f1](https://github.com/dhis2/multi-calendar-dates/commit/0bc26f15f8165febc3e60883bc1e6bde7fb0226b)) +* handle on-the-fly changes to selected calendar ([89f0427](https://github.com/dhis2/multi-calendar-dates/commit/89f04278aba25b131cbf57fe21809abd1a3fec9e)) +* make nepali calendar default to en-NP if no valid locale provided ([a074789](https://github.com/dhis2/multi-calendar-dates/commit/a074789125840bb349f581a4a70e0cf2b6dc928f)) +* make sure period calculation works with non-standard dhis2 calendar IDs ([7c56b1a](https://github.com/dhis2/multi-calendar-dates/commit/7c56b1a219e95dce7b781a3642e5b486d028ab7c)) +* put pack semantic-release config ([4ae3f4c](https://github.com/dhis2/multi-calendar-dates/commit/4ae3f4cf848a7c736b12809a2bc4cb1f41f8ad11)) +* remove .only for tests ([72fa7e5](https://github.com/dhis2/multi-calendar-dates/commit/72fa7e5c34cf0ec4e9a2f2ccfd7e705c480d1257)) +* remove .only from test ([c685e34](https://github.com/dhis2/multi-calendar-dates/commit/c685e3496ffc8a46155d8564327570ddfd1efc7d)) +* remove test unpublish alpha ([f815e31](https://github.com/dhis2/multi-calendar-dates/commit/f815e310538e22133c88fb20aea3928bc83de3ab)) +* respect startingDay for weekly period generation ([5f1196a](https://github.com/dhis2/multi-calendar-dates/commit/5f1196aff2bad6b77bdaa5fdd52b38bf720eea0b)) +* test npm publish ([40de24f](https://github.com/dhis2/multi-calendar-dates/commit/40de24f05a0e3d8277c0d3f39e7295d0dbf11f23)) +* test npm publish ([69eb402](https://github.com/dhis2/multi-calendar-dates/commit/69eb4026e06340c2a7e6f34e77da9e8e5a7887d4)) +* throw error if non-supported locale is passed for a custom calendar ([293db88](https://github.com/dhis2/multi-calendar-dates/commit/293db88269a079d4b3977859d5f7c62a661fa0f7)) +* update current day selection logic to use same calendar system ([adb0dc8](https://github.com/dhis2/multi-calendar-dates/commit/adb0dc8541cd995192441339e7c36ccf49977a07)) +* update label for financial year periods ([c13a829](https://github.com/dhis2/multi-calendar-dates/commit/c13a829c8e6f11313f6ab3a6e8ec89e31d902efd)) +* update labels for Financial Year period types ([f6c9b68](https://github.com/dhis2/multi-calendar-dates/commit/f6c9b68d2a15cfc1b6a2322b98524324cb319329)) +* update localisation logic for fixed period generation ([668f6d8](https://github.com/dhis2/multi-calendar-dates/commit/668f6d8a3e881926a192c6065aa82cea473150e1)) +* update useDatePicker hook to resolve options with hook ([ffa509a](https://github.com/dhis2/multi-calendar-dates/commit/ffa509ac462d0be44ca58cb2958592d26b19c416)) +* update useDatePicker to accept the calendar date rather than the iso one ([a65fc3d](https://github.com/dhis2/multi-calendar-dates/commit/a65fc3db33321c737c873bb5ef972f1e4a698da3)) +* update weekly period logic to match analytics tests ([2faf567](https://github.com/dhis2/multi-calendar-dates/commit/2faf567adcb5705d35f4d3d5930fb03aa7b343ef)) +* use numberinSystem if provided ([b3e82fb](https://github.com/dhis2/multi-calendar-dates/commit/b3e82fba160839beeafdc78f77f601d05e48f345)) + + +### Features + +* expose a method to return today date in specific calendar ([1213b45](https://github.com/dhis2/multi-calendar-dates/commit/1213b453a71f4eef5393cd72f2204e7deea2b998)) +* implement first iteration of the engine ([51526db](https://github.com/dhis2/multi-calendar-dates/commit/51526dbc08342c3ccaf59871f251af37aaf0b290)) +* implement nepali calendar ([bcb66c6](https://github.com/dhis2/multi-calendar-dates/commit/bcb66c6b38db7ebab720c737d658ac0a0d67dcf5)) +* implement nepali calendar from gregorian conversion ([4ee9173](https://github.com/dhis2/multi-calendar-dates/commit/4ee91733d6405b2ba53e8304c2dbabafff52e4a1)) +* implement period calculation special cases for ethiopic calendar ([62b3de3](https://github.com/dhis2/multi-calendar-dates/commit/62b3de325450ab86d271b825d58ab2c83f18818c)) +* implement rest of period calculations for gregrorian calendar ([9f83099](https://github.com/dhis2/multi-calendar-dates/commit/9f83099a4ad5361d6458be4606cfae8110ba44e1)) +* implement some fixed period calculations for gregrorian calendar ([040bd8e](https://github.com/dhis2/multi-calendar-dates/commit/040bd8ed1afe9f9594513bace74b2ab23d35a80f)) +* update period generation to add start and end date ([9adb0aa](https://github.com/dhis2/multi-calendar-dates/commit/9adb0aa8a5d14dc7d89a02382e391823638cde24)) + # [1.0.0-beta.24](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.0-beta.23...v1.0.0-beta.24) (2023-02-22) diff --git a/package.json b/package.json index 8d6e048..ed85639 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/multi-calendar-dates", - "version": "1.0.0-beta.24", + "version": "1.0.0", "license": "BSD-3-Clause", "publishConfig": { "access": "public" From 08c8032e5dc32ad9f6f2810ecd7b9cb594766d36 Mon Sep 17 00:00:00 2001 From: Mozafar Date: Thu, 9 Mar 2023 09:07:06 +0000 Subject: [PATCH 09/15] fix: parse date correctly when a dhis2 calendar type is passed (#22) fixes https://dhis2.atlassian.net/browse/DHIS2-14900 --- src/hooks/useDatePicker.spec.tsx | 24 +++++++++++++++++++++++- src/hooks/useDatePicker.ts | 19 +++++++++++-------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/hooks/useDatePicker.spec.tsx b/src/hooks/useDatePicker.spec.tsx index 4b3d1f2..181f722 100644 --- a/src/hooks/useDatePicker.spec.tsx +++ b/src/hooks/useDatePicker.spec.tsx @@ -550,7 +550,7 @@ describe('changing the calendar on the fly', () => { describe('default options for hook', () => { const originalDateTimeFormat = Intl.DateTimeFormat afterEach(() => { - // eslint-disable-next-line @typescript-eslint/no-extra-semi + // eslint-disable-next-line @typescript-eslint/no-extra-semi, @typescript-eslint/no-explicit-any ;(Intl.DateTimeFormat as any) = originalDateTimeFormat }) @@ -598,3 +598,25 @@ describe('default options for hook', () => { expect(result.weekDayLabels).toContain('lunes') }) }) + +it('should generate the correct calendar weeks when passed "Ethiopian" rather than "ethiopic" (bug)', () => { + const onDateSelect = jest.fn() + const date = '2015-06-29' + const options = { + calendar: 'ethiopian' as SupportedCalendar, + } + const renderedHook = renderHook(() => + useDatePicker({ onDateSelect, date, options }) + ) + const result = renderedHook.result?.current as UseDatePickerReturn + + expect( + result.calendarWeekDays.map((week) => week.map((d) => d.label)) + ).toEqual([ + ['29', '30', '1', '2', '3', '4', '5'], + ['6', '7', '8', '9', '10', '11', '12'], + ['13', '14', '15', '16', '17', '18', '19'], + ['20', '21', '22', '23', '24', '25', '26'], + ['27', '28', '29', '30', '1', '2', '3'], + ]) +}) diff --git a/src/hooks/useDatePicker.ts b/src/hooks/useDatePicker.ts index 2ef7564..07858b3 100644 --- a/src/hooks/useDatePicker.ts +++ b/src/hooks/useDatePicker.ts @@ -78,7 +78,14 @@ export const useDatePicker: UseDatePickerHookType = ({ date: dateParts, options, }) => { - const resolvedOptions = useResolvedLocaleOptions(options) + const calendar = getCustomCalendarIfExists( + dhis2CalendarsMap[options.calendar!] ?? options.calendar + ) as SupportedCalendar + + const resolvedOptions = useResolvedLocaleOptions({ + ...options, + calendar, + }) const prevDateStringRef = useRef(dateParts) const todayZdt = useMemo( @@ -98,16 +105,12 @@ export const useDatePicker: UseDatePickerHookType = ({ Temporal.MonthOrMonthCode & { day: number }) : todayZdt - const calendar: Temporal.CalendarLike = getCustomCalendarIfExists( - dhis2CalendarsMap[resolvedOptions.calendar] ?? resolvedOptions.calendar - ) - const temporalCalendar = useMemo( - () => Temporal.Calendar.from(calendar), - [calendar] + () => Temporal.Calendar.from(resolvedOptions.calendar), + [resolvedOptions.calendar] ) const temporalTimeZone = useMemo( - () => Temporal.TimeZone.from(resolvedOptions.timeZone!), + () => Temporal.TimeZone.from(resolvedOptions.timeZone), [resolvedOptions] ) From 36dd66fbcdef12012196501102636515adf519a1 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Thu, 9 Mar 2023 09:12:36 +0000 Subject: [PATCH 10/15] chore(release): cut 1.0.1 [skip ci] ## [1.0.1](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.0...v1.0.1) (2023-03-09) ### Bug Fixes * parse date correctly when a dhis2 calendar type is passed ([#22](https://github.com/dhis2/multi-calendar-dates/issues/22)) ([08c8032](https://github.com/dhis2/multi-calendar-dates/commit/08c8032e5dc32ad9f6f2810ecd7b9cb594766d36)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f439526..6a5b452 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.0.1](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.0...v1.0.1) (2023-03-09) + + +### Bug Fixes + +* parse date correctly when a dhis2 calendar type is passed ([#22](https://github.com/dhis2/multi-calendar-dates/issues/22)) ([08c8032](https://github.com/dhis2/multi-calendar-dates/commit/08c8032e5dc32ad9f6f2810ecd7b9cb594766d36)) + # 1.0.0 (2023-02-23) diff --git a/package.json b/package.json index ed85639..4e7fa03 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/multi-calendar-dates", - "version": "1.0.0", + "version": "1.0.1", "license": "BSD-3-Clause", "publishConfig": { "access": "public" From 3cfb58a436f1c3e4c58a5599b14097c50590c9c3 Mon Sep 17 00:00:00 2001 From: Mozafar Date: Thu, 9 Mar 2023 12:53:50 +0000 Subject: [PATCH 11/15] fix: use custom locale when it exists (#23) --- src/hooks/internal/useResolvedLocaleOptions.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/hooks/internal/useResolvedLocaleOptions.ts b/src/hooks/internal/useResolvedLocaleOptions.ts index 53e762a..f1dddea 100644 --- a/src/hooks/internal/useResolvedLocaleOptions.ts +++ b/src/hooks/internal/useResolvedLocaleOptions.ts @@ -6,6 +6,7 @@ import { WeekDayFormat, } from '../../types' import getValidLocale from '../../utils/getValidLocale' +import { isCustomCalendar } from '../../utils/helpers' type UseResolvedLocaleOptionsHook = ( options: PickerOptions @@ -59,9 +60,20 @@ export const useResolvedLocaleOptions: UseResolvedLocaleOptionsHook = ( weekday: userOptions.weekDayFormat, }).resolvedOptions() + let localeToUse = resolvedLocale || defaultUserOptions.locale + // This step is necessary for custom locales where we have our own localisation values (like ne-NP) + // otherwise they can be overridden by Intl.DateTimeFormat().resolvedOptions() + if ( + userOptions.calendar && + userOptions.locale && + isCustomCalendar(userOptions.calendar) + ) { + localeToUse = userOptions.locale + } + return { calendar: userOptions.calendar || defaultUserOptions.calendar, - locale: resolvedLocale || defaultUserOptions.locale, + locale: localeToUse, timeZone: resolvedOptions.timeZone || defaultUserOptions.timeZone, numberingSystem: resolvedOptions.numberingSystem || From 73057360c4720d995370779b02fe6e3784b326ab Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Thu, 9 Mar 2023 12:57:27 +0000 Subject: [PATCH 12/15] chore(release): cut 1.0.2 [skip ci] ## [1.0.2](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.1...v1.0.2) (2023-03-09) ### Bug Fixes * use custom locale when it exists ([#23](https://github.com/dhis2/multi-calendar-dates/issues/23)) ([3cfb58a](https://github.com/dhis2/multi-calendar-dates/commit/3cfb58a436f1c3e4c58a5599b14097c50590c9c3)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a5b452..23e84ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.0.2](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.1...v1.0.2) (2023-03-09) + + +### Bug Fixes + +* use custom locale when it exists ([#23](https://github.com/dhis2/multi-calendar-dates/issues/23)) ([3cfb58a](https://github.com/dhis2/multi-calendar-dates/commit/3cfb58a436f1c3e4c58a5599b14097c50590c9c3)) + ## [1.0.1](https://github.com/dhis2/multi-calendar-dates/compare/v1.0.0...v1.0.1) (2023-03-09) diff --git a/package.json b/package.json index 4e7fa03..268d67e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dhis2/multi-calendar-dates", - "version": "1.0.1", + "version": "1.0.2", "license": "BSD-3-Clause", "publishConfig": { "access": "public" From 3e347df22fd78e3b5375bc326f16d44b3f7fe757 Mon Sep 17 00:00:00 2001 From: Mozafar Date: Fri, 23 Jun 2023 13:11:25 +0300 Subject: [PATCH 13/15] docs: update multi-calendar documentation (#25) * docs: update multi-calendar documentation Update README.md Apply suggestions from code review Co-authored-by: Kai Vandivier <49666798+KaiVandivier@users.noreply.github.com> Add more examples to documentation * chore: lint commit messages and pr titles * docs: update according to code review Co-authored-by: Kai Vandivier <49666798+KaiVandivier@users.noreply.github.com> * docs: add more examples for generateFixedPeriods * docs: reorder docs --------- Co-authored-by: Kai Vandivier <49666798+KaiVandivier@users.noreply.github.com> --- .../workflows/dhis2-verify-commits.yml.yml | 32 ++ README.md | 328 +++++++++++++++++- 2 files changed, 356 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/dhis2-verify-commits.yml.yml diff --git a/.github/workflows/dhis2-verify-commits.yml.yml b/.github/workflows/dhis2-verify-commits.yml.yml new file mode 100644 index 0000000..ae7831b --- /dev/null +++ b/.github/workflows/dhis2-verify-commits.yml.yml @@ -0,0 +1,32 @@ +name: 'dhis2: verify (commits)' + +on: + pull_request: + types: ['opened', 'edited', 'reopened', 'synchronize'] + +jobs: + lint-pr-title: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: c-hive/gha-yarn-cache@v1 + - run: yarn install --frozen-lockfile + - id: commitlint + run: echo ::set-output name=config_path::$(node -e "process.stdout.write(require('@dhis2/cli-style').config.commitlint)") + - uses: JulienKode/pull-request-name-linter-action@v0.5.0 + with: + configuration-path: ${{ steps.commitlint.outputs.config_path }} + + lint-commits: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: c-hive/gha-yarn-cache@v1 + - run: yarn install --frozen-lockfile + - id: commitlint + run: echo ::set-output name=config_path::$(node -e "process.stdout.write(require('@dhis2/cli-style').config.commitlint)") + - uses: wagoid/commitlint-github-action@v4 + with: + configFile: ${{ steps.commitlint.outputs.config_path }} diff --git a/README.md b/README.md index 931ed68..994f270 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,331 @@ # multi-calendar-engine -This is the engine to build a multi-calendar component (part of @dhis/ui) that supports various calendars used around the world (i.e. Ethiopic, Nepali etc..). +This library is used to work with dates in multiple calendrical system (i.e. Ethiopic, Nepali etc..) across DHIS-2 applications. It mainly exposes two components: -It relies on the [Temporal API](https://tc39.es/proposal-temporal) which aims to achieve, among other goals, full-support for non-Gregorian calendars. +1. Hooks like [useDatePicker](https://github.com/dhis2/multi-calendar-dates/blob/multi-calendar-docs/src/hooks/useDatePicker.ts) used to build UI components (part of @dhis/ui) such as the [Calendar](https://ui.dhis2.nu/components/calendar) and [CalendarInput](https://ui.dhis2.nu/components/calendar-input) components. +1. Helper methods, like `generateFixedPeriods` and `getNowInCalendar` to deal with period generations, date manipulation and arithmetic across multiple calendrical systems. -This [document](https://docs.google.com/document/d/19zjyB45oBbqC5KeubaU8E7cw9fGhFc3tOXY0GkzZKqc/edit?userstoinvite=hendrik%40dhis2.org#heading=h.rjt0etsbsqh6) documents the requirements and design decisions for multi-calendar support. +The idea behind this library is to abstract the complicated details of dealing with dates in DHIS2, and to centralise them in one place for consumption in different apps and libraries. -## Architecture Design Records +Internally, the library relies on the [Temporal API](https://tc39.es/proposal-temporal) which aims to achieve, among other goals, full-support for non-Gregorian calendars. + +This [document](https://docs.google.com/document/d/19zjyB45oBbqC5KeubaU8E7cw9fGhFc3tOXY0GkzZKqc/edit?userstoinvite=hendrik%40dhis2.org#heading=h.rjt0etsbsqh6) has some of the requirements and design decisions for this project. + +This [Jira epic](https://dhis2.atlassian.net/browse/DHIS2-14051) lists the app that moved to using the library, and what comes next. + +# Periods and Dates helpers + +The library also provides helper methods to work with periods and dates in multiple calendars. This allows doing date arithmetic, comparisons in a standard timezone-safe way. It currently relies on the Temporal API. + +> The library is built on top of Temporal API, but this is an implementation detail, and one of the goals of the library is to hide that detail to allow replacing Temporal with a different implementation in the future, i.e. a Kotlin multi-platform implementation to achieve consistency between web, android and backend. + +## generateFixedPeriods + +`generateFixedPeriods` returns the periods of a specific type in a specific year. This is used, for example in [Data Visualizer](https://github.com/dhis2/data-visualizer-app/pull/2233), to display the list of periods of different types (i.e. monthly, weekly, yearly) in a specific year, according to the user's calendar and locale. + +### Examples + +Calling `generateFixedPeriods({year: 2015, periodType: "FYNOV", calendar: "gregory"})` will return all the November financial year periods (FYNOV) from the year 2015 (defaults to 10 years). Here are some more examples: + +```js +// some examples +import { generateFixedPeriods } from '@dhis2/multi-calendar-dates' + +describe('generateFixedPeriods', () => { + it('should generate financial years periods (starting November) for the specified', () => { + const result = generateFixedPeriods({ + year: 2015, + calendar: 'gregory', + locale: 'en', + periodType: 'FYNOV', + }) + + expect(result).toEqual( + expect.arrayContaining([ + { + id: '2015Nov', + name: 'November 2015 - October 2016', + startDate: '2015-11-01', + endDate: '2016-10-31', + }, + { + id: '2014Nov', + name: 'November 2014 - October 2015', + startDate: '2014-11-01', + endDate: '2015-10-31', + }, + // .... up to + { + id: '2006Nov', + name: 'November 2006 - October 2007', + startDate: '2006-11-01', + endDate: '2007-10-31', + }, + ]) + ) + }) + it('should generate weekly periods (weeks starting on Sunday) for the specified year', () => { + const result = generateFixedPeriods({ + year: 2015, + calendar: 'gregory', + locale: 'en', + periodType: 'WEEKLYSUN', + }) + + expect(result).toEqual( + expect.arrayContaining([ + { + id: '2015SunW1', + iso: '2015SunW1', + name: 'Week 1 - 2015-01-04 - 2015-01-10', + startDate: '2015-01-04', + endDate: '2015-01-10', + }, + // .... up to + { + id: '2015SunW52', + iso: '2015SunW52', + name: 'Week 52 - 2015-12-27 - 2016-01-02', + startDate: '2015-12-27', + endDate: '2016-01-02', + }, + ]) + ) + }) + + it('should generate monthly periods (localised in Spanish) for the specified year', () => { + const result = generateFixedPeriods({ + year: 2015, + calendar: 'gregory', + locale: 'es', + periodType: 'MONTHLY', + }) + + expect(result).toEqual( + expect.arrayContaining([ + { + id: '201501', + iso: '201501', + name: 'Enero de 2015', + startDate: '2015-01-01', + endDate: '2015-01-31', + }, + // .... up to + { + id: '201512', + iso: '201512', + name: 'Diciembre de 2015', + startDate: '2015-12-01', + endDate: '2015-12-31', + }, + ]) + ) + }) + + it('should generate bi-monthly periods for the Ethiopic calendar for the specified year', () => { + const result = generateFixedPeriods({ + year: 2015, + calendar: 'ethiopic', + locale: 'en', + periodType: 'BIMONTHLY', + }) + + expect(result).toEqual( + expect.arrayContaining([ + { + id: '201501B', + iso: '201501B', + name: 'Meskerem - Tekemt 2015', + startDate: '2015-01-01', + endDate: '2015-02-30', + }, + // .... up to + { + endDate: '2015-12-30', + id: '201506B', + iso: '201506B', + name: 'Hamle - Nehasse 2015', + startDate: '2015-11-01', + }, + ]) + ) + }) + it('should generate six-monthly periods for the Nepali calendar for the specified year', () => { + const result = generateFixedPeriods({ + year: 2078, + calendar: 'nepali', + locale: 'en', + periodType: 'SIXMONTHLY', + }) + + expect(result).toEqual([ + { + id: '2078S1', + iso: '2078S1', + name: 'Baisakh - Ashwin 2078', + startDate: '2078-01-01', + endDate: '2078-06-31', + }, + { + id: '2078S2', + iso: '2078S2', + name: 'Kartik - Chaitra 2078', + startDate: '2078-07-01', + endDate: '2078-12-30', + }, + ]) + }) +}) +``` + +### Types + +The method takes a single `options` parameter and returns an `Array`. + +#### The `options` param + +The `options` param is an object of type `GeneratedPeriodParams`: + +```ts +type GeneratedPeriodParams = { + year: number + periodType: PeriodIdentifier + calendar: SupportedCalendar + locale?: string + startingDay?: number /** 1 is Monday */ + yearsCount?: number +} +``` + +For convenience, `locale` can be passed in the Java-like style (i.e. `ar_SD` rather than `ar-SD`) and it will be converted to the JS-style. `yearsCount` is used when generating yearly periods to know how many years to generate (defaults to 10). ` + +`periodType` can be one of the period identifiers defined [here](https://github.com/dhis2/multi-calendar-dates/blob/multi-calendar-docs/src/period-calculation/fixed-periods.ts#L10). Although the library internally is flexible and can accept, for example, quarterly periods starting any month (i.e. `QUARTERLYMAY`), support for such periods might not be available in the backend, so they should be used carefully. The flexibility, though, means that a new period could be added to the backend and used without changes in the frontend. + +#### The return value + +The returned value is an array of `FixedPeriod`s: + +```ts +type FixedPeriod = { + id: string + iso?: string + name: string + startDate: string + endDate: string +} +``` + +- `id` (and `iso`) are the same right now, and return a period identifier, i.e. `2015Q1` (quarter one of the year 2015) or `2015SunW1` (the first week - starting Sunday - of the year 2015). The full list of values are documented in [periodValues](https://github.com/dhis2/multi-calendar-dates/blob/main/features/fixed-periods.ethiopic.feature) in the feature files. + +> please use `id` to identify the period. `iso` was added for backwards compatibility with existing implementations + +- `startDate` and `endDate` are the start and end dates of the specific period. This is provided for convenience, but the backend currently only makes use of the ID to work out what each period means. + +- `name` is the human readable name of the period, according to what we dispaly in DHIS2 Data Visualizer, i.e. `Week 1 - 2014-13-03 - 2015-01-04` for a weekly period or `2015` for a yearly period. + +## getNowInCalendar + +`getNowInCalendar` returns today's date in the specified calendrical system. + +### Examples + +```js +// Assuming today's date is 13th October 2021 +beforeEach(() => { + // 13 October 2021 UTC + jest.spyOn(Date, 'now').mockReturnValue(1634089600000) +}) +it('should get today date in Gregorian', () => { + const { day, month, year } = getNowInCalendar('gregory', 'UTC') + expect({ day, month, year }).toEqual({ day: 13, month: 10, year: 2021 }) +}) +it('should get today date in Ethiopic', () => { + const { day, month, eraYear: year } = getNowInCalendar('ethiopic', 'UTC') + expect({ day, month, year }).toEqual({ + day: 3, + month: 2, + year: 2014, + }) +}) +``` + +### Types + +The method takes two positional arguments: + +- `calendarToUse` which can be one of the calendars specified [here](https://github.com/dhis2/multi-calendar-dates/blob/multi-calendar-docs/src/constants/calendars.ts) (defaults to `gregory` calendar if not specied. +- `timeZone`: a string representing the time zone (defaults to `UTC`) of the user. + +and returns a [ZonedDateTime](https://tc39.es/proposal-temporal/docs/zoneddatetime.html#properties) object, which can be destructured to `.year` or `.eraYear` (`eraYear` preferred to avoid an issue with Ethiopic calendar), `.month`, `.day` which returns the values in the specified calendar, or you can `.getISOFields()` to return the underlying iso8601 (gregory) date. + +> ToDo: we should also return the date stringified into `yyyy-MM-dd` since this is the most common usecase and it would help clients not to have to do the conversion manually. + +## Upcoming methods + +There are new methods that will be added soon (in the alpha release right now), such as `getFixedPeriodByDate` (which, given a date in a calendar, it returns what fixed period the date falls in) and `getAdjacentFixedPeriods` (that facilitates being able to navigate to next and previous periods). + +> These new methods will be documented when merged into main branch, but this gives an idea about the general approach we want to follow with the library; if you encounter a use case that you think it should be included in the library then please get in touch to discuss whether it should live there, or at the consumer level. + +# Special cases and considerations with periods logic + +There are some special DHIS2-specific cases when doing period calculations that we handle. The specs for these are documented in the tests and cucumber feature files. Some of these are: + +- Dealing with the 13th month in the Ethiopian calendar: the Ethiopic calendar has 13 months: 12 months of 30 days, then the 13th month has 5 or 6 days depending on whether it's a leap year or not. When generating periods for bi-weekly or less (bi-weekly, weekly, daily) then the 13th month is displayed. But when we are generating periods for monthly or larger, we do not display the 13th month. The backend then makes the decision about where to include any data for the 13th month, so when doing monthly analytics, the 13th month will be lumped with the following month's data. + +- The period IDs are dictated by the backend, and they use the Gregorian month names, for example, `QuarterlyNov` or `QuarterlyApr`. In the frontend, in a non-Gregorian calendar, `Nov` will be "translated" into the 11th month of the current calendar system (Hamle in Ethiopic). Ideally, we will have period IDs that are calendar-agnostic in the future, but this works for now as a solution. + +- From the frontend perspective, we always send a date in the calendar system. It is formatted in an ISO-like format (`yyyy-MM-dd`). It is "ISO-like", because the date is actually in the calendar system rather than the Gregorian ISO8601 calendar. So when a system set to Ethiopic, sends `2015-01-01` to the backend, it means the year 2015 in Ethiopic (which is 2022 in Gregorian). This is what the backend expects, and if there is a need for a conversion, then it happens in the backend. + + - Given we have the Temporal object in the frontend, we have the ability to send the date converted into Gregorian, but that's what the backend expects right now. + +- Nepali is implemented as a custom calendar: see [nepaliCalendar.ts](https://github.com/dhis2/multi-calendar-dates/blob/multi-calendar-docs/src/custom-calendars/nepaliCalendar.ts). Nepali is luni-solar calendar which means that the length of months can vary from year to year. The way Temporal does date arithmetic, is that it converts the day to gregorian, performs the arithmetic, then converts it back to the calendar. This leads to weird situations where you do `nepaliDate.add({month: 1})` for example, but the result is still in the current month (since the month has 30 days in Gregorian, but 32 in Nepali for example). To get around that, we [set the day to the 14th](https://github.com/dhis2/multi-calendar-dates/blob/73057360c4720d995370779b02fe6e3784b326ab/src/period-calculation/getYearlyPeriods.ts#L23) before doing arithmetic (in the context of period generation) and this leads to results that make sense in the context of DHIS2. + +- Nepali is also not supported as a locale in major browsers. So we rely on localising it with a hardcoded map, meaning we don't have the same flexibility showing the day or month names as short or long for example with `.toLocaleString`. That means that the consumer can only use one of `ne-NP` or `en-NP` (nepali months and days transliterated into English) as a locale with the Nepali calendar, and they can't use browser localisations (so they can't display Nepali month names in French for example, but they would be able to do so with Ehtiopic or Islamic calendars). + +- In Ethiopic calendar, when consuming a date, use `.eraYear` rather than `.year` to get the year part of a date. There is an ongoing discussion on Temporal to decide which era of the Ethiopic calendar should be the default, but it's likely to be browser-dependent at the end, so it's safer to use `eraYear` as this is what users in Ethiopia would expect to see. We looked at abstracting this difference away in the library, but there was no easy solution for it. + +- The library also abstracts some DHIS2-specific inconsistencies with the backend to make it easier for consumers of the library. For example, it has a map to convert from the calendar IDs used in DHIS2 to the ones expected by the library: [dhis2CalendarsMap.ts](https://github.com/dhis2/multi-calendar-dates/blob/multi-calendar-docs/src/constants/dhis2CalendarsMap.ts). This maps "ethiopian" (used in DHIS2) to "ethiopic" which is the standard ID used in JavaScript (in [Unicode CLDR](https://cldr.unicode.org/)). It also maps the Java locale names with an underscore to ones with a dash, to make them easier to use in a JavaScript context (i.e from `ar_SD` to `ar-SD`). + +# Hooks for Calendar UI + +The library provides a hook `useDatePicker` that's consumed by the dhis/ui calendar components. There are two components that currently use it: + +- [Calendar](https://ui.dhis2.nu/components/calendar): a calendar component supporting non-Greogorian calendars +- [CalendarInput](https://ui.dhis2.nu/components/calendar-input): a wrapper around the Calendar component to support the most common use case for a calendar when we want to display it next to an input. + +`useDatePicker` takes a [DatePickerOptions](https://github.com/dhis2/multi-calendar-dates/blob/multi-calendar-docs/src/hooks/useDatePicker.ts#L16) object, and returns [UseDatePickerReturn](https://github.com/dhis2/multi-calendar-dates/blob/multi-calendar-docs/src/hooks/useDatePicker.ts#LL28C13-L28C32) that contains information needed to render a UI component, i.e. the localised day names, and the weeks in the current view (month). + +```ts +// the options passed to useDatePicker +type DatePickerOptions = { + date: string + options: PickerOptions + onDateSelect: ({ + calendarDate, + calendarDateString, + }: { + calendarDate: Temporal.ZonedDateTime + calendarDateString: string + }) => void +} +``` + +```ts +// the return type of the hook +type UseDatePickerReturn = UseNavigationReturnType & { + weekDayLabels: string[] + calendarWeekDays: { + zdt: Temporal.ZonedDateTime + label: string | number + calendarDate: string + onClick: () => void + isSelected: boolean | undefined + isToday: boolean + isInCurrentMonth: boolean + }[][] +} +``` + +# Architecture Design Records - [Use Temporal API as the backbone of the engine](./doc/architecture/decisions/0002-use-temporal-api-as-the-backbone-for-the-engine.md) From 4dea52d3a6e555d70b3ac30291f7ae89bf3398ca Mon Sep 17 00:00:00 2001 From: Jan-Gerke Salomon Date: Tue, 9 Jan 2024 12:01:44 +0100 Subject: [PATCH 14/15] chore(gh verify commit workflow): add skip condition --- .github/workflows/dhis2-verify-commits.yml.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/dhis2-verify-commits.yml.yml b/.github/workflows/dhis2-verify-commits.yml.yml index ae7831b..91ad933 100644 --- a/.github/workflows/dhis2-verify-commits.yml.yml +++ b/.github/workflows/dhis2-verify-commits.yml.yml @@ -19,6 +19,7 @@ jobs: lint-commits: runs-on: ubuntu-latest + if: ${{ !contains(github.event.pull_request.title, '[skip commit-lint]') }} steps: - uses: actions/checkout@v2 with: From f72fbeb950f2f4e8b2a837104d8ca7eaeb7e459a Mon Sep 17 00:00:00 2001 From: Jan-Gerke Salomon Date: Tue, 9 Jan 2024 16:01:48 +0100 Subject: [PATCH 15/15] fix: address merge issues (chore: merge branch 'main' into 'main->alpha') --- src/utils/localisationHelpers.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/utils/localisationHelpers.ts b/src/utils/localisationHelpers.ts index a5b72e0..09ed943 100644 --- a/src/utils/localisationHelpers.ts +++ b/src/utils/localisationHelpers.ts @@ -5,9 +5,8 @@ import { customCalendars, CustomCalendarTypes, } from '../custom-calendars' -import { LocaleOptions } from '../hooks/useDatePicker' +import { PickerOptions, SupportedCalendar } from '../types' import { formatYyyyMmDD, isCustomCalendar } from './helpers' -import { PickerOptions } from '../types' const getCustomCalendarLocale = ( calendar: Temporal.CalendarLike, @@ -33,7 +32,10 @@ const getCustomCalendarLocale = ( type LocaliseDateLabel = ( selectedDateZdt: Temporal.ZonedDateTime | Temporal.PlainDate, - localeOptions: LocaleOptions, + localeOptions: { + calendar: SupportedCalendar + locale: string + }, options?: { dateStyle: 'full' | 'long' | 'medium' | 'short' | undefined } ) => string