admin08077 commited on
Commit
1d7156d
·
verified ·
1 Parent(s): 63f04b7

Update App.tsx

Browse files
Files changed (1) hide show
  1. App.tsx +168 -90
App.tsx CHANGED
@@ -1,6 +1,5 @@
1
 
2
  import React, { useState, useEffect } from 'react';
3
- /* Fix: react-router-dom exports may be flaky in this environment, using standard v6 imports */
4
  import { HashRouter, Routes, Route, Link, useLocation, Navigate } from 'react-router-dom';
5
  import {
6
  Leaf,
@@ -11,9 +10,12 @@ import {
11
  Cpu,
12
  Settings as SettingsIcon,
13
  Terminal,
14
- Loader2
 
 
 
 
15
  } from 'lucide-react';
16
- /* Fix: removed .ts extensions from imports */
17
  import { routes } from './views/routes';
18
  import Login from './views/Login';
19
  import Landing from './views/Landing';
@@ -23,6 +25,66 @@ import Airdrop from './views/Airdrop';
23
  import { apiClient } from './services/api';
24
  import { UserSession } from './types/index';
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  const SidebarItem: React.FC<{ icon: any, label: string, path: string, active: boolean }> = ({ icon: Icon, label, path, active }) => (
27
  <Link
28
  to={path}
@@ -102,101 +164,61 @@ const Header = ({ user, onLogout }: { user: UserSession, onLogout: () => void })
102
  );
103
  };
104
 
105
- const App: React.FC = () => {
106
- const [currentUser, setCurrentUser] = useState<UserSession | null>(null);
107
- const [isAuthChecked, setIsAuthChecked] = useState<boolean>(false);
108
 
109
- const checkAuthStatus = async () => {
110
- const { user } = await apiClient.auth.me();
111
- setCurrentUser(user);
112
- setIsAuthChecked(true);
113
- };
114
-
115
- useEffect(() => {
116
- checkAuthStatus();
117
- window.addEventListener('auth-update', checkAuthStatus);
118
- return () => window.removeEventListener('auth-update', checkAuthStatus);
119
- }, []);
120
-
121
- const handleLogout = async () => {
122
- await apiClient.auth.logout();
123
- setCurrentUser(null);
124
- window.dispatchEvent(new Event('auth-update'));
125
- };
126
-
127
- if (!isAuthChecked) {
128
- return (
129
- <div className="min-h-screen bg-[#020202] flex flex-col items-center justify-center space-y-8">
130
- <Loader2 className="animate-spin text-blue-500" size={48} />
131
- <p className="text-[10px] font-black text-zinc-600 uppercase tracking-[0.4em] animate-pulse">Initializing Neural Link...</p>
132
- </div>
133
- );
134
- }
135
-
136
- if (!currentUser) {
137
- return (
138
- <HashRouter>
139
- <Routes>
140
- <Route path="/" element={<Landing />} />
141
- <Route path="/login" element={<Login />} />
142
- <Route path="/airdrop" element={<Airdrop />} />
143
- <Route path="/manifesto" element={<PrivacyPolicy />} />
144
- <Route path="/documentation" element={<Documentation />} />
145
- <Route path="*" element={<Navigate to="/" replace />} />
146
- </Routes>
147
- </HashRouter>
148
- );
149
  }
150
 
151
  return (
152
- <HashRouter>
153
- <div className="flex min-h-screen bg-[#020202] text-zinc-400 antialiased selection:bg-blue-500/30 selection:text-blue-200 font-sans">
154
- <div className="fixed inset-0 pointer-events-none opacity-[0.03] z-0 overflow-hidden">
155
- <div className="absolute inset-0 bg-[linear-gradient(to_right,#80808012_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-[size:40px_40px]"></div>
156
- </div>
157
 
158
- <aside className="w-80 fixed h-full bg-[#050505] border-r border-zinc-900 p-8 flex flex-col print:hidden z-50">
159
- <div className="mb-14 px-4 flex items-center space-x-4">
160
- <div className="w-12 h-12 bg-white rounded-2xl flex items-center justify-center shadow-2xl shadow-white/5">
161
- <Cpu size={24} className="text-black" />
162
- </div>
163
- <div>
164
- <h1 className="text-lg font-black italic tracking-tighter text-white uppercase leading-none">
165
- Lumina <span className="text-blue-500 not-italic">Quantum</span>
166
- </h1>
167
- <p className="text-[9px] uppercase tracking-[0.4em] font-bold text-zinc-600 mt-1">Institutional Ledger</p>
168
- </div>
169
  </div>
170
-
171
- <nav className="flex-1 space-y-2 overflow-y-auto custom-scrollbar pr-2 pb-10">
172
- <NavigationLinks />
173
- </nav>
174
-
175
- <div className="mt-auto pt-10 border-t border-zinc-900">
176
- <SidebarItem icon={SettingsIcon} label="System Config" path="/settings" active={window.location.hash.includes('settings')} />
177
- <div className="mt-8 p-6 bg-zinc-950 border border-zinc-900 rounded-[2rem] flex items-center justify-between group cursor-help shadow-2xl">
178
- <div className="flex items-center gap-3">
179
- <Activity size={16} className="text-emerald-500" />
180
- <span className="text-[9px] font-black uppercase tracking-widest text-zinc-500">Node Reachable</span>
181
- </div>
182
- <div className="w-2 h-2 bg-emerald-500 rounded-full animate-pulse shadow-[0_0_8px_rgba(16,185,129,0.5)]"></div>
183
- </div>
184
  </div>
185
- </aside>
186
-
187
- <main className="flex-1 ml-80 min-h-screen flex flex-col relative z-10 print:ml-0 print:bg-white">
188
- <Header user={currentUser} onLogout={handleLogout} />
189
- <div className="px-10 pb-20 print:p-0">
190
- <Routes>
191
- {routes.map((route) => (
192
- <Route key={route.path} path={route.path} element={<route.component />} />
193
- ))}
194
- <Route path="*" element={<Navigate to="/" replace />} />
195
- </Routes>
 
 
 
196
  </div>
197
- </main>
198
- </div>
199
- </HashRouter>
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  );
201
  };
