Princeaka's picture
Upload 44 files
0ff9b81 verified
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>
);
}