import Stack from "@mui/material/Stack"; import Grid from "@mui/material/Grid"; import Box from "@mui/material/Box"; import Typography from "@mui/material/Typography"; import Paper from "@mui/material/Paper"; import Table from "@mui/material/Table"; import TableBody from "@mui/material/TableBody"; import TableCell from "@mui/material/TableCell"; import TableContainer from "@mui/material/TableContainer"; import TableHead from "@mui/material/TableHead"; import TableRow from "@mui/material/TableRow"; import Collapse from "@mui/material/Collapse"; import IconButton from "@mui/material/IconButton"; import { ChevronsLeft, ChevronsRight, ChevronLeft, ChevronRight, } from "lucide-react"; import TablePagination from "@mui/material/TablePagination"; import type { TablePaginationProps } from "@mui/material/TablePagination"; import { useState, Fragment } from "react"; import { useTheme } from "@mui/material/styles"; import useMediaQuery from "@mui/material/useMediaQuery"; export type Header = { id: number | string; content: React.ReactNode; onClick?: ( event: React.MouseEvent, row: T ) => void; render: (row: T) => React.ReactNode; }; type DataTableProps = { headers: Header[]; data: T[]; onRowClick?: (row: T) => void; cardsOnSmallScreens?: boolean; expandableRows?: boolean; renderExpandedContent?: (row: T) => React.ReactNode; }; export function DataTable< T extends { id?: string | number; _id?: string | number; onRowClick?: (row: T) => void; }, >({ headers, data, onRowClick, cardsOnSmallScreens = true, expandableRows = false, renderExpandedContent, }: DataTableProps) { const theme = useTheme(); const [expanded, setExpanded] = useState<(string | number) | null>(null); const handleExpand = (row: T) => { const key = row.id || row._id || null; setExpanded(expanded === key ? null : key); }; const isSmall = useMediaQuery(theme.breakpoints.down("md")); if (data.length === 0 || headers.length === 0) return ; const keys = []; // Return stack of cards for small screens if (isSmall && cardsOnSmallScreens) { return ( {data.map((row) => { const key = row.id || row._id || Math.random(); keys.push(key); return ( (onRowClick ? onRowClick(row) : null)} spacing={theme.spacing(4)} sx={{ borderStyle: "solid", borderWidth: 1, borderColor: theme.palette.divider, borderRadius: theme.shape.borderRadius, padding: theme.spacing(4), cursor: onRowClick ? "pointer" : "default", }} key={key} > {headers.map((header) => { return ( {header.content} {header.render(row)}{" "} ); })} {expandableRows && renderExpandedContent && renderExpandedContent(row) && ( {renderExpandedContent(row)} )} ); })} ); } return ( {headers.map((header, idx) => { return ( {header.content} ); })} {data.map((row) => { const key = row.id || row._id || Math.random(); const isExpanded = expanded === key; return ( { if (expandableRows) handleExpand(row); else if (onRowClick) onRowClick(row); }} > {headers.map((header, index) => { return ( header.onClick!(e, row) : undefined } > {header.render(row)} ); })} {expandableRows && renderExpandedContent && renderExpandedContent(row) && ( {renderExpandedContent(row)} )} ); })}
); } interface TablePaginationActionsProps { count: number; page: number; rowsPerPage: number; onPageChange: ( event: React.MouseEvent, newPage: number ) => void; } function TablePaginationActions(props: TablePaginationActionsProps) { const theme = useTheme(); const { count, page, rowsPerPage, onPageChange } = props; const handleFirstPageButtonClick = ( event: React.MouseEvent ) => { onPageChange(event, 0); }; const handleBackButtonClick = ( event: React.MouseEvent ) => { onPageChange(event, page - 1); }; const handleNextButtonClick = ( event: React.MouseEvent ) => { onPageChange(event, page + 1); }; const handleLastPageButtonClick = ( event: React.MouseEvent ) => { onPageChange(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1)); }; return ( {theme.direction === "rtl" ? ( ) : ( )} {theme.direction === "rtl" ? ( ) : ( )} = Math.ceil(count / rowsPerPage) - 1} aria-label="next page" > {theme.direction === "rtl" ? ( ) : ( )} = Math.ceil(count / rowsPerPage) - 1} aria-label="last page" > {theme.direction === "rtl" ? ( ) : ( )} ); } export const Pagination: React.FC = ({ ...props }) => { const isSmall = useMediaQuery((theme: any) => theme.breakpoints.down("sm")); const theme = useTheme(); return ( ); }; const EmptyView = () => { const theme = useTheme(); return ( No data ); };