import { useCallback, useMemo, useState } from 'react'; export type SortDirection = 'asc' | 'desc'; export type SortState = { field: string; direction: SortDirection; }; function invertDirection(direction: SortDirection): SortDirection { return direction === 'asc' ? 'desc' : 'asc'; } export function formatSortParam(sort: SortState | null | undefined): string | undefined { if (!sort) { return undefined; } return sort.direction === 'desc' ? `-${sort.field}` : sort.field; } type UseSortingResult = { activeSort: SortState | null; sortParam: string | undefined; toggleSort: (field: string) => void; setSort: (next: SortState | null) => void; resetSort: () => void; }; export function useSorting(defaultSort?: SortState | null): UseSortingResult { const [overrideSort, setOverrideSort] = useState(null); const activeSort = overrideSort ?? defaultSort ?? null; const toggleSort = useCallback( (field: string) => { setOverrideSort((previousOverride) => { const baselineSort = defaultSort ?? null; const currentSort = previousOverride ?? baselineSort; if (!currentSort || currentSort.field !== field) { return { field, direction: 'asc' }; } if (baselineSort && baselineSort.field === field) { if (previousOverride == null) { return { field, direction: invertDirection(baselineSort.direction) }; } if (previousOverride.direction === baselineSort.direction) { return { field, direction: invertDirection(baselineSort.direction) }; } return null; } if (previousOverride == null || previousOverride.direction === 'desc') { return null; } return { field, direction: 'desc' }; }); }, [defaultSort], ); const setSort = useCallback((next: SortState | null) => { setOverrideSort(next); }, []); const resetSort = useCallback(() => { setOverrideSort(null); }, []); const sortParam = useMemo(() => formatSortParam(activeSort), [activeSort]); return { activeSort, sortParam, toggleSort, setSort, resetSort, }; }