"use client"; import { useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; import Link from "next/link"; import type { TMDBMovie } from "@/types/tmdb"; import { TMDB_GENRE_MAP, getTMDBImageUrl } from "@/types/tmdb"; interface MoreInfoModalProps { movie: TMDBMovie; onClose: () => void; } export function MoreInfoModal({ movie, onClose }: MoreInfoModalProps) { const [mounted, setMounted] = useState(false); const [trailerUrl, setTrailerUrl] = useState(null); const [trailerStatus, setTrailerStatus] = useState<"loading" | "ready" | "none" | "error">( "loading", ); const dialogRef = useRef(null); const closeBtnRef = useRef(null); useEffect(() => { // Standard SSR-safe portal mount flag — intentional setState-in-effect. // eslint-disable-next-line react-hooks/set-state-in-effect setMounted(true); }, []); const year = movie.release_date ? movie.release_date.slice(0, 4) : ""; const genres = movie.genre_ids .map((id) => TMDB_GENRE_MAP[id]) .filter(Boolean) .slice(0, 4); const posterUrl = getTMDBImageUrl(movie.poster_path, "panel"); useEffect(() => { let cancelled = false; fetch(`/api/tmdb/movie/${movie.id}/videos`) .then((res) => res.json()) .then((data: { trailerUrl: string | null }) => { if (cancelled) return; if (data.trailerUrl) { setTrailerUrl(data.trailerUrl); setTrailerStatus("ready"); } else { setTrailerStatus("none"); } }) .catch(() => { if (!cancelled) setTrailerStatus("error"); }); return () => { cancelled = true; }; }, [movie.id]); useEffect(() => { const previouslyFocused = document.activeElement as HTMLElement | null; closeBtnRef.current?.focus(); function handleKey(e: KeyboardEvent) { if (e.key === "Escape") { e.stopPropagation(); onClose(); } if (e.key === "Tab" && dialogRef.current) { const focusables = Array.from( dialogRef.current.querySelectorAll( 'button, a[href], [tabindex]:not([tabindex="-1"])', ), ).filter((el) => !el.hasAttribute("disabled")); if (focusables.length === 0) return; const first = focusables[0]; const last = focusables[focusables.length - 1]; if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); } else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); } } } document.addEventListener("keydown", handleKey); return () => { document.removeEventListener("keydown", handleKey); previouslyFocused?.focus?.(); }; }, [onClose]); if (!mounted) return null; return createPortal(
e.stopPropagation()} > {posterUrl && ( /* eslint-disable-next-line @next/next/no-img-element */ {`Poster )}

{movie.title} {year && ({year})}

{genres.length > 0 && (
{genres.map((genre) => ( {genre} ))}
)} {movie.overview && (

{movie.overview}

)}
Add to list {trailerStatus === "ready" && trailerUrl ? ( Watch Trailer ) : ( )}
, document.body, ); }