"use client"; import React from "react"; import { Loader2 } from "lucide-react"; import { useAuth } from "@/components/auth/authContext"; import { getBranches } from "@/lib/frontend/apiClient"; import { decideBranchUi, BRANCH_UI_DECISION, } from "@/lib/frontend/rbac/branchUiDecision"; import ForbiddenView from "@/components/system/ForbiddenView"; import NotFoundView from "@/components/system/NotFoundView"; const BRANCH_LIST_STATE = Object.freeze({ IDLE: "idle", LOADING: "loading", READY: "ready", ERROR: "error", }); function BranchValidationLoading() { return (
Validating branch...
); } export default function BranchGuard({ branch, children }) { const { status, user } = useAuth(); const isAuthenticated = status === "authenticated" && user; const needsExistenceCheck = isAuthenticated && (user.role === "admin" || user.role === "dev"); const [branchList, setBranchList] = React.useState({ status: BRANCH_LIST_STATE.IDLE, branches: null, }); React.useEffect(() => { if (!needsExistenceCheck) return; let cancelled = false; setBranchList({ status: BRANCH_LIST_STATE.LOADING, branches: null }); (async () => { try { const res = await getBranches(); if (cancelled) return; const branches = Array.isArray(res?.branches) ? res.branches : []; setBranchList({ status: BRANCH_LIST_STATE.READY, branches }); } catch (err) { if (cancelled) return; // Fail open: do not block navigation if validation fails. console.error("[BranchGuard] getBranches failed:", err); setBranchList({ status: BRANCH_LIST_STATE.ERROR, branches: null }); } })(); return () => { cancelled = true; }; // IMPORTANT: // - depend only on user identity + needsExistenceCheck // - do NOT depend on branchList.status (would cancel itself when setting LOADING) }, [needsExistenceCheck, user?.userId]); if (!isAuthenticated) { return children; } if (needsExistenceCheck && branchList.status === BRANCH_LIST_STATE.LOADING) { return ; } const allowedBranches = branchList.status === BRANCH_LIST_STATE.READY ? branchList.branches : null; const decision = decideBranchUi({ user, branch, allowedBranches, }); if (decision === BRANCH_UI_DECISION.FORBIDDEN) { return ; } if (decision === BRANCH_UI_DECISION.NOT_FOUND) { return ; } return children; }