Move UPC validation table adapter out of ValidationContainer

This commit is contained in:
2025-03-17 16:36:26 -04:00
parent 136f767309
commit 8fdb68fb19
3 changed files with 178 additions and 86 deletions

View File

@@ -0,0 +1,140 @@
import React, { useMemo } from 'react'
import ValidationTable from './ValidationTable'
import { RowSelectionState } from '@tanstack/react-table'
import { Fields } from '../../../types'
interface UpcValidationTableAdapterProps<T extends string> {
data: any[]
fields: Fields<string>
validationErrors: Map<number, Record<string, any[]>>
rowSelection: RowSelectionState
setRowSelection: (value: RowSelectionState) => void
updateRow: (rowIndex: number, key: T, value: any) => void
filters: any
templates: any[]
applyTemplate: (templateId: string, rowIndexes: number[]) => void
getTemplateDisplayText: (templateId: string) => string
isValidatingUpc: (rowIndex: number) => boolean
validatingUpcRows: number[]
copyDown: (rowIndex: number, fieldKey: string, endRowIndex?: number) => void
validatingCells: Set<string>
isLoadingTemplates: boolean
rowProductLines: Record<string, any[]>
rowSublines: Record<string, any[]>
isLoadingLines: Record<string, boolean>
isLoadingSublines: Record<string, boolean>
upcValidation: {
validatingRows: Set<number>
getItemNumber: (rowIndex: number) => string | undefined
}
}
/**
* UpcValidationTableAdapter component - connects UPC validation data to ValidationTable
*
* This component adapts UPC validation data and functionality to work with the core ValidationTable,
* transforming item numbers and validation states into a format the table component can render.
*/
function UpcValidationTableAdapter<T extends string>({
data,
fields,
validationErrors,
rowSelection,
setRowSelection,
updateRow,
filters,
templates,
applyTemplate,
getTemplateDisplayText,
isValidatingUpc,
validatingUpcRows,
copyDown,
validatingCells: externalValidatingCells,
isLoadingTemplates,
rowProductLines,
rowSublines,
isLoadingLines,
isLoadingSublines,
upcValidation
}: UpcValidationTableAdapterProps<T>) {
// Prepare the validation table with UPC data
const AdaptedTable = useMemo(() => React.memo((props: React.ComponentProps<typeof ValidationTable>) => {
// Create validatingCells set from validating rows, but only for item_number fields
// This ensures only the item_number column shows loading state during UPC validation
const combinedValidatingCells = new Set<string>();
// Add UPC validation cells
upcValidation.validatingRows.forEach(rowIndex => {
// Only mark the item_number cells as validating, NOT the UPC or supplier
combinedValidatingCells.add(`${rowIndex}-item_number`);
});
// Add any other validating cells from state
externalValidatingCells.forEach(cellKey => {
combinedValidatingCells.add(cellKey);
});
// Convert the Map to the expected format for the ValidationTable
// Create a new Map from the item numbers to ensure proper typing
const itemNumbersMap = new Map<number, string>();
// Merge the item numbers with the data for display purposes only
const enhancedData = props.data.map((row: any, index: number) => {
const itemNumber = upcValidation.getItemNumber(index);
if (itemNumber) {
// Add to our map for proper prop passing
itemNumbersMap.set(index, itemNumber);
return {
...row,
item_number: itemNumber
};
}
return row;
});
return (
<ValidationTable
{...props}
data={enhancedData}
validatingCells={combinedValidatingCells}
itemNumbers={itemNumbersMap}
isLoadingTemplates={isLoadingTemplates}
copyDown={copyDown}
rowProductLines={rowProductLines}
rowSublines={rowSublines}
isLoadingLines={isLoadingLines}
isLoadingSublines={isLoadingSublines}
/>
);
}), [upcValidation.validatingRows, upcValidation.getItemNumber, isLoadingTemplates, copyDown, externalValidatingCells, rowProductLines, rowSublines, isLoadingLines, isLoadingSublines]);
// Render the validation table with the provided props and UPC data
return (
<AdaptedTable
data={data}
fields={fields}
rowSelection={rowSelection}
setRowSelection={setRowSelection}
updateRow={updateRow as unknown as (rowIndex: number, key: string, value: any) => void}
validationErrors={validationErrors}
isValidatingUpc={isValidatingUpc}
validatingUpcRows={validatingUpcRows}
filters={filters}
templates={templates}
applyTemplate={applyTemplate}
getTemplateDisplayText={getTemplateDisplayText}
validatingCells={new Set()}
itemNumbers={new Map()}
isLoadingTemplates={isLoadingTemplates}
copyDown={copyDown}
upcValidationResults={new Map()}
rowProductLines={rowProductLines}
rowSublines={rowSublines}
isLoadingLines={isLoadingLines}
isLoadingSublines={isLoadingSublines}
/>
)
}
export default UpcValidationTableAdapter

