Move UPC validation table adapter out of ValidationContainer
This commit is contained in:
@@ -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
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user