'use client' import { useState, useEffect, useCallback, useRef } from 'react' import { ColumnVisibilityState, SortState } from '../types' interface TablePreferences { columnVisibility: ColumnVisibilityState columnOrder: string[] | null defaultSortColumn: string | null defaultSortDirection: 'asc' | 'desc' | null pageSize: number } interface UseTablePreferencesOptions { tableId: string enabled?: boolean defaultColumnVisibility?: ColumnVisibilityState defaultPageSize?: number debounceMs?: number // Custom fetch function for API calls // Applications should provide their own apiFetch implementation apiFetch?: typeof fetch } interface UseTablePreferencesReturn { preferences: TablePreferences | null isLoading: boolean error: Error | null updateColumnVisibility: (visibility: ColumnVisibilityState) => void updateColumnOrder: (order: string[]) => void updateSortPreference: (sort: SortState) => void updatePageSize: (size: number) => void resetPreferences: () => Promise } export function useTablePreferences({ tableId, enabled = true, defaultColumnVisibility = {}, defaultPageSize = 25, debounceMs = 500, apiFetch = fetch // Default to native fetch if not provided }: UseTablePreferencesOptions): UseTablePreferencesReturn { const [preferences, setPreferences] = useState(null) const [isLoading, setIsLoading] = useState(true) const [error, setError] = useState(null) const saveTimeoutRef = useRef(null) const pendingUpdatesRef = useRef>({}) // Load preferences on mount useEffect(() => { if (!enabled) { setIsLoading(false) return } const loadPreferences = async () => { try { const response = await apiFetch(`/api/v1/table-preferences/?tableId=${encodeURIComponent(tableId)}`) if (!response.ok) { throw new Error('Failed to load table preferences') } const data = await response.json() if (data) { setPreferences(data) } else { // Use defaults if no saved preferences setPreferences({ columnVisibility: defaultColumnVisibility, columnOrder: null, defaultSortColumn: null, defaultSortDirection: null, pageSize: defaultPageSize }) } } catch (err) { console.error('Error loading table preferences:', err) setError(err instanceof Error ? err : new Error('Unknown error')) // Fall back to defaults on error setPreferences({ columnVisibility: defaultColumnVisibility, columnOrder: null, defaultSortColumn: null, defaultSortDirection: null, pageSize: defaultPageSize }) } finally { setIsLoading(false) } } loadPreferences() }, [tableId, enabled, defaultPageSize]) // Debounced save function const savePreferences = useCallback(async (updates: Partial) => { // Merge with pending updates pendingUpdatesRef.current = { ...pendingUpdatesRef.current, ...updates } // Clear existing timeout if (saveTimeoutRef.current) { clearTimeout(saveTimeoutRef.current) } // Set new debounced timeout saveTimeoutRef.current = setTimeout(async () => { const updatesToSave = { ...pendingUpdatesRef.current } pendingUpdatesRef.current = {} try { const response = await apiFetch('/api/v1/table-preferences/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tableId, ...updatesToSave }) }) if (!response.ok) { throw new Error('Failed to save table preferences') } } catch (err) { console.error('Error saving table preferences:', err) // Don't update error state for save failures - user can continue working } }, debounceMs) }, [tableId, debounceMs]) // Cleanup timeout on unmount useEffect(() => { return () => { if (saveTimeoutRef.current) { clearTimeout(saveTimeoutRef.current) } } }, []) const updateColumnVisibility = useCallback((visibility: ColumnVisibilityState) => { setPreferences(prev => prev ? { ...prev, columnVisibility: visibility } : null) savePreferences({ columnVisibility: visibility }) }, [savePreferences]) const updateColumnOrder = useCallback((order: string[]) => { setPreferences(prev => prev ? { ...prev, columnOrder: order } : null) savePreferences({ columnOrder: order }) }, [savePreferences]) const updateSortPreference = useCallback((sort: SortState) => { setPreferences(prev => prev ? { ...prev, defaultSortColumn: sort.sortBy, defaultSortDirection: sort.sortDirection } : null) savePreferences({ defaultSortColumn: sort.sortBy, defaultSortDirection: sort.sortDirection }) }, [savePreferences]) const updatePageSize = useCallback((size: number) => { setPreferences(prev => prev ? { ...prev, pageSize: size } : null) savePreferences({ pageSize: size }) }, [savePreferences]) const resetPreferences = useCallback(async () => { try { const response = await apiFetch(`/api/v1/table-preferences/?tableId=${encodeURIComponent(tableId)}`, { method: 'DELETE' }) if (!response.ok) { throw new Error('Failed to reset table preferences') } setPreferences({ columnVisibility: defaultColumnVisibility, columnOrder: null, defaultSortColumn: null, defaultSortDirection: null, pageSize: defaultPageSize }) } catch (err) { console.error('Error resetting table preferences:', err) throw err } }, [tableId, defaultColumnVisibility, defaultPageSize]) return { preferences, isLoading, error, updateColumnVisibility, updateColumnOrder, updateSortPreference, updatePageSize, resetPreferences } }