import { useCallback, useMemo } from 'react' import type { TableRow, SortDirection, SortState, TableWidgetState, } from '../types' import { sortData } from '../helpers' import { widgetStoreActions } from '../../stores/widget-store' import { useWidgetSelector } from '../../stores/use-widget-selector' import { DEFAULT_COLUMN_ID, DEFAULT_DIRECTION } from '../config' export interface UseSortResult extends SortState { /** Whether sorting is enabled */ sortEnabled: boolean /** Current sort state */ columnId: string | null direction: SortDirection /** Sorted data (for local mode) */ sortedData: T[] /** Toggle sort on a column */ toggleSort: (columnId: string) => void /** Set sort state directly */ setSort: (columnId: string | null, direction: SortDirection) => void /** Clear sort */ clearSort: () => void } /** * Hook for managing table sorting with support for both local (client-side) and remote (server-side) modes. * State is persisted in the widget store for the given widget ID. * * @param widgetId - The widget ID to persist sort state under. * @param data - The data array to sort (for local mode). * @returns Sort state, sorted data, and sort control functions. * * @example * ```tsx * const { sortedData, sortField, sortDirection, handleSort } = useSort(widgetId, data) * ``` */ export function useSort( widgetId: string, data: T[], ): UseSortResult { // Get store state const { sortEnabled, columnId, direction, mode } = useWidgetSelector( widgetId, (w) => { const widget = w as TableWidgetState | undefined return { sortEnabled: !!widget?.sort, columnId: widget?.sort?.columnId ?? DEFAULT_COLUMN_ID, direction: widget?.sort?.direction ?? DEFAULT_DIRECTION, mode: widget?.mode, } }, ) // Toggle sort on a column const toggleSort = useCallback( (toggleColumnId: string) => { // Read current state directly from store to avoid stale closures const widget = widgetStoreActions.getWidget(widgetId) const currentColumnId = widget?.sort?.columnId ?? DEFAULT_COLUMN_ID const currentDirection = widget?.sort?.direction ?? DEFAULT_DIRECTION let newDirection: SortDirection = 'asc' if (currentColumnId === toggleColumnId) { // Same column - toggle direction newDirection = currentDirection === 'asc' ? 'desc' : 'asc' } widgetStoreActions.setWidget(widgetId, { sort: { columnId: toggleColumnId, direction: newDirection, }, }) }, [widgetId], ) // Set sort state directly const setSort = useCallback( (newColumnId: string | null, newDirection: SortDirection) => { widgetStoreActions.setWidget(widgetId, { sort: { columnId: newColumnId, direction: newDirection, }, }) }, [widgetId], ) // Clear sort const clearSort = useCallback(() => { const widget = widgetStoreActions.getWidget(widgetId) if (!widget?.sort) return widgetStoreActions.setWidget(widgetId, { sort: { ...widget.sort, columnId: null, direction: 'asc', }, }) }, [widgetId]) // Sorted data for local mode const sortedData = useMemo(() => { if (mode === 'remote' || !columnId || !sortEnabled) { // For remote mode, data is already sorted from server // If no sort column, return original data return data } return sortData(data, columnId, direction) }, [data, mode, columnId, direction, sortEnabled]) return { sortEnabled, columnId, direction, sortedData, toggleSort, setSort, clearSort, } }