import { useEffect } from "react"; import { View } from "react-native"; import Animated, { Easing, interpolate, useAnimatedStyle, useSharedValue, withDelay, withSequence, withSpring, withTiming, } from "react-native-reanimated"; import * as Haptics from "expo-haptics"; import { Check } from "lucide-react-native"; interface ParticleProps { angle: number; delay: number; color: string; } function Particle({ angle, delay, color }: ParticleProps) { const progress = useSharedValue(0); useEffect(() => { progress.value = withDelay( 200 + delay, withSequence( withTiming(1, { duration: 400, easing: Easing.out(Easing.ease) }), withTiming(0, { duration: 300 }), ), ); }, []); const particleStyle = useAnimatedStyle(() => { const distance = interpolate(progress.value, [0, 1], [0, 60]); const opacity = interpolate(progress.value, [0, 0.5, 1], [0, 1, 0]); const scale = interpolate(progress.value, [0, 0.5, 1], [0, 1, 0]); const angleRad = (angle * Math.PI) / 180; return { position: "absolute" as const, width: 8, height: 8, borderRadius: 4, backgroundColor: color, opacity, transform: [ { translateX: Math.cos(angleRad) * distance }, { translateY: Math.sin(angleRad) * distance }, { scale }, ], }; }); return ; } interface SuccessAnimationProps { isAlreadyExists: boolean; } export default function SuccessAnimation({ isAlreadyExists, }: SuccessAnimationProps) { const checkScale = useSharedValue(0); const checkOpacity = useSharedValue(0); const ringScale = useSharedValue(0.8); const ringOpacity = useSharedValue(0); const particleColor = isAlreadyExists ? "rgb(255, 180, 0)" : "rgb(0, 200, 100)"; useEffect(() => { Haptics.notificationAsync( isAlreadyExists ? Haptics.NotificationFeedbackType.Warning : Haptics.NotificationFeedbackType.Success, ); ringScale.value = withSequence( withTiming(1.2, { duration: 400, easing: Easing.out(Easing.ease) }), withTiming(1, { duration: 200 }), ); ringOpacity.value = withSequence( withTiming(1, { duration: 200 }), withDelay(300, withTiming(0.3, { duration: 300 })), ); checkScale.value = withDelay( 150, withSpring(1, { damping: 12, stiffness: 200, mass: 0.8, }), ); checkOpacity.value = withDelay(150, withTiming(1, { duration: 200 })); }, [isAlreadyExists]); const ringStyle = useAnimatedStyle(() => ({ transform: [{ scale: ringScale.value }], opacity: ringOpacity.value, })); const checkStyle = useAnimatedStyle(() => ({ transform: [{ scale: checkScale.value }], opacity: checkOpacity.value, })); return ( {Array.from({ length: 8 }, (_, i) => ( ))} ); }