"use client"; import { useState, useEffect, useCallback, useRef } from "react"; import { VideoPlayer, ChannelInfo, ChannelControls, ScheduleOverlay, UpNextBanner, NoSignal, } from "./components"; import type { ScheduleSlot } from "./components"; // --------------------------------------------------------------------------- // Mock data — replace with TanStack Query hooks once the API is ready // --------------------------------------------------------------------------- interface MockChannel { number: number; name: string; src?: string; schedule: ScheduleSlot[]; current: { title: string; startTime: string; endTime: string; progress: number; description?: string; }; next: { title: string; startTime: string; minutesUntil: number; }; } const MOCK_CHANNELS: MockChannel[] = [ { number: 1, name: "Cinema Classic", schedule: [ { id: "c1-1", title: "The Maltese Falcon", startTime: "17:00", endTime: "18:45" }, { id: "c1-2", title: "Casablanca", startTime: "18:45", endTime: "20:30", isCurrent: true }, { id: "c1-3", title: "Sunset Boulevard", startTime: "20:30", endTime: "22:15" }, { id: "c1-4", title: "Rear Window", startTime: "22:15", endTime: "00:00" }, ], current: { title: "Casablanca", startTime: "18:45", endTime: "20:30", progress: 72, description: "A cynical American expatriate struggles to decide whether or not he should help his former lover and her fugitive husband escape French Morocco.", }, next: { title: "Sunset Boulevard", startTime: "20:30", minutesUntil: 23 }, }, { number: 2, name: "Nature & Wild", schedule: [ { id: "c2-1", title: "Planet Earth II", startTime: "19:00", endTime: "20:00", isCurrent: true }, { id: "c2-2", title: "Blue Planet", startTime: "20:00", endTime: "21:00" }, { id: "c2-3", title: "Africa", startTime: "21:00", endTime: "22:00" }, ], current: { title: "Planet Earth II", startTime: "19:00", endTime: "20:00", progress: 85, description: "David Attenborough explores the world's most iconic landscapes and the remarkable animals that inhabit them.", }, next: { title: "Blue Planet", startTime: "20:00", minutesUntil: 9 }, }, { number: 3, name: "Sci-Fi Zone", schedule: [ { id: "c3-1", title: "2001: A Space Odyssey", startTime: "19:30", endTime: "22:10", isCurrent: true }, { id: "c3-2", title: "Blade Runner", startTime: "22:10", endTime: "00:17" }, ], current: { title: "2001: A Space Odyssey", startTime: "19:30", endTime: "22:10", progress: 40, description: "After discovering a mysterious artifact, mankind sets off on a quest to find its origins with help from intelligent supercomputer H.A.L. 9000.", }, next: { title: "Blade Runner", startTime: "22:10", minutesUntil: 96 }, }, ]; // --------------------------------------------------------------------------- const IDLE_TIMEOUT_MS = 3500; const BANNER_THRESHOLD = 80; // show "up next" banner when progress ≥ this export default function TvPage() { const [channelIdx, setChannelIdx] = useState(0); const [showOverlays, setShowOverlays] = useState(true); const [showSchedule, setShowSchedule] = useState(false); const idleTimer = useRef | null>(null); const channel = MOCK_CHANNELS[channelIdx]; const showBanner = channel.current.progress >= BANNER_THRESHOLD; // ------------------------------------------------------------------ // Idle detection — hide overlays after inactivity // ------------------------------------------------------------------ const resetIdle = useCallback(() => { setShowOverlays(true); if (idleTimer.current) clearTimeout(idleTimer.current); idleTimer.current = setTimeout(() => setShowOverlays(false), IDLE_TIMEOUT_MS); }, []); useEffect(() => { resetIdle(); return () => { if (idleTimer.current) clearTimeout(idleTimer.current); }; }, [resetIdle]); // ------------------------------------------------------------------ // Channel switching // ------------------------------------------------------------------ const prevChannel = useCallback(() => { setChannelIdx((i) => (i - 1 + MOCK_CHANNELS.length) % MOCK_CHANNELS.length); resetIdle(); }, [resetIdle]); const nextChannel = useCallback(() => { setChannelIdx((i) => (i + 1) % MOCK_CHANNELS.length); resetIdle(); }, [resetIdle]); const toggleSchedule = useCallback(() => { setShowSchedule((s) => !s); resetIdle(); }, [resetIdle]); // ------------------------------------------------------------------ // Keyboard shortcuts // ------------------------------------------------------------------ useEffect(() => { const handleKey = (e: KeyboardEvent) => { // Don't steal input from focused form elements if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return; switch (e.key) { case "ArrowUp": case "PageUp": e.preventDefault(); nextChannel(); break; case "ArrowDown": case "PageDown": e.preventDefault(); prevChannel(); break; case "g": case "G": toggleSchedule(); break; } }; window.addEventListener("keydown", handleKey); return () => window.removeEventListener("keydown", handleKey); }, [nextChannel, prevChannel, toggleSchedule]); // ------------------------------------------------------------------ // Render // ------------------------------------------------------------------ return (
{/* ── Base layer ─────────────────────────────────────────────── */} {channel.src ? ( ) : (
)} {/* ── Overlays ───────────────────────────────────────────────── */}
{/* Top-right: guide toggle */}
{/* Bottom: banner + info row */}
{showBanner && ( )}
{/* Schedule overlay — outside the fading div so it has its own visibility */} {showOverlays && showSchedule && (
)}
); }