diff --git a/inventory/src/components/product-import/steps/ValidationStepNew/README.md b/inventory/src/components/product-import/steps/ValidationStepNew/README.md deleted file mode 100644 index 3ef2e75..0000000 --- a/inventory/src/components/product-import/steps/ValidationStepNew/README.md +++ /dev/null @@ -1,58 +0,0 @@ -# ValidationStepNew Component - -This is a refactored version of the original ValidationStep component with improved architecture, performance, and maintainability. - -## Overview - -The ValidationStepNew component is designed to replace the original ValidationStep component in the React Spreadsheet Import library. It provides the same functionality but with a more modular and maintainable codebase. - -## Features - -- Field-level validation (required, regex, unique) -- Row-level validation (supplier, company fields) -- UPC validation with API integration -- Template management (saving, loading, applying) -- Filtering and sorting capabilities -- Error display and management -- Special field handling (input, multi-input, select, checkbox) - -## Usage - -To use the new ValidationStepNew component, select the "Use new validation component" checkbox in the MatchColumnsStep. This will route you to the new implementation instead of the original one. - -## Architecture - -The component is structured as follows: - -- **ValidationContainer**: Main container component that coordinates all subcomponents -- **ValidationTable**: Handles data display, filtering, and column configuration -- **ValidationCell**: Cell-level component with specialized rendering based on field type -- **ValidationToolbar**: Top toolbar with actions and statistics -- **ValidationSidebar**: Contains filters, actions, and other UI controls - -## State Management - -State is managed through custom hooks: - -- **useValidationState**: Main state management hook -- **useValidation**: Validation logic -- **useTemplates**: Template management -- **useFilters**: Filtering logic -- **useUpcValidation**: UPC validation - -## Development - -This component is still under development. The goal is to eventually replace the original ValidationStep component completely once all functionality is implemented and tested. - -## Known Issues - -- Some TypeScript errors in the UploadFlow component when integrating with the new component -- Not all features from the original component are fully implemented yet - -## Roadmap - -1. Complete implementation of all features from the original component -2. Add comprehensive tests -3. Improve performance with virtualization for large datasets -4. Add more customization options -5. Replace the original component completely \ No newline at end of file diff --git a/inventory/src/components/product-import/steps/ValidationStepNew/components/InitializingValidation.tsx b/inventory/src/components/product-import/steps/ValidationStepNew/components/InitializingValidation.tsx new file mode 100644 index 0000000..b225eb2 --- /dev/null +++ b/inventory/src/components/product-import/steps/ValidationStepNew/components/InitializingValidation.tsx @@ -0,0 +1,73 @@ +import React from 'react' +import { Loader2, Check, X } from 'lucide-react' +import { cn } from '@/lib/utils' + +interface InitializationTask { + label: string + status: 'pending' | 'in_progress' | 'completed' | 'failed' +} + +interface InitializingValidationProps { + totalRows: number + tasks: InitializationTask[] +} + +export const InitializingValidation: React.FC = ({ + totalRows, + tasks +}) => { + return ( +
+ +

Initializing Validation

+

Processing {totalRows} rows...

