/** * Unified Signup Form with Integrated Pricing Selection * Combines free and paid signup flows in one modern interface */ import { useState, useEffect } from 'react'; import ReactDOM from 'react-dom'; import { Link, useNavigate } from 'react-router-dom'; import { ChevronLeftIcon, EyeCloseIcon, EyeIcon } from '../../icons'; import { CreditCard, Building2, Wallet, Check, Loader2, CheckCircle } from 'lucide-react'; import Label from '../form/Label'; import Input from '../form/input/InputField'; import Checkbox from '../form/input/Checkbox'; import Button from '../ui/button/Button'; import SelectDropdown from '../form/SelectDropdown'; import { useAuthStore } from '../../store/authStore'; interface Plan { id: number; name: string; slug: string; price: string | number; billing_cycle: string; is_active: boolean; max_users: number; max_sites: number; max_keywords: number; monthly_word_count_limit: number; included_credits: number; features: string[]; } interface PaymentMethodConfig { id: number; payment_method: string; display_name: string; instructions: string | null; country_code: string; is_enabled: boolean; } interface SignUpFormUnifiedProps { plans: Plan[]; selectedPlan: Plan | null; onPlanSelect: (plan: Plan) => void; plansLoading: boolean; } export default function SignUpFormUnified({ plans, selectedPlan, onPlanSelect, plansLoading, }: SignUpFormUnifiedProps) { const [showPassword, setShowPassword] = useState(false); const [isChecked, setIsChecked] = useState(false); const [billingPeriod, setBillingPeriod] = useState<'monthly' | 'annually'>('monthly'); const [formData, setFormData] = useState({ firstName: '', lastName: '', email: '', password: '', accountName: '', billingCountry: 'US', }); const [selectedPaymentMethod, setSelectedPaymentMethod] = useState(''); const [paymentMethods, setPaymentMethods] = useState([]); const [paymentMethodsLoading, setPaymentMethodsLoading] = useState(false); const [error, setError] = useState(''); const navigate = useNavigate(); const { register, loading } = useAuthStore(); const isPaidPlan = selectedPlan && parseFloat(String(selectedPlan.price || 0)) > 0; // Update URL when plan changes useEffect(() => { if (selectedPlan) { const url = new URL(window.location.href); url.searchParams.set('plan', selectedPlan.slug); window.history.replaceState({}, '', url.toString()); } }, [selectedPlan]); // Load payment methods for paid plans useEffect(() => { if (!isPaidPlan) { setPaymentMethods([]); return; } const loadPaymentMethods = async () => { setPaymentMethodsLoading(true); try { const API_BASE_URL = import.meta.env.VITE_BACKEND_URL || 'https://api.igny8.com/api'; const country = formData.billingCountry || 'US'; const response = await fetch(`${API_BASE_URL}/v1/billing/payment-configs/payment-methods/?country=${country}`); if (!response.ok) { throw new Error('Failed to load payment methods'); } const data = await response.json(); let methodsList: PaymentMethodConfig[] = []; if (Array.isArray(data)) { methodsList = data; } else if (data.success && data.data) { methodsList = Array.isArray(data.data) ? data.data : data.data.results || []; } else if (data.results) { methodsList = data.results; } const enabledMethods = methodsList.filter((m: PaymentMethodConfig) => m.is_enabled); setPaymentMethods(enabledMethods); if (enabledMethods.length > 0 && !selectedPaymentMethod) { setSelectedPaymentMethod(enabledMethods[0].payment_method); } } catch (err: any) { console.error('Failed to load payment methods:', err); // Don't set error for free plans or if payment methods fail to load // Just log it and continue } finally { setPaymentMethodsLoading(false); } }; loadPaymentMethods(); }, [isPaidPlan, formData.billingCountry]); const handleChange = (e: React.ChangeEvent) => { const { name, value } = e.target; setFormData((prev) => ({ ...prev, [name]: value })); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(''); if (!formData.email || !formData.password || !formData.firstName || !formData.lastName) { setError('Please fill in all required fields'); return; } if (!isChecked) { setError('Please agree to the Terms and Conditions'); return; } if (!selectedPlan) { setError('Please select a plan'); return; } if (isPaidPlan && !selectedPaymentMethod) { setError('Please select a payment method'); return; } try { const username = formData.email.split('@')[0]; const registerPayload: any = { email: formData.email, password: formData.password, username: username, first_name: formData.firstName, last_name: formData.lastName, account_name: formData.accountName, plan_slug: selectedPlan.slug, }; if (isPaidPlan) { registerPayload.payment_method = selectedPaymentMethod; registerPayload.billing_email = formData.email; registerPayload.billing_country = formData.billingCountry; } const user = (await register(registerPayload)) as any; // CRITICAL: Verify auth state is actually set in Zustand store // The register function should have already set isAuthenticated=true const currentAuthState = useAuthStore.getState(); console.log('Post-registration auth state check:', { isAuthenticated: currentAuthState.isAuthenticated, hasUser: !!currentAuthState.user, hasToken: !!currentAuthState.token, userData: user }); // If for some reason state wasn't set, force set it again if (!currentAuthState.isAuthenticated || !currentAuthState.user || !currentAuthState.token) { console.error('Auth state not properly set after registration, forcing update...'); // Extract tokens from user data if available const tokenData = user?.tokens || {}; const accessToken = user?.access || tokenData.access || localStorage.getItem('access_token'); const refreshToken = user?.refresh || tokenData.refresh || localStorage.getItem('refresh_token'); // Force set the state useAuthStore.setState({ user: user, token: accessToken, refreshToken: refreshToken, isAuthenticated: true, loading: false }); // Wait a bit for state to propagate await new Promise((resolve) => setTimeout(resolve, 500)); } // Final verification before navigation const finalState = useAuthStore.getState(); if (!finalState.isAuthenticated) { throw new Error('Failed to authenticate after registration. Please try logging in manually.'); } const status = user?.account?.status; if (status === 'pending_payment') { navigate('/account/plans', { replace: true }); } else { navigate('/sites', { replace: true }); } } catch (err: any) { setError(err.message || 'Registration failed. Please try again.'); } }; const getPaymentIcon = (method: string) => { switch (method) { case 'stripe': return ; case 'bank_transfer': return ; case 'local_wallet': return ; default: return ; } }; const formatNumber = (num: number): string => { if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`; if (num >= 1000) return `${(num / 1000).toFixed(0)}K`; return num.toString(); }; const extractFeatures = (plan: Plan): string[] => { // Use features from plan's JSON field if available, otherwise build from limits if (plan.features && plan.features.length > 0) { return plan.features; } // Fallback to building from plan limits const features: string[] = []; features.push(`${plan.max_sites} ${plan.max_sites === 1 ? 'Site' : 'Sites'}`); features.push(`${plan.max_users} ${plan.max_users === 1 ? 'User' : 'Users'}`); features.push(`${formatNumber(plan.max_keywords || 0)} Keywords`); features.push(`${formatNumber(plan.monthly_word_count_limit || 0)} Words/Month`); features.push(`${formatNumber(plan.included_credits || 0)} AI Credits`); return features; }; const getDisplayPrice = (plan: Plan): number => { const monthlyPrice = typeof plan.price === 'number' ? plan.price : parseFloat(String(plan.price || 0)); if (billingPeriod === 'annually') { return monthlyPrice * 12 * 0.85; // 15% discount } return monthlyPrice; }; return (
{/* Mobile Pricing Toggle */}
Save 15%
Back to dashboard

Sign Up for {selectedPlan?.name || 'IGNY8'}

Complete your registration and select a payment method.

{/* Plan Selection - Mobile */}
{plans.map((plan) => { const displayPrice = getDisplayPrice(plan); const isSelected = selectedPlan?.id === plan.id; const isFree = parseFloat(String(plan.price || 0)) === 0; return ( ); })}
{error && (
{error}
)}
setShowPassword(!showPassword)} className="absolute z-30 -translate-y-1/2 cursor-pointer right-4 top-1/2"> {showPassword ? : }
{isPaidPlan && (
setFormData((prev) => ({ ...prev, billingCountry: value }))} className="text-base" />

Payment methods filtered by country

{paymentMethodsLoading ? (
) : paymentMethods.length === 0 ? (

No payment methods available

) : ( ({ value: m.payment_method, label: m.display_name }))} value={selectedPaymentMethod} onChange={(value) => setSelectedPaymentMethod(value)} className="text-base" /> )}

