feat:UX and fix drinkkaart payment logic

This commit is contained in:
2026-03-04 14:22:42 +01:00
parent 79869a9a21
commit f9d79c3879
26 changed files with 1432 additions and 283 deletions

View File

@@ -1,10 +1,5 @@
import { useMutation, useQuery } from "@tanstack/react-query";
import {
createFileRoute,
Link,
redirect,
useNavigate,
} from "@tanstack/react-router";
import { createFileRoute, Link, useNavigate } from "@tanstack/react-router";
import {
Check,
ChevronDown,
@@ -34,16 +29,6 @@ import { orpc } from "@/utils/orpc";
export const Route = createFileRoute("/admin/")({
component: AdminPage,
beforeLoad: async () => {
const session = await authClient.getSession();
if (!session.data?.user) {
throw redirect({ to: "/login" });
}
const user = session.data.user as { role?: string };
if (user.role !== "admin") {
throw redirect({ to: "/login" });
}
},
});
function AdminPage() {
@@ -60,6 +45,12 @@ function AdminPage() {
const [copiedId, setCopiedId] = useState<string | null>(null);
// Get current session to check user role
const sessionQuery = useQuery({
queryKey: ["session"],
queryFn: () => authClient.getSession(),
});
const handleCopyManageUrl = (token: string, id: string) => {
const url = `${window.location.origin}/manage/${token}`;
navigator.clipboard.writeText(url).then(() => {
@@ -146,6 +137,16 @@ function AdminPage() {
},
});
const requestAdminMutation = useMutation({
...orpc.requestAdminAccess.mutationOptions(),
onSuccess: () => {
toast.success("Admin toegang aangevraagd!");
},
onError: (error) => {
toast.error(`Aanvraag mislukt: ${error.message}`);
},
});
const handleSignOut = async () => {
await authClient.signOut();
navigate({ to: "/" });
@@ -163,6 +164,10 @@ function AdminPage() {
rejectRequestMutation.mutate({ requestId });
};
const handleRequestAdmin = () => {
requestAdminMutation.mutate(undefined);
};
const stats = statsQuery.data;
const registrations = registrationsQuery.data?.data ?? [];
const pagination = registrationsQuery.data?.pagination;
@@ -273,8 +278,119 @@ function AdminPage() {
return `${euros.toFixed(euros % 1 === 0 ? 0 : 2)}`;
};
// Check if user is admin
const user = sessionQuery.data?.data?.user as
| { role?: string; name?: string }
| undefined;
const isAdmin = user?.role === "admin";
const isAuthenticated = !!sessionQuery.data?.data?.user;
// Show loading state while checking session
if (sessionQuery.isLoading) {
return (
<div className="flex min-h-[calc(100dvh-2.75rem)] items-center justify-center px-4 py-8 sm:min-h-[calc(100dvh-3.5rem)]">
<p className="text-white/60">Laden...</p>
</div>
);
}
// Show login prompt for non-authenticated users
if (!isAuthenticated) {
return (
<div className="flex min-h-[calc(100dvh-2.75rem)] items-center justify-center overflow-y-auto px-4 py-8 sm:min-h-[calc(100dvh-3.5rem)]">
<Card className="my-auto w-full max-w-md border-white/10 bg-white/5">
<CardHeader className="text-center">
<CardTitle className="font-['Intro',sans-serif] text-3xl text-white">
Inloggen Vereist
</CardTitle>
<CardDescription className="text-white/60">
Je moet ingelogd zijn om admin toegang aan te vragen
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
<Button
onClick={() => navigate({ to: "/login" })}
className="w-full bg-white text-[#214e51] hover:bg-white/90"
>
Inloggen
</Button>
<Link
to="/"
className="block text-center text-sm text-white/40 hover:text-white"
>
Terug naar website
</Link>
</div>
</CardContent>
</Card>
</div>
);
}
// Show request admin UI for non-admin users
if (!isAdmin) {
return (
<div className="flex min-h-[calc(100dvh-2.75rem)] items-center justify-center overflow-y-auto px-4 py-8 sm:min-h-[calc(100dvh-3.5rem)]">
<Card className="my-auto w-full max-w-md border-white/10 bg-white/5">
<CardHeader className="text-center">
<CardTitle className="font-['Intro',sans-serif] text-3xl text-white">
Admin Toegang Vereist
</CardTitle>
<CardDescription className="text-white/60">
Je hebt geen admin rechten voor dit dashboard
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="rounded-lg border border-white/10 bg-white/5 p-4">
<p className="mb-3 text-center text-sm text-white/60">
Admin-toegang aanvragen?
</p>
<Button
onClick={handleRequestAdmin}
disabled={requestAdminMutation.isPending}
className="w-full bg-white text-[#214e51] hover:bg-white/90"
>
{requestAdminMutation.isPending
? "Bezig..."
: "Vraag Admin Toegang Aan"}
</Button>
</div>
<Button
onClick={() => navigate({ to: "/account" })}
variant="outline"
className="w-full border-white/20 bg-transparent text-white hover:bg-white/10"
>
Ga naar mijn account
</Button>
<Button
onClick={handleSignOut}
variant="outline"
className="w-full border-white/20 bg-transparent text-white/60 hover:bg-white/10 hover:text-white"
>
<LogOut className="mr-2 h-4 w-4" />
Uitloggen
</Button>
<Link
to="/"
className="block text-center text-sm text-white/40 hover:text-white"
>
Terug naar website
</Link>
</div>
</CardContent>
</Card>
</div>
);
}
return (
<div className="min-h-screen bg-[#214e51]">
<div>
{/* Header */}
<header className="border-white/10 border-b bg-[#214e51]/95 px-8 py-6">
<div className="mx-auto flex max-w-7xl items-center justify-between">