| 'use client'; |
| import { useRouter } from 'next/navigation'; |
| import { useState } from 'react'; |
|
|
| export default function LoginPage() { |
| const [phase, setPhase] = useState<'landing'|'transitioning'|'login'>('landing'); |
| const [username, setUsername] = useState(''); |
| const [password, setPassword] = useState(''); |
| const [error, setError] = useState(''); |
| const [isLoading, setIsLoading] = useState(false); |
| const [focused, setFocused] = useState<string|null>(null); |
| const router = useRouter(); |
|
|
| const handleGetStarted = () => { |
| setPhase('transitioning'); |
| setTimeout(() => setPhase('login'), 700); |
| }; |
|
|
| const handleSubmit = async (e: React.FormEvent) => { |
| e.preventDefault(); |
| setError(''); |
| setIsLoading(true); |
| try { |
| const response = await fetch('/api/auth/login', { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify({ username, password }), |
| }); |
| const data = await response.json(); |
| if (!response.ok) { |
| setError(data.message || 'Login failed'); |
| setIsLoading(false); |
| return; |
| } |
| router.push('/recruitment'); |
| } catch { |
| setError('Something went wrong. Please try again.'); |
| setIsLoading(false); |
| } |
| }; |
|
|
| return ( |
| <> |
| <style>{` |
| @import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap'); |
| * { box-sizing: border-box; margin: 0; padding: 0; } |
| :root { --blue: #3b82f6; --blue-dark: #1d4ed8; --blue-light: #eff6ff; --blue-mid: #dbeafe; } |
| |
| @keyframes fadeUp { from { opacity:0; transform:translateY(30px); } to { opacity:1; transform:translateY(0); } } |
| @keyframes fadeIn { from { opacity:0; } to { opacity:1; } } |
| @keyframes float { 0%,100%{transform:translateY(0) rotate(-2deg);} 50%{transform:translateY(-16px) rotate(2deg);} } |
| @keyframes float2 { 0%,100%{transform:translateY(0) rotate(3deg);} 50%{transform:translateY(-10px) rotate(-3deg);} } |
| @keyframes bobble { 0%,100%{transform:translateY(0);} 50%{transform:translateY(-8px);} } |
| @keyframes spin { to{transform:rotate(360deg);} } |
| @keyframes shake { 0%,100%{transform:translateX(0);} 20%{transform:translateX(-5px);} 40%{transform:translateX(5px);} 60%{transform:translateX(-3px);} 80%{transform:translateX(3px);} } |
| @keyframes slideLeft { from{opacity:1;transform:translateX(0);} to{opacity:0;transform:translateX(-120%);} } |
| @keyframes slideInRight { from{opacity:0;transform:translateX(60px);} to{opacity:1;transform:translateX(0);} } |
| @keyframes scaleIn { from{opacity:0;transform:scale(0.92);} to{opacity:1;transform:scale(1);} } |
| @keyframes blob { 0%,100%{border-radius:60% 40% 30% 70%/60% 30% 70% 40%;} 50%{border-radius:30% 60% 70% 40%/50% 60% 30% 60%;} } |
| @keyframes pulse { 0%,100%{opacity:0.15;transform:scale(1);} 50%{opacity:0.3;transform:scale(1.05);} } |
| @keyframes dotBounce { 0%,80%,100%{transform:translateY(0);} 40%{transform:translateY(-8px);} } |
| |
| input::placeholder { color: #93c5fd; } |
| input:-webkit-autofill { -webkit-box-shadow: 0 0 0 30px #eff6ff inset !important; } |
| .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 8px 28px rgba(59,130,246,0.45) !important; } |
| .btn-primary:active { transform: translateY(0); } |
| .input-field:focus { border-color: #3b82f6 !important; box-shadow: 0 0 0 3px rgba(59,130,246,0.15) !important; } |
| `}</style> |
| |
| <div style={{ minHeight:'100vh', fontFamily:'Plus Jakarta Sans, sans-serif', background:'#f0f7ff', overflow:'hidden', position:'relative' }}> |
| |
| {/* === LANDING PHASE === */} |
| {(phase === 'landing' || phase === 'transitioning') && ( |
| <div style={{ |
| position:'absolute', inset:0, display:'flex', alignItems:'stretch', |
| animation: phase==='transitioning' ? 'slideLeft 0.65s cubic-bezier(0.4,0,0.2,1) forwards' : 'fadeIn 0.5s ease both', |
| }}> |
| {/* Left Panel */} |
| <div style={{ flex:'0 0 45%', background:'#fff', display:'flex', flexDirection:'column', justifyContent:'center', padding:'60px 56px', position:'relative', zIndex:2 }}> |
| {/* Logo */} |
| <div style={{ display:'flex', alignItems:'center', gap:'10px', marginBottom:'56px', animation:'fadeUp 0.6s ease 0.1s both' }}> |
| <div style={{ width:36, height:36, borderRadius:10, background:'linear-gradient(135deg,#3b82f6,#1d4ed8)', display:'flex', alignItems:'center', justifyContent:'center' }}> |
| <span style={{ color:'#fff', fontWeight:800, fontSize:16 }}>CE</span> |
| </div> |
| <span style={{ fontWeight:700, fontSize:18, color:'#1e3a8a', letterSpacing:'-0.02em' }}>Candidate Explorer</span> |
| </div> |
| |
| <div style={{ animation:'fadeUp 0.6s ease 0.2s both' }}> |
| <p style={{ fontSize:12, fontWeight:700, letterSpacing:'0.12em', textTransform:'uppercase', color:'#3b82f6', marginBottom:12 }}>AI-Powered Recruiting</p> |
| <h1 style={{ fontSize:42, fontWeight:800, lineHeight:1.1, color:'#1e3a8a', letterSpacing:'-0.03em', marginBottom:20 }}> |
| Find the best<br/> |
| <span style={{ color:'#3b82f6' }}>candidates</span><br/> |
| faster. |
| </h1> |
| <p style={{ fontSize:15, color:'#64748b', lineHeight:1.7, maxWidth:340, marginBottom:40 }}> |
| Our intelligent platform analyzes thousands of profiles in seconds, so your team can focus on what matters β building great teams. |
| </p> |
| </div> |
| |
| <div style={{ display:'flex', flexDirection:'column', gap:12, animation:'fadeUp 0.6s ease 0.35s both' }}> |
| <button onClick={handleGetStarted} className="btn-primary" style={{ |
| padding:'16px 32px', background:'linear-gradient(135deg,#3b82f6,#2563eb)', |
| border:'none', borderRadius:14, color:'#fff', fontSize:15, fontWeight:700, |
| cursor:'pointer', transition:'all 0.25s ease', |
| boxShadow:'0 4px 16px rgba(59,130,246,0.35)', |
| letterSpacing:'-0.01em', |
| }}> |
| Get Started β |
| </button> |
| {/* <button style={{ |
| padding:'14px 32px', background:'transparent', |
| border:'2px solid #dbeafe', borderRadius:14, color:'#3b82f6', fontSize:15, fontWeight:600, |
| cursor:'pointer', transition:'all 0.2s ease', |
| }}> |
| Learn More |
| </button> */} |
| </div> |
| |
| {/* Stats */} |
| {/* <div style={{ display:'flex', gap:32, marginTop:48, animation:'fadeUp 0.6s ease 0.45s both' }}> |
| {[['10k+','Candidates'],['98%','Accuracy'],['3x','Faster Hiring']].map(([val,label]) => ( |
| <div key={label}> |
| <div style={{ fontSize:20, fontWeight:800, color:'#1e3a8a' }}>{val}</div> |
| <div style={{ fontSize:11, color:'#94a3b8', fontWeight:500, marginTop:2 }}>{label}</div> |
| </div> |
| ))} |
| </div> */} |
| </div> |
| |
| {/* Right Panel */} |
| <div style={{ flex:1, background:'linear-gradient(135deg,#1d4ed8 0%,#2563eb 40%,#3b82f6 100%)', position:'relative', overflow:'hidden', display:'flex', alignItems:'center', justifyContent:'center' }}> |
| {/* Blob shapes */} |
| <div style={{ position:'absolute', top:'-10%', right:'-5%', width:400, height:400, background:'rgba(255,255,255,0.06)', borderRadius:'60% 40% 30% 70%/60% 30% 70% 40%', animation:'blob 8s ease-in-out infinite' }} /> |
| <div style={{ position:'absolute', bottom:'-10%', left:'-5%', width:350, height:350, background:'rgba(255,255,255,0.04)', borderRadius:'40% 60% 70% 30%/40% 50% 60% 50%', animation:'blob 10s ease-in-out 2s infinite' }} /> |
| {/* Dots grid */} |
| <div style={{ position:'absolute', inset:0, opacity:0.1, backgroundImage:'radial-gradient(circle, #fff 1px, transparent 1px)', backgroundSize:'28px 28px' }} /> |
| |
| {/* Robot images */} |
| <div style={{ position:'relative', display:'flex', alignItems:'flex-end', gap:24 }}> |
| <img src="/loading2.png" alt="robot" style={{ width:200, height:200, objectFit:'contain', animation:'float 4s ease-in-out infinite', filter:'drop-shadow(0 20px 40px rgba(0,0,0,0.25))' }} /> |
| <img src="/loading1.png" alt="robot" style={{ width:180, height:180, objectFit:'contain', animation:'float2 5s ease-in-out 0.8s infinite', filter:'drop-shadow(0 20px 40px rgba(0,0,0,0.2))' }} /> |
| </div> |
| |
| {/* Feature chips */} |
| <div style={{ position:'absolute', top:60, left:40, animation:'fadeUp 0.8s ease 0.5s both' }}> |
| <div style={{ background:'rgba(255,255,255,0.15)', backdropFilter:'blur(12px)', borderRadius:12, padding:'10px 16px', color:'#fff', fontSize:13, fontWeight:600, border:'1px solid rgba(255,255,255,0.2)' }}> |
| π€ AI Resume Analysis |
| </div> |
| </div> |
| <div style={{ position:'absolute', top:120, right:40, animation:'fadeUp 0.8s ease 0.65s both' }}> |
| <div style={{ background:'rgba(255,255,255,0.15)', backdropFilter:'blur(12px)', borderRadius:12, padding:'10px 16px', color:'#fff', fontSize:13, fontWeight:600, border:'1px solid rgba(255,255,255,0.2)' }}> |
| π Smart Rankings |
| </div> |
| </div> |
| <div style={{ position:'absolute', bottom:80, right:48, animation:'fadeUp 0.8s ease 0.8s both' }}> |
| <div style={{ background:'rgba(255,255,255,0.15)', backdropFilter:'blur(12px)', borderRadius:12, padding:'10px 16px', color:'#fff', fontSize:13, fontWeight:600, border:'1px solid rgba(255,255,255,0.2)' }}> |
| β‘ Real-time Matching |
| </div> |
| </div> |
| <div style={{ position:'absolute', top:200, right:60, animation:'fadeUp 0.8s ease 0.5s both' }}> |
| <div style={{ background:'rgba(255,255,255,0.15)', backdropFilter:'blur(12px)', borderRadius:12, padding:'10px 16px', color:'#fff', fontSize:13, fontWeight:600, border:'1px solid rgba(255,255,255,0.2)' }}> |
| π§ Skill Gap Detection |
| </div> |
| </div> |
| <div style={{ position:'absolute', bottom:160, left:36, animation:'fadeUp 0.8s ease 0.5s both' }}> |
| <div style={{ background:'rgba(255,255,255,0.15)', backdropFilter:'blur(12px)', borderRadius:12, padding:'10px 16px', color:'#fff', fontSize:13, fontWeight:600, border:'1px solid rgba(255,255,255,0.2)' }}> |
| π Automated Shortlisting |
| </div> |
| </div> |
| <div style={{ position:'absolute', bottom:40, left:100, animation:'fadeUp 0.8s ease 0.5s both' }}> |
| <div style={{ background:'rgba(255,255,255,0.15)', backdropFilter:'blur(12px)', borderRadius:12, padding:'10px 16px', color:'#fff', fontSize:13, fontWeight:600, border:'1px solid rgba(255,255,255,0.2)' }}> |
| π― Culture Fit Scoring |
| </div> |
| </div> |
| </div> |
| </div> |
| )} |
| |
| {/* === LOGIN PHASE === */} |
| {phase === 'login' && ( |
| <div style={{ |
| position:'absolute', inset:0, display:'flex', alignItems:'stretch', |
| animation:'scaleIn 0.5s cubic-bezier(0.16,1,0.3,1) both', |
| }}> |
| {/* Left: Form */} |
| <div style={{ flex:'0 0 50%', background:'#fff', display:'flex', flexDirection:'column', justifyContent:'center', padding:'60px 64px', position:'relative' }}> |
| {/* Back button */} |
| <button onClick={() => setPhase('landing')} style={{ |
| position:'absolute', top:32, left:40, |
| background:'none', border:'none', cursor:'pointer', |
| color:'#64748b', fontSize:13, fontWeight:600, |
| display:'flex', alignItems:'center', gap:6, |
| padding:'6px 10px', borderRadius:8, |
| transition:'color 0.2s', |
| }}> |
| β Back |
| </button> |
| |
| {/* Logo */} |
| <div style={{ display:'flex', alignItems:'center', gap:10, marginBottom:48, animation:'fadeUp 0.5s ease 0.05s both' }}> |
| <div style={{ width:36, height:36, borderRadius:10, background:'linear-gradient(135deg,#3b82f6,#1d4ed8)', display:'flex', alignItems:'center', justifyContent:'center' }}> |
| <span style={{ color:'#fff', fontWeight:800, fontSize:16 }}>CE</span> |
| </div> |
| <span style={{ fontWeight:700, fontSize:18, color:'#1e3a8a', letterSpacing:'-0.02em' }}>Candidate Explorer</span> |
| </div> |
| |
| <div style={{ animation:'fadeUp 0.5s ease 0.1s both' }}> |
| <h2 style={{ fontSize:32, fontWeight:800, color:'#1e3a8a', letterSpacing:'-0.03em', marginBottom:8 }}>Welcome back π</h2> |
| <p style={{ color:'#64748b', fontSize:14, marginBottom:36 }}>Sign in to your account to continue</p> |
| </div> |
| |
| {error && ( |
| <div style={{ background:'#fef2f2', border:'1px solid #fecaca', color:'#dc2626', padding:'12px 16px', borderRadius:10, fontSize:13, marginBottom:20, animation:'shake 0.4s ease' }}> |
| {error} |
| </div> |
| )} |
| |
| <form onSubmit={handleSubmit} style={{ display:'flex', flexDirection:'column', gap:18, animation:'fadeUp 0.5s ease 0.2s both' }}> |
| <div> |
| <label style={{ display:'block', fontSize:12, fontWeight:700, color:'#374151', marginBottom:8, letterSpacing:'0.04em' }}>USERNAME</label> |
| <input |
| type="text" value={username} |
| onChange={e => setUsername(e.target.value)} |
| onFocus={() => setFocused('user')} onBlur={() => setFocused(null)} |
| placeholder="Enter your username" |
| required disabled={isLoading} |
| className="input-field" |
| style={{ width:'100%', padding:'14px 16px', border:'2px solid #e2e8f0', borderRadius:12, fontSize:14, color:'#1e293b', outline:'none', transition:'all 0.25s ease', background:'#f8faff' }} |
| /> |
| </div> |
| <div> |
| <div style={{ display:'flex', justifyContent:'space-between', marginBottom:8 }}> |
| <label style={{ fontSize:12, fontWeight:700, color:'#374151', letterSpacing:'0.04em' }}>PASSWORD</label> |
| {/* <a href="#" style={{ fontSize:12, color:'#3b82f6', textDecoration:'none', fontWeight:600 }}>Forgot Password?</a> */} |
| </div> |
| <input |
| type="password" value={password} |
| onChange={e => setPassword(e.target.value)} |
| onFocus={() => setFocused('pass')} onBlur={() => setFocused(null)} |
| placeholder="β’β’β’β’β’β’β’β’" |
| required disabled={isLoading} |
| className="input-field" |
| style={{ width:'100%', padding:'14px 16px', border:'2px solid #e2e8f0', borderRadius:12, fontSize:14, color:'#1e293b', outline:'none', transition:'all 0.25s ease', background:'#f8faff' }} |
| /> |
| </div> |
| |
| <button type="submit" disabled={isLoading} className="btn-primary" style={{ |
| marginTop:8, padding:'16px', |
| background:isLoading ? '#93c5fd' : 'linear-gradient(135deg,#3b82f6,#2563eb)', |
| border:'none', borderRadius:14, color:'#fff', fontSize:15, fontWeight:700, |
| cursor: isLoading ? 'not-allowed' : 'pointer', |
| transition:'all 0.25s ease', |
| boxShadow:'0 4px 16px rgba(59,130,246,0.35)', |
| letterSpacing:'-0.01em', |
| }}> |
| {isLoading ? ( |
| <span style={{ display:'flex', alignItems:'center', justifyContent:'center', gap:10 }}> |
| <span style={{ width:16,height:16,border:'2.5px solid rgba(255,255,255,0.4)',borderTop:'2.5px solid #fff',borderRadius:'50%',display:'inline-block',animation:'spin 0.7s linear infinite' }} /> |
| Signing in... |
| </span> |
| ) : 'Sign In'} |
| </button> |
| </form> |
| |
| {/* <p style={{ marginTop:28, textAlign:'center', fontSize:13, color:'#94a3b8', animation:'fadeUp 0.5s ease 0.35s both' }}> |
| {"Don't have an account? "} |
| <a href="#" style={{ color:'#3b82f6', fontWeight:700, textDecoration:'none' }}>Sign up</a> |
| </p> */} |
| |
| <div style={{ marginTop:'auto', paddingTop:48, display:'flex', justifyContent:'center', gap:24, animation:'fadeUp 0.5s ease 0.4s both' }}> |
| {['FAQ','Features','Support'].map(item => ( |
| <a key={item} href="#" style={{ fontSize:12, color:'#94a3b8', textDecoration:'none', fontWeight:500 }}>{item}</a> |
| ))} |
| </div> |
| </div> |
| |
| {/* Right: Illustration */} |
| <div style={{ flex:1, background:'linear-gradient(160deg,#1e40af 0%,#2563eb 50%,#3b82f6 100%)', position:'relative', overflow:'hidden', display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', gap:32 }}> |
| <div style={{ position:'absolute', inset:0, opacity:0.08, backgroundImage:'radial-gradient(circle, #fff 1px, transparent 1px)', backgroundSize:'24px 24px' }} /> |
| <div style={{ position:'absolute', top:'-15%', right:'-10%', width:450, height:450, background:'rgba(255,255,255,0.05)', borderRadius:'60% 40% 30% 70%/60% 30% 70% 40%', animation:'blob 9s ease-in-out infinite' }} /> |
| |
| <div style={{ position:'relative', zIndex:1, textAlign:'center', padding:'0 40px', animation:'fadeUp 0.6s ease 0.2s both' }}> |
| <img src="robot-1.png" alt="robot" style={{ width:180, height:180, objectFit:'contain', animation:'bobble 3s ease-in-out infinite', filter:'drop-shadow(0 16px 32px rgba(0,0,0,0.3))' }} /> |
| <h3 style={{ color:'#fff', fontSize:26, fontWeight:800, marginTop:24, letterSpacing:'-0.02em' }}> |
| AI-Powered Recruitment |
| </h3> |
| <p style={{ color:'rgba(255,255,255,0.7)', fontSize:14, lineHeight:1.7, marginTop:12, maxWidth:300 }}> |
| Let our intelligent assistant help you discover the perfect candidates from thousands of applications. |
| </p> |
| </div> |
| |
| {/* Floating feature pills */} |
| <div style={{ position:'relative', zIndex:1, display:'flex', flexWrap:'wrap', gap:10, justifyContent:'center', padding:'0 48px', animation:'fadeUp 0.6s ease 0.4s both' }}> |
| {['β
Smart Screening','π Analytics','π Deep Search','β‘ Auto-Match'].map((feat, i) => ( |
| <div key={feat} style={{ background:'rgba(255,255,255,0.12)', backdropFilter:'blur(12px)', border:'1px solid rgba(255,255,255,0.2)', borderRadius:10, padding:'8px 14px', color:'#fff', fontSize:13, fontWeight:600, animation:`fadeUp 0.5s ease ${0.5+i*0.08}s both` }}> |
| {feat} |
| </div> |
| ))} |
| </div> |
| </div> |
| </div> |
| )} |
| </div> |
| </> |
| ); |
| } |