Support multiple languages

This commit is contained in:
Urtzi Alfaro
2025-09-25 12:14:46 +02:00
parent 6d4090f825
commit f02a980c87
66 changed files with 3274 additions and 333 deletions

View File

@@ -1,5 +1,6 @@
import React, { useState, useEffect } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Button } from '../../ui/Button';
import { Card, CardHeader, CardBody } from '../../ui/Card';
import { useAuth } from '../../../contexts/AuthContext';
@@ -29,40 +30,41 @@ interface StepProps {
isLastStep: boolean;
}
// Steps must match backend ONBOARDING_STEPS exactly
// Note: "user_registered" is auto-completed and not shown in UI
const STEPS: StepConfig[] = [
{
id: 'setup',
title: 'Registrar Panadería',
description: 'Configura la información básica de tu panadería',
component: RegisterTenantStep,
},
{
id: 'smart-inventory-setup',
title: 'Configurar Inventario',
description: 'Sube datos de ventas y configura tu inventario inicial',
component: UploadSalesDataStep,
},
{
id: 'ml-training',
title: 'Entrenamiento IA',
description: 'Entrena tu modelo de inteligencia artificial personalizado',
component: MLTrainingStep,
},
{
id: 'completion',
title: 'Configuración Completa',
description: '¡Bienvenido a tu sistema de gestión inteligente!',
component: CompletionStep,
},
];
export const OnboardingWizard: React.FC = () => {
const { t } = useTranslation();
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const { user } = useAuth();
// Steps must match backend ONBOARDING_STEPS exactly
// Note: "user_registered" is auto-completed and not shown in UI
const STEPS: StepConfig[] = [
{
id: 'setup',
title: t('onboarding:wizard.steps.setup.title', 'Registrar Panadería'),
description: t('onboarding:wizard.steps.setup.description', 'Configura la información básica de tu panadería'),
component: RegisterTenantStep,
},
{
id: 'smart-inventory-setup',
title: t('onboarding:wizard.steps.smart_inventory_setup.title', 'Configurar Inventario'),
description: t('onboarding:wizard.steps.smart_inventory_setup.description', 'Sube datos de ventas y configura tu inventario inicial'),
component: UploadSalesDataStep,
},
{
id: 'ml-training',
title: t('onboarding:wizard.steps.ml_training.title', 'Entrenamiento IA'),
description: t('onboarding:wizard.steps.ml_training.description', 'Entrena tu modelo de inteligencia artificial personalizado'),
component: MLTrainingStep,
},
{
id: 'completion',
title: t('onboarding:wizard.steps.completion.title', 'Configuración Completa'),
description: t('onboarding:wizard.steps.completion.description', '¡Bienvenido a tu sistema de gestión inteligente!'),
component: CompletionStep,
},
];
// Check if this is a fresh onboarding (new tenant creation)
const isNewTenant = searchParams.get('new') === 'true';
@@ -277,7 +279,7 @@ export const OnboardingWizard: React.FC = () => {
}
// Don't advance automatically on error - user should see the issue
alert(`Error al completar paso "${currentStep.title}": ${errorMessage}`);
alert(`${t('onboarding:errors.step_failed', 'Error al completar paso')} "${currentStep.title}": ${errorMessage}`);
}
};
@@ -289,7 +291,7 @@ export const OnboardingWizard: React.FC = () => {
<CardBody>
<div className="flex items-center justify-center space-x-3">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-[var(--color-primary)]"></div>
<p className="text-[var(--text-secondary)] text-sm sm:text-base">Cargando tu progreso...</p>
<p className="text-[var(--text-secondary)] text-sm sm:text-base">{t('common:loading', 'Cargando tu progreso...')}</p>
</div>
</CardBody>
</Card>
@@ -311,17 +313,17 @@ export const OnboardingWizard: React.FC = () => {
</div>
<div>
<h2 className="text-base sm:text-lg font-semibold text-[var(--text-primary)] mb-2">
Error al cargar progreso
{t('onboarding:errors.network_error', 'Error al cargar progreso')}
</h2>
<p className="text-sm sm:text-base text-[var(--text-secondary)] mb-4 px-2">
No pudimos cargar tu progreso de configuración. Puedes continuar desde el inicio.
{t('onboarding:errors.try_again', 'No pudimos cargar tu progreso de configuración. Puedes continuar desde el inicio.')}
</p>
<Button
onClick={() => setIsInitialized(true)}
variant="primary"
size="lg"
>
Continuar
{t('onboarding:wizard.navigation.next', 'Continuar')}
</Button>
</div>
</div>
@@ -350,10 +352,10 @@ export const OnboardingWizard: React.FC = () => {
</div>
<div>
<p className="text-sm font-medium text-[var(--text-primary)]">
Creando Nueva Organización
{t('onboarding:wizard.title', '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.
{t('onboarding:wizard.subtitle', 'Configurarás una nueva panadería desde cero. Este proceso es independiente de tus organizaciones existentes.')}
</p>
</div>
</div>
@@ -366,21 +368,21 @@ export const OnboardingWizard: React.FC = () => {
<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)]">
{isNewTenant ? 'Crear Nueva Organización' : 'Bienvenido a Bakery IA'}
{isNewTenant ? t('onboarding:wizard.title', 'Crear Nueva Organización') : t('onboarding:wizard.title', 'Bienvenido a Bakery IA')}
</h1>
<p className="text-[var(--text-secondary)] text-xs sm:text-sm mt-1">
{isNewTenant
? 'Configura tu nueva panadería desde cero'
: 'Configura tu sistema de gestión inteligente paso a paso'
? t('onboarding:wizard.subtitle', 'Configura tu nueva panadería desde cero')
: t('onboarding:wizard.subtitle', 'Configura tu sistema de gestión inteligente paso a paso')
}
</p>
</div>
<div className="text-center sm:text-right">
<div className="text-sm text-[var(--text-secondary)]">
Paso {currentStepIndex + 1} de {STEPS.length}
{t('onboarding:wizard.progress.step_of', 'Paso {{current}} de {{total}}', { current: currentStepIndex + 1, total: STEPS.length })}
</div>
<div className="text-xs text-[var(--text-tertiary)]">
{Math.round(progressPercentage)}% completado
{Math.round(progressPercentage)}% {t('onboarding:wizard.progress.completed', 'completado')}
{isNewTenant && <span className="text-[var(--color-primary)] ml-1">(nuevo)</span>}
</div>
</div>