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