Roturas Stock
-
{metrics.stockouts}
+
{metrics?.stockouts ?? 0}
Reduciendo
diff --git a/frontend/src/pages/onboarding/OnboardingPage.tsx b/frontend/src/pages/onboarding/OnboardingPage.tsx
index 2b325abb..f833e7eb 100644
--- a/frontend/src/pages/onboarding/OnboardingPage.tsx
+++ b/frontend/src/pages/onboarding/OnboardingPage.tsx
@@ -51,7 +51,7 @@ const OnboardingPage: React.FC = ({ user, onComplete }) =>
name: '',
address: '',
businessType: 'individual',
- products: [],
+ products: MADRID_PRODUCTS, // Automatically assign all products
hasHistoricalData: false
});
@@ -64,13 +64,11 @@ const OnboardingPage: React.FC = ({ user, onComplete }) =>
const steps = [
{ id: 1, title: 'Datos de Panadería', icon: Store },
- { id: 2, title: 'Productos y Servicios', icon: Factory },
- { id: 3, title: 'Datos Históricos', icon: Upload },
- { id: 4, title: 'Entrenamiento IA', icon: Brain },
- { id: 5, title: 'Configuración Final', icon: Check }
+ { id: 2, title: 'Datos Históricos', icon: Upload },
+ { id: 3, title: 'Entrenamiento IA', icon: Brain },
+ { id: 4, title: 'Configuración Final', icon: Check }
];
-
const [trainingProgress, setTrainingProgress] = useState({
progress: 0,
status: 'pending',
@@ -123,7 +121,7 @@ const OnboardingPage: React.FC = ({ user, onComplete }) =>
// Auto-advance to final step after 2 seconds
setTimeout(() => {
- setCurrentStep(5);
+ setCurrentStep(4);
}, 2000);
} else if (messageType === 'failed' || messageType === 'training_failed' || messageType === 'training_error') {
@@ -161,7 +159,7 @@ const OnboardingPage: React.FC = ({ user, onComplete }) =>
// Connect to WebSocket when training starts
useEffect(() => {
- if (tenantId && trainingJobId && currentStep === 4) {
+ if (tenantId && trainingJobId && currentStep === 3) {
connect();
}
@@ -172,9 +170,42 @@ const OnboardingPage: React.FC = ({ user, onComplete }) =>
};
}, [tenantId, trainingJobId, currentStep, connect, disconnect, isConnected]);
+
+ const storeTenantId = (tenantId: string) => {
+ try {
+ // Method 1: Store tenant ID directly
+ localStorage.setItem('current_tenant_id', tenantId);
+
+ // Method 2: Update user_data to include tenant_id
+ const existingUserData = localStorage.getItem('user_data');
+ if (existingUserData) {
+ const userData = JSON.parse(existingUserData);
+ userData.current_tenant_id = tenantId;
+ userData.tenant_id = tenantId; // Backup key
+ localStorage.setItem('user_data', JSON.stringify(userData));
+ } else {
+ // Create user_data with tenant info if it doesn't exist
+ localStorage.setItem('user_data', JSON.stringify({
+ current_tenant_id: tenantId,
+ tenant_id: tenantId
+ }));
+ }
+
+ // Method 3: Store in a dedicated tenant context
+ localStorage.setItem('tenant_context', JSON.stringify({
+ current_tenant_id: tenantId,
+ last_updated: new Date().toISOString()
+ }));
+
+ console.log('✅ Tenant ID stored successfully:', tenantId);
+ } catch (error) {
+ console.error('❌ Failed to store tenant ID:', error);
+ }
+ };
+
const handleNext = () => {
if (validateCurrentStep()) {
- if (currentStep === 3) {
+ if (currentStep === 2) {
// Always proceed to training step after CSV upload
startTraining();
} else {
@@ -200,12 +231,6 @@ const OnboardingPage: React.FC = ({ user, onComplete }) =>
}
return true;
case 2:
- if (bakeryData.products.length === 0) {
- toast.error('Selecciona al menos un producto');
- return false;
- }
- return true;
- case 3:
if (!bakeryData.csvFile) {
toast.error('Por favor, selecciona un archivo con tus datos históricos');
return false;
@@ -235,7 +260,7 @@ const OnboardingPage: React.FC = ({ user, onComplete }) =>
};
const startTraining = async () => {
- setCurrentStep(4);
+ setCurrentStep(3);
setIsLoading(true);
try {
@@ -259,6 +284,7 @@ const OnboardingPage: React.FC = ({ user, onComplete }) =>
const tenant = await createTenant(tenantData);
setTenantId(tenant.id);
+ storeTenantId(tenant.id);
// Step 2: Validate and Upload CSV file if provided
if (bakeryData.csvFile) {
@@ -327,7 +353,7 @@ const OnboardingPage: React.FC = ({ user, onComplete }) =>
const handleComplete = async () => {
if (!validateCurrentStep()) return;
- if (currentStep < 4) {
+ if (currentStep < 3) {
// Start training process
await startTraining();
} else {
@@ -354,7 +380,7 @@ const OnboardingPage: React.FC = ({ user, onComplete }) =>
icon: 'ℹ️',
duration: 4000
});
- setCurrentStep(5);
+ setCurrentStep(4);
};
const handleTrainingTimeout = () => {
@@ -461,52 +487,6 @@ const OnboardingPage: React.FC = ({ user, onComplete }) =>
);
case 2:
- return (
-
-
-
- Productos y Servicios
-
-
- Selecciona los productos que vendes regularmente. Esto nos ayudará a crear predicciones más precisas.
-
-
-
- {MADRID_PRODUCTS.map((product) => (
-
- ))}
-
-
- {bakeryData.products.length > 0 && (
-
-
- ✅ {bakeryData.products.length} productos seleccionados
-
-
- )}
-
-
- );
-
- case 3:
return (
@@ -695,7 +675,7 @@ const OnboardingPage: React.FC = ({ user, onComplete }) =>
);
- case 4:
+ case 3:
return (
= ({ user, onComplete }) =>
/>
);
- case 5:
+ case 4:
return (
@@ -832,7 +812,7 @@ const OnboardingPage: React.FC
= ({ user, onComplete }) =>
{/* Dynamic Next/Complete Button */}
- {currentStep < 4 ? (
+ {currentStep < 3 ? (
- ) : currentStep === 4 ? (
+ ) : currentStep === 3 ? (
// Training step - show different buttons based on status
{trainingProgress.status === 'failed' ? (
@@ -877,7 +857,7 @@ const OnboardingPage: React.FC = ({ user, onComplete }) =>
>
) : trainingProgress.status === 'completed' ? (