Start integrating the onboarding flow with backend 13

This commit is contained in:
Urtzi Alfaro
2025-09-07 21:26:28 +02:00
parent b73f3b4993
commit 05898d504d
10 changed files with 24 additions and 132 deletions

View File

@@ -455,7 +455,7 @@ export const SmartInventorySetupStep: React.FC<OnboardingStepProps> = ({
</div> </div>
<div> <div>
<h3 className="text-3xl font-bold text-[var(--text-primary)] mb-4"> <h3 className="text-3xl font-bold text-[var(--text-primary)] mb-4">
Sube tu historial de ventas Sube tus datos de ventas de forma segura: eres el propietario de esos datos, nosotros solo los optimizamos.
</h3> </h3>
<p className="text-[var(--text-secondary)] text-xl leading-relaxed max-w-md mx-auto"> <p className="text-[var(--text-secondary)] text-xl leading-relaxed max-w-md mx-auto">
Arrastra y suelta tu archivo aquí, o <span className="text-[var(--color-primary)] font-semibold">haz clic para seleccionar</span> Arrastra y suelta tu archivo aquí, o <span className="text-[var(--color-primary)] font-semibold">haz clic para seleccionar</span>
@@ -771,7 +771,7 @@ export const SmartInventorySetupStep: React.FC<OnboardingStepProps> = ({
{/* Information */} {/* Information */}
<Card className="p-4 bg-[var(--color-info)]/5 border-[var(--color-info)]/20"> <Card className="p-4 bg-[var(--color-info)]/5 border-[var(--color-info)]/20">
<h4 className="font-medium text-[var(--color-info)] mb-2"> <h4 className="font-medium text-[var(--color-info)] mb-2">
📦 Inventario Inteligente: 📦 Sube tus datos de ventas de forma segura: eres el propietario, nosotros solo los optimizamos.:
</h4> </h4>
<ul className="text-sm text-[var(--color-info)] space-y-1"> <ul className="text-sm text-[var(--color-info)] space-y-1">
<li> <strong>Configuración automática</strong> - Los niveles de stock se calculan basándose en tus datos de ventas</li> <li> <strong>Configuración automática</strong> - Los niveles de stock se calculan basándose en tus datos de ventas</li>

View File

@@ -55,7 +55,8 @@ src/hooks/business/onboarding/
├── core/ ├── core/
│ ├── store.ts # Zustand centralized store │ ├── store.ts # Zustand centralized store
│ ├── actions.ts # Business logic orchestration │ ├── actions.ts # Business logic orchestration
── types.ts # Complete type definitions ── types.ts # Complete type definitions
│ └── useAutoResume.ts # Auto-resume wrapper
├── services/ ├── services/
│ ├── useTenantCreation.ts # Tenant service │ ├── useTenantCreation.ts # Tenant service
│ ├── useSalesProcessing.ts # Sales processing service │ ├── useSalesProcessing.ts # Sales processing service
@@ -65,10 +66,9 @@ src/hooks/business/onboarding/
│ └── useResumeLogic.ts # Resume service │ └── useResumeLogic.ts # Resume service
├── utils/ ├── utils/
│ └── createServiceHook.ts # Service factory │ └── createServiceHook.ts # Service factory
├── config/
│ └── steps.ts # Step definitions and validation
├── useOnboarding.ts # Main unified hook ├── useOnboarding.ts # Main unified hook
├── useAutoResume.ts # Auto-resume wrapper
├── steps.ts # Step definitions
├── types.ts # Legacy type exports
└── index.ts # Clean exports └── index.ts # Clean exports
``` ```

View File

@@ -2,7 +2,7 @@
* Onboarding step definitions and validation logic * Onboarding step definitions and validation logic
*/ */
import type { OnboardingStep, OnboardingData } from './types'; import type { OnboardingStep, OnboardingData } from '../core/types';
export const DEFAULT_STEPS: OnboardingStep[] = [ export const DEFAULT_STEPS: OnboardingStep[] = [
{ {

View File

@@ -10,7 +10,7 @@ import { useSalesProcessing } from '../services/useSalesProcessing';
import { useInventorySetup } from '../services/useInventorySetup'; import { useInventorySetup } from '../services/useInventorySetup';
import { useTrainingOrchestration } from '../services/useTrainingOrchestration'; import { useTrainingOrchestration } from '../services/useTrainingOrchestration';
import { useProgressTracking } from '../services/useProgressTracking'; import { useProgressTracking } from '../services/useProgressTracking';
import { getStepById } from '../steps'; import { getStepById } from '../config/steps';
import type { ProductSuggestionResponse } from '../core/types'; import type { ProductSuggestionResponse } from '../core/types';
import type { BakeryRegistration } from '../../../../api'; import type { BakeryRegistration } from '../../../../api';

View File

@@ -6,7 +6,7 @@
import { create } from 'zustand'; import { create } from 'zustand';
import { devtools } from 'zustand/middleware'; import { devtools } from 'zustand/middleware';
import type { OnboardingData, OnboardingStep, OnboardingProgress } from './types'; import type { OnboardingData, OnboardingStep, OnboardingProgress } from './types';
import { DEFAULT_STEPS } from '../steps'; import { DEFAULT_STEPS } from '../config/steps';
interface OnboardingStore { interface OnboardingStore {
// Flow state // Flow state

View File

@@ -2,7 +2,7 @@
* Auto-resume hook - Simple wrapper around resume logic service * Auto-resume hook - Simple wrapper around resume logic service
*/ */
import { useResumeLogic } from './services/useResumeLogic'; import { useResumeLogic } from '../services/useResumeLogic';
export const useAutoResume = () => { export const useAutoResume = () => {
const resumeLogic = useResumeLogic(); const resumeLogic = useResumeLogic();

View File

@@ -7,7 +7,7 @@
export type * from './core/types'; export type * from './core/types';
// Steps configuration // Steps configuration
export { DEFAULT_STEPS, getStepById, getStepIndex, canAccessStep, calculateProgress } from './steps'; export { DEFAULT_STEPS, getStepById, getStepIndex, canAccessStep, calculateProgress } from './config/steps';
// Core architecture (for advanced usage) // Core architecture (for advanced usage)
export { useOnboardingStore } from './core/store'; export { useOnboardingStore } from './core/store';
@@ -23,7 +23,7 @@ export { useResumeLogic } from './services/useResumeLogic';
// Main hooks - PRIMARY INTERFACE for components // Main hooks - PRIMARY INTERFACE for components
export { useOnboarding } from './useOnboarding'; export { useOnboarding } from './useOnboarding';
export { useAutoResume } from './useAutoResume'; export { useAutoResume } from './core/useAutoResume';
// Utility // Utility
export { createServiceHook } from './utils/createServiceHook'; export { createServiceHook } from './utils/createServiceHook';

View File

@@ -2,7 +2,7 @@
* Progress tracking service - Clean, standardized implementation * Progress tracking service - Clean, standardized implementation
*/ */
import { useCallback, useEffect } from 'react'; import { useCallback, useEffect, useRef } from 'react';
import { onboardingService } from '../../../../api/services/onboarding'; import { onboardingService } from '../../../../api/services/onboarding';
import { createServiceHook } from '../utils/createServiceHook'; import { createServiceHook } from '../utils/createServiceHook';
import type { ProgressTrackingState } from '../core/types'; import type { ProgressTrackingState } from '../core/types';
@@ -20,6 +20,7 @@ const useProgressTrackingService = createServiceHook<ProgressTrackingState>({
export const useProgressTracking = () => { export const useProgressTracking = () => {
const service = useProgressTrackingService(); const service = useProgressTrackingService();
const initializationAttempted = useRef(false);
// Load initial progress from backend // Load initial progress from backend
const loadProgress = useCallback(async (): Promise<UserProgress | null> => { const loadProgress = useCallback(async (): Promise<UserProgress | null> => {
@@ -121,12 +122,13 @@ export const useProgressTracking = () => {
} }
}, []); }, []);
// Auto-load progress on hook initialization // Auto-load progress on hook initialization - PREVENT multiple attempts
useEffect(() => { useEffect(() => {
if (!service.data?.isInitialized) { if (!service.data?.isInitialized && !initializationAttempted.current && !service.isLoading) {
initializationAttempted.current = true;
loadProgress(); loadProgress();
} }
}, [loadProgress, service.data?.isInitialized]); }, [service.data?.isInitialized, service.isLoading]); // Remove loadProgress from deps
return { return {
// State // State

View File

@@ -2,7 +2,7 @@
* Resume logic service - Clean, standardized implementation * Resume logic service - Clean, standardized implementation
*/ */
import { useCallback, useEffect } from 'react'; import { useCallback, useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useOnboardingStore } from '../core/store'; import { useOnboardingStore } from '../core/store';
import { useProgressTracking } from './useProgressTracking'; import { useProgressTracking } from './useProgressTracking';
@@ -22,6 +22,7 @@ export const useResumeLogic = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const progressTracking = useProgressTracking(); const progressTracking = useProgressTracking();
const { setCurrentStep } = useOnboardingStore(); const { setCurrentStep } = useOnboardingStore();
const resumeAttempted = useRef(false);
// Check if user should resume onboarding // Check if user should resume onboarding
const checkForResume = useCallback(async (): Promise<boolean> => { const checkForResume = useCallback(async (): Promise<boolean> => {
@@ -114,12 +115,13 @@ export const useResumeLogic = () => {
} }
}, [checkForResume, resumeFlow]); }, [checkForResume, resumeFlow]);
// Auto-check for resume when the hook is first used // Auto-check for resume when the hook is first used - PREVENT multiple attempts
useEffect(() => { useEffect(() => {
if (progressTracking.isInitialized && !service.data?.isCheckingResume) { if (progressTracking.isInitialized && !service.data?.isCheckingResume && !resumeAttempted.current) {
resumeAttempted.current = true;
handleAutoResume(); handleAutoResume();
} }
}, [progressTracking.isInitialized, handleAutoResume, service.data?.isCheckingResume]); }, [progressTracking.isInitialized, service.data?.isCheckingResume]); // Remove handleAutoResume from deps
return { return {
// State // State

View File

@@ -1,112 +0,0 @@
/**
* Shared types for onboarding hooks
*/
import type {
BakeryRegistration,
ProductSuggestionResponse,
BusinessModelAnalysisResponse,
User
} from '../../../api';
// Re-export for convenience
export type { ProductSuggestionResponse, BusinessModelAnalysisResponse };
export interface OnboardingStep {
id: string;
title: string;
description: string;
isRequired: boolean;
isCompleted: boolean;
validation?: (data: OnboardingData) => string | null;
}
export interface OnboardingData {
// Step 1: Setup
bakery?: BakeryRegistration;
// Step 2: Data Processing
files?: {
salesData?: File;
};
processingStage?: 'upload' | 'validating' | 'analyzing' | 'review' | 'completed' | 'error';
processingResults?: {
is_valid: boolean;
total_records: number;
unique_products: number;
product_list: string[];
validation_errors: string[];
validation_warnings: string[];
summary: {
date_range: string;
total_sales: number;
average_daily_sales: number;
};
};
// Step 3: Sales Validation (merged data processing + review)
suggestions?: ProductSuggestionResponse[];
detectedProducts?: any[]; // Products detected from AI analysis
approvedSuggestions?: ProductSuggestionResponse[];
approvedProducts?: ProductSuggestionResponse[];
reviewCompleted?: boolean;
// Step 4: Inventory
inventoryItems?: any[];
inventoryMapping?: { [productName: string]: string };
inventoryConfigured?: boolean;
salesImportResult?: {
success: boolean;
imported: boolean;
records_created: number;
message: string;
};
// Step 5: Suppliers
suppliers?: any[];
supplierMappings?: any[];
// Step 6: ML Training
trainingStatus?: 'idle' | 'validating' | 'training' | 'completed' | 'failed';
trainingProgress?: number;
trainingJob?: any;
trainingLogs?: any[];
trainingMetrics?: any;
autoStartTraining?: boolean;
// Step 7: Completion
completionStats?: {
totalProducts: number;
inventoryItems: number;
suppliersConfigured: number;
mlModelAccuracy: number;
estimatedTimeSaved: string;
completionScore: number;
};
// Cross-step data sharing
allStepData?: { [stepId: string]: any };
}
export interface OnboardingProgress {
currentStep: number;
totalSteps: number;
completedSteps: number;
isComplete: boolean;
progressPercentage: number;
}
export interface OnboardingError {
step?: string;
message: string;
details?: any;
}
// Processing progress callback
export type ProgressCallback = (progress: number, stage: string, message: string) => void;
// Step validation function
export type StepValidator = (data: OnboardingData) => string | null;
// Step update callback
export type StepDataUpdater = (stepId: string, data: Partial<OnboardingData>) => void;