202
 
@@ -228,4 +250,60 @@ const NavigationLinks = () => {
228
  );
229
  };
230
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  export default App;
 
1
 
2
  import React, { useState, useEffect } from 'react';
 
3
  import { HashRouter, Routes, Route, Link, useLocation, Navigate } from 'react-router-dom';
4
  import {
5
  Leaf,
 
10
  Cpu,
11
  Settings as SettingsIcon,
12
  Terminal,
13
+ Loader2,
14
+ Key as KeyIcon,
15
+ ShieldCheck,
16
+ ArrowRight,
17
+ Zap
18
  } from 'lucide-react';
 
19
  import { routes } from './views/routes';
20
  import Login from './views/Login';
21
  import Landing from './views/Landing';
 
25
  import { apiClient } from './services/api';
26
  import { UserSession } from './types/index';
27
 
28
+ const KeyGateway = ({ onAuthorized }: { onAuthorized: () => void }) => {
29
+ const [key, setKey] = useState('');
30
+ const [verifying, setVerifying] = useState(false);
31
+
32
+ const handleSubmit = (e: React.FormEvent) => {
33
+ e.preventDefault();
34
+ if (!key.trim()) return;
35
+ setVerifying(true);
36
+ localStorage.setItem('LQI_API_KEY', key.trim());
37
+ setTimeout(() => {
38
+ setVerifying(false);
39
+ onAuthorized();
40
+ }, 1000);
41
+ };
42
+
43
+ return (
44
+ <div className="min-h-screen bg-[#020202] flex items-center justify-center p-6 font-sans">
45
+ <div className="absolute inset-0 z-0 opacity-10">
46
+ <div className="matrix-line"></div>
47
+ </div>
48
+ <div className="w-full max-w-md bg-zinc-950 border border-zinc-900 rounded-[3rem] p-12 shadow-2xl relative z-10">
49
+ <div className="flex flex-col items-center text-center mb-10">
50
+ <div className="w-16 h-16 bg-blue-600/10 text-blue-500 rounded-3xl flex items-center justify-center mb-6 border border-blue-500/20">
51
+ <KeyIcon size={32} />
52
+ </div>
53
+ <h2 className="text-3xl font-black text-white italic tracking-tighter uppercase mb-2">Neural <span className="text-blue-500 not-italic">Handshake</span></h2>
54
+ <p className="text-zinc-600 text-[10px] font-black uppercase tracking-[0.3em]">Initialize Gemini Core Access</p>
55
+ </div>
56
+
57
+ <form onSubmit={handleSubmit} className="space-y-6">
58
+ <div className="space-y-2">
59
+ <label className="text-[10px] font-black text-zinc-700 uppercase tracking-widest ml-1">LQI_PRIVATE_KEY</label>
60
+ <input
61
+ type="password"
62
+ value={key}
63
+ onChange={(e) => setKey(e.target.value)}
64
+ placeholder="Enter Gemini API Key..."
65
+ className="w-full bg-black border border-zinc-800 focus:border-blue-500 rounded-2xl py-5 px-6 text-white font-mono text-sm outline-none transition-all shadow-inner"
66
+ required
67
+ />
68
+ </div>
69
+
70
+ <button
71
+ type="submit"
72
+ disabled={verifying}
73
+ 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 shadow-blue-900/40"
74
+ >
75
+ {verifying ? <Loader2 className="animate-spin" size={18} /> : (
76
+ <>
77
+ <span>Initialize Node</span>
78
+ <ArrowRight size={18} />
79
+ </>
80
+ )}
81
+ </button>
82
+ </form>
83
+ </div>
84
+ </div>
85
+ );
86
+ };
87
+
88
  const SidebarItem: React.FC<{ icon: any, label: string, path: string, active: boolean }> = ({ icon: Icon, label, path, active }) => (
89
  <Link
90
  to={path}
 
164
  );
