diff --git a/src/components/Footer/Hamburger.component.tsx b/src/components/Footer/Hamburger.component.tsx index 370bb53a2..76888b4cb 100644 --- a/src/components/Footer/Hamburger.component.tsx +++ b/src/components/Footer/Hamburger.component.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback } from 'react'; +import { useState, useEffect, useCallback, useRef } from 'react'; import Link from 'next/link'; import FadeLeftToRight from '@/components/Animations/FadeLeftToRight.component'; @@ -22,34 +22,71 @@ const opacityFull = 'opacity-100 group-hover:opacity-100'; const Hamburger = () => { const [isExpanded, setisExpanded] = useState(false); const [hidden, setHidden] = useState('invisible'); + const [isAnimating, setIsAnimating] = useState(false); + const animationTimeoutRef = useRef | null>( + null, + ); useEffect(() => { if (isExpanded) { setHidden(''); + setIsAnimating(true); + + // Clear any existing timeout + if (animationTimeoutRef.current) { + clearTimeout(animationTimeoutRef.current); + } + + // Set a timeout for the animation duration + animationTimeoutRef.current = setTimeout(() => { + setIsAnimating(false); + }, 1000); // Match this with the animation duration } else { - setTimeout(() => { + setIsAnimating(true); + + // Clear any existing timeout + if (animationTimeoutRef.current) { + clearTimeout(animationTimeoutRef.current); + } + + // Set a timeout for the animation duration and hiding + animationTimeoutRef.current = setTimeout(() => { setHidden('invisible'); - }, 1000); + setIsAnimating(false); + }, 1000); // Match this with the animation duration } + + // Cleanup function to clear timeout when component unmounts + return () => { + if (animationTimeoutRef.current) { + clearTimeout(animationTimeoutRef.current); + } + }; }, [isExpanded]); const handleMobileMenuClick = useCallback(() => { + // Prevent clicks during animation + if (isAnimating) { + return; + } + /** * Anti-pattern: setisExpanded(!isExpanded) * Even if your state updates are batched and multiple updates to the enabled/disabled state are made together * each update will rely on the correct previous state so that you always end up with the result you expect. */ setisExpanded((prevExpanded) => !prevExpanded); - }, [setisExpanded]); + }, [setisExpanded, isAnimating]); return (