moviebox/src/app/odkrywaj/gatunek/[id]/page.tsx

164 lines
4.7 KiB
TypeScript

import { getMovieGenres, getMoviesByGenre } from "@/lib/tmdb/server";
import { MovieList } from "@/components/molecules/MovieList";
import { FaCalendar, FaFire } from "react-icons/fa";
import { notFound } from "next/navigation";
import { GenreList } from "@/components/molecules/GenreList";
import { BackButton } from "@/components/atoms/BackButton";
// 6 hours cache for genre pages.
export const revalidate = 21600;
type PageProps = {
params: Promise<{ id: string }>;
};
export default async function GenrePage({ params }: PageProps) {
const { id } = await params;
const genreId = parseInt(id);
if (isNaN(genreId)) {
notFound();
}
const { genres } = await getMovieGenres();
const genre = genres.find((g) => g.id === genreId);
if (!genre) {
notFound();
}
const now = new Date();
// Get genre name and all movie data in parallel.
const [recentData, upcomingData, topRatedData] = await Promise.all([
getMoviesByGenre(genreId, 1, {
sort_by: "release_date.desc",
["release_date.lte"]: `${now.getFullYear()}-${
now.getMonth() + 1
}-${now.getDate()}`,
}),
getMoviesByGenre(genreId, 1, {
sort_by: "release_date.asc",
["release_date.gte"]: `${now.getFullYear()}-${now.getMonth() + 1}-${
now.getDate() + 1
} `,
}),
getMoviesByGenre(genreId, 1, {
sort_by: "",
vote_count_gte: "100",
["release_date.lte"]: `${now.getFullYear()}-${
now.getMonth() + 1
}-${now.getDate()}`,
}),
]);
// Convert TMDB movie format to our Movie type.
const convertMovies = (movies: any[]) =>
movies.map((movie) => ({
...movie,
genre_ids: JSON.stringify(movie.genre_ids),
seen: false,
favorite: false,
}));
const recentMovies = convertMovies(recentData.results);
const upcomingMovies = convertMovies(upcomingData.results);
const topRatedMovies = convertMovies(topRatedData.results);
return (
<>
{/* Hero section with genre name */}
<section className="blockp bg-gradient-to-br from-slate-900/50 via-slate-800/30 to-slate-900/50 border-b border-gray-800">
{/* Navigation */}
<div className="relative">
<div className="absolute top-0 left-0 right-0 z-20 px-6">
<BackButton />
</div>
</div>
<div className="container text-center">
<h1 className="text-4xl md:text-6xl font-bold mb-4 bg-gradient-to-r from-purple-400 via-pink-400 to-cyan-400 bg-clip-text text-transparent">
{genre.name}
</h1>
<p className="text-lg text-gray-300 max-w-2xl mx-auto">
Odkryj najlepsze filmy z kategorii {genre.name.toLowerCase()}
</p>
<div className="mt-8 w-32 h-px bg-gradient-to-r from-transparent via-purple-400/50 to-transparent mx-auto" />
</div>
</section>
{/* Recent movies section */}
<section className="blocks">
<MovieList
overrideMovies={recentMovies}
heading="Najnowsze filmy"
loadMore
icon={<FaCalendar />}
colors="green"
showFilters={false}
displayType="list"
/>
</section>
{/* Top rated section */}
{upcomingMovies.length > 0 && (
<section className="blocks">
<MovieList
overrideMovies={upcomingMovies}
heading="Nadchodzące premiery"
loadMore
icon={<FaCalendar />}
colors="blue"
showFilters={false}
sortDirection="desc"
displayType="list"
/>
</section>
)}
{/* Top rated section */}
{topRatedMovies.length > 0 && (
<section className="blocks">
<MovieList
overrideMovies={topRatedMovies}
heading="Najpopularniejsze filmy"
icon={<FaFire />}
colors="red"
showFilters={false}
displayType="list"
/>
</section>
)}
<GenreList heading="Odkryj inne gatunki" />
</>
);
}
export async function generateMetadata({ params }: PageProps) {
const { id } = await params;
const genreId = parseInt(id);
if (isNaN(genreId)) {
return {
title: "Gatunek nie znaleziony",
};
}
try {
const { genres } = await getMovieGenres();
const genre = genres.find((g) => g.id === genreId);
return {
title: genre ? `${genre.name} - Movie Box` : "Gatunek - Movie Box",
description: genre
? `Odkryj najlepsze filmy z kategorii ${genre.name}. Najnowsze premiery, popularne tytuły i najwyżej oceniane produkcje.`
: "Przeglądaj filmy według gatunków",
};
} catch (error) {
return {
title: "Gatunek - Movie Box",
};
}
}