Uecko_ERP/packages/rdx-ui/src/components/datatable/data-table.tsx

183 lines
5.9 KiB
TypeScript
Raw Normal View History

2025-10-16 11:18:55 +00:00
"use client"
import {
ColumnDef,
ColumnFiltersState,
ColumnSizingState,
SortingState,
VisibilityState,
flexRender,
getCoreRowModel,
getFacetedRowModel,
getFacetedUniqueValues,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable
} from "@tanstack/react-table"
import * as React from "react"
import {
Dialog,
DialogContent,
Table, TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@repo/shadcn-ui/components'
import { DataTablePagination } from './data-table-pagination.tsx'
import { DataTableToolbar } from "./data-table-toolbar.tsx"
import { useTranslation } from "../../locales/i18n.ts"
type DataTableRowOps = {
duplicate?(index: number): void;
remove?(index: number): void;
move?(from: number, to: number): void;
canMoveUp?(index: number): boolean;
canMoveDown?(index: number, lastIndex: number): boolean;
};
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[]
data: TData[],
meta?: Record<string, any>,
getRowId?: (row: TData, index: number) => string;
pageSize?: number;
enableRowSelection?: boolean;
renderRowEditor?: (index: number, close: () => void) => React.ReactNode; // editor modal opcional. Se muestra dentro de un Dialog.
}
export function DataTable<TData, TValue>({
columns,
data,
meta,
getRowId,
pageSize = 25,
enableRowSelection = true,
renderRowEditor,
}: DataTableProps<TData, TValue>) {
const { t } = useTranslation();
const [rowSelection, setRowSelection] = React.useState({});
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({});
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([]);
const [sorting, setSorting] = React.useState<SortingState>([]);
const [colSizes, setColSizes] = React.useState<ColumnSizingState>({});
const [editIndex, setEditIndex] = React.useState<number | null>(null);
const openEditor = React.useCallback((i: number) => setEditIndex(i), []);
const closeEditor = React.useCallback(() => setEditIndex(null), []);
const table = useReactTable({
data,
columns,
columnResizeMode: "onChange",
onColumnSizingChange: setColSizes,
getRowId: getRowId ?? ((row: any, idx) => (row?.id ? String(row.id) : String(idx))),
state: {
columnSizing: colSizes,
sorting,
columnVisibility,
rowSelection,
columnFilters,
},
initialState: { pagination: { pageSize } },
meta: { ...meta, openEditor },
enableRowSelection,
getCoreRowModel: getCoreRowModel(),
onRowSelectionChange: setRowSelection,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
onColumnVisibilityChange: setColumnVisibility,
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFacetedRowModel: getFacetedRowModel(),
getFacetedUniqueValues: getFacetedUniqueValues(),
})
return (
<div className="flex flex-col gap-4">
<DataTableToolbar table={table} />
<div className="overflow-hidden rounded-md border">
<Table className="w-full text-sm">
<TableHeader className="sticky top-0 bg-muted hover:bg-muted z-10">
{table.getHeaderGroups().map((hg) => (
<TableRow key={hg.id}>
{hg.headers.map((h) => {
const w = h.getSize(); // px
const minW = h.column.columnDef.minSize;
const maxW = h.column.columnDef.maxSize;
return (
<TableHead
key={h.id}
colSpan={h.colSpan}
style={{
width: w ? `${w}px` : undefined,
minWidth: typeof minW === "number" ? `${minW}px` : undefined,
maxWidth: typeof maxW === "number" ? `${maxW}px` : undefined,
}}
>
{h.isPlaceholder ? null : flexRender(h.column.columnDef.header, h.getContext())}
</TableHead>
);
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows.length ? (
table.getRowModel().rows.map((row) => (
<TableRow key={row.id} data-state={row.getIsSelected() && "selected"}>
{row.getVisibleCells().map((cell) => {
const w = cell.column.getSize();
const minW = cell.column.columnDef.minSize;
const maxW = cell.column.columnDef.maxSize;
return (
<TableCell
key={cell.id}
className="align-top"
style={{
width: w ? `${w}px` : undefined,
minWidth: typeof minW === "number" ? `${minW}px` : undefined,
maxWidth: typeof maxW === "number" ? `${maxW}px` : undefined,
}}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
);
})}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
{t("components.datatabla.empty")}
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
<DataTablePagination table={table} />
{!!renderRowEditor && editIndex !== null && (
<Dialog open onOpenChange={(open) => (!open ? closeEditor() : null)}>
<DialogContent className="max-w-xl">
{renderRowEditor(editIndex, closeEditor)}
</DialogContent>
</Dialog>
)}
</div>
);
}