'use client'; import { useCallback, useEffect, useState } from 'react'; import Link from 'next/link'; import { api, errMsg } from '@/lib/api'; import { Alert, Empty, fmt } from '@/components/ui'; interface Msg { id: string; fromEmail: string; fromName: string | null; subject: string | null; bodyText: string | null; receivedAt: string; status: 'unmatched' | 'matched' | 'created' | 'ignored'; ticketId: string | null; ticketNumber: string | null } interface Cust { id: string; name: string; customerNumber: string } const STATUS_LABEL: Record = { unmatched: 'Unzugeordnet', matched: 'An Ticket angehängt', created: 'Ticket erstellt', ignored: 'Ignoriert' }; /** Eine unzugeordnete Mail: Kunde zuweisen (legt neues Ticket an), an bestehendes Ticket anhängen, oder ignorieren. */ function UnmatchedRow({ m, custs, onDone, onError }: { m: Msg; custs: Cust[]; onDone: (t: string) => void; onError: (m: string) => void }) { const [org, setOrg] = useState(''); const [ticketNumber, setTicketNumber] = useState(''); const [busy, setBusy] = useState(false); const [open, setOpen] = useState(false); async function assign() { if (!org) return; setBusy(true); try { const r = await api<{ number: string }>('POST', `/admin/inbox/${m.id}/assign`, { orgId: org }); onDone(`Ticket ${r.number} angelegt.`); } catch (x) { onError(errMsg(x)); } finally { setBusy(false); } } async function link() { if (!ticketNumber.trim()) return; setBusy(true); try { await api('POST', `/admin/inbox/${m.id}/link`, { ticketNumber: ticketNumber.trim() }); onDone(`An Ticket ${ticketNumber.trim()} angehängt.`); } catch (x) { onError(errMsg(x)); } finally { setBusy(false); } } async function ignore() { setBusy(true); try { await api('POST', `/admin/inbox/${m.id}/ignore`); onDone('Ignoriert.'); } catch (x) { onError(errMsg(x)); } finally { setBusy(false); } } return (
{m.subject || '(kein Betreff)'}

Von: {m.fromName ? `${m.fromName} <${m.fromEmail}>` : m.fromEmail} · {fmt(m.receivedAt)}

{open &&
{m.bodyText || '(kein Text)'}
}
setTicketNumber(e.target.value)} style={{ width: 100 }} />
); } export default function Posteingang() { const [status, setStatus] = useState<'unmatched' | 'matched' | 'created' | 'ignored' | ''>('unmatched'); const [list, setList] = useState(null); const [custs, setCusts] = useState([]); const [err, setErr] = useState(''); const [ok, setOk] = useState(''); const load = useCallback(() => api('GET', `/admin/inbox${status ? `?status=${status}` : ''}`).then(setList).catch((e) => setErr(errMsg(e))), [status]); useEffect(() => { void load(); }, [load]); useEffect(() => { api('GET', '/admin/customers').then(setCusts).catch(() => undefined); }, []); return (<>

Posteingang

Mails aus dem konfigurierten Ticket-Postfach, die nicht automatisch zugeordnet werden konnten (siehe Einstellungen > E-Mail > IMAP-Posteingang).

{err && {err}} {ok && {ok}}
{(['unmatched', 'matched', 'created', 'ignored', ''] as const).map((s) => )}
{list === null ?

Wird geladen …

: list.length === 0 ?
{status === 'unmatched' ? 'Aktuell liegen keine unzugeordneten Mails vor.' : 'Für diesen Filter gibt es keine Einträge.'}
: list.map((m) => m.status === 'unmatched' ? { setOk(t); setErr(''); void load(); }} onError={setErr} /> :
{m.subject || '(kein Betreff)'}

Von: {m.fromName ? `${m.fromName} <${m.fromEmail}>` : m.fromEmail} · {fmt(m.receivedAt)}

{STATUS_LABEL[m.status]}{m.ticketNumber && {m.ticketNumber} ansehen}
)} ); }