import React, { useState, useEffect, useRef } from 'react'; import PaymentModal from '../components/PaymentModal'; import SuccessDialog from '../components/SuccessDialog'; import { useAuthStore } from '../stores/authStore'; import { useNavigate } from 'react-router-dom'; import { useSEO } from '../hooks/useSEO'; import { CONFIG, formatPriceWithCurrency } from '../utils/config'; const Subscription: React.FC = () => { const [loading, setLoading] = useState(true); const { userData, isAuthenticated } = useAuthStore(); const navigate = useNavigate(); // SEO optimization for Subscription page useSEO({ title: 'Buy Tokens - AiFigure Premium | Unlimited AI Action Figure Generation', description: 'Purchase tokens to unlock unlimited AI action figure generation. Create as many custom figurines as you want with premium features. Fast, high-quality AI art generation for collectors and artists.', keywords: 'buy tokens AiFigure, premium AI generator, unlimited action figures, AI art tokens, custom figurine generation, premium AI collectibles, high-quality AI images', ogTitle: 'Buy Tokens - AiFigure Premium | Unlimited AI Action Figure Generation', ogDescription: 'Purchase tokens to unlock unlimited AI action figure generation. Create as many custom figurines as you want with premium features.', ogImage: 'https://aifigure.com/subscription-og-image.jpg', ogUrl: window.location.href, twitterTitle: 'Buy Tokens - AiFigure Premium | Unlimited AI Action Figure Generation', twitterDescription: 'Purchase tokens to unlock unlimited AI action figure generation. Create as many custom figurines as you want with premium features.', twitterImage: 'https://aifigure.com/subscription-og-image.jpg', canonical: window.location.href, type: 'website', }); const [paymentModal, setPaymentModal] = useState<{ isOpen: boolean; amount: number; // cents packageId: 'starter' | 'popular' | 'party'; title: string; description?: string; }>({ isOpen: false, amount: 0, packageId: 'starter', title: '', description: '' }); const [successDialog, setSuccessDialog] = useState<{ isOpen: boolean; tokensAdded: number; amount: number; }>({ isOpen: false, tokensAdded: 0, amount: 0 }); // Track token balance around purchases to show correct tokensAdded after webhook credit const [lastTokensBeforePurchase, setLastTokensBeforePurchase] = useState(null); const [purchaseInFlight, setPurchaseInFlight] = useState(false); const [paymentInProgress, setPaymentInProgress] = useState(false); // Ref to manage webhook timeout const webhookTimeoutRef = useRef(null); useEffect(() => { if (!isAuthenticated) { navigate('/auth'); return; } // User data is now managed centrally by the auth store if (userData) { setLoading(false); // Handle purchase completion - show success dialog when tokens increase const currentTokens = (userData as any).tokens ?? 0; console.log('🔍 Checking for token increase:', { purchaseInFlight, lastTokensBeforePurchase, currentTokens, difference: currentTokens - (lastTokensBeforePurchase || 0) }); if (purchaseInFlight && lastTokensBeforePurchase !== null && currentTokens > lastTokensBeforePurchase) { const added = currentTokens - lastTokensBeforePurchase; console.log('🎉 Token increase detected! Added:', added, 'tokens'); setSuccessDialog({ isOpen: true, tokensAdded: added, amount: paymentModal.amount / 100 }); setPurchaseInFlight(false); setPaymentInProgress(false); // Reset payment progress state setLastTokensBeforePurchase(null); // Clear the timeout since webhook completed successfully if (webhookTimeoutRef.current) { clearTimeout(webhookTimeoutRef.current); webhookTimeoutRef.current = null; } console.log('✅ Success dialog shown, purchase flow completed'); } } }, [isAuthenticated, userData, navigate, purchaseInFlight, lastTokensBeforePurchase, paymentModal.amount]); const handleTokenPurchase = (pkg: 'starter' | 'popular' | 'party') => { // Prevent multiple payment modal openings if (paymentInProgress || paymentModal.isOpen) { console.log('⚠️ Payment already in progress, ignoring click'); return; } const conf = CONFIG.pricing[pkg]; console.log(`🛒 Starting purchase for ${pkg} package: ${conf.tokens} tokens`); // Remember current token balance before payment starts setLastTokensBeforePurchase((userData && (userData as any).tokens) ?? 0); setPaymentInProgress(true); setPaymentModal({ isOpen: true, amount: conf.amount, packageId: pkg, title: `Buy ${conf.tokens} Tokens`, description: `Purchase ${conf.tokens} tokens for ${formatPriceWithCurrency(conf.amount)}` }); }; const handlePaymentSuccess = async (_amount?: number) => { console.log('💳 Payment success callback triggered, amount:', _amount); // Payment succeeded; tokens will be granted by Stripe webhook shortly. setPaymentModal(prev => ({ ...prev, isOpen: false })); setPurchaseInFlight(true); console.log('🔄 Set purchaseInFlight to true, waiting for webhook...'); // Safety timeout: if webhook doesn't complete within 30 seconds, stop loading webhookTimeoutRef.current = setTimeout(() => { setPurchaseInFlight(false); setPaymentInProgress(false); // Reset payment progress state setLastTokensBeforePurchase(null); console.log('⏰ Webhook timeout - cleared loading state'); // Could show a message that tokens might take longer to appear }, 30000); // 30 seconds timeout }; const handlePaymentError = (error: string) => { console.error('Payment error:', error); // Reset loading state on error setPurchaseInFlight(false); setPaymentInProgress(false); // Reset payment progress state setLastTokensBeforePurchase(null); // Clear any pending timeout if (webhookTimeoutRef.current) { clearTimeout(webhookTimeoutRef.current); webhookTimeoutRef.current = null; } // You can show a toast notification or alert here }; if (loading) { return (
Loading subscription...
); } // const currentTier = tiers.find(t => t.id === userData.subscriptionTier) || tiers[0]; return (

