import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { useAuth } from '../context/AuthContext'; import api from '../utils/api'; import { Card } from '../components/ui/card'; import { Button } from '../components/ui/button'; import { Input } from '../components/ui/input'; import { Label } from '../components/ui/label'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '../components/ui/dialog'; import Navbar from '../components/Navbar'; import { CheckCircle, CreditCard, Loader2, Heart } from 'lucide-react'; import { toast } from 'sonner'; const Plans = () => { const { user } = useAuth(); const navigate = useNavigate(); const [plans, setPlans] = useState([]); const [loading, setLoading] = useState(true); const [processingPlanId, setProcessingPlanId] = useState(null); // Amount selection dialog state const [amountDialogOpen, setAmountDialogOpen] = useState(false); const [selectedPlan, setSelectedPlan] = useState(null); const [amountInput, setAmountInput] = useState(''); useEffect(() => { fetchPlans(); }, []); const fetchPlans = async () => { try { const response = await api.get('/subscriptions/plans'); setPlans(response.data); } catch (error) { console.error('Failed to fetch plans:', error); toast.error('Failed to load subscription plans'); } finally { setLoading(false); } }; const handleSelectPlan = (plan) => { if (!user) { navigate('/login'); return; } setSelectedPlan(plan); // Pre-fill with suggested price or minimum price const suggestedAmount = (plan.suggested_price_cents || plan.minimum_price_cents) / 100; setAmountInput(suggestedAmount.toFixed(2)); setAmountDialogOpen(true); }; const handleCheckout = async () => { const amountCents = Math.round(parseFloat(amountInput) * 100); const minimumCents = selectedPlan.minimum_price_cents || 3000; // Validate amount if (!amountInput || isNaN(amountCents) || amountCents < minimumCents) { toast.error(`Amount must be at least $${(minimumCents / 100).toFixed(2)}`); return; } // Check if plan allows donations const donationCents = amountCents - minimumCents; if (donationCents > 0 && !selectedPlan.allow_donation) { toast.error('This plan does not accept donations above the minimum price'); return; } setProcessingPlanId(selectedPlan.id); setAmountDialogOpen(false); try { const response = await api.post('/subscriptions/checkout', { plan_id: selectedPlan.id, amount_cents: amountCents }); // Redirect to Stripe Checkout window.location.href = response.data.checkout_url; } catch (error) { console.error('Failed to create checkout session:', error); toast.error(error.response?.data?.detail || 'Failed to start checkout process'); setProcessingPlanId(null); } }; const formatPrice = (cents) => { return `$${(cents / 100).toFixed(2)}`; }; const getBillingCycleLabel = (billingCycle) => { const labels = { yearly: 'per year', monthly: 'per month', quarterly: 'per quarter', lifetime: 'one-time', custom: 'custom period' }; return labels[billingCycle] || billingCycle; }; // Calculate donation breakdown const getAmountBreakdown = () => { if (!selectedPlan || !amountInput) return null; const totalCents = Math.round(parseFloat(amountInput) * 100); const minimumCents = selectedPlan.minimum_price_cents || 3000; const donationCents = Math.max(0, totalCents - minimumCents); return { total: totalCents, base: minimumCents, donation: donationCents }; }; const breakdown = getAmountBreakdown(); return (
{/* Header */}

Membership Plans

Choose the membership plan that works best for you and become part of our vibrant community.

{loading ? (

Loading plans...

) : plans.length > 0 ? (
{plans.map((plan) => { const minimumPrice = plan.minimum_price_cents || plan.price_cents || 3000; const suggestedPrice = plan.suggested_price_cents || minimumPrice; return ( {/* Plan Header */}

{plan.name}

{plan.description && (

{plan.description}

)}
{/* Pricing */}
Starting at
{formatPrice(minimumPrice)}
{suggestedPrice > minimumPrice && (
Suggested: {formatPrice(suggestedPrice)}
)}

{getBillingCycleLabel(plan.billing_cycle)}

{plan.allow_donation && (
Donations welcome
)}
{/* Features */}
Access to all member events
Community directory access
Exclusive member benefits
Newsletter subscription
{/* CTA Button */}
); })}
) : (

No Plans Available

Membership plans are not currently available. Please check back later!

)} {/* Info Section */}

Need Help Choosing?

If you have any questions about our membership plans or need assistance, please contact us.

{/* Amount Selection Dialog */} Choose Your Amount {selectedPlan?.name} - {getBillingCycleLabel(selectedPlan?.billing_cycle)}
{/* Amount Input */}
$ setAmountInput(e.target.value)} className="pl-8 h-14 text-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]" placeholder="50.00" />

Minimum: {selectedPlan ? formatPrice(selectedPlan.minimum_price_cents || 3000) : '$30.00'}

{/* Breakdown Display */} {breakdown && breakdown.total >= breakdown.base && (
Membership Fee: {formatPrice(breakdown.base)}
{breakdown.donation > 0 && (
Additional Donation: {formatPrice(breakdown.donation)}
)}
Total: {formatPrice(breakdown.total)}
)} {/* Donation Message */} {selectedPlan?.allow_donation && (

Thank you for supporting our community!
Your donation helps us continue our mission and provide meaningful experiences for all members.

)}
); }; export default Plans;