4e9ed97b05
- New backend: Group + GroupMembership models, schemas, CRUD router at /api/admin/groups (list, create, get detail, update, delete, add/remove members) - New Alembic migration: groups and group_memberships tables - Frontend: Admin sidebar item is now an expandable accordion with Users and Groups sub-items; AdminPage redirects to /admin/users; new AdminUsersPage and AdminGroupsPage with inline member management panel - API client: 7 new group functions + TypeScript types Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
64 lines
2.5 KiB
TypeScript
64 lines
2.5 KiB
TypeScript
import { Routes, Route, Navigate } from "react-router-dom";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { useAuth } from "./hooks/useAuth";
|
|
import { getMe } from "./api/client";
|
|
import AppShell from "./components/AppShell";
|
|
import LoginPage from "./pages/LoginPage";
|
|
import DashboardPage from "./pages/DashboardPage";
|
|
import ProfilePage from "./pages/ProfilePage";
|
|
import AppsPage from "./pages/AppsPage";
|
|
import AdminPage from "./pages/AdminPage";
|
|
import AdminUsersPage from "./pages/AdminUsersPage";
|
|
import AdminGroupsPage from "./pages/AdminGroupsPage";
|
|
import DocumentsPage from "./pages/DocumentsPage";
|
|
import DocumentAdminSettingsPage from "./pages/DocumentAdminSettingsPage";
|
|
import AIAdminSettingsPage from "./pages/AIAdminSettingsPage";
|
|
|
|
function PrivateRoute({ children }: { children: React.ReactNode }) {
|
|
const { token } = useAuth();
|
|
return token ? (
|
|
<AppShell>{children}</AppShell>
|
|
) : (
|
|
<Navigate to="/login" replace />
|
|
);
|
|
}
|
|
|
|
function AdminRoute({ children }: { children: React.ReactNode }) {
|
|
const { token } = useAuth();
|
|
const { data: user, isLoading } = useQuery({ queryKey: ["me"], queryFn: getMe });
|
|
|
|
if (!token) return <Navigate to="/login" replace />;
|
|
// Wait for the me query before deciding — prevents a flash redirect
|
|
if (isLoading) return null;
|
|
// Redirect to /login (not /) so the route appears not to exist
|
|
if (!user?.is_admin) return <Navigate to="/login" replace />;
|
|
return <AppShell>{children}</AppShell>;
|
|
}
|
|
|
|
export default function App() {
|
|
return (
|
|
<Routes>
|
|
<Route path="/login" element={<LoginPage />} />
|
|
|
|
<Route path="/" element={<PrivateRoute><DashboardPage /></PrivateRoute>} />
|
|
<Route path="/apps" element={<PrivateRoute><AppsPage /></PrivateRoute>} />
|
|
<Route path="/apps/documents" element={<PrivateRoute><DocumentsPage /></PrivateRoute>} />
|
|
<Route
|
|
path="/apps/documents/settings/admin"
|
|
element={<AdminRoute><DocumentAdminSettingsPage /></AdminRoute>}
|
|
/>
|
|
<Route
|
|
path="/apps/ai/settings/admin"
|
|
element={<AdminRoute><AIAdminSettingsPage /></AdminRoute>}
|
|
/>
|
|
<Route path="/profile" element={<PrivateRoute><ProfilePage /></PrivateRoute>} />
|
|
<Route path="/admin" element={<AdminRoute><AdminPage /></AdminRoute>} />
|
|
<Route path="/admin/users" element={<AdminRoute><AdminUsersPage /></AdminRoute>} />
|
|
<Route path="/admin/groups" element={<AdminRoute><AdminGroupsPage /></AdminRoute>} />
|
|
|
|
{/* Catch-all */}
|
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
</Routes>
|
|
);
|
|
}
|