import { Link } from '@inertiajs/react'; import { Skeleton } from './Skeleton'; interface Column { header: string; accessorKey: keyof T | string; sortable?: boolean; cell?: (item: T) => React.ReactNode; } interface PaginationMeta { current_page: number; last_page: number; total: number; per_page: number; } interface DataTableProps { data: T[]; columns: Column[]; meta?: PaginationMeta; links?: any[]; filters?: any; onFilterChange?: (filters: any) => void; onSort?: (field: string, direction: 'asc' | 'desc') => void; onEdit?: (item: T) => void; onDelete?: (item: T) => void; onRestore?: (item: T) => void; onPermanentDelete?: (item: T) => void; canEdit?: boolean; canDelete?: boolean; isLoading?: boolean; emptyAction?: React.ReactNode; } export function DataTable({ data, columns, meta, links, filters = {}, onSort, onEdit, onDelete, onRestore, onPermanentDelete, canEdit = false, canDelete = false, isLoading = false, emptyAction, selectedIds = [], onSelectionChange, }: DataTableProps & { selectedIds?: (number | string)[], onSelectionChange?: (ids: (number | string)[]) => void }) { const toggleAll = () => { if (!onSelectionChange) return; if (selectedIds.length === data.length) { onSelectionChange([]); } else { onSelectionChange(data.map(item => item.id)); } }; const toggleOne = (id: number | string) => { if (!onSelectionChange) return; if (selectedIds.includes(id)) { onSelectionChange(selectedIds.filter(i => i !== id)); } else { onSelectionChange([...selectedIds, id]); } }; const handleSort = (field: string) => { if (!onSort) return; const direction = filters.sort_field === field && filters.sort_direction === 'asc' ? 'desc' : 'asc'; onSort(field, direction); }; return (
{onSelectionChange && ( )} {columns.map((col, idx) => ( ))} {(canEdit || onDelete || onRestore || onPermanentDelete) && ( )} {isLoading ? ( Array.from({ length: 5 }).map((_, i) => ( {onSelectionChange && } {columns.map((_, idx) => ( ))} {(canEdit || onDelete || onRestore || onPermanentDelete) && ( )} )) ) : data.length === 0 ? ( ) : data.map((item) => ( {onSelectionChange && ( )} {columns.map((col, colIndex) => ( ))} {(canEdit || onDelete || onRestore || onPermanentDelete) && ( )} ))}
0 && selectedIds.length === data.length} onChange={toggleAll} className="w-4 h-4 rounded-lg border-gray-200 text-[#D4A017] focus:ring-[#D4A017]/20 transition-all cursor-pointer" />
col.sortable && handleSort(col.accessorKey as string)} >
{col.header} {col.sortable && (
)}
Actions

No data found

{emptyAction &&
{emptyAction}
}
toggleOne(item.id)} className="w-4 h-4 rounded-lg border-gray-200 text-[#D4A017] focus:ring-[#D4A017]/20 transition-all cursor-pointer" /> {col.cell ? col.cell(item) : ( {String(item[col.accessorKey as keyof T] || '-')} )}
{onRestore && ( )} {canEdit && onEdit && ( )} {onDelete && ( )} {onPermanentDelete && ( )}
{/* Pagination - Professional Flat Style */} {meta && links && (
Showing {data.length} of {meta.total} entries
{links.map((link, idx) => { if (link.label.includes('Previous')) { return ( Prev ); } if (link.label.includes('Next')) { return ( Next ); } if (link.label.includes('...') || /^\d+$/.test(link.label)) { return ( {link.label} ); } return null; })}
)}
); }