165
  };
166
 
167
+ const PrivateTerminal = ({ user, onLogout }: { user: UserSession, onLogout: () => void }) => {
168
+ const [isKeyAuthorized, setIsKeyAuthorized] = useState(!!localStorage.getItem('LQI_API_KEY'));
 
169
 
170
+ if (!isKeyAuthorized) {
171
+ return <KeyGateway onAuthorized={() => setIsKeyAuthorized(true)} />;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  }
173
 
174
  return (
175
+ <div className="flex min-h-screen bg-[#020202] text-zinc-400 antialiased selection:bg-blue-500/30 selection:text-blue-200 font-sans">
176
+ <div className="fixed inset-0 pointer-events-none opacity-[0.03] z-0 overflow-hidden">
177
+ <div className="absolute inset-0 bg-[linear-gradient(to_right,#80808012_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-[size:40px_40px]"></div>
178
+ </div>
 
179
 
180
+ <aside className="w-80 fixed h-full bg-[#050505] border-r border-zinc-900 p-8 flex flex-col print:hidden z-50">
181
+ <div className="mb-14 px-4 flex items-center space-x-4">
182
+ <div className="w-12 h-12 bg-white rounded-2xl flex items-center justify-center shadow-2xl shadow-white/5">
183
+ <Cpu size={24} className="text-black" />
 
 
 
 
 
 
 
184
  </div>
185
+ <div>
186
+ <h1 className="text-lg font-black italic tracking-tighter text-white uppercase leading-none">
187
+ Lumina <span className="text-blue-500 not-italic">Quantum</span>
188
+ </h1>
189
+ <p className="text-[9px] uppercase tracking-[0.4em] font-bold text-zinc-600 mt-1">Institutional Ledger</p>
 
 
 
 
 
 
 
 
 
190
  </div>
191
+ </div>
192
+
193
+ <nav className="flex-1 space-y-2 overflow-y-auto custom-scrollbar pr-2 pb-10">
194
+ <NavigationLinks />
195
+ </nav>
196
+
197
+ <div className="mt-auto pt-10 border-t border-zinc-900">
198
+ <SidebarItem icon={SettingsIcon} label="System Config" path="/settings" active={window.location.hash.includes('settings')} />
199
+ <div className="mt-8 p-6 bg-zinc-950 border border-zinc-900 rounded-[2rem] flex items-center justify-between group cursor-help shadow-2xl">
200
+ <div className="flex items-center gap-3">
201
+ <Activity size={16} className="text-emerald-500" />
202
+ <span className="text-[9px] font-black uppercase tracking-widest text-zinc-500">Node Reachable</span>
203
+ </div>
204
+ <div className="w-2 h-2 bg-emerald-500 rounded-full animate-pulse shadow-[0_0_8px_rgba(16,185,129,0.5)]"></div>
205
  </div>
206
+ </div>
207
+ </aside>
208
+
209
+ <main className="flex-1 ml-80 min-h-screen flex flex-col relative z-10 print:ml-0 print:bg-white">
210
+ <Header user={user} onLogout={onLogout} />
211
+ <div className="px-10 pb-20 print:p-0">
212
+ <Routes>
213
+ {routes.map((route) => (
214
+ <Route key={route.path} path={route.path} element={<route.component />} />
215
+ ))}
216
+ {/* Relative catch-all for terminal paths */}
217
+ <Route path="*" element={<Navigate to="/" replace />} />
218
+ </Routes>
219
+ </div>
220
+ </main>
221
+ </div>
222
  );
223
  };
