Add i18 support

This commit is contained in:
Urtzi Alfaro
2025-09-22 11:04:03 +02:00
parent ecfc6a1997
commit ee36c45d25
28 changed files with 2307 additions and 565 deletions

View File

@@ -1,17 +1,18 @@
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { Button } from '../../ui/Button';
import { Card, CardHeader, CardBody } from '../../ui/Card';
import { useAuth } from '../../../contexts/AuthContext';
import { useUserProgress, useMarkStepCompleted } from '../../../api/hooks/onboarding';
import { useTenantActions } from '../../../stores/tenant.store';
import { useTenantInitializer } from '../../../stores/useTenantInitializer';
import {
import {
RegisterTenantStep,
UploadSalesDataStep,
MLTrainingStep,
CompletionStep
} from './steps';
import { Building2 } from 'lucide-react';
interface StepConfig {
id: string;
@@ -58,11 +59,26 @@ const STEPS: StepConfig[] = [
];
export const OnboardingWizard: React.FC = () => {
const [currentStepIndex, setCurrentStepIndex] = useState(0);
const [isInitialized, setIsInitialized] = useState(false);
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const { user } = useAuth();
// Check if this is a fresh onboarding (new tenant creation)
const isNewTenant = searchParams.get('new') === 'true';
// Initialize state based on whether this is a new tenant or not
const [currentStepIndex, setCurrentStepIndex] = useState(0);
const [isInitialized, setIsInitialized] = useState(isNewTenant); // If new tenant, consider initialized immediately
// Debug log for new tenant creation
useEffect(() => {
if (isNewTenant) {
console.log('🆕 New tenant creation detected - UI will reset to step 0');
console.log('📊 Current step index:', currentStepIndex);
console.log('🎯 Is initialized:', isInitialized);
}
}, [isNewTenant, currentStepIndex, isInitialized]);
// Initialize tenant data for authenticated users
useTenantInitializer();
@@ -106,64 +122,77 @@ export const OnboardingWizard: React.FC = () => {
// Initialize step index based on backend progress with validation
useEffect(() => {
// Skip backend progress loading for new tenant creation
if (isNewTenant) {
return; // Already initialized to step 0
}
if (userProgress && !isInitialized) {
console.log('🔄 Initializing onboarding progress:', userProgress);
// Check if user_registered step is completed
const userRegisteredStep = userProgress.steps.find(s => s.step_name === 'user_registered');
if (!userRegisteredStep?.completed) {
console.log('⏳ Waiting for user_registered step to be auto-completed...');
return; // Wait for auto-completion to finish
}
// Find the current step index based on backend progress
const currentStepFromBackend = userProgress.current_step;
let stepIndex = STEPS.findIndex(step => step.id === currentStepFromBackend);
console.log(`🎯 Backend current step: "${currentStepFromBackend}", found at index: ${stepIndex}`);
// If current step is not found (e.g., suppliers step), find the next incomplete step
if (stepIndex === -1) {
console.log('🔍 Current step not found in UI steps, finding first incomplete step...');
// Find the first incomplete step that user can access
for (let i = 0; i < STEPS.length; i++) {
const step = STEPS[i];
const stepProgress = userProgress.steps.find(s => s.step_name === step.id);
if (!stepProgress?.completed) {
stepIndex = i;
console.log(`📍 Found first incomplete step: "${step.id}" at index ${i}`);
break;
let stepIndex = 0; // Default to first step
// If this is a new tenant creation, always start from the beginning
if (isNewTenant) {
console.log('🆕 New tenant creation - starting from first step');
stepIndex = 0;
} else {
// Find the current step index based on backend progress
const currentStepFromBackend = userProgress.current_step;
stepIndex = STEPS.findIndex(step => step.id === currentStepFromBackend);
console.log(`🎯 Backend current step: "${currentStepFromBackend}", found at index: ${stepIndex}`);
// If current step is not found (e.g., suppliers step), find the next incomplete step
if (stepIndex === -1) {
console.log('🔍 Current step not found in UI steps, finding first incomplete step...');
// Find the first incomplete step that user can access
for (let i = 0; i < STEPS.length; i++) {
const step = STEPS[i];
const stepProgress = userProgress.steps.find(s => s.step_name === step.id);
if (!stepProgress?.completed) {
stepIndex = i;
console.log(`📍 Found first incomplete step: "${step.id}" at index ${i}`);
break;
}
}
// If all visible steps are completed, go to last step
if (stepIndex === -1) {
stepIndex = STEPS.length - 1;
console.log('✅ All steps completed, going to last step');
}
}
// If all visible steps are completed, go to last step
if (stepIndex === -1) {
stepIndex = STEPS.length - 1;
console.log('✅ All steps completed, going to last step');
// Ensure user can't skip ahead - find the first incomplete step
const firstIncompleteStepIndex = STEPS.findIndex(step => {
const stepProgress = userProgress.steps.find(s => s.step_name === step.id);
return !stepProgress?.completed;
});
if (firstIncompleteStepIndex !== -1 && stepIndex > firstIncompleteStepIndex) {
console.log(`🚫 User trying to skip ahead. Redirecting to first incomplete step at index ${firstIncompleteStepIndex}`);
stepIndex = firstIncompleteStepIndex;
}
}
// Ensure user can't skip ahead - find the first incomplete step
const firstIncompleteStepIndex = STEPS.findIndex(step => {
const stepProgress = userProgress.steps.find(s => s.step_name === step.id);
return !stepProgress?.completed;
});
if (firstIncompleteStepIndex !== -1 && stepIndex > firstIncompleteStepIndex) {
console.log(`🚫 User trying to skip ahead. Redirecting to first incomplete step at index ${firstIncompleteStepIndex}`);
stepIndex = firstIncompleteStepIndex;
}
console.log(`🎯 Final step index: ${stepIndex} ("${STEPS[stepIndex]?.id}")`);
if (stepIndex !== currentStepIndex) {
setCurrentStepIndex(stepIndex);
}
setIsInitialized(true);
}
}, [userProgress, isInitialized, currentStepIndex]);
}, [userProgress, isInitialized, currentStepIndex, isNewTenant]);
const currentStep = STEPS[currentStepIndex];
@@ -214,7 +243,13 @@ export const OnboardingWizard: React.FC = () => {
}
if (currentStep.id === 'completion') {
navigate('/app');
// Navigate to dashboard after completion
if (isNewTenant) {
// For new tenant creation, navigate to dashboard and remove the new param
navigate('/app/dashboard');
} else {
navigate('/app');
}
} else {
// Auto-advance to next step after successful completion
if (currentStepIndex < STEPS.length - 1) {
@@ -246,8 +281,8 @@ export const OnboardingWizard: React.FC = () => {
}
};
// Show loading state while initializing progress
if (isLoadingProgress || !isInitialized) {
// Show loading state while initializing progress (skip for new tenant)
if (!isNewTenant && (isLoadingProgress || !isInitialized)) {
return (
<div className="max-w-4xl mx-auto px-4 sm:px-6">
<Card padding="lg" shadow="lg">
@@ -262,8 +297,8 @@ export const OnboardingWizard: React.FC = () => {
);
}
// Show error state if progress fails to load
if (progressError) {
// Show error state if progress fails to load (skip for new tenant)
if (!isNewTenant && progressError) {
return (
<div className="max-w-4xl mx-auto px-4 sm:px-6">
<Card padding="lg" shadow="lg">
@@ -297,19 +332,47 @@ export const OnboardingWizard: React.FC = () => {
}
const StepComponent = currentStep.component;
const progressPercentage = userProgress?.completion_percentage || ((currentStepIndex + 1) / STEPS.length) * 100;
// Calculate progress percentage - reset for new tenant creation
const progressPercentage = isNewTenant
? ((currentStepIndex + 1) / STEPS.length) * 100 // For new tenant, base progress only on current step
: userProgress?.completion_percentage || ((currentStepIndex + 1) / STEPS.length) * 100;
return (
<div className="max-w-4xl mx-auto px-4 sm:px-6 space-y-4 sm:space-y-6 pb-6">
{/* New Tenant Info Banner */}
{isNewTenant && (
<Card className="bg-gradient-to-r from-[var(--color-primary)]/5 to-[var(--color-primary)]/10 border-[var(--color-primary)]/20">
<CardBody className="py-3">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-[var(--color-primary)]/10 rounded-full flex items-center justify-center">
<Building2 className="w-4 h-4 text-[var(--color-primary)]" />
</div>
<div>
<p className="text-sm font-medium text-[var(--text-primary)]">
Creando Nueva Organización
</p>
<p className="text-xs text-[var(--text-secondary)]">
Configurarás una nueva panadería desde cero. Este proceso es independiente de tus organizaciones existentes.
</p>
</div>
</div>
</CardBody>
</Card>
)}
{/* Enhanced Progress Header */}
<Card shadow="sm" padding="lg">
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-center mb-4 space-y-2 sm:space-y-0">
<div className="text-center sm:text-left">
<h1 className="text-xl sm:text-2xl font-bold text-[var(--text-primary)]">
Bienvenido a Bakery IA
{isNewTenant ? 'Crear Nueva Organización' : 'Bienvenido a Bakery IA'}
</h1>
<p className="text-[var(--text-secondary)] text-xs sm:text-sm mt-1">
Configura tu sistema de gestión inteligente paso a paso
{isNewTenant
? 'Configura tu nueva panadería desde cero'
: 'Configura tu sistema de gestión inteligente paso a paso'
}
</p>
</div>
<div className="text-center sm:text-right">
@@ -318,6 +381,7 @@ export const OnboardingWizard: React.FC = () => {
</div>
<div className="text-xs text-[var(--text-tertiary)]">
{Math.round(progressPercentage)}% completado
{isNewTenant && <span className="text-[var(--color-primary)] ml-1">(nuevo)</span>}
</div>
</div>
</div>
@@ -334,7 +398,10 @@ export const OnboardingWizard: React.FC = () => {
<div className="sm:hidden">
<div className="flex space-x-4 overflow-x-auto pb-2 px-1">
{STEPS.map((step, index) => {
const isCompleted = userProgress?.steps.find(s => s.step_name === step.id)?.completed || index < currentStepIndex;
// For new tenant creation, only show completed if index is less than current step
const isCompleted = isNewTenant
? index < currentStepIndex
: userProgress?.steps.find(s => s.step_name === step.id)?.completed || index < currentStepIndex;
const isCurrent = index === currentStepIndex;
return (
@@ -377,7 +444,10 @@ export const OnboardingWizard: React.FC = () => {
{/* Desktop Step Indicators */}
<div className="hidden sm:flex sm:justify-between">
{STEPS.map((step, index) => {
const isCompleted = userProgress?.steps.find(s => s.step_name === step.id)?.completed || index < currentStepIndex;
// For new tenant creation, only show completed if index is less than current step
const isCompleted = isNewTenant
? index < currentStepIndex
: userProgress?.steps.find(s => s.step_name === step.id)?.completed || index < currentStepIndex;
const isCurrent = index === currentStepIndex;
return (