import React, { useEffect } from 'react'
import { useAuth } from '../lib/authContext'
// ── AuthGate ──────────────────────────────────────────────────────────────────
//
// Single source of truth for the "not authenticated" UI (IV6, IV7).
//
// - authenticated → renders children normally.
// - unauthenticated (cold, hasBeenAuthenticated === false)
// → shows a manual "Sign in with OIDC" card (IV7).
// - unauthenticated (mid-session, hasBeenAuthenticated === true)
// → auto-redirects via useEffect, shows a placeholder (IV7).
// - auth_error → shows the distinct error card with a manual "Try again"
// button (IV6). Never auto-retries.
export function AuthGate({ children }: { children: React.ReactNode }): React.JSX.Element {
const { state, signIn } = useAuth()
const { status, hasBeenAuthenticated, error } = state
// Mid-session expiry: auto-redirect on mount only (IV7).
useEffect(() => {
if (status === 'unauthenticated' && hasBeenAuthenticated) {
signIn(window.location.pathname)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [status, hasBeenAuthenticated]) // intentionally omits signIn (stable callback)
if (status === 'authenticated') {
return <>{children}</>
}
if (status === 'auth_error') {
return (
<div
className="body body-pad"
style={{ display: 'flex', justifyContent: 'center', paddingTop: 60 }}
>
<div className="card" style={{ padding: '24px 32px', textAlign: 'center' }}>
<div className="uppercase-mono" style={{ marginBottom: 8 }}>couldn't sign you in</div>
<div className="muted" style={{ marginBottom: 16 }}>
{error ?? 'An unknown error occurred.'}
</div>
<button
type="button"
style={{
padding: '4px 14px',
fontSize: 11,
fontFamily: 'var(--mono)',
border: '1px solid var(--rule)',
borderRadius: 4,
background: 'transparent',
color: 'var(--ink-2)',
cursor: 'pointer',
}}
onClick={() => signIn(window.location.pathname)}
>
Try again
</button>
</div>
</div>
)
}
// status === 'unauthenticated'
if (hasBeenAuthenticated) {
// Mid-session expiry — auto-redirect is in progress (useEffect above).
return (
<div
className="body body-pad"
style={{ display: 'flex', justifyContent: 'center', paddingTop: 60 }}
>
<div className="card" style={{ padding: '24px 32px', textAlign: 'center' }}>
<div className="uppercase-mono" style={{ marginBottom: 8 }}>session expired</div>
<div className="muted">Redirecting to sign in…</div>
</div>
</div>
)
}
// Cold first render — show manual sign-in button (IV7).
return (
<div
className="body body-pad"
style={{ display: 'flex', justifyContent: 'center', paddingTop: 60 }}
>
<div className="card" style={{ padding: '24px 32px', textAlign: 'center' }}>
<div className="uppercase-mono" style={{ marginBottom: 8 }}>not authenticated</div>
<div className="muted" style={{ marginBottom: 16 }}>
Sign in to continue.
</div>
<button
type="button"
style={{
padding: '4px 14px',
fontSize: 11,
fontFamily: 'var(--mono)',
border: '1px solid var(--rule)',
borderRadius: 4,
background: 'transparent',
color: 'var(--ink-2)',
cursor: 'pointer',
}}
onClick={() => signIn(window.location.pathname)}
>
Sign in with OIDC
</button>
</div>
</div>
)
}