diff --git a/src/services/hooks/useTableFilter.tsx b/src/services/hooks/useTableFilter.tsx index 17b875f0..43fc173c 100644 --- a/src/services/hooks/useTableFilter.tsx +++ b/src/services/hooks/useTableFilter.tsx @@ -1,4 +1,5 @@ -import { useCallback, useMemo, useReducer } from 'react'; +import { useCallback, useEffect, useMemo, useReducer } from 'react'; +import { useTableFilterStore } from '@/stores/table/table-filter.store'; /** Core filter shape (page + pageSize) extended by your custom fields */ export type TableFilterState> = { @@ -30,6 +31,9 @@ export type UseTableFilterOptions> = { paramMap?: Partial, string>>; /** If true, `toSearchParams`/`toQueryString` will omit values equal to defaults */ omitDefaultsInUrl?: boolean; + + persist?: boolean; + storeName?: string; }; function clampToInt(n: number, min = 1) { @@ -90,9 +94,37 @@ function shallowEqual>( export function useTableFilter>( options?: UseTableFilterOptions ) { - const defaults = useMemo( - () => createInitialState(options), - [options] + if (options?.persist && !options?.storeName) { + throw new Error( + 'storeName is required if persist is true in useTableFilter!' + ); + } + + const storeName = options?.storeName ?? ''; + const persistedState = useTableFilterStore( + useCallback( + (storeState) => + storeName + ? (storeState.data[storeName] as Partial>) + : undefined, + [storeName] + ) + ); + const setTableData = useTableFilterStore( + (storeState) => storeState.setTableData + ); + + const defaults = useMemo(() => { + return createInitialState(options); + }, [options]); + + const initialState = useMemo( + () => + ({ + ...defaults, + ...(persistedState as object), + }) as TableFilterState, + [defaults, persistedState] ); const [state, dispatch] = useReducer( @@ -106,15 +138,22 @@ export function useTableFilter>( case 'SET_PAGE_SIZE': { const pageSize = clampToInt(a.pageSize); const page = a.resetPage ? 1 : s.page; + return { ...s, pageSize, page }; } case 'SET_FILTERS': { const page = a.resetPage ? 1 : s.page; + return { ...s, ...a.filters, page }; } case 'UPDATE_FILTER': { const page = a.resetPage ? 1 : s.page; - return { ...s, [a.key]: a.value, page } as TableFilterState; + + return { + ...s, + [a.key]: a.value, + page, + } as TableFilterState; } case 'REPLACE_ALL': return { @@ -128,12 +167,19 @@ export function useTableFilter>( return s; } }, - defaults + initialState ); - // Notify consumer on change (stable ref) + useEffect(() => { + if (!options?.persist || !storeName) { + return; + } + + setTableData(storeName, state); + }, [options?.persist, setTableData, state, storeName]); + const onChange = options?.onChange; - useMemo(() => { + useEffect(() => { if (onChange) onChange(state); }, [state, onChange]);