import { useEffect, useState, type ReactNode } from 'react'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { apiFetch, setToken, UNAUTHORIZED_EVENT } from '@/lib/api'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { useI18n } from '@/i18n'
interface AuthStatus {
needsSetup: boolean
authenticated: boolean
email: string | null
}
function Centered({ children }: { children: ReactNode }) {
return (
)
}
function AuthForm({ mode, onAuthed }: { mode: 'setup' | 'login'; onAuthed: () => void }) {
const { t } = useI18n()
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
const [busy, setBusy] = useState(false)
const isSetup = mode === 'setup'
async function submit(e: React.FormEvent) {
e.preventDefault()
setBusy(true)
setError('')
try {
const res = await apiFetch<{ token: string }>(isSetup ? '/api/auth/setup' : '/api/auth/login', {
method: 'POST',
body: JSON.stringify({ email, password }),
})
setToken(res.token)
onAuthed()
} catch (err) {
setError((err as Error).message)
} finally {
setBusy(false)
}
}
return (
FreeLLMAPI
{isSetup ? t('auth.createYourAccount') : t('auth.signIn')}
{isSetup
? t('auth.setupDescription')
: t('auth.loginDescription')}
)
}
export function AuthGate({ children }: { children: ReactNode }) {
const { t } = useI18n()
const queryClient = useQueryClient()
const { data, isLoading, isError, refetch } = useQuery({
queryKey: ['auth-status'],
queryFn: () => apiFetch('/api/auth/status'),
retry: false,
})
useEffect(() => {
const handler = () => { refetch() }
window.addEventListener(UNAUTHORIZED_EVENT, handler)
return () => window.removeEventListener(UNAUTHORIZED_EVENT, handler)
}, [refetch])
function onAuthed() {
// New session: drop any cached (unauthenticated) data and re-check status.
queryClient.invalidateQueries()
refetch()
}
if (isLoading) return {t('auth.loading')}
if (isError || !data) {
return (
{t('auth.serverUnreachableBefore')}npm run dev{t('auth.serverUnreachableAfter')}
)
}
if (data.needsSetup) return
if (!data.authenticated) return
return <>{children}>
}