feat: enhance actor details page with MovieGallery and Carousel components; implement movie conversion helper for improved movie data handling
This commit is contained in:
parent
cf7ec070fd
commit
3c286e705c
|
|
@ -1,5 +1,10 @@
|
||||||
|
import { MovieCard } from "@/components/atoms/MovieCard";
|
||||||
import { ActorHero } from "@/components/molecules/ActorHero";
|
import { ActorHero } from "@/components/molecules/ActorHero";
|
||||||
|
import { Carousel } from "@/components/molecules/Carousel";
|
||||||
|
import { MovieGallery } from "@/components/molecules/MovieGallery";
|
||||||
|
import { convertToMovie } from "@/helpers/convertToMovie";
|
||||||
import { TMDB } from "@/lib/tmdb";
|
import { TMDB } from "@/lib/tmdb";
|
||||||
|
import { FaStar } from "react-icons/fa";
|
||||||
|
|
||||||
export default async function Page({
|
export default async function Page({
|
||||||
params,
|
params,
|
||||||
|
|
@ -9,10 +14,29 @@ export default async function Page({
|
||||||
const actorId = Number((await params).id);
|
const actorId = Number((await params).id);
|
||||||
|
|
||||||
const personDetails = await TMDB.getPersonDetails(actorId);
|
const personDetails = await TMDB.getPersonDetails(actorId);
|
||||||
|
const images = {
|
||||||
|
backdrops: personDetails.images.profiles,
|
||||||
|
posters: [],
|
||||||
|
logos: [],
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900">
|
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 pb-16">
|
||||||
<ActorHero personDetails={personDetails} />
|
<ActorHero personDetails={personDetails} />
|
||||||
|
<MovieGallery images={images} movieTitle={personDetails.name} />
|
||||||
|
<div className="container">
|
||||||
|
<Carousel
|
||||||
|
heading={`Filmy z udziałem ${personDetails.name}`}
|
||||||
|
icon={<FaStar />}
|
||||||
|
colors="purple"
|
||||||
|
>
|
||||||
|
{personDetails.movie_credits.cast.map((movie) => {
|
||||||
|
const convertedMovie = convertToMovie(movie);
|
||||||
|
if (!convertedMovie) return null;
|
||||||
|
return <MovieCard key={movie.id} {...convertedMovie} />;
|
||||||
|
})}
|
||||||
|
</Carousel>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export default async function Page({
|
||||||
params: Promise<{ id: string }>;
|
params: Promise<{ id: string }>;
|
||||||
}) {
|
}) {
|
||||||
const movieId = Number((await params).id);
|
const movieId = Number((await params).id);
|
||||||
const movieDetails = await TMDB.getMovieDetailsRich(movieId);
|
const movieDetails = await TMDB.getMovieDetails(movieId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen mt-16">
|
<div className="min-h-screen mt-16">
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ type Props = Movie & {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MovieCard: FC<Props> = ({
|
export const MovieCard: FC<Props> = ({
|
||||||
layout = "minimal",
|
layout = "aurora",
|
||||||
showDayCounter = true,
|
showDayCounter = true,
|
||||||
simpleToggle = false,
|
simpleToggle = false,
|
||||||
...movie
|
...movie
|
||||||
|
|
@ -73,6 +73,8 @@ export const MovieCard: FC<Props> = ({
|
||||||
simpleToggle,
|
simpleToggle,
|
||||||
buttonClass,
|
buttonClass,
|
||||||
iconSize,
|
iconSize,
|
||||||
|
favorite: alreadyInStore?.favorite || movie.favorite,
|
||||||
|
seen: alreadyInStore?.seen || movie.seen,
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (layout) {
|
switch (layout) {
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ export const AuroraLayout: FC<AuroraLayoutProps> = ({
|
||||||
>
|
>
|
||||||
<Link href={`/film/${id}`}>
|
<Link href={`/film/${id}`}>
|
||||||
<img
|
<img
|
||||||
className="w-full h-full object-cover transition-all duration-700 group-hover:scale-110 group-hover:brightness-110"
|
className="w-full h-full object-cover transition-all duration-700 group-hover:scale-110 group-hover:brightness-110 bg-gradient-to-b from-purple-600/50 to-emerald-600"
|
||||||
src={`http://image.tmdb.org/t/p/w342${poster_path}`}
|
src={`http://image.tmdb.org/t/p/w342${poster_path}`}
|
||||||
alt={title}
|
alt={title}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,7 @@ export const ActorHero: FC<Props> = ({ personDetails }) => {
|
||||||
];
|
];
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
|
key={key}
|
||||||
href={url(value as string)}
|
href={url(value as string)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
|
|
@ -257,14 +258,4 @@ const externalIdsMap = {
|
||||||
icon: <FaImdb />,
|
icon: <FaImdb />,
|
||||||
url: (id: string) => `https://www.imdb.com/name/${id}`,
|
url: (id: string) => `https://www.imdb.com/name/${id}`,
|
||||||
},
|
},
|
||||||
tvrage_id: {
|
|
||||||
label: "TVRage",
|
|
||||||
icon: null,
|
|
||||||
url: (id: string) => `https://www.tvrage.com/people/${id}`,
|
|
||||||
},
|
|
||||||
wikidata_id: {
|
|
||||||
label: "Wikidata",
|
|
||||||
icon: null,
|
|
||||||
url: (id: string) => `https://www.wikidata.org/wiki/${id}`,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import {
|
||||||
FaGlobe,
|
FaGlobe,
|
||||||
FaEye,
|
FaEye,
|
||||||
} from "react-icons/fa";
|
} from "react-icons/fa";
|
||||||
|
import { convertToMovie } from "@/helpers/convertToMovie";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
movieDetails: MovieDetailsRich;
|
movieDetails: MovieDetailsRich;
|
||||||
|
|
@ -33,37 +34,24 @@ export const HeroMovie: FC<Props> = ({ movieDetails }) => {
|
||||||
return `${hours}h ${mins}m`;
|
return `${hours}h ${mins}m`;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert TMDB movie to our Movie type.
|
const convertedMovie = convertToMovie(movieDetails);
|
||||||
const convertToMovie = () => ({
|
|
||||||
id: movieDetails.id,
|
|
||||||
title: movieDetails.title,
|
|
||||||
adult: movieDetails.adult,
|
|
||||||
backdrop_path: movieDetails.backdrop_path || "",
|
|
||||||
genre_ids: movieDetails.genres.map((g) => g.id).join(","),
|
|
||||||
original_language: movieDetails.original_language,
|
|
||||||
original_title: movieDetails.original_title,
|
|
||||||
overview: movieDetails.overview || "",
|
|
||||||
popularity: movieDetails.popularity,
|
|
||||||
poster_path: movieDetails.poster_path || "",
|
|
||||||
release_date: movieDetails.release_date,
|
|
||||||
video: movieDetails.video,
|
|
||||||
vote_average: movieDetails.vote_average,
|
|
||||||
vote_count: movieDetails.vote_count,
|
|
||||||
favorite: false,
|
|
||||||
seen: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// Convert TMDB movie to our Movie type.
|
||||||
const handleAddToList = () => {
|
const handleAddToList = () => {
|
||||||
if (isInStore) {
|
if (isInStore) {
|
||||||
deleteMovie(movieDetails.id);
|
deleteMovie(movieDetails.id);
|
||||||
} else {
|
} else {
|
||||||
addMovie(convertToMovie());
|
if (convertedMovie) {
|
||||||
|
addMovie(convertedMovie);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleToggleFavorite = () => {
|
const handleToggleFavorite = () => {
|
||||||
if (!isInStore) {
|
if (!isInStore) {
|
||||||
addMovie({ ...convertToMovie(), favorite: true });
|
if (convertedMovie) {
|
||||||
|
addMovie({ ...convertedMovie, favorite: true });
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
updateMovie(movieDetails.id, { favorite: !isFavorite });
|
updateMovie(movieDetails.id, { favorite: !isFavorite });
|
||||||
}
|
}
|
||||||
|
|
@ -71,7 +59,9 @@ export const HeroMovie: FC<Props> = ({ movieDetails }) => {
|
||||||
|
|
||||||
const handleToggleSeen = () => {
|
const handleToggleSeen = () => {
|
||||||
if (!isInStore) {
|
if (!isInStore) {
|
||||||
addMovie({ ...convertToMovie(), seen: true });
|
if (convertedMovie) {
|
||||||
|
addMovie({ ...convertedMovie, seen: true });
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
updateMovie(movieDetails.id, { seen: !isSeen });
|
updateMovie(movieDetails.id, { seen: !isSeen });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export const RecommendedMovies: FC<Props> = ({ movies }) => {
|
||||||
<Carousel
|
<Carousel
|
||||||
heading="Rekomendowane filmy"
|
heading="Rekomendowane filmy"
|
||||||
icon={<FaStar />}
|
icon={<FaStar />}
|
||||||
iconColor="bg-gradient-to-r from-yellow-500 to-orange-500"
|
colors="yellow"
|
||||||
>
|
>
|
||||||
{movies.results.map((movie) => (
|
{movies.results.map((movie) => (
|
||||||
<MovieCard
|
<MovieCard
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { Movie } from "@/types/global";
|
||||||
|
|
||||||
|
export const convertToMovie = (
|
||||||
|
movie: any,
|
||||||
|
override?: Partial<Movie>
|
||||||
|
): Movie | null => {
|
||||||
|
if (!movie.id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: movie.id,
|
||||||
|
title: movie.title,
|
||||||
|
adult: movie.adult,
|
||||||
|
backdrop_path: movie.backdrop_path || "",
|
||||||
|
genre_ids: movie.genres?.join(",") || "",
|
||||||
|
original_language: movie.original_language,
|
||||||
|
original_title: movie.original_title,
|
||||||
|
overview: movie.overview || "",
|
||||||
|
popularity: movie.popularity,
|
||||||
|
poster_path: movie.poster_path || "",
|
||||||
|
release_date: movie.release_date,
|
||||||
|
video: movie.video,
|
||||||
|
vote_average: movie.vote_average,
|
||||||
|
vote_count: movie.vote_count,
|
||||||
|
favorite: false,
|
||||||
|
seen: false,
|
||||||
|
};
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue