import React, { useState, useEffect, useCallback } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, ActivityIndicator, Alert, } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { router, useLocalSearchParams } from 'expo-router'; import { Ionicons } from '@expo/vector-icons'; import { usePaymentSheet } from '@stripe/stripe-react-native'; import { AppColors, Spacing, BorderRadius, FontSizes, FontWeights, Shadows } from '@/constants/theme'; import { useAuth } from '@/contexts/AuthContext'; import { api } from '@/services/api'; import { LoadingSpinner } from '@/components/ui/LoadingSpinner'; import { hasBeneficiaryDevices } from '@/services/BeneficiaryDetailController'; const STRIPE_API_URL = 'https://wellnuo.smartlaunchhub.com/api/stripe'; const STARTER_KIT = { name: 'WellNuo Starter Kit', price: '$399', priceValue: 399, }; export default function PurchaseScreen() { const params = useLocalSearchParams<{ lovedOneName?: string; beneficiaryId?: string }>(); const lovedOneName = params.lovedOneName || ''; const beneficiaryId = params.beneficiaryId; const [isProcessing, setIsProcessing] = useState(false); const [isLoading, setIsLoading] = useState(true); const [step, setStep] = useState<'purchase' | 'order_placed'>('purchase'); const { user } = useAuth(); const { initPaymentSheet, presentPaymentSheet } = usePaymentSheet(); // Check if equipment is already ordered - redirect to equipment-status const checkEquipmentStatus = useCallback(async () => { if (!beneficiaryId) { setIsLoading(false); return; } try { const response = await api.getWellNuoBeneficiary(parseInt(beneficiaryId, 10)); if (response.ok && response.data) { // If user already has devices - go to main screen if (hasBeneficiaryDevices(response.data)) { router.replace(`/(tabs)/beneficiaries/${beneficiaryId}`); return; } // If equipment is ordered/shipped/delivered - go to equipment-status const status = response.data.equipmentStatus; if (status && ['ordered', 'shipped', 'delivered'].includes(status)) { router.replace(`/(tabs)/beneficiaries/${beneficiaryId}/equipment-status`); return; } } } catch (error) { // Failed to check equipment status } setIsLoading(false); }, [beneficiaryId]); useEffect(() => { checkEquipmentStatus(); }, [checkEquipmentStatus]); const handlePurchase = async () => { setIsProcessing(true); try { const userId = user?.user_id; if (!userId) { Alert.alert('Error', 'User not authenticated. Please log in again.'); setIsProcessing(false); return; } if (!beneficiaryId) { Alert.alert('Error', 'Beneficiary not found. Please try again.'); setIsProcessing(false); return; } const token = await api.getToken(); if (!token) { Alert.alert('Error', 'Please log in again'); setIsProcessing(false); return; } const response = await fetch(`${STRIPE_API_URL}/create-payment-sheet`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify({ email: user?.email, amount: STARTER_KIT.priceValue * 100, metadata: { userId: String(userId), beneficiaryId: String(beneficiaryId), beneficiaryName: lovedOneName || 'To be configured', orderType: 'starter_kit', }, }), }); const data = await response.json(); if (!data.paymentIntent) { throw new Error(data.error || 'Failed to create 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); } const { error: presentError } = await presentPaymentSheet(); if (presentError) { if (presentError.code === 'Canceled') { setIsProcessing(false); return; } throw new Error(presentError.message); } await api.updateBeneficiaryEquipmentStatus( parseInt(beneficiaryId, 10), 'ordered' ); await api.setOnboardingCompleted(true); // Redirect directly to equipment-status page (skip order_placed screen) router.replace(`/(tabs)/beneficiaries/${beneficiaryId}/equipment-status`); } catch (error) { Alert.alert( 'Payment Failed', error instanceof Error ? error.message : 'Something went wrong. Please try again.' ); } setIsProcessing(false); }; const handleAlreadyHaveSensors = () => { router.replace({ pathname: '/(auth)/activate', params: { beneficiaryId, lovedOneName }, }); }; const handleGoToEquipmentStatus = () => { if (beneficiaryId) { router.replace(`/(tabs)/beneficiaries/${beneficiaryId}/equipment-status`); } else { router.replace('/(tabs)'); } }; // Loading state - checking equipment status if (isLoading) { return ; } // Order Placed Screen if (step === 'order_placed') { return ( Order Placed! Thank you for your purchase Item {STARTER_KIT.name} For {lovedOneName || 'Your loved one'} Total {STARTER_KIT.price} Track My Order ); } return ( {/* Header */} router.canGoBack() ? router.back() : router.replace('/(tabs)')} > Get Started {/* Product Card */} {STARTER_KIT.name} {STARTER_KIT.price} 5 smart sensors that easily plug into any outlet and set up through the app in minutes {/* Security Badge */} Secure payment powered by Stripe {/* Bottom Actions */} {isProcessing ? ( ) : ( <> Buy Now )} I already have sensors ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: AppColors.background, }, content: { flex: 1, padding: Spacing.lg, justifyContent: 'space-between', }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, backButton: { padding: Spacing.sm, marginLeft: -Spacing.sm, }, title: { fontSize: FontSizes.xl, fontWeight: FontWeights.bold, color: AppColors.textPrimary, }, placeholder: { width: 40, }, productCard: { backgroundColor: AppColors.white, borderRadius: BorderRadius.xl, padding: Spacing.xl, alignItems: 'center', borderWidth: 2, borderColor: AppColors.primary, ...Shadows.md, }, productIcon: { width: 80, height: 80, borderRadius: 40, backgroundColor: `${AppColors.primary}15`, alignItems: 'center', justifyContent: 'center', marginBottom: Spacing.lg, }, productName: { fontSize: FontSizes.xl, fontWeight: FontWeights.bold, color: AppColors.textPrimary, textAlign: 'center', marginBottom: Spacing.xs, }, productPrice: { fontSize: FontSizes['3xl'], fontWeight: FontWeights.bold, color: AppColors.primary, marginBottom: Spacing.lg, }, productDescription: { fontSize: FontSizes.base, color: AppColors.textSecondary, textAlign: 'center', lineHeight: 22, marginBottom: Spacing.lg, }, securityBadge: { flexDirection: 'row', alignItems: 'center', gap: Spacing.xs, paddingVertical: Spacing.sm, paddingHorizontal: Spacing.md, backgroundColor: `${AppColors.success}10`, borderRadius: BorderRadius.lg, }, securityText: { fontSize: FontSizes.sm, color: AppColors.success, }, bottomActions: { gap: Spacing.md, }, purchaseButton: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: Spacing.sm, backgroundColor: AppColors.primary, paddingVertical: Spacing.lg, borderRadius: BorderRadius.lg, ...Shadows.primary, }, buttonDisabled: { opacity: 0.7, }, purchaseButtonText: { fontSize: FontSizes.lg, fontWeight: FontWeights.semibold, color: AppColors.white, }, skipButton: { alignItems: 'center', paddingVertical: Spacing.sm, }, skipButtonText: { fontSize: FontSizes.base, color: AppColors.textSecondary, textDecorationLine: 'underline', }, // Order Placed Screen orderPlacedContainer: { flex: 1, padding: Spacing.lg, alignItems: 'center', justifyContent: 'center', }, successIcon: { width: 100, height: 100, borderRadius: 50, backgroundColor: AppColors.success, alignItems: 'center', justifyContent: 'center', marginBottom: Spacing.xl, ...Shadows.lg, }, orderPlacedTitle: { fontSize: FontSizes['2xl'], fontWeight: FontWeights.bold, color: AppColors.textPrimary, marginBottom: Spacing.xs, }, orderPlacedSubtitle: { fontSize: FontSizes.base, color: AppColors.textSecondary, marginBottom: Spacing.xl, }, orderInfoCard: { width: '100%', backgroundColor: AppColors.surface, borderRadius: BorderRadius.lg, padding: Spacing.lg, marginBottom: Spacing.xl, ...Shadows.sm, }, orderInfoRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: Spacing.sm, borderBottomWidth: 1, borderBottomColor: AppColors.border, }, orderInfoLabel: { fontSize: FontSizes.sm, color: AppColors.textSecondary, }, orderInfoValue: { fontSize: FontSizes.base, fontWeight: FontWeights.medium, color: AppColors.textPrimary, }, orderInfoPrice: { color: AppColors.primary, fontWeight: FontWeights.bold, }, primaryButton: { width: '100%', backgroundColor: AppColors.primary, paddingVertical: Spacing.lg, borderRadius: BorderRadius.lg, alignItems: 'center', ...Shadows.primary, }, primaryButtonText: { fontSize: FontSizes.base, fontWeight: FontWeights.semibold, color: AppColors.white, }, });