Files
2026-10-15 19:40:28 +05:30

57 lines
1.6 KiB
TypeScript

"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&apos;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;
}