import classNames from "classnames"; import React, { useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { LazyLoadImage } from "react-lazy-load-image-component"; import { useNavigate } from "react-router-dom"; import "react-lazy-load-image-component/src/effects/blur.css"; import { ThinContainer } from "@/components/layout/ThinContainer"; import { WideContainer } from "@/components/layout/WideContainer"; import { HomeLayout } from "@/pages/layouts/HomeLayout"; import { conf } from "@/setup/config"; import { PageTitle } from "./parts/util/PageTitle"; import { get } from "../backend/metadata/tmdb"; import { Icon, Icons } from "../components/Icon"; const pagesToFetch = 8; // Define the Media type interface Media { id: number; poster_path: string; title?: string; name?: string; } // Update the Movie and TVShow interfaces to extend the Media interface interface Movie extends Media { title: string; } interface TVShow extends Media { name: string; } // Define the Genre type interface Genre { id: number; name: string; } // Define the Category type interface Category { name: string; endpoint: string; } // Define the categories const categories: Category[] = [ { name: "Now Playing", endpoint: "/movie/now_playing?language=en-US", }, { name: "Top Rated", endpoint: "/movie/top_rated?language=en-US", }, ]; export function Discover() { const { t } = useTranslation(); const [showBg] = useState(false); const [genres, setGenres] = useState([]); const [randomMovie, setRandomMovie] = useState(null); // Add this line const [genreMovies, setGenreMovies] = useState<{ [genreId: number]: Movie[]; }>({}); const [countdown, setCountdown] = useState(null); const navigate = useNavigate(); // Add a new state variable for the category movies const [categoryMovies, setCategoryMovies] = useState<{ [categoryName: string]: Movie[]; }>({}); useEffect(() => { const fetchMoviesForCategory = async (category: Category) => { try { const movies: any[] = []; for (let page = 1; page <= pagesToFetch; page += 1) { const data = await get(category.endpoint, { api_key: conf().TMDB_READ_API_KEY, language: "en-US", page: page.toString(), }); movies.push(...data.results); } setCategoryMovies((prevCategoryMovies) => ({ ...prevCategoryMovies, [category.name]: movies, })); } catch (error) { console.error( `Error fetching movies for category ${category.name}:`, error, ); } }; categories.forEach(fetchMoviesForCategory); }, []); // Add a new state variable for the TV show genres const [tvGenres, setTVGenres] = useState([]); // Add a new state variable for the TV shows const [tvShowGenres, setTVShowGenres] = useState<{ [genreId: number]: TVShow[]; }>({}); // Fetch TV show genres useEffect(() => { const fetchTVGenres = async () => { try { const data = await get("/genre/tv/list", { api_key: conf().TMDB_READ_API_KEY, language: "en-US", }); // Shuffle the array of genres for (let i = data.genres.length - 1; i > 0; i -= 1) { const j = Math.floor(Math.random() * (i + 1)); [data.genres[i], data.genres[j]] = [data.genres[j], data.genres[i]]; } // Fetch only the first 4 TV show genres setTVGenres(data.genres.slice(0, 4)); } catch (error) { console.error("Error fetching TV show genres:", error); } }; fetchTVGenres(); }, []); // Fetch TV shows for each genre useEffect(() => { const fetchTVShowsForGenre = async (genreId: number) => { try { const tvShows: any[] = []; for (let page = 1; page <= 4; page += 1) { // Fetch only 4 pages const data = await get("/discover/tv", { api_key: conf().TMDB_READ_API_KEY, with_genres: genreId.toString(), language: "en-US", page: page.toString(), }); tvShows.push(...data.results); } setTVShowGenres((prevTVShowGenres) => ({ ...prevTVShowGenres, [genreId]: tvShows, })); } catch (error) { console.error(`Error fetching TV shows for genre ${genreId}:`, error); } }; tvGenres.forEach((genre) => fetchTVShowsForGenre(genre.id)); }, [tvGenres]); // Move the hooks outside of the renderMovies function const carouselRef = useRef(null); const carouselRefs = useRef<{ [key: string]: HTMLDivElement | null }>({}); const gradientRef = useRef(null); // Update the scrollCarousel function to use the new ref map function scrollCarousel(categorySlug: string, direction: string) { const carousel = carouselRefs.current[categorySlug]; if (carousel) { const movieElements = carousel.getElementsByTagName("a"); if (movieElements.length > 0) { const movieWidth = movieElements[0].offsetWidth; const visibleMovies = Math.floor(carousel.offsetWidth / movieWidth); const scrollAmount = movieWidth * visibleMovies; if (direction === "left") { carousel.scrollBy({ left: -scrollAmount, behavior: "smooth" }); } else { carousel.scrollBy({ left: scrollAmount, behavior: "smooth" }); } } } } const [movieWidth, setMovieWidth] = useState( window.innerWidth < 600 ? "150px" : "200px", ); useEffect(() => { const handleResize = () => { setMovieWidth(window.innerWidth < 600 ? "150px" : "200px"); }; window.addEventListener("resize", handleResize); return () => { window.removeEventListener("resize", handleResize); }; }, []); useEffect(() => { if (carouselRef.current && gradientRef.current) { const carouselHeight = carouselRef.current.getBoundingClientRect().height; gradientRef.current.style.top = `${carouselHeight}px`; gradientRef.current.style.bottom = `${carouselHeight}px`; } }, [movieWidth]); // Added movieWidth to the dependency array function renderMovies(medias: Media[], category: string, isTVShow = false) { const categorySlug = category.toLowerCase().replace(/ /g, "-"); // Convert the category to a slug const displayCategory = category === "Now Playing" ? "In Cinemas" : category.includes("Movie") ? `${category}s` : isTVShow ? `${category} Programmes` : `${category} Movies`; return (

{displayCategory}

{ carouselRefs.current[categorySlug] = el; }} style={{ overflowX: "hidden" }} > {medias.slice(0, 20).map((media) => ( ))}
); } const handleRandomMovieClick = () => { const allMovies = Object.values(genreMovies).flat(); // Flatten all movie arrays const uniqueTitles = new Set(); // Use a Set to store unique titles allMovies.forEach((movie) => uniqueTitles.add(movie.title)); // Add each title to the Set const uniqueTitlesArray = Array.from(uniqueTitles); // Convert the Set back to an array const randomIndex = Math.floor(Math.random() * uniqueTitlesArray.length); const selectedMovie = allMovies.find( (movie) => movie.title === uniqueTitlesArray[randomIndex], ); if (selectedMovie) { setRandomMovie(selectedMovie); setCountdown(5); // Schedule navigation after 5 seconds setTimeout(() => { navigate( `/media/tmdb-movie-${selectedMovie.id}-${selectedMovie.title}`, ); }, 5000); } }; // Fetch Movie genres useEffect(() => { const fetchGenres = async () => { try { const data = await get("/genre/movie/list", { api_key: conf().TMDB_READ_API_KEY, language: "en-US", }); // Shuffle the array of genres for (let i = data.genres.length - 1; i > 0; i -= 1) { const j = Math.floor(Math.random() * (i + 1)); [data.genres[i], data.genres[j]] = [data.genres[j], data.genres[i]]; } // Fetch only the first 4 genres setGenres(data.genres.slice(0, 4)); } catch (error) { console.error("Error fetching genres:", error); } }; fetchGenres(); }, []); // Fetch movies for each genre useEffect(() => { const fetchMoviesForGenre = async (genreId: number) => { try { const movies: any[] = []; for (let page = 1; page <= 4; page += 1) { // Fetch only 4 pages const data = await get("/discover/movie", { api_key: conf().TMDB_READ_API_KEY, with_genres: genreId.toString(), language: "en-US", page: page.toString(), }); movies.push(...data.results); } setGenreMovies((prevGenreMovies) => ({ ...prevGenreMovies, [genreId]: movies, })); } catch (error) { console.error(`Error fetching movies for genre ${genreId}:`, error); } }; genres.forEach((genre) => fetchMoviesForGenre(genre.id)); }, [genres]); useEffect(() => { let countdownInterval: NodeJS.Timeout; if (countdown !== null && countdown > 0) { countdownInterval = setInterval(() => { setCountdown((prevCountdown) => prevCountdown !== null ? prevCountdown - 1 : prevCountdown, ); }, 1000); } return () => { clearInterval(countdownInterval); }; }, [countdown]); return (

{t("global.pages.discover")}

<>
{randomMovie && (

Now Playing {randomMovie.title}

{/* You can add additional details or play functionality here */}
)}
{categories.map((category) => (
{renderMovies( categoryMovies[category.name] || [], category.name, )}
))} {genres.map((genre) => (
{renderMovies(genreMovies[genre.id] || [], genre.name)}
))} {tvGenres.map((genre) => (
{renderMovies(tvShowGenres[genre.id] || [], genre.name, true)}
))}
); }