| "use client"; | |
| import { useState, useEffect, useRef } from "react"; | |
| import "./HeroSection.css"; | |
| import apiClient from "@/api/apiClient"; | |
| import SkeletonLoader from "@/skeletons/Sections/HeroSection"; | |
| import Link from "next/link"; | |
| const HeroSection = () => { | |
| const [currentIndex, setCurrentIndex] = useState(0); | |
| const intervalRef = useRef(null); | |
| const [fadeOut, setFadeOut] = useState(false); | |
| const [items, setItems] = useState([]); | |
| const [loading, setLoading] = useState(true); | |
| const [isDragging, setIsDragging] = useState(false); | |
| const [startX, setStartX] = useState(0); | |
| useEffect(() => { | |
| const fetchRecentItems = async () => { | |
| try { | |
| const response = await apiClient.getRecent(); | |
| const movies = response.movies.map((film) => ({ | |
| title: film[0], | |
| description: film[2], | |
| imageUrl: film[3], | |
| type: "Movie", | |
| })); | |
| const series = response.series.map((serie) => ({ | |
| title: serie[0], | |
| description: serie[2], | |
| imageUrl: serie[3], | |
| type: "TvShow", | |
| })); | |
| setItems([...movies, ...series]); | |
| } catch (error) { | |
| console.error("Error fetching recent items:", error); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| fetchRecentItems(); | |
| }, []); | |
| const startAutoSwitch = () => { | |
| if (intervalRef.current) clearInterval(intervalRef.current); | |
| intervalRef.current = setInterval(() => { | |
| setFadeOut(true); | |
| setTimeout(() => { | |
| setCurrentIndex((prevIndex) => (prevIndex + 1) % items.length); | |
| setFadeOut(false); | |
| }, 200); | |
| }, 5000); | |
| }; | |
| useEffect(() => { | |
| if (items.length > 0) { | |
| startAutoSwitch(); | |
| } | |
| return () => { | |
| clearInterval(intervalRef.current); | |
| }; | |
| }, [items]); | |
| const handleSwipe = (direction) => { | |
| setFadeOut(true); | |
| setTimeout(() => { | |
| setCurrentIndex((prevIndex) => { | |
| if (direction === "left") { | |
| return (prevIndex + 1) % items.length; | |
| } else { | |
| return (prevIndex - 1 + items.length) % items.length; | |
| } | |
| }); | |
| setFadeOut(false); | |
| }, 100); | |
| startAutoSwitch(); | |
| }; | |
| const handleTouchStart = (e) => { | |
| const touchStartX = e.touches[0].clientX; | |
| setStartX(touchStartX); | |
| const handleTouchMove = (event) => { | |
| const touchEndX = event.touches[0].clientX; | |
| const diffX = touchStartX - touchEndX; | |
| if (diffX > 50) { | |
| handleSwipe("left"); | |
| document.removeEventListener("touchmove", handleTouchMove); | |
| } else if (diffX < -50) { | |
| handleSwipe("right"); | |
| document.removeEventListener("touchmove", handleTouchMove); | |
| } | |
| }; | |
| document.addEventListener("touchmove", handleTouchMove); | |
| }; | |
| const handleMouseDown = (e) => { | |
| setStartX(e.clientX); | |
| setIsDragging(true); | |
| }; | |
| const handleMouseMove = (e) => { | |
| if (!isDragging) return; | |
| const diffX = startX - e.clientX; | |
| if (diffX > 50) { | |
| handleSwipe("left"); | |
| setIsDragging(false); | |
| } else if (diffX < -50) { | |
| handleSwipe("right"); | |
| setIsDragging(false); | |
| } | |
| }; | |
| const handleMouseUp = () => { | |
| setIsDragging(false); | |
| }; | |
| if (loading) { | |
| return <SkeletonLoader />; | |
| } | |
| if (items.length === 0) { | |
| return <div>No items available</div>; | |
| } | |
| const { title, description, imageUrl, type } = items[currentIndex]; | |
| const linkPath = `/${type.toLowerCase()}/${encodeURIComponent(title)}`; | |
| return ( | |
| <div | |
| className="hero-container" | |
| onTouchStart={handleTouchStart} | |
| onMouseDown={handleMouseDown} | |
| onMouseMove={handleMouseMove} | |
| onMouseUp={handleMouseUp} | |
| onMouseLeave={handleMouseUp} | |
| > | |
| <div className="hero-section"> | |
| {items.map((item, index) => ( | |
| <div | |
| key={index} | |
| className={`hero-image ${index === currentIndex ? "active" : ""} ${ | |
| fadeOut ? "fade-out" : "" | |
| }`} | |
| style={{ | |
| backgroundImage: `linear-gradient(rgba(0, 0, 0, 0.1) 20%, #11121f 80%), url("${item.imageUrl}")`, | |
| }} | |
| ></div> | |
| ))} | |
| <div className="hero-text"> | |
| <Link href={linkPath}> | |
| <h1 className="hero-title">{title}</h1> | |
| </Link> | |
| <p className="hero-description">{description}</p> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default HeroSection; |