import React, { useRef, useState, useEffect, useCallback } from 'react'; import { View, Text, Image, TextInput, StyleSheet, FlatList, Dimensions, TouchableOpacity, Animated, KeyboardAvoidingView, Platform, Keyboard, } from 'react-native'; import AsyncStorage from '@react-native-async-storage/async-storage'; import StarField from '../components/StarField'; import Button from '../components/Button'; import useAppStore from '../store/useAppStore'; import useAuthStore from '../store/useAuthStore'; import { colors, fonts, spacing, borderRadius } from '../utils/theme'; const { width } = Dimensions.get('window'); const ONBOARDING_KEY = 'onboarding_done'; const pages = [ { id: '1', title: 'Identity First', text: 'Every transformation begins with identity.\nNot goals. Not habits. Identity.', iconSize: 90, glowIntensity: 0.3, showOrbit: false, }, { id: '2', title: '40 Days', text: "In 40 days, you won't just change habits\n— you'll change who you are.", iconSize: 110, glowIntensity: 0.65, showOrbit: false, }, { id: '3', title: 'Your Nova Awaits', text: 'Small actions. Massive transformation.', iconSize: 110, glowIntensity: 1, showOrbit: true, isLast: true, }, ]; function PageContent({ item, isActive }) { const fadeAnim = useRef(new Animated.Value(0)).current; const slideAnim = useRef(new Animated.Value(30)).current; const pulse = useRef(new Animated.Value(1)).current; useEffect(() => { if (isActive) { fadeAnim.setValue(0); slideAnim.setValue(30); Animated.parallel([ Animated.timing(fadeAnim, { toValue: 1, duration: 500, delay: 150, useNativeDriver: true }), Animated.timing(slideAnim, { toValue: 0, duration: 500, delay: 150, useNativeDriver: true }), ]).start(); } }, [isActive]); useEffect(() => { const anim = Animated.loop( Animated.sequence([ Animated.timing(pulse, { toValue: 1.12, duration: 2200, useNativeDriver: true }), Animated.timing(pulse, { toValue: 1, duration: 2200, useNativeDriver: true }), ]) ); anim.start(); return () => anim.stop(); }, []); return ( {/* Icon area */} {item.showOrbit && ( )} {/* Text */} {item.title} {item.text} ); } export default function OnboardingScreen({ navigation }) { const flatListRef = useRef(null); const [currentIndex, setCurrentIndex] = useState(0); const [identityInput, setIdentityInput] = useState(''); const [keyboardVisible, setKeyboardVisible] = useState(false); const setInitialIdentity = useAppStore((s) => s.setInitialIdentity); const buttonFade = useRef(new Animated.Value(0)).current; const inputFade = useRef(new Animated.Value(0)).current; const isLastPage = currentIndex === pages.length - 1; useEffect(() => { const showSub = Keyboard.addListener('keyboardWillShow', () => setKeyboardVisible(true)); const hideSub = Keyboard.addListener('keyboardWillHide', () => setKeyboardVisible(false)); // Android uses keyboardDidShow/keyboardDidHide const showSubAnd = Keyboard.addListener('keyboardDidShow', () => setKeyboardVisible(true)); const hideSubAnd = Keyboard.addListener('keyboardDidHide', () => setKeyboardVisible(false)); return () => { showSub.remove(); hideSub.remove(); showSubAnd.remove(); hideSubAnd.remove(); }; }, []); useEffect(() => { if (isLastPage) { Animated.stagger(200, [ Animated.timing(inputFade, { toValue: 1, duration: 400, useNativeDriver: true }), Animated.timing(buttonFade, { toValue: 1, duration: 400, useNativeDriver: true }), ]).start(); } else { buttonFade.setValue(0); inputFade.setValue(0); } }, [isLastPage]); const completeOnboarding = useCallback(async () => { await AsyncStorage.setItem(ONBOARDING_KEY, 'true'); if (identityInput.trim()) { setInitialIdentity(identityInput.trim()); } // If user is already logged in (came from Register), go to story input // Otherwise go to Login const session = useAuthStore.getState().session; if (session) { navigation.reset({ index: 0, routes: [{ name: 'IdentityStory' }] }); } else { navigation.reset({ index: 0, routes: [{ name: 'Login' }] }); } }, [identityInput, navigation, setInitialIdentity]); const onViewableItemsChanged = useRef(({ viewableItems }) => { if (viewableItems.length > 0) { setCurrentIndex(viewableItems[0].index ?? 0); } }).current; return ( {/* Skip button — hidden on last page */} {!isLastPage && ( Skip )} {/* Hide pager when keyboard is visible on last page to make room */} {!(keyboardVisible && isLastPage) && ( item.id} onViewableItemsChanged={onViewableItemsChanged} viewabilityConfig={{ viewAreaCoveragePercentThreshold: 50 }} renderItem={({ item, index }) => ( )} /> )} {/* Bottom section: input + button + dots */} {/* Show title when keyboard hides the pager */} {keyboardVisible && isLastPage && ( Who do you want to become? )} {/* Identity input on last page */} {isLastPage && ( {!keyboardVisible && ( Who do you want to become? )} Keyboard.dismiss()} /> )} {/* CTA button on last page */} {isLastPage && (