fix(app): review fixes — billing-unknown pre-check, free-user top-ups, pro out-of-credits copy
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -161,8 +161,6 @@ const getBillingCopy = (language: Language) => {
|
||||
topupMedium: '100 Credits – 6,99 €',
|
||||
topupLarge: '250 Credits – 12,99 €',
|
||||
topupBestValue: 'BESTES ANGEBOT',
|
||||
topupRequiresProTitle: 'Pro erforderlich',
|
||||
topupRequiresProMessage: 'Top-ups sind für aktive Pro-Nutzer gedacht. Starte Pro, um zusätzliche Credits zu kaufen.',
|
||||
cancelTitle: 'Schade, dass du gehst',
|
||||
cancelQuestion: 'Dürfen wir fragen, warum du kündigst?',
|
||||
reasonTooExpensive: 'Es ist mir zu teuer',
|
||||
@@ -237,8 +235,6 @@ const getBillingCopy = (language: Language) => {
|
||||
topupMedium: '100 Créditos – 6,99 €',
|
||||
topupLarge: '250 Créditos – 12,99 €',
|
||||
topupBestValue: 'MEJOR OFERTA',
|
||||
topupRequiresProTitle: 'Pro requerido',
|
||||
topupRequiresProMessage: 'Los top-ups son para usuarios Pro activos. Inicia Pro para comprar créditos adicionales.',
|
||||
cancelTitle: 'Lamentamos verte ir',
|
||||
cancelQuestion: '¿Podemos saber por qué cancelas?',
|
||||
reasonTooExpensive: 'Es muy caro',
|
||||
@@ -313,8 +309,6 @@ const getBillingCopy = (language: Language) => {
|
||||
topupMedium: '100 Credits – €6.99',
|
||||
topupLarge: '250 Credits – €12.99',
|
||||
topupBestValue: 'BEST VALUE',
|
||||
topupRequiresProTitle: 'Pro required',
|
||||
topupRequiresProMessage: 'Top-ups are for active Pro users. Start Pro to buy extra credits.',
|
||||
cancelTitle: 'Sorry to see you go',
|
||||
cancelQuestion: 'May we ask why you are cancelling?',
|
||||
reasonTooExpensive: 'It is too expensive',
|
||||
@@ -487,10 +481,9 @@ export default function BillingScreen() {
|
||||
};
|
||||
|
||||
const handlePurchase = async (productId: PurchaseProductId) => {
|
||||
if (isTopupProductId(productId) && planId !== 'pro') {
|
||||
Alert.alert(copy.topupRequiresProTitle, copy.topupRequiresProMessage, [
|
||||
{ text: copy.manageSubscription, onPress: () => setSubModalVisible(true) },
|
||||
]);
|
||||
// Guests can't sync purchases to an account; signed-in free users may
|
||||
// buy top-ups (the server counts topupBalance for free plans too).
|
||||
if (isTopupProductId(productId) && !session) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,16 +26,12 @@ import { getMockPlantByImage } from '../services/backend/mockCatalog';
|
||||
import { consumeSharedImageUri, SHARE_INTENT_KEY } from '../utils/shareHandoff';
|
||||
import { OutOfCreditsSheet } from '../components/OutOfCreditsSheet';
|
||||
|
||||
const HEALTH_CHECK_CREDIT_COST = 2;
|
||||
const DEMO_SCAN_LIMIT = 5;
|
||||
|
||||
const getBillingCopy = (language: 'de' | 'en' | 'es') => {
|
||||
if (language === 'de') {
|
||||
return {
|
||||
creditsLabel: 'Credits',
|
||||
noCreditsTitle: 'Keine Credits mehr',
|
||||
noCreditsMessage: 'Du hast keine Credits mehr fuer KI-Scans. Upgrade oder Top-up im Profil.',
|
||||
healthNoCreditsMessage: `Du brauchst ${HEALTH_CHECK_CREDIT_COST} Credits fuer den Health-Check.`,
|
||||
managePlan: 'Plan verwalten',
|
||||
dismiss: 'Schliessen',
|
||||
genericErrorTitle: 'Fehler',
|
||||
@@ -68,9 +64,6 @@ const getBillingCopy = (language: 'de' | 'en' | 'es') => {
|
||||
if (language === 'es') {
|
||||
return {
|
||||
creditsLabel: 'Creditos',
|
||||
noCreditsTitle: 'Sin creditos',
|
||||
noCreditsMessage: 'No tienes creditos para escaneos AI. Actualiza o compra top-up en Perfil.',
|
||||
healthNoCreditsMessage: `Necesitas ${HEALTH_CHECK_CREDIT_COST} creditos para el health-check.`,
|
||||
managePlan: 'Gestionar plan',
|
||||
dismiss: 'Cerrar',
|
||||
genericErrorTitle: 'Error',
|
||||
@@ -102,9 +95,6 @@ const getBillingCopy = (language: 'de' | 'en' | 'es') => {
|
||||
|
||||
return {
|
||||
creditsLabel: 'Credits',
|
||||
noCreditsTitle: 'No credits left',
|
||||
noCreditsMessage: 'You have no AI scan credits left. Upgrade or buy a top-up in Profile.',
|
||||
healthNoCreditsMessage: `You need ${HEALTH_CHECK_CREDIT_COST} credits for the health check.`,
|
||||
managePlan: 'Manage plan',
|
||||
dismiss: 'Close',
|
||||
genericErrorTitle: 'Error',
|
||||
@@ -286,8 +276,11 @@ export default function ScannerScreen() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only pre-block when the billing summary is actually known; if it's null
|
||||
// (fetch failed / still loading) let the request proceed — the server 402
|
||||
// path opens the sheet as the safety net.
|
||||
const requiredCredits = isHealthMode ? 2 : 1;
|
||||
if (!isDemoMode && availableCredits < requiredCredits) {
|
||||
if (!isDemoMode && billingSummary && availableCredits < requiredCredits) {
|
||||
posthog.capture('out_of_credits_shown', { trigger: 'pre_check', scan_type: isHealthMode ? 'health_check' : 'identification' });
|
||||
setOutOfCreditsVisible(true);
|
||||
return;
|
||||
@@ -862,6 +855,7 @@ export default function ScannerScreen() {
|
||||
visible={outOfCreditsVisible}
|
||||
language={language}
|
||||
colors={colors}
|
||||
isPro={hasActiveEntitlement}
|
||||
renewsAtIso={billingSummary?.credits.cycleEndsAt}
|
||||
onSeePlans={() => {
|
||||
setOutOfCreditsVisible(false);
|
||||
|
||||
Reference in New Issue
Block a user