| import { useState } from "react"; |
| import { useNavigate } from "react-router-dom"; |
| import "./DataTable.css"; |
|
|
| |
| |
| |
| |
| export function DataTable({ columns, data, onRowClick, getRowLink, emptyMessage = "No data." }) { |
| const navigate = useNavigate(); |
| const [sortKey, setSortKey] = useState(null); |
| const [sortDir, setSortDir] = useState("asc"); |
|
|
| const handleSort = (key) => { |
| if (!key) return; |
| if (sortKey === key) { |
| setSortDir((d) => (d === "asc" ? "desc" : "asc")); |
| } else { |
| setSortKey(key); |
| setSortDir("asc"); |
| } |
| }; |
|
|
| let sortedData = data; |
| if (sortKey) { |
| sortedData = [...data].sort((a, b) => { |
| const aVal = a[sortKey] ?? ""; |
| const bVal = b[sortKey] ?? ""; |
| if (aVal < bVal) return sortDir === "asc" ? -1 : 1; |
| if (aVal > bVal) return sortDir === "asc" ? 1 : -1; |
| return 0; |
| }); |
| } |
|
|
| if (!data || data.length === 0) { |
| return <p className="dw-table__empty">{emptyMessage}</p>; |
| } |
|
|
| const handleRowClick = (e, row) => { |
| if (e.target.closest("button, a, input, select, textarea")) { |
| return; |
| } |
| if (onRowClick) { |
| onRowClick(row); |
| } else if (getRowLink) { |
| const link = getRowLink(row); |
| if (link) navigate(link); |
| } |
| }; |
|
|
| return ( |
| <div className="dw-table__wrapper"> |
| <table className="dw-table"> |
| <thead> |
| <tr> |
| {columns.map((col) => ( |
| <th |
| key={col.key} |
| className={`dw-table__th ${col.sortable ? "dw-table__th--sortable" : ""} ${col.align === "right" ? "dw-table__th--right" : ""}`} |
| onClick={() => col.sortable && handleSort(col.key)} |
| style={col.width ? { width: col.width } : undefined} |
| > |
| {col.label} |
| {col.sortable && sortKey === col.key && ( |
| <span className="dw-table__sort-icon"> |
| {sortDir === "asc" ? " ↑" : " ↓"} |
| </span> |
| )} |
| </th> |
| ))} |
| </tr> |
| </thead> |
| <tbody> |
| {sortedData.map((row, i) => { |
| const rowLink = getRowLink ? getRowLink(row) : null; |
| const isClickable = Boolean(onRowClick || rowLink); |
| |
| return ( |
| <tr |
| key={row.id || i} |
| className={`dw-table__row ${isClickable ? "dw-table__row--clickable" : ""}`} |
| onClick={(e) => isClickable && handleRowClick(e, row)} |
| > |
| {columns.map((col) => ( |
| <td |
| key={col.key} |
| className={`dw-table__td ${col.align === "right" ? "dw-table__td--right" : ""}`} |
| > |
| {col.render ? col.render(row[col.key], row) : row[col.key]} |
| </td> |
| ))} |
| </tr> |
| ); |
| })} |
| </tbody> |
| </table> |
| </div> |
| ); |
| } |
|
|