"use client"; import { type ColumnFiltersState, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, useReactTable, } from "@tanstack/react-table"; import { Alert, AlertDescription, AlertTitle, } from "@workspace/ui/components/alert"; import { Button } from "@workspace/ui/components/button"; import { Checkbox } from "@workspace/ui/components/checkbox"; import Empty from "@workspace/ui/composed/empty"; import { ColumnFilter, type IParams, } from "@workspace/ui/composed/pro-list/column-filter"; import { Pagination } from "@workspace/ui/composed/pro-list/pagination"; import { cn } from "@workspace/ui/lib/utils"; import { ListRestart, Loader, RefreshCcw } from "lucide-react"; import type React from "react"; import { useEffect, useImperativeHandle, useState } from "react"; 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; }>; empty?: React.ReactNode; } export interface ProListActions { refresh: () => void; reset: () => void; } export function ProList>({ request, params, header, batchRender, renderItem, action, texts, empty, }: 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, }); 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(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [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]) )} params={params} table={table} /> ) : ( 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) } /> ); return
{renderItem(item, checkbox)}
; }) ) : (
{empty || }
)}
{loading && (
)}
{rowCount > 0 && }
); }