diff --git a/frontend/src/components/LogoCarousel.tsx b/frontend/src/components/LogoCarousel.tsx index 22aa206891..b6490da097 100644 --- a/frontend/src/components/LogoCarousel.tsx +++ b/frontend/src/components/LogoCarousel.tsx @@ -1,6 +1,5 @@ import Image from 'next/image' import Link from 'next/link' -import { useEffect, useRef } from 'react' import type { Sponsor } from 'types/home' interface MovingLogosProps { @@ -8,54 +7,52 @@ interface MovingLogosProps { } export default function MovingLogos({ sponsors }: Readonly) { - const scrollerRef = useRef(null) + // Keep duration behavior stable even when sponsors is empty. + const animationDurationSeconds = Math.max(sponsors.length, 1) * 2 - useEffect(() => { - if (scrollerRef.current) { - const scrollContainer = scrollerRef.current - // Clone and append children for infinite scroll effect. - const children = Array.from(scrollContainer.children) - children.forEach((child) => { - scrollContainer.appendChild(child.cloneNode(true)) - }) - } - }, [sponsors]) + const renderSponsorCard = (sponsor: Sponsor, index: number, keySuffix: string) => { + // Include `index` to guarantee uniqueness even if `sponsor.id` repeats (e.g. in tests). + const keyBase = sponsor.id + ? `${sponsor.id}-${index}` + : `${sponsor.url || sponsor.name || 'sponsor'}-${index}` + + return ( +
+ +
+ {sponsor.imageUrl ? ( + {sponsor.name + ) : ( + {sponsor.name} + )} +
+ +
+ ) + } return (
- {sponsors.map((sponsor, index) => ( -
- -
- {sponsor.imageUrl ? ( - {sponsor.name - ) : ( - {sponsor.name} - )} -
- -
- ))} + {sponsors.map((sponsor, index) => renderSponsorCard(sponsor, index, ''))} + {sponsors.map((sponsor, index) => renderSponsorCard(sponsor, index, 'loop'))}