import AsyncStorage from '@react-native-async-storage/async-storage'; import { Analytics } from './analytics'; /** * Leichtgewichtiges A/B-Testing ohne PostHog-Provider. * * Warum lokal und nicht PostHog Feature Flags: der PostHog-Client laeuft hier * bewusst ohne Provider (siehe services/analytics.ts). Flags waeren damit erst * nach einem Netzwerk-Roundtrip verfuegbar — der Welcome-Screen rendert aber * sofort. Eine lokal gewuerfelte, persistierte Zuweisung ist deterministisch, * funktioniert offline und wird als Event + Person-Property an PostHog gemeldet, * sodass sich jeder Funnel-Schritt bis zum Kauf nach Variante segmentieren laesst. */ const STORAGE_PREFIX = 'greenlens_experiment_'; export const EXPERIMENTS = { /** Welcome-Headline: Symptom-Einstieg vs. Abgrenzung zu Gratis-Identifikations-Apps. */ welcomeHeadline: { key: 'welcome_headline_v1', variants: ['symptom', 'contrast'] as const, }, } as const; export type WelcomeHeadlineVariant = (typeof EXPERIMENTS.welcomeHeadline.variants)[number]; const memoryCache = new Map(); const pick = (variants: T): T[number] => variants[Math.floor(Math.random() * variants.length)]; /** * Liefert die Variante fuer einen Nutzer. Beim ersten Aufruf wird gewuerfelt, * persistiert und `experiment_assigned` an PostHog geschickt. Alle weiteren * Aufrufe geben dieselbe Variante zurueck. */ export const getVariant = async ( experimentKey: string, variants: T, ): Promise => { const cached = memoryCache.get(experimentKey); if (cached && (variants as readonly string[]).includes(cached)) { return cached as T[number]; } try { const stored = await AsyncStorage.getItem(STORAGE_PREFIX + experimentKey); if (stored && (variants as readonly string[]).includes(stored)) { memoryCache.set(experimentKey, stored); return stored as T[number]; } } catch { // Storage nicht verfuegbar — wir wuerfeln neu, statt den Screen zu blockieren. } const variant = pick(variants); memoryCache.set(experimentKey, variant); try { await AsyncStorage.setItem(STORAGE_PREFIX + experimentKey, variant); } catch { // Nicht persistierbar: die Variante gilt dann nur fuer diese Session. } // Event fuer die Zuweisung selbst ... Analytics.capture('experiment_assigned', { experiment: experimentKey, variant }); // ... plus Person-Property, damit sich JEDER spaetere Funnel-Schritt // (onboarding_started, paywall_opened, purchase_completed) in PostHog nach // Variante aufteilen laesst, ohne die Property ueberall mitschicken zu muessen. Analytics.identifyProperties({ [`experiment_${experimentKey}`]: variant }); return variant; }; /** Nur fuer QA/Debug: erzwingt eine Variante. */ export const forceVariant = async (experimentKey: string, variant: string): Promise => { memoryCache.set(experimentKey, variant); try { await AsyncStorage.setItem(STORAGE_PREFIX + experimentKey, variant); } catch { // ignorieren } }; export const getWelcomeHeadlineVariant = (): Promise => getVariant(EXPERIMENTS.welcomeHeadline.key, EXPERIMENTS.welcomeHeadline.variants);