Skip to content
Snippets Groups Projects
PublicationsTable.component.tsx 6.58 KiB
Newer Older
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,
} from '@/redux/publications/publications.selectors';
import { getPublications } from '@/redux/publications/publications.thunks';
import { Button } from '@/shared/Button';
import {
  createColumnHelper,
  flexRender,
  getCoreRowModel,
  useReactTable,
} from '@tanstack/react-table';
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>();
  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);
        params: {
          page: nextState.pageIndex,
          length: DEFAULT_PAGE_SIZE,
          sortColumn,
          sortOrder,
    )
      .unwrap()
      .then(() => {
        setPagination(nextState);

        tableRef.current?.scrollIntoView();
      });

  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" ref={tableRef}>
          <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>
  );
};