import { ReactNode } from 'react' import { LucideIcon } from 'lucide-react' // Core table configuration export interface UnifiedTableProps { // Data & Columns data: TData[] columns: ColumnConfig[] // Identification tableId: string getRowId: (row: TData) => string // Pagination pagination?: PaginationConfig // Selection selection?: SelectionConfig // Filters filters?: FiltersConfig // Bulk Actions bulkActions?: BulkAction[] // Row Actions rowActions?: RowAction[] // Search search?: SearchConfig // Sorting sorting?: SortingConfig // Column Visibility columnVisibility?: ColumnVisibilityConfig // Column Reordering columnReorder?: ColumnReorderConfig // Column Resizing columnResize?: ColumnResizeConfig // Inline Editing inlineEdit?: InlineEditConfig // Saved Views savedViews?: SavedViewsConfig // URL Persistence urlPersistence?: URLPersistenceConfig // Export export?: ExportConfig // Navigation onRowClick?: (row: TData) => void // Mobile mobileConfig?: MobileCardConfig // Loading States loading?: boolean loadingRows?: Set // Customization className?: string emptyState?: ReactNode errorState?: ReactNode } // Column Configuration export interface ColumnConfig { id: string header: string | ((props: any) => ReactNode) accessorKey?: string accessorFn?: (row: TData) => any cell?: (row: TData) => ReactNode sortable?: boolean sortingFn?: (a: TData, b: TData) => number width?: string | number minWidth?: string | number maxWidth?: string | number mobilePrimary?: boolean mobileSecondary?: boolean hideOnMobile?: boolean hideable?: boolean // Whether this column can be hidden (default: true) editable?: boolean // Whether this column can be edited inline (default: false) editType?: 'text' | 'number' | 'select' | 'date' // Type of editor to use editOptions?: string[] // Options for select type validate?: (value: any, row: TData) => string | null // Validation function (returns error message or null) } // Pagination Configuration export interface PaginationConfig { enabled: boolean pageSize: number totalCount: number currentPage: number serverSide: boolean onPageChange: (page: number) => void } // Selection Configuration export interface SelectionConfig { enabled: boolean selectAllPages?: boolean selectedIds?: Set onSelectionChange?: (ids: Set) => void onSelectAllPages?: (enabled: boolean) => void renderSelectionCell?: (row: any) => ReactNode } // Filter Configuration export interface FiltersConfig { enabled: boolean position: 'top' | 'side' collapsible: boolean config: FilterConfig value: FilterState onChange: (filters: FilterState) => void presets?: FilterPreset[] showPresets?: boolean // Show preset chips in toolbar (default: true if presets provided) // Render the filter panel expanded on first mount instead of collapsed behind the "Filters" toggle (default: false) defaultExpanded?: boolean } export interface FilterConfig { sections: FilterSection[] } export interface FilterSection { id: string type: 'chips' | 'buckets' | 'dropdown' | 'search' | 'range' | 'date' | 'collapsible' | 'custom' label?: string filters?: FilterItem[] buckets?: FilterBucket[] // Custom filter handler for complex filter logic (type: 'custom') customFilter?: CustomFilterHandler } export interface CustomFilterHandler { // Render the custom filter UI render: (value: any, onChange: (value: any) => void) => ReactNode // Apply filter to data (client-side filtering) apply?: (data: TData[], filterValue: any) => TData[] // Convert filter value to API query params (server-side filtering) toApiParams?: (filterValue: any) => Record // Default value for the filter defaultValue?: any // Check if filter is active (for showing clear button, etc.) isActive?: (value: any) => boolean } export interface FilterItem { id: string label: string type?: 'chips' | 'dropdown' | 'search' | 'checkbox' options?: string[] multiple?: boolean } export interface FilterBucket { label: string min: number max: number } export interface FilterState { [key: string]: any } export interface FilterPreset { id: string label: string icon?: LucideIcon filters: FilterState description?: string // Tooltip text } // Bulk Actions export interface BulkAction { id: string label: string icon: LucideIcon variant: 'default' | 'gradient-purple' | 'gradient-green' | 'gradient-indigo' | 'gradient-orange' | 'gradient-blue' onClick: (selectedIds: Set) => Promise | void maxSelection?: number confirmMessage?: string disabled?: (selectedIds: Set) => boolean } // Row Actions export interface RowAction { id: string label: string icon?: LucideIcon onClick: (row: TData) => void disabled?: (row: TData) => boolean destructive?: boolean separator?: boolean } // Search Configuration export interface SearchConfig { enabled: boolean placeholder: string value: string onChange: (value: string) => void debounceMs?: number autoFocus?: boolean preserveFocus?: boolean } // Sorting Configuration export interface SortingConfig { enabled: boolean serverSide: boolean value?: SortState onChange?: (sort: SortState) => void } export interface SortState { sortBy: string | null sortDirection: 'asc' | 'desc' } // URL Persistence Configuration export interface URLPersistenceConfig { enabled: boolean debounceMs?: number } // Column Visibility Configuration export interface ColumnVisibilityConfig { enabled: boolean defaultVisible?: string[] // Column IDs that are visible by default (if not set, all are visible) alwaysVisible?: string[] // Column IDs that cannot be hidden persistKey?: string // localStorage key to persist visibility state } export interface ColumnVisibilityState { [columnId: string]: boolean } // Column Reorder Configuration export interface ColumnReorderConfig { enabled: boolean initialOrder?: string[] | null // Initial column order (from saved preferences) onOrderChange?: (order: string[]) => void // Callback when order changes (for persistence) } // Column Resize Configuration export interface ColumnResizeConfig { enabled: boolean initialWidths?: { [columnId: string]: number } | null // Initial column widths (from saved preferences) minWidth?: number // Minimum column width in pixels (default: 50) onWidthChange?: (widths: { [columnId: string]: number }) => void // Callback when widths change } // Inline Edit Configuration export interface InlineEditConfig { enabled: boolean onSave: (rowId: string, columnId: string, value: any, row: TData) => Promise // Save callback onCancel?: () => void // Cancel callback optimisticUpdate?: boolean // Apply changes immediately before save completes (default: true) } // Saved View Configuration export interface SavedView { id: string name: string isDefault?: boolean createdAt: string // View settings columnVisibility?: { [columnId: string]: boolean } columnOrder?: string[] sortBy?: string | null sortDirection?: 'asc' | 'desc' filters?: { [key: string]: any } pageSize?: number } export interface SavedViewsConfig { enabled: boolean views?: SavedView[] // Initial saved views currentViewId?: string | null // Currently active view onSaveView: (view: Omit) => Promise // Save a new view onUpdateView?: (viewId: string, updates: Partial) => Promise // Update existing view onDeleteView?: (viewId: string) => Promise // Delete a view onLoadView?: (viewId: string) => void // Called when user loads a view getCurrentViewState?: () => Omit // Get current table state for saving } // Export Configuration export interface ExportConfig { enabled: boolean baseFilename?: string // Base filename for exports (default: 'export') formats?: ('csv' | 'excel')[] // Available export formats (default: both) showProgress?: boolean // Show progress during export (default: true) onExportStart?: (format: 'csv' | 'excel', scope: 'all' | 'filtered' | 'selected') => void onExportComplete?: (format: 'csv' | 'excel', scope: 'all' | 'filtered' | 'selected', rowCount: number) => void onExportError?: (error: Error) => void } // Mobile Card Configuration export interface MobileCardConfig { titleKey: string subtitleKey?: string descriptionKey?: string primaryFields: string[] secondaryFields?: string[] renderCustomContent?: (row: TData) => ReactNode } // Internal State Types export interface TableState { data: TData[] filteredData: TData[] displayedData: TData[] // Pagination currentPage: number pageSize: number totalPages: number totalCount: number // Selection selectedIds: Set selectAllPages: boolean // Filters activeFilters: FilterState // Sorting sortBy: string | null sortDirection: 'asc' | 'desc' // Search searchTerm: string debouncedSearchTerm: string // UI loading: boolean loadingRows: Set error: Error | null viewMode: 'table' | 'card' } // Hook Return Types export interface UseTableStateReturn { state: TableState setData: (data: TData[]) => void setPage: (page: number) => void setPageSize: (size: number) => void setLoading: (loading: boolean) => void setLoadingRows: (ids: Set) => void setError: (error: Error | null) => void setViewMode: (mode: 'table' | 'card') => void } export interface UseSelectionReturn { selectedIds: Set selectAllPages: boolean toggleRow: (id: string) => void toggleAll: () => void selectAllPagesToggle: () => void clearSelection: () => void getSelectedCount: () => number } export interface UsePaginationReturn { currentPage: number pageSize: number totalPages: number totalCount: number canGoNext: boolean canGoPrevious: boolean goToPage: (page: number) => void goToFirstPage: () => void goToLastPage: () => void goToNextPage: () => void goToPreviousPage: () => void getPageNumbers: () => (number | '...')[] getDisplayRange: () => { start: number; end: number } } export interface UseFiltersReturn { filters: FilterState setFilter: (key: string, value: any) => void clearFilter: (key: string) => void clearAllFilters: () => void hasActiveFilters: () => boolean getActiveFilterCount: () => number }