feat(app): paywall is param-driven and dismissible; onboarding context routes X to sign-up
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@ 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 { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { useRouter, useLocalSearchParams } from 'expo-router';
|
||||
import { useFocusEffect } from '@react-navigation/native';
|
||||
import Constants from 'expo-constants';
|
||||
import Purchases, {
|
||||
@@ -330,6 +330,9 @@ const getBillingCopy = (language: Language) => {
|
||||
|
||||
export default function BillingScreen() {
|
||||
const router = useRouter();
|
||||
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 colors = useColors(isDarkMode, colorPalette);
|
||||
const posthog = useSafeAnalytics();
|
||||
@@ -351,7 +354,7 @@ export default function BillingScreen() {
|
||||
|
||||
const planId = billingSummary?.entitlement?.plan || 'free';
|
||||
const credits = isLoadingBilling && !billingSummary ? '...' : (billingSummary?.credits?.available ?? 0);
|
||||
const showPaywallPlans = !session || (!isLoadingBilling && planId !== 'pro');
|
||||
const showPaywallPlans = (!session || paywallRequested) && planId !== 'pro';
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
@@ -439,6 +442,16 @@ export default function BillingScreen() {
|
||||
|
||||
const handleBack = useCallback(() => {
|
||||
if (showPaywallPlans) {
|
||||
posthog.capture('paywall_dismissed', { context: onboardingContext ? 'onboarding' : 'in_app' });
|
||||
if (onboardingContext) {
|
||||
router.replace('/auth/signup');
|
||||
return;
|
||||
}
|
||||
if (session) {
|
||||
if (router.canGoBack()) router.back();
|
||||
else router.replace('/(tabs)');
|
||||
return;
|
||||
}
|
||||
router.replace('/onboarding');
|
||||
return;
|
||||
}
|
||||
@@ -447,7 +460,9 @@ export default function BillingScreen() {
|
||||
return;
|
||||
}
|
||||
router.replace('/(tabs)');
|
||||
}, [router, showPaywallPlans]);
|
||||
}, [router, showPaywallPlans, onboardingContext, session, posthog]);
|
||||
|
||||
const postPurchaseRoute = onboardingContext ? '/auth/signup' : '/(tabs)';
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
@@ -455,12 +470,12 @@ export default function BillingScreen() {
|
||||
if (!showPaywallPlans) {
|
||||
return false;
|
||||
}
|
||||
router.replace('/onboarding');
|
||||
handleBack();
|
||||
return true;
|
||||
});
|
||||
|
||||
return () => subscription.remove();
|
||||
}, [router, showPaywallPlans]),
|
||||
}, [showPaywallPlans, handleBack]),
|
||||
);
|
||||
|
||||
const completeExpoGoSimulation = async (productId: PurchaseProductId) => {
|
||||
@@ -471,7 +486,7 @@ export default function BillingScreen() {
|
||||
posthog.capture('subscription_started', { product_id: productId, simulated: true });
|
||||
posthog.capture('trial_started', { product_id: productId, simulated: true });
|
||||
setSubModalVisible(false);
|
||||
router.replace('/(tabs)');
|
||||
router.replace(postPurchaseRoute);
|
||||
} else {
|
||||
posthog.capture('topup_purchased', { product_id: productId, simulated: true });
|
||||
}
|
||||
@@ -534,7 +549,7 @@ export default function BillingScreen() {
|
||||
posthog.capture('subscription_started', { product_id: productId });
|
||||
posthog.capture('trial_started', { product_id: productId });
|
||||
setSubModalVisible(false);
|
||||
setTimeout(() => router.replace('/(tabs)'), 0);
|
||||
setTimeout(() => router.replace(postPurchaseRoute), 0);
|
||||
return;
|
||||
} else {
|
||||
const selectedProduct = topupProducts[productId];
|
||||
|
||||
Reference in New Issue
Block a user