aibanking.dev / views /Login.tsx
admin08077's picture
Upload 26 files
b8b3edf verified
import React, { useState, useEffect, useRef } from 'react';
import {
ShieldCheck,
Cpu,
Key,
Terminal,
Lock,
Loader2,
CheckCircle2,
Zap,
ShieldAlert,
ArrowRight,
Fingerprint,
FileCheck,
UserPlus
} from 'lucide-react';
import { apiClient } from '../services/api.ts';
const Login: React.FC = () => {
const [loading, setLoading] = useState(false);
const [isRegistering, setIsRegistering] = useState(false);
const [stage, setStage] = useState<'IDLE' | 'AUTHORIZING' | 'CONSENT' | 'EXCHANGING' | 'VERIFIED'>('IDLE');
const [logs, setLogs] = useState<string[]>(["LQI Auth Engine v1.3.0 (Persistent DB) initializing..."]);
const [error, setError] = useState<string | null>(null);
const [successMsg, setSuccessMsg] = useState<string | null>(null);
const logEndRef = useRef<HTMLDivElement>(null);
const [params, setParams] = useState({
username: '',
password: '',
});
useEffect(() => {
logEndRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [logs]);
const addLog = (msg: string) => setLogs(prev => [...prev, `${new Date().toLocaleTimeString()} - ${msg}`]);
const handleAuth = async (e: React.FormEvent) => {
e.preventDefault();
if (loading) return;
setLoading(true);
setError(null);
setSuccessMsg(null);
addLog(`INIT: Establishing ${isRegistering ? 'Registration' : 'Login'} protocol handshake...`);
try {
if (isRegistering) {
const { success, error: regError } = await apiClient.auth.register(params.username, params.password);
if (success) {
addLog("DB_WRITE: New identity node successfully written to disk.");
setSuccessMsg("Registration complete. Initialize handshake to sign in.");
setIsRegistering(false);
} else {
throw new Error(regError || "Registration handshake denied.");
}
} else {
const { success, user, error: loginError } = await apiClient.auth.login(params.username, params.password);
if (success && user) {
addLog("DB_QUERY: Identity parity confirmed via cryptographic hash.");
setStage('VERIFIED');
setTimeout(() => {
window.dispatchEvent(new Event('auth-update'));
}, 1000);
} else {
throw new Error(loginError || "Handshake rejected by identity node.");
}
}
} catch (err: any) {
addLog(`CRITICAL: ${err.message}`);
setError(err.message);
} finally {
setLoading(false);
}
};
return (
<div className="min-h-screen bg-[#020202] flex items-center justify-center p-6 relative overflow-hidden font-sans">
<div className="absolute inset-0 z-0 opacity-10">
<div className="absolute top-0 left-0 w-full h-full bg-[radial-gradient(circle_at_50%_50%,_#1e1b4b_0%,_transparent_50%)]"></div>
<div className="matrix-line"></div>
</div>
<div className="w-full max-w-5xl grid grid-cols-1 lg:grid-cols-2 bg-zinc-950 border border-zinc-900 rounded-[48px] shadow-2xl relative z-10 overflow-hidden backdrop-blur-3xl">
<div className="p-12 bg-zinc-900/50 flex flex-col justify-between border-r border-zinc-900">
<div>
<div className="flex items-center space-x-3 mb-8">
<div className="w-12 h-12 bg-white rounded-2xl flex items-center justify-center shadow-xl">
<Cpu size={28} className="text-black" />
</div>
<div>
<h1 className="text-2xl font-black italic tracking-tighter text-white uppercase leading-none">
Lumina <span className="text-blue-500 not-italic">Quantum</span>
</h1>
<p className="text-[10px] uppercase tracking-[0.4em] font-bold text-zinc-500">Identity v1.3.0</p>
</div>
</div>
<div className="space-y-6">
<h2 className="text-4xl font-black text-white leading-tight tracking-tighter uppercase italic">
{isRegistering ? 'Register' : 'Handshake'} <br />
<span className="text-blue-500 not-italic">Protocol</span>
</h2>
<p className="text-zinc-500 text-sm leading-relaxed max-w-xs font-medium italic">
Establish a secure session fabric using persistent node storage and RSA-OAEP-4096 hashing.
</p>
</div>
</div>
<div className="mt-10">
<div className="flex items-center gap-2 mb-4">
<Terminal size={14} className="text-blue-500" />
<span className="text-[9px] font-black uppercase text-zinc-600 tracking-widest">Quantum Trace Stream</span>
</div>
<div className="h-48 bg-black/80 rounded-3xl p-6 overflow-y-auto font-mono text-[10px] border border-zinc-900 custom-scrollbar">
{logs.map((log, i) => (
<div key={i} className={`mb-1 ${
log.includes('SUCCESS') || log.includes('DB_WRITE') ? 'text-emerald-400 font-bold' :
log.includes('INIT') || log.includes('DB_QUERY') ? 'text-blue-400' :
log.includes('CRITICAL') ? 'text-rose-500' : 'text-zinc-600'
}`}>
{log}
</div>
))}
<div ref={logEndRef} />
</div>
</div>
</div>
<div className="p-12 flex flex-col justify-center bg-black/20">
{stage === 'VERIFIED' ? (
<div className="text-center animate-in zoom-in-95 duration-500">
<div className="w-24 h-24 bg-emerald-500/10 border border-emerald-500/20 rounded-full flex items-center justify-center mx-auto mb-6 shadow-[0_0_50px_rgba(16,185,129,0.2)]">
<CheckCircle2 size={48} className="text-emerald-500" />
</div>
<h3 className="text-2xl font-black text-white uppercase italic tracking-tighter mb-2">Authenticated</h3>
<p className="text-zinc-500 text-[10px] font-black uppercase tracking-[0.4em] animate-pulse">Initializing Subspace Ledger...</p>
</div>
) : (
<div className="animate-in fade-in duration-500">
<div className="mb-10 flex items-center justify-between">
<h3 className="text-2xl font-black text-white uppercase italic tracking-tighter">
{isRegistering ? 'Create Identity' : 'Identity Core'}
</h3>
<div className="flex items-center gap-2 px-3 py-1 bg-blue-600/10 border border-blue-500/20 rounded-full">
<Fingerprint size={12} className="text-blue-500" />
<span className="text-[9px] font-black text-blue-500 uppercase">Secure Link</span>
</div>
</div>
<form onSubmit={handleAuth} className="space-y-6">
<div className="space-y-4">
<div className="space-y-2">
<label className="text-[10px] font-black text-zinc-600 uppercase tracking-widest ml-1">Universal UID</label>
<div className="relative">
<Key className="absolute left-4 top-1/2 -translate-y-1/2 text-zinc-700" size={16} />
<input
value={params.username}
onChange={(e) => setParams({...params, username: e.target.value})}
className="w-full bg-black border border-zinc-800 rounded-2xl py-4 pl-12 pr-4 text-white font-mono text-sm outline-none focus:border-blue-500 transition-all shadow-inner"
placeholder="Node Identifier"
required
/>
</div>
</div>
<div className="space-y-2">
<label className="text-[10px] font-black text-zinc-600 uppercase tracking-widest ml-1">Private Secret</label>
<div className="relative">
<Lock className="absolute left-4 top-1/2 -translate-y-1/2 text-zinc-700" size={16} />
<input
type="password"
value={params.password}
onChange={(e) => setParams({...params, password: e.target.value})}
className="w-full bg-black border border-zinc-800 rounded-2xl py-4 pl-12 pr-4 text-white font-mono text-sm outline-none focus:border-blue-500 transition-all shadow-inner"
placeholder="••••••••"
required
/>
</div>
</div>
</div>
{error && (
<div className="flex items-center gap-3 text-rose-500 text-xs p-4 bg-rose-500/10 rounded-2xl border border-rose-500/20 animate-pulse">
<ShieldAlert size={16} /> {error}
</div>
)}
{successMsg && (
<div className="flex items-center gap-3 text-emerald-500 text-xs p-4 bg-emerald-500/10 rounded-2xl border border-emerald-500/20">
<CheckCircle2 size={16} /> {successMsg}
</div>
)}
<button
type="submit"
disabled={loading}
className="w-full bg-blue-600 hover:bg-blue-500 text-white rounded-[2rem] py-5 font-black text-xs uppercase tracking-[0.3em] transition-all flex items-center justify-center gap-3 shadow-xl group disabled:opacity-50"
>
{loading ? (
<>
<Loader2 className="animate-spin" size={18} />
<span>Processing...</span>
</>
) : (
<>
<span>{isRegistering ? 'Register Node' : 'Initialize Handshake'}</span>
{isRegistering ? <UserPlus size={18} /> : <ArrowRight size={18} className="group-hover:translate-x-1 transition-transform" />}
</>
)}
</button>
<button
type="button"
onClick={() => {
setIsRegistering(!isRegistering);
setError(null);
setSuccessMsg(null);
}}
className="w-full text-[10px] font-black text-zinc-600 hover:text-white uppercase tracking-widest transition-colors"
>
{isRegistering ? 'Abort Registration / Return to Hub' : 'Request New Identity Node'}
</button>
</form>
</div>
)}
</div>
</div>
</div>
);
};
export default Login;