import { useState, useEffect, useMemo, useCallback, ReactNode } from 'react'; import { Button, Dialog, DialogContent, DialogHeader, DialogTitle, SearchInput, DataGrid, TypeBadge, type CellMouseEvent, type CellClickArgs, type RenderCellProps, type RenderHeaderCellProps, type SortColumn, SortableHeaderRenderer, type DatabaseRecord, type ConvertedValue, type DataGridRowType, } from '@/components'; import { useTables } from '@/features/database/hooks/useTables'; import { useRecords } from '@/features/database/hooks/useRecords'; import { convertSchemaToColumns } from '@/features/database/components/DatabaseDataGrid'; import { formatValueForDisplay } from '@/lib/utils/utils'; import { ColumnType } from '@insforge/shared-schemas'; const PAGE_SIZE = 50; interface LinkRecordModalProps { referenceTable: string; referenceColumn: string; onSelectRecord: (record: DatabaseRecord) => void; children: (openModal: () => void) => ReactNode; } export function LinkRecordModal({ referenceTable, referenceColumn, onSelectRecord, children, }: LinkRecordModalProps) { const [open, setOpen] = useState(false); const [searchQuery, setSearchQuery] = useState(''); const [selectedRecord, setSelectedRecord] = useState(null); const [sortColumns, setSortColumns] = useState([]); const [currentPage, setCurrentPage] = useState(1); const { useTableSchema } = useTables(); const recordsHook = useRecords(referenceTable); // Fetch table schema const { data: schema } = useTableSchema(referenceTable, open); // Fetch records from the reference table const offset = (currentPage - 1) * PAGE_SIZE; const { data: recordsResponse, isLoading } = recordsHook.useTableRecords( PAGE_SIZE, offset, searchQuery || undefined, sortColumns, open ); const recordsData = schema && recordsResponse ? { schema, records: recordsResponse.records, totalRecords: recordsResponse.pagination.total || schema.recordCount, } : undefined; // Reset page when search query changes useEffect(() => { setCurrentPage(1); }, [searchQuery]); const records = useMemo( (): DataGridRowType[] => recordsData?.records || [], [recordsData?.records] ); const totalRecords = recordsData?.totalRecords || 0; const totalPages = Math.ceil(totalRecords / PAGE_SIZE); // Create selected rows set for highlighting const selectedRows = useMemo(() => { if (!selectedRecord) { return new Set(); } return new Set([String(selectedRecord.id || '')]); }, [selectedRecord]); // Handle cell click to select record - only for reference column const handleCellClick = useCallback( (args: CellClickArgs, event: CellMouseEvent) => { // Only allow selection when clicking on the reference column if (args.column.key !== referenceColumn) { // Prevent the default selection behavior for non-reference columns event?.preventDefault(); event?.stopPropagation(); return; } const record = records.find((r: DatabaseRecord) => String(r.id) === String(args.row.id)); if (record) { setSelectedRecord(record); } }, [records, referenceColumn] ); // Convert schema to columns for the DataGrid with visual distinction const columns = useMemo(() => { const cols = convertSchemaToColumns(schema); // Add visual indication for the reference column (clickable column) return cols.map((col) => { const baseCol = { ...col, width: 210, minWidth: 210, resizable: true, editable: false, }; // Helper function to render cell value properly based on type const renderCellValue = (value: ConvertedValue, type: ColumnType | undefined) => { return formatValueForDisplay(value, type); }; if (col.key === referenceColumn) { return { ...baseCol, renderCell: (props: RenderCellProps) => { const displayValue = renderCellValue(String(props.row[col.key]), col.type); return (
{displayValue}
); }, renderHeaderCell: (props: RenderHeaderCellProps) => ( ), }; } return { ...baseCol, cellClass: 'link-modal-disabled-cell', renderCell: (props: RenderCellProps) => { const displayValue = renderCellValue(String(props.row[col.key]), col.type); return (
{displayValue}
); }, renderHeaderCell: (props: RenderHeaderCellProps) => ( ), }; }); }, [schema, referenceColumn]); const handleConfirmSelection = () => { if (selectedRecord) { onSelectRecord(selectedRecord); setOpen(false); } }; const handleCancel = () => { setOpen(false); }; return ( <> {children(() => setOpen(true))} Link Record
Select a record to reference from
{/* Search Bar */}
{/* Records DataGrid */}
{ // Handle selection changes from cell clicks const selectedId = Array.from(newSelectedRows)[0]; if (selectedId) { const record = records.find((r: DatabaseRecord) => String(r.id) === selectedId); if (record) { setSelectedRecord(record); } } else { setSelectedRecord(null); } }} sortColumns={sortColumns} onSortColumnsChange={setSortColumns} onCellClick={handleCellClick} currentPage={currentPage} totalPages={totalPages} pageSize={PAGE_SIZE} totalRecords={totalRecords} onPageChange={setCurrentPage} showSelection={false} showPagination={true} emptyState={

{searchQuery ? 'No records match your search criteria' : 'No records found'}

} />
{/* Footer */}
); }