View File

@@ -1,6 +1,5 @@
import React, { useState, useEffect, useRef, useCallback, useMemo, useLayoutEffect } from 'react' import React, { useState, useEffect, useRef, useCallback, useMemo, useLayoutEffect } from 'react'
import { useValidationState, Props } from '../hooks/useValidationState' import { useValidationState, Props } from '../hooks/useValidationState'
import ValidationTable from './ValidationTable'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { Loader2, X, Plus, Edit3, Sparkles, FileText } from 'lucide-react' import { Loader2, X, Plus, Edit3, Sparkles, FileText } from 'lucide-react'
import { toast } from 'sonner' import { toast } from 'sonner'
@@ -9,7 +8,6 @@ import { useRsi } from '../../../hooks/useRsi'
import SearchableTemplateSelect from './SearchableTemplateSelect' import SearchableTemplateSelect from './SearchableTemplateSelect'
import { useAiValidation } from '../hooks/useAiValidation' import { useAiValidation } from '../hooks/useAiValidation'
import { AiValidationDialogs } from './AiValidationDialogs' import { AiValidationDialogs } from './AiValidationDialogs'
import config from '@/config'
import { Fields } from '../../../types' import { Fields } from '../../../types'
import { SearchProductTemplateDialog } from '@/components/templates/SearchProductTemplateDialog' import { SearchProductTemplateDialog } from '@/components/templates/SearchProductTemplateDialog'
import { TemplateForm } from '@/components/templates/TemplateForm' import { TemplateForm } from '@/components/templates/TemplateForm'
@@ -17,6 +15,7 @@ import axios from 'axios'
import { RowSelectionState } from '@tanstack/react-table' import { RowSelectionState } from '@tanstack/react-table'
import { useUpcValidation } from '../hooks/useUpcValidation' import { useUpcValidation } from '../hooks/useUpcValidation'
import { useProductLinesFetching } from '../hooks/useProductLinesFetching' import { useProductLinesFetching } from '../hooks/useProductLinesFetching'
import UpcValidationTableAdapter from './UpcValidationTableAdapter'
/** /**
* ValidationContainer component - the main wrapper for the validation step * ValidationContainer component - the main wrapper for the validation step
@@ -75,13 +74,12 @@ const ValidationContainer = <T extends string>({
const [validatingCells, setValidatingCells] = useState<Set<string>>(new Set()); const [validatingCells, setValidatingCells] = useState<Set<string>>(new Set());
// Use UPC validation hook // Use UPC validation hook
const upcValidation = useUpcValidation<T>(data, setData); const upcValidation = useUpcValidation(data, setData);
// Function to check if a specific row is being validated - memoized // Function to check if a specific row is being validated - memoized
const isRowValidatingUpc = upcValidation.isRowValidatingUpc; const isRowValidatingUpc = upcValidation.isRowValidatingUpc;
// Apply all pending updates to the data state // Apply all pending updates to the data state
const applyItemNumbersToData = upcValidation.applyItemNumbersToData;
// Use AI validation hook // Use AI validation hook
const aiValidation = useAiValidation<T>( const aiValidation = useAiValidation<T>(
@@ -553,99 +551,60 @@ const ValidationContainer = <T extends string>({
// No cleanup needed since we're not using a timer // No cleanup needed since we're not using a timer
}, [data, upcValidation]); }, [data, upcValidation]);
// Memoize the enhanced validation table component // Memoize the rendered validation table
const EnhancedValidationTable = useMemo(() => React.memo((props: React.ComponentProps<typeof ValidationTable>) => { const renderValidationTable = useMemo(() => {
// Create validatingCells set from validating rows, but only for item_number fields // Create wrapper for applyTemplate that matches the expected interface
// This ensures only the item_number column shows loading state during UPC validation const applyTemplateWrapper = (templateId: string, rowIndexes: number[]) => {
const combinedValidatingCells = new Set<string>(); if (rowIndexes.length === 1) {
// Single row apply - pass the array with a single index
// Add UPC validation cells applyTemplate(templateId, rowIndexes);
upcValidation.validatingRows.forEach(rowIndex => { } else if (rowIndexes.length > 1) {
// Only mark the item_number cells as validating, NOT the UPC or supplier // Multiple rows - use applyTemplateToSelected
combinedValidatingCells.add(`${rowIndex}-item_number`); applyTemplateToSelected(templateId);
});
// Add any other validating cells from state
validatingCells.forEach(cellKey => {
combinedValidatingCells.add(cellKey);
});
// Convert the Map to the expected format for the ValidationTable
// Create a new Map from the item numbers to ensure proper typing
const itemNumbersMap = new Map<number, string>();
// Merge the item numbers with the data for display purposes only
const enhancedData = props.data.map((row: any, index: number) => {
const itemNumber = upcValidation.getItemNumber(index);
if (itemNumber) {
// Add to our map for proper prop passing
itemNumbersMap.set(index, itemNumber);
return {
...row,
item_number: itemNumber
};
} }
return row; };
});
return ( return (
<ValidationTable <UpcValidationTableAdapter
{...props} data={filteredData}
data={enhancedData} fields={fields as unknown as Fields<string>}
validatingCells={combinedValidatingCells} validationErrors={validationErrors}
itemNumbers={itemNumbersMap} rowSelection={rowSelection}
isLoadingTemplates={isLoadingTemplates} setRowSelection={handleRowSelectionChange}
updateRow={handleUpdateRow}
filters={filters}
templates={templates}
applyTemplate={applyTemplateWrapper}
getTemplateDisplayText={getTemplateDisplayText}
isValidatingUpc={isRowValidatingUpc}
validatingUpcRows={Array.from(upcValidation.validatingRows)}
copyDown={handleCopyDown} copyDown={handleCopyDown}
validatingCells={validatingCells}
isLoadingTemplates={isLoadingTemplates}
rowProductLines={rowProductLines} rowProductLines={rowProductLines}
rowSublines={rowSublines} rowSublines={rowSublines}
isLoadingLines={isLoadingLines} isLoadingLines={isLoadingLines}
isLoadingSublines={isLoadingSublines} isLoadingSublines={isLoadingSublines}
upcValidation={upcValidation}
/> />
); );
}), [upcValidation.validatingRows, upcValidation.getItemNumber, isLoadingTemplates, handleCopyDown, validatingCells, rowProductLines, rowSublines, isLoadingLines, isLoadingSublines]); }, [
// Memoize the rendered validation table
const renderValidationTable = useMemo(() => (
<EnhancedValidationTable
data={filteredData}
fields={fields as unknown as Fields<string>}
rowSelection={rowSelection}
setRowSelection={handleRowSelectionChange as React.Dispatch<React.SetStateAction<RowSelectionState>>}
updateRow={handleUpdateRow as unknown as (rowIndex: number, key: string, value: any) => void}
validationErrors={validationErrors}
isValidatingUpc={isRowValidatingUpc}
validatingUpcRows={Array.from(upcValidation.validatingRows)}
filters={filters}
templates={templates}
applyTemplate={applyTemplate}
getTemplateDisplayText={getTemplateDisplayText}
validatingCells={new Set()}
itemNumbers={new Map()}
isLoadingTemplates={isLoadingTemplates}
copyDown={handleCopyDown}
upcValidationResults={new Map()}
rowProductLines={rowProductLines}
rowSublines={rowSublines}
isLoadingLines={isLoadingLines}
isLoadingSublines={isLoadingSublines}
/>
), [
EnhancedValidationTable,
filteredData, filteredData,
fields, fields,
validationErrors,
rowSelection, rowSelection,
handleRowSelectionChange, handleRowSelectionChange,
handleUpdateRow, handleUpdateRow,
validationErrors,
isRowValidatingUpc,
upcValidation.validatingRows,
filters, filters,
templates, templates,
applyTemplate, applyTemplate,
applyTemplateToSelected,
getTemplateDisplayText, getTemplateDisplayText,
isLoadingTemplates, isRowValidatingUpc,
upcValidation,
handleCopyDown, handleCopyDown,
validatingCells,
isLoadingTemplates,
rowProductLines, rowProductLines,
rowSublines, rowSublines,
isLoadingLines, isLoadingLines,

View File

@@ -1,12 +1,6 @@
import { useState, useCallback, useRef, useEffect } from 'react' import { useState, useCallback, useRef, useEffect } from 'react'
import config from '@/config' import config from '@/config'
import { toast } from 'sonner'
interface UpcValidationResult {
error?: boolean
message?: string
data?: Record<string, any>
}
interface ValidationState { interface ValidationState {
validatingCells: Set<string>; // Using rowIndex-fieldKey as identifier validatingCells: Set<string>; // Using rowIndex-fieldKey as identifier
@@ -14,7 +8,7 @@ interface ValidationState {
validatingRows: Set<number>; // Rows currently being validated validatingRows: Set<number>; // Rows currently being validated
} }
export const useUpcValidation = <T extends string>( export const useUpcValidation = (
data: any[], data: any[],
setData: (updater: any[] | ((prevData: any[]) => any[])) => void setData: (updater: any[] | ((prevData: any[]) => any[])) => void
) => { ) => {
@@ -158,7 +152,6 @@ export const useUpcValidation = <T extends string>(
// Process the response // Process the response
if (response.status === 409) { if (response.status === 409) {
// UPC already exists - show validation error // UPC already exists - show validation error
const errorData = await response.json();
return { success: false }; return { success: false };
} else if (response.ok) { } else if (response.ok) {
// Successful validation - update item number // Successful validation - update item number