diff --git a/src/components/data-table.tsx b/src/components/data-table.tsx new file mode 100644 index 0000000..2bf169a --- /dev/null +++ b/src/components/data-table.tsx @@ -0,0 +1,148 @@ +"use client" + +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "./ui/table" +import { Button } from "./ui/button" +import { Input } from "./ui/input" + +interface Column { + key: string + label: string + sortable?: boolean + width?: string + render?: (value: any, row: any) => React.ReactNode +} + +interface Action { + label: string + onClick: (row: any) => void + variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" +} + +interface DataTableProps { + columns: Column[] + data: any[] + isLoading?: boolean + searchPlaceholder?: string + searchableColumns?: string[] + actions?: Action[] +} + +export function DataTable({ + columns, + data, + isLoading, + searchPlaceholder = "Search...", + searchableColumns = [], + actions = [] +}: DataTableProps) { + const [searchTerm, setSearchTerm] = useState("") + const [sortConfig, setSortConfig] = useState<{ key: string; direction: "asc" | "desc" } | null>(null) + + const filteredData = data.filter((row) => { + if (!searchTerm) return true + return searchableColumns.some((key) => { + const value = row[key] + return value?.toString().toLowerCase().includes(searchTerm.toLowerCase()) + }) + }) + + const sortedData = [...filteredData].sort((a, b) => { + if (!sortConfig) return 0 + const aValue = a[sortConfig.key] + const bValue = b[sortConfig.key] + + if (aValue < bValue) return sortConfig.direction === "asc" ? -1 : 1 + if (aValue > bValue) return sortConfig.direction === "asc" ? 1 : -1 + return 0 + }) + + const handleSort = (key: string) => { + setSortConfig(current => { + if (current?.key === key) { + return { key, direction: current.direction === "asc" ? "desc" : "asc" } + } + return { key, direction: "asc" } + }) + } + + return ( +