"use client"; import Image from "next/image"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import type { CSSProperties } from "react"; export interface SliderPhoto { src: string; alt: string; id?: string | number; } const ROTATE_MS = 5500; // --- 1. SLIDE COMPONENT --- interface SlideProps { photo: SliderPhoto; } function PromoStripSingleSlide({ photo }: SlideProps) { return (
{photo.alt}
); } // --- 2. DATA HOOK --- function useSliderPhotos(): { photos: SliderPhoto[]; loading: boolean } { const [photos, setPhotos] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { let cancelled = false; fetch("/api/slider-photos", { cache: "no-store" }) .then((r) => (r.ok ? r.json() : [])) .then((data: unknown) => { if (cancelled) return; if (Array.isArray(data)) { const validated = data.filter( (x): x is SliderPhoto => typeof x === "object" && x !== null && "src" in x && "alt" in x ); setPhotos(validated); } }) .catch(() => { if (!cancelled) setPhotos([]); }) .finally(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; }, []); return { photos, loading }; } // --- 3. MAIN COMPONENT --- export function TvonePromoStrip() { const { photos, loading } = useSliderPhotos(); const [index, setIndex] = useState(0); const [reduceMotion, setReduceMotion] = useState(false); // Constants for the 4.8:1 ratio const FIXED_RATIO = 4.8 / 1; useEffect(() => { const mq = window.matchMedia("(prefers-reduced-motion: reduce)"); const sync = () => setReduceMotion(mq.matches); sync(); mq.addEventListener("change", sync); return () => mq.removeEventListener("change", sync); }, []); const advance = useCallback(() => { if (photos.length <= 1) return; setIndex((i: number) => (i + 1) % photos.length); }, [photos.length]); useEffect(() => { if (photos.length <= 1 || reduceMotion) return; const id = window.setInterval(advance, ROTATE_MS); return () => window.clearInterval(id); }, [photos.length, reduceMotion, advance]); // Loading state with fixed ratio if (loading && photos.length === 0) { return (
); } if (photos.length === 0) return null; return (
{/* THE TRACK */}
{photos.map((photo: SliderPhoto, i: number) => (
))}
{/* INDICATORS */} {photos.length > 1 && (
{photos.map((_, i: number) => (
)}
); }