From f545b4b73f80a82af7145f458b476a078e761276 Mon Sep 17 00:00:00 2001 From: Suzanne Aitchison Date: Wed, 25 May 2022 17:08:00 +0100 Subject: [PATCH] localize display of US and non-US date format (#17758) --- .../DateRangePicker/DateRangePicker.jsx | 12 ++- .../__stories__/DateRangePicker.test.jsx | 78 +++++++++++++++++++ app/javascript/utilities/runtime.js | 5 ++ 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 app/javascript/crayons/formElements/DateRangePicker/__stories__/DateRangePicker.test.jsx diff --git a/app/javascript/crayons/formElements/DateRangePicker/DateRangePicker.jsx b/app/javascript/crayons/formElements/DateRangePicker/DateRangePicker.jsx index df69e6165..760a237d8 100644 --- a/app/javascript/crayons/formElements/DateRangePicker/DateRangePicker.jsx +++ b/app/javascript/crayons/formElements/DateRangePicker/DateRangePicker.jsx @@ -10,6 +10,7 @@ import { Icon } from '@crayons'; import ChevronLeft from '@images/chevron-left.svg'; import ChevronRight from '@images/chevron-right.svg'; import Calendar from '@images/calendar.svg'; +import { getCurrentLocale } from '@utilities/runtime'; const PICKER_PHRASES = { ...defaultPhrases, @@ -117,6 +118,8 @@ export const DateRangePicker = ({ relevantDate.month() === latestMoment.month(); const today = moment(); + const dateFormat = + getCurrentLocale().toLowerCase() === 'en-us' ? 'MM/DD/YYYY' : 'DD/MM/YYYY'; return ( // We wrap in a span to assist with scoping CSS selectors & overriding styles from react-dates @@ -126,6 +129,9 @@ export const DateRangePicker = ({ startDate={startMoment} endDate={endMoment} endDateId={endDateId} + startDatePlaceholderText={dateFormat} + endDatePlaceholderText={dateFormat} + displayFormat={dateFormat} focusedInput={focusedInput} // It is strange to add a tabindex to an icon, but react-dates renders these inside a role="button" which does not have a tabindex // This is a workaround to make sure keyboard users can reach and interact with the nav buttons @@ -134,7 +140,11 @@ export const DateRangePicker = ({ minDate={earliestMoment} maxDate={latestMoment} initialVisibleMonth={() => { - const relevantDate = startMoment ? startMoment : today; + let relevantDate = startMoment; + + if (!relevantDate) { + relevantDate = latestMoment ? latestMoment : today; + } return isMonthSameAsLatestMonth(relevantDate) ? relevantDate.clone().subtract(1, 'month') diff --git a/app/javascript/crayons/formElements/DateRangePicker/__stories__/DateRangePicker.test.jsx b/app/javascript/crayons/formElements/DateRangePicker/__stories__/DateRangePicker.test.jsx new file mode 100644 index 000000000..20b4b15f8 --- /dev/null +++ b/app/javascript/crayons/formElements/DateRangePicker/__stories__/DateRangePicker.test.jsx @@ -0,0 +1,78 @@ +import { h } from 'preact'; +import { render, waitFor } from '@testing-library/preact'; +import { DateRangePicker } from '@crayons'; +import '@testing-library/jest-dom'; + +const windowNavigator = window.navigator; + +describe('', () => { + describe('Localization', () => { + afterAll(() => { + Object.defineProperty(window, 'navigator', { + value: windowNavigator, + writable: true, + }); + }); + + it('localizes for en-US date format', async () => { + Object.defineProperty(window, 'navigator', { + value: { language: 'en-US' }, + writable: true, + }); + + const { getAllByPlaceholderText, getByRole, getByDisplayValue } = render( + , + ); + + const inputs = getAllByPlaceholderText('MM/DD/YYYY'); + expect(inputs).toHaveLength(2); + + getByRole('button', { + name: 'Interact with the calendar and add your start date', + }).click(); + + getByRole('button', { + name: 'Choose Wednesday, January 22, 2020 as start date', + }).click(); + + await waitFor(() => + expect(getByDisplayValue('01/22/2020')).toBeInTheDocument(), + ); + }); + + it('localizes for non en-US format', async () => { + Object.defineProperty(window, 'navigator', { + value: { language: 'en' }, + writable: true, + }); + + const { getAllByPlaceholderText, getByRole, getByDisplayValue } = render( + , + ); + + expect(getAllByPlaceholderText('DD/MM/YYYY')).toHaveLength(2); + + getByRole('button', { + name: 'Interact with the calendar and add your start date', + }).click(); + + getByRole('button', { + name: 'Choose Wednesday, January 22, 2020 as start date', + }).click(); + + await waitFor(() => + expect(getByDisplayValue('22/01/2020')).toBeInTheDocument(), + ); + }); + }); +}); diff --git a/app/javascript/utilities/runtime.js b/app/javascript/utilities/runtime.js index 0984af10a..cb051c091 100644 --- a/app/javascript/utilities/runtime.js +++ b/app/javascript/utilities/runtime.js @@ -145,3 +145,8 @@ export const hasOSSpecificModifier = (event) => { */ export const getOSKeyboardModifierKeyString = () => currentOS() === 'macOS' ? 'cmd' : 'ctrl'; + +/** + * @returns {string} A string representing the locale as per the user's browser settings + */ +export const getCurrentLocale = () => navigator.language;