/** * Embedded Stripe Connect Onboarding Component * * Uses Stripe's Connect embedded components to provide a seamless * onboarding experience without redirecting users away from the app. */ import React, { useState, useCallback } from 'react'; import { ConnectComponentsProvider, ConnectAccountOnboarding, } from '@stripe/react-connect-js'; import { loadConnectAndInitialize } from '@stripe/connect-js'; import type { StripeConnectInstance } from '@stripe/connect-js'; import { CheckCircle, AlertCircle, Loader2, CreditCard, Wallet, Building2, } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { createAccountSession, refreshConnectStatus, ConnectAccountInfo } from '../api/payments'; interface ConnectOnboardingEmbedProps { connectAccount: ConnectAccountInfo | null; tier: string; onComplete?: () => void; onError?: (error: string) => void; } type LoadingState = 'idle' | 'loading' | 'ready' | 'error' | 'complete'; const ConnectOnboardingEmbed: React.FC = ({ connectAccount, tier, onComplete, onError, }) => { const { t } = useTranslation(); const [stripeConnectInstance, setStripeConnectInstance] = useState(null); const [loadingState, setLoadingState] = useState('idle'); const [errorMessage, setErrorMessage] = useState(null); const isActive = connectAccount?.status === 'active' && connectAccount?.charges_enabled; // Initialize Stripe Connect const initializeStripeConnect = useCallback(async () => { if (loadingState === 'loading' || loadingState === 'ready') return; setLoadingState('loading'); setErrorMessage(null); try { // Fetch account session from our backend const response = await createAccountSession(); const { client_secret, publishable_key } = response.data; // Initialize the Connect instance const instance = await loadConnectAndInitialize({ publishableKey: publishable_key, fetchClientSecret: async () => client_secret, appearance: { overlays: 'drawer', variables: { colorPrimary: '#635BFF', colorBackground: '#ffffff', colorText: '#1a1a1a', colorDanger: '#df1b41', fontFamily: 'system-ui, -apple-system, sans-serif', fontSizeBase: '14px', spacingUnit: '12px', borderRadius: '8px', }, }, }); setStripeConnectInstance(instance); setLoadingState('ready'); } catch (err: any) { console.error('Failed to initialize Stripe Connect:', err); const message = err.response?.data?.error || err.message || t('payments.failedToInitializePayment'); setErrorMessage(message); setLoadingState('error'); onError?.(message); } }, [loadingState, onError, t]); // Handle onboarding completion const handleOnboardingExit = useCallback(async () => { // Refresh status from Stripe to sync the local database try { await refreshConnectStatus(); } catch (err) { console.error('Failed to refresh Connect status:', err); } setLoadingState('complete'); onComplete?.(); }, [onComplete]); // Handle errors from the Connect component const handleLoadError = useCallback((loadError: { error: { message?: string }; elementTagName: string }) => { console.error('Connect component load error:', loadError); const message = loadError.error.message || t('payments.failedToLoadPaymentComponent'); setErrorMessage(message); setLoadingState('error'); onError?.(message); }, [onError, t]); // Account type display const getAccountTypeLabel = () => { switch (connectAccount?.account_type) { case 'standard': return t('payments.standardConnect'); case 'express': return t('payments.expressConnect'); case 'custom': return t('payments.customConnect'); default: return t('payments.connect'); } }; // If account is already active, show status if (isActive) { return (

{t('payments.stripeConnected')}

{t('payments.stripeConnectedDesc')}

{t('payments.accountDetails')}

{t('payments.accountType')}: {getAccountTypeLabel()}
{t('payments.status')}: {connectAccount.status}
{t('payments.charges')}: {t('payments.enabled')}
{t('payments.payouts')}: {connectAccount.payouts_enabled ? t('payments.enabled') : t('payments.pending')}
); } // Completion state if (loadingState === 'complete') { return (

{t('payments.onboardingComplete')}

{t('payments.stripeSetupComplete')}

); } // Error state if (loadingState === 'error') { return (

{t('payments.setupFailed')}

{errorMessage}

); } // Idle state - show start button if (loadingState === 'idle') { return (

{t('payments.setUpPayments')}

{t('payments.tierPaymentDescriptionWithOnboarding', { tier })}

  • {t('payments.securePaymentProcessing')}
  • {t('payments.automaticPayouts')}
  • {t('payments.pciCompliance')}
); } // Loading state if (loadingState === 'loading') { return (

{t('payments.initializingPaymentSetup')}

); } // Ready state - show embedded onboarding if (loadingState === 'ready' && stripeConnectInstance) { return (

{t('payments.completeAccountSetup')}

{t('payments.fillOutInfoForPayment')}

); } return null; }; export default ConnectOnboardingEmbed;