diff --git a/src/components/organisms/Hero/index.tsx b/src/components/organisms/Hero/index.tsx new file mode 100644 index 0000000..daeb9dd --- /dev/null +++ b/src/components/organisms/Hero/index.tsx @@ -0,0 +1,248 @@ +"use client"; +import { FC, useState, useEffect, useCallback } from "react"; +import { Movie } from "@/types/global"; +import { + FaPlus, + FaFire, + FaChevronLeft, + FaChevronRight, + FaMinus, +} from "react-icons/fa"; +import { RiCalendarCheckLine, RiCalendarScheduleLine } from "react-icons/ri"; +import { useGlobalStore } from "@/app/store/globalStore"; +import { addMovie, deleteMovie } from "@/lib/db"; +import { ReadMore } from "@/components/atoms/ReadMore"; + +type Props = { + movies: Movie[]; + preheading?: string; + autoRotate?: boolean; + rotateInterval?: number; +}; + +export const Hero: FC = ({ + movies, + preheading, + autoRotate = true, + rotateInterval = 10000, +}) => { + const [currentIndex, setCurrentIndex] = useState(0); + const [isTransitioning, setIsTransitioning] = useState(false); + + const { + movies: storedMovies, + addMovie: addMovieToStore, + deleteMovie: deleteMovieInStore, + } = useGlobalStore(); + + const currentMovie = movies[currentIndex]; + + if (!currentMovie) return null; + + const { + id, + title, + overview, + backdrop_path, + poster_path, + release_date, + popularity, + vote_average, + } = currentMovie; + + const alreadyInStore = storedMovies.find((m) => m.id === id); + const isReleased = new Date(release_date) < new Date(); + const releaseDate = new Date(release_date); + + const nextSlide = useCallback(() => { + if (isTransitioning) return; + setIsTransitioning(true); + setTimeout(() => { + setCurrentIndex((prev) => (prev + 1) % movies.length); + setIsTransitioning(false); + }, 500); + }, [movies.length, isTransitioning]); + + const prevSlide = useCallback(() => { + if (isTransitioning) return; + setIsTransitioning(true); + setTimeout(() => { + setCurrentIndex((prev) => (prev - 1 + movies.length) % movies.length); + setIsTransitioning(false); + }, 500); + }, [movies.length, isTransitioning]); + + const goToSlide = useCallback( + (index: number) => { + if (isTransitioning || index === currentIndex) return; + setIsTransitioning(true); + setTimeout(() => { + setCurrentIndex(index); + setIsTransitioning(false); + }, 500); + }, + [currentIndex, isTransitioning] + ); + + // Auto-rotate functionality. + useEffect(() => { + if (!autoRotate || movies.length <= 1) return; + + const interval = setInterval(nextSlide, rotateInterval); + return () => clearInterval(interval); + }, [autoRotate, rotateInterval, nextSlide, movies.length]); + + const handleAdd = async () => { + await addMovie(currentMovie); + addMovieToStore(currentMovie); + }; + + const handleRemove = async () => { + await deleteMovie(id); + deleteMovieInStore(id); + }; + + return ( +
+ {/* Background carousel */} +
+ {movies.map((movie, index) => ( +
+ {movie.title} +
+ ))} +
+
+
+ + {/* Navigation arrows */} + {movies.length > 1 && ( + <> + + + + )} + + {/* Content with fade transitions */} +
+
+ {/* Poster */} +
+ {title} +
+ + {/* Movie details */} +
+ {preheading && ( +

+ {preheading} +

+ )} +

+ {title} +

+ + {/* Movie meta info */} +
+
+ + {isReleased ? ( + + ) : ( + + )} + {releaseDate.toLocaleDateString("pl-PL", { + day: "numeric", + month: "long", + year: "numeric", + })} + +
+ +
+ + {popularity.toFixed(1)} +
+ +
+ + {vote_average.toFixed(1)}/10 +
+
+ + {/* Overview */} +
+ +
+ + {/* Action buttons */} +
+ +
+
+
+
+ + {/* Dot indicators */} + {movies.length > 1 && ( +
+ {movies.map((_, index) => ( +
+ )} +
+ ); +};