224
 
 
250
  );
251
  };
252
 
253
+ const App: React.FC = () => {
254
+ const [currentUser, setCurrentUser] = useState<UserSession | null>(null);
255
+ const [isAuthChecked, setIsAuthChecked] = useState<boolean>(false);
256
+
257
+ const checkAuthStatus = async () => {
258
+ const { user } = await apiClient.auth.me();
259
+ setCurrentUser(user);
260
+ setIsAuthChecked(true);
261
+ };
262
+
263
+ useEffect(() => {
264
+ checkAuthStatus();
265
+ window.addEventListener('auth-update', checkAuthStatus);
266
+ return () => window.removeEventListener('auth-update', checkAuthStatus);
267
+ }, []);
268
+
269
+ const handleLogout = async () => {
270
+ await apiClient.auth.logout();
271
+ setCurrentUser(null);
272
+ window.dispatchEvent(new Event('auth-update'));
273
+ };
274
+
275
+ if (!isAuthChecked) {
276
+ return (
277
+ <div className="min-h-screen bg-[#020202] flex flex-col items-center justify-center space-y-8">
278
+ <Loader2 className="animate-spin text-blue-500" size={48} />
279
+ <p className="text-[10px] font-black text-zinc-600 uppercase tracking-[0.4em] animate-pulse">Synchronizing Node Registry...</p>
280
+ </div>
281
+ );
282
+ }
283
+
284
+ return (
285
+ <HashRouter>
286
+ <Routes>
287
+ <Route path="/" element={<Landing />} />
288
+ <Route path="/login" element={<Login />} />
289
+ <Route path="/airdrop" element={<Airdrop />} />
290
+ <Route path="/manifesto" element={<PrivacyPolicy />} />
291
+ <Route path="/documentation" element={<Documentation />} />
292
+
293
+ {/* The terminal area handles its own key authorization logic inside */}
294
+ <Route
295
+ path="/*"
296
+ element={
297
+ currentUser ? (
298
+ <PrivateTerminal user={currentUser} onLogout={handleLogout} />
299
+ ) : (
300
+ <Navigate to="/login" replace />
301
+ )
302
+ }
303
+ />
304
+ </Routes>
305
+ </HashRouter>
306
+ );
307
+ };
308
+
309
  export default App;