File size: 5,127 Bytes
0ff9b81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import React, { useEffect } from "react";
import { Routes, Route, Navigate, useLocation } from "react-router-dom";
import { useStore } from "./state/store";
import { Sidebar } from "./components/Sidebar";
import { Topbar } from "./components/Topbar";
import { Orbit } from "./components/Orbit";

// Pages
import Login from "./pages/user/Login";
import Signup from "./pages/user/Signup";
import Main from "./pages/user/Main";
import Chat from "./pages/user/Chat";
import History from "./pages/user/History";
import ApiKeys from "./pages/user/ApiKeys";
import HowTo from "./pages/user/HowTo";
import About from "./pages/user/About";
import Settings from "./pages/user/Settings";

// Admin pages
import Monitor from "./pages/admin/Monitor";
import Knowledge from "./pages/admin/Knowledge";
import Skills from "./pages/admin/Skills";
import VFS from "./pages/admin/VFS";
import Verify from "./pages/admin/Verify";
import Logs from "./pages/admin/Logs";
import Users from "./pages/admin/Users";
import Connections from "./pages/admin/Connections";

// Landing
import Landing from "./pages/Landing";

// Backend API
const API_BASE = "https://princeaka-multimodal-module.hf.space";

export async function apiFetch(endpoint, method = "GET", body = null, token = null) {
  const headers = { "Content-Type": "application/json" };
  if (token) headers["Authorization"] = `Bearer ${token}`;

  const res = await fetch(`${API_BASE}${endpoint}`, {
    method,
    headers,
    body: body ? JSON.stringify(body) : undefined,
  });

  if (!res.ok) {
    const errText = await res.text();
    throw new Error(`API ${res.status}: ${errText}`);
  }

  return res.json();
}

// βœ… Protected route wrapper
function Protected({ children, role }) {
  const { auth } = useStore();
  if (!auth.token) return <Navigate to="/login" replace />;
  if (role && auth.role !== role) return <Navigate to="/" replace />;
  return children;
}

export default function App() {
  const { ui, setUi } = useStore();
  const loc = useLocation();
  const isAuthPage = loc.pathname === "/login" || loc.pathname === "/signup";

  // βœ… Auto-clear toast after 4s
  useEffect(() => {
    if (ui.toast) {
      const timer = setTimeout(() => setUi(u => ({ ...u, toast: null })), 4000);
      return () => clearTimeout(timer);
    }
  }, [ui.toast, setUi]);

  return (
    <div style={{ height: "100%" }}>
      <Routes>
        {/* Landing page */}
        <Route path="/landing" element={<Landing />} />

        {/* Auth pages */}
        <Route path="/login" element={<Login />} />
        <Route path="/signup" element={<Signup />} />

        {/* Protected app pages */}
        <Route
          path="/*"
          element={
            !isAuthPage ? (
              <div className="app">
                <Sidebar />

                <div className="main">
                  <header className="topbar">
                    <Topbar />
                  </header>

                  <div className="content">
                    <Routes>
                      <Route path="/" element={<Protected><Main /></Protected>} />
                      <Route path="/chat" element={<Protected><Chat /></Protected>} />
                      <Route path="/history" element={<Protected><History /></Protected>} />
                      <Route path="/apikeys" element={<Protected><ApiKeys /></Protected>} />
                      <Route path="/howto" element={<Protected><HowTo /></Protected>} />
                      <Route path="/about" element={<Protected><About /></Protected>} />
                      <Route path="/settings" element={<Protected><Settings /></Protected>} />

                      {/* Admin routes */}
                      <Route path="/admin/monitor" element={<Protected role="admin"><Monitor /></Protected>} />
                      <Route path="/admin/knowledge" element={<Protected role="admin"><Knowledge /></Protected>} />
                      <Route path="/admin/skills" element={<Protected role="admin"><Skills /></Protected>} />
                      <Route path="/admin/vfs" element={<Protected role="admin"><VFS /></Protected>} />
                      <Route path="/admin/verify" element={<Protected role="admin"><Verify /></Protected>} />
                      <Route path="/admin/logs" element={<Protected role="admin"><Logs /></Protected>} />
                      <Route path="/admin/users" element={<Protected role="admin"><Users /></Protected>} />
                      <Route path="/admin/connections" element={<Protected role="admin"><Connections /></Protected>} />
                    </Routes>
                  </div>
                </div>

                <Orbit />
              </div>
            ) : (
              <Navigate to="/landing" replace />
            )
          }
        />

        {/* Default redirect */}
        <Route path="*" element={<Navigate to="/landing" replace />} />
      </Routes>

      {/* βœ… Toast */}
      {ui.toast && (
        <div className="toast fixed bottom-4 right-4 bg-black text-white px-4 py-2 rounded shadow-lg z-50">
          {ui.toast}
        </div>
      )}
    </div>
  );
}