Skip to content

Commit

Permalink
Basic admin UI
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanlaj committed Mar 7, 2024
1 parent 7b77ecf commit 35ede7d
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 8 deletions.
40 changes: 32 additions & 8 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Layout } from "antd";
import { Routes, Route } from "react-router-dom";
import { Routes, Route, Navigate, Outlet } from "react-router-dom";
import Navbar from "./components/Navbar";
import ChallengesView from "./pages/ChallengesView";
import Home from "./pages/Home";
Expand All @@ -11,6 +11,8 @@ import useInterceptor from "./hooks/useInterceptor";
import Loading from "./components/Loading";
import Leaderboard from "./pages/Leaderboard";
import Badges from "./pages/Badges";
import AdminLayout from "./pages/admin/Admin";
import UserRouteLayout from "./components/UserRouteLayout";

const { Content } = Layout;

Expand All @@ -30,14 +32,36 @@ const App = () => {
return (
<Layout className="flex flex-col min-h-screen">
<Navbar />
<Content className="p-50px">
<Content>
<Routes>
<Route path={"/"} element={<Home />} />
<Route path={"/challenges"} element={<ChallengesView />} />
<Route path={"/login"} element={<Login />} />
<Route path={"/register"} element={<Register />} />
<Route path={"/leaderboard"} element={<Leaderboard />} />
<Route path={"/badges"} element={<Badges />} />
<Route element={<UserRouteLayout />}>
<Route path={"/"} element={<Home />} />
<Route path={"/challenges"} element={<ChallengesView />} />
<Route path={"/login"} element={<Login />} />
<Route path={"/register"} element={<Register />} />
<Route path={"/leaderboard"} element={<Leaderboard />} />
<Route path={"/badges"} element={<Badges />} />
</Route>
<Route path="/admin" element={<AdminLayout />}>
<Route index element={<Navigate replace to="users" />} />
<Route path="users" element={<div>Users</div>} />
<Route path="challenges" element={<div>Challenges</div>} />
<Route
path="submissions/*"
element={
<>
<div>Submissions</div>
<Outlet />
</>
}
>
<Route path="all" element={<div>All Submissions</div>} />
<Route path="manual" element={<div>Manual Review</div>} />
<Route path="correct" element={<div>Correct Submissions</div>} />
<Route path="incorrect" element={<div>Incorrect Submissions</div>} />
</Route>
<Route path="settings" element={<div>Settings</div>} />
</Route>
</Routes>
</Content>
</Layout>
Expand Down
1 change: 1 addition & 0 deletions client/src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const Navbar = () => {
"/challenges": "Challenges",
"/leaderboard": "Leaderboard",
"/badges": "Badges",
"/admin": "Admin",
};

const isLoggedIn = user != null;
Expand Down
11 changes: 11 additions & 0 deletions client/src/components/UserRouteLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Outlet } from "react-router-dom";

const UserRouteLayout = () => {
return (
<div className="p-50px">
<Outlet />
</div>
);
};

export default UserRouteLayout;
41 changes: 41 additions & 0 deletions client/src/pages/admin/Admin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Header } from "antd/es/layout/layout";
import { Link, Outlet, useLocation } from "react-router-dom";

const AdminLayout = () => {
const location = useLocation();
const selectedKey = location.pathname;

const adminNavLinks = {
"/admin/users": "Users",
"/admin/challenges": "Challenges",
"/admin/submissions/all": "Submissions",
"/admin/settings": "Settings",
};

return (
<div>
<Header className="bg-gray-800 text-white flex justify-between px-5">
<div className="flex">
{Object.entries(adminNavLinks).map(([link, text]) => (
<Link
key={link}
to={link}
className={`text-gray-400 select-none px-4 inline-block ${
selectedKey.startsWith(link)
? "bg-blue-600 text-white pointer-events-none"
: "hover:text-gray-200"
}`}
>
{text}
</Link>
))}
</div>
</Header>
<div className="p-50px">
<Outlet />
</div>
</div>
);
};

export default AdminLayout;
8 changes: 8 additions & 0 deletions server/src/middleware/verifyIsAdmin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Response, NextFunction, Request } from "express";

export function verifyIsAdmin(req: Request, res: Response, next: NextFunction) {
if (!req.payload)
throw new Error("This middleware should be used after verifyAccess middleware");

return req.payload.isAdmin ? next() : res.status(403).send("Forbidden");
}

0 comments on commit 35ede7d

Please sign in to comment.