File size: 10,860 Bytes
b8b3edf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236

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;