import { useState, useEffect } from 'react'; import { Card, CardContent } from './ui/card'; import { Button } from './ui/button'; import { Input } from './ui/input'; import { Label } from './ui/label'; import { Alert, AlertDescription } from './ui/alert'; import { ShieldCheck, Loader2, AlertCircle, LogIn } from 'lucide-react'; import { apiClient } from '../services/api/client'; interface AuthGateProps { children: React.ReactNode; } export function AuthGate({ children }: AuthGateProps) { const [state, setState] = useState<'checking' | 'authenticated' | 'login'>('checking'); const [token, setToken] = useState(''); const [error, setError] = useState(''); const [submitting, setSubmitting] = useState(false); // On mount, check if saved token is still valid useEffect(() => { checkAuth(); }, []); async function checkAuth() { // If no token saved, might be dev mode (no auth required) try { const resp = await fetch(`${apiClient.getBaseURL()}/api/v1/health`); if (!resp.ok) { setState('login'); return; } // Health is public, but try a protected endpoint to see if auth is needed const headers: Record = { 'Content-Type': 'application/json' }; if (apiClient.hasToken()) { headers['Authorization'] = `Bearer ${localStorage.getItem('wild-central:token')}`; } const statusResp = await fetch(`${apiClient.getBaseURL()}/api/v1/operator`, { headers }); if (statusResp.ok) { setState('authenticated'); } else if (statusResp.status === 401) { // Auth required but token is missing or invalid if (apiClient.hasToken()) { apiClient.clearToken(); } setState('login'); } else { // Other error — maybe server is starting up, treat as authenticated setState('authenticated'); } } catch { // Can't reach server — show app anyway, it'll show connection errors setState('authenticated'); } } async function handleLogin(e: React.FormEvent) { e.preventDefault(); setError(''); setSubmitting(true); try { // Test the token against a protected endpoint const resp = await fetch(`${apiClient.getBaseURL()}/api/v1/operator`, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, }); if (resp.ok) { apiClient.setToken(token); setState('authenticated'); } else if (resp.status === 401) { setError('Invalid token'); } else { setError(`Server error: ${resp.status}`); } } catch { setError('Cannot reach Wild Central'); } finally { setSubmitting(false); } } if (state === 'checking') { return (
); } if (state === 'authenticated') { return <>{children}; } // Login screen return (

Wild Central

Enter your API token to continue

{error && ( {error} )}
setToken(e.target.value)} placeholder="Paste your bearer token" className="mt-1 font-mono" autoFocus />

Find your token in secrets.yaml under api.bearerToken

); }