Add new frontend - fix 24

This commit is contained in:
Urtzi Alfaro
2025-07-23 17:51:39 +02:00
parent 20c31a07f7
commit e3a5256281
3 changed files with 161 additions and 313 deletions

View File

@@ -322,151 +322,140 @@ const OnboardingPage = () => {
}
};
const handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file) return;
// ✅ FIXED: Update handleFileUpload to use backend's schema
const handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file) return;
setFormData(prev => ({ ...prev, salesFile: file }));
setUploadValidation(null);
setFormData(prev => ({ ...prev, salesFile: file }));
setUploadValidation(null);
try {
setLoading(true);
console.log('Validating file:', file.name);
// Auto-validate file on selection
try {
setLoading(true);
console.log('Validating file:', file.name);
// ✅ CRITICAL FIX: Add null check for validation response
const validation = await api.data.validateSalesData(file);
if (!validation) {
throw new Error('No validation response received from server');
}
console.log('Validation result:', validation); // Debug log
setUploadValidation(validation);
// ✅ FIXED: Use correct field name is_valid instead of valid
if (validation.is_valid) {
showNotification('success', 'Archivo válido',
`${validation.total_records} registros detectados, ${validation.valid_records} válidos.`);
} else if (validation.warnings && validation.warnings.length > 0 &&
validation.errors && validation.errors.length === 0) {
showNotification('warning', 'Archivo con advertencias',
'El archivo es válido pero tiene algunas advertencias.');
} else {
const errorCount = validation.errors ? validation.errors.length : 0;
showNotification('error', 'Archivo con errores',
`Se encontraron ${errorCount} errores en el archivo.`);
}
} catch (error: any) {
console.error('Error validating file:', error);
// Handle network or other errors
let errorMessage = 'Error al validar el archivo';
if (error.response?.status === 422) {
errorMessage = 'Formato de archivo inválido';
} else if (error.response?.status === 400) {
errorMessage = 'El archivo no se puede procesar';
} else if (error.response?.status === 500) {
errorMessage = 'Error del servidor. Inténtalo más tarde.';
} else if (error.message) {
errorMessage = error.message;
}
showNotification('error', 'Error de validación', errorMessage);
// ✅ FIXED: Set validation state with correct field names
setUploadValidation({
is_valid: false, // ✅ Use is_valid not valid
total_records: 0,
valid_records: 0,
invalid_records: 0,
errors: [{ message: errorMessage }], // ✅ Array of objects, not strings
warnings: [],
summary: { validation_failed: true }
});
} finally {
setLoading(false);
// Pass the current tenant ID to validation
const validation = await api.data.validateSalesData(file, currentTenantId);
if (!validation) {
throw new Error('No validation response received from server');
}
};
console.log('Validation result:', validation);
setUploadValidation(validation);
// ✅ FIXED: Use backend's "valid" field instead of "is_valid"
if (validation.valid) {
showNotification('success', 'Archivo válido',
`${validation.recordCount || 'Algunos'} registros detectados.`);
} else if (validation.warnings && validation.warnings.length > 0 &&
validation.errors && validation.errors.length === 0) {
showNotification('warning', 'Archivo con advertencias',
'El archivo es válido pero tiene algunas advertencias.');
} else {
const errorCount = validation.errors ? validation.errors.length : 0;
showNotification('error', 'Archivo con errores',
`Se encontraron ${errorCount} errores en el archivo.`);
}
} catch (error: any) {
console.error('Error validating file:', error);
let errorMessage = 'Error al validar el archivo';
if (error.response?.status === 422) {
errorMessage = 'Formato de archivo inválido';
} else if (error.response?.status === 400) {
errorMessage = 'El archivo no se puede procesar';
} else if (error.response?.status === 500) {
errorMessage = 'Error del servidor. Inténtalo más tarde.';
} else if (error.message) {
errorMessage = error.message;
}
showNotification('error', 'Error de validación', errorMessage);
// ✅ FIXED: Set validation state using backend's schema
setUploadValidation({
valid: false,
errors: [errorMessage],
warnings: [],
suggestions: ['Intenta con un archivo diferente']
});
} finally {
setLoading(false);
}
};
// Fixed validation display component
const renderValidationResult = () => {
{uploadValidation && (
if (!uploadValidation) return null;
return (
<div className={`border rounded-lg p-4 ${
uploadValidation.is_valid ? 'bg-green-50 border-green-200' : 'bg-red-50 border-red-200'
uploadValidation.valid ? 'bg-green-50 border-green-200' : 'bg-red-50 border-red-200'
}`}>
<div className="flex items-start">
{uploadValidation.is_valid ? (
{uploadValidation.valid ? (
<CheckIcon className="w-5 h-5 text-green-600 mt-0.5 mr-3" />
) : (
<XMarkIcon className="w-5 h-5 text-red-600 mt-0.5 mr-3" />
)}
<div className="flex-1">
<h4 className={`font-semibold ${
uploadValidation.is_valid ? 'text-green-800' : 'text-red-800'
uploadValidation.valid ? 'text-green-800' : 'text-red-800'
}`}>
{uploadValidation.is_valid ? 'Archivo válido' : 'Archivo con problemas'}
{uploadValidation.valid ? 'Archivo válido' : 'Archivo con problemas'}
</h4>
{/* Always safe record count display */}
{/* ✅ FIXED: Display record count using backend's field names */}
<p className={`text-sm mt-1 ${
uploadValidation.is_valid ? 'text-green-700' : 'text-red-700'
uploadValidation.valid ? 'text-green-700' : 'text-red-700'
}`}>
{uploadValidation.total_records || uploadValidation.recordCount || 0} registros procesados
{uploadValidation.recordCount || 0} registros encontrados
{uploadValidation.duplicates && uploadValidation.duplicates > 0 &&
`, ${uploadValidation.duplicates} duplicados`}
</p>
{/* Only show errors if they exist and are in array format */}
{!uploadValidation.is_valid && uploadValidation.errors && (
{/* ✅ FIXED: Handle errors as string array (backend's current format) */}
{!uploadValidation.valid && uploadValidation.errors && uploadValidation.errors.length > 0 && (
<div className="mt-2">
<p className="text-sm font-medium text-red-700 mb-1">
{Array.isArray(uploadValidation.errors) ? 'Errores encontrados:' : 'Error:'}
</p>
{Array.isArray(uploadValidation.errors) ? (
<ul className="text-sm text-red-700 space-y-1">
{uploadValidation.errors.map((error, idx) => (
<li key={idx}>
{error?.message || error || 'Error no especificado'}
</li>
))}
</ul>
) : (
<p className="text-sm text-red-700">
{uploadValidation.errors.message || uploadValidation.errors || 'Error desconocido'}
</p>
)}
</div>
)}
{/* Show warnings if they exist */}
{uploadValidation.warnings && Array.isArray(uploadValidation.warnings) && uploadValidation.warnings.length > 0 && (
<div className="mt-2">
<p className="text-sm font-medium text-yellow-700 mb-1">Advertencias:</p>
<ul className="text-sm text-yellow-700 space-y-1">
{uploadValidation.warnings.map((warning, idx) => (
<li key={idx}>
{warning?.message || warning || 'Advertencia no especificada'}
</li>
<p className="text-sm font-medium text-red-700 mb-1">Errores encontrados:</p>
<ul className="text-sm text-red-700 space-y-1">
{uploadValidation.errors.map((error, idx) => (
<li key={idx}> {error}</li>
))}
</ul>
</div>
)}
{/* Show technical info for debugging */}
{uploadValidation.summary && uploadValidation.summary.error_type && (
<div className="mt-2 p-2 bg-gray-100 rounded">
<p className="text-xs text-gray-600">
<strong>Info técnica:</strong> {uploadValidation.summary.error_type}
</p>
{/* ✅ FIXED: Handle warnings as string array (backend's current format) */}
{uploadValidation.warnings && uploadValidation.warnings.length > 0 && (
<div className="mt-2">
<p className="text-sm font-medium text-yellow-700 mb-1">Advertencias:</p>
<ul className="text-sm text-yellow-700 space-y-1">
{uploadValidation.warnings.map((warning, idx) => (
<li key={idx}> {warning}</li>
))}
</ul>
</div>
)}
{/* ✅ FIXED: Handle backend's "suggestions" field */}
{uploadValidation.suggestions && uploadValidation.suggestions.length > 0 && (
<div className="mt-2">
<p className="text-sm font-medium text-blue-700 mb-1">Sugerencias:</p>
<ul className="text-sm text-blue-700 space-y-1">
{uploadValidation.suggestions.map((suggestion, idx) => (
<li key={idx}> {suggestion}</li>
))}
</ul>
</div>
)}
</div>
</div>
</div>
)}
};
);
};
const renderStepIndicator = () => (
<div className="mb-12">
@@ -814,8 +803,10 @@ const OnboardingPage = () => {
<div className="mt-2">
<p className="text-sm font-medium text-red-700 mb-1">Errores:</p>
<ul className="text-sm text-red-700 space-y-1">
{uploadValidation.errors.map((error, idx) => (
<li key={idx}> {error}</li>
{validation.errors.map((error, idx) => (
<li key={idx}>
{typeof error === 'string' ? error : (error?.message || 'Error no especificado')}
</li>
))}
</ul>
</div>