diff --git a/client/src/App.jsx b/client/src/App.jsx index 6b242a6..3968464 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -8,6 +8,7 @@ import Profile from "./pages/Profile"; import useAuthLoader from "./hooks/useAuthLoader"; import MoviePage from "./pages/MoviePage"; import Navbar from "./components/Navbar"; +import TmdbMovie from "./pages/MoviesPage"; function isTokenExpired(token) { if (!token) return true; @@ -79,6 +80,15 @@ export default function App() { } /> + + : + } + /> + { + const res = await axiosInstance.get('/movies/trending'); + return res; +} \ No newline at end of file diff --git a/client/src/components/HistoryTab.jsx b/client/src/components/HistoryTab.jsx index 90755cc..d874d20 100644 --- a/client/src/components/HistoryTab.jsx +++ b/client/src/components/HistoryTab.jsx @@ -83,11 +83,11 @@ export default function HistoryTab() { > {/* THE TIMELINE HEADER */}
-
+

{date}

-
+
{/* MOVIE GRID */} diff --git a/client/src/components/Tabs.jsx b/client/src/components/Tabs.jsx index d0eee77..69fc474 100644 --- a/client/src/components/Tabs.jsx +++ b/client/src/components/Tabs.jsx @@ -70,7 +70,7 @@ export default function Tabs({ profileData, isMyProfile }) {
{/* 2. CONTENT AREA */} -
+
{loading ? ( - {/* Cinematic Vignette Overlay */} -
+ {/* Vignette Overlay */} +
- {/* Rating Badge - Updated to Glassmorphism */} + {/* Rating Badge */} {rating && (
diff --git a/client/src/pages/MoviePage.jsx b/client/src/pages/MoviePage.jsx index dd8f003..e08e6bc 100644 --- a/client/src/pages/MoviePage.jsx +++ b/client/src/pages/MoviePage.jsx @@ -1,8 +1,7 @@ import { useEffect, useState } from "react"; -import { motion, AnimatePresence } from "framer-motion"; +import { motion } from "framer-motion"; import { getMovieById } from "../api/movie.api"; import Loader from "../components/ui/Loader"; -import { useParams } from "react-router-dom"; export default function MoviePage() { const [movieData, setMovieData] = useState(null); diff --git a/client/src/pages/MoviesPage.jsx b/client/src/pages/MoviesPage.jsx new file mode 100644 index 0000000..5e6095f --- /dev/null +++ b/client/src/pages/MoviesPage.jsx @@ -0,0 +1,150 @@ +import { useEffect, useState, useRef } from "react"; +import { motion } from "framer-motion"; +import { getTrendingMovies } from "../api/tmdb.api"; +import MovieCard from "../components/ui/MovieCard"; +import Loader from "../components/ui/Loader"; +import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"; + +export default function MoviesPage() { + const [loading, setLoading] = useState(true); + const [trendingMovies, setTrendingMovies] = useState([]); + const [featuredMovie, setFeaturedMovie] = useState(null); + + useEffect(() => { + const fetchTrending = async () => { + try { + const res = await getTrendingMovies(); + const movies = res.data || []; + setTrendingMovies(movies); + + if (movies.length > 0) { + const randomIndex = Math.floor(Math.random() * movies.length); + setFeaturedMovie(movies[randomIndex]); + } + } catch (error) { + console.error("Error fetching trending movies: ", error); + } finally { + setLoading(false); + } + }; + + fetchTrending(); + }, []); + + if (loading) return ; + + return ( +
+ + {/* 1. FEATURED HERO SECTION */} +
+ + + {/* Gradient & Content Overlay */} +
+ +

+ Featured Spotlight +

+

+ {featuredMovie?.title || featuredMovie?.name} +

+

+ {featuredMovie?.overview} +

+
+
+
+ +
+ {/* 2. TRENDING SECTION */} + +
+
+ ); +} + +function MovieSlider({ title, subtitle, movies }) { + const scrollRef = useRef(null); + + const scroll = (direction) => { + if (scrollRef.current) { + const { scrollLeft, clientWidth } = scrollRef.current; + const scrollAmount = clientWidth * 0.8; + const scrollTo = direction === "left" ? scrollLeft - scrollAmount : scrollLeft + scrollAmount; + scrollRef.current.scrollTo({ left: scrollTo, behavior: "smooth" }); + } + }; + + if (!movies || movies.length === 0) return null; + + return ( +
+
+
+
+
+
{subtitle}
+
+

{title}

+
+ +
+ + +
+
+ +
+ {movies.map((movie) => ( +
+ +
+ ))} +
+
+ ); +} \ No newline at end of file diff --git a/client/src/pages/Profile.jsx b/client/src/pages/Profile.jsx index 171bf36..c7ad3b9 100644 --- a/client/src/pages/Profile.jsx +++ b/client/src/pages/Profile.jsx @@ -190,7 +190,7 @@ export default function Profile() { {/* Modal for Cover Selection */} -
+
{/* Header */}
@@ -208,7 +208,6 @@ export default function Profile() {
- {/* Content Area */}
{banners.length > 0 ? (
@@ -219,11 +218,11 @@ export default function Profile() { animate={{ opacity: 1, y: 0 }} transition={{ delay: index * 0.05 }} whileHover={{ scale: 1.02 }} - className={`group relative aspect-video rounded-[2rem] overflow-hidden cursor-pointer bg-stone-200 border-4 + className={`group relative aspect-video rounded-4xl overflow-hidden cursor-pointer bg-stone-200 border-4 ${selectedBackdrop === banner?.backdropPath ? "border-amber-500/70" : "border-white"} shadow-xl transition-all hover:shadow-amber-500/20 hover:border-amber-500/40`} onClick={() => { - setSelectedBackdrop(banner?.backdropPath); // βœ… Select banner + setSelectedBackdrop(banner?.backdropPath); }} > {banner?.title} -
+
@@ -263,7 +262,6 @@ export default function Profile() { )}
- {/* βœ… Save & Cancel Buttons */} {selectedBackdrop && (