// =====================================================================
// Viewer context — drives the "View as..." access-control demo.
// The App provides a viewer (one of VIEWERS) and every screen uses
// useViewer() to filter what they show.
// =====================================================================
const ViewerContext = React.createContext(null);
function ViewerProvider({ viewer, children }) {
return {children} ;
}
function useViewer() {
return React.useContext(ViewerContext) || VIEWERS[0]; // default to admin
}
// Filter a candidate list down to what the current viewer can see.
function useVisibleCandidates(list = CANDIDATES) {
const viewer = useViewer();
return React.useMemo(() => visibleCandidates(viewer, list), [viewer, list]);
}
// =====================================================================
// "Viewing as..." top banner — slim strip above the topnav, color-coded
// to the viewer's role. Only shows when role !== 'admin' so the default
// experience has no chrome cost.
// =====================================================================
function RoleBanner() {
const viewer = useViewer();
if (!viewer || viewer.role === "admin") return null;
const role = ROLES[viewer.role];
if (!role) return null;
const visibleCount = visibleCandidates(viewer).length;
const authUser = window.__atsAuthUser;
const isSimulated = authUser && authUser.role === "admin" && viewer.role !== "admin";
const exitSimulation = () => {
if (typeof window.__atsSetViewer === "function" && authUser) {
const nameParts = (authUser.full_name || "").split(" ");
const initials = nameParts.map(p => p[0] || "").join("").slice(0, 2).toUpperCase();
window.__atsSetViewer({
id: authUser.id, name: authUser.full_name, initials,
color: "#7595D5", role: "admin", title: authUser.email,
avatar_url: authUser.avatar_url,
});
}
};
return (
{isSimulated ? "Viewing as" : ""} {role.label}
·
{viewer.name}
Showing {visibleCount} candidates · {role.desc}
{isSimulated && (
e.currentTarget.style.background = 'rgba(255,255,255,0.35)'}
onMouseLeave={(e) => e.currentTarget.style.background = 'rgba(255,255,255,0.2)'}
>
Exit
)}
);
}
// =====================================================================
// "Hidden by access" placeholder — replaces a row/card when a feature
// would have been visible to admins but the current viewer is locked
// out. (Used in the Permissions screen demos.)
// =====================================================================
function AccessLock({ reason }) {
return (
Hidden
);
}
Object.assign(window, {
ViewerContext, ViewerProvider, useViewer, useVisibleCandidates,
RoleBanner, AccessLock,
});