diff --git a/packages/admin/dashboard/src/components/data-table/data-table.tsx b/packages/admin/dashboard/src/components/data-table/data-table.tsx index cb641625f2ee9..e4c708018b7c1 100644 --- a/packages/admin/dashboard/src/components/data-table/data-table.tsx +++ b/packages/admin/dashboard/src/components/data-table/data-table.tsx @@ -91,7 +91,8 @@ export const DataTable = ({ const enableCommands = commands && commands.length > 0 const enableSorting = columns.some((column) => column.enableSorting) - const filterIds = filters?.map((f) => getQueryParamKey(f.id, prefix)) ?? [] + const filterIds = filters?.map((f) => f.id) ?? [] + const prefixedFilterIds = filterIds.map((id) => getQueryParamKey(id, prefix)) const { offset, order, q, ...filterParams } = useQueryParams( [ @@ -145,13 +146,16 @@ export const DataTable = ({ setSearchParams((prev) => { Array.from(prev.keys()).forEach((key) => { - if (filterIds.includes(key) && !(key in value)) { + if (prefixedFilterIds.includes(key) && !(key in value)) { prev.delete(key) } }) Object.entries(value).forEach(([key, filter]) => { - if (filterIds.includes(key) && filter.value) { + if ( + prefixedFilterIds.includes(getQueryParamKey(key, prefix)) && + filter.value + ) { prev.set(getQueryParamKey(key, prefix), JSON.stringify(filter.value)) } }) diff --git a/packages/admin/dashboard/src/i18n/translations/$schema.json b/packages/admin/dashboard/src/i18n/translations/$schema.json index 85a02345b202a..c3eb1fa6bb159 100644 --- a/packages/admin/dashboard/src/i18n/translations/$schema.json +++ b/packages/admin/dashboard/src/i18n/translations/$schema.json @@ -1242,6 +1242,12 @@ }, "to": { "type": "string" + }, + "starting": { + "type": "string" + }, + "ending": { + "type": "string" } }, "required": [ @@ -1252,7 +1258,9 @@ "lastTwelveMonths", "custom", "from", - "to" + "to", + "starting", + "ending" ], "additionalProperties": false }, diff --git a/packages/admin/dashboard/src/i18n/translations/en.json b/packages/admin/dashboard/src/i18n/translations/en.json index 4ebf7dcd5f390..a870460081a51 100644 --- a/packages/admin/dashboard/src/i18n/translations/en.json +++ b/packages/admin/dashboard/src/i18n/translations/en.json @@ -305,7 +305,9 @@ "lastTwelveMonths": "Last 12 months", "custom": "Custom", "from": "From", - "to": "To" + "to": "To", + "starting": "Starting", + "ending": "Ending" }, "compare": { "lessThan": "Less than", diff --git a/packages/admin/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/customer-group-list-table.tsx b/packages/admin/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/customer-group-list-table.tsx index 560377921cecc..7b552c6c82673 100644 --- a/packages/admin/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/customer-group-list-table.tsx +++ b/packages/admin/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/customer-group-list-table.tsx @@ -215,6 +215,7 @@ const useDateFilterOptions = () => { const useFilters = () => { const { t } = useTranslation() + const { getFullDate } = useDate() const dateFilterOptions = useDateFilterOptions() return useMemo(() => { @@ -223,14 +224,22 @@ const useFilters = () => { type: "date", label: t("fields.createdAt"), format: "date", + formatDateValue: (date) => getFullDate({ date }), + rangeOptionStartLabel: t("filters.date.starting"), + rangeOptionEndLabel: t("filters.date.ending"), + rangeOptionLabel: t("filters.date.custom"), options: dateFilterOptions, }), filterHelper.accessor("updated_at", { type: "date", label: t("fields.updatedAt"), format: "date", + rangeOptionStartLabel: t("filters.date.starting"), + rangeOptionEndLabel: t("filters.date.ending"), + rangeOptionLabel: t("filters.date.custom"), + formatDateValue: (date) => getFullDate({ date }), options: dateFilterOptions, }), ] - }, [t, dateFilterOptions]) + }, [t, dateFilterOptions, getFullDate]) } diff --git a/packages/design-system/ui/src/blocks/data-table/components/data-table-filter.tsx b/packages/design-system/ui/src/blocks/data-table/components/data-table-filter.tsx index 1000d066b32f8..065f5d2d1c10c 100644 --- a/packages/design-system/ui/src/blocks/data-table/components/data-table-filter.tsx +++ b/packages/design-system/ui/src/blocks/data-table/components/data-table-filter.tsx @@ -8,6 +8,7 @@ import { DropdownMenu } from "@/components/dropdown-menu" import { clx } from "@/utils/clx" import { DatePicker } from "../../../components/date-picker" +import { Label } from "../../../components/label" import { useDataTableContext } from "../context/use-data-table-context" import { DateComparisonOperator, DateFilterProps, FilterOption } from "../types" import { isDateComparisonOperator } from "../utils/is-date-comparison-operator" @@ -16,9 +17,20 @@ interface DataTableFilterProps { filter: ColumnFilter } +const DEFAULT_FORMAT_DATE_VALUE = (d: Date) => + d.toLocaleDateString(undefined, { + year: "numeric", + month: "short", + day: "numeric", + }) +const DEFAULT_RANGE_OPTION_LABEL = "Custom" +const DEFAULT_RANGE_OPTION_START_LABEL = "Starting" +const DEFAULT_RANGE_OPTION_END_LABEL = "Ending" + const DataTableFilter = ({ filter }: DataTableFilterProps) => { const { instance } = useDataTableContext() const [open, setOpen] = React.useState(filter.value === undefined) + const [isCustom, setIsCustom] = React.useState(false) const onOpenChange = React.useCallback( (open: boolean) => { @@ -62,12 +74,37 @@ const DataTableFilter = ({ filter }: DataTableFilterProps) => { } return ( + !isCustom && (value.$gte === o.value.$gte || (!value.$gte && !o.value.$gte)) && (value.$lte === o.value.$lte || (!value.$lte && !o.value.$lte)) && (value.$gt === o.value.$gt || (!value.$gt && !o.value.$gt)) && (value.$lt === o.value.$lt || (!value.$lt && !o.value.$lt)) ) })?.label ?? null + + if (!displayValue && isDateFilterProps(meta)) { + const formatDateValue = meta.formatDateValue + ? meta.formatDateValue + : DEFAULT_FORMAT_DATE_VALUE + + if (value.$gte && !value.$lte) { + displayValue = `${ + meta.rangeOptionStartLabel || DEFAULT_RANGE_OPTION_START_LABEL + } ${formatDateValue(new Date(value.$gte))}` + } + + if (value.$lte && !value.$gte) { + displayValue = `${ + meta.rangeOptionEndLabel || DEFAULT_RANGE_OPTION_END_LABEL + } ${formatDateValue(new Date(value.$lte))}` + } + + if (value.$gte && value.$lte) { + displayValue = `${formatDateValue( + new Date(value.$gte) + )} - ${formatDateValue(new Date(value.$lte))}` + } + } } return displayValue @@ -137,6 +174,7 @@ const DataTableFilter = ({ filter }: DataTableFilterProps) => { []} + setIsCustom={setIsCustom} {...rest} /> ) @@ -152,7 +190,15 @@ const DataTableFilter = ({ filter }: DataTableFilterProps) => { type DataTableFilterDateContentProps = { filter: ColumnFilter options: FilterOption[] -} & Pick + setIsCustom: (isCustom: boolean) => void +} & Pick< + DateFilterProps, + | "format" + | "rangeOptionLabel" + | "disableRangeOption" + | "rangeOptionStartLabel" + | "rangeOptionEndLabel" +> function getIsCustomOptionSelected( options: FilterOption[], @@ -171,15 +217,18 @@ function getIsCustomOptionSelected( return false } - return value.$gte || value.$lte + return !!value.$gte || !!value.$lte } const DataTableFilterDateContent = ({ filter, options, format = "date", - rangeOptionLabel = "Custom", + rangeOptionLabel = DEFAULT_RANGE_OPTION_LABEL, + rangeOptionStartLabel = DEFAULT_RANGE_OPTION_START_LABEL, + rangeOptionEndLabel = DEFAULT_RANGE_OPTION_END_LABEL, disableRangeOption = false, + setIsCustom, }: DataTableFilterDateContentProps) => { const currentValue = filter.value as DateComparisonOperator | undefined const { instance } = useDataTableContext() @@ -188,13 +237,17 @@ const DataTableFilterDateContent = ({ getIsCustomOptionSelected(options, currentValue) ) + React.useEffect(() => { + setIsCustom(showCustom) + }, [showCustom]) + const selectedValue = React.useMemo(() => { - if (!currentValue) { + if (!currentValue || showCustom) { return undefined } return JSON.stringify(currentValue) - }, [currentValue]) + }, [currentValue, showCustom]) const onValueChange = React.useCallback( (valueStr: string) => { @@ -268,19 +321,31 @@ const DataTableFilterDateContent = ({ {!disableRangeOption && showCustom && ( -
- onCustomValueChange("$gte", value)} - maxValue={maxDate} - /> - onCustomValueChange("$lte", value)} - minValue={minDate} - /> +
+
+ + onCustomValueChange("$gte", value)} + maxValue={maxDate} + /> +
+
+ + onCustomValueChange("$lte", value)} + minValue={minDate} + /> +
)} @@ -375,5 +440,13 @@ const DataTableFilterRadioContent = ({ ) } +function isDateFilterProps(props?: unknown | null): props is DateFilterProps { + if (!props) { + return false + } + + return (props as DateFilterProps).type === "date" +} + export { DataTableFilter } export type { DataTableFilterProps } diff --git a/packages/design-system/ui/src/blocks/data-table/types.ts b/packages/design-system/ui/src/blocks/data-table/types.ts index d77390b01a10e..2460f454eb016 100644 --- a/packages/design-system/ui/src/blocks/data-table/types.ts +++ b/packages/design-system/ui/src/blocks/data-table/types.ts @@ -124,7 +124,10 @@ export interface DateFilterProps extends BaseFilterProps { */ format?: "date" | "date-time" rangeOptionLabel?: string + rangeOptionStartLabel?: string + rangeOptionEndLabel?: string disableRangeOption?: boolean + formatDateValue?: (value: Date) => string options: FilterOption[] }