1import{bn as Ae,cI as Fe,cP as qe,cG as $e,c9 as j,cK as v,cH as N,bN as e,S as ee,b,Q as se,a3 as Oe,a6 as Re,a7 as Le,a4 as De,a5 as te,c7 as L,b5 as g}from"./index-feE7tAhu.js";import{a as ae,e as Ee}from"./AdminLayout-TC8aUQqP.js";import{C as o}from"./card-DsnXC7O4.js";import{A as ie,c as ne,f as de,g as re,d as le,e as ce,b as oe,a as me}from"./alert-dialog-C24ZQQpp.js";import{C as Ue}from"./chevron-right-qCouvXSQ.js";import{C as Ie}from"./circle-x-DM398HSJ.js";import{P as Ve}from"./pencil-CO-ZPwqn.js";import{S as We}from"./shield-check-DHaNpHTd.js";import{C as Ke}from"./calendar-clock-DWQWuCYh.js";import"./lock-J2QDtiS5.js";import"./users-DksU9zI3.js";import"./mail-D8LyDl_h.js";import"./calendar-DXZWDWxy.js";import"./door-open-C4t005Q3.js";import"./map-pin-B6S3Kid-.js";import"./circle-check-big-D2F-na_C.js";/** 2 * @license lucide-react v0.453.0 - ISC 3 * 4 * This source code is licensed under the ISC license. 5 * See the LICENSE file in the root directory of this source tree. 6 */const ue=Ae("RotateCw",[["path",{d:"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8",key:"1p45f6"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}]]);function Be(n,d,l){var y,m,C;return{channel:n.channel,audiences:n.audiences,subject:n.subject,bodyHtml:n.bodyHtml,bodyText:n.bodyText,fromEmail:n.fromEmail,fromName:n.fromName,replyTo:n.replyTo,firstNameFallback:n.firstNameFallback??null,previewText:n.previewText??null,category:n.category,suppressionRules:n.suppressionRules??null,experimentKey:n.experimentKey??null,subjectVariants:n.subjectVariants??null,excludePastDonors:((y=n.composeMeta)==null?void 0:y.excludePastDonors)===!0,pastDonorWindow:((m=n.composeMeta)==null?void 0:m.pastDonorWindow)??"all_time",checkedInVisitorsFilter:((C=n.composeMeta)==null?void 0:C.checkedInVisitorsFilter)??null,utmSource:n.utmSource??null,utmMedium:n.utmMedium??null,utmCampaign:n.utmCampaign??null,utmContent:n.utmContent??null,seedWave:n.seedWave??null,testTo:d,...Array.isArray(n.subjectVariants)?{proofArm:l}:{}}}function rs(){var _,H,z,Q,G,X,Y;const d=Fe().id,{toast:l}=qe(),[,y]=$e(),[m,C]=j.useState(""),[xe,D]=j.useState(!1),[he,P]=j.useState(!1),[k,E]=j.useState(""),[w,pe]=j.useState(""),[U,je]=j.useState("A"),{data:c}=v({queryKey:["/api/admin/broadcasts",d],refetchInterval:s=>{var r;const i=(r=s.state.data)==null?void 0:r.campaign;return(i==null?void 0:i.status)==="sending"?2e3:!1}}),{data:u}=v({queryKey:["/api/admin/broadcasts/send-rate"]}),{data:a,isError:be}=v({queryKey:["/api/admin/broadcasts",d,"engagement"],queryFn:async()=>{const s=await fetch(`/api/admin/broadcasts/${d}/engagement`,{credentials:"include"});if(!s.ok)throw new Error("Failed to load engagement");return s.json()},refetchInterval:1e4}),{data:x}=v({queryKey:["/api/admin/broadcasts",d,"recipients",m],queryFn:async()=>{const s=`/api/admin/broadcasts/${d}/recipients${m?`?status=${m}`:""}`,i=await fetch(s,{credentials:"include"});if(!i.ok)throw new Error("Failed to fetch recipients");return i.json()},refetchInterval:5e3}),{data:f}=v({queryKey:["/api/admin/broadcasts",d,"arm-stats"],enabled:!!((_=c==null?void 0:c.campaign)!=null&&_.subjectVariants)}),I=N({mutationFn:async()=>g("POST",`/api/admin/broadcasts/${d}/cancel`,{}),onSuccess:()=>{L.invalidateQueries({queryKey:["/api/admin/broadcasts",d]}),l({title:"Campaign cancelled"})},onError:s=>l({title:"Cancel failed",description:(s==null?void 0:s.message)||String(s),variant:"destructive"})}),T=N({mutationFn:async()=>(await g("POST",`/api/admin/broadcasts/${d}/resume`,{})).json(),onSuccess:s=>{L.invalidateQueries({queryKey:["/api/admin/broadcasts",d]});const i=(s==null?void 0:s.retriedFailed)??0;l({title:"Campaign resumed",description:i>0?`Sending picks up where it stopped. ${i.toLocaleString()} previously-failed recipient${i===1?"":"s"} queued for retry.`:"Sending picks up where it stopped. No failed recipients needed a retry."})},onError:s=>l({title:"Resume failed",description:(s==null?void 0:s.message)||String(s),variant:"destructive"})}),A=N({mutationFn:async()=>g("POST",`/api/admin/broadcasts/${d}/send`,{}),onSuccess:()=>{L.invalidateQueries({queryKey:["/api/admin/broadcasts",d]}),l({title:"Sending started"})},onError:s=>l({title:"Send failed",description:(s==null?void 0:s.message)||String(s),variant:"destructive"})}),F=N({mutationFn:async()=>g("POST",`/api/admin/broadcasts/${d}
6/non-opener-resend`,{subject:k}).then(s=>s.json()),onSuccess:s=>{P(!1),l({title:"Non-opener resend prepared",description:`${s.inserted.toLocaleString()} final recipients. Review the draft, send a proof, then launch.`}),y(`/admin/broadcasts/${s.campaign.id}`)},onError:s=>l({title:"Could not prepare resend",description:(s==null?void 0:s.message)||String(s),variant:"destructive"})}),q=N({mutationFn:async()=>{const s=c==null?void 0:c.campaign;if(!s)throw new Error("Campaign is not loaded.");return g("POST","/api/admin/broadcasts/test",Be(s,w,U)).then(i=>i.json())},onSuccess:s=>l({title:s.ok?"Proof sent":"Proof failed",description:s.ok?`Sent to ${w}`:"Check server logs",variant:s.ok?"default":"destructive"}),onError:s=>l({title:"Proof failed",description:(s==null?void 0:s.message)||String(s),variant:"destructive"})}),t=c==null?void 0:c.campaign;if(!t)return e.jsx(ae,{children:e.jsx("div",{className:"p-8 admin-muted",children:"Loadingâ¦"})});const fe=180*1e3,ve=t.lastSentAt?new Date(t.lastSentAt).getTime():0,Ne=t.lastClaimedAt?new Date(t.lastClaimedAt).getTime():0,ge=Math.max(ve,Ne),ye=t.startedAt?new Date(t.startedAt).getTime():0,V=ge||ye,Ce=t.status==="sending"&&V>0&&Date.now()-V>fe,W=t.status==="sent"&&t.failedCount>0,we=t.status==="failed"||Ce||W,K=Math.min(t.recipientCountPlanned,t.sentCount+t.failedCount),B=t.recipientCountPlanned>0?Math.min(100,Math.round(K/t.recipientCountPlanned*100)):0,S=t.channel==="sms"?u==null?void 0:u.smsDelayMs:u==null?void 0:u.emailDelayMs,Se=Math.max(0,t.recipientCountPlanned-K);let $=null;if(t.status==="sending"&&S&&S>0){const s=1e3/S,i=Math.ceil(Se*S/1e3),r=i<60?`${i} sec`:i<3600?`about ${Math.ceil(i/60)} min`:`about ${(i/3600).toFixed(1)} hr`;$=`Sending ~${s.toFixed(s<1?2:1)} ${t.channel==="sms"?"msg":"email"}/sec · ${r} remaining`}return e.jsx(ae,{children:e.jsxs("div",{className:"max-w-5xl mx-auto",children:[e.jsx(ee,{href:"/admin/broadcasts",children:e.jsxs("span",{className:"inline-flex items-center text-sm text-gray-600 hover:text-gray-900 mb-4 cursor-pointer",children:[e.jsx(Ue,{className:"w-4 h-4"}),"Back to broadcasts"]})}),e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3 mb-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl sm:text-3xl font-bold admin-heading","data-testid":"text-page-title",children:t.subject||`${t.channel.toUpperCase()} broadcast`}),e.jsxs("div",{className:"text-sm admin-muted mt-1",children:["Campaign #",t.id.slice(0,8)," · ",t.channel," · status: ",e.jsx("strong",{children:t.status})]})]}),(t.status==="sending"||t.status==="scheduled")&&e.jsxs(b,{variant:"outline",onClick:()=>I.mutate(),disabled:I.isPending,"data-testid":"button-cancel",children:[e.jsx(Ie,{className:"w-4 h-4 mr-2"}),t.status==="scheduled"?"Cancel schedule":"Cancel"]}),t.status==="scheduled"&&e.jsx(ee,{href:`/admin/broadcasts/new?scheduled=${t.id}`,children:e.jsxs(b,{variant:"outline","data-testid":"button-edit-schedule",children:[e.jsx(Ve,{className:"w-4 h-4 mr-2"}),"Edit schedule"]})}),we&&e.jsxs(b,{onClick:()=>D(!0),disabled:T.isPending,"data-testid":"button-resume",children:[e.jsx(ue,{className:"w-4 h-4 mr-2"}),T.isPending?"Resumingâ¦":t.status==="failed"?"Resume sending":W?"Retry failed recipients":"Restart stalled send"]}),t.status==="draft"&&t.recipientCountPlanned>0&&e.jsxs(b,{onClick:()=>A.mutate(),disabled:A.isPending,"data-testid":"button-start-frozen-send",children:[e.jsx(Ee,{className:"w-4 h-4 mr-2"}),A.isPending?"Startingâ¦":`Send to ${t.recipientCountPlanned.toLocaleString()}`]}),t.channel==="email"&&(t.status==="sent"||t.status==="failed")&&e.jsxs(b,{variant:"outline",onClick:()=>{E(""),P(!0)},"data-testid":"button-non-opener-resend",children:[e.jsx(ue,{className:"w-4 h-4 mr-2"}),"Resend to non-openers"]}),e.jsx(ie,{open:he,onOpenChange:P,children:e.jsxs(ne,{"data-testid":"dialog-non-opener-resend",children:[e.jsxs(de,{children:[e.jsx(re,{children:"Prepare a non-opener resend"}),e.jsx(le,{children:"This creates a new frozen draft with the same message and stable subject-test arms. Openers, donors, global opt-outs, bounces, and complaints are automatically excluded."})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium",htmlFor:"resend-subject",children:"New subject"}),e.jsx(se,{id:"resend-subject",value:k,onChange:s=>E(s.target.value),placeholder:"Required new subject line","data-testid":"input-resend-subject"})]}),e.jsxs(ce,{children:[e.jsx(oe,{children:"Cancel"}),e.jsx(me,{onClick:s=>{s.preventDefault(),F.mutate()},disabled:!k.trim()||F.isPending,children:F.isPending?"Preparingâ¦":"Create frozen draft"})]})]})}),e.jsx(ie,{open:xe,onOpenChange:D,children:e.jsxs(ne,{"data-testid":"dialog-resume-confirm",children:[e.jsxs(de,{children:[e.jsx(re,{children:t.status==="failed"?"Resume this campaign?":"Restart this stalled send?"}),e.jsx(le,{"data-testid":"text-resume-confirm-description",children:t.failedCount>
60?`${t.failedCount.toLocaleString()} previously-failed recipient${t.failedCount===1?"":"s"} will be queued for retry and re-sent, in addition to any recipients that were never attempted.`:"No failed recipients will be retried â sending will simply pick up any recipients that were never attempted."})]}),e.jsxs(ce,{children:[e.jsx(oe,{"data-testid":"button-resume-cancel",children:"Cancel"}),e.jsx(me,{onClick:()=>T.mutate(),"data-testid":"button-resume-confirm",children:t.failedCount>0?`Retry ${t.failedCount.toLocaleString()} failed & resume`:"Resume sending"})]})]})})]}),e.jsxs(o,{className:"p-6 mb-6",children:[e.jsxs("div",{className:"mb-4 text-sm",children:[e.jsx("span",{className:"text-xs admin-muted block",children:"Audience"}),(t.audiences||[]).map(s=>{var i,r,h;return((r=(i=t.composeMeta)==null?void 0:i.audienceLabels)==null?void 0:r[s])||((h=t.audienceLabels)==null?void 0:h[s])||(s.startsWith("tour-rsvp:")?`Tour RSVP: ${s.slice(10)}`:null)||(s.startsWith("tour-waitlist:")?`Tour waitlist: ${s.slice(14)}`:null)||s}).join(", ")]}),((H=t.composeMeta)==null?void 0:H.excludePastDonors)===!0&&e.jsxs("div",{className:"mb-4 flex items-center gap-2 rounded-md border border-green-200 bg-green-50 px-3 py-2 text-sm text-green-800","data-testid":"campaign-past-donor-policy",children:[e.jsx(We,{className:"w-4 h-4 shrink-0"}),e.jsxs("span",{children:[e.jsx("strong",{children:"Past donors excluded"})," · ",((z=t.composeMeta)==null?void 0:z.pastDonorWindow)==="all_time"?"All time":`Past ${(G=(Q=t.composeMeta)==null?void 0:Q.pastDonorWindow)==null?void 0:G.replace("d","")} days`]})]}),((X=t.composeMeta)==null?void 0:X.checkedInVisitorsFilter)&&e.jsx("div",{className:"flex items-start gap-2 text-sm mt-2","data-testid":"checked-in-visitors-filter-summary",children:e.jsxs("span",{children:[e.jsx("strong",{children:"Checked-in visit window"})," · ",t.composeMeta.checkedInVisitorsFilter.startDate," through ",t.composeMeta.checkedInVisitorsFilter.endDate," · stop ",t.composeMeta.checkedInVisitorsFilter.tourStopId," (inclusive local dates)"]})}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-5 gap-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted",children:"Planned"}),e.jsx("div",{className:"text-2xl font-bold",children:t.recipientCountPlanned})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted",children:"Sending now"}),e.jsx("div",{className:"text-2xl font-bold text-blue-600","data-testid":"stat-claimed",children:t.claimedCount??0})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted",children:"Sent"}),e.jsx("div",{className:"text-2xl font-bold text-green-600","data-testid":"stat-sent",children:t.sentCount})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted",children:"Failed"}),e.jsx("div",{className:"text-2xl font-bold text-red-600","data-testid":"stat-failed",children:t.failedCount})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted",children:"Suppressed"}),e.jsx("div",{className:"text-2xl font-bold text-amber-600","data-testid":"stat-suppressed",children:t.suppressedCount})]})]}),e.jsxs("div",{className:"mt-4",children:[e.jsx("div",{className:"h-2 bg-gray-200 rounded-full overflow-hidden",children:e.jsx("div",{className:"h-full bg-green-500 transition-all",style:{width:`${B}%`}})}),e.jsxs("div",{className:"text-xs admin-muted mt-1 flex items-center justify-between gap-3",children:[e.jsxs("span",{children:[B,"% complete"]}),$&&e.jsx("span",{"data-testid":"text-eta",children:$})]})]})]}),t.status==="draft"&&t.recipientCountPlanned>0&&e.jsxs(o,{className:"p-6 mb-6 border-blue-200 bg-blue-50","data-testid":"card-frozen-draft-launch",children:[e.jsx("h3",{className:"font-semibold",children:"Frozen draft ready for review"}),e.jsxs("p",{className:"text-sm mt-1",children:["Final recipients: ",e.jsx("strong",{children:t.recipientCountPlanned.toLocaleString()})," · suppressed before snapshot: ",e.jsx("strong",{children:t.suppressedCount.toLocaleString()})]}),Array.isArray((Y=t.composeMeta)==null?void 0:Y.suppressionBreakdown)&&e.jsx("ul",{className:"mt-3 text-xs space-y-1","data-testid":"draft-suppression-breakdown",children:t.composeMeta.suppressionBreakdown.map((s,i)=>e.jsxs("li",{children:[s.label,": ",s.matched," matched, ",s.newlyExcluded," newly excluded"]},`${s.label}-${i}`))}),e.jsxs("div",{className:"mt-4 flex flex-col sm:flex-row gap-2",children:[e.jsx(se,{value:w,onChange:s=>pe(s.target.value),placeholder:t.channel==="email"?"Proof email address":"Proof phone number","data-testid":"input-proof-to"}),t.channel==="email"&&Array.isArray(t.subjectVariants)&&e.jsxs(Oe,{value:U,onValueChange:s=>je(s),children:[e.jsx(Re,{className:"sm:w-36","data-testid":"select-proof-arm",children:e.jsx(Le,{})}),e.jsxs(De,{children:[e.jsx(te,{value:"A",children:"Proof arm A"}),e.jsx(te,{value:"B",children:"Proof arm B"})]})]}),e.jsx(b,{variant:"outline",onClick:()=>q.mutate(),disabled:!w.trim()||q.isPending,"data-testid":"button-send-proof",children:q.isPending?"Sendingâ¦":"Send proof"})]})]}),t.status==="scheduled"&&t.scheduledFor&&e.jsxs(o,{className:"p-6 mb-6 border-purple-200 bg-purple-50","data-testid":"card-scheduled-status",children:[e.jsxs("div",{className:"flex items-center gap-2 font-semibold text-purple-800",children:[e.jsx(Ke,{className:"w-5 h-5"}),"Scheduled launch"]}),e.jsxs("div",{className:"mt-1 text-lg font-medium","data-testid":"text-scheduled-for",children:[new Date(t.scheduledFor).toLocaleStr
6ing("en-US",{timeZone:"America/New_York",dateStyle:"full",timeStyle:"short"})," ET"]}),e.jsx("p",{className:"text-xs admin-muted mt-1",children:"Recipients are frozen. The multi-instance scheduler will promote this campaign once at the scheduled minute."})]}),t.channel==="email"&&(t.utmSource||t.utmMedium||t.utmCampaign||t.utmContent||t.seedWave)&&e.jsxs(o,{className:"p-6 mb-6","data-testid":"card-attribution-settings",children:[e.jsx("h3",{className:"font-semibold mb-3",children:"Campaign attribution"}),e.jsxs("dl",{className:"grid grid-cols-2 md:grid-cols-5 gap-3 text-sm",children:[e.jsxs("div",{children:[e.jsx("dt",{className:"text-xs admin-muted",children:"UTM source"}),e.jsx("dd",{children:t.utmSource||"â"})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"text-xs admin-muted",children:"UTM medium"}),e.jsx("dd",{children:t.utmMedium||"â"})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"text-xs admin-muted",children:"UTM campaign"}),e.jsx("dd",{children:t.utmCampaign||"â"})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"text-xs admin-muted",children:"UTM content"}),e.jsx("dd",{children:t.utmContent||"â"})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"text-xs admin-muted",children:"Seed wave"}),e.jsx("dd",{children:t.seedWave||"â"})]})]})]}),t.channel==="sms"&&e.jsxs(o,{className:"p-6 mb-6",children:[e.jsx("h3",{className:"font-semibold mb-3",children:"Engagement"}),(()=>{const s=(a==null?void 0:a.totals)||{},i=s.sms_delivered??t.sentCount??0,r=s.sms_failed??0,h=s.unsubscribe??0,O=Math.max(1,i+r),M=(i/O*100).toFixed(1);return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-3 gap-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted",children:"Delivered"}),e.jsx("div",{className:"text-2xl font-bold text-green-700","data-testid":"eng-sms-delivered",children:i}),e.jsxs("div",{className:"text-xs admin-muted",children:[M,"% of attempted"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted",children:"Failed"}),e.jsx("div",{className:"text-2xl font-bold text-red-700","data-testid":"eng-sms-failed",children:r})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted",children:"Unsubscribes (STOP)"}),e.jsx("div",{className:"text-2xl font-bold text-gray-700","data-testid":"eng-sms-unsub",children:h})]})]}),i===0&&r===0&&e.jsx("p",{className:"text-xs admin-muted mt-3",children:"No SMS engagement data yet â events arrive via SMTP2GO webhook after delivery."})]})})()]}),t.channel==="email"&&e.jsxs(o,{className:"p-6 mb-6",children:[e.jsx("h3",{className:"font-semibold mb-3",children:"Engagement"}),be&&e.jsx("div",{className:"mb-3 rounded border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-800","data-testid":"banner-engagement-error",children:"Engagement stats could not be loaded â the numbers below may be missing or stale. Retrying automatically."}),(()=>{const s=(a==null?void 0:a.totals)||{},i=(a==null?void 0:a.deliveredCount)??s.delivered??0,r=s.spam_complaint??0,h=s.hard_bounce??0,O=s.soft_bounce??0,M=i||1,Me=(((a==null?void 0:a.uniqueOpens)??0)/M*100).toFixed(1),Pe=(a==null?void 0:a.uniqueCtr)!=null?Number(a.uniqueCtr).toFixed(1):(((a==null?void 0:a.uniqueClicks)??0)/M*100).toFixed(1),ke=(a==null?void 0:a.clickToOpenRate)!=null?Number(a.clickToOpenRate).toFixed(1):a!=null&&a.uniqueOpens?(a.uniqueClicks/a.uniqueOpens*100).toFixed(1):"0.0",R=a==null?void 0:a.reconciled,Te=(R==null?void 0:R.optOutsOrUnsubsFromRecipients)??0,Z=(a==null?void 0:a.topDestinations)||(a==null?void 0:a.perLink)||[];return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-5 gap-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted cursor-help",title:"Delivered = successfully sent recipients minus recipients that bounced (hard or soft). This is the denominator for open rate and CTR.",children:"Delivered"}),e.jsx("div",{className:"text-2xl font-bold","data-testid":"eng-delivered",children:i}),((a==null?void 0:a.sentCount)??0)>0&&e.jsxs("div",{className:"text-xs admin-muted",children:["of ",a==null?void 0:a.sentCount," sent · ",(a==null?void 0:a.uniqueBounced)??0," bounced"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted",children:"Opens"}),e.jsx("div",{className:"text-2xl font-bold text-blue-600","data-testid":"eng-opens",children:(a==null?void 0:a.uniqueOpens)??0}),e.jsxs("div",{className:"text-xs admin-muted",children:["unique (",Me,"% of delivered)"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted",children:"Clicks"}),e.jsx("div",{className:"text-2xl font-bold text-indigo-600","data-testid":"eng-clicks",children:(a==null?void 0:a.uniqueClicks)??0}),e.jsxs("div",{className:"text-xs admin-muted",children:[Pe,"% unique CTR · ",ke,"% CTOR"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted",children:"Bounces / Spam"}),e.jsxs("div",{className:"text-sm font-medium",children:[e.jsx("span",{className:"text-red-700","data-testid":"eng-hard",children:h})," hard"," · ",e.jsx("span",{className:"text-amber-700","data-testid":"eng-soft",children:O})," soft"," · ",e.jsx("span",{className:"text-red-700","data-testid":"eng-spam",children:r})," spam"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted cursor-help",title:"Distinct recipients of this campaign who opted out of its email category or globally unsubscribed since the send started. Someone who did both counts once.",children:"Opt-outs & unsubscribes"}),e.jsx("div",{className:"text-2xl font-bold text-amber-700","data-testid":"eng-optouts-unsubs",children:Te}),e.jsx("div",{className:"text-xs admin-muted",children:"this campaign's recipients, since the send started"})]})]}),e.jsxs("div",{className:"mt-4 grid grid-cols-2 md:grid-cols-4 gap-3 text-sm",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted",children:"Attributed sessions"}),e.jsx("strong",{"data-testid":"eng-sessions",children:(a==null?void 0:a.attributedSessions)??0})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs admin-muted",children:"Supported conversions"}),e.jsx("strong",{"data-testid":"eng-conversions",children:(a==null?void 0:a.supportedConversions)??(a==null?void 0:a.conversions)??0})]})]}),e.jsx("p",{className:"text-xs text-amber-700 mt-3",children:"Open measurements are directional: privacy proxies (including Apple Mail) and blocked images can inflate, suppress, or delay opens. Use unique clicks and attributed sessions for stronger engagement signals."}),Z.length>0&&e.jsxs("div",{className:"mt-5",children:[e.jsx("h4",{className:"font-semibold text-sm mb-2",children:"Top destinations"}),e.jsx("div",{className:"overflow-auto max-h-64 border border-gray-200 rounded",children:e.jsxs("table",{className:"w-full text-sm min-w-[480px]",children:[e.jsx("thead",{className:"bg-gray-50 sticky top-0",children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-left px-2 py-1.5",children:"URL"}),e.jsx("th",{className:"text-right px-2 py-1.5",children:"Clicks"}),e.jsx("th",{className:"text-right px-2 py-1.5",children:"Unique"})]})}),e.jsx("tbody",{children:Z.map((p,J)=>e.jsxs("tr",{className:"border-b border-gray-100","data-testid":`eng-link-${J}`,children:[e.jsx("td",{className:"px-2 py-1.5 font-mono text-xs truncate max-w-[420px]",title:p.destinationUrl||p.url,children:p.destinationUrl||p.url}),e.jsx("td",{className:"px-2 py-1.5 text-right",children:p.clicks}),e.jsx("td",{className:"px-2 py-1.5 text-right",children:p.uniqueClicks})]},J))})]})})]}),i===0&&e.jsx("p",{className:"text-xs admin-muted mt-3",children:"No engagement data yet â events arrive via SMTP2GO webhook after delivery."})]})})()]}),(f==null?void 0:f.arms)&&f.arms.length>1&&e.jsxs(o,{className:"p-6 mb-6","data-testid":"card-subject-test-results",children:[e.jsx("h3",{className:"font-semibold mb-3",children:"Subject test performance"}),e.jsx("div",{className:"overflow-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-left py-2",children:"Arm"}),e.jsx("th",{className:"text-right",children:"Planned"}),e.jsx("th",{className:"text-right",children:"Delivered"}),e.jsx("th",{className:"text-right",children:"Unique opens"}),e.jsx("th",{className:"text-right",children:"Open rate"})]})}),e.jsx("tbody",{children:f.arms.map(s=>e.jsxs("tr",{className:"border-t",children:[e.jsx("td",{className:"py-2 font-semibold",children:s.arm}),e.jsx("td",{className:"text-right",children:s.planned}),e.jsx("td",{className:"text-right",children:s.delivered}),e.jsx("td",{className:"text-right",children:s.uniqueOpens}),e.jsxs("td",{className:"text-right",children:[s.delivered?(s.uniqueOpens/s.delivered*100).toFixed(1):"0.0","%"]})]},s.arm))})]})})]}),e.jsxs(o,{className:"p-6 mb-6",children:[e.jsx("h3",{className:"font-semibold mb-2",children:"Message"}),t.subject&&e.jsxs("div",{className:"mb-2 text-sm",children:[e.jsx("strong",{children:"Subject:"})," ",t.subject]}),e.jsx("pre",{className:"text-sm bg-gray-50 p-3 rounded whitespace-pre-wrap font-sans border border-gray-200",children:t.bodyText}),t.channel==="email"&&t.bodyHtml&&e.jsxs("details",{className:"mt-3",children:[e.jsx("summary",{className:"cursor-pointer text-sm admin-muted",children:"Show HTML"}),e.jsx("pre",{className:"text-xs bg-gray-50 p-3 rounded mt-2 overflow-auto max-h-96 border border-gray-200",children:t.bodyHtml})]})]}),e.jsxs(o,{className:"p-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 mb-3",children:[e.jsxs("h3",{className:"font-semibold",children:["Recipients (",(x==null?void 0:x.total)??0,")"]}),e.jsxs("select",{value:m,onChange:s=>C(s.target.value),className:"text-base sm:text-sm border border-gray-200 rounded px-2 py-1
6w-full sm:w-auto","data-testid":"select-status-filter",children:[e.jsx("option",{value:"",children:"All statuses"}),e.jsx("option",{value:"pending",children:"Pending"}),e.jsx("option",{value:"claimed",children:"Sending now"}),e.jsx("option",{value:"sent",children:"Sent"}),e.jsx("option",{value:"failed",children:"Failed"}),e.jsx("option",{value:"suppressed",children:"Suppressed"})]})]}),e.jsx("div",{className:"overflow-auto max-h-[400px]",children:e.jsxs("table",{className:"w-full text-sm min-w-[640px]",children:[e.jsx("thead",{className:"bg-gray-50 sticky top-0",children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-left px-2 py-2",children:"Contact"}),e.jsx("th",{className:"text-left px-2 py-2",children:"Source"}),e.jsx("th",{className:"text-left px-2 py-2",children:"Arm"}),e.jsx("th",{className:"text-left px-2 py-2",children:"Status"}),e.jsx("th",{className:"text-left px-2 py-2",children:"When"}),e.jsx("th",{className:"text-left px-2 py-2",children:"Error"})]})}),e.jsx("tbody",{children:x==null?void 0:x.rows.map(s=>e.jsxs("tr",{className:"border-b border-gray-100","data-testid":`row-recipient-${s.id}`,children:[e.jsx("td",{className:"px-2 py-1.5 font-mono text-xs",children:s.email||s.phone}),e.jsx("td",{className:"px-2 py-1.5 text-xs admin-muted",children:s.sourceTable}),e.jsx("td",{className:"px-2 py-1.5 text-xs font-semibold",children:s.variantArm||"â"}),e.jsx("td",{className:"px-2 py-1.5",children:e.jsx("span",{className:`text-xs px-1.5 py-0.5 rounded ${s.status==="sent"?"bg-green-100 text-green-700":s.status==="failed"?"bg-red-100 text-red-700":s.status==="suppressed"?"bg-amber-100 text-amber-700":s.status==="claimed"?"bg-blue-100 text-blue-700":"bg-gray-100 text-gray-600"}`,children:s.status})}),e.jsx("td",{className:"px-2 py-1.5 text-xs admin-muted",children:s.sentAt?new Date(s.sentAt).toLocaleTimeString():"â"}),e.jsx("td",{className:"px-2 py-1.5 text-xs text-red-700 max-w-[280px] truncate",title:s.errorMessage||"","data-testid":`recipient-error-${s.id}`,children:s.errorMessage||""})]},s.id))})]})})]})]})})}export{Be as buildBroadcastProofPayload,rs as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.