Fix validation timing issues with templates
This commit is contained in:
@@ -141,13 +141,26 @@ const ItemNumberCell = React.memo(({
|
||||
field: Field<string>,
|
||||
onChange: (value: any) => void
|
||||
}) => {
|
||||
// Determine if the field has an error
|
||||
const hasError = errors.some(error => error.level === 'error' || error.level === 'warning');
|
||||
const isRequiredButEmpty = errors.some(error => error.level === 'required' && (!value || value.trim() === ''));
|
||||
const nonRequiredErrors = errors.filter(error => error.level !== 'required');
|
||||
|
||||
// Determine if the field is required but empty
|
||||
const isRequiredButEmpty = errors.some(error =>
|
||||
error.message?.toLowerCase().includes('required') &&
|
||||
(!value || (typeof value === 'string' && value.trim() === ''))
|
||||
);
|
||||
|
||||
// Only show error icons for non-empty fields
|
||||
const shouldShowErrorIcon = hasError && value && (typeof value !== 'string' || value.trim() !== '');
|
||||
|
||||
// Get error messages for the tooltip
|
||||
const errorMessages = shouldShowErrorIcon
|
||||
? errors.filter(e => e.level === 'error' || e.level === 'warning').map(e => e.message).join('\n')
|
||||
: '';
|
||||
|
||||
return (
|
||||
<TableCell className="p-1" style={{ width: `${width}px`, minWidth: `${width}px` }}>
|
||||
<div className={`relative ${hasError ? 'border-red-500' : (isRequiredButEmpty ? 'border-red-500' : '')}`}>
|
||||
<div className={`relative ${hasError || isRequiredButEmpty ? 'border-red-500' : ''}`}>
|
||||
{isValidating ? (
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<Loader2 className="h-4 w-4 animate-spin text-blue-500" />
|
||||
@@ -164,10 +177,10 @@ const ItemNumberCell = React.memo(({
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{nonRequiredErrors.length > 0 && (
|
||||
{shouldShowErrorIcon && (
|
||||
<div className="absolute right-2 top-1/2 -translate-y-1/2 z-20">
|
||||
<ValidationIcon error={{
|
||||
message: nonRequiredErrors.map(e => e.message).join('\n'),
|
||||
message: errorMessages,
|
||||
level: 'error'
|
||||
}} />
|
||||
</div>
|
||||
@@ -209,21 +222,27 @@ const ValidationCell = ({
|
||||
);
|
||||
}
|
||||
|
||||
// Error states
|
||||
// Determine if the field has an error
|
||||
const hasError = errors.some(error => error.level === 'error' || error.level === 'warning');
|
||||
const isRequiredButEmpty = errors.some(error => {
|
||||
if (error.level !== 'required') return false;
|
||||
|
||||
// Handle different value types
|
||||
if (Array.isArray(value)) {
|
||||
return value.length === 0;
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
return !value || value.trim() === '';
|
||||
}
|
||||
return value === undefined || value === null;
|
||||
});
|
||||
const nonRequiredErrors = errors.filter(error => error.level !== 'required');
|
||||
// Determine if the field is required but empty
|
||||
const isRequiredButEmpty = errors.some(error =>
|
||||
error.message?.toLowerCase().includes('required') &&
|
||||
(value === undefined || value === null ||
|
||||
(typeof value === 'string' && value.trim() === '') ||
|
||||
(Array.isArray(value) && value.length === 0))
|
||||
);
|
||||
|
||||
// Only show error icons for non-empty fields
|
||||
const shouldShowErrorIcon = hasError &&
|
||||
!(value === undefined || value === null ||
|
||||
(typeof value === 'string' && value.trim() === '') ||
|
||||
(Array.isArray(value) && value.length === 0));
|
||||
|
||||
// Get error messages for the tooltip
|
||||
const errorMessages = shouldShowErrorIcon
|
||||
? errors.filter(e => e.level === 'error' || e.level === 'warning').map(e => e.message).join('\n')
|
||||
: '';
|
||||
|
||||
// Check if this is a multiline field
|
||||
const isMultiline = typeof field.fieldType === 'object' &&
|
||||
@@ -235,7 +254,7 @@ const ValidationCell = ({
|
||||
|
||||
return (
|
||||
<TableCell className="p-1" style={{ width: `${width}px`, minWidth: `${width}px` }}>
|
||||
<div className={`relative ${hasError ? 'border-red-500' : (isRequiredButEmpty ? 'border-red-500' : '')} ${cellHeight}`}>
|
||||
<div className={`relative ${hasError || isRequiredButEmpty ? 'border-red-500' : ''} ${cellHeight}`}>
|
||||
|
||||
|
||||
<div className={`truncate overflow-hidden ${isMultiline ? 'h-full' : ''}`}>
|
||||
@@ -248,10 +267,10 @@ const ValidationCell = ({
|
||||
/>
|
||||
</div>
|
||||
|
||||
{nonRequiredErrors.length > 0 && (
|
||||
{shouldShowErrorIcon && (
|
||||
<div className="absolute right-2 top-1/2 -translate-y-1/2 z-20">
|
||||
<ValidationIcon error={{
|
||||
message: nonRequiredErrors.map(e => e.message).join('\n'),
|
||||
message: errorMessages,
|
||||
level: 'error'
|
||||
}} />
|
||||
</div>
|
||||
|
||||
@@ -562,17 +562,51 @@ const ValidationContainer = <T extends string>({
|
||||
onNext?.(data)
|
||||
}, [onNext, data, applyItemNumbersToData]);
|
||||
|
||||
// Delete selected rows - memoized
|
||||
const deleteSelectedRows = useCallback(() => {
|
||||
// Get selected row indices
|
||||
const selectedRowIndexes = Object.keys(rowSelection).map(Number);
|
||||
const newData = data.filter((_, index) => !selectedRowIndexes.includes(index));
|
||||
|
||||
if (selectedRowIndexes.length === 0) {
|
||||
toast.error("No rows selected");
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort indices in descending order to avoid index shifting during removal
|
||||
const sortedIndices = [...selectedRowIndexes].sort((a, b) => b - a);
|
||||
|
||||
// Create a new array without the selected rows
|
||||
const newData = [...data];
|
||||
|
||||
// Remove rows from bottom up to avoid index issues
|
||||
sortedIndices.forEach(index => {
|
||||
if (index >= 0 && index < newData.length) {
|
||||
newData.splice(index, 1);
|
||||
}
|
||||
});
|
||||
|
||||
// Update the data with rows removed
|
||||
setData(newData);
|
||||
|
||||
// Clear row selection
|
||||
setRowSelection({});
|
||||
|
||||
// Show success message
|
||||
toast.success(
|
||||
selectedRowIndexes.length === 1
|
||||
? "Row deleted"
|
||||
: `${selectedRowIndexes.length} rows deleted`
|
||||
);
|
||||
|
||||
// Reindex the data in the next render cycle
|
||||
requestAnimationFrame(() => {
|
||||
// Update indices to maintain consistency
|
||||
setData(current =>
|
||||
current.map((row, newIndex) => ({
|
||||
...row,
|
||||
__index: String(newIndex)
|
||||
}))
|
||||
);
|
||||
});
|
||||
}, [data, rowSelection, setData, setRowSelection]);
|
||||
|
||||
// Enhanced ValidationTable component that's aware of item numbers
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -137,7 +137,7 @@ export const validateSpecialFields = <T extends string>(row: Data<T>): Record<st
|
||||
message: 'Supplier is required',
|
||||
level: 'error',
|
||||
source: ErrorSources.Row
|
||||
} as ErrorType]
|
||||
}]
|
||||
}
|
||||
|
||||
// Validate company field
|
||||
@@ -146,7 +146,7 @@ export const validateSpecialFields = <T extends string>(row: Data<T>): Record<st
|
||||
message: 'Company is required',
|
||||
level: 'error',
|
||||
source: ErrorSources.Row
|
||||
} as ErrorType]
|
||||
}]
|
||||
}
|
||||
|
||||
return errors
|
||||
|
||||
Reference in New Issue
Block a user