import { useEffect } from "react"; import { Alert } from "react-native"; import { useQuery } from "@tanstack/react-query"; import { api } from "@/lib/api"; import { useAnalytics } from "@/lib/analytics"; import { paywallViewed } from "@app/analytics"; import { t } from "@/lib/i18n"; import { formatMinor } from "@/lib/money"; import { Body, Button, Card, Heading, Row, Screen, Small, Spacer, Tag, Title, } from "@/components/ui"; /** * Paywall (spec §45–46). Köpet går via StoreKit/Play Billing i klienten * (react-native-purchases eller expo-in-app-purchases integreras i fas 7); * kvittot verifieras ALLTID av backend (spec §61.14). Här visas planerna och * flödet är förberett med /v1/subscriptions/verify. */ interface PlanRow { key: string; priceMinor: number; members: number; highlight?: boolean; } const PLANS: PlanRow[] = [ { key: "paywall.household", priceMinor: 7900, members: 3 }, { key: "paywall.family", priceMinor: 12900, members: 6, highlight: true }, { key: "paywall.large", priceMinor: 16900, members: 12 }, ]; interface Entitlements { plan: string; status: string; expiresAt?: string; } export default function PaywallScreen() { const { track } = useAnalytics(); const entitlements = useQuery({ queryKey: ["entitlements"], queryFn: () => api("/v1/me/entitlements"), }); useEffect(() => { track( paywallViewed({ properties: { plan: entitlements.data?.plan, status: entitlements.data?.status }, }), ); }, []); // eslint-disable-line react-hooks/exhaustive-deps const trialDaysLeft = entitlements.data?.status === "trial" && entitlements.data.expiresAt ? Math.max(0, Math.ceil((Date.parse(entitlements.data.expiresAt) - Date.now()) / 86_400_000)) : null; const buy = () => { Alert.alert(t("paywall.soonTitle"), t("paywall.soonBody")); }; return ( {t("paywall.title")} {t("paywall.subtitle")} {trialDaysLeft != null && ( )} {PLANS.map((plan) => ( {t(plan.key as never)} {plan.highlight && } {t("paywall.perMonth", { price: formatMinor(plan.priceMinor, "SEK") })}