From 8952881b52545d827cc2aee97507b9ddb0736ec0 Mon Sep 17 00:00:00 2001 From: Potenz Date: Mon, 15 Sep 2025 01:42:17 +0530 Subject: [PATCH] feat(popup-table) - added popup table for extracted ocr data --- .../components/payments/payment-ocr-block.tsx | 316 ++++++++++-------- 1 file changed, 185 insertions(+), 131 deletions(-) diff --git a/apps/Frontend/src/components/payments/payment-ocr-block.tsx b/apps/Frontend/src/components/payments/payment-ocr-block.tsx index 393dc3b..bf387f8 100644 --- a/apps/Frontend/src/components/payments/payment-ocr-block.tsx +++ b/apps/Frontend/src/components/payments/payment-ocr-block.tsx @@ -27,8 +27,12 @@ export default function PaymentOCRBlock() { const [uploadedImages, setUploadedImages] = React.useState([]); const [isDragging, setIsDragging] = React.useState(false); const [isExtracting, setIsExtracting] = React.useState(false); + + // extracted rows shown only inside modal const [rows, setRows] = React.useState([]); - const [columns, setColumns] = React.useState[]>([]); + const [modalColumns, setModalColumns] = React.useState([]); + const [showModal, setShowModal] = React.useState(false); + const [error, setError] = React.useState(null); //Mutation @@ -64,29 +68,10 @@ export default function PaymentOCRBlock() { }, new Set()) ); - setColumns( - allKeys.map((key) => ({ - id: key, // ✅ unique identifier - header: key, - cell: ({ row }) => ( - { - const newData = [...rows]; - newData[row.index] = { - ...newData[row.index], - __id: newData[row.index]!.__id, - [key]: e.target.value, - }; - setRows(newData); - }} - /> - ), - })) - ); + setModalColumns(allKeys); setIsExtracting(false); + setShowModal(true); }, onError: (error: any) => { @@ -99,13 +84,6 @@ export default function PaymentOCRBlock() { }, }); - // ---- Table instance ---- - const table = useReactTable({ - data: rows, - columns, - getCoreRowModel: getCoreRowModel(), - }); - // ---- handlers (all in this file) ----------------------------------------- const handleImageSelect = (e: React.ChangeEvent) => { @@ -143,7 +121,7 @@ export default function PaymentOCRBlock() { const next = prev.filter((_, i) => i !== index); if (next.length === 0) { setRows([]); - setColumns([]); + setModalColumns([]); setError(null); } return next; @@ -222,10 +200,12 @@ export default function PaymentOCRBlock() { // ✅ CLEAR UI: remove files and table rows setUploadedImages([]); setRows([]); - setColumns([]); + setModalColumns([]); setError(null); setIsDragging(false); if (fileInputRef.current) fileInputRef.current.value = ""; + + setShowModal(false); } catch (err: any) { toast({ title: "Error", @@ -235,19 +215,6 @@ export default function PaymentOCRBlock() { } }; - //rows helper - const handleAddRow = () => { - const newRow: Row = { __id: rows.length }; - columns.forEach((c) => { - if (c.id) newRow[c.id] = ""; - }); - setRows((prev) => [...prev, newRow]); - }; - - const handleDeleteRow = (index: number) => { - setRows((prev) => prev.filter((_, i) => i !== index)); - }; - return (
@@ -358,96 +325,183 @@ export default function PaymentOCRBlock() {
- {/* Results Table */} - + {/* show extraction error if any */} {error &&

{error}

} - - {rows.length > 0 && ( -
- {/* Row/Column control buttons */} -
- -
- - {/* Table */} - -
- - - {table.getHeaderGroups().map((hg) => ( - - {hg.headers.map((header) => ( - - ))} - - - ))} - - - {table.getRowModel().rows.map((row, rowIndex) => ( - - {row.getVisibleCells().map((cell) => { - const colId = cell.column.id; // ✅ key for field - return ( - - ); - })} - - - ))} - -
- {flexRender( - header.column.columnDef.header, - header.getContext() - )} - Actions
- { - const newData = [...rows]; - newData[rowIndex] = { - ...newData[rowIndex], - __id: newData[rowIndex]!.__id, // keep id - [colId]: e.target.value, - }; - setRows(newData); - }} - /> - - -
-
- - -
- )} + + setShowModal(false)} + onSave={handleSave} + rows={rows} + setRows={setRows} + columnKeys={modalColumns} + /> +
+ ); +} + +// ---------------- Simple Modal (in-app popup) ---------------- + +export function OCRDetailsModal({ + open, + onClose, + onSave, + rows, + setRows, + columnKeys, +}: { + open: boolean; + onClose: () => void; + onSave: () => void; + rows: Row[]; + setRows: React.Dispatch>; + columnKeys: string[]; +}) { + if (!open) return null; + + //rows helper + const handleDeleteRow = (index: number) => { + setRows((prev) => prev.filter((_, i) => i !== index)); + }; + + const handleAddRow = React.useCallback(() => { + setRows((prev) => { + const newRow: Row = { __id: prev.length }; + columnKeys.forEach((k) => { + newRow[k] = ""; + }); + return [...prev, newRow]; + }); + }, [setRows, columnKeys]); + + const modalColumns = React.useMemo[]>(() => { + // ensure ICN (if present) is moved to the end of the data columns + const reorderedKeys = [ + ...columnKeys.filter((k) => k !== "ICN"), + ...(columnKeys.includes("ICN") ? ["ICN"] : []), + ]; + + return reorderedKeys.map((key) => ({ + id: key, + header: key, + cell: ({ row }) => { + const value = (row.original[key] ?? "") as string; + return ( + { + const v = e.target.value; + setRows((prev) => { + const next = [...prev]; + next[row.index] = { + ...next[row.index], + __id: next[row.index]!.__id, + [key]: v, + }; + return next; + }); + }} + /> + ); + }, + })); + }, [columnKeys, setRows]); + + const table = useReactTable({ + data: rows, + columns: modalColumns, + getCoreRowModel: getCoreRowModel(), + }); + + return ( +
+
+ + {/* larger modal, column layout so footer sticks to bottom */} +
+ {/* header */} +
+
+ +

OCR Payment Details

+
+ +
+ +
+
+ + {/* body (scrollable) */} +
+
+ + + {table.getHeaderGroups().map((hg) => ( + + {hg.headers.map((header) => ( + + ))} + + + ))} + + + + {table.getRowModel().rows.map((r) => ( + + {r.getVisibleCells().map((cell) => ( + + ))} + + + ))} + +
+ {flexRender( + header.column.columnDef.header, + header.getContext() + )} + Actions
+ {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + +
+
+
+ + {/* footer (always visible) */} +
+ +
+
); }