import React from 'react'; import { Image, Modal, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { Language } from '../types'; import { useColors } from '../constants/Colors'; type ColorsType = ReturnType; const getCopy = (language: Language, isPro: boolean) => { // Framing: der Nutzer wollte gerade etwas tun und wurde gestoppt. Der CTA // bringt die angefangene Aufgabe zu Ende - das Abo ist das Mittel, nicht das // Angebot. Kein "unbegrenzt": das Pro-Kontingent ist 100 Scans pro Monat. if (language === 'de') { return { title: 'Diese Pflanze schauen wir uns noch an.', body: (date: string) => (isPro ? `Deine Credits erneuern sich am ${date}. Mit einem Credit-Paket läuft dieser Scan sofort.` : `Deine 3 Gratis-Scans erneuern sich am ${date}. Mit Pro läuft dieser Scan sofort - plus Ursachen-Ranking, Prüfschritte und dein 7-Tage-Plan.`), bodyNoDate: isPro ? 'Mit einem Credit-Paket läuft dieser Scan sofort.' : 'Mit Pro läuft dieser Scan sofort - plus Ursachen-Ranking, Prüfschritte und dein 7-Tage-Plan.', cta: isPro ? 'Credits aufladen' : 'Diesen Scan mit Pro starten', topupsLabel: 'Oder einzelne Credits kaufen', later: 'Später', best: 'BESTE WAHL', credits: 'Credits', }; } if (language === 'es') { return { title: 'Vamos a mirar esta planta.', body: (date: string) => (isPro ? `Tus créditos se renuevan el ${date}. Con un paquete de créditos este escaneo sale ya.` : `Tus 3 escaneos gratis se renuevan el ${date}. Con Pro este escaneo sale ya - más ranking de causas, pasos de revisión y tu plan de 7 días.`), bodyNoDate: isPro ? 'Con un paquete de créditos este escaneo sale ya.' : 'Con Pro este escaneo sale ya - más ranking de causas, pasos de revisión y tu plan de 7 días.', cta: isPro ? 'Recargar créditos' : 'Hacer este escaneo con Pro', topupsLabel: 'O compra créditos sueltos', later: 'Más tarde', best: 'MEJOR OPCIÓN', credits: 'créditos', }; } return { title: "Let's still look at this plant.", body: (date: string) => (isPro ? `Your credits renew on ${date}. With a credit pack this scan runs right now.` : `Your 3 free scans renew on ${date}. With Pro this scan runs right now - plus a cause ranking, things to check and your 7-day plan.`), bodyNoDate: isPro ? 'With a credit pack this scan runs right now.' : 'With Pro this scan runs right now - plus a cause ranking, things to check and your 7-day plan.', cta: isPro ? 'Top up credits' : 'Run this scan with Pro', topupsLabel: 'Or buy single credits', later: 'Later', best: 'BEST', credits: 'credits', }; }; const formatRenewalDate = (iso: string | null | undefined, language: Language): string | null => { if (!iso) return null; const date = new Date(iso); if (Number.isNaN(date.getTime())) return null; const locale = language === 'de' ? 'de-DE' : language === 'es' ? 'es-ES' : 'en-US'; return date.toLocaleDateString(locale, { day: 'numeric', month: 'long' }); }; type Props = { visible: boolean; language: Language; colors: ColorsType; isPro?: boolean; renewsAtIso?: string | null; onSeePlans: () => void; onTopup: (productId: 'topup_small' | 'topup_medium' | 'topup_large') => void; onDismiss: () => void; }; const TOPUPS = [ { id: 'topup_small' as const, amount: 30, best: false }, { id: 'topup_medium' as const, amount: 100, best: false }, { id: 'topup_large' as const, amount: 250, best: true }, ]; export function OutOfCreditsSheet({ visible, language, colors, isPro = false, renewsAtIso, onSeePlans, onTopup, onDismiss }: Props) { const copy = getCopy(language, isPro); const renewalDate = formatRenewalDate(renewsAtIso, language); return ( 0 {copy.title} {renewalDate ? copy.body(renewalDate) : copy.bodyNoDate} {!isPro && ( {copy.cta} )} {copy.topupsLabel.toUpperCase()} {TOPUPS.map((topup) => ( onTopup(topup.id)} activeOpacity={0.85} > {topup.best && ( {copy.best} )} +{topup.amount} {copy.credits} ))} {copy.later} ); } const styles = StyleSheet.create({ backdrop: { flex: 1, backgroundColor: 'rgba(10,17,11,0.45)', justifyContent: 'flex-end' }, backdropTouchable: { flex: 1 }, sheet: { borderTopLeftRadius: 26, borderTopRightRadius: 26, paddingHorizontal: 24, paddingTop: 10, paddingBottom: 34, alignItems: 'center' }, handle: { width: 44, height: 5, borderRadius: 3, marginBottom: 18 }, iconWrap: { marginBottom: 14 }, iconCircle: { width: 76, height: 76, borderRadius: 38, alignItems: 'center', justifyContent: 'center' }, zeroBadge: { position: 'absolute', top: -2, right: -4, width: 26, height: 26, borderRadius: 13, alignItems: 'center', justifyContent: 'center' }, zeroBadgeText: { color: '#fff', fontSize: 13, fontWeight: '900' }, title: { fontSize: 24, fontWeight: '900', textAlign: 'center', marginBottom: 8 }, body: { fontSize: 15, lineHeight: 21, textAlign: 'center', marginBottom: 18, maxWidth: 320 }, cta: { alignSelf: 'stretch', height: 56, borderRadius: 14, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 8, marginBottom: 16 }, ctaText: { fontSize: 17, fontWeight: '800' }, topupsLabel: { fontSize: 11, fontWeight: '800', letterSpacing: 0.8, marginBottom: 10 }, topupRow: { flexDirection: 'row', gap: 10, alignSelf: 'stretch', marginBottom: 14 }, topupChip: { flex: 1, borderWidth: 1.5, borderRadius: 14, paddingVertical: 14, alignItems: 'center', overflow: 'hidden' }, bestBadge: { position: 'absolute', top: 0, left: 0, right: 0, paddingVertical: 3, alignItems: 'center' }, bestBadgeText: { fontSize: 9, fontWeight: '900', letterSpacing: 0.6 }, topupAmount: { fontSize: 22, fontWeight: '900', marginTop: 6 }, topupUnit: { fontSize: 12, fontWeight: '600' }, laterBtn: { paddingVertical: 8 }, laterText: { fontSize: 15, fontWeight: '800' }, });