'use client'; import { apiFetch } from '@/lib/api'; import { Loader2 } from 'lucide-react'; import Link from 'next/link'; import { useEffect, useState } from 'react'; interface AdminTicketRow { ticket: { id: string; subject: string; status: 'awaiting_admin' | 'awaiting_user' | 'closed'; guestEmail: string | null; createdAt: string; lastMessageAt: string; }; userEmail: string | null; userName: string | null; } const STATUS_BADGE: Record = { awaiting_admin: 'bg-amber-500/20 text-amber-300', awaiting_user: 'bg-emerald-500/20 text-emerald-300', closed: 'bg-[--color-bg-subtle] text-[--color-fg-subtle]', }; export default function AdminSupport() { const [rows, setRows] = useState(null); const [error, setError] = useState(null); const [filter, setFilter] = useState<'all' | 'awaiting_admin' | 'awaiting_user' | 'closed'>( 'awaiting_admin', ); useEffect(() => { apiFetch<{ tickets: AdminTicketRow[] }>('/v1/admin/support/tickets') .then((r) => setRows(r.tickets)) .catch((e) => setError((e as Error).message)); }, []); const filtered = (rows ?? []).filter( (r) => filter === 'all' || r.ticket.status === filter, ); return (
← Admin

Support tickets

{(['awaiting_admin', 'awaiting_user', 'closed', 'all'] as const).map((s) => ( ))}
{error &&

{error}

}
{rows === null && (
)} {rows && filtered.length === 0 && (
No tickets in this view.
)} {rows && filtered.length > 0 && (
    {filtered.map((r) => { const from = r.userEmail ? `${r.userName ? `${r.userName} · ` : ''}${r.userEmail}` : r.ticket.guestEmail ? `${r.ticket.guestEmail} (guest)` : 'unknown'; return (
  • {/* Whole row is the link — table-style layout via flex so any pixel inside is clickable, not just the subject. */}
    {r.ticket.subject}
    {from}
    {r.ticket.status.replace('_', ' ')} {new Date(r.ticket.lastMessageAt).toLocaleString()}
  • ); })}
)}
); }