import { Row, ColumnDef, useReactTable, getCoreRowModel, flexRender, createColumnHelper, } from "@tanstack/react-table"; import { ChangeEvent, useState, useEffect, Key, Dispatch, SetStateAction, } from "react"; import { TableAction } from "./TableAction"; import { PlusIcon } from "@heroicons/react/24/solid"; import { rankItem } from "@tanstack/match-sorter-utils"; import { RowOptionMenu } from "./RowOptionMenu"; import DataPoint from "@/utils/models/DataPoint"; type TableProps = { data: T[]; setData: Dispatch>; columns: ColumnDef[]; }; /** Fuzzy search function */ const fuzzyFilter = ( row: Row, columnId: string, value: any, addMeta: (meta: any) => void ) => { // Rank the item const itemRank = rankItem(row.getValue(columnId), value); // Store the ranking info addMeta(itemRank); // Return if the item should be filtered in/out return itemRank.passed; }; /** * General componenet that holds shared functionality for any data table component * @param props.data Stateful list of data to be held in the table * @param props.setData State setter for the list of data * @param props.columns Column definitions made with Tanstack columnHelper */ export default function Table({ data, setData, columns, }: TableProps) { const columnHelper = createColumnHelper(); /** Sorting function based on visibility */ const visibilitySort = (a: T, b: T) => a.visible === b.visible ? 0 : a.visible ? -1 : 1; // Sort data on load useEffect(() => { setData((prevData) => prevData.sort(visibilitySort)); }, [setData]); // Data manipulation methods // TODO: Connect data manipulation methods to the database (deleteData, hideData, addData) const deleteData = (dataId: number) => { console.log(data); setData((currentData) => currentData.filter((data) => data.id !== dataId) ); }; const hideData = (dataId: number) => { console.log(`Toggling visibility for data with ID: ${dataId}`); setData((currentData) => { const newData = currentData .map((data) => data.id === dataId ? { ...data, visible: !data.visible } : data ) .sort(visibilitySort); console.log(newData); return newData; }); }; const addData = () => { setData([...data]); }; // Add data manipulation options to the first column columns.unshift( columnHelper.display({ id: "options", cell: (props) => ( deleteData(props.row.original.id)} onHide={() => hideData(props.row.original.id)} /> ), }) ); // Searching const [query, setQuery] = useState(""); const handleSearchChange = (e: ChangeEvent) => { const target = e.target as HTMLInputElement; setQuery(String(target.value)); }; const handleCellChange = (e: ChangeEvent, key: Key) => { const target = e.target as HTMLInputElement; console.log(key); }; // TODO: Filtering // TODO: Sorting // Define Tanstack table const table = useReactTable({ columns, data, filterFns: { fuzzy: fuzzyFilter, }, state: { globalFilter: query, }, onGlobalFilterChange: setQuery, globalFilterFn: fuzzyFilter, getCoreRowModel: getCoreRowModel(), }); const handleRowData = (row: any) => { const rowData: any = {}; row.cells.forEach((cell: any) => { rowData[cell.column.id] = cell.value; }); // Use rowData object containing data from all columns for the current row console.log(rowData); return rowData; }; return (
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header, i) => ( ))} ))} {table.getRowModel().rows.map((row) => { // Individual row const isDataVisible = row.original.visible; const rowClassNames = `text-gray-800 border-y lowercase hover:bg-gray-50 ${ !isDataVisible ? "bg-gray-200 text-gray-500" : "" }`; return ( {row.getVisibleCells().map((cell, i) => ( ))} ); })}
{header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext() )}
{flexRender( cell.column.columnDef.cell, cell.getContext() )}
New
); }