import { useCallback, useEffect, useState } from 'react' import { LogOut } from 'lucide-react' interface Ticket { id: string; name: string; email: string; topic: string; message: string; status: string; emailed: number; created: string } interface StaffFaq { id: number; category: string; question: string; answer: string; link: string; linkLabel: string; up: number; down: number } interface Member { id: number; email: string; name: string } type Tab = 'tickets' | 'faqs' | 'team' async function api(path: string, method = 'GET', body?: unknown): Promise { const res = await fetch(`/api${path}`, { method, headers: body ? { 'Content-Type': 'application/json' } : undefined, body: body ? JSON.stringify(body) : undefined }) const data = await res.json().catch(() => ({})) if (!res.ok) throw Object.assign(new Error(data.error || 'Request failed'), { status: res.status }) return data as T } const box = 'liquid-glass rounded-3xl p-6 text-white' const input = 'w-full bg-white/5 rounded-2xl px-4 py-3 text-white placeholder:text-white/40 outline-none' const btn = 'liquid-glass rounded-full px-5 py-2 text-sm text-white hover:bg-white/5 transition-colors' function Login({ onDone }: { onDone: () => void }) { const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [error, setError] = useState('') const submit = async (e: React.FormEvent) => { e.preventDefault() try { await api('/login', 'POST', { email, password }); onDone() } catch (err) { setError((err as Error).message) } } return (

Staff login

setEmail(e.target.value)} autoComplete="username" /> setPassword(e.target.value)} autoComplete="current-password" /> {error &&

{error}

}
) } function Tickets() { const [rows, setRows] = useState([]) const load = useCallback(() => api('/staff/tickets').then(setRows), []) useEffect(() => { load() }, [load]) const setStatus = async (id: string, status: string) => { await api(`/staff/tickets/${id}`, 'PATCH', { status }); load() } if (!rows.length) return

No tickets yet.

return (
    {rows.map((t) => (
  • {t.id} · {t.topic} · {new Date(t.created).toLocaleString()} {t.emailed ? 'emailed' : 'not emailed'}

    {t.message}

    {t.name} · {t.email}

  • ))}
) } const emptyFaq = { category: '', question: '', answer: '', link: '', linkLabel: '' } function Faqs() { const [rows, setRows] = useState([]) const [editing, setEditing] = useState<(typeof emptyFaq & { id?: number }) | null>(null) const [error, setError] = useState('') const load = useCallback(() => api('/staff/faqs').then(setRows), []) useEffect(() => { load() }, [load]) const save = async (e: React.FormEvent) => { e.preventDefault() if (!editing) return try { if (editing.id) await api(`/staff/faqs/${editing.id}`, 'PUT', editing) else await api('/staff/faqs', 'POST', editing) setEditing(null); setError(''); load() } catch (err) { setError((err as Error).message) } } const remove = async (f: StaffFaq) => { if (confirm(`Delete "${f.question}"?`)) { await api(`/staff/faqs/${f.id}`, 'DELETE'); load() } } const set = (k: keyof typeof emptyFaq) => (e: React.ChangeEvent) => editing && setEditing({ ...editing, [k]: e.target.value }) return (
{editing ? (