From 5855ce33d4e7fb91add0996100db746e32ba28b9 Mon Sep 17 00:00:00 2001 From: AmirReza Jamali Date: Mon, 11 May 2026 16:42:49 +0330 Subject: [PATCH] feat(date-picker): add clearable option and enhance date handling - Introduced a clearable option for the DatePicker component, allowing users to easily reset the selected date. - Enhanced date handling logic to support conversion from Unix timestamps and improved value management for single and range selections. - Updated TenderListFilters to utilize the clearable feature in multiple DatePicker instances for better user experience. - Refactored useTenderListPresenter to manage date range filters more effectively, ensuring proper cleanup of cleared values. --- .../FormElements/DatePicker/DatePicker.tsx | 80 ++++++++++++- .../Tables/tenders/TenderListFilters.tsx | 36 +----- .../Tables/tenders/useTenderListPresenter.ts | 113 +++++++++++++++++- 3 files changed, 194 insertions(+), 35 deletions(-) diff --git a/src/components/FormElements/DatePicker/DatePicker.tsx b/src/components/FormElements/DatePicker/DatePicker.tsx index 2db5842..5c487d6 100644 --- a/src/components/FormElements/DatePicker/DatePicker.tsx +++ b/src/components/FormElements/DatePicker/DatePicker.tsx @@ -24,6 +24,7 @@ interface IProps { minDate?: number; maxDate?: number; timePicker?: boolean; + clearable?: boolean; rules?: Omit< RegisterOptions>, "valueAsNumber" | "valueAsDate" | "setValueAs" | "disabled" @@ -44,6 +45,7 @@ const DatePicker = ({ rules, maxDate, minDate, + clearable = false, }: IProps) => { return (
@@ -66,6 +68,50 @@ const DatePicker = ({ }) => { const error = errors[name]; + const toUnixSeconds = (v: unknown): number | null => { + if (v === "" || v === undefined || v === null) return null; + const n = typeof v === "number" ? v : Number(v); + return Number.isFinite(n) ? n : null; + }; + + const toPickerValue = (): + | DateObject + | DateObject[] + | undefined => { + if (value === "" || value === undefined || value === null) { + return undefined; + } + + if (multiple && Array.isArray(value)) { + const secs = value + .map(toUnixSeconds) + .filter((s): s is number => s !== null); + if (!secs.length) return undefined; + return secs.map((unix) => new DateObject(new Date(unix * 1000))); + } + + if (range && Array.isArray(value)) { + const secs = value + .map(toUnixSeconds) + .filter((s): s is number => s !== null); + if (!secs.length) return undefined; + return secs.map((unix) => new DateObject(new Date(unix * 1000))); + } + + if (range && !Array.isArray(value)) { + return undefined; + } + + const unix = toUnixSeconds(value); + if (unix === null) return undefined; + return new DateObject(new Date(unix * 1000)); + }; + + const pickerValue = toPickerValue(); + const hasValue = + pickerValue !== undefined && + (Array.isArray(pickerValue) ? pickerValue.length > 0 : true); + return ( <>
@@ -81,9 +127,11 @@ const DatePicker = ({ } onlyYearPicker={onlyYearPicker} multiple={multiple} + value={pickerValue} onChange={(date: DateObject | DateObject[] | null) => { if (!date) { - return onChange(""); + onChange(""); + return; } if (Array.isArray(date)) { @@ -97,6 +145,7 @@ const DatePicker = ({ containerClassName="w-full" inputClass={cn( "w-full rounded-xl border border-stroke/70 bg-white/90 px-5.5 py-3 pl-12.5 text-dark shadow-[0_1px_2px_rgba(16,24,40,0.04),0_8px_20px_rgba(16,24,40,0.04)] outline-none backdrop-blur-[1px] transition-all duration-200 focus:border-primary/70 focus:bg-white focus:shadow-[0_0_0_2px_rgba(59,130,246,0.14),0_10px_24px_rgba(59,130,246,0.08)] disabled:cursor-default disabled:bg-gray-2/70 dark:border-dark-3/80 dark:bg-dark-2/85 dark:text-white dark:focus:border-primary/80 dark:focus:shadow-[0_0_0_2px_rgba(59,130,246,0.2),0_10px_24px_rgba(15,23,42,0.45)] dark:disabled:bg-dark", + clearable && hasValue && "pr-11", error && "border-red/80 focus:border-red focus:shadow-[0_0_0_2px_rgba(239,68,68,0.16),0_10px_24px_rgba(239,68,68,0.1)] dark:border-red/80 dark:focus:shadow-[0_0_0_2px_rgba(239,68,68,0.24),0_10px_24px_rgba(127,29,29,0.45)]", )} @@ -105,6 +154,35 @@ const DatePicker = ({ + {clearable && hasValue && ( + + )}
{error && ( diff --git a/src/components/Tables/tenders/TenderListFilters.tsx b/src/components/Tables/tenders/TenderListFilters.tsx index d188234..74f08a1 100644 --- a/src/components/Tables/tenders/TenderListFilters.tsx +++ b/src/components/Tables/tenders/TenderListFilters.tsx @@ -1,11 +1,6 @@ import DatePicker from "@/components/FormElements/DatePicker/DatePicker"; import InputGroup from "@/components/FormElements/InputGroup"; -import { Select } from "@/components/FormElements/select"; import { Button } from "@/components/ui-elements/button"; -import { Countries } from "@/constants/countries"; -import { TenderStatus } from "@/constants/enums"; -import { Languages } from "@/constants/languages"; -import { getEnumAsArray } from "@/utils/shared"; import { Control, FieldValues, @@ -59,30 +54,14 @@ const TenderListFilters = ({ label="description" type="text" /> - setValue("country_code", undefined)} - /> + -