import React, { useMemo, useState } from 'react'; import usePagination, { Offset } from 'src/hooks/usePagination'; import { SelectFilter, NumberInput, resolveFilterByType, type Filter, } from './Filters'; export type DataItem = Record; export enum HeaderType { Index, String, Number, Select, Multiple, } export interface Header { key: string; header: string; formatter?: (data: DataItem) => string; type: HeaderType; } interface Props { data: DataItem[]; headers: Header[]; } export default function Table({ data, headers }: Props): JSX.Element { const [filters, setFilters] = useState>({}); const filteredItems = useMemo(() => { return data.filter((item) => { return Object.entries(filters).every(([key, filter]) => resolveFilterByType(filter, item[key]), ); }); }, [data, filters]); const { items, changeOffset } = usePagination({ items: filteredItems, }); const handleUpdateFilters = ( name: string, type: HeaderType, value: any, ): void => { console.log(value); setFilters((prev) => { if (value === null) { // eslint-disable-next-line @typescript-eslint/no-dynamic-delete delete prev[name]; return { ...prev }; } return { ...prev, [name]: { value, type } }; }); }; function formatCell(data: DataItem, header: Header): JSX.Element { // This formatting is only used because the source is trusted (private markdown files manage only by me) // and because Astro don't allow me to pass JSX from an Astro file to a TSX file, // so I have to pass the formatted row as a string. // DON'T use this method on a public API if (header.formatter != null) { return (
); } if (header.type === HeaderType.Multiple) { return (
    {data[header.key].map((item: JSX.Element, idx: number) => (
  • {item}
  • ))}
); } return data[header.key]; } function formatFilter(header: Header): JSX.Element { switch (header.type) { case HeaderType.String: return ( { handleUpdateFilters( header.key, header.type, e.target.value ?? null, ); }} /> ); case HeaderType.Number: return ( { handleUpdateFilters(header.key, header.type, value); }} /> ); case HeaderType.Select: return ( { handleUpdateFilters(header.key, header.type, value); }} /> ); case HeaderType.Multiple: return ( { handleUpdateFilters(header.key, header.type, value); }} /> ); default: break; } return <>; } return ( <> {headers.map((item, idx) => ( ))} {items.map((item, idx) => ( {headers.map((header, hidx) => ( ))} ))}
{item.header} {formatFilter(item)}
{formatCell(item, header)}
); }