finish bills , po , jobcards relational fields creation

This commit is contained in:
2026-04-13 18:48:15 +03:00
parent 3eb471a604
commit 020ffccfd6
41 changed files with 11973 additions and 467 deletions
@@ -1,10 +1,12 @@
"use client"
import { useState, useMemo, useEffect, useRef } from "react"
import {
useReactTable,
getCoreRowModel,
flexRender,
type ColumnDef,
type RowSelectionState,
} from "@tanstack/react-table"
import {
Table,
@@ -15,8 +17,9 @@ import {
TableRow,
TableCell,
} from "@/shared/components/ui/table"
import { Checkbox } from "@/shared/components/ui/checkbox"
import { DataViewProvider } from "./data-view-context"
import type { DataViewProps } from "./types"
import type { DataViewProps } from "./types"
import { DataViewPagination } from "./data-view-pagination"
import { Skeleton } from "@/shared/components/ui/skeleton"
@@ -29,20 +32,83 @@ export function DataTable<TData>({
isLoading = false,
onRowClick,
slots,
selection,
}: DataViewProps<TData>) {
const rowKeyStr = (selection?.rowKey as string) ?? "id"
// Persisted map of id → original row data across all pages
const persistedMap = useRef<Map<string, TData>>(new Map())
// Current-page selection state that TanStack Table controls
const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
// When the page/data changes, restore selection state for the new page from the map
useEffect(() => {
if (!selection) return
const restored: RowSelectionState = {}
data.forEach((row) => {
const id = String((row as Record<string, unknown>)[rowKeyStr])
if (persistedMap.current.has(id)) restored[id] = true
})
setRowSelection(restored)
}, [data]) // eslint-disable-line react-hooks/exhaustive-deps
const selectionColumn: ColumnDef<TData, unknown> = useMemo(
() => ({
id: "__select__",
header: ({ table }) => (
<Checkbox
checked={
table.getIsAllPageRowsSelected()
? true
: table.getIsSomePageRowsSelected()
? "indeterminate"
: false
}
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
aria-label="Select all"
/>
),
cell: ({ row }) => (
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
aria-label="Select row"
onClick={(e) => e.stopPropagation()}
/>
),
size: 40,
enableSorting: false,
}),
[],
)
const resolvedColumns = useMemo(
() =>
selection
? [selectionColumn, ...(columns as ColumnDef<TData, unknown>[])]
: (columns as ColumnDef<TData, unknown>[]),
[selection, columns, selectionColumn],
)
const table = useReactTable({
data,
columns: columns as ColumnDef<TData, unknown>[],
columns: resolvedColumns,
getCoreRowModel: getCoreRowModel(),
manualPagination: true,
manualSorting: true,
pageCount: pagination.pageCount,
enableRowSelection: !!selection,
getRowId: selection
? (row) => String((row as Record<string, unknown>)[(selection.rowKey as string) ?? "id"])
: undefined,
state: {
sorting,
pagination: {
pageIndex: pagination.page - 1,
pageSize: pagination.pageSize,
},
rowSelection,
},
onSortingChange: (updater) => {
const next = typeof updater === "function" ? updater(sorting) : updater
@@ -61,6 +127,22 @@ export function DataTable<TData>({
},
})
},
onRowSelectionChange: (updater) => {
const next = typeof updater === "function" ? updater(rowSelection) : updater
setRowSelection(next)
if (selection) {
// Sync current page into the persisted map
data.forEach((row) => {
const id = String((row as Record<string, unknown>)[rowKeyStr])
if (next[id]) {
persistedMap.current.set(id, row)
} else {
persistedMap.current.delete(id)
}
})
selection.onSelectionChange(Array.from(persistedMap.current.values()))
}
},
})
return (
@@ -26,6 +26,12 @@ export type DataViewSlots = {
footer?: ReactNode
}
export type DataViewSelection<TData> = {
onSelectionChange: (selectedRows: TData[]) => void
/** Field used as the unique row identifier. Defaults to "id". */
rowKey?: keyof TData
}
export type DataViewProps<TData> = {
columns: ColumnDef<TData, any>[]
data: TData[]
@@ -35,4 +41,5 @@ export type DataViewProps<TData> = {
isLoading?: boolean
onRowClick?: (row: TData) => void
slots?: DataViewSlots
selection?: DataViewSelection<TData>
}