Files
NexaPG/frontend/src/App.jsx
2026-02-12 11:32:10 +01:00

99 lines
3.6 KiB
JavaScript

import React from "react";
import { NavLink, Navigate, Route, Routes, useLocation } from "react-router-dom";
import { useAuth } from "./state";
import { LoginPage } from "./pages/LoginPage";
import { DashboardPage } from "./pages/DashboardPage";
import { TargetsPage } from "./pages/TargetsPage";
import { TargetDetailPage } from "./pages/TargetDetailPage";
import { QueryInsightsPage } from "./pages/QueryInsightsPage";
import { AdminUsersPage } from "./pages/AdminUsersPage";
function Protected({ children }) {
const { tokens } = useAuth();
const location = useLocation();
if (!tokens?.accessToken) return <Navigate to="/login" state={{ from: location.pathname }} replace />;
return children;
}
function Layout({ children }) {
const { me, logout } = useAuth();
const navClass = ({ isActive }) => `nav-btn${isActive ? " active" : ""}`;
return (
<div className="shell">
<aside className="sidebar">
<div className="brand">
<img src="/nexapg-logo.svg" alt="NexaPG" className="brand-logo" />
<h1>NexaPG</h1>
</div>
<nav className="sidebar-nav">
<NavLink to="/" end className={navClass}>
<span className="nav-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<path d="M4 6c0-1.7 3.6-3 8-3s8 1.3 8 3-3.6 3-8 3-8-1.3-8-3zm0 6c0 1.7 3.6 3 8 3s8-1.3 8-3M4 18c0 1.7 3.6 3 8 3s8-1.3 8-3" />
</svg>
</span>
<span className="nav-label">Dashboard</span>
</NavLink>
<NavLink to="/targets" className={navClass}>
<span className="nav-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<path d="M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3zM12 12l8-4.5M12 12L4 7.5M12 12v9" />
</svg>
</span>
<span className="nav-label">Targets</span>
</NavLink>
<NavLink to="/query-insights" className={navClass}>
<span className="nav-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<path d="M4 19h16M7 15l3-3 3 2 4-5M18 8h.01" />
</svg>
</span>
<span className="nav-label">Query Insights</span>
</NavLink>
{me?.role === "admin" && (
<NavLink to="/admin/users" className={navClass}>
<span className="nav-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<path d="M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8zm-7 8a7 7 0 0 1 14 0" />
</svg>
</span>
<span className="nav-label">Admin</span>
</NavLink>
)}
</nav>
<div className="profile">
<div>{me?.email}</div>
<div className="role">{me?.role}</div>
<button className="logout-btn" onClick={logout}>Logout</button>
</div>
</aside>
<main className="main">{children}</main>
</div>
);
}
export function App() {
return (
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route
path="*"
element={
<Protected>
<Layout>
<Routes>
<Route path="/" element={<DashboardPage />} />
<Route path="/targets" element={<TargetsPage />} />
<Route path="/targets/:id" element={<TargetDetailPage />} />
<Route path="/query-insights" element={<QueryInsightsPage />} />
<Route path="/admin/users" element={<AdminUsersPage />} />
</Routes>
</Layout>
</Protected>
}
/>
</Routes>
);
}