|
"use client"; |
|
import apiClient from "@/api/apiClient"; |
|
import { useEffect, useState, useRef } from "react"; |
|
import Link from "next/link"; |
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; |
|
import { |
|
faCaretLeft, |
|
faCaretRight, |
|
faFilter, |
|
faTimes, |
|
faXmark, |
|
} from "@fortawesome/free-solid-svg-icons"; |
|
import Image from "next/image"; |
|
import "./genres.css"; |
|
import GenreFilterModal from "@/modals/GenreFilterModal"; |
|
import { Spinner } from "@/components/Spinner"; |
|
|
|
export default function GenrePage({ params }) { |
|
const [genreItems, setGenreItems] = useState(null); |
|
const [loading, setLoading] = useState(true); |
|
const [error, setError] = useState(null); |
|
const [itemLimit, setItemLimit] = useState(10); |
|
const [selectedGenres, setSelectedGenres] = useState( |
|
new Set(params.genre ? decodeURIComponent(params.genre).split(",") : []) |
|
); |
|
const [isModalOpen, setIsModalOpen] = useState(false); |
|
|
|
const moviesRef = useRef(null); |
|
const seriesRef = useRef(null); |
|
|
|
useEffect(() => { |
|
async function fetchData() { |
|
try { |
|
if (selectedGenres.size === 0) { |
|
setGenreItems({ movies: [], series: [] }); |
|
setLoading(false); |
|
return; |
|
} |
|
|
|
const genreArray = Array.from(selectedGenres); |
|
const data = await apiClient.getGenreItems(genreArray, null, itemLimit); |
|
if (data) { |
|
setGenreItems(data); |
|
console.log(data); |
|
} else { |
|
setError("Genre data not found."); |
|
} |
|
} catch (err) { |
|
setError(err.message || "An error occurred while fetching genre data."); |
|
console.log(err); |
|
} finally { |
|
setLoading(false); |
|
} |
|
} |
|
fetchData(); |
|
}, [selectedGenres, itemLimit]); |
|
|
|
const loadMore = () => { |
|
setItemLimit((prevLimit) => prevLimit + 5); |
|
}; |
|
|
|
const scroll = (ref, direction) => { |
|
if (ref.current) { |
|
const scrollAmount = direction === "left" ? -360 : 360; |
|
ref.current.scrollBy({ left: scrollAmount, behavior: "smooth" }); |
|
} |
|
}; |
|
|
|
const openModal = () => setIsModalOpen(true); |
|
const closeModal = () => setIsModalOpen(false); |
|
|
|
const removeGenre = (genreToRemove) => { |
|
setSelectedGenres((prevGenres) => { |
|
const updatedGenres = new Set(prevGenres); |
|
updatedGenres.delete(genreToRemove); |
|
return updatedGenres; |
|
}); |
|
}; |
|
|
|
if (loading) { |
|
return ( |
|
<div className="loading"> |
|
<Spinner /> |
|
</div> |
|
); |
|
} |
|
|
|
return ( |
|
<div className="genre-page"> |
|
<div className="genre-title-section"></div> |
|
<div className="genre-bubbles"> |
|
<button className="genre-filter-button" onClick={openModal}> |
|
<FontAwesomeIcon icon={faFilter} size="sm" /> |
|
</button> |
|
<div className="genre-bubbles-scroll-section"> |
|
{selectedGenres.size > 0 |
|
? Array.from(selectedGenres).map((genre, index) => ( |
|
<div key={index} className="bubbles"> |
|
{genre} |
|
<button |
|
className="genre-bubble-close-button" |
|
onClick={() => removeGenre(genre)} |
|
> |
|
<FontAwesomeIcon icon={faXmark} size="sm" /> |
|
</button> |
|
</div> |
|
)) |
|
: "Select Genres"} |
|
</div> |
|
</div> |
|
<GenreFilterModal |
|
isOpen={isModalOpen} |
|
onClose={closeModal} |
|
selectedGenres={selectedGenres} |
|
onGenreChange={setSelectedGenres} |
|
/> |
|
|
|
{genreItems && ( |
|
<> |
|
{genreItems.movies && genreItems.movies.length > 0 && ( |
|
<section className="genre-section movies"> |
|
<div className="genre-section-controls"> |
|
<h2>Movies</h2> |
|
<div className="load-more-container"> |
|
<button className="load-more-button" onClick={loadMore}> |
|
Load More |
|
</button> |
|
</div> |
|
<div className="genre-scroll-controls"> |
|
<button |
|
onClick={() => scroll(moviesRef, "left")} |
|
className="genre-scroll-button" |
|
> |
|
<FontAwesomeIcon icon={faCaretLeft} size="2xl" /> |
|
</button> |
|
<button |
|
onClick={() => scroll(moviesRef, "right")} |
|
className="genre-scroll-button" |
|
> |
|
<FontAwesomeIcon icon={faCaretRight} size="2xl" /> |
|
</button> |
|
</div> |
|
</div> |
|
<div className="genre-items-grid" ref={moviesRef}> |
|
{genreItems.movies.map((item, index) => ( |
|
<div key={index} className="genre-item-card"> |
|
<Link href={`/movie/${item[0]}`} passHref> |
|
<div className="genre-item-link"> |
|
<Image |
|
src={ |
|
item[3] || |
|
`https://via.placeholder.com/300x80/1a1c3f/FFF?text=${encodeURIComponent( |
|
item[0] |
|
)}` |
|
} |
|
alt={item[0]} |
|
className="genre-item-image" |
|
height={80} |
|
width={300} |
|
/> |
|
<div className="genre-item-info"> |
|
<h3 className="genre-item-title">{item[0]}</h3> |
|
<p className="genre-item-description">{item[2]}</p> |
|
</div> |
|
</div> |
|
</Link> |
|
</div> |
|
))} |
|
</div> |
|
</section> |
|
)} |
|
|
|
{genreItems.series && genreItems.series.length > 0 && ( |
|
<section className="genre-section series"> |
|
<div className="genre-section-controls"> |
|
<h2>TV Shows</h2> |
|
<div className="genre-scroll-controls"> |
|
<button |
|
onClick={() => scroll(seriesRef, "left")} |
|
className="genre-scroll-button" |
|
> |
|
<FontAwesomeIcon icon={faCaretLeft} size="2xl" /> |
|
</button> |
|
<button |
|
onClick={() => scroll(seriesRef, "right")} |
|
className="genre-scroll-button" |
|
> |
|
<FontAwesomeIcon icon={faCaretRight} size="2xl" /> |
|
</button> |
|
</div> |
|
</div> |
|
<div className="genre-items-grid" ref={seriesRef}> |
|
{genreItems.series.map((item, index) => ( |
|
<div key={index} className="genre-item-card"> |
|
<Link href={`/series/${item[0]}`} passHref> |
|
<div className="genre-item-link"> |
|
<Image |
|
src={ |
|
item[3] || |
|
`https://via.placeholder.com/300x80?text=${encodeURIComponent( |
|
item[0] |
|
)}` |
|
} |
|
alt={item[0]} |
|
className="genre-item-image" |
|
width={300} |
|
height={80} |
|
/> |
|
<div className="genre-item-info"> |
|
<h3 className="genre-item-title">{item[0]}</h3> |
|
<p className="genre-item-description">{item[2]}</p> |
|
</div> |
|
</div> |
|
</Link> |
|
</div> |
|
))} |
|
</div> |
|
</section> |
|
)} |
|
</> |
|
)} |
|
|
|
{(!genreItems || |
|
(genreItems.movies.length === 0 && genreItems.series.length === 0)) && ( |
|
<p className="genre-no-items"> |
|
{selectedGenres.size === 0 |
|
? "Please select a genre to see results." |
|
: "No items available for the selected genres."} |
|
</p> |
|
)} |
|
</div> |
|
); |
|
} |
|
|