Files
openmaic/OpenMAIC/components/access-code-guard.tsx

66 lines
2.1 KiB
TypeScript

'use client';
import { useEffect, useState, ReactNode } from 'react';
import { AccessCodeModal } from '@/components/access-code-modal';
import { useSettingsStore } from '@/lib/store/settings';
export function AccessCodeGuard({ children }: { children: ReactNode }) {
const isOpsDeployment = process.env.NEXT_PUBLIC_OPENMAIC_DEPLOYMENT_ROLE === 'ops';
const [status, setStatus] = useState<{
enabled: boolean;
authenticated: boolean;
loading: boolean;
}>({ enabled: false, authenticated: false, loading: true });
useEffect(() => {
if (isOpsDeployment || new URLSearchParams(window.location.search).get('embedded') === '1') {
setStatus({ enabled: false, authenticated: true, loading: false });
return;
}
let cancelled = false;
fetch('/api/access-code/status')
.then((res) => res.json())
.then((data) => {
if (!cancelled) {
setStatus({
enabled: data.enabled,
authenticated: data.authenticated,
loading: false,
});
}
})
.catch(() => {
if (!cancelled) {
// Default to requiring auth on error — safer than silently disabling
setStatus({ enabled: true, authenticated: false, loading: false });
}
});
return () => {
cancelled = true;
};
}, [isOpsDeployment]);
const needsAuth = !status.loading && status.enabled && !status.authenticated;
return (
<>
{needsAuth && (
<AccessCodeModal
open={true}
onSuccess={() => {
setStatus((s) => ({ ...s, authenticated: true }));
// ServerProvidersInit runs on mount, which on an ACCESS_CODE-gated
// deployment is before any access cookie exists: the middleware
// answers 401 and the store silently keeps its blank defaults.
// Nothing re-fetches afterwards, so every server-configured
// provider reads as unconfigured until a manual reload. Re-fetch
// now that the request will be authorized.
void useSettingsStore.getState().fetchServerProviders();
}}
/>
)}
{children}
</>
);
}