IMPORVE ONBOARDING STEPS

This commit is contained in:
Urtzi Alfaro
2025-11-09 09:22:08 +01:00
parent 4678f96f8f
commit cbe19a3cd1
27 changed files with 2801 additions and 1149 deletions

View File

@@ -11,7 +11,8 @@ import { WizardProvider, useWizardContext, BakeryType, DataSource } from './cont
import {
BakeryTypeSelectionStep,
RegisterTenantStep,
UploadSalesDataStep,
FileUploadStep,
InventoryReviewStep,
ProductCategorizationStep,
InitialStockEntryStep,
ProductionProcessesStep,
@@ -73,20 +74,20 @@ const OnboardingWizardContent: React.FC = () => {
isConditional: true,
condition: (ctx) => ctx.state.bakeryType !== null,
},
// Phase 2a: AI-Assisted Path (ONLY PATH NOW)
// Phase 2a: AI-Assisted Inventory Setup (REFACTORED - split into 3 focused steps)
{
id: 'smart-inventory-setup',
title: t('onboarding:steps.smart_inventory.title', 'Subir Datos de Ventas'),
description: t('onboarding:steps.smart_inventory.description', 'Configuración con IA'),
component: UploadSalesDataStep,
id: 'upload-sales-data',
title: t('onboarding:steps.upload_sales.title', 'Subir Datos de Ventas'),
description: t('onboarding:steps.upload_sales.description', 'Cargar archivo con historial de ventas'),
component: FileUploadStep,
isConditional: true,
condition: (ctx) => ctx.tenantId !== null,
condition: (ctx) => ctx.state.bakeryType !== null, // Tenant created after bakeryType is set
},
{
id: 'product-categorization',
title: t('onboarding:steps.categorization.title', 'Categorizar Productos'),
description: t('onboarding:steps.categorization.description', 'Clasifica ingredientes vs productos'),
component: ProductCategorizationStep,
id: 'inventory-review',
title: t('onboarding:steps.inventory_review.title', 'Revisar Inventario'),
description: t('onboarding:steps.inventory_review.description', 'Confirmar productos detectados'),
component: InventoryReviewStep,
isConditional: true,
condition: (ctx) => ctx.state.aiAnalysisComplete,
},
@@ -96,7 +97,7 @@ const OnboardingWizardContent: React.FC = () => {
description: t('onboarding:steps.stock.description', 'Cantidades iniciales'),
component: InitialStockEntryStep,
isConditional: true,
condition: (ctx) => ctx.state.categorizationCompleted,
condition: (ctx) => ctx.state.inventoryReviewCompleted,
},
{
id: 'suppliers-setup',
@@ -130,7 +131,7 @@ const OnboardingWizardContent: React.FC = () => {
description: t('onboarding:steps.quality.description', 'Estándares de calidad'),
component: QualitySetupStep,
isConditional: true,
condition: (ctx) => ctx.tenantId !== null,
condition: (ctx) => ctx.state.bakeryType !== null, // Tenant created after bakeryType is set
},
{
id: 'team-setup',
@@ -138,7 +139,7 @@ const OnboardingWizardContent: React.FC = () => {
description: t('onboarding:steps.team.description', 'Miembros del equipo'),
component: TeamSetupStep,
isConditional: true,
condition: (ctx) => ctx.tenantId !== null,
condition: (ctx) => ctx.state.bakeryType !== null, // Tenant created after bakeryType is set
},
// Phase 4: ML & Finalization
{
@@ -154,7 +155,7 @@ const OnboardingWizardContent: React.FC = () => {
description: t('onboarding:steps.review.description', 'Confirma tu configuración'),
component: ReviewSetupStep,
isConditional: true,
condition: (ctx) => ctx.tenantId !== null,
condition: (ctx) => ctx.state.bakeryType !== null, // Tenant created after bakeryType is set
},
{
id: 'completion',
@@ -182,7 +183,7 @@ const OnboardingWizardContent: React.FC = () => {
});
return visibleSteps;
}, [wizardContext.state, wizardContext.tenantId]);
}, [wizardContext.state]);
const isNewTenant = searchParams.get('new') === 'true';
const [currentStepIndex, setCurrentStepIndex] = useState(0);
@@ -316,10 +317,15 @@ const OnboardingWizardContent: React.FC = () => {
if (currentStep.id === 'data-source-choice' && data?.dataSource) {
wizardContext.updateDataSource(data.dataSource as DataSource);
}
if (currentStep.id === 'smart-inventory-setup' && data?.aiSuggestions) {
// REFACTORED: Handle new split steps for AI-assisted inventory
if (currentStep.id === 'upload-sales-data' && data?.aiSuggestions) {
wizardContext.updateAISuggestions(data.aiSuggestions);
wizardContext.updateUploadedFile(data.uploadedFile, data.validationResult);
wizardContext.setAIAnalysisComplete(true);
}
if (currentStep.id === 'inventory-review') {
wizardContext.markStepComplete('inventoryReviewCompleted');
}
if (currentStep.id === 'product-categorization' && data?.categorizedProducts) {
wizardContext.updateCategorizedProducts(data.categorizedProducts);
wizardContext.markStepComplete('categorizationCompleted');
@@ -345,8 +351,8 @@ const OnboardingWizardContent: React.FC = () => {
console.log(`✅ Successfully completed step: "${currentStep.id}"`);
// Special handling for smart-inventory-setup
if (currentStep.id === 'smart-inventory-setup' && data?.shouldAutoCompleteSuppliers) {
// Special handling for inventory-review - auto-complete suppliers if requested
if (currentStep.id === 'inventory-review' && data?.shouldAutoCompleteSuppliers) {
try {
console.log('🔄 Auto-completing suppliers-setup step...');
await markStepCompleted.mutateAsync({
@@ -452,12 +458,12 @@ const OnboardingWizardContent: React.FC = () => {
: userProgress?.completion_percentage || ((currentStepIndex + 1) / VISIBLE_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">
<div className="max-w-4xl mx-auto px-2 sm:px-4 md:px-6 space-y-3 sm:space-y-4 md:space-y-6 pb-4 md:pb-6">
{/* 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">
<Card shadow="sm" padding="md">
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-center mb-3 sm: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)]">
<h1 className="text-lg sm:text-xl md:text-2xl font-bold text-[var(--text-primary)]">
{isNewTenant ? t('onboarding:wizard.title_new', 'Nueva Panadería') : t('onboarding:wizard.title', 'Configuración Inicial')}
</h1>
<p className="text-[var(--text-secondary)] text-xs sm:text-sm mt-1">
@@ -488,9 +494,9 @@ const OnboardingWizardContent: React.FC = () => {
{/* Step Content */}
<Card shadow="lg" padding="none">
<CardHeader padding="lg" divider>
<div className="flex items-center space-x-3">
<div className="w-8 h-8 sm:w-10 sm:h-10 bg-[var(--color-primary)]/10 rounded-full flex items-center justify-center">
<CardHeader padding="md" divider>
<div className="flex items-center space-x-2 sm:space-x-3">
<div className="w-8 h-8 sm:w-10 sm:h-10 bg-[var(--color-primary)]/10 rounded-full flex items-center justify-center flex-shrink-0">
<div className="w-5 h-5 sm:w-6 sm:h-6 bg-[var(--color-primary)] rounded-full flex items-center justify-center text-white text-xs font-bold">
{currentStepIndex + 1}
</div>
@@ -506,7 +512,7 @@ const OnboardingWizardContent: React.FC = () => {
</div>
</CardHeader>
<CardBody padding="lg">
<CardBody padding="md">
<StepComponent
onNext={() => {}}
onPrevious={() => {}}
@@ -515,6 +521,18 @@ const OnboardingWizardContent: React.FC = () => {
isFirstStep={currentStepIndex === 0}
isLastStep={currentStepIndex === VISIBLE_STEPS.length - 1}
canContinue={canContinue}
initialData={
// Pass AI data and file to InventoryReviewStep
currentStep.id === 'inventory-review'
? {
uploadedFile: wizardContext.state.uploadedFile,
validationResult: wizardContext.state.uploadedFileValidation,
aiSuggestions: wizardContext.state.aiSuggestions,
uploadedFileName: wizardContext.state.uploadedFileName || '',
uploadedFileSize: wizardContext.state.uploadedFileSize || 0,
}
: undefined
}
/>
</CardBody>
</Card>