258 lines
9.4 KiB
TypeScript
258 lines
9.4 KiB
TypeScript
"use client";
|
|
import { BackButton } from "@/components/atoms/BackButton";
|
|
import { Button } from "@/components/atoms/Button";
|
|
import { GenreLabel } from "@/components/atoms/GenreLabel";
|
|
import { MovieDetailsRich } from "@/lib/tmdb/types";
|
|
import { useGlobalStore } from "@/app/store/globalStore";
|
|
import { FC } from "react";
|
|
import {
|
|
FaHeart,
|
|
FaBookmark,
|
|
FaClock,
|
|
FaCalendar,
|
|
FaGlobe,
|
|
FaEye,
|
|
} from "react-icons/fa";
|
|
import { convertToMovie } from "@/helpers/convertToMovie";
|
|
|
|
type Props = {
|
|
movieDetails: MovieDetailsRich;
|
|
};
|
|
|
|
export const HeroMovie: FC<Props> = ({ movieDetails }) => {
|
|
const { movies, addMovie, deleteMovie, updateMovie } = useGlobalStore();
|
|
|
|
// Check if movie is in store and get its state.
|
|
const movieInStore = movies.find((m) => m.id === movieDetails.id);
|
|
const isInStore = !!movieInStore;
|
|
const isFavorite = movieInStore?.favorite || false;
|
|
const isSeen = movieInStore?.seen || false;
|
|
const loading = movies.length === 0;
|
|
|
|
const formatRuntime = (minutes: number) => {
|
|
const hours = Math.floor(minutes / 60);
|
|
const mins = minutes % 60;
|
|
return `${hours}h ${mins}m`;
|
|
};
|
|
|
|
const convertedMovie = convertToMovie(movieDetails);
|
|
|
|
// Convert TMDB movie to our Movie type.
|
|
const handleAddToList = () => {
|
|
if (isInStore) {
|
|
deleteMovie(movieDetails.id);
|
|
} else {
|
|
if (convertedMovie) {
|
|
addMovie(convertedMovie);
|
|
}
|
|
}
|
|
};
|
|
|
|
const handleToggleFavorite = () => {
|
|
if (!isInStore) {
|
|
if (convertedMovie) {
|
|
addMovie({ ...convertedMovie, favorite: true, seen: true });
|
|
}
|
|
} else {
|
|
updateMovie(movieDetails.id, {
|
|
favorite: !isFavorite,
|
|
seen: isSeen || !isFavorite,
|
|
});
|
|
}
|
|
};
|
|
|
|
const handleToggleSeen = () => {
|
|
if (!isInStore) {
|
|
if (convertedMovie) {
|
|
addMovie({ ...convertedMovie, seen: true });
|
|
}
|
|
} else {
|
|
updateMovie(movieDetails.id, {
|
|
seen: !isSeen,
|
|
favorite: false,
|
|
});
|
|
}
|
|
};
|
|
|
|
return (
|
|
<section className="my-16">
|
|
<div className="relative">
|
|
{/* Navigation */}
|
|
<div className="absolute top-0 left-0 right-0 z-20 px-6">
|
|
<BackButton />
|
|
</div>
|
|
|
|
{/* Main content */}
|
|
<div className="relative z-10 px-6 lg:px-8">
|
|
<div className="max-w-7xl mx-auto">
|
|
<div className="flex flex-col lg:flex-row gap-8">
|
|
{/* Movie poster */}
|
|
<div className="flex-shrink-0">
|
|
<div className="relative group">
|
|
<img
|
|
src={`https://image.tmdb.org/t/p/w500${movieDetails.poster_path}`}
|
|
alt={movieDetails.title}
|
|
className="w-80 h-auto rounded-2xl shadow-2xl shadow-purple-500/20 group-hover:shadow-purple-500/40 transition-all duration-500"
|
|
/>
|
|
<div className="absolute inset-0 rounded-2xl bg-gradient-to-t from-purple-600/20 to-transparent opacity-100" />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Movie details */}
|
|
<div className="flex-1 text-white">
|
|
<div className="space-y-6">
|
|
{/* Title and rating */}
|
|
<div>
|
|
<h1 className="text-4xl lg:text-5xl font-bold bg-gradient-to-r from-white to-gray-300 bg-clip-text text-transparent mb-3">
|
|
{movieDetails.title}
|
|
</h1>
|
|
{movieDetails.tagline && (
|
|
<p className="text-xl text-gray-300 italic mb-4">
|
|
"{movieDetails.tagline}"
|
|
</p>
|
|
)}
|
|
|
|
<div className="flex items-center gap-6 flex-wrap">
|
|
<div className="flex items-center gap-2">
|
|
<div className="flex">
|
|
{[...Array(5)].map((_, i) => (
|
|
<span
|
|
key={i}
|
|
className={`text-2xl ${
|
|
i < Math.round(movieDetails.vote_average / 2)
|
|
? "text-yellow-400"
|
|
: "text-gray-600"
|
|
}`}
|
|
>
|
|
★
|
|
</span>
|
|
))}
|
|
</div>
|
|
<span className="text-lg font-semibold">
|
|
{movieDetails.vote_average.toFixed(1)}
|
|
</span>
|
|
<span className="text-gray-400">
|
|
({movieDetails.vote_count} głosów)
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Key info */}
|
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
|
{movieDetails.release_date && (
|
|
<div className="flex items-center gap-2 text-gray-300">
|
|
<FaCalendar className="text-purple-400" />
|
|
<span>
|
|
{new Date(movieDetails.release_date).getFullYear()}
|
|
</span>
|
|
</div>
|
|
)}
|
|
|
|
{movieDetails.runtime && (
|
|
<div className="flex items-center gap-2 text-gray-300">
|
|
<FaClock className="text-purple-400" />
|
|
<span>{formatRuntime(movieDetails.runtime)}</span>
|
|
</div>
|
|
)}
|
|
|
|
{movieDetails.spoken_languages[0] && (
|
|
<div className="flex items-center gap-2 text-gray-300">
|
|
<FaGlobe className="text-purple-400" />
|
|
<span>{movieDetails.spoken_languages[0].name}</span>
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex items-center gap-2 text-gray-300">
|
|
<span className="text-purple-400">Status:</span>
|
|
<span>{movieDetails.status}</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Genres */}
|
|
{movieDetails.genres.length > 0 && (
|
|
<div>
|
|
<h3 className="text-lg font-semibold mb-3 text-purple-300">
|
|
Gatunki
|
|
</h3>
|
|
<div className="flex flex-wrap gap-2">
|
|
{movieDetails.genres.map((genre) => (
|
|
<GenreLabel key={genre.id} genre={genre.name} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Synopsis */}
|
|
{movieDetails.overview && (
|
|
<div>
|
|
<h3 className="text-lg font-semibold mb-3 text-purple-300">
|
|
Opis
|
|
</h3>
|
|
<p className="text-gray-300 leading-relaxed text-lg">
|
|
{movieDetails.overview}
|
|
</p>
|
|
</div>
|
|
)}
|
|
|
|
{/* Action buttons */}
|
|
{!loading && (
|
|
<div className="flex gap-4 flex-wrap">
|
|
<Button
|
|
gradient={
|
|
isInStore
|
|
? {
|
|
from: "from-purple-600 hover:from-purple-500",
|
|
to: "to-emerald-600 hover:to-emerald-500",
|
|
}
|
|
: {
|
|
from: "from-purple-600 hover:from-purple-500",
|
|
to: "to-pink-600 hover:to-pink-500",
|
|
}
|
|
}
|
|
className={`flex items-center gap-3`}
|
|
onClick={handleAddToList}
|
|
>
|
|
<FaBookmark />
|
|
{isInStore ? "Usuń z listy" : "Dodaj do listy"}
|
|
</Button>
|
|
<Button
|
|
theme={isFavorite ? "rose" : "glass"}
|
|
className={`flex items-center gap-3 ${
|
|
isFavorite
|
|
? "bg-gradient-to-r border-rose-400/30"
|
|
: ""
|
|
}`}
|
|
onClick={handleToggleFavorite}
|
|
>
|
|
<FaHeart
|
|
className={isFavorite ? "text-rose-200" : ""}
|
|
/>
|
|
{isFavorite
|
|
? "Usuń z ulubionych"
|
|
: "Dodaj do ulubionych"}
|
|
</Button>
|
|
<Button
|
|
theme={isSeen ? "emerald" : "glass"}
|
|
className={`flex items-center gap-3 ${
|
|
isSeen ? "bg-gradient-to-r border-emerald-400/30" : ""
|
|
}`}
|
|
onClick={handleToggleSeen}
|
|
>
|
|
<FaEye className={isSeen ? "text-emerald-200" : ""} />
|
|
{isSeen
|
|
? "Oznacz jako nieobejrzany"
|
|
: "Oznacz jako obejrzany"}
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|