Data Table
DataTable is a highly versatile component used to organize large quantities of tabular data. It supports pagination to help navigate through the data easily and efficiently, and also allows the user to sort and filter the data by columns. Additionally, it offers the ability to select one or multiple rows using checkboxes, which can be useful for performing batch actions or manipulating the data in other ways.
import React, { useEffect, useState } from "react";
import { DataTable } from "@nimbus-ds/patterns";
import { Tag, Box, IconButton, Chip } from "@nimbus-ds/components";
import {
ChevronDownIcon,
CheckCircleIcon,
ChevronUpIcon,
ExclamationTriangleIcon,
} from "@nimbus-ds/icons";
const pageSize = 5;
const orders = [
{
id: 10,
clientName: "Dr. Johnnie Bins",
total: "R$16.788,20",
qty: "9",
status: false,
},
{
id: 9,
clientName: "Earnest Berge",
total: "R$62.657,83",
qty: "3",
status: false,
},
{
id: 8,
clientName: "Irene Purdy",
total: "R$17.692,10",
qty: "4",
status: false,
},
{
id: 7,
clientName: "Owen Swift DVM",
total: "R$60.269,67",
qty: "5",
status: false,
},
{
id: 6,
clientName: "Felipe Ferry",
total: "R$75.058,94",
qty: "3",
status: false,
},
{
id: 5,
clientName: "Derek Kub",
total: "R$29.068,91",
qty: "1",
status: false,
},
{
id: 4,
clientName: "Elisa Vandervort",
total: "R$22.636,41",
qty: "5",
status: false,
},
{
id: 3,
clientName: "Rochelle Spencer",
total: "R$76.244,05",
qty: "9",
status: false,
},
{
id: 2,
clientName: "Angelina Koelpin",
total: "R$65.306,79",
qty: "4",
status: false,
},
{
id: 1,
clientName: "Edna Jacobi",
total: "R$97.025,32",
qty: "6",
status: false,
},
];
const Example: React.FC = () => {
interface RowProps {
id: number;
clientName: string;
total: string;
qty: string;
status: boolean;
}
const [rows, setRows] = useState<RowProps[]>(orders);
const [checkedRows, setCheckedRows] = useState<number[]>([]);
const [headerCheckboxStatus, setHeaderCheckboxStatus] = useState(false);
const [headerIndeterminateStatus, setHeaderIndeterminateStatus] =
useState(false);
const [currentPage, setCurrentPage] = useState<number>(1);
const [sortDirection, setSortDirection] = useState<
"ascending" | "descending"
>("descending");
const [sortColumn, setSortColumn] = useState<"id" | "clientName">("id");
useEffect(() => {
if (checkedRows.length === rows.length) {
setHeaderCheckboxStatus(true);
setHeaderIndeterminateStatus(false);
} else if (checkedRows.length > 0) {
setHeaderCheckboxStatus(false);
setHeaderIndeterminateStatus(true);
} else {
setHeaderCheckboxStatus(false);
setHeaderIndeterminateStatus(false);
}
}, [checkedRows.length, rows.length]);
const handleRowClick = (id: number) => {
if (checkedRows.includes(id)) {
setCheckedRows(checkedRows.filter((rowId) => rowId !== id));
} else {
setCheckedRows([...checkedRows, id]);
}
};
const handleHeaderCheckboxClick = () => {
if (headerCheckboxStatus) {
setCheckedRows([]);
} else {
const rowIds = rows.map((row) => row.id);
setCheckedRows(rowIds);
}
};
const handleBulkUpdateStatusClick = (status: boolean) => {
const updatedRows = rows.map((row) => {
const checked = checkedRows.includes(row.id);
return { ...row, status: checked ? status : row.status };
});
setRows(updatedRows);
};
const handlePageChange = (page: number): void => {
setCurrentPage(page);
};
const handleSort = (column: "id" | "clientName") => {
if (column === sortColumn) {
setSortDirection(
sortDirection === "ascending" ? "descending" : "ascending"
);
} else {
setSortColumn(column);
setSortDirection("ascending");
}
};
const sortCompareFunction = (rowA: RowProps, rowB: RowProps) => {
if (sortColumn === "id") {
return sortDirection === "ascending"
? rowA.id - rowB.id
: rowB.id - rowA.id;
}
if (sortColumn === "clientName") {
return sortDirection === "ascending"
? rowA.clientName.localeCompare(rowB.clientName)
: rowB.clientName.localeCompare(rowA.clientName);
}
return 0;
};
const getDisplayedRows = (): RowProps[] => {
const sortedRows = rows.slice().sort(sortCompareFunction);
const startIndex = (currentPage - 1) * pageSize;
const endIndex = startIndex + pageSize;
return sortedRows.slice(startIndex, endIndex);
};
const displayedRows = getDisplayedRows();
const totalRows = rows.length;
const firstRow = (currentPage - 1) * pageSize + 1;
const lastRow = Math.min(currentPage * pageSize, totalRows);
const tableHeader = (
<DataTable.Header
checkbox={{
name: "check-all-rows",
checked: headerCheckboxStatus,
onChange: handleHeaderCheckboxClick,
indeterminate: headerIndeterminateStatus,
}}
>
<DataTable.Cell width="120px">
<Box display="flex" gap="2" alignItems="center">
Order no.
<IconButton
source={
sortDirection === "ascending" ? (
<ChevronUpIcon size={10} />
) : (
<ChevronDownIcon size={10} />
)
}
size="1rem"
onClick={() => handleSort("id")}
/>
</Box>
</DataTable.Cell>
<DataTable.Cell width="auto">Client name</DataTable.Cell>
<DataTable.Cell width="120px">Total</DataTable.Cell>
<DataTable.Cell width="120px">Qty. of products</DataTable.Cell>
<DataTable.Cell width="120px">Order status</DataTable.Cell>
</DataTable.Header>
);
const tableFooter = (
<DataTable.Footer
itemCount={`Showing ${firstRow}-${lastRow} orders of ${totalRows}`}
pagination={{
pageCount: Math.ceil(totalRows / pageSize),
activePage: currentPage,
onPageChange: handlePageChange,
}}
/>
);
const hasBulkActions = checkedRows.length > 0 && (
<DataTable.BulkActions
checkbox={{
name: "check-all",
checked: headerCheckboxStatus,
onChange: handleHeaderCheckboxClick,
indeterminate: headerIndeterminateStatus,
}}
label={`${checkedRows.length} selected`}
action={
<Box display="flex" gap="1">
<Chip
onClick={() => handleBulkUpdateStatusClick(true)}
text="Fulfill orders"
/>
<Chip
onClick={() => handleBulkUpdateStatusClick(false)}
text="Unfulfill orders"
/>
</Box>
}
/>
);
return (
<DataTable
header={tableHeader}
footer={tableFooter}
bulkActions={hasBulkActions}
>
{displayedRows.map((row) => {
const { id, status } = row;
const statusIcon = status ? (
<CheckCircleIcon />
) : (
<ExclamationTriangleIcon />
);
const statusAppearance = status ? "success" : "warning";
const statusMsg = status ? "Fulfilled" : "Pending";
return (
<DataTable.Row
key={id}
backgroundColor={
checkedRows.includes(id)
? {
rest: "primary-surface",
hover: "primary-surfaceHighlight",
}
: {
rest: "neutral-background",
hover: "neutral-surface",
}
}
checkbox={{
name: `check-${id}`,
checked: checkedRows.includes(id),
onChange: () => handleRowClick(id),
}}
>
<DataTable.Cell>#{row.id}</DataTable.Cell>
<DataTable.Cell>{row.clientName}</DataTable.Cell>
<DataTable.Cell>{row.total}</DataTable.Cell>
<DataTable.Cell>{row.qty}</DataTable.Cell>
<DataTable.Cell>
<Tag appearance={statusAppearance}>
{statusIcon}
{statusMsg}
</Tag>
</DataTable.Cell>
</DataTable.Row>
);
})}
</DataTable>
);
};
export default Example;
Instalá el componente via terminal.
npm install @nimbus-ds/data-table
Additional props are passed to the <DataTable> element. See div docs for a list of props accepted by the <DataTable> element.