+ + {/* Task checklist */} +
+ {tasks.map((task, index) => ( +
+ {/* Status icon */} +
+ {task.status === 'completed' && ( + + )} + {task.status === 'failed' && ( + + )} + {task.status === 'in_progress' && ( + + )} + {task.status === 'pending' && ( + + )} +
+ + {/* Task label */} + + {task.label} + +
+ ))} +
+
+ ) +} + +export default InitializingValidation diff --git a/inventory/src/components/product-import/steps/ValidationStepNew/components/ValidationContainer.tsx b/inventory/src/components/product-import/steps/ValidationStepNew/components/ValidationContainer.tsx index 3e41ce7..1caec13 100644 --- a/inventory/src/components/product-import/steps/ValidationStepNew/components/ValidationContainer.tsx +++ b/inventory/src/components/product-import/steps/ValidationStepNew/components/ValidationContainer.tsx @@ -20,6 +20,7 @@ import { Skeleton } from '@/components/ui/skeleton' import { Protected } from '@/components/auth/Protected' import { normalizeCountryCode } from '../utils/countryUtils' import { cleanPriceField } from '../utils/priceUtils' +import InitializingValidation from './InitializingValidation' /** * ValidationContainer component - the main wrapper for the validation step * @@ -62,8 +63,8 @@ const ValidationContainer = ({ fields, upcValidation, isLoadingTemplates, - isValidating, isInitializing, + initializationTasks, validatingCells, setValidatingCells, editingCells, @@ -130,10 +131,6 @@ const ValidationContainer = ({ const [isTemplateFormOpen, setIsTemplateFormOpen] = useState(false) const [templateFormInitialData, setTemplateFormInitialData] = useState(null) - const pendingInitializationTasks: string[] = [] - if (isValidating) pendingInitializationTasks.push('validating rows') - if (upcValidation.validatingRows.size > 0) pendingInitializationTasks.push('checking UPCs') - if (isLoadingTemplates) pendingInitializationTasks.push('loading templates') const [fieldOptions, setFieldOptions] = useState(null) // Track fields that need revalidation due to value changes @@ -699,15 +696,17 @@ const ValidationContainer = ({ // Show loading state during initialization if (isInitializing) { + // Convert initializationTasks object to array format + const tasksArray = Object.values(initializationTasks).map(task => ({ + label: task.label, + status: task.status as 'pending' | 'in_progress' | 'completed' | 'failed' + })); + return ( -
- -

Initializing Validation

-

Processing {data.length} rows...

- {pendingInitializationTasks.length > 0 && ( -

Still {pendingInitializationTasks.join(' | ')}

- )} -
+ ); } diff --git a/inventory/src/components/product-import/steps/ValidationStepNew/components/ValidationTable.tsx b/inventory/src/components/product-import/steps/ValidationStepNew/components/ValidationTable.tsx index 74993fe..718e55b 100644 --- a/inventory/src/components/product-import/steps/ValidationStepNew/components/ValidationTable.tsx +++ b/inventory/src/components/product-import/steps/ValidationStepNew/components/ValidationTable.tsx @@ -355,27 +355,28 @@ const ValidationTable = ({ ? row.original[field.key] : row.original[field.key as keyof typeof row.original]; - // Determine if this cell is in loading state - only show loading for empty fields + // Determine if this cell is in loading state let isLoading = false; - - // Only show loading if the field is currently empty - const isEmpty = currentValue === undefined || currentValue === null || currentValue === '' || + + const cellLoadingKey = `${row.index}-${fieldKey}`; + const isEmpty = currentValue === undefined || currentValue === null || currentValue === '' || (Array.isArray(currentValue) && currentValue.length === 0); - - if (isEmpty) { - // Check the validatingCells Set first (for item_number and other fields) - const cellLoadingKey = `${row.index}-${fieldKey}`; - if (validatingCells.has(cellLoadingKey)) { - isLoading = true; - } + + // CRITICAL: Check validatingCells FIRST - this shows loading for item_number during UPC validation + // even if the field already has a value (because we're fetching a new one) + if (validatingCells.has(cellLoadingKey)) { + isLoading = true; + } + // Only show loading for empty fields for these other cases + else if (isEmpty) { // Check if UPC is validating for this row and field is item_number - else if (fieldKey === 'item_number' && isRowValidatingUpc(row.index)) { + if (fieldKey === 'item_number' && isRowValidatingUpc(row.index)) { isLoading = true; } // Add loading state for line/subline fields else if (fieldKey === 'line' && rowId && isLoadingLines[rowId]) { isLoading = true; - } + } else if (fieldKey === 'subline' && rowId && isLoadingSublines[rowId]) { isLoading = true; } diff --git a/inventory/src/components/product-import/steps/ValidationStepNew/hooks/useValidationState.tsx b/inventory/src/components/product-import/steps/ValidationStepNew/hooks/useValidationState.tsx index 55fdd3f..3a0eaa2 100644 --- a/inventory/src/components/product-import/steps/ValidationStepNew/hooks/useValidationState.tsx +++ b/inventory/src/components/product-import/steps/ValidationStepNew/hooks/useValidationState.tsx @@ -280,14 +280,36 @@ export const useValidationState = ({ }, [data, initialValidationComplete, upcValidation.initialValidationDone]); const hasPendingUpcValidation = upcValidation.validatingRows.size > 0; + + // Separate initial validation from subsequent validations + // isInitializing should ONLY be true during the first load, never again const isInitializing = !initialValidationComplete || isInitialValidationRunning || templateManagement.isLoadingTemplates || - hasPendingUpcValidation; + (hasPendingUpcValidation && !upcValidation.initialValidationDone); const isValidating = isInitialValidationRunning; + // Track initialization task statuses for the progress UI + const initializationTasks = { + upcValidation: { + label: 'Validating UPCs and generating item numbers', + status: upcValidation.initialValidationDone ? 'completed' : + hasPendingUpcValidation ? 'in_progress' : 'pending' + }, + fieldValidation: { + label: 'Validating field requirements and formats', + status: initialValidationComplete ? 'completed' : + isInitialValidationRunning ? 'in_progress' : 'pending' + }, + templateLoading: { + label: 'Loading product templates', + status: !templateManagement.isLoadingTemplates ? 'completed' : + 'in_progress' + } + }; + // Targeted uniqueness revalidation: run only when item_number values change useEffect(() => { if (!data || data.length === 0) return; @@ -433,6 +455,7 @@ export const useValidationState = ({ // Validation isValidating, isInitializing, + initializationTasks, validationErrors, rowValidationStatus, validateRow,