import { useEffect, useRef } from 'react'; import { Animated, Easing, Text, useWindowDimensions, View } from 'react-native'; import { useTranslation } from 'react-i18next'; import { Ionicons } from '@expo/vector-icons'; import * as Notifications from 'expo-notifications'; import { useColors } from '../../../lib/theme'; import { OnboardingShell } from '../OnboardingShell'; import { LyraBubble } from '../LyraBubble'; import { CTABar } from '../CTABar'; import { FaqAccordion, type FaqItem } from '../../FaqAccordion'; import { useNotificationPrefsStore } from '../../../stores/notificationPrefs'; // Top-5 (kuratiert für Onboarding-Ende) — alle 8 sind unter app/help/faq.tsx. const ONBOARDING_FAQ_IDS = [1, 2, 4, 5, 8] as const; export function DoneSlide({ onEnter, current, total, }: { onEnter: () => void; current: number; total: number; }) { const { t } = useTranslation(); const colors = useColors(); const scale = useRef(new Animated.Value(0.6)).current; const opacity = useRef(new Animated.Value(0)).current; const setPushEnabled = useNotificationPrefsStore((s) => s.setPushEnabled); const faqItems: FaqItem[] = ONBOARDING_FAQ_IDS.map((id) => ({ q: t(`help.faq_q${id}`), a: t(`help.faq_a${id}`), })); useEffect(() => { Animated.parallel([ Animated.spring(scale, { toValue: 1, useNativeDriver: true, friction: 5, tension: 90 }), Animated.timing(opacity, { toValue: 1, duration: 500, useNativeDriver: true, easing: Easing.out(Easing.cubic), }), ]).start(); (async () => { try { const { status } = await Notifications.requestPermissionsAsync(); if (status !== 'granted') { await setPushEnabled(false); } } catch {} })(); }, [setPushEnabled]); return ( } > {t('onboarding.done.headline')} {t('onboarding.done.subhead')} {/* Inline Top-5-FAQ Accordion (pills-Variante) */} {t('onboarding.done.faq_section_title')} ); } // ─── Confetti-Overlay (Reanimated Particles) ───────────────────────────────── const CONFETTI_COUNT = 22; const CONFETTI_COLORS = ['#fbbf24', '#34d399', '#60a5fa', '#a78bfa', '#f472b6']; function ConfettiOverlay() { const { width: screenW } = useWindowDimensions(); // Stabile Particle-Definitionen — Math.random nur einmal beim Mount const particles = useRef( Array.from({ length: CONFETTI_COUNT }).map((_, i) => ({ key: i, anim: new Animated.Value(0), startX: Math.random() * screenW, drift: (Math.random() - 0.5) * 80, color: CONFETTI_COLORS[i % CONFETTI_COLORS.length], rotateStart: Math.random() * 360, size: 6 + Math.random() * 6, delay: Math.random() * 600, duration: 2200 + Math.random() * 1300, })), ).current; useEffect(() => { Animated.stagger( 40, particles.map((p) => Animated.timing(p.anim, { toValue: 1, duration: p.duration, delay: p.delay, useNativeDriver: true, easing: Easing.out(Easing.quad), }), ), ).start(); }, []); return ( {particles.map((p) => { const translateY = p.anim.interpolate({ inputRange: [0, 1], outputRange: [-30, 580] }); const translateX = p.anim.interpolate({ inputRange: [0, 1], outputRange: [0, p.drift] }); const rotate = p.anim.interpolate({ inputRange: [0, 1], outputRange: [`${p.rotateStart}deg`, `${p.rotateStart + 540}deg`], }); const opacity = p.anim.interpolate({ inputRange: [0, 0.85, 1], outputRange: [1, 1, 0] }); return ( ); })} ); }