feat: quiz
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* The signed-in staff member's role and permissions, for the whole panel.
|
||||
*
|
||||
* Used to HIDE what someone can't do — nav entries, buttons, whole pages.
|
||||
* Hiding is a courtesy, not the boundary: every /admin/* route on the BFF
|
||||
* checks its own permission, so a hidden button that somehow fired would
|
||||
* still be refused.
|
||||
*/
|
||||
|
||||
import { createContext, useContext } from "react";
|
||||
import type { StaffMe } from "@/lib/api";
|
||||
|
||||
const StaffContext = createContext<StaffMe | null>(null);
|
||||
|
||||
export const StaffProvider = StaffContext.Provider;
|
||||
|
||||
export function useStaff() {
|
||||
const me = useContext(StaffContext);
|
||||
const perms = new Set(me?.permissions ?? []);
|
||||
return {
|
||||
me,
|
||||
can: (perm: string) => perms.has(perm),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders children only for staff holding `perm`; otherwise a short notice.
|
||||
* Wraps whole pages, so landing on one by URL explains itself rather than
|
||||
* showing a screen of 403 errors.
|
||||
*/
|
||||
export function RequirePermission({
|
||||
perm,
|
||||
children,
|
||||
}: {
|
||||
perm: string;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const { can } = useStaff();
|
||||
if (!can(perm)) {
|
||||
return (
|
||||
<div className="rounded-xl border border-border p-6 text-sm text-muted-foreground">
|
||||
Your role doesn't include access to this section. A superadmin
|
||||
can change that from the Staff page.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
/** Renders children only when the signed-in role holds `perm`. */
|
||||
export function Can({ perm, children }: { perm: string; children: React.ReactNode }) {
|
||||
const { can } = useStaff();
|
||||
return can(perm) ? <>{children}</> : null;
|
||||
}
|
||||
Reference in New Issue
Block a user