import {
useReactTable,
Column,
ColumnDef,
getCoreRowModel,
flexRender,
getSortedRowModel,
InitialTableState,
SortingState,
TableOptions,
SortingOptions,
} from "@tanstack/react-table"
import * as styles from "./Table.module.scss"
import Loader2 from "../ui/Loader2"
import NoItems from "../ui/noItems"
import { useEffect, useState, useCallback } from "react"
import cx from "classnames"
import Triangle from "../atoms/Triangle/Triangle"
// import { sessionStorageKeys } from 'src/constants/sessionStorageKeys';
import { tableIDs } from "./tableIDs"
import React from "react"
// check ssr
const storage = typeof window !== "undefined" && sessionStorage
const SS_KEY = "tableSorting"
type TableIDs = typeof tableIDs
function getDataFromStorage(): Record<keyof TableIDs, SortingState> {
return JSON.parse(storage.getItem(SS_KEY) || "{}")
}
function saveDataToStorage(id: string, sorting: SortingState) {
storage.setItem(
SS_KEY,
JSON.stringify({
...getDataFromStorage(),
[id]: sorting,
})
)
}
export type Props<T extends object> = {
columns: ColumnDef<T>[]
data: T[]
isLoading?: boolean
onSelect?: (id: string | null) => void
// prefer not use
style?: any
id?: keyof TableIDs
initialState?: InitialTableState
// maybe temporary
enableSorting?: boolean
}
function Table<T extends object>({
columns,
data,
isLoading,
style,
onSelect,
initialState,
id,
enableSorting = true,
}: Props<T>) {
const [selected, setSelected] = useState<string | null>(null)
const savedSorting = id && getDataFromStorage()[id]
const [sorting, setSorting] = useState<SortingState>(
savedSorting || initialState?.sorting || []
)
useEffect(() => {
if (!id) {
return
}
saveDataToStorage(id, sorting)
}, [sorting, id])
const handleSortingChange = useCallback(
(sorting: TableOptions<any>["onSortingChange"]) => {
setSorting(sorting)
},
[]
)
const table = useReactTable({
// debugTable: true,
columns,
data,
state: {
rowSelection: {},
sorting,
},
initialState,
enableSorting,
// enableRowSelection: true,
// onRowSelectionChange: (state) => {
// console.log(state);
// debugger;
// },
// enableColumnResizing: true,
// columnResizeMode: 'onChange',
onSortingChange: handleSortingChange,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
})
return (
<>
<table
className={cx(styles.table, {
[styles.selectable]: !!onSelect,
})}
style={style}
>
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<th
key={header.id}
className={cx({
[styles.sortable]: header.column.getCanSort(),
})}
colSpan={header.colSpan}
style={{
width: header.column.getSize(),
}}
onClick={header.column.getToggleSortingHandler()}
>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
{header.column.getCanSort() && (
<Triangle
disabled={!header.column.getIsSorted()}
direction={
header.column.getIsSorted() === "desc" ? "down" : "up"
}
/>
)}
{/* <div
{...{
onDoubleClick: () => header.column.resetSize(),
onMouseDown: header.getResizeHandler(),
onTouchStart: header.getResizeHandler(),
className: `${styles.resizer} ${
header.column.getIsResizing() ? styles.isResizing : ''
}`,
}}
/> */}
</th>
)
})}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => {
return (
<tr
key={row.id}
data-id={row.id}
className={cx({ [styles.rowSelected]: row.id === selected })}
onClick={(e) => {
// TODO: move to tbody
if (!onSelect) {
return
}
if (
["a", "button", "input"].includes(
(e.target as any).tagName.toLowerCase()
)
) {
return
}
const id = e.currentTarget.getAttribute("data-id")
if (id === selected) {
setSelected(null)
onSelect(null)
return
}
setSelected(id)
onSelect(id)
}}
>
{row.getVisibleCells().map((cell) => {
return (
<td
key={cell.id}
style={{
width: cell.column.getSize(),
}}
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</td>
)
})}
</tr>
)
})}
</tbody>
</table>
{isLoading ? <Loader2 /> : !data.length && <NoItems text="No data" />}
</>
)
}
export default Table