'use client'; import { Alert, AlertDescription, AlertTitle } from '@shadcn/ui/alert'; import { Button } from '@shadcn/ui/button'; import { Checkbox } from '@shadcn/ui/checkbox'; import { cn } from '@shadcn/ui/lib/utils'; import { ColumnFiltersState, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, useReactTable, } from '@tanstack/react-table'; import { ListRestart, Loader, RefreshCcw } from 'lucide-react'; import React, { useEffect, useImperativeHandle, useState } from 'react'; import Empty from '../empty'; import { ColumnFilter, IParams } from './column-filter'; import { Pagination } from './pagination'; export interface ProListProps { request: ( pagination: { page: number; size: number; }, filter: TValue, ) => Promise<{ list: TData[]; total: number }>; params?: IParams[]; header?: { title?: React.ReactNode; toolbar?: React.ReactNode | React.ReactNode[]; }; batchRender?: (rows: TData[]) => React.ReactNode[]; renderItem: (item: TData, checkbox: React.ReactNode) => React.ReactNode; action?: React.Ref; texts?: Partial<{ textRowsPerPage: string; textPageOf: (current: number, total: number) => string; selectedRowsText: (total: number) => string; }>; } export interface ProListActions { refresh: () => void; reset: () => void; } export function ProList>({ request, params, header, batchRender, renderItem, action, texts, }: ProListProps) { const [columnFilters, setColumnFilters] = useState([]); const [rowSelection, setRowSelection] = useState<{ [key: number]: boolean }>({}); const [data, setData] = useState([]); const [rowCount, setRowCount] = useState(0); const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10, }); const [loading, setLoading] = useState(false); const table = useReactTable({ data, columns: [], onPaginationChange: setPagination, onColumnFiltersChange: setColumnFilters, getCoreRowModel: getCoreRowModel(), getPaginationRowModel: getPaginationRowModel(), getFilteredRowModel: getFilteredRowModel(), onRowSelectionChange: setRowSelection, state: { columnFilters, rowSelection, pagination, }, manualPagination: true, manualFiltering: true, rowCount: rowCount, }); const fetchData = async () => { setLoading(true); try { const response = await request( { page: pagination.pageIndex + 1, size: pagination.pageSize, }, Object.fromEntries(columnFilters.map((item) => [item.id, item.value])) as TValue, ); setData(response.list); setRowCount(response.total); } catch (error) { console.log('Fetch data error:', error); } finally { setLoading(false); } }; const reset = async () => { table.resetColumnFilters(); table.resetGlobalFilter(true); table.resetColumnVisibility(); setRowSelection({}); table.resetPagination(); }; useImperativeHandle(action, () => ({ refresh: fetchData, reset, })); useEffect(() => { fetchData(); }, [pagination.pageIndex, pagination.pageSize, columnFilters]); const handleSelectionChange = (index: number, isSelected: boolean) => { setRowSelection((prevSelection) => ({ ...prevSelection, [index]: isSelected, })); }; const selectedRows = data.filter((_, index) => rowSelection[index]); const selectedCount = selectedRows.length; return (
{params ? ( [item.id, item.value]))} /> ) : ( header?.title )}
{params && params?.length > 0 && ( <> )} {header?.toolbar}
{selectedCount > 0 && batchRender && ( {texts?.selectedRowsText?.(selectedCount) || `Selected ${selectedCount} rows`} {batchRender(selectedRows)} )}
{data.length ? ( data.map((item, index) => { const isSelected = !!rowSelection[index]; const checkbox = ( handleSelectionChange(index, !!value)} aria-label='Select row' /> ); return
{renderItem(item, checkbox)}
; }) ) : (
)}
{loading && (
)}
{rowCount > 0 && ( )}
); }