- Restructured profile screens location - Updated beneficiary detail page - Updated API service - Updated all scheme files (MainScheme, ENV API, Discussion, AppStore, SysAnal) - Added PageHeader component 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
520 lines
16 KiB
TypeScript
520 lines
16 KiB
TypeScript
import React, { useState } from 'react';
|
|
import {
|
|
View,
|
|
Text,
|
|
StyleSheet,
|
|
ScrollView,
|
|
TouchableOpacity,
|
|
Alert,
|
|
} from 'react-native';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
import { router } from 'expo-router';
|
|
import { AppColors, BorderRadius, FontSizes, Spacing } from '@/constants/theme';
|
|
import { PageHeader } from '@/components/PageHeader';
|
|
|
|
interface PlanFeatureProps {
|
|
text: string;
|
|
included: boolean;
|
|
}
|
|
|
|
function PlanFeature({ text, included }: PlanFeatureProps) {
|
|
return (
|
|
<View style={styles.featureRow}>
|
|
<Ionicons
|
|
name={included ? 'checkmark-circle' : 'close-circle'}
|
|
size={20}
|
|
color={included ? AppColors.success : AppColors.textMuted}
|
|
/>
|
|
<Text style={[styles.featureText, !included && styles.featureTextDisabled]}>
|
|
{text}
|
|
</Text>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
export default function SubscriptionScreen() {
|
|
const [selectedPlan, setSelectedPlan] = useState<'monthly' | 'yearly'>('yearly');
|
|
const currentPlan = 'free'; // Could be 'free', 'pro', 'enterprise'
|
|
|
|
const handleSubscribe = () => {
|
|
Alert.alert(
|
|
'Subscribe to Pro',
|
|
`You selected the ${selectedPlan === 'yearly' ? 'Yearly' : 'Monthly'} plan.\n\n` +
|
|
`Total: ${selectedPlan === 'yearly' ? '$79.99/year (Save $39.89!)' : '$9.99/month'}`,
|
|
[
|
|
{ text: 'Cancel', style: 'cancel' },
|
|
{
|
|
text: 'Continue to Payment',
|
|
onPress: () => Alert.alert('Coming Soon', 'Payment integration coming soon!')
|
|
},
|
|
]
|
|
);
|
|
};
|
|
|
|
const handleRestorePurchases = () => {
|
|
Alert.alert(
|
|
'Restoring Purchases',
|
|
'Looking for previous purchases...',
|
|
[{ text: 'OK' }]
|
|
);
|
|
|
|
setTimeout(() => {
|
|
Alert.alert('No Purchases Found', 'We couldn\'t find any previous purchases associated with your account.');
|
|
}, 1500);
|
|
};
|
|
|
|
return (
|
|
<SafeAreaView style={styles.container} edges={['top', 'bottom']}>
|
|
<PageHeader title="WellNuo Pro" />
|
|
<ScrollView showsVerticalScrollIndicator={false}>
|
|
{/* Current Plan Badge */}
|
|
<View style={styles.currentPlanBanner}>
|
|
<View style={styles.currentPlanBadge}>
|
|
<Text style={styles.currentPlanBadgeText}>CURRENT PLAN</Text>
|
|
</View>
|
|
<Text style={styles.currentPlanName}>Free</Text>
|
|
<Text style={styles.currentPlanDescription}>
|
|
Basic monitoring features
|
|
</Text>
|
|
</View>
|
|
|
|
{/* Pro Features */}
|
|
<View style={styles.section}>
|
|
<View style={styles.proCard}>
|
|
<View style={styles.proHeader}>
|
|
<View style={styles.proBadge}>
|
|
<Ionicons name="diamond" size={20} color="#9333EA" />
|
|
<Text style={styles.proBadgeText}>PRO</Text>
|
|
</View>
|
|
<Text style={styles.proTitle}>WellNuo Pro</Text>
|
|
<Text style={styles.proSubtitle}>Everything you need for complete care</Text>
|
|
</View>
|
|
|
|
<View style={styles.featuresContainer}>
|
|
<PlanFeature text="Unlimited beneficiaries" included={true} />
|
|
<PlanFeature text="Advanced analytics dashboard" included={true} />
|
|
<PlanFeature text="AI-powered health insights" included={true} />
|
|
<PlanFeature text="Priority 24/7 support" included={true} />
|
|
<PlanFeature text="Custom alert rules" included={true} />
|
|
<PlanFeature text="API access for integrations" included={true} />
|
|
<PlanFeature text="Export data to CSV/PDF" included={true} />
|
|
<PlanFeature text="Multi-location monitoring" included={true} />
|
|
<PlanFeature text="Family sharing (5 members)" included={true} />
|
|
<PlanFeature text="Wellness trend predictions" included={true} />
|
|
</View>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Pricing Options */}
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>Choose Your Plan</Text>
|
|
|
|
<TouchableOpacity
|
|
style={[styles.planOption, selectedPlan === 'yearly' && styles.planOptionSelected]}
|
|
onPress={() => setSelectedPlan('yearly')}
|
|
>
|
|
<View style={styles.planOptionContent}>
|
|
<View style={styles.planOptionHeader}>
|
|
<Text style={styles.planOptionTitle}>Yearly</Text>
|
|
<View style={styles.saveBadge}>
|
|
<Text style={styles.saveBadgeText}>SAVE 33%</Text>
|
|
</View>
|
|
</View>
|
|
<Text style={styles.planOptionPrice}>$79.99/year</Text>
|
|
<Text style={styles.planOptionSubprice}>$6.67/month</Text>
|
|
</View>
|
|
<View style={[
|
|
styles.radioButton,
|
|
selectedPlan === 'yearly' && styles.radioButtonSelected
|
|
]}>
|
|
{selectedPlan === 'yearly' && (
|
|
<View style={styles.radioButtonInner} />
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
|
|
<TouchableOpacity
|
|
style={[styles.planOption, selectedPlan === 'monthly' && styles.planOptionSelected]}
|
|
onPress={() => setSelectedPlan('monthly')}
|
|
>
|
|
<View style={styles.planOptionContent}>
|
|
<Text style={styles.planOptionTitle}>Monthly</Text>
|
|
<Text style={styles.planOptionPrice}>$9.99/month</Text>
|
|
<Text style={styles.planOptionSubprice}>Billed monthly</Text>
|
|
</View>
|
|
<View style={[
|
|
styles.radioButton,
|
|
selectedPlan === 'monthly' && styles.radioButtonSelected
|
|
]}>
|
|
{selectedPlan === 'monthly' && (
|
|
<View style={styles.radioButtonInner} />
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
{/* Compare Plans */}
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>Compare Plans</Text>
|
|
<View style={styles.comparisonCard}>
|
|
<View style={styles.comparisonHeader}>
|
|
<Text style={styles.comparisonFeatureTitle}>Feature</Text>
|
|
<Text style={styles.comparisonPlanTitle}>Free</Text>
|
|
<Text style={styles.comparisonPlanTitle}>Pro</Text>
|
|
</View>
|
|
|
|
{[
|
|
{ feature: 'Beneficiaries', free: '2', pro: 'Unlimited' },
|
|
{ feature: 'Real-time alerts', free: '✓', pro: '✓' },
|
|
{ feature: 'Activity history', free: '7 days', pro: '1 year' },
|
|
{ feature: 'AI insights', free: '—', pro: '✓' },
|
|
{ feature: 'Custom alerts', free: '—', pro: '✓' },
|
|
{ feature: 'Data export', free: '—', pro: '✓' },
|
|
{ feature: 'Support', free: 'Email', pro: '24/7 Priority' },
|
|
].map((row, index) => (
|
|
<View key={index} style={styles.comparisonRow}>
|
|
<Text style={styles.comparisonFeature}>{row.feature}</Text>
|
|
<Text style={styles.comparisonValue}>{row.free}</Text>
|
|
<Text style={[styles.comparisonValue, styles.comparisonValuePro]}>{row.pro}</Text>
|
|
</View>
|
|
))}
|
|
</View>
|
|
</View>
|
|
|
|
{/* Testimonials */}
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>What Users Say</Text>
|
|
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
|
|
{[
|
|
{
|
|
name: 'Sarah M.',
|
|
text: 'WellNuo Pro gives me peace of mind. The AI insights helped detect early warning signs.',
|
|
rating: 5,
|
|
},
|
|
{
|
|
name: 'John D.',
|
|
text: 'The family sharing feature is amazing. Now my siblings can all monitor our parents together.',
|
|
rating: 5,
|
|
},
|
|
{
|
|
name: 'Maria L.',
|
|
text: 'Worth every penny. The advanced analytics helped us understand mom\'s patterns better.',
|
|
rating: 5,
|
|
},
|
|
].map((testimonial, index) => (
|
|
<View key={index} style={styles.testimonialCard}>
|
|
<View style={styles.testimonialStars}>
|
|
{[...Array(testimonial.rating)].map((_, i) => (
|
|
<Ionicons key={i} name="star" size={16} color="#F59E0B" />
|
|
))}
|
|
</View>
|
|
<Text style={styles.testimonialText}>"{testimonial.text}"</Text>
|
|
<Text style={styles.testimonialName}>— {testimonial.name}</Text>
|
|
</View>
|
|
))}
|
|
</ScrollView>
|
|
</View>
|
|
|
|
{/* Restore Purchases */}
|
|
<TouchableOpacity style={styles.restoreButton} onPress={handleRestorePurchases}>
|
|
<Text style={styles.restoreButtonText}>Restore Purchases</Text>
|
|
</TouchableOpacity>
|
|
|
|
{/* Terms */}
|
|
<Text style={styles.termsText}>
|
|
Payment will be charged to your Apple ID account at the confirmation of purchase.
|
|
Subscription automatically renews unless it is cancelled at least 24 hours before
|
|
the end of the current period.
|
|
</Text>
|
|
</ScrollView>
|
|
|
|
{/* Subscribe Button */}
|
|
<View style={styles.footer}>
|
|
<TouchableOpacity style={styles.subscribeButton} onPress={handleSubscribe}>
|
|
<Text style={styles.subscribeButtonText}>
|
|
Subscribe to Pro — {selectedPlan === 'yearly' ? '$79.99/year' : '$9.99/month'}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
<Text style={styles.guaranteeText}>7-day free trial • Cancel anytime</Text>
|
|
</View>
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: AppColors.surface,
|
|
},
|
|
currentPlanBanner: {
|
|
backgroundColor: AppColors.background,
|
|
padding: Spacing.lg,
|
|
alignItems: 'center',
|
|
},
|
|
currentPlanBadge: {
|
|
backgroundColor: '#E0E7FF',
|
|
paddingHorizontal: Spacing.sm,
|
|
paddingVertical: 4,
|
|
borderRadius: BorderRadius.sm,
|
|
},
|
|
currentPlanBadgeText: {
|
|
fontSize: FontSizes.xs,
|
|
fontWeight: '600',
|
|
color: '#4F46E5',
|
|
},
|
|
currentPlanName: {
|
|
fontSize: FontSizes.xl,
|
|
fontWeight: '700',
|
|
color: AppColors.textPrimary,
|
|
marginTop: Spacing.sm,
|
|
},
|
|
currentPlanDescription: {
|
|
fontSize: FontSizes.sm,
|
|
color: AppColors.textSecondary,
|
|
marginTop: 4,
|
|
},
|
|
section: {
|
|
marginTop: Spacing.md,
|
|
},
|
|
sectionTitle: {
|
|
fontSize: FontSizes.sm,
|
|
fontWeight: '600',
|
|
color: AppColors.textSecondary,
|
|
paddingHorizontal: Spacing.lg,
|
|
paddingVertical: Spacing.sm,
|
|
textTransform: 'uppercase',
|
|
},
|
|
proCard: {
|
|
backgroundColor: AppColors.background,
|
|
marginHorizontal: Spacing.lg,
|
|
borderRadius: BorderRadius.lg,
|
|
overflow: 'hidden',
|
|
borderWidth: 2,
|
|
borderColor: '#9333EA',
|
|
},
|
|
proHeader: {
|
|
backgroundColor: '#F3E8FF',
|
|
padding: Spacing.lg,
|
|
alignItems: 'center',
|
|
},
|
|
proBadge: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
backgroundColor: AppColors.white,
|
|
paddingHorizontal: Spacing.md,
|
|
paddingVertical: Spacing.xs,
|
|
borderRadius: BorderRadius.full,
|
|
},
|
|
proBadgeText: {
|
|
fontSize: FontSizes.sm,
|
|
fontWeight: '700',
|
|
color: '#9333EA',
|
|
marginLeft: Spacing.xs,
|
|
},
|
|
proTitle: {
|
|
fontSize: FontSizes.xl,
|
|
fontWeight: '700',
|
|
color: '#9333EA',
|
|
marginTop: Spacing.md,
|
|
},
|
|
proSubtitle: {
|
|
fontSize: FontSizes.sm,
|
|
color: '#7C3AED',
|
|
marginTop: 4,
|
|
},
|
|
featuresContainer: {
|
|
padding: Spacing.lg,
|
|
},
|
|
featureRow: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
paddingVertical: Spacing.xs,
|
|
},
|
|
featureText: {
|
|
fontSize: FontSizes.sm,
|
|
color: AppColors.textPrimary,
|
|
marginLeft: Spacing.sm,
|
|
},
|
|
featureTextDisabled: {
|
|
color: AppColors.textMuted,
|
|
},
|
|
planOption: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
backgroundColor: AppColors.background,
|
|
marginHorizontal: Spacing.lg,
|
|
marginBottom: Spacing.sm,
|
|
padding: Spacing.md,
|
|
borderRadius: BorderRadius.lg,
|
|
borderWidth: 2,
|
|
borderColor: AppColors.border,
|
|
},
|
|
planOptionSelected: {
|
|
borderColor: AppColors.primary,
|
|
backgroundColor: '#DBEAFE',
|
|
},
|
|
planOptionContent: {
|
|
flex: 1,
|
|
},
|
|
planOptionHeader: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
},
|
|
planOptionTitle: {
|
|
fontSize: FontSizes.lg,
|
|
fontWeight: '600',
|
|
color: AppColors.textPrimary,
|
|
},
|
|
saveBadge: {
|
|
backgroundColor: AppColors.success,
|
|
paddingHorizontal: Spacing.xs,
|
|
paddingVertical: 2,
|
|
borderRadius: BorderRadius.sm,
|
|
marginLeft: Spacing.sm,
|
|
},
|
|
saveBadgeText: {
|
|
fontSize: 10,
|
|
fontWeight: '700',
|
|
color: AppColors.white,
|
|
},
|
|
planOptionPrice: {
|
|
fontSize: FontSizes.xl,
|
|
fontWeight: '700',
|
|
color: AppColors.primary,
|
|
marginTop: 4,
|
|
},
|
|
planOptionSubprice: {
|
|
fontSize: FontSizes.xs,
|
|
color: AppColors.textMuted,
|
|
marginTop: 2,
|
|
},
|
|
radioButton: {
|
|
width: 24,
|
|
height: 24,
|
|
borderRadius: 12,
|
|
borderWidth: 2,
|
|
borderColor: AppColors.border,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
},
|
|
radioButtonSelected: {
|
|
borderColor: AppColors.primary,
|
|
},
|
|
radioButtonInner: {
|
|
width: 12,
|
|
height: 12,
|
|
borderRadius: 6,
|
|
backgroundColor: AppColors.primary,
|
|
},
|
|
comparisonCard: {
|
|
backgroundColor: AppColors.background,
|
|
marginHorizontal: Spacing.lg,
|
|
borderRadius: BorderRadius.lg,
|
|
overflow: 'hidden',
|
|
},
|
|
comparisonHeader: {
|
|
flexDirection: 'row',
|
|
backgroundColor: AppColors.surface,
|
|
paddingVertical: Spacing.sm,
|
|
paddingHorizontal: Spacing.md,
|
|
},
|
|
comparisonFeatureTitle: {
|
|
flex: 2,
|
|
fontSize: FontSizes.xs,
|
|
fontWeight: '600',
|
|
color: AppColors.textSecondary,
|
|
},
|
|
comparisonPlanTitle: {
|
|
flex: 1,
|
|
fontSize: FontSizes.xs,
|
|
fontWeight: '600',
|
|
color: AppColors.textSecondary,
|
|
textAlign: 'center',
|
|
},
|
|
comparisonRow: {
|
|
flexDirection: 'row',
|
|
paddingVertical: Spacing.sm,
|
|
paddingHorizontal: Spacing.md,
|
|
borderBottomWidth: 1,
|
|
borderBottomColor: AppColors.border,
|
|
},
|
|
comparisonFeature: {
|
|
flex: 2,
|
|
fontSize: FontSizes.sm,
|
|
color: AppColors.textPrimary,
|
|
},
|
|
comparisonValue: {
|
|
flex: 1,
|
|
fontSize: FontSizes.sm,
|
|
color: AppColors.textSecondary,
|
|
textAlign: 'center',
|
|
},
|
|
comparisonValuePro: {
|
|
color: '#9333EA',
|
|
fontWeight: '500',
|
|
},
|
|
testimonialCard: {
|
|
width: 280,
|
|
backgroundColor: AppColors.background,
|
|
marginLeft: Spacing.lg,
|
|
padding: Spacing.md,
|
|
borderRadius: BorderRadius.lg,
|
|
},
|
|
testimonialStars: {
|
|
flexDirection: 'row',
|
|
marginBottom: Spacing.sm,
|
|
},
|
|
testimonialText: {
|
|
fontSize: FontSizes.sm,
|
|
color: AppColors.textPrimary,
|
|
fontStyle: 'italic',
|
|
lineHeight: 20,
|
|
},
|
|
testimonialName: {
|
|
fontSize: FontSizes.xs,
|
|
color: AppColors.textMuted,
|
|
marginTop: Spacing.sm,
|
|
},
|
|
restoreButton: {
|
|
alignItems: 'center',
|
|
paddingVertical: Spacing.md,
|
|
marginTop: Spacing.md,
|
|
},
|
|
restoreButtonText: {
|
|
fontSize: FontSizes.sm,
|
|
color: AppColors.primary,
|
|
},
|
|
termsText: {
|
|
fontSize: FontSizes.xs,
|
|
color: AppColors.textMuted,
|
|
textAlign: 'center',
|
|
paddingHorizontal: Spacing.xl,
|
|
paddingBottom: Spacing.lg,
|
|
lineHeight: 16,
|
|
},
|
|
footer: {
|
|
padding: Spacing.lg,
|
|
backgroundColor: AppColors.background,
|
|
borderTopWidth: 1,
|
|
borderTopColor: AppColors.border,
|
|
},
|
|
subscribeButton: {
|
|
backgroundColor: '#9333EA',
|
|
borderRadius: BorderRadius.lg,
|
|
paddingVertical: Spacing.md,
|
|
alignItems: 'center',
|
|
},
|
|
subscribeButtonText: {
|
|
fontSize: FontSizes.base,
|
|
fontWeight: '600',
|
|
color: AppColors.white,
|
|
},
|
|
guaranteeText: {
|
|
fontSize: FontSizes.xs,
|
|
color: AppColors.textMuted,
|
|
textAlign: 'center',
|
|
marginTop: Spacing.sm,
|
|
},
|
|
});
|