Fix applying templates to or discarding multiple rows
This commit is contained in:
@@ -52,17 +52,6 @@ const SearchableTemplateSelect: React.FC<SearchableTemplateSelectProps> = ({
|
|||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [] = useState<string | null>(null);
|
const [] = useState<string | null>(null);
|
||||||
|
|
||||||
// Debug logging
|
|
||||||
useEffect(() => {
|
|
||||||
// Only log when selectedBrand changes or on mount
|
|
||||||
console.debug('SearchableTemplateSelect brand update:', {
|
|
||||||
selectedBrand,
|
|
||||||
defaultBrand,
|
|
||||||
templatesCount: templates?.length || 0,
|
|
||||||
templatesForBrand: templates?.filter(t => t.company === selectedBrand)?.length || 0
|
|
||||||
});
|
|
||||||
}, [selectedBrand, defaultBrand, templates]);
|
|
||||||
|
|
||||||
// Set default brand when component mounts or defaultBrand changes
|
// Set default brand when component mounts or defaultBrand changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (defaultBrand) {
|
if (defaultBrand) {
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ const ValidationContainer = <T extends string>({
|
|||||||
loadTemplates,
|
loadTemplates,
|
||||||
setData,
|
setData,
|
||||||
fields,
|
fields,
|
||||||
isLoadingTemplates
|
isLoadingTemplates,
|
||||||
|
rowValidationStatus
|
||||||
} = validationState
|
} = validationState
|
||||||
|
|
||||||
// Add state for tracking product lines and sublines per row
|
// Add state for tracking product lines and sublines per row
|
||||||
@@ -563,16 +564,37 @@ const ValidationContainer = <T extends string>({
|
|||||||
}, [onNext, data, applyItemNumbersToData]);
|
}, [onNext, data, applyItemNumbersToData]);
|
||||||
|
|
||||||
const deleteSelectedRows = useCallback(() => {
|
const deleteSelectedRows = useCallback(() => {
|
||||||
// Get selected row indices
|
// Get selected row keys (which may be UUIDs)
|
||||||
const selectedRowIndexes = Object.keys(rowSelection).map(Number);
|
const selectedKeys = Object.entries(rowSelection)
|
||||||
|
.filter(([_, selected]) => selected === true)
|
||||||
|
.map(([key, _]) => key);
|
||||||
|
|
||||||
if (selectedRowIndexes.length === 0) {
|
console.log('Selected row keys for deletion:', selectedKeys);
|
||||||
|
|
||||||
|
if (selectedKeys.length === 0) {
|
||||||
toast.error("No rows selected");
|
toast.error("No rows selected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Map UUID keys to array indices
|
||||||
|
const selectedIndices = selectedKeys.map(key => {
|
||||||
|
// Find the matching row index in the data array
|
||||||
|
const index = data.findIndex(row =>
|
||||||
|
(row.__index && row.__index === key) || // Match by __index
|
||||||
|
(String(data.indexOf(row)) === key) // Or by numeric index
|
||||||
|
);
|
||||||
|
return index;
|
||||||
|
}).filter(index => index !== -1); // Filter out any not found
|
||||||
|
|
||||||
|
console.log('Mapped row indices for deletion:', selectedIndices);
|
||||||
|
|
||||||
|
if (selectedIndices.length === 0) {
|
||||||
|
toast.error('Could not find selected rows');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Sort indices in descending order to avoid index shifting during removal
|
// Sort indices in descending order to avoid index shifting during removal
|
||||||
const sortedIndices = [...selectedRowIndexes].sort((a, b) => b - a);
|
const sortedIndices = [...selectedIndices].sort((a, b) => b - a);
|
||||||
|
|
||||||
// Create a new array without the selected rows
|
// Create a new array without the selected rows
|
||||||
const newData = [...data];
|
const newData = [...data];
|
||||||
@@ -592,9 +614,9 @@ const ValidationContainer = <T extends string>({
|
|||||||
|
|
||||||
// Show success message
|
// Show success message
|
||||||
toast.success(
|
toast.success(
|
||||||
selectedRowIndexes.length === 1
|
selectedIndices.length === 1
|
||||||
? "Row deleted"
|
? "Row deleted"
|
||||||
: `${selectedRowIndexes.length} rows deleted`
|
: `${selectedIndices.length} rows deleted`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reindex the data in the next render cycle
|
// Reindex the data in the next render cycle
|
||||||
@@ -829,7 +851,11 @@ const ValidationContainer = <T extends string>({
|
|||||||
<Button
|
<Button
|
||||||
variant={isFromScratch ? "destructive" : "outline"}
|
variant={isFromScratch ? "destructive" : "outline"}
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={deleteSelectedRows}
|
onClick={() => {
|
||||||
|
console.log('Delete/Discard button clicked');
|
||||||
|
console.log('Row selection state:', rowSelection);
|
||||||
|
deleteSelectedRows();
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{isFromScratch ? "Delete Row" : translations.validationStep.discardButtonTitle || "Discard Row"}
|
{isFromScratch ? "Delete Row" : translations.validationStep.discardButtonTitle || "Discard Row"}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -350,6 +350,10 @@ const ValidationTable = <T extends string>({
|
|||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const templateValue = row.original.__template || null;
|
const templateValue = row.original.__template || null;
|
||||||
const defaultBrand = row.original.company || undefined;
|
const defaultBrand = row.original.company || undefined;
|
||||||
|
const rowIndex = data.findIndex(r => r === row.original);
|
||||||
|
|
||||||
|
console.log(`Template cell for row ${row.id}, index ${rowIndex}`);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableCell className="p-1" style={{ width: '200px', minWidth: '200px' }}>
|
<TableCell className="p-1" style={{ width: '200px', minWidth: '200px' }}>
|
||||||
{isLoadingTemplates ? (
|
{isLoadingTemplates ? (
|
||||||
@@ -362,7 +366,7 @@ const ValidationTable = <T extends string>({
|
|||||||
templates={templates}
|
templates={templates}
|
||||||
value={templateValue || ''}
|
value={templateValue || ''}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
applyTemplate(value, [row.index]);
|
applyTemplate(value, [rowIndex]);
|
||||||
}}
|
}}
|
||||||
getTemplateDisplayText={getTemplateDisplayText}
|
getTemplateDisplayText={getTemplateDisplayText}
|
||||||
defaultBrand={defaultBrand}
|
defaultBrand={defaultBrand}
|
||||||
@@ -371,7 +375,7 @@ const ValidationTable = <T extends string>({
|
|||||||
</TableCell>
|
</TableCell>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}), [templates, applyTemplate, getTemplateDisplayText, isLoadingTemplates]);
|
}), [templates, applyTemplate, getTemplateDisplayText, isLoadingTemplates, data]);
|
||||||
|
|
||||||
// Memoize field columns
|
// Memoize field columns
|
||||||
const fieldColumns = useMemo(() => fields.map((field): ColumnDef<RowData<T>, any> | null => {
|
const fieldColumns = useMemo(() => fields.map((field): ColumnDef<RowData<T>, any> | null => {
|
||||||
@@ -421,9 +425,26 @@ const ValidationTable = <T extends string>({
|
|||||||
state: { rowSelection },
|
state: { rowSelection },
|
||||||
enableRowSelection: true,
|
enableRowSelection: true,
|
||||||
onRowSelectionChange: setRowSelection,
|
onRowSelectionChange: setRowSelection,
|
||||||
getRowId: (row) => row.__index || String(row.index)
|
getRowId: (row) => {
|
||||||
|
// Prefer __index if available (likely a UUID)
|
||||||
|
if (row.__index) return row.__index;
|
||||||
|
|
||||||
|
// Fall back to position in array
|
||||||
|
const index = data.indexOf(row);
|
||||||
|
return String(index);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Log selection changes for debugging
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedCount = Object.values(rowSelection).filter(v => v === true).length;
|
||||||
|
const selectedIds = Object.entries(rowSelection)
|
||||||
|
.filter(([_, selected]) => selected === true)
|
||||||
|
.map(([id, _]) => id);
|
||||||
|
|
||||||
|
console.log(`Row selection updated: ${selectedCount} rows selected, IDs:`, selectedIds);
|
||||||
|
}, [rowSelection]);
|
||||||
|
|
||||||
// Don't render if no data
|
// Don't render if no data
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -980,6 +980,25 @@ useEffect(() => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`Applying template ${templateId} to rows:`, rowIndexes);
|
||||||
|
console.log(`Template data:`, template);
|
||||||
|
|
||||||
|
// Validate row indexes
|
||||||
|
const validRowIndexes = rowIndexes.filter(index =>
|
||||||
|
index >= 0 && index < data.length && Number.isInteger(index)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (validRowIndexes.length === 0) {
|
||||||
|
toast.error('No valid rows to update');
|
||||||
|
console.error('Invalid row indexes:', rowIndexes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validRowIndexes.length !== rowIndexes.length) {
|
||||||
|
console.warn('Some row indexes were invalid and will be skipped:',
|
||||||
|
rowIndexes.filter(idx => !validRowIndexes.includes(idx)));
|
||||||
|
}
|
||||||
|
|
||||||
// Set the template application flag
|
// Set the template application flag
|
||||||
isApplyingTemplateRef.current = true;
|
isApplyingTemplateRef.current = true;
|
||||||
|
|
||||||
@@ -989,51 +1008,49 @@ useEffect(() => {
|
|||||||
top: window.scrollY
|
top: window.scrollY
|
||||||
};
|
};
|
||||||
|
|
||||||
// Track updated rows
|
// Track updated rows for UPC validation
|
||||||
const updatedRows: number[] = [];
|
const updatedRows: number[] = [];
|
||||||
|
|
||||||
// Apply template to data - capture the updated data to use for validation
|
// Create a copy of the data to track updates
|
||||||
let updatedData: RowData<T>[] = [];
|
const newData = [...data];
|
||||||
|
|
||||||
setData(prevData => {
|
// Apply template to each valid row
|
||||||
const newData = [...prevData];
|
validRowIndexes.forEach(index => {
|
||||||
|
// Create a new row with template values
|
||||||
|
const originalRow = newData[index];
|
||||||
|
console.log(`Applying to row at index ${index}:`, originalRow);
|
||||||
|
|
||||||
rowIndexes.forEach(index => {
|
const updatedRow = { ...originalRow };
|
||||||
if (index >= 0 && index < newData.length) {
|
|
||||||
// Create a new row with template values
|
|
||||||
const updatedRow = { ...newData[index] };
|
|
||||||
|
|
||||||
// Clear existing errors and validation status
|
// Clear existing errors
|
||||||
delete updatedRow.__errors;
|
delete updatedRow.__errors;
|
||||||
|
|
||||||
// Apply template fields (excluding metadata fields)
|
// Apply template fields (excluding metadata fields)
|
||||||
Object.entries(template).forEach(([key, value]) => {
|
Object.entries(template).forEach(([key, value]) => {
|
||||||
if (!['id', '__errors', '__meta', '__template', '__original', '__corrected', '__changes'].includes(key)) {
|
if (!['id', '__errors', '__meta', '__template', '__original', '__corrected', '__changes'].includes(key)) {
|
||||||
(updatedRow as any)[key] = value;
|
(updatedRow as any)[key] = value;
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Mark the row as using this template
|
|
||||||
updatedRow.__template = templateId;
|
|
||||||
|
|
||||||
// Update the row in the data array
|
|
||||||
newData[index] = updatedRow;
|
|
||||||
|
|
||||||
// Track which rows were updated
|
|
||||||
updatedRows.push(index);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Store the updated data for validation
|
// Mark the row as using this template
|
||||||
updatedData = [...newData];
|
updatedRow.__template = templateId;
|
||||||
|
|
||||||
return newData;
|
// Update the row in the data array
|
||||||
|
newData[index] = updatedRow;
|
||||||
|
|
||||||
|
// Track which rows were updated
|
||||||
|
updatedRows.push(index);
|
||||||
|
|
||||||
|
console.log(`Row ${index} updated:`, updatedRow);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update all data at once
|
||||||
|
setData(newData);
|
||||||
|
|
||||||
// Clear validation errors and status for affected rows
|
// Clear validation errors and status for affected rows
|
||||||
setValidationErrors(prev => {
|
setValidationErrors(prev => {
|
||||||
const newErrors = new Map(prev);
|
const newErrors = new Map(prev);
|
||||||
rowIndexes.forEach(index => {
|
validRowIndexes.forEach(index => {
|
||||||
newErrors.delete(index);
|
newErrors.delete(index);
|
||||||
});
|
});
|
||||||
return newErrors;
|
return newErrors;
|
||||||
@@ -1041,7 +1058,7 @@ useEffect(() => {
|
|||||||
|
|
||||||
setRowValidationStatus(prev => {
|
setRowValidationStatus(prev => {
|
||||||
const newStatus = new Map(prev);
|
const newStatus = new Map(prev);
|
||||||
rowIndexes.forEach(index => {
|
validRowIndexes.forEach(index => {
|
||||||
newStatus.set(index, 'validated'); // Mark as validated immediately
|
newStatus.set(index, 'validated'); // Mark as validated immediately
|
||||||
});
|
});
|
||||||
return newStatus;
|
return newStatus;
|
||||||
@@ -1053,10 +1070,10 @@ useEffect(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Show success toast
|
// Show success toast
|
||||||
if (rowIndexes.length === 1) {
|
if (validRowIndexes.length === 1) {
|
||||||
toast.success('Template applied');
|
toast.success('Template applied');
|
||||||
} else if (rowIndexes.length > 1) {
|
} else if (validRowIndexes.length > 1) {
|
||||||
toast.success(`Template applied to ${rowIndexes.length} rows`);
|
toast.success(`Template applied to ${validRowIndexes.length} rows`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule UPC validation with a delay
|
// Schedule UPC validation with a delay
|
||||||
@@ -1065,7 +1082,7 @@ useEffect(() => {
|
|||||||
const processRows = async () => {
|
const processRows = async () => {
|
||||||
for (const rowIndex of updatedRows) {
|
for (const rowIndex of updatedRows) {
|
||||||
// Get the current row data after template application
|
// Get the current row data after template application
|
||||||
const currentRow = updatedData[rowIndex];
|
const currentRow = newData[rowIndex];
|
||||||
|
|
||||||
// Check if UPC validation is needed
|
// Check if UPC validation is needed
|
||||||
if (currentRow && currentRow.upc && currentRow.supplier) {
|
if (currentRow && currentRow.upc && currentRow.supplier) {
|
||||||
@@ -1085,7 +1102,7 @@ useEffect(() => {
|
|||||||
// Start processing rows
|
// Start processing rows
|
||||||
processRows();
|
processRows();
|
||||||
}, 500);
|
}, 500);
|
||||||
}, [templates, validateUpc, setData, setValidationErrors, setRowValidationStatus]);
|
}, [data, templates, validateUpc, setData, setValidationErrors, setRowValidationStatus]);
|
||||||
|
|
||||||
// Apply template to selected rows
|
// Apply template to selected rows
|
||||||
const applyTemplateToSelected = useCallback((templateId: string) => {
|
const applyTemplateToSelected = useCallback((templateId: string) => {
|
||||||
@@ -1097,17 +1114,38 @@ useEffect(() => {
|
|||||||
selectedTemplateId: templateId
|
selectedTemplateId: templateId
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Get selected row indexes
|
// Get selected row keys (which may be UUIDs)
|
||||||
const selectedIndexes = Object.keys(rowSelection).map(i => parseInt(i));
|
const selectedKeys = Object.entries(rowSelection)
|
||||||
|
.filter(([_, selected]) => selected === true)
|
||||||
|
.map(([key, _]) => key);
|
||||||
|
|
||||||
|
console.log('Selected row keys:', selectedKeys);
|
||||||
|
|
||||||
|
if (selectedKeys.length === 0) {
|
||||||
|
toast.error('No rows selected');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map UUID keys to array indices
|
||||||
|
const selectedIndexes = selectedKeys.map(key => {
|
||||||
|
// Find the matching row index in the data array
|
||||||
|
const index = data.findIndex(row =>
|
||||||
|
(row.__index && row.__index === key) || // Match by __index
|
||||||
|
(String(data.indexOf(row)) === key) // Or by numeric index
|
||||||
|
);
|
||||||
|
return index;
|
||||||
|
}).filter(index => index !== -1); // Filter out any not found
|
||||||
|
|
||||||
|
console.log('Mapped row indices:', selectedIndexes);
|
||||||
|
|
||||||
if (selectedIndexes.length === 0) {
|
if (selectedIndexes.length === 0) {
|
||||||
toast.error('No rows selected');
|
toast.error('Could not find selected rows');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply template to selected rows
|
// Apply template to selected rows
|
||||||
applyTemplate(templateId, selectedIndexes);
|
applyTemplate(templateId, selectedIndexes);
|
||||||
}, [rowSelection, applyTemplate, setTemplateState]);
|
}, [rowSelection, applyTemplate, setTemplateState, data]);
|
||||||
|
|
||||||
// Add field options query
|
// Add field options query
|
||||||
const { data: fieldOptionsData } = useQuery({
|
const { data: fieldOptionsData } = useQuery({
|
||||||
|
|||||||
Reference in New Issue
Block a user