41 lines
1.2 KiB
TypeScript
41 lines
1.2 KiB
TypeScript
"use client";
|
|
|
|
import type { ReactNode } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { adminHasAnyPermission } from "@/lib/admin-permissions";
|
|
import { useAdminProfile } from "@/stores/admin-session";
|
|
|
|
type AdminPermissionGateProps = {
|
|
requiredAny: readonly string[];
|
|
children: ReactNode;
|
|
className?: string;
|
|
};
|
|
|
|
/** 深链进入无权限页面时展示拒绝说明,避免空白或反复 403。 */
|
|
export function AdminPermissionGate({
|
|
requiredAny,
|
|
children,
|
|
className,
|
|
}: AdminPermissionGateProps): React.ReactElement {
|
|
const { t } = useTranslation("common");
|
|
const profile = useAdminProfile();
|
|
const allowed = adminHasAnyPermission(profile?.permissions, [...requiredAny]);
|
|
|
|
if (allowed) {
|
|
return <>{children}</>;
|
|
}
|
|
|
|
return (
|
|
<Card className={className ?? "admin-list-card"}>
|
|
<CardHeader>
|
|
<CardTitle className="text-base">{t("permission.deniedTitle")}</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<p className="text-sm text-muted-foreground">{t("permission.deniedDescription")}</p>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|