173 lines
5.2 KiB
React
173 lines
5.2 KiB
React
import React, { useState } from 'react';
|
|
import { Link, useNavigate, useLocation } from 'react-router-dom';
|
|
import { Shield, Mail, Lock, Sparkles, ArrowRight, Server } from 'lucide-react';
|
|
import { useAuth } from '../context/AuthContext';
|
|
import { Button } from '../components/common/Button';
|
|
import { Input } from '../components/common/Input';
|
|
import { Toast } from '../components/common/Toast';
|
|
import { ThemeToggle } from '../components/layout/ThemeToggle';
|
|
import { DEMO_USER } from '../services/mockData';
|
|
import '../styles/auth.css';
|
|
|
|
export function Login() {
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
const { login } = useAuth();
|
|
|
|
const [email, setEmail] = useState('');
|
|
const [password, setPassword] = useState('');
|
|
const [rememberMe, setRememberMe] = useState(true);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState(null);
|
|
|
|
// If redirected with registered email
|
|
React.useEffect(() => {
|
|
if (location.state?.registeredEmail) {
|
|
setEmail(location.state.registeredEmail);
|
|
}
|
|
}, [location.state]);
|
|
|
|
const handleSubmit = async (e) => {
|
|
e.preventDefault();
|
|
if (!email.trim() || !password.trim()) {
|
|
setError('Please provide both email and password.');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
setLoading(true);
|
|
setError(null);
|
|
await login(email, password);
|
|
navigate('/dashboard');
|
|
} catch (err) {
|
|
console.error('Login error:', err);
|
|
setError(err.message || 'Failed to authenticate. Please check your credentials.');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleQuickDemo = async () => {
|
|
setEmail(DEMO_USER.email);
|
|
setPassword('admin123');
|
|
try {
|
|
setLoading(true);
|
|
setError(null);
|
|
await login(DEMO_USER.email, 'admin123', true);
|
|
navigate('/dashboard');
|
|
} catch (err) {
|
|
setError(err.message);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="auth-container">
|
|
{/* Background Orbs */}
|
|
<div className="auth-bg-decorations">
|
|
<div className="auth-orb auth-orb-1" />
|
|
<div className="auth-orb auth-orb-2" />
|
|
<div className="auth-orb auth-orb-3" />
|
|
</div>
|
|
|
|
<div className="auth-card animate-fade-in">
|
|
{/* Top bar with Brand and Theme Toggle */}
|
|
<div className="auth-top-bar">
|
|
<div className="auth-brand">
|
|
<div className="auth-brand-icon">
|
|
<Shield size={22} />
|
|
</div>
|
|
<span className="auth-brand-name">AuthSec</span>
|
|
</div>
|
|
<ThemeToggle />
|
|
</div>
|
|
|
|
{/* Header */}
|
|
<div className="auth-header">
|
|
<h1 className="auth-title">Welcome back</h1>
|
|
<p className="auth-subtitle">Sign in to your enterprise security console</p>
|
|
</div>
|
|
|
|
{/* Demo Credentials Quick-Fill Banner */}
|
|
<div className="demo-quick-bar">
|
|
<div className="demo-quick-info">
|
|
<Sparkles size={16} />
|
|
<span>Demo: <strong>{DEMO_USER.email}</strong></span>
|
|
</div>
|
|
<button
|
|
type="button"
|
|
className="demo-quick-btn"
|
|
onClick={handleQuickDemo}
|
|
disabled={loading}
|
|
>
|
|
One-Click Login
|
|
</button>
|
|
</div>
|
|
|
|
{/* Error Toast */}
|
|
{error && <Toast type="error" message={error} onClose={() => setError(null)} />}
|
|
|
|
{/* Login Form */}
|
|
<form onSubmit={handleSubmit} className="auth-form" noValidate>
|
|
<Input
|
|
label="Email Address"
|
|
type="email"
|
|
placeholder="admin@authsec.com"
|
|
value={email}
|
|
onChange={(e) => setEmail(e.target.value)}
|
|
icon={Mail}
|
|
required
|
|
autoComplete="email"
|
|
/>
|
|
|
|
<Input
|
|
label="Password"
|
|
type="password"
|
|
placeholder="••••••••"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
icon={Lock}
|
|
required
|
|
autoComplete="current-password"
|
|
/>
|
|
|
|
<div className="auth-options">
|
|
<label className="auth-remember">
|
|
<input
|
|
type="checkbox"
|
|
className="auth-checkbox"
|
|
checked={rememberMe}
|
|
onChange={(e) => setRememberMe(e.target.checked)}
|
|
/>
|
|
<span>Remember this session</span>
|
|
</label>
|
|
<a href="#trouble" className="auth-link" onClick={(e) => { e.preventDefault(); setError('Contact security administrator to reset credential tokens.'); }}>
|
|
Forgot password?
|
|
</a>
|
|
</div>
|
|
|
|
<Button
|
|
type="submit"
|
|
variant="primary"
|
|
size="lg"
|
|
fullWidth
|
|
isLoading={loading}
|
|
icon={ArrowRight}
|
|
>
|
|
Sign In to AuthSec
|
|
</Button>
|
|
</form>
|
|
|
|
{/* Bottom Switch to Register */}
|
|
<div className="auth-footer">
|
|
Don't have an enterprise account?{' '}
|
|
<Link to="/register" className="auth-link">
|
|
Register here
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|