data-table.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. 'use client';
  2. import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table.js';
  3. import { DataTablePagination } from '@/framework/internal/data-table/data-table-pagination.js';
  4. import { DataTableViewOptions } from '@/framework/internal/data-table/data-table-view-options.js';
  5. import {
  6. ColumnDef,
  7. flexRender,
  8. getCoreRowModel,
  9. getPaginationRowModel,
  10. PaginationState,
  11. VisibilityState,
  12. SortingState,
  13. Table as TableType,
  14. useReactTable,
  15. ColumnFilter,
  16. ColumnFiltersState,
  17. } from '@tanstack/react-table';
  18. import React, { useEffect } from 'react';
  19. interface DataTableProps<TData, TValue> {
  20. columns: ColumnDef<TData, TValue>[];
  21. data: TData[];
  22. totalItems: number;
  23. page?: number;
  24. itemsPerPage?: number;
  25. sorting?: SortingState;
  26. columnFilters?: ColumnFiltersState;
  27. onPageChange?: (table: TableType<TData>, page: number, itemsPerPage: number) => void;
  28. onSortChange?: (table: TableType<TData>, sorting: SortingState) => void;
  29. onFilterChange?: (table: TableType<TData>, columnFilters: ColumnFilter[]) => void;
  30. defaultColumnVisibility?: VisibilityState;
  31. }
  32. export function DataTable<TData, TValue>({
  33. columns,
  34. data,
  35. totalItems,
  36. page,
  37. itemsPerPage,
  38. sorting: sortingInitialState,
  39. columnFilters: filtersInitialState,
  40. onPageChange,
  41. onSortChange,
  42. onFilterChange,
  43. defaultColumnVisibility,
  44. }: DataTableProps<TData, TValue>) {
  45. const [sorting, setSorting] = React.useState<SortingState>(sortingInitialState || []);
  46. const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(filtersInitialState || []);
  47. const [pagination, setPagination] = React.useState<PaginationState>({
  48. pageIndex: (page ?? 1) - 1,
  49. pageSize: itemsPerPage ?? 10,
  50. });
  51. const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>(
  52. defaultColumnVisibility ?? {},
  53. );
  54. const table = useReactTable({
  55. data,
  56. columns,
  57. getCoreRowModel: getCoreRowModel(),
  58. getPaginationRowModel: getPaginationRowModel(),
  59. manualPagination: true,
  60. manualSorting: true,
  61. manualFiltering: true,
  62. rowCount: totalItems,
  63. onPaginationChange: setPagination,
  64. onSortingChange: setSorting,
  65. onColumnVisibilityChange: setColumnVisibility,
  66. onColumnFiltersChange: setColumnFilters,
  67. state: {
  68. pagination,
  69. sorting,
  70. columnVisibility,
  71. columnFilters,
  72. },
  73. });
  74. useEffect(() => {
  75. onPageChange?.(table, pagination.pageIndex + 1, pagination.pageSize);
  76. }, [pagination]);
  77. useEffect(() => {
  78. onSortChange?.(table, sorting);
  79. }, [sorting]);
  80. useEffect(() => {
  81. onFilterChange?.(table, columnFilters);
  82. }, [columnFilters]);
  83. return (
  84. <>
  85. <DataTableViewOptions table={table} />
  86. <div className="rounded-md border my-2">
  87. <Table>
  88. <TableHeader>
  89. {table.getHeaderGroups().map(headerGroup => (
  90. <TableRow key={headerGroup.id}>
  91. {headerGroup.headers.map(header => {
  92. return (
  93. <TableHead key={header.id}>
  94. {header.isPlaceholder
  95. ? null
  96. : flexRender(
  97. header.column.columnDef.header,
  98. header.getContext(),
  99. )}
  100. </TableHead>
  101. );
  102. })}
  103. </TableRow>
  104. ))}
  105. </TableHeader>
  106. <TableBody>
  107. {table.getRowModel().rows?.length ? (
  108. table.getRowModel().rows.map(row => (
  109. <TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
  110. {row.getVisibleCells().map(cell => (
  111. <TableCell key={cell.id}>
  112. {flexRender(cell.column.columnDef.cell, cell.getContext())}
  113. </TableCell>
  114. ))}
  115. </TableRow>
  116. ))
  117. ) : (
  118. <TableRow>
  119. <TableCell colSpan={columns.length} className="h-24 text-center">
  120. No results.
  121. </TableCell>
  122. </TableRow>
  123. )}
  124. </TableBody>
  125. </Table>
  126. </div>
  127. <DataTablePagination table={table} />
  128. </>
  129. );
  130. }