/** * Onboarding Wizard Component * Multi-step wizard for paid-tier businesses to complete post-signup setup * Step 1: Welcome/Overview * Step 2: Stripe Connect setup (embedded) * Step 3: Completion */ import React, { useState, useEffect } from 'react'; import { useSearchParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { CheckCircle, CreditCard, Rocket, ArrowRight, Sparkles, Loader2, X, AlertCircle, } from 'lucide-react'; import { Business } from '../types'; import { usePaymentConfig } from '../hooks/usePayments'; import { useUpdateBusiness } from '../hooks/useBusiness'; import ConnectOnboardingEmbed from './ConnectOnboardingEmbed'; interface OnboardingWizardProps { business: Business; onComplete: () => void; onSkip?: () => void; } type OnboardingStep = 'welcome' | 'stripe' | 'complete'; const OnboardingWizard: React.FC = ({ business, onComplete, onSkip, }) => { const { t } = useTranslation(); const [searchParams, setSearchParams] = useSearchParams(); const [currentStep, setCurrentStep] = useState('welcome'); const { data: paymentConfig, isLoading: configLoading, refetch: refetchConfig } = usePaymentConfig(); const updateBusinessMutation = useUpdateBusiness(); // Check if Stripe Connect is complete const isStripeConnected = paymentConfig?.connect_account?.status === 'active' && paymentConfig?.connect_account?.charges_enabled; // Handle return from Stripe Connect (for fallback redirect flow) useEffect(() => { const connectStatus = searchParams.get('connect'); if (connectStatus === 'complete' || connectStatus === 'refresh') { // User returned from Stripe, refresh the config refetchConfig(); // Clear the search params setSearchParams({}); // Show stripe step to verify completion setCurrentStep('stripe'); } }, [searchParams, refetchConfig, setSearchParams]); // Auto-advance to complete step when Stripe is connected useEffect(() => { if (isStripeConnected && currentStep === 'stripe') { setCurrentStep('complete'); } }, [isStripeConnected, currentStep]); // Handle embedded onboarding completion const handleEmbeddedOnboardingComplete = () => { refetchConfig(); setCurrentStep('complete'); }; // Handle embedded onboarding error const handleEmbeddedOnboardingError = (error: string) => { console.error('Embedded onboarding error:', error); }; const handleCompleteOnboarding = async () => { try { await updateBusinessMutation.mutateAsync({ initialSetupComplete: true }); onComplete(); } catch (err) { console.error('Failed to complete onboarding:', err); onComplete(); // Still call onComplete even if the update fails } }; const handleSkip = async () => { try { await updateBusinessMutation.mutateAsync({ initialSetupComplete: true }); } catch (err) { console.error('Failed to skip onboarding:', err); } if (onSkip) { onSkip(); } else { onComplete(); } }; const steps = [ { key: 'welcome', label: t('onboarding.steps.welcome') }, { key: 'stripe', label: t('onboarding.steps.payments') }, { key: 'complete', label: t('onboarding.steps.complete') }, ]; const currentStepIndex = steps.findIndex(s => s.key === currentStep); // Step indicator component const StepIndicator = () => (
{steps.map((step, index) => (
{index < currentStepIndex ? ( ) : ( index + 1 )}
{index < steps.length - 1 && (
)} ))}
); // Welcome step const WelcomeStep = () => (

{t('onboarding.welcome.title', { businessName: business.name })}

{t('onboarding.welcome.subtitle')}

{t('onboarding.welcome.whatsIncluded')}

  • {t('onboarding.welcome.connectStripe')}
  • {t('onboarding.welcome.automaticPayouts')}
  • {t('onboarding.welcome.pciCompliance')}
); // Stripe Connect step - uses embedded onboarding const StripeStep = () => (

{t('onboarding.stripe.title')}

{t('onboarding.stripe.subtitle', { plan: business.plan })}

{configLoading ? (
{t('onboarding.stripe.checkingStatus')}
) : isStripeConnected ? (

{t('onboarding.stripe.connected.title')}

{t('onboarding.stripe.connected.subtitle')}

) : (
)}
); // Complete step const CompleteStep = () => (

{t('onboarding.complete.title')}

{t('onboarding.complete.subtitle')}

  • {t('onboarding.complete.checklist.accountCreated')}
  • {t('onboarding.complete.checklist.stripeConfigured')}
  • {t('onboarding.complete.checklist.readyForPayments')}
); return (
{/* Header with close button */}
{/* Content */}
{currentStep === 'welcome' && } {currentStep === 'stripe' && } {currentStep === 'complete' && }
); }; export default OnboardingWizard;