File size: 8,245 Bytes
bb0f10e
 
084aac3
bb0f10e
6b0e3cb
 
084aac3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bb0f10e
084aac3
 
 
 
 
 
 
 
 
 
 
1d7156d
bb0f10e
 
084aac3
bb0f10e
 
 
 
084aac3
 
bb0f10e
 
1d7156d
bb0f10e
1d7156d
084aac3
1d7156d
 
bb0f10e
1d7156d
bb0f10e
084aac3
1d7156d
 
 
6b0e3cb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1d7156d
 
bb0f10e
 
 
 
 
 
 
 
 
1d7156d
 
bb0f10e
1d7156d
bb0f10e
084aac3
1d7156d
 
 
bb0f10e
6b0e3cb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bb0f10e
1d7156d
 
 
 
bb0f10e
1d7156d
 
 
 
084aac3
 
 
1d7156d
 
 
 
bb0f10e
6b0e3cb
 
 
 
 
 
 
 
bb0f10e
1d7156d
 
bb0f10e
 
 
 
1d7156d
6b0e3cb
1d7156d
bb0f10e
 
 
 
 
 
1d7156d
 
 
 
 
 
 
6b0e3cb
bb0f10e
1d7156d
 
 
bb0f10e
6b0e3cb
bb0f10e
 
 
1d7156d
 
 
 
 
bb0f10e
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
import React, { useState, useEffect, useCallback } from 'react';
import { HashRouter, Routes, Route, Link, useLocation, Navigate, useNavigate } from 'react-router-dom';
import { 
  Bell, LogOut, Activity, ChevronRight, Cpu, Settings as SettingsIcon, Terminal, Loader2, Key,
  ShieldCheck, Zap, ArrowRight, ShieldAlert, Globe, Lock, Database, Shield, ZapOff, Fingerprint, Code,
  Server, Layers, Network
} from 'lucide-react';
import { routes } from './views/routes';
import Login from './views/Login';
import Landing from './views/Landing';
import PrivacyPolicy from './views/PrivacyPolicy';
import Documentation from './views/Documentation';
import Airdrop from './views/Airdrop';
import { apiClient } from './services/api';
import { UserSession } from './types/index';

const SidebarItem: React.FC<{ icon: any, label: string, path: string, active: boolean }> = ({ icon: Icon, label, path, active }) => (
  <Link 
    to={path} 
    className={`flex items-center justify-between px-6 py-4 rounded-2xl transition-all duration-500 group ${
      active 
        ? 'bg-white text-black shadow-2xl scale-[1.02]' 
        : 'text-zinc-500 hover:text-white hover:bg-zinc-900/50'
    }`}
  >
    <div className="flex items-center space-x-4">
      <Icon size={18} className={`${active ? 'text-black' : 'text-zinc-600 group-hover:text-blue-500'} transition-colors duration-500`} />
      <span className="font-black text-[10px] uppercase tracking-[0.2em]">{label}</span>
    </div>
    {active && <ChevronRight size={14} />}
  </Link>
);

