File size: 3,793 Bytes
dd92235
46cb663
dd92235
 
 
 
 
 
46cb663
 
dd92235
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46cb663
 
 
 
 
 
 
 
 
 
 
 
dd92235
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46cb663
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dd92235
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import "./DataTable.css";

/**
 * Enterprise-style data table with sortable columns, compact rows,
 * and inline status badges.
 */
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>
    );
}