From 29347c24f489ad5bbab8192ab259f3b74f41f4d0 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Wed, 29 Apr 2026 15:10:25 +0700 Subject: [PATCH] fix: create TableFilterStateValue type --- src/services/hooks/useTableFilter.tsx | 88 +++++++++++++++------------ 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/src/services/hooks/useTableFilter.tsx b/src/services/hooks/useTableFilter.tsx index 5db57bcb..ad9c6679 100644 --- a/src/services/hooks/useTableFilter.tsx +++ b/src/services/hooks/useTableFilter.tsx @@ -1,13 +1,29 @@ import { useCallback, useEffect, useMemo, useReducer } from 'react'; import { useTableFilterStore } from '@/stores/table/table-filter.store'; +import { OptionType } from '@/components/input/SelectInput'; + +type TableFilterStateValue = + | undefined + | null + | boolean + | string + | string[] + | number + | number[] + | OptionType + | OptionType[] + | OptionType + | OptionType[]; /** Core filter shape (page + pageSize) extended by your custom fields */ -export type TableFilterState> = { +export type TableFilterState< + TExtra extends Record, +> = { page: number; pageSize: number; } & TExtra; -type Action> = +type Action> = | { type: 'SET_PAGE'; page: number } | { type: 'SET_PAGE_SIZE'; pageSize: number; resetPage?: boolean } | { type: 'SET_FILTERS'; filters: Partial; resetPage?: boolean } @@ -20,7 +36,9 @@ type Action> = | { type: 'REPLACE_ALL'; next: TableFilterState } | { type: 'RESET' }; -export type UseTableFilterOptions> = { +export type UseTableFilterOptions< + TExtra extends Record, +> = { /** Initial state; anything you omit falls back to defaults */ initial?: Partial>; /** Called after any state change */ @@ -43,9 +61,9 @@ function clampToInt(n: number, min = 1) { return v < min ? min : v; } -function createInitialState>( - opts: UseTableFilterOptions | undefined -): TableFilterState { +function createInitialState< + TExtra extends Record, +>(opts: UseTableFilterOptions | undefined): TableFilterState { const defaults = { page: 1, pageSize: opts?.defaultPageSize ?? 10, @@ -59,10 +77,22 @@ function createInitialState>( function serializeValue(v: unknown): string | null { if (v === undefined || v === null) return null; + if (v instanceof Date) return v.toISOString(); - if (Array.isArray(v)) return v.map((x) => x ?? '').join(','); // e.g., ids=1,2,3 + + if (v instanceof Object && (v as OptionType).value) + return String((v as OptionType).value); + + if (Array.isArray(v)) + return v + .map((x) => serializeValue(x)) + .filter((x) => x !== null) + .join(','); + const t = typeof v; + if (t === 'string' || t === 'number' || t === 'boolean') return String(v); + try { return JSON.stringify(v); } catch { @@ -70,32 +100,16 @@ function serializeValue(v: unknown): string | null { } } -// function shallowEqual(a: unknown, b: unknown): boolean { -// if (a === b) return true; -// if (!a || !b) return false; -// const ka = Object.keys(a); -// const kb = Object.keys(b); -// if (ka.length !== kb.length) return false; -// for (const k of ka) if (a[k] !== b[k]) return false; -// return true; -// } - -function shallowEqual>( +function shallowEqual( a: T | undefined | null, b: T | undefined | null ): boolean { - if (a === b) return true; - if (!a || !b) return false; - const ka = Object.keys(a) as (keyof T)[]; - const kb = Object.keys(b) as (keyof T)[]; - if (ka.length !== kb.length) return false; - for (const k of ka) if (a[k] !== b[k]) return false; - return true; + return JSON.stringify(a) === JSON.stringify(b); } -export function useTableFilter>( - options?: UseTableFilterOptions -) { +export function useTableFilter< + TExtra extends Record, +>(options?: UseTableFilterOptions) { if (options?.persist && !options?.storeName) { throw new Error( 'storeName is required if persist is true in useTableFilter!' @@ -220,7 +234,9 @@ export function useTableFilter>( ); const extras = useMemo(() => { - const stateWithExtras = state as TableFilterState>; + const stateWithExtras = state as TableFilterState< + Record + >; const rest = Object.fromEntries( Object.entries(stateWithExtras).filter( ([key]) => key !== 'page' && key !== 'pageSize' @@ -241,10 +257,8 @@ export function useTableFilter>( /** Build URLSearchParams from current state */ const toSearchParams = useCallback(() => { const params = new URLSearchParams(); - const source = state as Record; - const baseline = options?.omitDefaultsInUrl - ? (defaults as Record) - : null; + const source = state as Record; + const baseline = options?.omitDefaultsInUrl ? defaults : null; const excludedKeys = new Set( (options?.excludeKeysFromUrl as string[] | undefined) ?? [] ); @@ -255,13 +269,7 @@ export function useTableFilter>( const value = source[key]; if (value === undefined || value === null) continue; - if ( - baseline && - shallowEqual( - value as Record, - baseline[key] as Record - ) - ) { + if (baseline && shallowEqual(value, baseline[key])) { continue; }