import React, { useState } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, ActivityIndicator, } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { usePaymentSheet } from '@stripe/stripe-react-native'; import { useAuth } from '@/contexts/AuthContext'; import { useBeneficiary } from '@/contexts/BeneficiaryContext'; import { useToast } from '@/components/ui/Toast'; import { AppColors, BorderRadius, FontSizes, FontWeights, Spacing, Shadows } from '@/constants/theme'; import type { Beneficiary, BeneficiarySubscription } from '@/types'; const STRIPE_API_URL = 'https://wellnuo.smartlaunchhub.com/api/stripe'; const SUBSCRIPTION_PRICE = 49; // $49/month interface SubscriptionPaymentProps { beneficiary: Beneficiary; onSuccess?: () => void; compact?: boolean; // For inline use vs full page } export function SubscriptionPayment({ beneficiary, onSuccess, compact = false }: SubscriptionPaymentProps) { const [isProcessing, setIsProcessing] = useState(false); const { initPaymentSheet, presentPaymentSheet } = usePaymentSheet(); const { user } = useAuth(); const { updateLocalBeneficiary } = useBeneficiary(); const toast = useToast(); const isExpired = beneficiary?.subscription?.status === 'expired'; const handleSubscribe = async () => { setIsProcessing(true); try { // 1. Create Payment Sheet on our server const response = await fetch(`${STRIPE_API_URL}/create-payment-sheet`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ email: user?.email || 'guest@wellnuo.com', amount: SUBSCRIPTION_PRICE * 100, // Convert to cents ($49.00) metadata: { type: 'subscription', planType: 'monthly', userId: user?.user_id || 'guest', beneficiaryId: beneficiary.id, beneficiaryName: beneficiary.name, }, }), }); const data = await response.json(); if (!data.paymentIntent) { throw new Error(data.error || 'Failed to create payment sheet'); } // 2. Initialize the Payment Sheet const { error: initError } = await initPaymentSheet({ merchantDisplayName: 'WellNuo', paymentIntentClientSecret: data.paymentIntent, customerId: data.customer, customerEphemeralKeySecret: data.ephemeralKey, defaultBillingDetails: { email: user?.email || '', }, returnURL: 'wellnuo://stripe-redirect', applePay: { merchantCountryCode: 'US', }, googlePay: { merchantCountryCode: 'US', testEnv: true, }, }); if (initError) { throw new Error(initError.message); } // 3. Present the Payment Sheet const { error: presentError } = await presentPaymentSheet(); if (presentError) { if (presentError.code === 'Canceled') { setIsProcessing(false); return; } throw new Error(presentError.message); } // 4. Payment successful! Save subscription to beneficiary const now = new Date(); const endDate = new Date(now); endDate.setMonth(endDate.getMonth() + 1); // 1 month subscription const newSubscription: BeneficiarySubscription = { status: 'active', startDate: now.toISOString(), endDate: endDate.toISOString(), planType: 'monthly', price: SUBSCRIPTION_PRICE, }; await updateLocalBeneficiary(beneficiary.id, { subscription: newSubscription, }); toast.success( 'Subscription Activated!', `Subscription for ${beneficiary.name} is now active.` ); onSuccess?.(); } catch (error) { console.error('Payment error:', error); toast.error( 'Payment Failed', error instanceof Error ? error.message : 'Something went wrong. Please try again.' ); } finally { setIsProcessing(false); } }; const features = [ '24/7 AI wellness monitoring', 'Unlimited Julia AI chat', 'Detailed activity reports', 'Smart alerts & notifications', ]; if (compact) { // Compact version for inline use return ( {isExpired ? 'Subscription Expired' : 'Subscription Required'} ${SUBSCRIPTION_PRICE}/month {isProcessing ? ( ) : ( <> {isExpired ? 'Renew Now' : 'Subscribe Now'} )} ); } // Full version return ( {/* Icon */} {/* Title */} {isExpired ? 'Subscription Expired' : 'Subscription Required'} {isExpired ? `Your subscription for ${beneficiary.name} has expired. Renew now to continue monitoring their wellness.` : `Activate a subscription to view ${beneficiary.name}'s dashboard and wellness data.`} {/* Price Card */} WellNuo Pro Full access to all features ${SUBSCRIPTION_PRICE} /month {features.map((feature, index) => ( {feature} ))} {/* Subscribe Button */} {isProcessing ? ( ) : ( <> {isExpired ? 'Renew Subscription' : 'Subscribe Now'} )} {/* Security Badge */} Secure payment powered by Stripe ); } const styles = StyleSheet.create({ // Full version styles container: { flex: 1, padding: Spacing.xl, alignItems: 'center', justifyContent: 'center', }, iconContainer: { width: 100, height: 100, borderRadius: 50, backgroundColor: AppColors.accentLight, justifyContent: 'center', alignItems: 'center', marginBottom: Spacing.lg, }, title: { fontSize: FontSizes['2xl'], fontWeight: FontWeights.bold, color: AppColors.textPrimary, textAlign: 'center', marginBottom: Spacing.sm, }, subtitle: { fontSize: FontSizes.base, color: AppColors.textSecondary, textAlign: 'center', lineHeight: 24, marginBottom: Spacing.xl, paddingHorizontal: Spacing.md, }, priceCard: { width: '100%', backgroundColor: AppColors.surface, borderRadius: BorderRadius.xl, padding: Spacing.lg, marginBottom: Spacing.xl, ...Shadows.sm, }, priceHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: Spacing.md, }, planName: { fontSize: FontSizes.lg, fontWeight: FontWeights.semibold, color: AppColors.textPrimary, }, planDesc: { fontSize: FontSizes.sm, color: AppColors.textSecondary, marginTop: 2, }, priceBadge: { flexDirection: 'row', alignItems: 'baseline', }, priceAmount: { fontSize: FontSizes['2xl'], fontWeight: FontWeights.bold, color: AppColors.primary, }, priceUnit: { fontSize: FontSizes.sm, color: AppColors.textMuted, marginLeft: 2, }, features: { gap: Spacing.sm, }, featureRow: { flexDirection: 'row', alignItems: 'center', gap: Spacing.sm, }, featureText: { fontSize: FontSizes.sm, color: AppColors.textSecondary, }, subscribeButtonFull: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: Spacing.sm, width: '100%', backgroundColor: AppColors.primary, paddingVertical: Spacing.lg, borderRadius: BorderRadius.lg, ...Shadows.primary, }, subscribeButtonTextFull: { fontSize: FontSizes.lg, fontWeight: FontWeights.semibold, color: AppColors.white, }, securityBadge: { flexDirection: 'row', alignItems: 'center', gap: Spacing.xs, marginTop: Spacing.lg, }, securityText: { fontSize: FontSizes.xs, color: AppColors.success, }, // Compact version styles compactContainer: { backgroundColor: AppColors.surface, borderRadius: BorderRadius.xl, padding: Spacing.lg, ...Shadows.sm, }, compactHeader: { flexDirection: 'row', alignItems: 'center', marginBottom: Spacing.md, }, compactIconContainer: { width: 56, height: 56, borderRadius: 28, backgroundColor: AppColors.accentLight, justifyContent: 'center', alignItems: 'center', marginRight: Spacing.md, }, compactInfo: { flex: 1, }, compactTitle: { fontSize: FontSizes.base, fontWeight: FontWeights.semibold, color: AppColors.textPrimary, }, compactPrice: { fontSize: FontSizes.lg, fontWeight: FontWeights.bold, color: AppColors.primary, marginTop: 2, }, subscribeButton: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: Spacing.sm, backgroundColor: AppColors.primary, paddingVertical: Spacing.md, borderRadius: BorderRadius.lg, }, subscribeButtonText: { fontSize: FontSizes.base, fontWeight: FontWeights.semibold, color: AppColors.white, }, buttonDisabled: { opacity: 0.7, }, });