This commit is contained in:
2026-07-08 22:07:59 +02:00
parent 0b2305a3ad
commit 9be9b2987b
10 changed files with 349 additions and 268 deletions

View File

@@ -24,7 +24,7 @@ type SubscriptionProductId = 'monthly_pro' | 'yearly_pro';
type TopupProductId = Extract<PurchaseProductId, 'topup_small' | 'topup_medium' | 'topup_large'>;
type SubscriptionPackages = Partial<Record<SubscriptionProductId, PurchasesPackage>>;
type TopupProducts = Partial<Record<TopupProductId, PurchasesStoreProduct>>;
type PaywallPlanId = 'weekly' | 'yearly';
type PaywallPlanId = 'monthly' | 'yearly';
const PAYWALL_BACKGROUND = require('../../assets/paywall_scan_background.png');
@@ -159,7 +159,7 @@ const getBillingCopy = (language: Language) => {
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',
trialToggleLabel: '7 Tage gratis testen',
dueTodayTrial: 'Fällig heute — 7 Tage gratis',
dueTodayAmount: '0,00 €',
dueLater: (date: string) => `Fällig am ${date}`,
@@ -224,7 +224,7 @@ const getBillingCopy = (language: Language) => {
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',
trialToggleLabel: 'Probar 7 días gratis',
dueTodayTrial: 'Hoy — 7 días gratis',
dueTodayAmount: '0,00 €',
dueLater: (date: string) => `El ${date}`,
@@ -289,7 +289,7 @@ const getBillingCopy = (language: Language) => {
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',
trialToggleLabel: 'Try 7 days free',
dueTodayTrial: 'Due today — 7 days free',
dueTodayAmount: '€0.00',
dueLater: (date: string) => `Due ${date}`,
@@ -308,7 +308,7 @@ export default function BillingScreen() {
const params = useLocalSearchParams<{ view?: string; context?: string }>();
const paywallRequested = params.view === 'paywall';
const onboardingContext = params.context === 'onboarding';
const { isDarkMode, language, billingSummary, isLoadingBilling, simulatePurchase, simulateWebhookEvent, syncRevenueCatState, colorPalette, session } = useApp();
const { isDarkMode, language, billingSummary, isLoadingBilling, simulatePurchase, simulateWebhookEvent, syncRevenueCatState, colorPalette, session, hasCompletedOnboarding, markOnboardingCompleted } = useApp();
const colors = useColors(isDarkMode, colorPalette);
const posthog = useSafeAnalytics();
const copy = getBillingCopy(language);
@@ -320,7 +320,8 @@ export default function BillingScreen() {
const [storeError, setStoreError] = useState<string | null>(null);
const [subscriptionPackages, setSubscriptionPackages] = useState<SubscriptionPackages>({});
const [topupProducts, setTopupProducts] = useState<TopupProducts>({});
const [selectedPaywallPlan, setSelectedPaywallPlan] = useState<PaywallPlanId>('yearly');
// Monthly is the default; the 7-day trial (yearly plan) must be opted into via the toggle.
const [selectedPaywallPlan, setSelectedPaywallPlan] = useState<PaywallPlanId>('monthly');
// Cancel Flow State
const [cancelStep, setCancelStep] = useState<'none' | 'survey' | 'offer'>('none');
@@ -426,7 +427,9 @@ export default function BillingScreen() {
if (showPaywallPlans) {
posthog.capture('paywall_dismissed', { context: onboardingContext ? 'onboarding' : 'in_app' });
if (onboardingContext) {
router.replace('/auth/signup');
// Guests continue into the app; paid actions are gated at the point of use.
markOnboardingCompleted();
router.replace('/(tabs)');
return;
}
if (session) {
@@ -434,7 +437,7 @@ export default function BillingScreen() {
else router.replace('/(tabs)');
return;
}
router.replace('/onboarding');
router.replace(hasCompletedOnboarding ? '/(tabs)' : '/onboarding');
return;
}
if (router.canGoBack()) {
@@ -442,7 +445,7 @@ export default function BillingScreen() {
return;
}
router.replace('/(tabs)');
}, [router, showPaywallPlans, onboardingContext, session, posthog]);
}, [router, showPaywallPlans, onboardingContext, session, posthog, hasCompletedOnboarding, markOnboardingCompleted]);
const postPurchaseRoute = onboardingContext ? '/auth/signup' : '/(tabs)';
@@ -653,7 +656,7 @@ export default function BillingScreen() {
<Text style={[styles.trialToggleLabel, { color: colors.text }]}>{copy.trialToggleLabel}</Text>
<Switch
value={trialEnabled}
onValueChange={(next) => setSelectedPaywallPlan(next ? 'yearly' : 'weekly')}
onValueChange={(next) => setSelectedPaywallPlan(next ? 'yearly' : 'monthly')}
trackColor={{ true: colors.primary, false: colors.border }}
thumbColor="#FFFFFF"
/>