'use client'; import { OnboardingCardAccent } from '@/ui/OnboardingCardAccent'; import { OnboardingContainer } from '@/ui/OnboardingContainer'; import { OnboardingError } from '@/ui/OnboardingError'; import { OnboardingForm } from '@/ui/OnboardingForm'; import { OnboardingHeader } from '@/ui/OnboardingHeader'; import { OnboardingHelpText } from '@/ui/OnboardingHelpText'; import { OnboardingNavigation } from '@/ui/OnboardingNavigation'; import { PersonalInfo, PersonalInfoStep } from '@/components/onboarding/PersonalInfoStep'; import { Card } from '@/ui/Card'; import { StepIndicator } from '@/ui/StepIndicator'; import { FormEvent, useState } from 'react'; import { AvatarInfo, AvatarStep } from './AvatarStep'; type OnboardingStep = 1 | 2; interface FormErrors { [key: string]: string | undefined; firstName?: string; lastName?: string; displayName?: string; country?: string; facePhoto?: string; avatar?: string; submit?: string; } interface OnboardingWizardProps { onCompleted: () => void; onCompleteOnboarding: (data: { firstName: string; lastName: string; displayName: string; country: string; timezone?: string; }) => Promise<{ success: boolean; error?: string }>; onGenerateAvatars: (params: { facePhotoData: string; suitColor: string; }) => Promise<{ success: boolean; data?: { success: boolean; avatarUrls?: string[]; errorMessage?: string }; error?: string }>; } export function OnboardingWizard({ onCompleted, onCompleteOnboarding, onGenerateAvatars }: OnboardingWizardProps) { const [step, setStep] = useState(1); const [errors, setErrors] = useState({}); // Form state const [personalInfo, setPersonalInfo] = useState({ firstName: '', lastName: '', displayName: '', country: '', timezone: '', }); const [avatarInfo, setAvatarInfo] = useState({ facePhoto: null, suitColor: 'blue', generatedAvatars: [], selectedAvatarIndex: null, isGenerating: false, isValidating: false, }); // Validation const validateStep = (currentStep: OnboardingStep): boolean => { const newErrors: FormErrors = {}; if (currentStep === 1) { if (!personalInfo.firstName.trim()) { newErrors.firstName = 'First name is required'; } if (!personalInfo.lastName.trim()) { newErrors.lastName = 'Last name is required'; } if (!personalInfo.displayName.trim()) { newErrors.displayName = 'Display name is required'; } else if (personalInfo.displayName.length < 3) { newErrors.displayName = 'Display name must be at least 3 characters'; } if (!personalInfo.country) { newErrors.country = 'Please select your country'; } } if (currentStep === 2) { if (!avatarInfo.facePhoto) { newErrors.facePhoto = 'Please upload a photo of your face'; } if (avatarInfo.generatedAvatars.length > 0 && avatarInfo.selectedAvatarIndex === null) { newErrors.avatar = 'Please select one of the generated avatars'; } } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleNext = () => { const isValid = validateStep(step); if (isValid && step < 2) { setStep((step + 1) as OnboardingStep); } }; const handleBack = () => { if (step > 1) { setStep((step - 1) as OnboardingStep); } }; const generateAvatars = async () => { if (!avatarInfo.facePhoto) { setErrors({ ...errors, facePhoto: 'Please upload a photo first' }); return; } setAvatarInfo(prev => ({ ...prev, isGenerating: true, generatedAvatars: [], selectedAvatarIndex: null })); const newErrors = { ...errors }; delete newErrors.avatar; setErrors(newErrors); try { const result = await onGenerateAvatars({ facePhotoData: avatarInfo.facePhoto, suitColor: avatarInfo.suitColor, }); if (result.success && result.data?.success && result.data.avatarUrls) { setAvatarInfo(prev => ({ ...prev, generatedAvatars: result.data!.avatarUrls!, isGenerating: false, })); } else { setErrors(prev => ({ ...prev, avatar: result.data?.errorMessage || result.error || 'Failed to generate avatars' })); setAvatarInfo(prev => ({ ...prev, isGenerating: false })); } } catch (error) { setErrors(prev => ({ ...prev, avatar: 'Failed to generate avatars. Please try again.' })); setAvatarInfo(prev => ({ ...prev, isGenerating: false })); } }; const handleSubmit = async (e: FormEvent) => { e.preventDefault(); // Validate step 2 - must have selected an avatar if (!validateStep(2)) { return; } if (avatarInfo.selectedAvatarIndex === null) { setErrors({ ...errors, avatar: 'Please select an avatar' }); return; } setErrors({}); try { const result = await onCompleteOnboarding({ firstName: personalInfo.firstName.trim(), lastName: personalInfo.lastName.trim(), displayName: personalInfo.displayName.trim(), country: personalInfo.country, timezone: personalInfo.timezone || undefined, }); if (result.success) { onCompleted(); } else { setErrors({ submit: result.error || 'Failed to create profile' }); } } catch (error) { setErrors({ submit: 'Failed to create profile' }); } }; // Loading state comes from the mutations const loading = false; // This would be managed by the parent component return ( {step === 1 && ( )} {step === 2 && ( )} {errors.submit && } ); }