/** * Progress tracking service - Clean, standardized implementation */ import { useCallback, useEffect, useRef } from 'react'; import { onboardingService } from '../../../../api/services/onboarding'; import { createServiceHook } from '../utils/createServiceHook'; import type { ProgressTrackingState } from '../core/types'; import type { UserProgress } from '../../../../api/types/onboarding'; const useProgressTrackingService = createServiceHook({ initialState: { progress: null, isInitialized: false, isCompleted: false, completionPercentage: 0, currentBackendStep: null, }, }); export const useProgressTracking = () => { const service = useProgressTrackingService(); const initializationAttempted = useRef(false); // Load initial progress from backend const loadProgress = useCallback(async (): Promise => { const result = await service.executeAsync(async () => { const progress = await onboardingService.getUserProgress(''); // Update service state with additional computed values const updatedData = { ...service.data!, progress, isInitialized: true, isCompleted: progress?.fully_completed || false, completionPercentage: progress?.completion_percentage || 0, currentBackendStep: progress?.current_step || null, }; service.setSuccess(updatedData); return progress; }); return result.data || null; }, [service]); // Mark a step as completed and save to backend const markStepCompleted = useCallback(async ( stepId: string, data?: Record ): Promise => { const result = await service.executeAsync(async () => { const updatedProgress = await onboardingService.markStepAsCompleted(stepId, data); // Update service state service.setSuccess({ ...service.data!, progress: updatedProgress, isCompleted: updatedProgress?.fully_completed || false, completionPercentage: updatedProgress?.completion_percentage || 0, currentBackendStep: updatedProgress?.current_step || null, }); console.log(`✅ Step "${stepId}" marked as completed in backend`); return updatedProgress; }); if (!result.success) { console.error(`❌ Error marking step "${stepId}" as completed:`, result.error); } return result.success; }, [service]); // Get the next step the user should work on const getNextStep = useCallback(async (): Promise => { try { return await onboardingService.getNextStepId(); } catch (error) { console.error('Error getting next step:', error); return 'setup'; } }, []); // Get the step and index where user should resume const getResumePoint = useCallback(async (): Promise<{ stepId: string; stepIndex: number }> => { try { return await onboardingService.getResumeStep(); } catch (error) { console.error('Error getting resume point:', error); return { stepId: 'setup', stepIndex: 0 }; } }, []); // Complete the entire onboarding process const completeOnboarding = useCallback(async (): Promise => { const result = await service.executeAsync(async () => { const result = await onboardingService.completeOnboarding(); if (result.success) { // Reload progress to get updated status await loadProgress(); console.log('🎉 Onboarding completed successfully!'); return result; } throw new Error('Failed to complete onboarding'); }); return result.success; }, [service, loadProgress]); // Check if user can access a specific step const canAccessStep = useCallback(async (stepId: string): Promise => { try { const result = await onboardingService.canAccessStep(stepId); return result.can_access; } catch (error) { console.error(`Error checking access for step "${stepId}":`, error); return true; // Allow access on error } }, []); // Auto-load progress on hook initialization - PREVENT multiple attempts useEffect(() => { if (!service.data?.isInitialized && !initializationAttempted.current && !service.isLoading) { initializationAttempted.current = true; loadProgress(); } }, [service.data?.isInitialized, service.isLoading]); // Remove loadProgress from deps return { // State isLoading: service.isLoading, error: service.error, progress: service.data?.progress || null, isInitialized: service.data?.isInitialized || false, isCompleted: service.data?.isCompleted || false, completionPercentage: service.data?.completionPercentage || 0, currentBackendStep: service.data?.currentBackendStep || null, // Actions loadProgress, markStepCompleted, getNextStep, getResumePoint, completeOnboarding, canAccessStep, clearError: service.clearError, }; };