import React, {useCallback, useContext, useEffect, useState} from "react"; import "./data-table.css"; import {LocaleContext} from "../locale"; import clsx from "clsx"; import {Box, Button, Select, TextField, Table, TableBody, TableCell, TableHead, TableRow} from "@mui/material"; import {formatDate, formatDateTime} from "../util"; import {isNumber} from "chart.js/helpers"; import {ArrowUpward, ArrowDownward, Refresh} from "@mui/icons-material"; import TableBodyStriped from "./table-body-striped"; export function DataTable(props) { const { className, placeholder, columns, data, pagination, fetchData, onClick, onFilter, defaultSortColumn, defaultSortOrder, forceReload, buttons, ...other } = props; const {translate: L} = useContext(LocaleContext); const [doFetchData, setFetchData] = useState(false); const [sortAscending, setSortAscending] = useState(["asc","ascending"].includes(defaultSortOrder?.toLowerCase())); const [sortColumn, setSortColumn] = useState(isNumber(defaultSortColumn) || null); const sortable = !!fetchData && (props.hasOwnProperty("sortable") ? !!props.sortable : true); const onRowClick = onClick || (() => {}); const onFetchData = useCallback((force = false) => { if (fetchData) { if (doFetchData || force) { setFetchData(false); const orderBy = columns[sortColumn]?.field || null; const sortOrder = sortAscending ? "asc" : "desc"; fetchData(pagination.getPage(), pagination.getPageSize(), orderBy, sortOrder); } } }, [fetchData, doFetchData, columns, sortColumn, sortAscending, pagination]); // pagination changed? useEffect(() => { if (pagination) { let forceFetch = false; if (pagination.getPageSize() < pagination.getTotal()) { // page size is smaller than the total count forceFetch = true; } else if (data?.length && pagination.getPageSize() >= data.length && data.length < pagination.getTotal()) { // page size is greater than the current visible count but there were hidden rows before forceFetch = true; } onFetchData(forceFetch); } }, [pagination?.data?.pageSize, pagination?.data?.current]); // sorting changed or we forced an update useEffect(() => { onFetchData(true); }, [sortAscending, sortColumn, forceReload]); let headerRow = []; const onChangeSort = useCallback((index, column) => { if (sortable && column.sortable) { if (sortColumn === index) { setSortAscending(!sortAscending); } else { setSortColumn(index); } } }, [onFetchData, sortColumn, sortAscending]); for (const [index, column] of columns.entries()) { if (!(column instanceof DataColumn)) { throw new Error("DataTable can only have DataColumn-objects as column definition, got: " + typeof column); } else if (column.hidden) { continue; } if (sortable && column.sortable) { headerRow.push( onChangeSort(index, column)} align={column.align}> {sortColumn === index ? (sortAscending ? : ) : <> } {column.renderHead(index)} ); } else { headerRow.push( {column.renderHead(index)} ); } } const numColumns = columns.length; let numRows = 0; let rows = []; if (data && data?.length) { numRows = data.length; for (const [rowIndex, entry] of data.entries()) { let row = []; for (const [index, column] of columns.entries()) { row.push( {column.renderData(L, entry, index)} ); } rows.push( ["tr","td"].includes(e.target.tagName.toLowerCase()) && onRowClick(rowIndex, entry)} key={"row-" + rowIndex}> { row } ); } } else if (placeholder) { rows.push( { placeholder } ); } return {(buttons || []).map(b =>