import React, { useEffect, useState } from 'react'; import { StyleSheet, View, Dimensions } from 'react-native'; import Animated, { useSharedValue, useAnimatedStyle, withTiming, withSequence, withDelay, withSpring, interpolate, Easing, runOnJS, } from 'react-native-reanimated'; import { COLORS } from '../constants/colors'; const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window'); interface CountdownOverlayProps { onComplete: () => void; } export const CountdownOverlay: React.FC = ({ onComplete }) => { const [currentNumber, setCurrentNumber] = useState(3); const [showGo, setShowGo] = useState(false); const [visible, setVisible] = useState(true); const numberScale = useSharedValue(0); const numberOpacity = useSharedValue(0); const ringScale = useSharedValue(0); const bgOpacity = useSharedValue(1); const animateNumber = (num: number) => { numberScale.value = 0.3; numberOpacity.value = 0; ringScale.value = 0.5; numberScale.value = withSequence( withSpring(1, { damping: 8, stiffness: 150 }), withDelay(500, withTiming(1.5, { duration: 200 })) ); numberOpacity.value = withSequence( withTiming(1, { duration: 150 }), withDelay(500, withTiming(0, { duration: 200 })) ); ringScale.value = withSequence( withSpring(1, { damping: 8, stiffness: 120 }), withDelay(400, withTiming(1.8, { duration: 300 })) ); }; useEffect(() => { animateNumber(3); const timers = [ setTimeout(() => { setCurrentNumber(2); animateNumber(2); }, 900), setTimeout(() => { setCurrentNumber(1); animateNumber(1); }, 1800), setTimeout(() => { setShowGo(true); numberScale.value = 0.3; numberOpacity.value = 0; numberScale.value = withSpring(1.2, { damping: 6, stiffness: 100 }); numberOpacity.value = withTiming(1, { duration: 150 }); }, 2700), setTimeout(() => { bgOpacity.value = withTiming(0, { duration: 300 }); setTimeout(() => { setVisible(false); onComplete(); }, 300); }, 3300), ]; return () => timers.forEach(clearTimeout); }, []); const numberStyle = useAnimatedStyle(() => ({ transform: [{ scale: numberScale.value }], opacity: numberOpacity.value, })); const ringStyle = useAnimatedStyle(() => ({ transform: [{ scale: ringScale.value }], opacity: interpolate(ringScale.value, [0.5, 1, 1.8], [0.3, 0.5, 0]), })); const containerStyle = useAnimatedStyle(() => ({ opacity: bgOpacity.value, })); if (!visible) return null; return ( {/* Pulse Ring */} {/* Number / GO */} {showGo ? 'GO!' : currentNumber} ); }; const styles = StyleSheet.create({ overlay: { ...StyleSheet.absoluteFillObject, backgroundColor: 'rgba(10, 10, 11, 0.95)', alignItems: 'center', justifyContent: 'center', zIndex: 999, }, ring: { position: 'absolute', width: 150, height: 150, borderRadius: 75, borderWidth: 3, borderColor: COLORS.primary, }, number: { fontSize: 80, fontWeight: '900', color: COLORS.text, textShadowColor: COLORS.primary + '60', textShadowOffset: { width: 0, height: 0 }, textShadowRadius: 30, fontVariant: ['tabular-nums'], }, goText: { color: COLORS.primary, fontSize: 64, letterSpacing: 8, }, });