Buy Tokens

Unlock more tokens to create amazing action figures

{/* Current Plan */} {/*

Current Plan

You're currently on the {currentTier.name} plan

{userData.tokens}
tokens remaining
*/} {/* Subscription Tiers */} {/*
{tiers.map((tier) => (
{tier.popular && (
Most Popular
)}

{tier.name}

${tier.price} /month
{tier.tokens} tokens
    {tier.features.map((feature, index) => (
  • {feature}
  • ))}
{tier.id === userData.subscriptionTier ? ( ) : ( )}
))}
*/} {/* Token Purchase */}
STARTER
{CONFIG.pricing.starter.tokens} Tokens
Good for {Math.floor(CONFIG.pricing.starter.tokens / CONFIG.tokenCost.generation)} images
{formatPriceWithCurrency(CONFIG.pricing.starter.amount)}
POPULAR
{CONFIG.pricing.popular.tokens} Tokens
Good for {Math.floor(CONFIG.pricing.popular.tokens / CONFIG.tokenCost.generation)} images
{formatPriceWithCurrency(CONFIG.pricing.popular.amount)}
PARTY PACK
{CONFIG.pricing.party.tokens} Tokens
Good for {Math.floor(CONFIG.pricing.party.tokens / CONFIG.tokenCost.generation)} images
{formatPriceWithCurrency(CONFIG.pricing.party.amount)}
{/* Payment Modal */} setPaymentModal(prev => ({ ...prev, isOpen: false }))} amount={paymentModal.amount} packageId={paymentModal.packageId} title={paymentModal.title} description={paymentModal.description} onSuccess={(amount) => handlePaymentSuccess(amount)} onError={handlePaymentError} /> {/* Payment Processing Overlay */} {purchaseInFlight && (

Processing Payment

Your payment was successful! We're adding tokens to your account...

This usually takes 5-10 seconds
)} {/* Success Dialog */} setSuccessDialog(prev => ({ ...prev, isOpen: false }))} tokensAdded={successDialog.tokensAdded} amount={successDialog.amount} />
); }; export default Subscription;