feat(panel): add react-router-dom, update auth hook with roles, add NotEnrolled page

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
syntaxbullet
2026-04-02 13:23:39 +02:00
parent 37fa5fc3c8
commit aa145592c5
4 changed files with 50 additions and 22 deletions

View File

@@ -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"
},

View File

@@ -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<void> } {
const [state, setState] = useState<AuthState>({ loading: true, user: null });
const [state, setState] = useState<AuthState>({ 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 };
}

View File

@@ -0,0 +1,15 @@
export default function NotEnrolled() {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="text-center max-w-sm">
<div className="font-display font-bold text-3xl tracking-tight mb-1">Aurora</div>
<p className="text-sm text-text-tertiary mb-6">
You need to use the Aurora bot in Discord before you can access this panel.
</p>
<p className="text-xs text-text-disabled">
Use <span className="font-mono bg-surface px-1.5 py-0.5 rounded">/enroll</span> in any server with Aurora to get started.
</p>
</div>
</div>
);
}