MON.es.addEventListener("connected", () => $("#liveInd").classList.remove("hidden")); MON.es.addEventListener("progress", ev => { try { paintProgress(JSON.parse(ev.data)); } catch {} }); MON.es.addEventListener("done", ev => { try { paintProgress(JSON.parse(ev.data)); } catch {} stopStream(); toast(`Campaign finished — status: ${(JSON.parse(ev.data) || {}).status || "?"}`, "info", 6000); drawControls(); }); MON.es.onerror = () => { $("#liveInd").classList.add("hidden"); }; } async function drawProgress() { try { const p = await GET(`/campaigns/${MON.id}/progress`); paintProgress(p); } catch (e) { $("#monBody").innerHTML = `
| Seq | Status | Account | Subject | Invoice | Amount | Attempts | Sent at | Message ID | Last error | |
|---|---|---|---|---|---|---|---|---|---|---|
| ${r.seq} | ${esc(r.email)} | ${esc(r.status)} | ${esc(r.account || "—")} | ${esc((r.subject || "—").slice(0, 60))} | ${esc(r.invoice_number || "—")} | ${r.amount != null ? fmtMoney(r.amount) : "—"} | ${r.attempts ?? 0} | ${fmtDT(r.sent_at)} | ${r.message_id ? esc(r.message_id.slice(0, 14)) + "…" : "—"} | ${esc((r.last_error || "—").slice(0, 80))} |
No recipients materialized yet — they are created when the campaign starts.