import { useState } from 'react'; import { Check, KeyRound, Loader2, AlertCircle } from 'lucide-react'; import { authFetch } from '../../lib/auth'; export interface EnvField { name: string; label: string; placeholder: string; } export interface EnvGroupData { title: string; fields: EnvField[]; } interface Props { group: EnvGroupData; } export default function EnvForm({ group }: Props) { const [values, setValues] = useState>({}); const [status, setStatus] = useState<'idle' | 'submitting' | 'submitted' | 'error'>('idle'); const [errorMsg, setErrorMsg] = useState(''); const handleChange = (name: string, value: string) => { setValues((prev) => ({ ...prev, [name]: value })); }; const handleSubmit = async () => { // Check that at least one field has a value const filled = Object.entries(values).filter(([, v]) => v.trim()); if (filled.length === 0) return; setStatus('submitting'); setErrorMsg(''); try { const res = await authFetch('/api/env', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ vars: Object.fromEntries(filled) }), }); if (!res.ok) { const data = await res.json().catch(() => ({ error: 'Request failed' })); throw new Error(data.error || 'Request failed'); } setStatus('submitted'); } catch (err: any) { setErrorMsg(err.message || 'Failed to save'); setStatus('error'); } }; const filledCount = Object.values(values).filter((v) => v.trim()).length; // Submitted state if (status === 'submitted') { return (
{group.title} {filledCount} variable{filledCount !== 1 ? 's' : ''} saved — backend restarting
); } return (
{/* Header */}
{group.title}
{/* Fields */}
{group.fields.map((field) => (
handleChange(field.name, e.target.value)} disabled={status === 'submitting'} className="w-full px-3 py-2 rounded-lg text-sm bg-background border border-border/60 text-foreground placeholder:text-muted-foreground/40 focus:outline-none focus:ring-2 focus:ring-primary/30 focus:border-primary/50 disabled:opacity-50 transition-colors font-mono" spellCheck={false} autoComplete="off" />
))}
{/* Error message */} {status === 'error' && (
{errorMsg}
)} {/* Footer */}
Values are written to .env
); }