feat(app): Stitch paywall — single plan card with free-trial toggle

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Timo Knuth
2026-07-06 13:31:37 +02:00
parent b2dbd3e652
commit 30a2537eaa

View File

@@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { View, Text, TouchableOpacity, ScrollView, StyleSheet, Modal, ActivityIndicator, Alert, Linking, BackHandler, ImageBackground, Platform, useWindowDimensions } from 'react-native';
import { View, Text, TouchableOpacity, ScrollView, StyleSheet, Modal, ActivityIndicator, Alert, Linking, BackHandler, ImageBackground, Platform, Switch } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { Ionicons } from '@expo/vector-icons';
import { useRouter, useLocalSearchParams } from 'expo-router';
@@ -175,6 +175,20 @@ const getBillingCopy = (language: Language) => {
autoRenewMonthly: 'Verlängert sich monatlich automatisch. Jederzeit über iOS-Einstellungen kündbar.',
autoRenewYearly: 'Verlängert sich jährlich automatisch. Jederzeit über iOS-Einstellungen kündbar.',
manageInSettings: 'In iOS-Einstellungen verwalten',
paywallEyebrow: 'GreenLens Pro',
paywallHeadline: 'Unbegrenzter Zugriff',
paywallSub: 'Unbegrenzte Scans, Health-Checks und dein persönlicher Pflegeplan.',
planCardTitle: 'GreenLens Pro',
planCardBody: 'Unbegrenzte KI-Scans, Gesundheitsdiagnose, 7-Tage-Rettungspläne, 100 Credits/Monat',
planCardPriceTrial: (price: string) => `7 Tage gratis, dann ${price}/Jahr`,
planCardPriceMonthly: (price: string) => `${price}/Monat`,
trialToggleLabel: 'Gratis-Test aktiviert',
dueTodayTrial: 'Fällig heute — 7 Tage gratis',
dueTodayAmount: '0,00 €',
dueLater: (date: string) => `Fällig am ${date}`,
ctaTrial: 'Gratis testen',
ctaMonthly: 'Jetzt starten',
cancelAnytime: 'Jederzeit kündbar',
};
} else if (language === 'es') {
return {
@@ -249,6 +263,20 @@ const getBillingCopy = (language: Language) => {
autoRenewMonthly: 'Se renueva mensualmente de forma automática. Cancela cuando quieras en Ajustes de iOS.',
autoRenewYearly: 'Se renueva anualmente de forma automática. Cancela cuando quieras en Ajustes de iOS.',
manageInSettings: 'Administrar en Ajustes de iOS',
paywallEyebrow: 'GreenLens Pro',
paywallHeadline: 'Acceso ilimitado',
paywallSub: 'Escaneos ilimitados, chequeos de salud y tu plan de cuidados personal.',
planCardTitle: 'GreenLens Pro',
planCardBody: 'Escaneos IA ilimitados, diagnóstico de salud, planes de rescate de 7 días, 100 créditos/mes',
planCardPriceTrial: (price: string) => `7 días gratis, luego ${price}/año`,
planCardPriceMonthly: (price: string) => `${price}/mes`,
trialToggleLabel: 'Prueba gratis activada',
dueTodayTrial: 'Hoy — 7 días gratis',
dueTodayAmount: '0,00 €',
dueLater: (date: string) => `El ${date}`,
ctaTrial: 'Probar gratis',
ctaMonthly: 'Empezar ahora',
cancelAnytime: 'Cancela cuando quieras',
};
}
return {
@@ -323,6 +351,20 @@ const getBillingCopy = (language: Language) => {
autoRenewMonthly: 'Auto-renews monthly. Cancel anytime in iOS Settings.',
autoRenewYearly: 'Auto-renews annually. Cancel anytime in iOS Settings.',
manageInSettings: 'Manage in iOS Settings',
paywallEyebrow: 'GreenLens Pro',
paywallHeadline: 'Get Unlimited Access',
paywallSub: 'Unlimited scans, health checks and your personal care plan.',
planCardTitle: 'GreenLens Pro',
planCardBody: 'Unlimited AI scans, health diagnosis, 7-day rescue plans, 100 credits/month',
planCardPriceTrial: (price: string) => `Free for 7 days, then ${price}/year`,
planCardPriceMonthly: (price: string) => `${price}/month`,
trialToggleLabel: 'Free Trial Enabled',
dueTodayTrial: 'Due today — 7 days free',
dueTodayAmount: '€0.00',
dueLater: (date: string) => `Due ${date}`,
ctaTrial: 'Try Free',
ctaMonthly: 'Start Now',
cancelAnytime: 'Cancel Anytime',
};
};
@@ -338,8 +380,6 @@ export default function BillingScreen() {
const posthog = useSafeAnalytics();
const copy = getBillingCopy(language);
const isExpoGo = Constants.appOwnership === 'expo';
const { height: windowHeight } = useWindowDimensions();
const compactPaywall = windowHeight < 760;
const [subModalVisible, setSubModalVisible] = useState(false);
const [isUpdating, setIsUpdating] = useState(false);
@@ -407,8 +447,16 @@ export default function BillingScreen() {
};
}, [isExpoGo]);
const trialEnabled = selectedPaywallPlan === 'yearly';
useEffect(() => {
try { posthog.capture('paywall_viewed', { plan_id: planId }); } catch {}
try {
posthog.capture('paywall_viewed', {
plan_id: planId,
context: onboardingContext ? 'onboarding' : 'in_app',
trial_enabled: trialEnabled,
});
} catch {}
if (showPaywallPlans) {
try {
posthog.capture('hard_paywall_viewed', {
@@ -417,18 +465,19 @@ export default function BillingScreen() {
});
} catch {}
}
}, [posthog, planId, session?.serverUserId, showPaywallPlans]);
}, [posthog, planId, session?.serverUserId, showPaywallPlans, onboardingContext, trialEnabled]);
const monthlyPackage = subscriptionPackages.monthly_pro;
const yearlyPackage = subscriptionPackages.yearly_pro;
const monthlyPrice = monthlyPackage?.product.priceString ?? copy.proPlanPrice;
const yearlyPrice = yearlyPackage?.product.priceString ?? copy.proYearlyPlanPrice;
const weeklyDisplayPrice = copy.weeklyPriceFallback;
const yearlyDisplayPrice = copy.yearlyPriceFallback;
const selectedProductId: SubscriptionProductId = selectedPaywallPlan === 'yearly' ? 'yearly_pro' : 'monthly_pro';
const paywallCtaLabel = selectedPaywallPlan === 'yearly' ? copy.startTrial : copy.monthlyCta;
const paywallFooterLabel = selectedPaywallPlan === 'yearly' ? copy.noPaymentToday : copy.monthlyFooter;
const trialEndDate = useMemo(() => {
const date = new Date();
date.setDate(date.getDate() + 7);
const locale = language === 'de' ? 'de-DE' : language === 'es' ? 'es-ES' : 'en-US';
return date.toLocaleDateString(locale, { day: 'numeric', month: 'long' });
}, [language]);
const topupLabels = useMemo(() => ({
topup_small: topupProducts.topup_small ? `${TOPUP_CREDITS_BY_PRODUCT.topup_small} Credits - ${topupProducts.topup_small.priceString}` : copy.topupSmall,
@@ -638,125 +687,89 @@ export default function BillingScreen() {
imageStyle={styles.hardPaywallHeroImage}
resizeMode="cover"
>
<SafeAreaView
style={[styles.hardPaywallSafe, compactPaywall && styles.hardPaywallSafeCompact]}
edges={['top']}
>
<SafeAreaView style={styles.hardPaywallSafe} edges={['top']}>
<View style={styles.heroTopBar}>
<TouchableOpacity onPress={handleBack} style={styles.heroIconButton}>
<Ionicons name="close" size={24} color="#FFFFFF" />
</TouchableOpacity>
<TouchableOpacity onPress={handleRestore} disabled={isUpdating}>
<Text style={styles.heroRestoreText}>{copy.restorePurchases}</Text>
</TouchableOpacity>
</View>
<View style={[styles.scanFrameOverlay, compactPaywall && styles.scanFrameOverlayCompact]}>
<View style={[styles.scanCorner, styles.scanCornerTopLeft]} />
<View style={[styles.scanCorner, styles.scanCornerTopRight]} />
<View style={[styles.scanCorner, styles.scanCornerBottomLeft]} />
<View style={[styles.scanCorner, styles.scanCornerBottomRight]} />
</View>
<View style={[styles.identifiedChip, compactPaywall && styles.identifiedChipCompact]}>
<Ionicons name="leaf-outline" size={17} color="#8FD19E" />
<Text style={styles.identifiedChipText}>{copy.identifiedChip}</Text>
</View>
<View style={[styles.hardPaywallSheet, compactPaywall && styles.hardPaywallSheetCompact]}>
<View style={[styles.sheetHandle, compactPaywall && styles.sheetHandleCompact]} />
<Text style={[styles.hardPaywallTitle, compactPaywall && styles.hardPaywallTitleCompact]}>
{copy.hardPaywallTitle}
</Text>
<Text style={[styles.hardPaywallHint, compactPaywall && styles.hardPaywallHintCompact]}>
{copy.hardPaywallHint}
</Text>
<View style={[styles.hardBenefits, compactPaywall && styles.hardBenefitsCompact]}>
{[
{ icon: 'infinite-outline' as const, title: copy.benefitUnlimitedScans },
{ icon: 'calendar-outline' as const, title: copy.benefitCarePlan },
].map((benefit) => (
<View key={benefit.title} style={[styles.hardBenefitRow, compactPaywall && styles.hardBenefitRowCompact]}>
<View style={[styles.hardBenefitIcon, compactPaywall && styles.hardBenefitIconCompact]}>
<Ionicons name={benefit.icon} size={compactPaywall ? 18 : 20} color="#1F5B34" />
</View>
<Text style={[styles.hardBenefitText, compactPaywall && styles.hardBenefitTextCompact]}>
{benefit.title}
</Text>
</View>
))}
</View>
<View style={styles.hardPlanRow}>
{[
{ id: 'weekly' as PaywallPlanId, name: copy.weeklyPlanName, price: weeklyDisplayPrice },
{ id: 'yearly' as PaywallPlanId, name: copy.yearlyPlanName, price: yearlyDisplayPrice, badge: copy.bestOffer },
].map((plan) => {
const selected = selectedPaywallPlan === plan.id;
return (
<TouchableOpacity
key={plan.id}
style={[
styles.hardPlanCard,
compactPaywall && styles.hardPlanCardCompact,
selected && styles.hardPlanCardSelected,
]}
onPress={() => setSelectedPaywallPlan(plan.id)}
activeOpacity={0.88}
>
<View style={[styles.planRadio, selected && styles.planRadioSelected]}>
{selected ? <Ionicons name="checkmark" size={15} color="#FFFFFF" /> : null}
</View>
<View style={{ flex: 1 }}>
<Text style={[styles.hardPlanName, compactPaywall && styles.hardPlanNameCompact]}>{plan.name}</Text>
<Text style={[styles.hardPlanPrice, compactPaywall && styles.hardPlanPriceCompact]}>{plan.price}</Text>
{plan.badge ? (
<View style={styles.bestOfferBadge}>
<Text style={styles.bestOfferText}>{plan.badge}</Text>
</View>
) : null}
</View>
</TouchableOpacity>
);
})}
</View>
<TouchableOpacity
style={[
styles.hardPaywallCta,
compactPaywall && styles.hardPaywallCtaCompact,
(!storeReady || isUpdating || Boolean(storeError)) && styles.disabledPlanCard,
]}
onPress={() => handlePurchase(selectedProductId)}
disabled={isUpdating || !storeReady || Boolean(storeError)}
activeOpacity={0.9}
<View style={[styles.paywallSheet, { backgroundColor: colors.background }]}>
<ScrollView
contentContainerStyle={styles.paywallBody}
showsVerticalScrollIndicator={false}
>
{isUpdating || !storeReady ? (
<ActivityIndicator color="#FFFFFF" />
) : (
<>
<Text style={[styles.hardPaywallCtaText, compactPaywall && styles.hardPaywallCtaTextCompact]}>
{paywallCtaLabel}
</Text>
<Ionicons name="arrow-forward" size={23} color="#FFFFFF" />
</>
)}
</TouchableOpacity>
<View style={[styles.sheetHandle, { backgroundColor: colors.border }]} />
<Text style={[styles.paywallEyebrow, { color: colors.primary }]}>{copy.paywallEyebrow.toUpperCase()}</Text>
<Text style={[styles.paywallHeadline, { color: colors.text }]}>{copy.paywallHeadline}</Text>
<Text style={[styles.paywallSub, { color: colors.textSecondary }]}>{copy.paywallSub}</Text>
{storeError ? (
<Text style={styles.hardPaywallFooter}>{storeError}</Text>
) : null}
<Text style={styles.hardPaywallFooter}>{paywallFooterLabel}</Text>
<View style={styles.legalLinksRow}>
<TouchableOpacity onPress={() => Linking.openURL('https://greenlenspro.com/privacy')}>
<Text style={[styles.legalLink, { color: '#1F5B34' }]}>Privacy Policy</Text>
<View style={[styles.planCard, { backgroundColor: colors.surfaceMuted }]}>
<Text style={[styles.planCardTitle, { color: colors.text }]}>{copy.planCardTitle}</Text>
<Text style={[styles.planCardBody, { color: colors.textSecondary }]}>{copy.planCardBody}</Text>
<View style={[styles.planCardDivider, { backgroundColor: colors.border }]} />
<Text style={[styles.planCardPrice, { color: colors.text }]}>
{trialEnabled ? copy.planCardPriceTrial(yearlyPrice) : copy.planCardPriceMonthly(monthlyPrice)}
</Text>
</View>
<View style={[styles.trialToggleRow, { backgroundColor: colors.surface, borderColor: colors.border }]}>
<Text style={[styles.trialToggleLabel, { color: colors.text }]}>{copy.trialToggleLabel}</Text>
<Switch
value={trialEnabled}
onValueChange={(next) => setSelectedPaywallPlan(next ? 'yearly' : 'weekly')}
trackColor={{ true: colors.primary, false: colors.border }}
thumbColor="#FFFFFF"
/>
</View>
{trialEnabled ? (
<View style={styles.dueTimeline}>
<View style={styles.dueRow}>
<View style={[styles.dueDot, { backgroundColor: colors.primary }]} />
<Text style={[styles.dueLabel, { color: colors.primary }]}>{copy.dueTodayTrial}</Text>
<Text style={[styles.dueAmount, { color: colors.text }]}>{copy.dueTodayAmount}</Text>
</View>
<View style={[styles.dueLine, { backgroundColor: colors.border }]} />
<View style={styles.dueRow}>
<View style={[styles.dueDot, { backgroundColor: colors.border }]} />
<Text style={[styles.dueLabel, { color: colors.textSecondary }]}>{copy.dueLater(trialEndDate)}</Text>
<Text style={[styles.dueAmount, { color: colors.text }]}>{yearlyPrice}</Text>
</View>
</View>
) : null}
{storeError ? (
<Text style={[styles.paywallFooterText, { color: colors.danger, marginBottom: 8 }]}>{storeError}</Text>
) : null}
<TouchableOpacity
style={[
styles.paywallCta,
{ backgroundColor: colors.primary },
(!storeReady || isUpdating || Boolean(storeError)) && styles.disabledPlanCard,
]}
onPress={() => handlePurchase(trialEnabled ? 'yearly_pro' : 'monthly_pro')}
disabled={isUpdating || !storeReady || Boolean(storeError)}
activeOpacity={0.86}
>
{isUpdating || !storeReady ? (
<ActivityIndicator color={colors.onPrimary} />
) : (
<Text style={[styles.paywallCtaText, { color: colors.onPrimary }]}>
{trialEnabled ? copy.ctaTrial : copy.ctaMonthly}
</Text>
)}
</TouchableOpacity>
<Text style={[styles.legalSep, { color: '#7A8079' }]}> · </Text>
<TouchableOpacity onPress={() => Linking.openURL('https://greenlenspro.com/terms')}>
<Text style={[styles.legalLink, { color: '#1F5B34' }]}>Terms of Use</Text>
</TouchableOpacity>
</View>
<TouchableOpacity style={styles.hardRestoreBtn} onPress={handleRestore} disabled={isUpdating}>
<Text style={styles.hardRestoreText}>{copy.restorePurchases}</Text>
</TouchableOpacity>
<View style={styles.paywallFooter}>
<Text style={[styles.paywallFooterText, { color: colors.textMuted }]}>Privacy | Terms</Text>
<Text style={[styles.paywallFooterText, { color: colors.textMuted }]}>{copy.cancelAnytime}</Text>
</View>
</ScrollView>
</View>
</SafeAreaView>
</ImageBackground>
@@ -1142,10 +1155,6 @@ const styles = StyleSheet.create({
},
hardPaywallSafe: {
flex: 1,
justifyContent: 'space-between',
},
hardPaywallSafeCompact: {
justifyContent: 'flex-end',
},
heroTopBar: {
flexDirection: 'row',
@@ -1170,256 +1179,42 @@ const styles = StyleSheet.create({
textShadowOffset: { width: 0, height: 1 },
textShadowRadius: 3,
},
scanFrameOverlay: {
position: 'absolute',
top: '14%',
left: 54,
right: 54,
height: '28%',
},
scanFrameOverlayCompact: {
display: 'none',
},
scanCorner: {
position: 'absolute',
width: 44,
height: 44,
borderColor: '#FFFFFF',
},
scanCornerTopLeft: {
top: 0,
left: 0,
borderTopWidth: 4,
borderLeftWidth: 4,
borderTopLeftRadius: 18,
},
scanCornerTopRight: {
top: 0,
right: 0,
borderTopWidth: 4,
borderRightWidth: 4,
borderTopRightRadius: 18,
},
scanCornerBottomLeft: {
bottom: 0,
left: 0,
borderBottomWidth: 4,
borderLeftWidth: 4,
borderBottomLeftRadius: 18,
},
scanCornerBottomRight: {
bottom: 0,
right: 0,
borderBottomWidth: 4,
borderRightWidth: 4,
borderBottomRightRadius: 18,
},
identifiedChip: {
position: 'absolute',
alignSelf: 'center',
top: '43%',
zIndex: 4,
flexDirection: 'row',
alignItems: 'center',
gap: 8,
borderRadius: 18,
paddingHorizontal: 16,
paddingVertical: 8,
backgroundColor: '#16351FCC',
},
identifiedChipCompact: {
display: 'none',
},
identifiedChipText: {
color: '#FFFFFF',
fontSize: 15,
fontWeight: '800',
},
hardPaywallSheet: {
backgroundColor: '#FAFAF5',
paywallSheet: {
flex: 1,
borderTopLeftRadius: 30,
borderTopRightRadius: 30,
paddingHorizontal: 20,
paddingTop: 9,
paddingBottom: 18,
overflow: 'hidden',
zIndex: 5,
},
hardPaywallSheetCompact: {
paddingHorizontal: 18,
paddingTop: 8,
paddingBottom: 16,
},
sheetHandle: {
alignSelf: 'center',
width: 42,
height: 5,
borderRadius: 999,
backgroundColor: '#C7C8C3',
marginTop: 10,
marginBottom: 8,
},
sheetHandleCompact: {
marginBottom: 8,
},
hardPaywallTitle: {
color: '#101411',
fontSize: 23,
lineHeight: 28,
fontWeight: '900',
textAlign: 'center',
marginBottom: 5,
},
hardPaywallTitleCompact: {
fontSize: 22,
lineHeight: 26,
},
hardPaywallHint: {
color: '#676C66',
fontSize: 12,
lineHeight: 17,
textAlign: 'center',
marginBottom: 10,
},
hardPaywallHintCompact: {
display: 'none',
},
hardBenefits: {
gap: 5,
marginBottom: 7,
},
hardBenefitsCompact: {
marginBottom: 10,
},
hardBenefitRow: {
flexDirection: 'row',
alignItems: 'center',
gap: 12,
},
hardBenefitRowCompact: {
gap: 9,
},
hardBenefitIcon: {
width: 34,
height: 34,
borderRadius: 17,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#E3EFD9',
},
hardBenefitIconCompact: {
width: 32,
height: 32,
borderRadius: 16,
},
hardBenefitText: {
color: '#101411',
fontSize: 13,
fontWeight: '800',
},
hardBenefitTextCompact: {
fontSize: 13,
},
hardPlanRow: {
flexDirection: 'row',
gap: 10,
marginBottom: 7,
},
hardPlanCard: {
flex: 1,
minHeight: 76,
borderRadius: 14,
borderWidth: 1.5,
borderColor: '#D8DAD3',
padding: 9,
flexDirection: 'row',
gap: 10,
backgroundColor: '#FFFFFF',
},
hardPlanCardCompact: {
minHeight: 76,
padding: 9,
gap: 8,
},
hardPlanCardSelected: {
borderColor: '#1F5B34',
borderWidth: 2,
backgroundColor: '#FBFFF8',
},
planRadio: {
width: 20,
height: 20,
borderRadius: 11,
borderWidth: 2,
borderColor: '#8C918A',
alignItems: 'center',
justifyContent: 'center',
marginTop: 2,
},
planRadioSelected: {
backgroundColor: '#1F5B34',
borderColor: '#1F5B34',
},
hardPlanName: {
color: '#101411',
fontSize: 14,
fontWeight: '900',
marginBottom: 4,
},
hardPlanNameCompact: {
fontSize: 13,
marginBottom: 2,
},
hardPlanPrice: {
color: '#626862',
fontSize: 11,
fontWeight: '700',
lineHeight: 18,
},
hardPlanPriceCompact: {
fontSize: 11,
lineHeight: 15,
},
bestOfferBadge: {
alignSelf: 'flex-start',
backgroundColor: '#DDEBCF',
borderRadius: 999,
paddingHorizontal: 8,
paddingVertical: 3,
marginTop: 5,
},
bestOfferText: {
color: '#1F5B34',
fontSize: 10,
fontWeight: '900',
},
hardPaywallCta: {
minHeight: 50,
borderRadius: 14,
backgroundColor: '#1F5B34',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
gap: 12,
marginBottom: 5,
},
hardPaywallCtaCompact: {
minHeight: 48,
marginBottom: 8,
},
hardPaywallCtaText: {
color: '#FFFFFF',
fontSize: 15,
fontWeight: '900',
},
hardPaywallCtaTextCompact: {
fontSize: 14,
},
hardPaywallFooter: {
color: '#777C75',
fontSize: 12,
fontWeight: '600',
textAlign: 'center',
marginBottom: 5,
},
paywallBody: { paddingHorizontal: 22, paddingTop: 10, paddingBottom: 24 },
paywallEyebrow: { fontSize: 12, fontWeight: '900', letterSpacing: 1.4, textAlign: 'center', marginBottom: 6 },
paywallHeadline: { fontSize: 32, fontWeight: '900', textAlign: 'center', marginBottom: 6 },
paywallSub: { fontSize: 15, lineHeight: 21, textAlign: 'center', marginBottom: 18 },
planCard: { borderRadius: 16, padding: 18, marginBottom: 14 },
planCardTitle: { fontSize: 19, fontWeight: '800', marginBottom: 6 },
planCardBody: { fontSize: 14, lineHeight: 20 },
planCardDivider: { height: StyleSheet.hairlineWidth, marginVertical: 12 },
planCardPrice: { fontSize: 15, fontWeight: '800' },
trialToggleRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', borderRadius: 14, borderWidth: 1, paddingHorizontal: 16, paddingVertical: 12, marginBottom: 16 },
trialToggleLabel: { fontSize: 15, fontWeight: '800' },
dueTimeline: { marginBottom: 18, paddingHorizontal: 4 },
dueRow: { flexDirection: 'row', alignItems: 'center', gap: 10 },
dueDot: { width: 10, height: 10, borderRadius: 5 },
dueLine: { width: 2, height: 18, marginLeft: 4, marginVertical: 2 },
dueLabel: { flex: 1, fontSize: 14, fontWeight: '700' },
dueAmount: { fontSize: 14, fontWeight: '800' },
paywallCta: { height: 58, borderRadius: 14, alignItems: 'center', justifyContent: 'center', marginBottom: 12 },
paywallCtaText: { fontSize: 18, fontWeight: '800' },
paywallFooter: { flexDirection: 'row', justifyContent: 'space-between' },
paywallFooterText: { fontSize: 12, fontWeight: '600' },
safeArea: { flex: 1 },
header: { flexDirection: 'row', alignItems: 'center', padding: 16 },
backButton: { width: 40, height: 40, justifyContent: 'center' },
@@ -1768,17 +1563,6 @@ const styles = StyleSheet.create({
alignItems: 'center',
paddingVertical: 8,
},
hardRestoreBtn: {
alignItems: 'center',
paddingVertical: 6,
marginTop: 4,
},
hardRestoreText: {
color: '#7A8079',
fontSize: 12,
fontWeight: '500',
textDecorationLine: 'underline',
},
autoRenewText: {
fontSize: 11,
marginTop: 2,