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 { useValidationState, Props } from '../hooks/useValidationState'
import ValidationTable from './ValidationTable'
import { Button } from '@/components/ui/button'
import { Loader2, X, Plus, Edit3, Sparkles, FileText } from 'lucide-react'
import { toast } from 'sonner'
@@ -9,7 +8,6 @@ import { useRsi } from '../../../hooks/useRsi'
import SearchableTemplateSelect from './SearchableTemplateSelect'
import { useAiValidation } from '../hooks/useAiValidation'
import { AiValidationDialogs } from './AiValidationDialogs'
import config from '@/config'
import { Fields } from '../../../types'
import { SearchProductTemplateDialog } from '@/components/templates/SearchProductTemplateDialog'
import { TemplateForm } from '@/components/templates/TemplateForm'
@@ -17,6 +15,7 @@ import axios from 'axios'
import { RowSelectionState } from '@tanstack/react-table'
import { useUpcValidation } from '../hooks/useUpcValidation'
import { useProductLinesFetching } from '../hooks/useProductLinesFetching'
import UpcValidationTableAdapter from './UpcValidationTableAdapter'
/**
* 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());
// 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
const isRowValidatingUpc = upcValidation.isRowValidatingUpc;
// Apply all pending updates to the data state
const applyItemNumbersToData = upcValidation.applyItemNumbersToData;
// Use AI validation hook
const aiValidation = useAiValidation<T>(
@@ -553,99 +551,60 @@ const ValidationContainer = <T extends string>({
// No cleanup needed since we're not using a timer
}, [data, upcValidation]);
// Memoize the enhanced validation table component
const EnhancedValidationTable = 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
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
};
// Memoize the rendered validation table
const renderValidationTable = useMemo(() => {
// Create wrapper for applyTemplate that matches the expected interface
const applyTemplateWrapper = (templateId: string, rowIndexes: number[]) => {
if (rowIndexes.length === 1) {
// Single row apply - pass the array with a single index
applyTemplate(templateId, rowIndexes);
} else if (rowIndexes.length > 1) {
// Multiple rows - use applyTemplateToSelected
applyTemplateToSelected(templateId);
}
return row;
});
};
return (
<ValidationTable
{...props}
data={enhancedData}
validatingCells={combinedValidatingCells}
itemNumbers={itemNumbersMap}
isLoadingTemplates={isLoadingTemplates}
<UpcValidationTableAdapter
data={filteredData}
fields={fields as unknown as Fields<string>}
validationErrors={validationErrors}
rowSelection={rowSelection}
setRowSelection={handleRowSelectionChange}
updateRow={handleUpdateRow}
filters={filters}
templates={templates}
applyTemplate={applyTemplateWrapper}
getTemplateDisplayText={getTemplateDisplayText}
isValidatingUpc={isRowValidatingUpc}
validatingUpcRows={Array.from(upcValidation.validatingRows)}
copyDown={handleCopyDown}
validatingCells={validatingCells}
isLoadingTemplates={isLoadingTemplates}
rowProductLines={rowProductLines}
rowSublines={rowSublines}
isLoadingLines={isLoadingLines}
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,
fields,
validationErrors,
rowSelection,
handleRowSelectionChange,
handleUpdateRow,
validationErrors,
isRowValidatingUpc,
upcValidation.validatingRows,
filters,
templates,
applyTemplate,
applyTemplateToSelected,
getTemplateDisplayText,
isLoadingTemplates,
isRowValidatingUpc,
upcValidation,
handleCopyDown,
validatingCells,
isLoadingTemplates,
rowProductLines,
rowSublines,
isLoadingLines,

View File

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