const ex = el("button", { class: "btn sm secondary", onclick: () => { window.location = `/campaigns/${MON.id}/export`; } }, "Export CSV");
const pv = el("button", { class: "btn sm secondary", onclick: () => campaignPreview(MON.id) }, "Preview");
ctl.append(ex, pv);
}).catch(() => {});
}
async function drawRecipients() {
let box = $("#recBox");
if (!box) { box = el("div", { id: "recBox" }); $("#monBody").append(box); }
await loadRecipients(box);
}
async function loadRecipients(box) {
const p = new URLSearchParams({ status: MON.statusF, search: MON.q,
page: MON.page, page_size: 50 });
let d;
try { d = await GET(`/campaigns/${MON.id}/recipients?` + p); }
catch (e) { box.innerHTML = `
`; return; }
const rows = d.recipients || [];
const RS_BADGE = { pending: "b-gray", queued: "b-blue", processing: "b-amber", sent: "b-green",
temp_failed: "b-amber", perm_failed: "b-red", suppressed: "b-violet",
skipped: "b-gray", bounced: "b-red" };
box.innerHTML = `
Per-recipient monitor
${d.total} recipients
${rows.length ? `
| Seq | Email | Status | Account | Subject | Invoice | Amount | Attempts | Sent at | Message ID | Last error |
${rows.map(r => `
| ${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))} |
`).join("")}
` : `
◷
No recipients materialized yet — they are created when the campaign starts.
`}
`;
$("#recF").onchange = () => { MON.statusF = $("#recF").value; MON.page = 1; loadRecipients(box); };
$("#recQ").onkeydown = e => { if (e.key === "Enter") { MON.q = $("#recQ").value.trim(); MON.page = 1; loadRecipients(box); } };
$("#recGo").onclick = () => { MON.statusF = $("#recF").value; MON.q = $("#recQ").value.trim(); MON.page = 1; loadRecipients(box); };
const pages = Math.max(1, Math.ceil(d.total / 50));
$("#recPager").innerHTML = pages > 1 ?
`
Page ${MON.page} of ${pages}
` : "";
$$("#recPager [data-pg]").forEach(b => b.onclick = () => { MON.page = +b.dataset.pg; loadRecipients(box); });
}
/* ==================== CAMPAIGN PREVIEW MODAL ==================== */
async function campaignPreview(cid, size) {
let d;