From c295c330ff522b9317b10ce03df967d1e1fa3321 Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 9 Mar 2025 16:30:11 -0400 Subject: [PATCH] Add copy down functionality to validate table --- .../components/ValidationCell.tsx | 56 +++++++++++++++++-- .../components/ValidationContainer.tsx | 31 ++++------ .../components/ValidationTable.tsx | 27 +++++++-- .../hooks/useValidationState.tsx | 15 ++++- 4 files changed, 99 insertions(+), 30 deletions(-) diff --git a/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx b/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx index c8a22f5..fdce32e 100644 --- a/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx +++ b/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationCell.tsx @@ -1,6 +1,6 @@ import React from 'react' import { Field } from '../../../types' -import { Loader2, AlertCircle } from 'lucide-react' +import { Loader2, AlertCircle, CopyDown, ArrowDown } from 'lucide-react' import { Tooltip, TooltipContent, @@ -122,6 +122,7 @@ export interface ValidationCellProps { itemNumber?: string width: number rowIndex: number + copyDown?: () => void } const ItemNumberCell = React.memo(({ @@ -131,7 +132,8 @@ const ItemNumberCell = React.memo(({ width, errors = [], field, - onChange + onChange, + copyDown }: { value: any, itemNumber?: string, @@ -139,7 +141,8 @@ const ItemNumberCell = React.memo(({ width: number, errors?: ErrorObject[], field: Field, - onChange: (value: any) => void + onChange: (value: any) => void, + copyDown?: () => void }) => { // Helper function to check if a value is empty const isEmpty = (val: any): boolean => @@ -171,7 +174,7 @@ const ItemNumberCell = React.memo(({ : ''; return ( - +
{isValidating ? (
@@ -197,6 +200,25 @@ const ItemNumberCell = React.memo(({ }} />
)} + {copyDown && ( +
+ + + + + + +

Copy value to all cells below

+
+
+
+
+ )}
); @@ -218,7 +240,9 @@ const ValidationCell = ({ fieldKey, options = [], itemNumber, - width}: ValidationCellProps) => { + width, + rowIndex, + copyDown}: ValidationCellProps) => { // For item_number fields, use the specialized component if (fieldKey === 'item_number') { return ( @@ -230,6 +254,7 @@ const ValidationCell = ({ errors={errors} field={field} onChange={onChange} + copyDown={copyDown} /> ); } @@ -273,7 +298,7 @@ const ValidationCell = ({ field.fieldType.price === true; return ( - +
{isValidating ? (
@@ -299,6 +324,25 @@ const ValidationCell = ({ }} />
)} + {copyDown && ( +
+ + + + + + +

Copy value to all cells below

+
+
+
+
+ )}
); diff --git a/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx b/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx index 577f73f..7149e6d 100644 --- a/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx +++ b/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationContainer.tsx @@ -56,7 +56,8 @@ const ValidationContainer = ({ loadTemplates, setData, fields, - isLoadingTemplates } = validationState + isLoadingTemplates, + copyDown } = validationState // Add state for tracking product lines and sublines per row const [rowProductLines, setRowProductLines] = useState>({}); @@ -832,22 +833,20 @@ const ValidationContainer = ({ validatingCells={validatingCells} itemNumbers={itemNumbersMap} isLoadingTemplates={isLoadingTemplates} + copyDown={copyDown} /> ); - }, [validatingUpcRows, itemNumbers, isLoadingTemplates]); + }, [validatingUpcRows, itemNumbers, isLoadingTemplates, copyDown]); // Memoize the ValidationTable to prevent unnecessary re-renders const renderValidationTable = useMemo(() => { return ( - enhancedUpdateRow(rowIndex, key as T, value) - } + fields={fields} rowSelection={rowSelection} setRowSelection={setRowSelection} + updateRow={updateRow} validationErrors={validationErrors} isValidatingUpc={isRowValidatingUpc} validatingUpcRows={Array.from(validatingUpcRows)} @@ -855,22 +854,19 @@ const ValidationContainer = ({ templates={templates} applyTemplate={applyTemplate} getTemplateDisplayText={getTemplateDisplayText} - rowProductLines={rowProductLines} - rowSublines={rowSublines} - isLoadingLines={isLoadingLines} - isLoadingSublines={isLoadingSublines} - upcValidationResults={new Map(Object.entries(itemNumbers).map(([key, value]) => [parseInt(key), { itemNumber: value }]))} validatingCells={new Set()} itemNumbers={new Map()} + isLoadingTemplates={isLoadingTemplates} + copyDown={copyDown} /> ); }, [ EnhancedValidationTable, filteredData, - validationState.fields, - enhancedUpdateRow, + fields, rowSelection, setRowSelection, + updateRow, validationErrors, isRowValidatingUpc, validatingUpcRows, @@ -878,11 +874,8 @@ const ValidationContainer = ({ templates, applyTemplate, getTemplateDisplayText, - rowProductLines, - rowSublines, - isLoadingLines, - isLoadingSublines, - itemNumbers + isLoadingTemplates, + copyDown ]); return ( diff --git a/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx b/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx index caf1f8e..b1a9e48 100644 --- a/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx +++ b/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/components/ValidationTable.tsx @@ -45,6 +45,7 @@ interface ValidationTableProps { validatingCells: Set itemNumbers: Map isLoadingTemplates?: boolean + copyDown: (rowIndex: number, key: string) => void [key: string]: any } @@ -62,6 +63,7 @@ interface MemoizedCellProps { validatingCells: Set itemNumbers: Map width: number + copyDown: (rowIndex: number, key: string) => void } // Memoized cell component that only updates when its specific data changes @@ -73,7 +75,8 @@ const MemoizedCell = React.memo(({ validationErrors, validatingCells, itemNumbers, - width + width, + copyDown }: MemoizedCellProps) => { const rowErrors = validationErrors.get(rowIndex) || {}; const fieldErrors = rowErrors[String(field.key)] || []; @@ -92,6 +95,11 @@ const MemoizedCell = React.memo(({ updateRow(rowIndex, field.key, newValue); }, [updateRow, rowIndex, field.key]); + // Memoize the copyDown handler + const handleCopyDown = useCallback(() => { + copyDown(rowIndex, field.key); + }, [copyDown, rowIndex, field.key]); + return ( ); }, (prev, next) => { @@ -177,6 +186,7 @@ interface MemoizedRowProps { options?: { [key: string]: any[] }; rowIndex: number; isSelected: boolean; + copyDown: (rowIndex: number, key: string) => void; } const MemoizedRow = React.memo(({ @@ -188,7 +198,8 @@ const MemoizedRow = React.memo(({ itemNumbers, options = {}, rowIndex, - isSelected + isSelected, + copyDown }) => { return ( (({ const isValidating = validatingCells.has(`${rowIndex}-${field.key}`); + // Memoize the copyDown handler + const handleCopyDown = () => { + copyDown(rowIndex, field.key); + }; + return ( (({ width={fieldWidth} rowIndex={rowIndex} itemNumber={itemNumbers.get(rowIndex)} + copyDown={handleCopyDown} /> ); })} @@ -272,7 +289,8 @@ const ValidationTable = ({ getTemplateDisplayText, validatingCells, itemNumbers, - isLoadingTemplates = false + isLoadingTemplates = false, + copyDown }: ValidationTableProps) => { const { translations } = useRsi(); @@ -430,11 +448,12 @@ const ValidationTable = ({ validatingCells={validatingCells} itemNumbers={itemNumbers} width={fieldWidth} + copyDown={(rowIndex, key) => copyDown(rowIndex, key as T)} /> ); } }; - }).filter((col): col is ColumnDef, any> => col !== null), [fields, validationErrors, validatingCells, itemNumbers, updateRow]); + }).filter((col): col is ColumnDef, any> => col !== null), [fields, validationErrors, validatingCells, itemNumbers, updateRow, copyDown]); // Combine columns const columns = useMemo(() => [selectionColumn, templateColumn, ...fieldColumns], [selectionColumn, templateColumn, fieldColumns]); diff --git a/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx b/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx index d6c87a9..d5f4ea5 100644 --- a/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx +++ b/inventory/src/lib/react-spreadsheet-import/src/steps/ValidationStepNew/hooks/useValidationState.tsx @@ -901,9 +901,21 @@ useEffect(() => { newSet.delete(`${rowIndex}-${key}`); return newSet; }); - }, 300); // Increase debounce time to reduce validation frequency + }, 300); }, [data, validateRow, validateUpc, setData, setRowValidationStatus, cleanPriceFields, fields]); + // Copy a cell value to all cells below it in the same column + const copyDown = useCallback((rowIndex: number, key: T) => { + // Get the source value to copy + const sourceValue = data[rowIndex][key]; + + // Update all rows below with the same value using the existing updateRow function + // This ensures all validation logic runs consistently + for (let i = rowIndex + 1; i < data.length; i++) { + updateRow(i, key, sourceValue); + } + }, [data, updateRow]); + // Add this at the top of the component, after other useRef declarations const validationTimeoutsRef = useRef>({}); @@ -1616,6 +1628,7 @@ useEffect(() => { // Row manipulation updateRow, + copyDown, // Templates templates,