Files
bakery-ia/frontend/src/hooks/business/onboarding/services/useProgressTracking.ts
2025-09-07 21:26:28 +02:00

152 lines
4.9 KiB
TypeScript

/**
* 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<ProgressTrackingState>({
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<UserProgress | null> => {
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<string, any>
): Promise<boolean> => {
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<string> => {
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<boolean> => {
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<boolean> => {
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,
};
};