Fix new Frontend 6
This commit is contained in:
@@ -2,6 +2,10 @@ import React, { useState } from 'react';
|
|||||||
import { ChevronLeft, ChevronRight, Upload, MapPin, Store, Factory, Check } from 'lucide-react';
|
import { ChevronLeft, ChevronRight, Upload, MapPin, Store, Factory, Check } from 'lucide-react';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
|
|
||||||
|
import { useTenant, useTraining, useData, useAuth } from '../../api/hooks';
|
||||||
|
import { TenantCreate } from '../../api/types';
|
||||||
|
import { UserResponse } from '../../api/types';
|
||||||
|
|
||||||
interface OnboardingPageProps {
|
interface OnboardingPageProps {
|
||||||
user: any;
|
user: any;
|
||||||
onComplete: () => void;
|
onComplete: () => void;
|
||||||
@@ -34,6 +38,11 @@ const OnboardingPage: React.FC<OnboardingPageProps> = ({ user, onComplete }) =>
|
|||||||
hasHistoricalData: false
|
hasHistoricalData: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { createTenant, isLoading: tenantLoading } = useTenant();
|
||||||
|
const { startTrainingJob } = useTraining();
|
||||||
|
const { uploadSalesHistory, validateSalesData, uploadProgress } = useData();
|
||||||
|
const [ setUploadProgress ] = useState<number>(0);
|
||||||
|
|
||||||
const steps = [
|
const steps = [
|
||||||
{ id: 1, title: 'Datos de Panadería', icon: Store },
|
{ id: 1, title: 'Datos de Panadería', icon: Store },
|
||||||
{ id: 2, title: 'Productos y Servicios', icon: Factory },
|
{ id: 2, title: 'Productos y Servicios', icon: Factory },
|
||||||
@@ -81,76 +90,131 @@ const OnboardingPage: React.FC<OnboardingPageProps> = ({ user, onComplete }) =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleComplete = async () => {
|
const handleComplete = async () => {
|
||||||
|
if (!validateCurrentStep()) return;
|
||||||
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Step 1: Register tenant/bakery
|
// Step 1: Create tenant using the API service
|
||||||
const tenantResponse = await fetch('/api/v1/tenants/register', {
|
const tenantData: TenantCreate = {
|
||||||
method: 'POST',
|
name: bakeryData.name,
|
||||||
headers: {
|
address: bakeryData.address,
|
||||||
'Content-Type': 'application/json',
|
business_type: bakeryData.businessType,
|
||||||
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`
|
coordinates: bakeryData.coordinates,
|
||||||
},
|
products: bakeryData.products,
|
||||||
body: JSON.stringify({
|
has_historical_data: bakeryData.hasHistoricalData,
|
||||||
name: bakeryData.name,
|
};
|
||||||
address: bakeryData.address,
|
|
||||||
business_type: bakeryData.businessType,
|
const newTenant = await createTenant(tenantData);
|
||||||
coordinates: bakeryData.coordinates,
|
const tenantId = newTenant.id;
|
||||||
products: bakeryData.products
|
|
||||||
})
|
// Step 2: Validate and Upload CSV file if provided
|
||||||
});
|
|
||||||
|
|
||||||
if (!tenantResponse.ok) {
|
|
||||||
throw new Error('Error al registrar la panadería');
|
|
||||||
}
|
|
||||||
|
|
||||||
const tenantData = await tenantResponse.json();
|
|
||||||
const tenantId = tenantData.tenant.id;
|
|
||||||
|
|
||||||
// Step 2: Upload CSV data if provided
|
|
||||||
if (bakeryData.hasHistoricalData && bakeryData.csvFile) {
|
if (bakeryData.hasHistoricalData && bakeryData.csvFile) {
|
||||||
const formData = new FormData();
|
try {
|
||||||
formData.append('file', bakeryData.csvFile);
|
// Step 2.1: First validate the CSV data
|
||||||
|
toast.loading('Validando datos del archivo CSV...', { id: 'csv-validation' });
|
||||||
|
|
||||||
|
const validationResult = await validateSalesData(tenantId, bakeryData.csvFile);
|
||||||
|
|
||||||
|
toast.dismiss('csv-validation');
|
||||||
|
|
||||||
|
// Check validation result
|
||||||
|
if (!validationResult.success) {
|
||||||
|
// Validation failed - show errors but let user decide
|
||||||
|
const errorMessages = validationResult.errors?.slice(0, 3).join(', ') || 'Errores de validación';
|
||||||
|
const hasMoreErrors = validationResult.errors && validationResult.errors.length > 3;
|
||||||
|
|
||||||
|
toast.error(
|
||||||
|
`Errores en el archivo CSV: ${errorMessages}${hasMoreErrors ? '...' : ''}. Revisa la consola para más detalles.`
|
||||||
|
);
|
||||||
|
console.error('CSV validation errors:', validationResult.errors);
|
||||||
|
console.warn('CSV validation warnings:', validationResult.warnings);
|
||||||
|
|
||||||
|
// Don't proceed with upload if validation fails
|
||||||
|
throw new Error('Validación del CSV falló');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation passed - show summary and proceed
|
||||||
|
if (validationResult.warnings && validationResult.warnings.length > 0) {
|
||||||
|
toast.warn(`CSV validado con ${validationResult.warnings.length} advertencias. Continuando con la subida...`);
|
||||||
|
console.warn('CSV validation warnings:', validationResult.warnings);
|
||||||
|
} else {
|
||||||
|
toast.success('CSV validado correctamente. Procediendo con la subida...');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2.2: Now upload the validated CSV
|
||||||
|
toast.loading('Subiendo datos históricos...', { id: 'csv-upload' });
|
||||||
|
|
||||||
|
const uploadResult = await uploadSalesHistory(tenantId, bakeryData.csvFile, {
|
||||||
|
source: 'onboarding_upload',
|
||||||
|
validate_only: false,
|
||||||
|
onProgress: (progress) => {
|
||||||
|
setUploadProgress(progress.percentage);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
toast.dismiss('csv-upload');
|
||||||
|
|
||||||
|
// Check upload result
|
||||||
|
if (uploadResult.success) {
|
||||||
|
toast.success(
|
||||||
|
`¡Datos históricos subidos exitosamente! ${uploadResult.records_created} de ${uploadResult.records_processed} registros procesados.`
|
||||||
|
);
|
||||||
|
|
||||||
|
// Show additional info if some records failed
|
||||||
|
if (uploadResult.records_failed > 0) {
|
||||||
|
toast.warn(
|
||||||
|
`${uploadResult.records_failed} registros fallaron durante la subida. Success rate: ${uploadResult.success_rate?.toFixed(1)}%`
|
||||||
|
);
|
||||||
|
console.warn('Upload errors:', uploadResult.errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log warnings for debugging
|
||||||
|
if (uploadResult.warnings && uploadResult.warnings.length > 0) {
|
||||||
|
console.info('Upload warnings:', uploadResult.warnings);
|
||||||
|
}
|
||||||
|
|
||||||
const uploadResponse = await fetch(`/api/v1/tenants/${tenantId}/data/upload`, {
|
try {
|
||||||
method: 'POST',
|
// Start training process (if you have a training service)
|
||||||
headers: {
|
await startTrainingJob(tenantId);
|
||||||
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`
|
toast.success('¡Entrenamiento del modelo iniciado!');
|
||||||
},
|
} catch (trainingError) {
|
||||||
body: formData
|
console.warn('Training start failed:', trainingError);
|
||||||
});
|
// Don't fail onboarding if training fails to start
|
||||||
|
}
|
||||||
if (!uploadResponse.ok) {
|
|
||||||
throw new Error('Error al subir los datos históricos');
|
} else {
|
||||||
|
// Upload failed
|
||||||
|
throw new Error(`Upload failed: ${uploadResult.errors?.join(', ') || 'Unknown error'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset progress when done
|
||||||
|
setUploadProgress(0);
|
||||||
|
|
||||||
|
} catch (uploadError) {
|
||||||
|
// Handle validation or upload error gracefully
|
||||||
|
console.error('CSV validation/upload error:', uploadError);
|
||||||
|
|
||||||
|
const errorMessage = uploadError instanceof Error ? uploadError.message : 'Error desconocido';
|
||||||
|
|
||||||
|
if (errorMessage.includes('Validación')) {
|
||||||
|
toast.error('No se pudieron subir los datos históricos debido a errores de validación. La configuración se completó sin datos históricos.');
|
||||||
|
} else {
|
||||||
|
toast.warn(`Error al procesar archivo CSV: ${errorMessage}. La configuración se completó sin datos históricos.`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3: Start training process
|
|
||||||
const trainingResponse = await fetch(`/api/v1/tenants/${tenantId}/training/start`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
products: bakeryData.products
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!trainingResponse.ok) {
|
|
||||||
throw new Error('Error al iniciar el entrenamiento del modelo');
|
|
||||||
}
|
|
||||||
|
|
||||||
toast.success('¡Datos subidos! El entrenamiento del modelo comenzará pronto.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.success('¡Configuración completada! Bienvenido a PanIA');
|
toast.success('¡Configuración completada exitosamente!');
|
||||||
onComplete();
|
onComplete();
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error('Onboarding completion error:', error);
|
console.error('Onboarding completion error:', error);
|
||||||
toast.error(error.message || 'Error al completar la configuración');
|
const errorMessage = error instanceof Error ? error.message : 'Error al completar la configuración';
|
||||||
|
toast.error(errorMessage);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
setUploadProgress(0); // Reset progress in case of error
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user