Yash Goyal
Correction
2070fe3
import React, { useState, useEffect } from 'react';
import { motion } from 'framer-motion';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
// --- Icons (Lucide React) ---
const ChevronLeftIcon = ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}><path d="m15 18-6-6 6-6"/></svg>
);
const AtSignIcon = ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}><circle cx="12" cy="12" r="4"/><path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-3.92 7.94"/></svg>
);
const GoogleIcon = ({ className }) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className={className}><path d="M12.479,14.265v-3.279h11.049c0.108,0.571,0.164,1.247,0.164,1.979c0,2.46-0.672,5.502-2.84,7.669 C18.744,22.829,16.051,24,12.483,24C5.869,24,0.308,18.613,0.308,12S5.869,0,12.483,0c3.659,0,6.265,1.436,8.223,3.307L18.392,5.62 c-1.404-1.317-3.307-2.341-5.913-2.341C7.65,3.279,3.873,7.171,3.873,12s3.777,8.721,8.606,8.721c3.132,0,4.916-1.258,6.059-2.401 c0.927-0.927,1.537-2.251,1.777-4.059L12.479,14.265z" /></svg>
);
// --- Background Animation Component ---
function FloatingPaths({ position }) {
const paths = Array.from({ length: 36 }, (_, i) => ({
id: i,
d: `M-${380 - i * 5 * position} -${189 + i * 6}C-${
380 - i * 5 * position
} -${189 + i * 6} -${312 - i * 5 * position} ${216 - i * 6} ${
152 - i * 5 * position
} ${343 - i * 6}C${616 - i * 5 * position} ${470 - i * 6} ${
684 - i * 5 * position
} ${875 - i * 6} ${684 - i * 5 * position} ${875 - i * 6}`,
color: `rgba(255, 255, 255, ${0.1 + i * 0.03})`,
width: 0.5 + i * 0.03,
}));
return (
<div className="pointer-events-none absolute inset-0">
<svg
className="h-full w-full text-red-500"
viewBox="0 0 696 316"
fill="none"
>
<title>Background Paths</title>
{paths.map((path) => (
<motion.path
key={path.id}
d={path.d}
stroke="currentColor"
strokeWidth={path.width}
strokeOpacity={0.1 + path.id * 0.03}
initial={{ pathLength: 0.3, opacity: 0.6 }}
animate={{
pathLength: 1,
opacity: [0.3, 0.6, 0.3],
pathOffset: [0, 1, 0],
}}
transition={{
duration: 20 + Math.random() * 10,
repeat: Number.POSITIVE_INFINITY,
ease: 'linear',
}}
/>
))}
</svg>
</div>
);
}
// --- Main Login Page Component ---
export default function Login() {
const navigate = useNavigate();
const location = useLocation();
const { login, googleLogin, user } = useAuth();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const rightSideImagePath = '../login-illustration.jpg';
// Check for error in URL params
useEffect(() => {
const params = new URLSearchParams(location.search);
const errorParam = params.get('error');
if (errorParam) {
const errorMessages = {
'auth_failed': 'Authentication failed. Please try again.',
'session_error': 'Session error. Please try again.',
'save_error': 'Failed to save session. Please try again.',
'verification_failed': 'Could not verify your authentication.',
'verification_error': 'Error verifying authentication.',
'timed out': 'Database connection timed out. Please try again.',
};
setError(errorMessages[errorParam] || `Error: ${errorParam}`);
console.error('Login page error:', errorParam);
// Clean up URL
window.history.replaceState({}, '', location.pathname);
}
}, [location]);
// Redirect if already logged in
useEffect(() => {
if (user) {
console.log('User already logged in, redirecting to dashboard');
navigate('/dashboard');
}
}, [user, navigate]);
// Handle Email/Password Login
const handleEmailLogin = async (e) => {
e.preventDefault();
setError('');
setLoading(true);
try {
await login({ email, password });
navigate('/dashboard');
} catch (err) {
setError(err.response?.data?.message || 'Login failed. Please check your credentials.');
} finally {
setLoading(false);
}
};
// Handle Google Login
const handleGoogleLogin = () => {
console.log('Initiating Google OAuth...');
googleLogin();
};
return (
<main className="relative md:h-screen md:overflow-hidden lg:grid lg:grid-cols-2 bg-black text-white">
{/* --- Left Column: Art & Testimonials --- */}
<div className="relative hidden h-full flex-col border-r border-gray-800 p-10 lg:flex overflow-hidden">
{/* Gradient Overlay */}
<div className="absolute inset-0 z-10 bg-gradient-to-t from-black/80 via-black/20 to-transparent" />
{/* Logo */}
<div className="z-10 flex items-center gap-2">
<img
src="/logo.png"
alt="PopcornPing"
className="h-8 w-8 object-contain"
onError={(e) => { e.target.style.display = 'none'; }}
/>
<span className="text-xl font-bold tracking-wide">PopcornPing</span>
</div>
{/* Testimonial */}
<div className="z-10 mt-auto max-w-lg">
<blockquote className="space-y-4">
<p className="text-xl font-medium leading-relaxed text-gray-200">
&ldquo;This platform has revolutionized how we conduct creative reviews. The screen sharing quality is unmatched.&rdquo;
</p>
</blockquote>
</div>
{/* Animated Background Paths */}
<div className="absolute inset-0 z-0">
<FloatingPaths position={1} />
<FloatingPaths position={-1} />
</div>
</div>
{/* --- Right Column: Auth Form --- */}
<div className="relative flex min-h-screen flex-col justify-center p-8 md:p-12 lg:p-16">
<div className="absolute inset-0 hidden lg:block z-0">
<img
src={rightSideImagePath}
alt="Login Illustration"
className="h-full w-full object-cover opacity-20"
onError={(e) => {
e.target.style.display = 'none';
}}
/>
<div className="absolute inset-0 bg-black/30" />
</div>
{/* Background Glow Effects */}
<div aria-hidden="true" className="absolute inset-0 isolate -z-10 overflow-hidden">
<div className="absolute top-0 right-0 h-[500px] w-[500px] bg-purple-900/10 blur-[100px] rounded-full translate-x-1/2 -translate-y-1/2" />
<div className="absolute bottom-0 right-0 h-[400px] w-[400px] bg-blue-900/10 blur-[100px] rounded-full translate-x-1/3 translate-y-1/3" />
</div>
{/* Back to Home Button */}
<button
onClick={() => navigate('/')}
className="absolute top-8 left-8 md:left-12 inline-flex items-center text-sm font-medium text-gray-400 hover:text-white transition-colors z-20"
>
<ChevronLeftIcon className="w-4 h-4 mr-2" />
Home
</button>
{/* Form Container */}
<div className="mx-auto w-full max-w-sm space-y-8 relative z-20">
{/* Mobile Logo */}
<div className="flex items-center gap-2 lg:hidden mb-8">
<span className="text-xl font-bold">PopcornPing</span>
</div>
{/* Headers */}
<div className="flex flex-col space-y-2">
<h1 className="text-3xl font-bold tracking-tight text-white drop-shadow-lg">
Sign In or Join Now!
</h1>
<p className="text-gray-300 text-sm drop-shadow-md">
Login or create your PopcornPing account.
</p>
</div>
{/* Social Login Buttons */}
<div className="space-y-3">
<button
onClick={handleGoogleLogin}
className="w-full flex items-center justify-center gap-2 bg-white text-black hover:bg-gray-200 h-12 rounded-md font-medium transition-colors"
>
<GoogleIcon className="w-5 h-5" />
Continue with Google
</button>
</div>
{/* Separator */}
<div className="relative">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-800" />
</div>
<div className="relative flex justify-center text-xs uppercase">
<span className="bg-black px-2 text-gray-500">Or</span>
</div>
</div>
{/* Email Form */}
<form onSubmit={handleEmailLogin} className="space-y-4">
{error && (
<div className="p-3 text-sm text-red-400 bg-red-500/10 border border-red-500/20 rounded-md">
{error}
</div>
)}
<div className="space-y-4">
<div className="space-y-2">
<label className="text-xs font-medium text-gray-400 ml-1">Email Address</label>
<div className="relative">
<input
type="email"
placeholder="your.email@example.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
className="w-full h-11 bg-gray-900/80 border border-gray-800 rounded-md pl-10 pr-4 text-white text-sm focus:outline-none focus:ring-2 focus:ring-white/20 transition-all placeholder:text-gray-600"
/>
<div className="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none text-gray-500">
<AtSignIcon className="w-4 h-4" />
</div>
</div>
</div>
{/* Password Field */}
<div className="space-y-2">
<label className="text-xs font-medium text-gray-400 ml-1">Password</label>
<div className="relative">
<input
type="password"
placeholder="••••••••"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
className="w-full h-11 bg-gray-900/80 border border-gray-800 rounded-md pl-4 pr-4 text-white text-sm focus:outline-none focus:ring-2 focus:ring-white/20 transition-all placeholder:text-gray-600"
/>
</div>
</div>
</div>
<button
type="submit"
disabled={loading}
className="w-full h-12 bg-white text-black font-semibold rounded-md hover:bg-gray-200 transition-colors disabled:opacity-50 disabled:cursor-not-allowed mt-2"
>
{loading ? 'Processing...' : 'Continue With Email'}
</button>
</form>
</div>
</div>
</main>
);
}