satupeta-main/shared/components/auth/admin-route-guard.tsx
2026-02-23 12:21:05 +07:00

72 lines
1.9 KiB
TypeScript
Executable File

"use client";
import { useRouter, usePathname } from "next/navigation";
import { Loader2 } from "lucide-react";
import { useEffect } from "react";
import { useAuthSession } from "@/shared/hooks/use-session";
import { adminRoutePermissions } from "@/shared/config/route-permission-map";
import { hasPermission } from "@/shared/config/role";
import { roles } from "@/shared/config/role";
export default function AdminRouteGuard({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const router = useRouter();
const pathname = usePathname();
const isAdminRoute = pathname.startsWith("/admin");
const { session, status } = useAuthSession(true);
const role = session?.user?.role;
const redirectPath = role
? roles[role.name]?.redirectTo
: "/auth/admin/login";
const matched = Object.entries(adminRoutePermissions).find(([route]) =>
pathname.startsWith(route)
);
const menu = matched?.[1]?.menu;
const permission = matched?.[1]?.permission;
const isAllowed =
pathname === "/admin" ||
(role && menu && permission
? hasPermission(role, menu, permission)
: false);
useEffect(() => {
if (isAdminRoute && status === "unauthenticated") {
router.push(
`/auth/admin/login?callbackUrl=${encodeURIComponent(pathname)}`
);
}
}, [isAdminRoute, pathname, router, status]);
useEffect(() => {
if (
status === "authenticated" &&
!isAllowed &&
isAdminRoute &&
pathname !== redirectPath
) {
router.push(redirectPath);
}
}, [status, isAllowed, isAdminRoute, router, redirectPath, pathname]);
if (
isAdminRoute &&
(status === "loading" || (status === "unauthenticated" && !isAllowed))
) {
return (
<div className="flex items-center justify-center h-screen">
<Loader2 className="w-6 h-6 animate-spin" />
</div>
);
}
return <>{children}</>;
}