From 166432bcb0cfa5f107d8ca6bf273a494bc53d92e Mon Sep 17 00:00:00 2001 From: Jaanus Sellin Date: Fri, 8 Dec 2023 13:20:39 +0200 Subject: [PATCH] feat: support localization in date filter (#5572) --- .../common/FilterDateItem/FilterDateItem.tsx | 18 +++++++++++++----- .../common/Table/cells/DateCell/DateCell.tsx | 10 ++-------- frontend/src/component/common/util.ts | 15 ++++++++++++++- .../feature-search/feature.search.e2e.test.ts | 6 +++--- .../spec/feature-search-query-parameters.ts | 4 ++-- 5 files changed, 34 insertions(+), 19 deletions(-) diff --git a/frontend/src/component/common/FilterDateItem/FilterDateItem.tsx b/frontend/src/component/common/FilterDateItem/FilterDateItem.tsx index 371f3e11fe..1339f20db7 100644 --- a/frontend/src/component/common/FilterDateItem/FilterDateItem.tsx +++ b/frontend/src/component/common/FilterDateItem/FilterDateItem.tsx @@ -4,8 +4,10 @@ import { StyledPopover } from '../FilterItem/FilterItem.styles'; import { FilterItemChip } from '../FilterItem/FilterItemChip/FilterItemChip'; import { FilterItem } from '../FilterItem/FilterItem'; import { DateCalendar, LocalizationProvider } from '@mui/x-date-pickers'; -import { parseISO, format } from 'date-fns'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; +import { format } from 'date-fns'; +import { useLocationSettings } from 'hooks/useLocationSettings'; +import { getLocalizedDateString } from '../util'; interface IFilterDateItemProps { label: string; @@ -24,7 +26,7 @@ export const FilterDateItem: FC = ({ }) => { const ref = useRef(null); const [anchorEl, setAnchorEl] = useState(null); - const [searchText, setSearchText] = useState(''); + const { locationSettings } = useLocationSettings(); const onClick = () => { setAnchorEl(ref.current); @@ -34,10 +36,16 @@ export const FilterDateItem: FC = ({ setAnchorEl(null); }; - const selectedOptions = state ? state.values : []; + const selectedOptions = state + ? [ + getLocalizedDateString( + state.values[0], + locationSettings.locale, + ) || '', + ] + : []; const selectedDate = state ? new Date(state.values[0]) : null; const currentOperator = state ? state.operator : operators[0]; - const onDelete = () => { onChange(undefined); onClose(); @@ -45,7 +53,7 @@ export const FilterDateItem: FC = ({ }; const setValue = (value: Date | null) => { - const formattedValue = value ? format(value, 'MM/dd/yyyy') : ''; + const formattedValue = value ? format(value, 'yyyy-MM-dd') : ''; onChange({ operator: currentOperator, values: [formattedValue] }); }; diff --git a/frontend/src/component/common/Table/cells/DateCell/DateCell.tsx b/frontend/src/component/common/Table/cells/DateCell/DateCell.tsx index 388eed8f41..4bb99582c5 100644 --- a/frontend/src/component/common/Table/cells/DateCell/DateCell.tsx +++ b/frontend/src/component/common/Table/cells/DateCell/DateCell.tsx @@ -1,8 +1,7 @@ import { VFC } from 'react'; import { useLocationSettings } from 'hooks/useLocationSettings'; -import { formatDateYMD } from 'utils/formatDate'; -import { parseISO } from 'date-fns'; import { TextCell } from 'component/common/Table/cells/TextCell/TextCell'; +import { getLocalizedDateString } from '../../../util'; interface IDateCellProps { value?: Date | string | null; @@ -10,12 +9,7 @@ interface IDateCellProps { export const DateCell: VFC = ({ value }) => { const { locationSettings } = useLocationSettings(); - - const date = value - ? value instanceof Date - ? formatDateYMD(value, locationSettings.locale) - : formatDateYMD(parseISO(value), locationSettings.locale) - : undefined; + const date = getLocalizedDateString(value, locationSettings.locale); return {date}; }; diff --git a/frontend/src/component/common/util.ts b/frontend/src/component/common/util.ts index 510517615d..3cc584c772 100644 --- a/frontend/src/component/common/util.ts +++ b/frontend/src/component/common/util.ts @@ -2,8 +2,9 @@ import { weightTypes } from 'constants/weightTypes'; import { IUiConfig } from 'interfaces/uiConfig'; import { INavigationMenuItem } from 'interfaces/route'; import { IFeatureVariant } from 'interfaces/featureToggle'; -import { format, isValid } from 'date-fns'; +import { format, isValid, parseISO } from 'date-fns'; import { IFeatureVariantEdit } from 'component/feature/FeatureView/FeatureVariants/FeatureEnvironmentVariants/EnvironmentVariantsModal/EnvironmentVariantsModal'; +import { formatDateYMD } from '../../utils/formatDate'; /** * Handle feature flags and configuration for different plans. @@ -48,6 +49,18 @@ export const trim = (value: string): string => { } }; +export const getLocalizedDateString = ( + value: Date | string | null | undefined, + locale: string, +) => { + const date = value + ? value instanceof Date + ? formatDateYMD(value, locale) + : formatDateYMD(parseISO(value), locale) + : undefined; + return date; +}; + export const parseDateValue = (value: string) => { const date = new Date(value); return `${format(date, 'yyyy-MM-dd')}T${format(date, 'HH:mm')}`; diff --git a/src/lib/features/feature-search/feature.search.e2e.test.ts b/src/lib/features/feature-search/feature.search.e2e.test.ts index 450cf07d17..f260a7766b 100644 --- a/src/lib/features/feature-search/feature.search.e2e.test.ts +++ b/src/lib/features/feature-search/feature.search.e2e.test.ts @@ -829,13 +829,13 @@ test('should search features by created date with operators', async () => { createdAt: '2023-01-29T15:21:39.975Z', }); - const { body } = await filterFeaturesByCreated('IS_BEFORE:01/28/2023'); + const { body } = await filterFeaturesByCreated('IS_BEFORE:2023-01-28'); expect(body).toMatchObject({ features: [{ name: 'my_feature_a' }], }); const { body: afterBody } = await filterFeaturesByCreated( - 'IS_ON_OR_AFTER:01/28/2023', + 'IS_ON_OR_AFTER:2023-01-28', ); expect(afterBody).toMatchObject({ features: [{ name: 'my_feature_b' }], @@ -861,7 +861,7 @@ test('should filter features by combined operators', async () => { const { body } = await filterFeaturesByOperators( 'IS_NOT:active', 'DO_NOT_INCLUDE:simple:my_tag', - 'IS_BEFORE:01/28/2023', + 'IS_BEFORE:2023-01-28', ); expect(body).toMatchObject({ features: [{ name: 'my_feature_a' }], diff --git a/src/lib/openapi/spec/feature-search-query-parameters.ts b/src/lib/openapi/spec/feature-search-query-parameters.ts index 6519b2f613..346f585bdf 100644 --- a/src/lib/openapi/spec/feature-search-query-parameters.ts +++ b/src/lib/openapi/spec/feature-search-query-parameters.ts @@ -137,8 +137,8 @@ export const featureSearchQueryParameters = [ name: 'createdAt', schema: { type: 'string', - example: 'IS_ON_OR_AFTER:28/01/2023', - pattern: '^(IS_BEFORE|IS_ON_OR_AFTER):\\d{2}\\/\\d{2}\\/\\d{4}$', + example: 'IS_ON_OR_AFTER:2023-01-28', + pattern: '^(IS_BEFORE|IS_ON_OR_AFTER):\\d{4}-\\d{2}-\\d{2}$', }, description: 'The date the feature was created. The date can be specified with an operator. The supported operators are IS_BEFORE, IS_ON_OR_AFTER.',