mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
fix: create TableFilterStateValue type
This commit is contained in:
@@ -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<number>
|
||||
| OptionType<number>[]
|
||||
| OptionType<string>
|
||||
| OptionType<string>[];
|
||||
|
||||
/** Core filter shape (page + pageSize) extended by your custom fields */
|
||||
export type TableFilterState<TExtra extends Record<string, unknown>> = {
|
||||
export type TableFilterState<
|
||||
TExtra extends Record<string, TableFilterStateValue>,
|
||||
> = {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
} & TExtra;
|
||||
|
||||
type Action<TExtra extends Record<string, unknown>> =
|
||||
type Action<TExtra extends Record<string, TableFilterStateValue>> =
|
||||
| { type: 'SET_PAGE'; page: number }
|
||||
| { type: 'SET_PAGE_SIZE'; pageSize: number; resetPage?: boolean }
|
||||
| { type: 'SET_FILTERS'; filters: Partial<TExtra>; resetPage?: boolean }
|
||||
@@ -20,7 +36,9 @@ type Action<TExtra extends Record<string, unknown>> =
|
||||
| { type: 'REPLACE_ALL'; next: TableFilterState<TExtra> }
|
||||
| { type: 'RESET' };
|
||||
|
||||
export type UseTableFilterOptions<TExtra extends Record<string, unknown>> = {
|
||||
export type UseTableFilterOptions<
|
||||
TExtra extends Record<string, TableFilterStateValue>,
|
||||
> = {
|
||||
/** Initial state; anything you omit falls back to defaults */
|
||||
initial?: Partial<TableFilterState<TExtra>>;
|
||||
/** Called after any state change */
|
||||
@@ -43,9 +61,9 @@ function clampToInt(n: number, min = 1) {
|
||||
return v < min ? min : v;
|
||||
}
|
||||
|
||||
function createInitialState<TExtra extends Record<string, unknown>>(
|
||||
opts: UseTableFilterOptions<TExtra> | undefined
|
||||
): TableFilterState<TExtra> {
|
||||
function createInitialState<
|
||||
TExtra extends Record<string, TableFilterStateValue>,
|
||||
>(opts: UseTableFilterOptions<TExtra> | undefined): TableFilterState<TExtra> {
|
||||
const defaults = {
|
||||
page: 1,
|
||||
pageSize: opts?.defaultPageSize ?? 10,
|
||||
@@ -59,10 +77,22 @@ function createInitialState<TExtra extends Record<string, unknown>>(
|
||||
|
||||
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<T extends Record<string, unknown>>(
|
||||
function shallowEqual<T extends TableFilterStateValue>(
|
||||
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<TExtra extends Record<string, unknown>>(
|
||||
options?: UseTableFilterOptions<TExtra>
|
||||
) {
|
||||
export function useTableFilter<
|
||||
TExtra extends Record<string, TableFilterStateValue>,
|
||||
>(options?: UseTableFilterOptions<TExtra>) {
|
||||
if (options?.persist && !options?.storeName) {
|
||||
throw new Error(
|
||||
'storeName is required if persist is true in useTableFilter!'
|
||||
@@ -220,7 +234,9 @@ export function useTableFilter<TExtra extends Record<string, unknown>>(
|
||||
);
|
||||
|
||||
const extras = useMemo(() => {
|
||||
const stateWithExtras = state as TableFilterState<Record<string, unknown>>;
|
||||
const stateWithExtras = state as TableFilterState<
|
||||
Record<string, TableFilterStateValue>
|
||||
>;
|
||||
const rest = Object.fromEntries(
|
||||
Object.entries(stateWithExtras).filter(
|
||||
([key]) => key !== 'page' && key !== 'pageSize'
|
||||
@@ -241,10 +257,8 @@ export function useTableFilter<TExtra extends Record<string, unknown>>(
|
||||
/** Build URLSearchParams from current state */
|
||||
const toSearchParams = useCallback(() => {
|
||||
const params = new URLSearchParams();
|
||||
const source = state as Record<string, unknown>;
|
||||
const baseline = options?.omitDefaultsInUrl
|
||||
? (defaults as Record<string, unknown>)
|
||||
: null;
|
||||
const source = state as Record<string, TableFilterStateValue>;
|
||||
const baseline = options?.omitDefaultsInUrl ? defaults : null;
|
||||
const excludedKeys = new Set<string>(
|
||||
(options?.excludeKeysFromUrl as string[] | undefined) ?? []
|
||||
);
|
||||
@@ -255,13 +269,7 @@ export function useTableFilter<TExtra extends Record<string, unknown>>(
|
||||
const value = source[key];
|
||||
if (value === undefined || value === null) continue;
|
||||
|
||||
if (
|
||||
baseline &&
|
||||
shallowEqual(
|
||||
value as Record<string, unknown>,
|
||||
baseline[key] as Record<string, unknown>
|
||||
)
|
||||
) {
|
||||
if (baseline && shallowEqual(value, baseline[key])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user