JenishMakwana's picture
feat: implement core frontend auth and chat interface components
da3aae2
Raw
History Blame Contribute Delete
8.26 kB
import { useState } from 'react';
import { Gavel, ShieldCheck, Scale, BrainCircuit, Eye, EyeOff } from 'lucide-react';
import { login, register } from '../api';
const logo = "https://huggingface.co/spaces/JenishMakwana/RAG/resolve/main/frontend-react/public/logo.png";
export default function Auth({ onLoginSuccess }) {
const [isLogin, setIsLogin] = useState(true);
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [showPassword, setShowPassword] = useState(false);
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const toggleAuthMode = () => {
setIsLogin(!isLogin);
setUsername('');
setEmail('');
setPassword('');
setError('');
setShowPassword(false);
};
const handleSubmit = async (e) => {
e.preventDefault();
setError('');
setLoading(true);
try {
if (isLogin) {
const data = await login(email, password);
onLoginSuccess(data.access_token, email);
} else {
// Frontend validation for complexity
const hasUpper = /[A-Z]/.test(password);
const hasNumber = /\d/.test(password);
const hasSpecial = /[@$!%*?&]/.test(password);
if (!hasUpper || !hasNumber || !hasSpecial || password.length < 8) {
throw new Error('Password does not meet complexity requirements.');
}
await register(username, email, password);
const data = await login(email, password);
onLoginSuccess(data.access_token, email);
}
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
return (
<div className="auth-screen">
{/* Left Panel: Legal Case Law Brand Info (Unique & Cinematic) */}
<div className="auth-graphic-side">
<div className="graphic-brand">
<div className="graphic-brand-logo" style={{
background: '#000000',
border: '1.5px solid rgba(168, 85, 247, 0.4)',
boxShadow: '0 8px 24px rgba(168, 85, 247, 0.25), inset 0 0 12px rgba(168, 85, 247, 0.2)',
padding: '2px'
}}>
<img src={logo} alt="Logo" style={{ width: '100%', height: '100%', objectFit: 'contain', borderRadius: '8px' }} />
</div>
<span className="graphic-brand-name">Legal Case Law RAG</span>
</div>
<div className="graphic-content">
<h2>The Supreme Intelligence for Case Law Research</h2>
<p>
An advanced, cloud-resilient legal analysis assistant powered by lightning-fast AI reranking and secure document audit guardrails.
</p>
<div className="feature-highlights">
<div className="feature-item">
<div className="feature-icon-wrapper">
<BrainCircuit size={18} />
</div>
<span className="feature-text">Dual Cloud LLM Failover & Real-Time Stream responses</span>
</div>
<div className="feature-item">
<div className="feature-icon-wrapper">
<Scale size={18} />
</div>
<span className="feature-text">High-Accuracy Indian Legal Embeddings & Reranking</span>
</div>
<div className="feature-item">
<div className="feature-icon-wrapper">
<ShieldCheck size={18} />
</div>
<span className="feature-text">Secure Native Cryptography & Document Audit Guardrails</span>
</div>
</div>
</div>
</div>
{/* Right Panel: The Interactive Sleek Glassmorphic Form Card */}
<div className="auth-form-side">
<div className="auth-card">
<div style={{ display: 'flex', justifyContent: 'center', marginBottom: '1.5rem' }}>
<div className="graphic-brand-logo" style={{
width: '64px',
height: '64px',
borderRadius: '16px',
background: '#000000',
border: '1.5px solid rgba(168, 85, 247, 0.4)',
boxShadow: '0 8px 24px rgba(168, 85, 247, 0.25), inset 0 0 12px rgba(168, 85, 247, 0.2)',
padding: '3px'
}}>
<img src={logo} alt="Logo" style={{ width: '100%', height: '100%', objectFit: 'contain', borderRadius: '12px' }} />
</div>
</div>
<h1>{isLogin ? 'Welcome Back' : 'Create Account'}</h1>
<p className="auth-subtitle">
{isLogin
? 'Sign in to access your legal documents and case analysis.'
: 'Create an account to start your legal case research.'}
</p>
<form onSubmit={handleSubmit}>
{!isLogin && (
<div className="form-group">
<label htmlFor="username">Username</label>
<input
id="username"
type="text"
placeholder="Case Manager ID"
value={username}
onChange={(e) => setUsername(e.target.value)}
required
/>
</div>
)}
<div className="form-group">
<label htmlFor="email">Email Address</label>
<input
id="email"
type="email"
placeholder="lawyer@firm.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<div className="password-input-wrapper" style={{ position: 'relative', display: 'flex', alignItems: 'center' }}>
<input
id="password"
type={showPassword ? 'text' : 'password'}
placeholder="••••••••"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
minLength={8}
style={{ paddingRight: '2.5rem', width: '100%' }}
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="password-toggle-btn"
style={{
position: 'absolute',
right: '1rem',
background: 'none',
border: 'none',
color: 'var(--text-muted)',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
padding: 0
}}
title={showPassword ? "Hide password" : "Show password"}
>
{showPassword ? <EyeOff size={18} /> : <Eye size={18} />}
</button>
</div>
{!isLogin && (
<p className="password-hint" style={{ fontSize: '0.7rem', color: 'var(--text-muted)', marginTop: '0.35rem', lineHeight: '1.4' }}>
Must contain 8+ characters, 1 uppercase, 1 number, and 1 special symbol.
</p>
)}
</div>
{error && (
<div style={{ color: '#ef4444', background: 'rgba(239, 68, 68, 0.1)', border: '1px solid rgba(239, 68, 68, 0.2)', padding: '0.75rem', borderRadius: '10px', marginBottom: '1.25rem', fontSize: '0.85rem', textAlign: 'center', fontWeight: '500' }}>
{error}
</div>
)}
<button type="submit" className="auth-btn" disabled={loading} style={{ width: '100%' }}>
{loading ? 'Processing...' : isLogin ? 'Sign In' : 'Create Account'}
</button>
</form>
<p className="toggle-auth" style={{ marginBottom: 0 }}>
{isLogin ? "New to Case Assistant? " : "Already have an account? "}
<span onClick={toggleAuthMode}>
{isLogin ? 'Create one now' : 'Sign in here'}
</span>
</p>
</div>
</div>
</div>
);
}