From aa145592c5ea46a7b25319de7a54fc674ba0913b Mon Sep 17 00:00:00 2001 From: syntaxbullet Date: Thu, 2 Apr 2026 13:23:39 +0200 Subject: [PATCH] feat(panel): add react-router-dom, update auth hook with roles, add NotEnrolled page Co-Authored-By: Claude Opus 4.6 (1M context) --- bun.lock | 9 +++++++ panel/package.json | 1 + panel/src/lib/useAuth.ts | 47 ++++++++++++++++++--------------- panel/src/pages/NotEnrolled.tsx | 15 +++++++++++ 4 files changed, 50 insertions(+), 22 deletions(-) create mode 100644 panel/src/pages/NotEnrolled.tsx diff --git a/bun.lock b/bun.lock index 50e64ba..e965105 100644 --- a/bun.lock +++ b/bun.lock @@ -30,6 +30,7 @@ "lucide-react": "^0.564.0", "react": "^19.1.0", "react-dom": "^19.1.0", + "react-router-dom": "^7.13.2", "tailwind-merge": "^3.4.0", "tailwindcss-animate": "^1.0.7", }, @@ -341,6 +342,8 @@ "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], @@ -471,6 +474,10 @@ "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="], + "react-router": ["react-router@7.13.2", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-tX1Aee+ArlKQP+NIUd7SE6Li+CiGKwQtbS+FfRxPX6Pe4vHOo6nr9d++u5cwg+Z8K/x8tP+7qLmujDtfrAoUJA=="], + + "react-router-dom": ["react-router-dom@7.13.2", "", { "dependencies": { "react-router": "7.13.2" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-aR7SUORwTqAW0JDeiWF07e9SBE9qGpByR9I8kJT5h/FrBKxPMS6TiC7rmVO+gC0q52Bx7JnjWe8Z1sR9faN4YA=="], + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], "rollup": ["rollup@4.57.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A=="], @@ -479,6 +486,8 @@ "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="], + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], diff --git a/panel/package.json b/panel/package.json index 2434b30..c2859d2 100644 --- a/panel/package.json +++ b/panel/package.json @@ -15,6 +15,7 @@ "lucide-react": "^0.564.0", "react": "^19.1.0", "react-dom": "^19.1.0", + "react-router-dom": "^7.13.2", "tailwind-merge": "^3.4.0", "tailwindcss-animate": "^1.0.7" }, diff --git a/panel/src/lib/useAuth.ts b/panel/src/lib/useAuth.ts index 99f4935..dab1683 100644 --- a/panel/src/lib/useAuth.ts +++ b/panel/src/lib/useAuth.ts @@ -1,35 +1,38 @@ import { useState, useEffect } from "react"; export interface AuthUser { - discordId: string; - username: string; - avatar: string | null; + discordId: string; + username: string; + avatar: string | null; + role: "admin" | "player"; } interface AuthState { - loading: boolean; - user: AuthUser | null; + loading: boolean; + user: AuthUser | null; + enrolled: boolean; } export function useAuth(): AuthState & { logout: () => Promise } { - const [state, setState] = useState({ loading: true, user: null }); + const [state, setState] = useState({ loading: true, user: null, enrolled: true }); - useEffect(() => { - fetch("/auth/me", { credentials: "same-origin" }) - .then((r) => r.json()) - .then((data: { authenticated: boolean; user?: AuthUser }) => { - setState({ - loading: false, - user: data.authenticated ? data.user! : null, - }); - }) - .catch(() => setState({ loading: false, user: null })); - }, []); + useEffect(() => { + fetch("/auth/me", { credentials: "same-origin" }) + .then((r) => r.json()) + .then((data: { authenticated: boolean; enrolled: boolean; user?: AuthUser }) => { + setState({ + loading: false, + user: data.authenticated ? data.user! : null, + enrolled: data.enrolled ?? true, + }); + }) + .catch(() => setState({ loading: false, user: null, enrolled: true })); + }, []); - const logout = async () => { - await fetch("/auth/logout", { method: "POST", credentials: "same-origin" }); - setState({ loading: false, user: null }); - }; + const logout = async () => { + await fetch("/auth/logout", { method: "POST", credentials: "same-origin" }); + setState({ loading: false, user: null, enrolled: true }); + }; - return { ...state, logout }; + return { ...state, logout }; } diff --git a/panel/src/pages/NotEnrolled.tsx b/panel/src/pages/NotEnrolled.tsx new file mode 100644 index 0000000..de9a54a --- /dev/null +++ b/panel/src/pages/NotEnrolled.tsx @@ -0,0 +1,15 @@ +export default function NotEnrolled() { + return ( +
+
+
Aurora
+

+ You need to use the Aurora bot in Discord before you can access this panel. +

+

+ Use /enroll in any server with Aurora to get started. +

+
+
+ ); +}