diff --git a/apps/portal/src/features/landing-page/hooks/useInfiniteCarousel.ts b/apps/portal/src/features/landing-page/hooks/useInfiniteCarousel.ts index 5b45a3b3..226b6186 100644 --- a/apps/portal/src/features/landing-page/hooks/useInfiniteCarousel.ts +++ b/apps/portal/src/features/landing-page/hooks/useInfiniteCarousel.ts @@ -48,10 +48,13 @@ export function useInfiniteCarousel({ items }: { items: T[] }) { const startAuto = useCallback(() => { if (autoRef.current) clearInterval(autoRef.current); autoRef.current = setInterval(() => { - setTrackIndex(prev => prev + 1); + setTrackIndex(prev => { + if (prev <= 0 || prev >= total + 1) return prev; + return prev + 1; + }); setIsTransitioning(true); }, AUTO_INTERVAL); - }, []); + }, [total]); const stopAuto = useCallback(() => { if (autoRef.current) { @@ -65,15 +68,22 @@ export function useInfiniteCarousel({ items }: { items: T[] }) { return stopAuto; }, [startAuto, stopAuto]); - const handleTransitionEnd = useCallback(() => { - if (trackIndex >= total + 1) { - setIsTransitioning(false); - setTrackIndex(1); - } else if (trackIndex <= 0) { - setIsTransitioning(false); - setTrackIndex(total); - } - }, [trackIndex, total]); + const handleTransitionEnd = useCallback( + (e: React.TransitionEvent) => { + // Only respond to the track's own transform transition, + // not bubbled events from child slide transitions (scale/opacity/filter) + if (e.target !== e.currentTarget || e.propertyName !== "transform") return; + + if (trackIndex >= total + 1) { + setIsTransitioning(false); + setTrackIndex(1); + } else if (trackIndex <= 0) { + setIsTransitioning(false); + setTrackIndex(total); + } + }, + [trackIndex, total] + ); useEffect(() => { if (isTransitioning) return; @@ -83,11 +93,15 @@ export function useInfiniteCarousel({ items }: { items: T[] }) { const navigate = useCallback( (updater: number | ((prev: number) => number)) => { - setTrackIndex(updater); + setTrackIndex(prev => { + // Block navigation while at a clone position (snap-back pending) + if (prev <= 0 || prev >= total + 1) return prev; + return typeof updater === "function" ? updater(prev) : updater; + }); setIsTransitioning(true); startAuto(); }, - [startAuto] + [startAuto, total] ); const goTo = useCallback((i: number) => navigate(i + 1), [navigate]);