import { useCallback, useEffect, useState } from "react" import { arr, str, type CaseStudy } from "./types" const ROTATE_MS = 8000 /** * Customer case-study carousel. * * TODO(copy): populate `frontmatter.sections` with real case studies. With no * items this renders nothing; with exactly one it degrades to a static card. * * Rotation is suspended when the visitor prefers reduced motion, and pauses * while the carousel is hovered or focused. */ export function Cases({ items }: { items?: CaseStudy[] }) { const studies = (arr(items) ?? []).filter((item) => str(item?.company)) const [active, setActive] = useState(0) const [paused, setPaused] = useState(false) const count = studies.length const go = useCallback( (next: number) => setActive(count > 0 ? ((next % count) + count) % count : 0), [count] ) useEffect(() => { if (count <= 1 || paused) return if ( typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ) { return } const timer = window.setInterval(() => setActive((current) => (current + 1) % count), ROTATE_MS) return () => window.clearInterval(timer) }, [count, paused]) if (count === 0) return null const current = studies[Math.min(active, count - 1)] const company = str(current.company) ?? "" const quote = str(current.quote) const details = str(current.details) const author = str(current.author) const role = str(current.role) const link = str(current.link) const logo = str(current.logo) return (
setPaused(true)} onMouseLeave={() => setPaused(false)} onFocus={() => setPaused(true)} onBlur={() => setPaused(false)}>
{logo && {company}} {quote && (
{quote}
)} {/* Without an approved testimonial, describe the engagement instead. */} {!quote && details && (

{details}

)}
{author && {author}} {author && role && · } {role} {link ? ( <> {" · "} {company} ) : ( company && · {company} )}
{count > 1 && (
{studies.map((study, index) => (
)}
) }