| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- import { useEffect, useState } from 'react'
- import {
- type SortingState,
- type VisibilityState,
- flexRender,
- getCoreRowModel,
- getFacetedRowModel,
- getFacetedUniqueValues,
- useReactTable,
- } from '@tanstack/react-table'
- import { cn } from '@/lib/utils'
- import { type NavigateFn, useTableUrlState } from '@/hooks/use-table-url-state'
- import {
- Table,
- TableBody,
- TableCell,
- TableHead,
- TableHeader,
- TableRow,
- } from '@/components/ui/table'
- import { DataTablePagination, DataTableToolbar } from '@/components/data-table'
- import { DataTableBulkActions } from './data-table-bulk-actions'
- import { evaluationColumns as columns } from './evaluations-columns'
- import type { Pagination } from '@/types/common.types'
- import type { Evaluation } from '@/types/evaluations.types'
- type DataTableProps = {
- data: Evaluation[]
- paginationData?: Pagination
- search: Record<string, unknown>
- navigate: NavigateFn
- }
- export function EvaluationsTable({
- data,
- paginationData,
- search,
- navigate,
- }: DataTableProps) {
- // Local UI-only states
- const [rowSelection, setRowSelection] = useState({})
- const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({
- status: false,
- })
- const [sorting, setSorting] = useState<SortingState>([])
- // Local state management for table (uncomment to use local-only state, not synced with URL)
- // const [columnFilters, onColumnFiltersChange] = useState<ColumnFiltersState>([])
- // const [pagination, onPaginationChange] = useState<PaginationState>({ pageIndex: 0, pageSize: 10 })
- // Synced with URL states (keys/defaults mirror users route search schema)
- const {
- columnFilters,
- onColumnFiltersChange,
- pagination,
- onPaginationChange,
- ensurePageInRange,
- } = useTableUrlState({
- search,
- navigate,
- pagination: { defaultPage: 1, defaultPageSize: 10 },
- globalFilter: { enabled: false },
- columnFilters: [
- // username per-column text filter
- { columnId: 'username', searchKey: 'username', type: 'string' },
- { columnId: 'status', searchKey: 'status', type: 'array' },
- { columnId: 'role', searchKey: 'role', type: 'array' },
- {
- columnId: 'status',
- searchKey: 'status',
- type: 'string',
- },
- ],
- })
- // eslint-disable-next-line react-hooks/incompatible-library
- const table = useReactTable({
- data,
- columns,
- state: {
- sorting,
- pagination,
- rowSelection,
- columnFilters,
- columnVisibility,
- },
- pageCount: paginationData?.last_page ?? -1,
- manualPagination: true,
- manualFiltering: true,
- manualSorting: true,
- enableRowSelection: true,
- onPaginationChange,
- onColumnFiltersChange,
- onRowSelectionChange: setRowSelection,
- onSortingChange: setSorting,
- onColumnVisibilityChange: setColumnVisibility,
- getCoreRowModel: getCoreRowModel(),
- getFacetedRowModel: getFacetedRowModel(),
- getFacetedUniqueValues: getFacetedUniqueValues(),
- })
- useEffect(() => {
- ensurePageInRange(table.getPageCount())
- }, [table, ensurePageInRange])
- return (
- <div
- className={cn(
- 'max-sm:has-[div[role="toolbar"]]:mb-16', // Add margin bottom to the table on mobile when the toolbar is visible
- 'flex flex-1 flex-col gap-4'
- )}
- >
- <DataTableToolbar
- table={table}
- searchPlaceholder='فیلتر کاربران...'
- searchKey='username'
- filters={[
- {
- columnId: 'status',
- title: 'وضعیت ارزیابی',
- multiple: false,
- options: [
- { label: 'تکمیل شده', value: 'approved' },
- { label: 'در انتظار تایید', value: 'approved_ai' },
- { label: 'در حال بررسی', value: 'pending' },
- { label: 'رد شده', value: 'rejected' },
- ],
- },
- ]}
- />
- <div className='overflow-hidden rounded-md border'>
- <Table>
- <TableHeader>
- {table.getHeaderGroups().map((headerGroup) => (
- <TableRow key={headerGroup.id} className='group/row'>
- {headerGroup.headers.map((header) => {
- return (
- <TableHead
- key={header.id}
- colSpan={header.colSpan}
- className={cn(
- 'bg-background group-hover/row:bg-muted group-data-[state=selected]/row:bg-muted',
- header.column.columnDef.meta?.className,
- header.column.columnDef.meta?.thClassName
- )}
- >
- {header.isPlaceholder
- ? null
- : flexRender(
- header.column.columnDef.header,
- header.getContext()
- )}
- </TableHead>
- )
- })}
- </TableRow>
- ))}
- </TableHeader>
- <TableBody>
- {table.getRowModel().rows?.length ? (
- table.getRowModel().rows.map((row) => (
- <TableRow
- key={row.id}
- data-state={row.getIsSelected() && 'selected'}
- className='group/row'
- >
- {row.getVisibleCells().map((cell) => (
- <TableCell
- key={cell.id}
- className={cn(
- 'bg-background group-hover/row:bg-muted group-data-[state=selected]/row:bg-muted',
- cell.column.columnDef.meta?.className,
- cell.column.columnDef.meta?.tdClassName
- )}
- >
- {flexRender(
- cell.column.columnDef.cell,
- cell.getContext()
- )}
- </TableCell>
- ))}
- </TableRow>
- ))
- ) : (
- <TableRow>
- <TableCell
- colSpan={columns?.length}
- className='h-24 text-center'
- >
- نتیجه ای یافت نشد.
- </TableCell>
- </TableRow>
- )}
- </TableBody>
- </Table>
- </div>
- <DataTablePagination table={table} className='mt-auto' />
- <DataTableBulkActions table={table} />
- </div>
- )
- }
|