import { useIsLoading } from "@/contexts"; import { usePageSize } from "@/utilities/storage"; import { Box, createStyles, Skeleton, Table, Text } from "@mantine/core"; import { ReactNode, useMemo } from "react"; import { HeaderGroup, Row, TableInstance } from "react-table"; export type BaseTableProps = TableInstance & { tableStyles?: TableStyleProps; }; export interface TableStyleProps { emptyText?: string; striped?: boolean; placeholder?: number; hideHeader?: boolean; fixHeader?: boolean; headersRenderer?: (headers: HeaderGroup[]) => JSX.Element[]; rowRenderer?: (row: Row) => Nullable; } const useStyles = createStyles((theme) => { return { container: { display: "block", maxWidth: "100%", overflowX: "auto", }, table: { borderCollapse: "collapse", }, header: {}, }; }); function DefaultHeaderRenderer( headers: HeaderGroup[] ): JSX.Element[] { return headers.map((col) => ( {col.render("Header")} )); } function DefaultRowRenderer(row: Row): JSX.Element | null { return ( {row.cells.map((cell) => ( {cell.render("Cell")} ))} ); } export default function BaseTable(props: BaseTableProps) { const { headerGroups, rows, prepareRow, getTableProps, getTableBodyProps, tableStyles, } = props; const headersRenderer = tableStyles?.headersRenderer ?? DefaultHeaderRenderer; const rowRenderer = tableStyles?.rowRenderer ?? DefaultRowRenderer; const { classes } = useStyles(); const colCount = useMemo(() => { return headerGroups.reduce( (prev, curr) => (curr.headers.length > prev ? curr.headers.length : prev), 0 ); }, [headerGroups]); const empty = rows.length === 0; const [pageSize] = usePageSize(); const isLoading = useIsLoading(); let body: ReactNode; if (isLoading) { body = Array(tableStyles?.placeholder ?? pageSize) .fill(0) .map((_, i) => ( )); } else if (empty && tableStyles?.emptyText) { body = ( {tableStyles.emptyText} ); } else { body = rows.map((row) => { prepareRow(row); return rowRenderer(row); }); } return ( {headerGroups.map((headerGroup) => ( {headersRenderer(headerGroup.headers)} ))} {body}
); }