moviebox/src/components/molecules/HeroMovie/index.tsx

259 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";
import { formatter } from "@/helpers/formater";
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 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="blocks">
<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">
<div className="container">
<div className="flex flex-col lg:flex-row gap-8">
{/* Movie poster */}
<div className="flex-shrink-0 text-center">
<div className="relative group inline-block">
<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"
/>
<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>
{formatter.formatDate(movieDetails.release_date)}
</span>
</div>
)}
{movieDetails.runtime && (
<div className="flex items-center gap-2 text-gray-300">
<FaClock className="text-purple-400" />
<span>
{formatter.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}
id={genre.id}
/>
))}
</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 ? "rosePink" : "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 ? "emeraldTeal" : "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>
);
};