import { ONE, ZERO } from '@/constants/common'; import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; import { useAppSelector } from '@/redux/hooks/useAppSelector'; import { totalSizeSelector, paginationSelector, isLoadingSelector, sortColumnSelector, sortOrderSelector, selectedModelIdSelector, searchValueSelector, } from '@/redux/publications/publications.selectors'; import { getPublications } from '@/redux/publications/publications.thunks'; import { Button } from '@/shared/Button'; import { PaginationState, createColumnHelper, flexRender, getCoreRowModel, useReactTable, OnChangeFn, } from '@tanstack/react-table'; import { useState } from 'react'; import { SortByHeader } from './SortByHeader'; import { DEFAULT_PAGE_SIZE } from './PublicationsTable.constants'; import { FilterBySubmapHeader } from './FilterBySubmapHeader/FilterBySubmapHeader.component'; export type PublicationsTableData = { pubmedId: string; title: string; authors: string[]; journal: string; year: number; elementsOnMap: string; submaps: string; }; const columnHelper = createColumnHelper<PublicationsTableData>(); const columns = [ columnHelper.accessor(row => row.pubmedId, { id: 'pubmedId', header: () => <SortByHeader columnName="pubmedId">Pubmed ID</SortByHeader>, size: 128, }), columnHelper.accessor(row => row.title, { id: 'title', header: () => <SortByHeader columnName="title">Title</SortByHeader>, size: 288, }), columnHelper.accessor(row => row.authors, { id: 'authors', header: () => <SortByHeader columnName="authors">Authors</SortByHeader>, size: 200, }), columnHelper.accessor(row => row.journal, { id: 'journal', header: () => <SortByHeader columnName="journal">Journal</SortByHeader>, size: 168, }), columnHelper.accessor(row => row.year, { id: 'year', header: () => <SortByHeader columnName="year">Year</SortByHeader>, size: 80, }), // eslint-disable-next-line @typescript-eslint/no-unused-vars columnHelper.accessor(row => row.elementsOnMap, { header: 'Elements on map', size: 176 }), // eslint-disable-next-line @typescript-eslint/no-unused-vars columnHelper.accessor(row => row.submaps, { id: 'submaps', header: () => <FilterBySubmapHeader />, size: 144, }), ]; type PublicationsTableProps = { data: PublicationsTableData[]; }; export const PublicationsTable = ({ data }: PublicationsTableProps): JSX.Element => { const dispatch = useAppDispatch(); const pagesCount = useAppSelector(totalSizeSelector); const isPublicationsLoading = useAppSelector(isLoadingSelector); const sortColumn = useAppSelector(sortColumnSelector); const sortOrder = useAppSelector(sortOrderSelector); const selectedId = useAppSelector(selectedModelIdSelector); const searchValue = useAppSelector(searchValueSelector); const reduxPagination = useAppSelector(paginationSelector); const [pagination, setPagination] = useState(reduxPagination); const onPaginationChange: OnChangeFn<PaginationState> = updater => { /** updating state this way is forced by table library */ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const nextState = updater(pagination); dispatch( getPublications({ params: { page: nextState.pageIndex, length: DEFAULT_PAGE_SIZE, sortColumn, sortOrder, search: searchValue, }, modelId: selectedId, }), ); setPagination(nextState); }; const table = useReactTable({ state: { pagination, }, columns, data, getCoreRowModel: getCoreRowModel(), manualPagination: true, pageCount: pagesCount, // onPaginationChange: setPagination, onPaginationChange, }); return ( <div className="flex max-h-full w-full flex-col items-center justify-center bg-white p-6"> <div className="w-full overflow-auto"> <table className="w-full min-w-[1184px] table-auto overflow-auto text-sm"> <thead className="sticky top-0 bg-white-pearl"> {table.getHeaderGroups().map(headerGroup => ( <tr key={headerGroup.id} className="border-y "> {headerGroup.headers.map(header => ( <th key={header.id} className="whitespace-nowrap py-2.5" style={{ width: header.getSize() }} > {flexRender(header.column.columnDef.header, header.getContext())} </th> ))} </tr> ))} </thead> <tbody> {data && table.getRowModel().rows.map(row => ( <tr key={row.id} className="even:bg-lotion"> {row.getVisibleCells().map(cell => ( <td key={cell.id} className="p-3" style={{ width: cell.column.getSize(), }} > {flexRender(cell.column.columnDef.cell, cell.getContext())} </td> ))} </tr> ))} </tbody> </table> </div> <div className="flex w-full flex-row justify-end border-t"> <div className="mt-6 flex flex-row items-center"> <Button variantStyles="quiet" className="text-primary-500" onClick={() => table.setPageIndex(ZERO)} disabled={isPublicationsLoading} > First page </Button> <Button variantStyles="secondary" onClick={() => table.previousPage()} disabled={isPublicationsLoading} > Previous page </Button> <div className="mx-4 text-sm font-semibold"> Page {table.getState().pagination.pageIndex + ONE} out of {table.getPageCount()} </div> <Button variantStyles="secondary" onClick={() => table.nextPage()} disabled={isPublicationsLoading} > Next page </Button> <Button variantStyles="quiet" className="text-primary-500" onClick={() => table.setPageIndex(table.getPageCount() - ONE)} disabled={isPublicationsLoading} > Last page </Button> </div> </div> </div> ); };