Add onboardin steps improvements

This commit is contained in:
Urtzi Alfaro
2025-08-11 07:01:08 +02:00
parent c721575cd3
commit c4d4aeb449
16 changed files with 2015 additions and 103 deletions

View File

@@ -9,6 +9,16 @@ export { useData } from './useData';
export { useTraining } from './useTraining';
export { useForecast } from './useForecast';
export { useNotification } from './useNotification';
export { useOnboarding, useOnboardingStep } from './useOnboarding';
// Import hooks for combined usage
import { useAuth } from './useAuth';
import { useTenant } from './useTenant';
import { useData } from './useData';
import { useTraining } from './useTraining';
import { useForecast } from './useForecast';
import { useNotification } from './useNotification';
import { useOnboarding } from './useOnboarding';
// Combined hook for common operations
export const useApiHooks = () => {
@@ -18,6 +28,7 @@ export const useApiHooks = () => {
const training = useTraining();
const forecast = useForecast();
const notification = useNotification();
const onboarding = useOnboarding();
return {
auth,
@@ -26,5 +37,6 @@ export const useApiHooks = () => {
training,
forecast,
notification,
onboarding,
};
};

View File

@@ -0,0 +1,194 @@
// frontend/src/api/hooks/useOnboarding.ts
/**
* Onboarding Hook
* React hook for managing user onboarding flow and progress
*/
import { useState, useEffect } from 'react';
import { onboardingService } from '../services/onboarding.service';
import type { UserProgress, UpdateStepRequest } from '../services/onboarding.service';
export interface UseOnboardingReturn {
progress: UserProgress | null;
isLoading: boolean;
error: string | null;
currentStep: string | null;
nextStep: string | null;
completionPercentage: number;
isFullyComplete: boolean;
// Actions
updateStep: (data: UpdateStepRequest) => Promise<void>;
completeStep: (stepName: string, data?: Record<string, any>) => Promise<void>;
resetStep: (stepName: string) => Promise<void>;
getNextStep: () => Promise<string>;
completeOnboarding: () => Promise<void>;
canAccessStep: (stepName: string) => Promise<boolean>;
refreshProgress: () => Promise<void>;
}
export const useOnboarding = (): UseOnboardingReturn => {
const [progress, setProgress] = useState<UserProgress | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// Derived state
const currentStep = progress?.current_step || null;
const nextStep = progress?.next_step || null;
const completionPercentage = progress?.completion_percentage || 0;
const isFullyComplete = progress?.fully_completed || false;
// Load initial progress
const loadProgress = async () => {
setIsLoading(true);
setError(null);
try {
const userProgress = await onboardingService.getUserProgress();
setProgress(userProgress);
} catch (err) {
const message = err instanceof Error ? err.message : 'Failed to load onboarding progress';
setError(message);
console.error('Onboarding progress load error:', err);
} finally {
setIsLoading(false);
}
};
// Update step
const updateStep = async (data: UpdateStepRequest) => {
setIsLoading(true);
setError(null);
try {
const updatedProgress = await onboardingService.updateStep(data);
setProgress(updatedProgress);
} catch (err) {
const message = err instanceof Error ? err.message : 'Failed to update step';
setError(message);
throw err; // Re-throw so calling component can handle it
} finally {
setIsLoading(false);
}
};
// Complete step with data
const completeStep = async (stepName: string, data?: Record<string, any>) => {
await updateStep({
step_name: stepName,
completed: true,
data
});
};
// Reset step
const resetStep = async (stepName: string) => {
await updateStep({
step_name: stepName,
completed: false
});
};
// Get next step
const getNextStep = async (): Promise<string> => {
try {
const result = await onboardingService.getNextStep();
return result.step;
} catch (err) {
const message = err instanceof Error ? err.message : 'Failed to get next step';
setError(message);
throw err;
}
};
// Complete entire onboarding
const completeOnboarding = async () => {
setIsLoading(true);
setError(null);
try {
await onboardingService.completeOnboarding();
await loadProgress(); // Refresh progress after completion
} catch (err) {
const message = err instanceof Error ? err.message : 'Failed to complete onboarding';
setError(message);
throw err;
} finally {
setIsLoading(false);
}
};
// Check if user can access step
const canAccessStep = async (stepName: string): Promise<boolean> => {
try {
const result = await onboardingService.canAccessStep(stepName);
return result.can_access;
} catch (err) {
console.error('Can access step check failed:', err);
return false;
}
};
// Refresh progress
const refreshProgress = async () => {
await loadProgress();
};
// Load progress on mount
useEffect(() => {
loadProgress();
}, []);
return {
progress,
isLoading,
error,
currentStep,
nextStep,
completionPercentage,
isFullyComplete,
updateStep,
completeStep,
resetStep,
getNextStep,
completeOnboarding,
canAccessStep,
refreshProgress,
};
};
// Helper hook for specific steps
export const useOnboardingStep = (stepName: string) => {
const onboarding = useOnboarding();
const stepStatus = onboarding.progress?.steps.find(
step => step.step_name === stepName
);
const isCompleted = stepStatus?.completed || false;
const stepData = stepStatus?.data || {};
const completedAt = stepStatus?.completed_at;
const completeThisStep = async (data?: Record<string, any>) => {
await onboarding.completeStep(stepName, data);
};
const resetThisStep = async () => {
await onboarding.resetStep(stepName);
};
const canAccessThisStep = async (): Promise<boolean> => {
return await onboarding.canAccessStep(stepName);
};
return {
...onboarding,
stepName,
isCompleted,
stepData,
completedAt,
completeThisStep,
resetThisStep,
canAccessThisStep,
};
};