"use client";
import React from "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",
});
/**
* BranchGuard
*
* UX improvement:
* - We do NOT block rendering while admin/dev branch list is loading.
* - Existence validation is applied once the list is READY.
* - While LOADING/ERROR we fail open to avoid "solo spinner" screens.
*
* Security note:
* - Backend RBAC remains authoritative.
* - Branch users are enforced immediately (no existence check needed).
*/
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;
};
}, [needsExistenceCheck, user?.userId]);
if (!isAuthenticated) return children;
// Only apply existence validation when the list is READY.
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;
}