const PrivateTerminal = ({ user, onLogout }: { user: UserSession, onLogout: () => void }) => {
  const location = useLocation();
  const navigate = useNavigate();

  const handleTerminate = async () => {
    await onLogout();
    navigate('/');
  };

  return (
    <div className="flex min-h-screen bg-[#020202] text-zinc-400 antialiased font-sans">
      <aside className="w-80 fixed h-full bg-[#050505] border-r border-zinc-900 p-8 flex flex-col z-50">
        <div className="mb-14 px-4 flex items-center space-x-4">
          <div className="w-12 h-12 bg-white rounded-2xl flex items-center justify-center shadow-2xl">
            <Cpu size={24} className="text-black" />
          </div>
          <div>
            <h1 className="text-lg font-black italic tracking-tighter text-white uppercase leading-none">
              AIBanking <span className="text-blue-500 not-italic">Core</span>
            </h1>
            <p className="text-[9px] uppercase tracking-[0.4em] font-bold text-zinc-600 mt-1">Institutional Mesh</p>
          </div>
        </div>
        
        <nav className="flex-1 space-y-2 overflow-y-auto custom-scrollbar pr-2 pb-10">
          <div className="space-y-10">
            {['core', 'registry', 'finance', 'intelligence', 'system', 'admin'].map(cat => {
              const catRoutes = routes.filter(r => r.showInSidebar && r.category === cat);
              if (catRoutes.length === 0) return null;
              return (
                <div key={cat} className="space-y-3">
                   <p className="px-6 text-[8px] font-black uppercase text-zinc-700 tracking-[0.5em] mb-4">{cat.toUpperCase()}_SUITE</p>
                   {catRoutes.map((route) => (
                    <SidebarItem 
                      key={route.path} 
                      icon={route.icon} 
                      label={route.label} 
                      path={route.path} 
                      active={location.pathname === route.path} 
                    />
                  ))}
                </div>
              );
            })}
          </div>
        </nav>

        <div className="mt-auto pt-10 border-t border-zinc-900 space-y-4">
          <button 
            onClick={handleTerminate}
            className="w-full flex items-center gap-4 px-6 py-4 rounded-2xl text-rose-500 hover:bg-rose-500/10 transition-all font-black text-[10px] uppercase tracking-widest border border-transparent hover:border-rose-500/20"
          >
            <ShieldAlert size={16} />
            <span>Terminate Link</span>
          </button>
          <div className="mt-8 p-6 bg-zinc-950 border border-zinc-900 rounded-[2rem] flex items-center justify-between shadow-2xl">
            <div className="flex items-center gap-3">
              <Activity size={16} className="text-emerald-500" />
              <span className="text-[9px] font-black uppercase tracking-widest text-zinc-500">Node Sync: 100%</span>
            </div>
            <div className="w-2 h-2 bg-emerald-500 rounded-full animate-pulse shadow-[0_0_8px_#10b981]"></div>
          </div>
        </div>
      </aside>

      <main className="flex-1 ml-80 min-h-screen flex flex-col relative z-10">
        <header className="h-24 flex items-center justify-between px-10 bg-transparent relative z-50">
          <div className="flex items-center space-x-6">
            <div className="flex flex-col">
              <h1 className="text-xl font-black tracking-tighter text-white italic leading-none uppercase">SYSTEM <span className="text-blue-500 not-italic">CONSOLE</span></h1>
              <p className="text-[10px] text-zinc-600 font-black uppercase tracking-[0.3em] mt-1 flex items-center gap-2">
                <Terminal size={10} /> ROOT: {user.name.toUpperCase()}
              </p>
            </div>
          </div>
          <div className="flex items-center space-x-6">
            <div className="text-right">
              <p className="text-xs font-black text-white uppercase italic tracking-tighter">{user.name}</p>
              <p className="text-[9px] text-zinc-600 uppercase tracking-[0.2em] font-bold">{user.role}</p>
            </div>
            <button onClick={handleTerminate} className="w-12 h-12 rounded-2xl bg-zinc-950 border border-zinc-900 flex items-center justify-center hover:border-rose-500/50 transition-all shadow-2xl">
              <LogOut size={18} className="text-zinc-600" />
            </button>
          </div>
        </header>
        <div className="px-10 pb-20">
          <Routes>
            {routes.map((route) => (
              <Route key={route.path} path={route.path} element={<route.component />} />
            ))}
            <Route path="*" element={<Navigate to="/overview" replace />} />
          </Routes>
        </div>
      </main>
    </div>
  );
};

const App: React.FC = () => {
  const [currentUser, setCurrentUser] = useState<UserSession | null>(null);
  const [isAuthChecked, setIsAuthChecked] = useState<boolean>(false);

  const checkStatus = useCallback(async () => {
    try {
      const { user } = await apiClient.auth.me();
      setCurrentUser(user);
    } catch (e) {
      console.error("Session sync failed.");
    } finally {
      setIsAuthChecked(true);
    }
  }, []);

  useEffect(() => {
    checkStatus();
    window.addEventListener('auth-update', checkStatus);
    return () => window.removeEventListener('auth-update', checkStatus);
  }, [checkStatus]);

  if (!isAuthChecked) {
    return (
      <div className="min-h-screen bg-black flex flex-col items-center justify-center space-y-12">
        <div className="relative">
          <div className="w-24 h-24 border-4 border-zinc-900 border-t-blue-500 rounded-full animate-spin"></div>
          <Cpu className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-white" size={32} />
        </div>
        <p className="text-[11px] font-black text-zinc-700 uppercase tracking-[0.8em] animate-pulse italic">Synchronizing Node Registry...</p>
      </div>
    );
  }

  return (
    <HashRouter>
      <Routes>
        <Route path="/" element={<Landing />} />
        <Route path="/login" element={currentUser ? <Navigate to="/overview" replace /> : <Login />} />
        <Route path="/airdrop" element={<Airdrop />} />
        <Route path="/manifesto" element={<PrivacyPolicy />} />
        <Route path="/documentation" element={<Documentation />} />
        <Route path="/*" element={currentUser ? (
          <PrivateTerminal user={currentUser} onLogout={async () => { await apiClient.auth.logout(); setCurrentUser(null); }} />
        ) : (
          <Navigate to="/" replace />
        )} />
      </Routes>
    </HashRouter>
  );
};

export default App;