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 [] = 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
|
||||
useEffect(() => {
|
||||
if (defaultBrand) {
|
||||
|
||||
@@ -54,7 +54,8 @@ const ValidationContainer = <T extends string>({
|
||||
loadTemplates,
|
||||
setData,
|
||||
fields,
|
||||
isLoadingTemplates
|
||||
isLoadingTemplates,
|
||||
rowValidationStatus
|
||||
} = validationState
|
||||
|
||||
// Add state for tracking product lines and sublines per row
|
||||
@@ -563,16 +564,37 @@ const ValidationContainer = <T extends string>({
|
||||
}, [onNext, data, applyItemNumbersToData]);
|
||||
|
||||
const deleteSelectedRows = useCallback(() => {
|
||||
// Get selected row indices
|
||||
const selectedRowIndexes = Object.keys(rowSelection).map(Number);
|
||||
// Get selected row keys (which may be UUIDs)
|
||||
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");
|
||||
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
|
||||
const sortedIndices = [...selectedRowIndexes].sort((a, b) => b - a);
|
||||
const sortedIndices = [...selectedIndices].sort((a, b) => b - a);
|
||||
|
||||
// Create a new array without the selected rows
|
||||
const newData = [...data];
|
||||
@@ -592,9 +614,9 @@ const ValidationContainer = <T extends string>({
|
||||
|
||||
// Show success message
|
||||
toast.success(
|
||||
selectedRowIndexes.length === 1
|
||||
selectedIndices.length === 1
|
||||
? "Row deleted"
|
||||
: `${selectedRowIndexes.length} rows deleted`
|
||||
: `${selectedIndices.length} rows deleted`
|
||||
);
|
||||
|
||||
// Reindex the data in the next render cycle
|
||||
@@ -829,7 +851,11 @@ const ValidationContainer = <T extends string>({
|
||||
<Button
|
||||
variant={isFromScratch ? "destructive" : "outline"}
|
||||
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"}
|
||||
</Button>
|
||||
|
||||
@@ -350,6 +350,10 @@ const ValidationTable = <T extends string>({
|
||||
cell: ({ row }) => {
|
||||
const templateValue = row.original.__template || null;
|
||||
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 (
|
||||
<TableCell className="p-1" style={{ width: '200px', minWidth: '200px' }}>
|
||||
{isLoadingTemplates ? (
|
||||
@@ -362,7 +366,7 @@ const ValidationTable = <T extends string>({
|
||||
templates={templates}
|
||||
value={templateValue || ''}
|
||||
onValueChange={(value) => {
|
||||
applyTemplate(value, [row.index]);
|
||||
applyTemplate(value, [rowIndex]);
|
||||
}}
|
||||
getTemplateDisplayText={getTemplateDisplayText}
|
||||
defaultBrand={defaultBrand}
|
||||
@@ -371,7 +375,7 @@ const ValidationTable = <T extends string>({
|
||||
</TableCell>
|
||||
);
|
||||
}
|
||||
}), [templates, applyTemplate, getTemplateDisplayText, isLoadingTemplates]);
|
||||
}), [templates, applyTemplate, getTemplateDisplayText, isLoadingTemplates, data]);
|
||||
|
||||
// Memoize field columns
|
||||
const fieldColumns = useMemo(() => fields.map((field): ColumnDef<RowData<T>, any> | null => {
|
||||
@@ -421,9 +425,26 @@ const ValidationTable = <T extends string>({
|
||||
state: { rowSelection },
|
||||
enableRowSelection: true,
|
||||
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
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
|
||||
@@ -980,6 +980,25 @@ useEffect(() => {
|
||||
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
|
||||
isApplyingTemplateRef.current = true;
|
||||
|
||||
@@ -989,51 +1008,49 @@ useEffect(() => {
|
||||
top: window.scrollY
|
||||
};
|
||||
|
||||
// Track updated rows
|
||||
// Track updated rows for UPC validation
|
||||
const updatedRows: number[] = [];
|
||||
|
||||
// Apply template to data - capture the updated data to use for validation
|
||||
let updatedData: RowData<T>[] = [];
|
||||
// Create a copy of the data to track updates
|
||||
const newData = [...data];
|
||||
|
||||
setData(prevData => {
|
||||
const newData = [...prevData];
|
||||
// Apply template to each valid row
|
||||
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 => {
|
||||
if (index >= 0 && index < newData.length) {
|
||||
// Create a new row with template values
|
||||
const updatedRow = { ...newData[index] };
|
||||
const updatedRow = { ...originalRow };
|
||||
|
||||
// Clear existing errors and validation status
|
||||
delete updatedRow.__errors;
|
||||
// Clear existing errors
|
||||
delete updatedRow.__errors;
|
||||
|
||||
// Apply template fields (excluding metadata fields)
|
||||
Object.entries(template).forEach(([key, value]) => {
|
||||
if (!['id', '__errors', '__meta', '__template', '__original', '__corrected', '__changes'].includes(key)) {
|
||||
(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);
|
||||
// Apply template fields (excluding metadata fields)
|
||||
Object.entries(template).forEach(([key, value]) => {
|
||||
if (!['id', '__errors', '__meta', '__template', '__original', '__corrected', '__changes'].includes(key)) {
|
||||
(updatedRow as any)[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
// Store the updated data for validation
|
||||
updatedData = [...newData];
|
||||
// Mark the row as using this template
|
||||
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
|
||||
setValidationErrors(prev => {
|
||||
const newErrors = new Map(prev);
|
||||
rowIndexes.forEach(index => {
|
||||
validRowIndexes.forEach(index => {
|
||||
newErrors.delete(index);
|
||||
});
|
||||
return newErrors;
|
||||
@@ -1041,7 +1058,7 @@ useEffect(() => {
|
||||
|
||||
setRowValidationStatus(prev => {
|
||||
const newStatus = new Map(prev);
|
||||
rowIndexes.forEach(index => {
|
||||
validRowIndexes.forEach(index => {
|
||||
newStatus.set(index, 'validated'); // Mark as validated immediately
|
||||
});
|
||||
return newStatus;
|
||||
@@ -1053,10 +1070,10 @@ useEffect(() => {
|
||||
});
|
||||
|
||||
// Show success toast
|
||||
if (rowIndexes.length === 1) {
|
||||
if (validRowIndexes.length === 1) {
|
||||
toast.success('Template applied');
|
||||
} else if (rowIndexes.length > 1) {
|
||||
toast.success(`Template applied to ${rowIndexes.length} rows`);
|
||||
} else if (validRowIndexes.length > 1) {
|
||||
toast.success(`Template applied to ${validRowIndexes.length} rows`);
|
||||
}
|
||||
|
||||
// Schedule UPC validation with a delay
|
||||
@@ -1065,7 +1082,7 @@ useEffect(() => {
|
||||
const processRows = async () => {
|
||||
for (const rowIndex of updatedRows) {
|
||||
// Get the current row data after template application
|
||||
const currentRow = updatedData[rowIndex];
|
||||
const currentRow = newData[rowIndex];
|
||||
|
||||
// Check if UPC validation is needed
|
||||
if (currentRow && currentRow.upc && currentRow.supplier) {
|
||||
@@ -1085,7 +1102,7 @@ useEffect(() => {
|
||||
// Start processing rows
|
||||
processRows();
|
||||
}, 500);
|
||||
}, [templates, validateUpc, setData, setValidationErrors, setRowValidationStatus]);
|
||||
}, [data, templates, validateUpc, setData, setValidationErrors, setRowValidationStatus]);
|
||||
|
||||
// Apply template to selected rows
|
||||
const applyTemplateToSelected = useCallback((templateId: string) => {
|
||||
@@ -1097,17 +1114,38 @@ useEffect(() => {
|
||||
selectedTemplateId: templateId
|
||||
}));
|
||||
|
||||
// Get selected row indexes
|
||||
const selectedIndexes = Object.keys(rowSelection).map(i => parseInt(i));
|
||||
// Get selected row keys (which may be UUIDs)
|
||||
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) {
|
||||
toast.error('No rows selected');
|
||||
toast.error('Could not find selected rows');
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply template to selected rows
|
||||
applyTemplate(templateId, selectedIndexes);
|
||||
}, [rowSelection, applyTemplate, setTemplateState]);
|
||||
}, [rowSelection, applyTemplate, setTemplateState, data]);
|
||||
|
||||
// Add field options query
|
||||
const { data: fieldOptionsData } = useQuery({
|
||||
|
||||
Reference in New Issue
Block a user