How you'd like to pay

{/* Payment Method Details - Full Width Below */} {selectedPaymentMethod && paymentMethods.length > 0 && (
{paymentMethods.filter(m => m.payment_method === selectedPaymentMethod).map((method) => ( method.instructions && (
{getPaymentIcon(method.payment_method)}

{method.display_name}

{method.instructions}

) ))}
)}
)}

By creating an account means you agree to the Terms and Conditions, and our{' '} Privacy Policy

Already have an account?{' '} Sign In

{/* Desktop Pricing Panel - Renders in right side */}
{/* This will be portaled to the right side */} {typeof document !== 'undefined' && document.getElementById('signup-pricing-plans') && ReactDOM.createPortal(
{/* Billing Toggle - Improved UI */}

Save 15% with annual billing

{/* Plan Cards - 2 columns, wider cards, no buttons */}
{plans.map((plan) => { const displayPrice = getDisplayPrice(plan); const features = extractFeatures(plan); const isSelected = selectedPlan?.id === plan.id; const isFree = parseFloat(String(plan.price || 0)) === 0; const isPopular = plan.slug.toLowerCase().includes('growth'); return (
onPlanSelect(plan)} className={`relative rounded-2xl p-6 cursor-pointer transition-all duration-300 border-2 ${ isSelected ? 'border-brand-500 bg-white dark:bg-gray-800 shadow-2xl ring-4 ring-brand-500/20' : isPopular ? 'border-brand-200 dark:border-brand-800 bg-white dark:bg-gray-800/50 hover:shadow-xl' : 'border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800/50 hover:shadow-lg' }`} > {isPopular && !isSelected && (
⭐ POPULAR
)} {isSelected && (
)}

{plan.name}

{isFree ? 'Free' : `$${displayPrice.toFixed(2)}`}
{!isFree && ( {billingPeriod === 'annually' ? '/year' : '/month'} )}
{billingPeriod === 'annually' && !isFree && (

${(displayPrice / 12).toFixed(2)}/month billed annually

)}
{/* Features - All features in 2 columns */}
{features.map((feature, idx) => (
{feature}
))}
); })}
, document.getElementById('signup-pricing-plans')! )}
); }