/* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
import {tooltipClasses, TooltipProps} from "@mui/material";
import Autocomplete from "@mui/material/Autocomplete";
import Icon from "@mui/material/Icon";
import {styled} from "@mui/material/styles";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableContainer from "@mui/material/TableContainer";
import TableRow from "@mui/material/TableRow";
import Tooltip from "@mui/material/Tooltip";
import parse from "html-react-parser";
import {useEffect, useMemo, useState} from "react";
import {useAsyncDebounce, useGlobalFilter, usePagination, useSortBy, useTable} from "react-table";
import DataTableBodyCell from "qqq/components/Temporary/DataTable/DataTableBodyCell";
import DataTableHeadCell from "qqq/components/Temporary/DataTable/DataTableHeadCell";
import DefaultCell from "qqq/components/Temporary/DefaultCell";
import MDBox from "qqq/components/Temporary/MDBox";
import MDInput from "qqq/components/Temporary/MDInput";
import MDPagination from "qqq/components/Temporary/MDPagination";
import MDTypography from "qqq/components/Temporary/MDTypography";
import ImageCell from "qqq/pages/dashboards/Tables/ImageCell";
export interface TableDataInput
{
columns: { [key: string]: any }[];
rows: { [key: string]: any }[];
}
interface Props
{
entriesPerPage?:
| false
| {
defaultValue: number;
entries: number[];
};
canSearch?: boolean;
showTotalEntries?: boolean;
table: TableDataInput;
pagination?: {
variant: "contained" | "gradient";
color: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "dark" | "light";
};
isSorted?: boolean;
noEndBorder?: boolean;
}
const NoMaxWidthTooltip = styled(({className, ...props}: TooltipProps) => (
))({
[`& .${tooltipClasses.tooltip}`]: {
maxWidth: "none",
textAlign: "left"
},
});
function DataTable({
entriesPerPage,
canSearch,
showTotalEntries,
table,
pagination,
isSorted,
noEndBorder,
}: Props): JSX.Element
{
let defaultValue: any;
let entries: any[];
if (entriesPerPage)
{
defaultValue = entriesPerPage.defaultValue ? entriesPerPage.defaultValue : "10";
entries = entriesPerPage.entries ? entriesPerPage.entries : ["10", "25", "50", "100"];
}
const columns = useMemo(() => table.columns, [table]);
const data = useMemo(() => table.rows, [table]);
if (!columns || !data)
{
return null;
}
const tableInstance = useTable(
{columns, data, initialState: {pageIndex: 0}},
useGlobalFilter,
useSortBy,
usePagination
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
prepareRow,
rows,
page,
pageOptions,
canPreviousPage,
canNextPage,
gotoPage,
nextPage,
previousPage,
setPageSize,
setGlobalFilter,
state: {pageIndex, pageSize, globalFilter},
}: any = tableInstance;
// Set the default value for the entries per page when component mounts
useEffect(() => setPageSize(defaultValue || 10), [defaultValue]);
// Set the entries per page value based on the select value
const setEntriesPerPage = (value: any) => setPageSize(value);
// Render the paginations
const renderPagination = pageOptions.map((option: any) => (
gotoPage(Number(option))}
active={pageIndex === option}
>
{option + 1}
));
// Handler for the input to set the pagination index
const handleInputPagination = ({target: {value}}: any) =>
value > pageOptions.length || value < 0 ? gotoPage(0) : gotoPage(Number(value));
// Customized page options starting from 1
const customizedPageOptions = pageOptions.map((option: any) => option + 1);
// Setting value for the pagination input
const handleInputPaginationValue = ({target: value}: any) => gotoPage(Number(value.value - 1));
// Search input value state
const [search, setSearch] = useState(globalFilter);
// Search input state handle
const onSearchChange = useAsyncDebounce((value) =>
{
setGlobalFilter(value || undefined);
}, 100);
// A function that sets the sorted value for the table
const setSortedValue = (column: any) =>
{
let sortedValue;
if (isSorted && column.isSorted)
{
sortedValue = column.isSortedDesc ? "desc" : "asce";
}
else if (isSorted)
{
sortedValue = "none";
}
else
{
sortedValue = false;
}
return sortedValue;
};
// Setting the entries starting point
const entriesStart = pageIndex === 0 ? pageIndex + 1 : pageIndex * pageSize + 1;
// Setting the entries ending point
let entriesEnd;
if (pageIndex === 0)
{
entriesEnd = pageSize;
}
else if (pageIndex === pageOptions.length - 1)
{
entriesEnd = rows.length;
}
else
{
entriesEnd = pageSize * (pageIndex + 1);
}
return (
{entriesPerPage || canSearch ? (
{entriesPerPage && (
{
setEntriesPerPage(parseInt(newValue, 10));
}}
size="small"
sx={{width: "5rem"}}
renderInput={(params) => }
/>
entries per page
)}
{canSearch && (
{
setSearch(search);
onSearchChange(currentTarget.value);
}}
/>
)}
) : null}
{headerGroups.map((headerGroup: any, i: number) => (
{headerGroup.headers.map((column: any) => (
column.type !== "hidden" && (
{column.render("header")}
)
))}
))}
{page.map((row: any, key: any) =>
{
prepareRow(row);
return (
{row.cells.map((cell: any) => (
cell.column.type !== "hidden" && (
{
cell.column.type === "default" && (
cell.value && "number" === typeof cell.value ? (
{cell.value.toLocaleString()}
) : ({cell.render("Cell")})
)
}
{
cell.column.type === "htmlAndTooltip" && (
{parse(cell.value)}
)
}
{
cell.column.type === "html" && (
{parse(cell.value)}
)
}
{
cell.column.type === "image" && row.values["imageTotal"] && (
)
}
{
cell.column.type === "image" && !row.values["imageTotal"] && (
)
}
)
))}
);
})}
{showTotalEntries && (
Showing {entriesStart} to {entriesEnd} of {rows.length} entries
)}
{pageOptions.length > 1 && (
{canPreviousPage && (
previousPage()}>
chevron_left
)}
{renderPagination.length > 6 ? (
{
handleInputPagination(event);
handleInputPaginationValue(event);
}}
/>
) : (
renderPagination
)}
{canNextPage && (
nextPage()}>
chevron_right
)}
)}
);
}
// Declaring default props for DataTable
DataTable.defaultProps = {
entriesPerPage: {defaultValue: 10, entries: ["5", "10", "15", "20", "25"]},
canSearch: false,
showTotalEntries: true,
pagination: {variant: "gradient", color: "info"},
isSorted: true,
noEndBorder: false,
};
export default DataTable;