import Area from '@components/common/Area.js'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@components/common/ui/Table.js'; import { _ } from '@evershop/evershop/lib/locale/translate/_'; import React from 'react'; export interface TableColumn { key: string; header: { label: React.ReactNode; className?: string; }; sortable?: boolean; width?: string; className?: string; isRemoved?: boolean; render?: (row: T, rowIndex?: number, loading?: boolean) => React.ReactNode; } export interface TableContextValue { columns: TableColumn[]; setColumns: React.Dispatch[]>>; tableData: T[]; currentSort?: { key: string; direction: 'asc' | 'desc' }; addColumnBefore: (newColumn: TableColumn, beforeColumnKey: string) => void; addColumnAfter: (newColumn: TableColumn, afterColumnKey: string) => void; removeColumn: (key: string) => void; tableName: string; } interface TableProviderProps { children: React.ReactNode; name: string; initialColumns: TableColumn[]; tableData: T[]; onSort?: (key: string, direction: 'asc' | 'desc') => void; currentSort?: { key: string; direction: 'asc' | 'desc' }; } const TableContext = React.createContext(null); export function useTableContext(): TableContextValue { const context = React.useContext(TableContext); if (!context) { throw new Error('useTableContext must be used within a TableProvider'); } return context as TableContextValue; } export function TableProvider({ children, name, initialColumns, tableData, onSort, currentSort }: TableProviderProps) { const [columns, setColumns] = React.useState[]>(initialColumns); // Update columns when props change React.useEffect(() => { setColumns(initialColumns.map((col) => ({ ...col }))); }, [initialColumns]); const addColumnBefore = React.useCallback( (newColumn: TableColumn, beforeColumnKey: string) => { setColumns((cols) => { // Find index of the column to insert before const index = cols.findIndex((col) => col.key === beforeColumnKey); // If found, insert before it (index), else add to the start const position = index !== -1 ? index : 0; return [...cols.slice(0, position), newColumn, ...cols.slice(position)]; }); }, [] ); const addColumnAfter = React.useCallback( (newColumn: TableColumn, afterColumnKey: string) => { setColumns((cols) => { // Find index of the column to insert after const index = cols.findIndex((col) => col.key === afterColumnKey); // If found, insert after it (index + 1), else add to the end const position = index !== -1 ? index + 1 : cols.length; return [...cols.slice(0, position), newColumn, ...cols.slice(position)]; }); }, [] ); const removeColumn = React.useCallback((key: string) => { setColumns((cols) => cols.map((col) => (col.key === key ? { ...col, isRemoved: true } : col)) ); }, []); const contextValue: TableContextValue = { columns, setColumns, tableData, currentSort, addColumnBefore, addColumnAfter, removeColumn, tableName: name }; return ( {children} ); } interface ExtendableTableProps { name: string; columns: TableColumn[]; initialData: T[]; loading?: boolean; noHeader?: boolean; emptyMessage?: string; onSort?: (key: string, direction: 'asc' | 'desc') => void; currentSort?: { key: string; direction: 'asc' | 'desc' }; className?: string; } export function ExtendableTable({ name, columns, initialData, loading = false, noHeader = false, emptyMessage = _('No data available'), onSort, currentSort, className = '' }: ExtendableTableProps) { const handleSort = (key: string) => { if (!onSort) return; const direction = currentSort?.key === key && currentSort.direction === 'asc' ? 'desc' : 'asc'; onSort(key, direction); }; return ( ); } // Separate component to use the context function TableContent({ loading = false, noHeader = false, onSort, currentSort, emptyMessage, className }: { loading?: boolean; noHeader?: boolean; onSort?: (key: string, direction: 'asc' | 'desc') => void; currentSort?: { key: string; direction: 'asc' | 'desc' }; emptyMessage: string; className: string; }) { const { columns, tableData } = useTableContext(); const handleSort = (key: string) => { if (!onSort) return; const direction = currentSort?.key === key && currentSort.direction === 'asc' ? 'desc' : 'asc'; onSort(key, direction); }; return ( <> {!noHeader && ( {columns .filter((col) => !col.isRemoved) .map((col) => ( col.sortable && handleSort(col.key)} style={{ width: col.width }} > {col.header.label} {col.sortable && currentSort?.key === col.key && ( {currentSort.direction === 'asc' ? '↑' : '↓'} )} ))} )} {tableData.length === 0 ? ( !col.isRemoved).length} > {emptyMessage} ) : ( tableData.map((row, rowIndex) => ( {columns .filter((col) => !col.isRemoved) .map((col) => ( {col.render ? col.render(row, rowIndex, loading) : row[col.key]} ))} )) )}
); }