182 lines
6.3 KiB
TypeScript
182 lines
6.3 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { OnboardingWizard, OnboardingStep } from '../../../components/domain/onboarding/OnboardingWizard';
|
|
import { onboardingApiService } from '../../../services/api/onboarding.service';
|
|
import { useAuthUser, useIsAuthenticated } from '../../../stores/auth.store';
|
|
import { LoadingSpinner } from '../../../components/shared/LoadingSpinner';
|
|
|
|
// Step Components
|
|
import { BakerySetupStep } from '../../../components/domain/onboarding/steps/BakerySetupStep';
|
|
import { DataProcessingStep } from '../../../components/domain/onboarding/steps/DataProcessingStep';
|
|
import { ReviewStep } from '../../../components/domain/onboarding/steps/ReviewStep';
|
|
import { InventorySetupStep } from '../../../components/domain/onboarding/steps/InventorySetupStep';
|
|
import { SuppliersStep } from '../../../components/domain/onboarding/steps/SuppliersStep';
|
|
import { MLTrainingStep } from '../../../components/domain/onboarding/steps/MLTrainingStep';
|
|
import { CompletionStep } from '../../../components/domain/onboarding/steps/CompletionStep';
|
|
|
|
const OnboardingPage: React.FC = () => {
|
|
const navigate = useNavigate();
|
|
const user = useAuthUser();
|
|
const isAuthenticated = useIsAuthenticated();
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [globalData, setGlobalData] = useState<any>({});
|
|
|
|
// Define the 8 onboarding steps (simplified by merging data upload + analysis)
|
|
const steps: OnboardingStep[] = [
|
|
{
|
|
id: 'setup',
|
|
title: '🏢 Setup',
|
|
description: 'Configuración básica de tu panadería y creación del tenant',
|
|
component: BakerySetupStep,
|
|
isRequired: true,
|
|
validation: (data) => {
|
|
if (!data.bakery?.name) return 'El nombre de la panadería es requerido';
|
|
if (!data.bakery?.business_model) return 'El modelo de negocio es requerido';
|
|
if (!data.bakery?.address) return 'La dirección es requerida';
|
|
if (!data.bakery?.city) return 'La ciudad es requerida';
|
|
if (!data.bakery?.postal_code) return 'El código postal es requerido';
|
|
if (!data.bakery?.phone) return 'El teléfono es requerido';
|
|
// Tenant creation will happen automatically when validation passes
|
|
return null;
|
|
}
|
|
},
|
|
{
|
|
id: 'data-processing',
|
|
title: '📊 Historial de Ventas',
|
|
description: 'Sube tus datos de ventas para obtener insights personalizados',
|
|
component: DataProcessingStep,
|
|
isRequired: true,
|
|
validation: (data) => {
|
|
if (!data.files?.salesData) return 'Debes cargar el archivo de datos de ventas';
|
|
if (data.processingStage !== 'completed') return 'El procesamiento debe completarse antes de continuar';
|
|
if (!data.processingResults?.is_valid) return 'Los datos deben ser válidos para continuar';
|
|
return null;
|
|
}
|
|
},
|
|
{
|
|
id: 'review',
|
|
title: '📋 Revisión',
|
|
description: 'Revisión de productos detectados por IA y resultados',
|
|
component: ReviewStep,
|
|
isRequired: true,
|
|
validation: (data) => {
|
|
if (!data.reviewCompleted) return 'Debes revisar y aprobar los productos detectados';
|
|
return null;
|
|
}
|
|
},
|
|
{
|
|
id: 'inventory',
|
|
title: '⚙️ Inventario',
|
|
description: 'Configuración de inventario (stock, fechas de vencimiento)',
|
|
component: InventorySetupStep,
|
|
isRequired: true,
|
|
validation: (data) => {
|
|
if (!data.inventoryConfigured) return 'Debes configurar el inventario básico';
|
|
return null;
|
|
}
|
|
},
|
|
{
|
|
id: 'suppliers',
|
|
title: '🏪 Proveedores',
|
|
description: 'Configuración de proveedores y asociaciones',
|
|
component: SuppliersStep,
|
|
isRequired: false,
|
|
validation: () => null // Optional step
|
|
},
|
|
{
|
|
id: 'ml-training',
|
|
title: '🎯 Inteligencia',
|
|
description: 'Creación de tu asistente inteligente personalizado',
|
|
component: MLTrainingStep,
|
|
isRequired: true,
|
|
validation: (data) => {
|
|
if (data.trainingStatus !== 'completed') return 'El entrenamiento del modelo debe completarse';
|
|
return null;
|
|
}
|
|
},
|
|
{
|
|
id: 'completion',
|
|
title: '🎉 Listo',
|
|
description: 'Finalización y preparación para usar la plataforma',
|
|
component: CompletionStep,
|
|
isRequired: true,
|
|
validation: () => null
|
|
}
|
|
];
|
|
|
|
const handleComplete = async (allData: any) => {
|
|
setIsLoading(true);
|
|
try {
|
|
// Mark onboarding as complete in the backend
|
|
if (user?.tenant_id) {
|
|
await onboardingApiService.completeOnboarding(user.tenant_id, {
|
|
completedAt: new Date().toISOString(),
|
|
data: allData
|
|
});
|
|
}
|
|
|
|
// Navigate to dashboard
|
|
navigate('/app/dashboard', {
|
|
state: {
|
|
message: '¡Felicidades! Tu panadería ha sido configurada exitosamente.',
|
|
type: 'success'
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('Error completing onboarding:', error);
|
|
// Still navigate to dashboard but show warning
|
|
navigate('/app/dashboard', {
|
|
state: {
|
|
message: 'Configuración completada. Algunos ajustes finales pueden estar pendientes.',
|
|
type: 'warning'
|
|
}
|
|
});
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleExit = () => {
|
|
const confirmExit = window.confirm(
|
|
'¿Estás seguro de que quieres salir del proceso de configuración? Tu progreso se guardará automáticamente.'
|
|
);
|
|
|
|
if (confirmExit) {
|
|
navigate('/app/dashboard');
|
|
}
|
|
};
|
|
|
|
// Redirect to login if not authenticated
|
|
useEffect(() => {
|
|
if (!isAuthenticated) {
|
|
navigate('/login', {
|
|
state: {
|
|
message: 'Debes iniciar sesión para acceder al onboarding.',
|
|
returnUrl: '/app/onboarding'
|
|
}
|
|
});
|
|
}
|
|
}, [isAuthenticated, navigate]);
|
|
|
|
if (isLoading) {
|
|
return <LoadingSpinner overlay text="Completando configuración..." />;
|
|
}
|
|
|
|
// Don't render if not authenticated (will redirect)
|
|
if (!isAuthenticated || !user) {
|
|
return <LoadingSpinner overlay text="Verificando autenticación..." />;
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-[var(--bg-primary)]">
|
|
<OnboardingWizard
|
|
steps={steps}
|
|
onComplete={handleComplete}
|
|
onExit={handleExit}
|
|
className="py-8"
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default OnboardingPage; |