import { useEffect, useRef, useState } from 'react'; import { Animated, Dimensions, Easing, Text, TouchableOpacity, View, } from 'react-native'; import Svg, { Defs, RadialGradient, Rect, Stop } from 'react-native-svg'; import { useRouter } from 'expo-router'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { Ionicons } from '@expo/vector-icons'; import { useTranslation } from 'react-i18next'; import { apiFetch } from '../../lib/api'; import { invalidateMe } from '../../hooks/useMe'; const { height: SH } = Dimensions.get('window'); type Bullet = { icon: keyof typeof Ionicons.glyphMap; titleKey: string; descKey: string; }; const BULLETS: Bullet[] = [ { icon: 'eye-off-outline', titleKey: 'onboarding.welcome.bullet_anon_title', descKey: 'onboarding.welcome.bullet_anon_desc' }, { icon: 'shield-checkmark-outline', titleKey: 'onboarding.welcome.bullet_protect_title', descKey: 'onboarding.welcome.bullet_protect_desc' }, { icon: 'people-outline', titleKey: 'onboarding.welcome.bullet_community_title', descKey: 'onboarding.welcome.bullet_community_desc' }, ]; export default function OnboardingWelcomeScreen() { const router = useRouter(); const insets = useSafeAreaInsets(); const { t } = useTranslation(); const [submitting, setSubmitting] = useState(false); // Animation values — Spiegel zur LandingScreen-Choreografie für visuelle Kohärenz const glowOpacity = useRef(new Animated.Value(0.5)).current; const haloOpacity = useRef(new Animated.Value(0)).current; const haloScale = useRef(new Animated.Value(0.6)).current; const heroOpacity = useRef(new Animated.Value(0)).current; const heroScale = useRef(new Animated.Value(0.85)).current; const heroPulse = useRef(new Animated.Value(1)).current; const headlineOpacity = useRef(new Animated.Value(0)).current; const headlineTranslate = useRef(new Animated.Value(10)).current; const bulletsOpacity = useRef([0, 0, 0].map(() => new Animated.Value(0))).current; const bulletsTranslate = useRef([0, 0, 0].map(() => new Animated.Value(14))).current; const privacyOpacity = useRef(new Animated.Value(0)).current; const privacyTranslate = useRef(new Animated.Value(14)).current; const ctaOpacity = useRef(new Animated.Value(0)).current; const ctaTranslate = useRef(new Animated.Value(14)).current; useEffect(() => { Animated.loop( Animated.sequence([ Animated.timing(glowOpacity, { toValue: 0.9, duration: 2200, useNativeDriver: true }), Animated.timing(glowOpacity, { toValue: 0.5, duration: 2200, useNativeDriver: true }), ]), ).start(); const ease = (toValue: number, duration: number) => ({ toValue, duration, useNativeDriver: true, easing: Easing.out(Easing.cubic), }); Animated.parallel([ Animated.timing(haloOpacity, ease(1, 900)), Animated.timing(haloScale, ease(1, 900)), ]).start(); setTimeout(() => { Animated.parallel([ Animated.timing(heroOpacity, ease(1, 650)), Animated.spring(heroScale, { toValue: 1, useNativeDriver: true, friction: 6, tension: 80 }), ]).start(); }, 250); setTimeout(() => { Animated.loop( Animated.sequence([ Animated.timing(heroPulse, { toValue: 1.06, duration: 1400, useNativeDriver: true }), Animated.timing(heroPulse, { toValue: 1, duration: 1400, useNativeDriver: true }), ]), ).start(); }, 1000); setTimeout(() => { Animated.parallel([ Animated.timing(headlineOpacity, ease(1, 600)), Animated.timing(headlineTranslate, ease(0, 600)), ]).start(); }, 700); BULLETS.forEach((_, i) => { setTimeout(() => { Animated.parallel([ Animated.timing(bulletsOpacity[i], ease(1, 450)), Animated.timing(bulletsTranslate[i], ease(0, 450)), ]).start(); }, 1100 + i * 180); }); setTimeout(() => { Animated.parallel([ Animated.timing(privacyOpacity, ease(1, 600)), Animated.timing(privacyTranslate, ease(0, 600)), ]).start(); }, 1700); setTimeout(() => { Animated.parallel([ Animated.timing(ctaOpacity, ease(1, 600)), Animated.timing(ctaTranslate, ease(0, 600)), ]).start(); }, 1950); }, []); async function handleStart() { if (submitting) return; setSubmitting(true); try { await apiFetch('/api/profile/me/onboarding-step', { method: 'PATCH', body: { step: 'nickname' }, }); invalidateMe(); router.replace('/profile/edit'); } catch (e) { console.warn('[onboarding/welcome] failed to advance step:', e); // Sackgasse-Verhalten: Step bleibt 'welcome', User kann nochmal tappen. setSubmitting(false); } } return ( {/* Atmender Top-Glow */} {/* Center indigo halo */} {/* Hero-Icon */} {/* Headline + Subhead */} {t('onboarding.welcome.headline')} {t('onboarding.welcome.subhead')} {/* Mission-Bullets */} {BULLETS.map((b, i) => ( {t(b.titleKey)} {t(b.descKey)} ))} {/* DSGVO-Box */} {t('onboarding.welcome.privacy_label')} {t('onboarding.welcome.privacy_body')} {/* CTA */} {submitting ? t('onboarding.welcome.cta_loading') : t('onboarding.welcome.cta')} {t('onboarding.welcome.next_hint')} ); }