servicepoint-tanks/tank-frontend/src/components/DataTable.tsx
2024-04-14 18:26:13 +02:00

80 lines
2.3 KiB
TypeScript

import {ReactNode, useState} from "react";
import './DataTable.css';
export type DataTableColumnDefinition<T> = {
field: string,
label?: string,
visualize?: (value: T) => ReactNode,
sorter?: (a: T, b: T) => number
};
function DataTableRow({rowData, columns}: {
rowData: any,
columns: DataTableColumnDefinition<any>[]
}) {
return <tr>
{
columns.map(column => {
return <td key={column.field}>
{
column.visualize
? column.visualize(rowData)
: rowData[column.field]
}
</td>;
})
}
</tr>;
}
export default function DataTable<T>({data, columns, className}: {
data: T[],
columns: DataTableColumnDefinition<any>[],
className?: string
}) {
const [sortBy, setSortBy] = useState<DataTableColumnDefinition<any> | null>(null);
const [sortReversed, setSortReversed] = useState(false);
const headerClick = (column: DataTableColumnDefinition<any>) => {
console.log('column clicked', column);
if (column.field === sortBy?.field)
setSortReversed(prevState => !prevState);
else if (column.sorter)
setSortBy(column);
else
console.log('cannot sort by', column)
};
const dataToDisplay = [...data];
const actualSorter = sortReversed && sortBy?.sorter
? (a: T, b: T) => -sortBy.sorter!(a, b)
: sortBy?.sorter;
dataToDisplay.sort(actualSorter)
console.log('sorted', {dataToDisplay});
return <div className={'DataTable ' + (className ?? '')}>
<table>
<thead className='DataTableHead'>
<tr>
{
columns.map(column =>
<th key={column.field} onClick={() => headerClick(column)}>
{column.label ?? column.field}
</th>)
}
</tr>
</thead>
<tbody>
{
dataToDisplay.map((element, index) =>
<DataTableRow key={`${sortBy?.field}-${index}`} rowData={element} columns={columns}/>)
}
</tbody>
</table>
</div>;
}