Files
Magent/frontend/app/ui/FeatureGate.tsx
T
Assclaw f852e7c941
Magent CI/CD / verify (push) Failing after 9m34s
Magent CI/CD / deploy-beta (push) Skipped
chore: standardize security and quality foundations
2026-09-17 20:03:47 +12:00

56 lines
1.9 KiB
TypeScript

"use client";
import { usePathname } from "next/navigation";
import { useEffect, useState, type ReactNode } from "react";
import { authFetch, getApiBase, getToken } from "../lib/auth";
import { canAccess, featureForPath, type FeatureAccess } from "../lib/features";
export function useFeatureUser() {
const pathname = usePathname();
const [state, setState] = useState<{
path: string;
user: { role?: string; features?: FeatureAccess; invite_management_enabled?: boolean } | null;
}>({ path: "", user: null });
useEffect(() => {
let active = true;
const load = async () => {
if (!getToken()) {
if (active) setState({ path: pathname, user: null });
return;
}
try {
const response = await authFetch(`${getApiBase()}/auth/me`);
const user = response.ok ? await response.json() : null;
if (active) setState({ path: pathname, user });
} catch {
if (active) setState({ path: pathname, user: null });
}
};
void load();
window.addEventListener("focus", load);
return () => {
active = false;
window.removeEventListener("focus", load);
};
}, [pathname]);
return { user: state.user, ready: state.path === pathname };
}
export default function FeatureGate({ children }: { children: ReactNode }) {
const pathname = usePathname();
const { user, ready } = useFeatureUser();
const feature = featureForPath(pathname);
if (!feature) return children;
if (!ready) return <main className="card">Loading account access...</main>;
if (!getToken()) return children;
if (!canAccess(user, feature))
return (
<main className="card">
<h1>Feature unavailable</h1>
<p>Your account does not have access to this feature. Ask an administrator if you need it enabled.</p>
<a href="/profile">Go to my profile</a>
</main>
);
return children;
}