Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 48 additions & 46 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,52 +51,54 @@ export default function App() {
<AuthProvider>
<Router>
<NavbarVisibility />
<Routes>

<Route path="/" element={<Landing />} />
<Route path="/register" element={<PublicRoute><Register /></PublicRoute>} />
<Route path="/login" element={<PublicRoute><Login /></PublicRoute>} />
<Route path="/dashboard" element={<ProtectedRoute><Dashboard /></ProtectedRoute>} />
<Route path="/admin" element={<ProtectedRoute><AdminDashboard /></ProtectedRoute>} />
<Route path="/movies/:id" element={<MovieDetails />} />
<Route path="/search" element={<Search />} />
<Route path="/reviews/:id" element={<ReviewDetails />} />
<Route path="/watchlist" element={<Watchlist />} />
<Route path="/ai" element={<AIRecommendations />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
<Route path="/terms" element={<Terms />} />
<Route path="/privacy" element={<Privacy />} />
<Route path="/discover" element={<Placeholder title="Discover" />} />
<Route path="/trending" element={<TopTrending />} />
<Route path="/top-rated" element={<TopRated />} />
<Route path="/recommendations" element={<ProtectedRoute><Recommended /></ProtectedRoute>} />
<Route path="/profile" element={<ProtectedRoute><UserProfile /></ProtectedRoute>} />
<Route path="/forgot-password" element={ <PublicRoute> <ForgotPassword /></PublicRoute>}/>

<Route path="/profile/:id" element={<ProtectedRoute><UserProfile /></ProtectedRoute>} />

<Route
path="/friends/activity"
element={
<ProtectedRoute>
<FriendActivityFeed />
</ProtectedRoute>
}
/>

<Route path="/friends" element={<ProtectedRoute><Friends /></ProtectedRoute>} />

{/* ✅ Forum routes */}
<Route path="/forum" element={<ProtectedRoute><ForumFeed /></ProtectedRoute>} />
<Route path="/forum/create" element={<ProtectedRoute><ForumPostCreateEdit /></ProtectedRoute>} />
<Route path="/forum/edit/:postId" element={<ProtectedRoute><ForumPostCreateEdit /></ProtectedRoute>} />
<Route path="/forum/:postId" element={<ProtectedRoute><ForumPostDetail /></ProtectedRoute>} />

{/* Redirects */}
<Route path="/AI Recommendation" element={<Navigate to="/ai" replace />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
<main className="flex-1">
<Routes>

<Route path="/" element={<Landing />} />
<Route path="/register" element={<PublicRoute><Register /></PublicRoute>} />
<Route path="/login" element={<PublicRoute><Login /></PublicRoute>} />
<Route path="/dashboard" element={<ProtectedRoute><Dashboard /></ProtectedRoute>} />
<Route path="/admin" element={<ProtectedRoute><AdminDashboard /></ProtectedRoute>} />
<Route path="/movies/:id" element={<MovieDetails />} />
<Route path="/search" element={<Search />} />
<Route path="/reviews/:id" element={<ReviewDetails />} />
<Route path="/watchlist" element={<Watchlist />} />
<Route path="/ai" element={<AIRecommendations />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
<Route path="/terms" element={<Terms />} />
<Route path="/privacy" element={<Privacy />} />
<Route path="/discover" element={<Placeholder title="Discover" />} />
<Route path="/trending" element={<TopTrending />} />
<Route path="/top-rated" element={<TopRated />} />
<Route path="/recommendations" element={<ProtectedRoute><Recommended /></ProtectedRoute>} />
<Route path="/profile" element={<ProtectedRoute><UserProfile /></ProtectedRoute>} />
<Route path="/forgot-password" element={ <PublicRoute> <ForgotPassword /></PublicRoute>}/>

<Route path="/profile/:id" element={<ProtectedRoute><UserProfile /></ProtectedRoute>} />

<Route
path="/friends/activity"
element={
<ProtectedRoute>
<FriendActivityFeed />
</ProtectedRoute>
}
/>

<Route path="/friends" element={<ProtectedRoute><Friends /></ProtectedRoute>} />

{/* ✅ Forum routes */}
<Route path="/forum" element={<ProtectedRoute><ForumFeed /></ProtectedRoute>} />
<Route path="/forum/create" element={<ProtectedRoute><ForumPostCreateEdit /></ProtectedRoute>} />
<Route path="/forum/edit/:postId" element={<ProtectedRoute><ForumPostCreateEdit /></ProtectedRoute>} />
<Route path="/forum/:postId" element={<ProtectedRoute><ForumPostDetail /></ProtectedRoute>} />

{/* Redirects */}
<Route path="/AI Recommendation" element={<Navigate to="/ai" replace />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</main>
<FooterVisibility />
<GlobalChatbotVisibility />
</Router>
Expand Down
28 changes: 14 additions & 14 deletions frontend/src/components/Footer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function Footer() {
}, []);

return (
<footer className="bg-gray-900 dark:bg-black border-t border-gray-800 dark:border-gray-700 mt-16">
<footer className="bg-gray-100 dark:bg-black border-t border-gray-300 dark:border-gray-800 mt-auto">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{/* Brand Section */}
Expand All @@ -30,11 +30,11 @@ export default function Footer() {
RedPill
</span>
</Link>
<p className="text-gray-400 text-sm max-w-md">
<p className="text-gray-600 dark:text-gray-400 text-sm max-w-md">
Discover, review, and discuss movies with fellow film enthusiasts.
Get AI-powered recommendations and analyze movie personalities in our community.
</p>
<div className="flex items-center mt-4 text-gray-400 text-sm">
<div className="flex items-center mt-4 text-gray-600 dark:text-gray-400 text-sm">
<span>Made with</span>
<FaHeart className="text-red-500 mx-1" />
<span>by movie lovers</span>
Expand All @@ -43,10 +43,10 @@ export default function Footer() {
{/* Game of Thrones Quote */}
{gotQuote && (
<div className="mt-6 text-left">
<div className="italic text-base text-gray-300">
<div className="italic text-base text-gray-700 dark:text-gray-300">
<span>❝{gotQuote.sentence}❞</span>
{gotQuote.character && (
<span className="block mt-2 text-sm text-gray-500">— {gotQuote.character.name}</span>
<span className="block mt-2 text-sm text-gray-500 dark:text-gray-500">— {gotQuote.character.name}</span>
)}
</div>
</div>
Expand All @@ -55,36 +55,36 @@ export default function Footer() {

{/* Legal & Info */}
<div>
<h3 className="text-white font-semibold mb-4">Information</h3>
<h3 className="text-gray-900 dark:text-white font-semibold mb-4">Information</h3>
<ul className="space-y-2">
<li>
<Link
to="/about"
className="text-gray-400 hover:text-white transition-colors text-sm"
className="text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white transition-colors text-sm"
>
About Us
</Link>
</li>
<li>
<Link
to="/contact"
className="text-gray-400 hover:text-white transition-colors text-sm"
className="text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white transition-colors text-sm"
>
Contact
</Link>
</li>
<li>
<Link
to="/terms"
className="text-gray-400 hover:text-white transition-colors text-sm"
className="text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white transition-colors text-sm"
>
Terms of Service
</Link>
</li>
<li>
<Link
to="/privacy"
className="text-gray-400 hover:text-white transition-colors text-sm"
className="text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white transition-colors text-sm"
>
Privacy Policy
</Link>
Expand All @@ -94,18 +94,18 @@ export default function Footer() {
</div>

{/* Divider */}
<div className="border-t border-gray-800 dark:border-gray-700 mt-8 pt-8">
<div className="border-t border-gray-300 dark:border-gray-800 mt-8 pt-8">
<div className="flex flex-col md:flex-row justify-between items-center">
<p className="text-gray-400 text-sm">
<p className="text-gray-600 dark:text-gray-400 text-sm">
© {currentYear} RedPill. All rights reserved.
</p>
<div className="flex items-center space-x-4 mt-4 md:mt-0">
<span className="text-gray-400 text-sm">Follow us:</span>
<span className="text-gray-600 dark:text-gray-400 text-sm">Follow us:</span>
<a
href="https://github.com/RedPill-Team"
target="_blank"
rel="noopener noreferrer"
className="text-gray-400 hover:text-white transition-colors"
className="text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white transition-colors"
>
<FaGithub className="w-5 h-5" />
</a>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<ThemeProvider>
<UserProvider>
<div className="bg-white dark:bg-[#181A20] min-h-screen">
<div className="bg-white dark:bg-[#181A20] min-h-screen flex flex-col">
<App />
</div>
</UserProvider>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/ForumFeed.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const ForumFeed = () => {
);

return (
<div className={`min-h-screen pt-24 transition-colors duration-300 ${theme === 'dark' ? 'bg-black' : 'bg-gray-50'}`}>
<div className={`min-h-screen pt-24 pb-16 transition-colors duration-300 ${theme === 'dark' ? 'bg-black' : 'bg-gray-50'}`}>
<div className="max-w-4xl mx-auto px-4">

{/* Create Post Box */}
Expand Down
58 changes: 34 additions & 24 deletions frontend/src/pages/Recommended.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,34 @@ function MovieCard({ movie, onClick }) {
return (
<motion.button
onClick={() => onClick?.(movie)}
className="group text-left rounded-xl border border-gray-200/50 dark:border-white/10 bg-white/60 dark:bg-gray-800/40 hover:bg-white/80 dark:hover:bg-gray-800/60 hover:border-gray-300 dark:hover:border-white/20 hover:shadow-lg transition-all duration-200 overflow-hidden"
whileHover={{ y: -2 }}
className="group text-left rounded-xl bg-white dark:bg-gray-900 hover:bg-gray-50 dark:hover:bg-gray-800 shadow-md hover:shadow-xl transition-all duration-300 overflow-hidden relative"
whileHover={{ y: -4, scale: 1.02 }}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
>
<div className="aspect-[2/3] overflow-hidden rounded-t-xl">
<div className="aspect-[2/3] overflow-hidden relative">
<img
src={img.poster(movie.poster_path)}
alt={movie.title}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"
/>
{/* Rating overlay */}
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300">
<div className="absolute bottom-3 left-3 right-3">
<div className="text-yellow-400 text-sm font-semibold mb-1">
{ratingOf(movie)}
</div>
<h3 className="text-white font-semibold text-sm line-clamp-2">{movie.title}</h3>
<p className="text-gray-300 text-xs">{yearOf(movie)}</p>
</div>
</div>
</div>
<div className="p-4">
<h3 className="font-semibold text-gray-900 dark:text-white line-clamp-2 mb-1">{movie.title}</h3>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-2">{yearOf(movie)}</p>
<div className="flex items-center justify-between">
<div className="text-xs text-yellow-600 dark:text-yellow-400 font-medium">
{ratingOf(movie)}
<h3 className="font-semibold text-gray-900 dark:text-white line-clamp-2 mb-2 text-sm">{movie.title}</h3>
<div className="flex items-center justify-between text-xs">
<span className="text-gray-600 dark:text-gray-400">{yearOf(movie)}</span>
<div className="flex items-center gap-1 text-yellow-600 dark:text-yellow-400 font-medium">
<span>{ratingOf(movie)}</span>
</div>
</div>
</div>
Expand All @@ -47,12 +57,11 @@ function MovieCard({ movie, onClick }) {

function SkeletonCard() {
return (
<div className="rounded-xl border border-gray-200 dark:border-white/10 bg-white/60 dark:bg-gray-800/40 overflow-hidden animate-pulse">
<div className="rounded-xl bg-white dark:bg-gray-900 shadow-md overflow-hidden animate-pulse">
<div className="aspect-[2/3] bg-gray-200 dark:bg-gray-700"></div>
<div className="p-4">
<div className="h-4 bg-gray-200 dark:bg-gray-700 rounded mb-2"></div>
<div className="h-3 bg-gray-200 dark:bg-gray-700 rounded w-2/3 mb-2"></div>
<div className="h-3 bg-gray-200 dark:bg-gray-700 rounded w-1/3"></div>
<div className="h-3 bg-gray-200 dark:bg-gray-700 rounded w-2/3"></div>
</div>
</div>
);
Expand Down Expand Up @@ -104,37 +113,38 @@ export default function Recommended() {
}

return (
<div className="min-h-screen bg-white dark:bg-black dark:text-gray-200 pt-24">
<div className="max-w-7xl mx-auto px-6 py-8">
<div className="min-h-screen bg-gray-50 dark:bg-black pt-24 pb-16">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div className="mb-8">
<h1 className="text-3xl font-bold text-gray-900 dark:text-white mb-2">Recommended for You</h1>
<p className="text-gray-600 dark:text-gray-400">
<h1 className="text-4xl font-bold text-gray-900 dark:text-white mb-3">
Recommended for You
</h1>
<p className="text-gray-600 dark:text-gray-400 text-lg">
Personalized movie recommendations based on your viewing history and preferences
</p>
</div>

{loading ? (
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-6">
{Array.from({ length: 18 }).map((_, i) => (
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 2xl:grid-cols-7 gap-4 md:gap-6">
{Array.from({ length: 21 }).map((_, i) => (
<SkeletonCard key={i} />
))}
</div>
) : movies.length === 0 ? (
<div className="text-center py-16">
<div className="mb-4 text-gray-400 text-6xl">🎬</div>
<h3 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">No Recommendations Yet</h3>
<p className="text-gray-600 dark:text-gray-400 mb-6">
<div className="text-center py-20">
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-3">No Recommendations Yet</h3>
<p className="text-gray-600 dark:text-gray-400 mb-8 max-w-md mx-auto">
Start rating and watching movies to get personalized recommendations!
</p>
<button
onClick={() => navigate('/search')}
className="px-6 py-3 bg-yellow-500 text-black font-semibold rounded-lg hover:bg-yellow-600 transition-colors"
className="px-8 py-3 bg-purple-500 text-white font-semibold rounded-xl hover:bg-purple-600 transition-colors shadow-lg"
>
Explore Movies
</button>
</div>
) : (
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-6">
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 2xl:grid-cols-7 gap-4 md:gap-6">
{movies.map((movie) => (
<MovieCard
key={movie.id}
Expand Down
Loading