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:
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
15
panel/src/pages/NotEnrolled.tsx
Normal file
15
panel/src/pages/NotEnrolled.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user