1import{bn as M,cP as se,c9 as p,cK as L,cH as D,bN as e,b as g,Q as ne,b5 as G,c7 as V}from"./index-feE7tAhu.js";import{e as ie,g as Q,a as le}from"./AdminLayout-TC8aUQqP.js";import{M as re}from"./mail-D8LyDl_h.js";import{T as de}from"./triangle-alert-pv6JPMvJ.js";import{H as ce}from"./history-D4yIheM-.js";import{R as oe}from"./refresh-cw-CDuYFNiB.js";import{S as me}from"./search-C8OsDzax.js";import{C as ue,a as pe}from"./chevron-right-qCouvXSQ.js";import"./lock-J2QDtiS5.js";import"./users-DksU9zI3.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 he=M("MailOpen",[["path",{d:"M21.2 8.4c.5.38.8.97.8 1.6v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V10a2 2 0 0 1 .8-1.6l8-6a2 2 0 0 1 2.4 0l8 6Z",key:"1jhwl8"}],["path",{d:"m22 10-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 10",key:"1qfld7"}]]);/** 7 * @license lucide-react v0.453.0 - ISC 8 * 9 * This source code is licensed under the ISC license. 10 * See the LICENSE file in the root directory of this source tree. 11 */const xe=M("MousePointerClick",[["path",{d:"M14 4.1 12 6",key:"ita8i4"}],["path",{d:"m5.1 8-2.9-.8",key:"1go3kf"}],["path",{d:"m6 12-1.9 2",key:"mnht97"}],["path",{d:"M7.2 2.2 8 5.1",key:"1cfko1"}],["path",{d:"M9.037 9.69a.498.498 0 0 1 .653-.653l11 4.5a.5.5 0 0 1-.074.949l-4.349 1.041a1 1 0 0 0-.74.739l-1.04 4.35a.5.5 0 0 1-.95.074z",key:"s0h3yz"}]]);/** 12 * @license lucide-react v0.453.0 - ISC 13 * 14 * This source code is licensed under the ISC license. 15 * See the LICENSE file in the root directory of this source tree. 16 */const be=M("OctagonX",[["path",{d:"m15 9-6 6",key:"1uzhvr"}],["path",{d:"M2.586 16.726A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2h6.624a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586z",key:"2d38gg"}],["path",{d:"m9 9 6 6",key:"z0biqf"}]]),X={"24h":"Last 24 hours","7d":"Last 7 days","30d":"Last 30 days",all:"All time"},ye=["delivered","open","click","soft_bounce","hard_bounce","spam_complaint","unsubscribe"],Z={delivered:"Delivered",open:"Opens",click:"Clicks",soft_bounce:"Soft bounces",hard_bounce:"Hard bounces",spam_complaint:"Spam complaints",unsubscribe:"Unsubscribes"};function h(o){if(!o)return"â";const u=new Date(o);return Number.isNaN(u.getTime())?"â":u.toLocaleString()}const E=50;function Te(){var F,I,B,H,z,K,U;const{toast:o}=se(),[u,Y]=p.useState("7d"),[k,J]=p.useState(""),[A,W]=p.useState(""),[x,P]=p.useState("all"),[b,y]=p.useState(0),{data:l,isLoading:ee}=L({queryKey:["/api/admin/email-health/overview",{range:u}],queryFn:async()=>{const a=await fetch(`/api/admin/email-health/overview?range=${u}`,{credentials:"include"});if(!a.ok)throw new Error("Failed to load overview");return a.json()}}),{data:i}=L({queryKey:["/api/admin/bookmobile-signup/status"],queryFn:async()=>{const a=await fetch("/api/admin/bookmobile-signup/status",{credentials:"include"});if(!a.ok)throw new Error("Failed to load Bookmobile status");return a.json()}}),ae=["/api/admin/email-health/activity",{search:k,eventType:x,page:b}],{data:d,isLoading:T}=L({queryKey:ae,queryFn:async()=>{const a=new URLSearchParams;k&&a.set("search",k),x!=="all"&&a.set("eventType",x),a.set("limit",String(E)),a.set("offset",String(b*E));const r=await fetch(`/api/admin/email-health/activity?${a.toString()}`,{credentials:"include"});if(!r.ok)throw new Error("Failed to load activity");return r.json()}}),$=(a,r)=>{var m,j,c,N;const n=a==null?void 0:a.result;if(V.invalidateQueries({queryKey:["/api/admin/email-health/overview"]}),V.invalidateQueries({queryKey:["/api/admin/email-health/activity"]}),r!=null&&r.backfill){const C=n!=null&&n.complete?"History backfill complete":"Backfill chunk ingested";o({title:C,description:n?n.complete?`Full history ingested · ${((j=(m=n.totalIngested)==null?void 0:m.toLocaleString)==null?void 0:j.call(m))??n.totalIngested} total rows`:`${n.newActivityRows}
16 new this run · ${((N=(c=n.totalIngested)==null?void 0:c.toLocaleString)==null?void 0:N.call(c))??n.totalIngested} total so far · click again to continue back to ${h(n.oldestMessageAt)}`:void 0});return}o({title:"Refreshed from SMTP2GO",description:n?`${n.eventsFetched} events fetched · ${n.pagesFetched} pages · ${n.newActivityRows} new · ${n.suppressionsAdded} suppressed`:void 0})},v=D({mutationFn:async()=>G("POST","/api/admin/email-health/refresh",{}).then(a=>a.json()),onSuccess:a=>$(a),onError:a=>o({title:"Refresh failed",description:a==null?void 0:a.message,variant:"destructive"})}),f=D({mutationFn:async a=>G("POST","/api/admin/email-health/refresh",{full:!0,reset:(a==null?void 0:a.reset)===!0}).then(r=>r.json()),onSuccess:a=>$(a,{backfill:!0}),onError:a=>o({title:"Backfill failed",description:a==null?void 0:a.message,variant:"destructive"})}),w=v.isPending||f.isPending,s=l==null?void 0:l.backfill,t=l==null?void 0:l.stats,q=(d==null?void 0:d.total)??0,O=Math.max(1,Math.ceil(q/E)),te=p.useMemo(()=>{const a=(t==null?void 0:t.byType)??{},r=a.delivered??0,n=r||0,m=C=>n>0?`${(C/n*100).toFixed(1)}%`:"â",j=(t==null?void 0:t.campaignAttributed)??0,c=(t==null?void 0:t.total)??0,N=c>0?`${(j/c*100).toFixed(0)}%`:"â";return[{key:"total",label:"Total events",value:c,sub:`${N} attributed to a broadcast â the rest are transactional or pre-attribution`,icon:ie,accent:"text-zinc-500"},{key:"delivered",label:"Delivered",value:r,icon:re,accent:"text-emerald-600"},{key:"open",label:"Unique opens",value:(t==null?void 0:t.uniqueOpens)??0,sub:`${m((t==null?void 0:t.uniqueOpens)??0)} of delivered`,icon:he,accent:"text-blue-600"},{key:"click",label:"Unique clicks",value:(t==null?void 0:t.uniqueClicks)??0,sub:`${m((t==null?void 0:t.uniqueClicks)??0)} of delivered`,icon:xe,accent:"text-indigo-600"},{key:"soft_bounce",label:"Soft bounces",value:a.soft_bounce??0,icon:de,accent:"text-amber-600"},{key:"hard_bounce",label:"Hard bounces",value:a.hard_bounce??0,sub:"auto-suppressed",icon:be,accent:"text-red-600"},{key:"spam_complaint",label:"Spam complaints",value:a.spam_complaint??0,sub:"auto-suppressed",icon:Q,accent:"text-red-600"},{key:"unsubscribe",label:"Unsubscribes",value:a.unsubscribe??0,icon:Q,accent:"text-orange-600"}]},[t]),S=(F=l==null?void 0:l.webhooks)==null?void 0:F.smtp2go_events,R=()=>{J(A.trim()),y(0)},_=a=>`px-2.5 py-1 rounded-full text-xs font-medium border transition-colors ${a?"bg-[var(--admin-primary-blue)] border-[var(--admin-primary-blue)] text-white":"bg-white border-[var(--admin-border)] admin-muted hover:border-[var(--admin-border-dark)]"}`;return e.jsx(le,{children:e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"admin-title",children:"Email Health & Deliverability"}),e.jsx("p",{className:"admin-muted mt-1",children:"SMTP2GO email activity â delivery, engagement, bounces & spam. SMS is tracked separately."}),e.jsx("p",{className:"text-xs text-amber-700 mt-2 max-w-3xl",children:"Open reporting is directional, not an exact audience count: privacy proxies (especially Apple Mail) and blocked images can create false opens or hide real ones. Before a broadcast, confirm readiness for the branded SMTP2GO redirect, sender DNS authentication, webhook ingestion, and one-click unsubscribe; after launch, use unique clicks and attributed sessions as stronger signals."})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(g,{onClick:()=>f.mutate(void 0),disabled:w||(s==null?void 0:s.complete),"data-testid":"button-backfill-email-health",className:"admin-btn-outline flex items-center gap-2",title:s!=null&&s.complete?"Full history already ingested. Use âRestart backfillâ to walk it again.":"Ingest the next chunk of SMTP2GO history (walks backward in time; click repeatedly until complete). The scheduler also advances this automatically.",children:[e.jsx(ce,{className:`h-4 w-4 ${f.isPending?"animate-spin":""}`}),f.isPending?"Backfillingâ¦":s!=null&&s.complete?"Backfill complete":s!=null&&s.started?"Continue backfill":"Backfill history"]}),e.jsxs(g,{onClick:()=>v.mutate(),disabled:w,"data-testid":"button-refresh-email-health",className:"admin-btn-primary-blue flex items-center gap-2",children:[e.jsx(oe,{className:`h-4 w-4 ${v.isPending?"animate-spin":""}`}
16),v.isPending?"Refreshingâ¦":"Refresh now"]})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-x-6 gap-y-1 text-xs admin-muted",children:[e.jsxs("span",{"data-testid":"text-last-pulled",children:["Last pull: ",e.jsx("span",{className:"admin-body",children:h(((I=l==null?void 0:l.cursor)==null?void 0:I.lastPulledAt)??null)})]}),e.jsxs("span",{children:["Newest event: ",e.jsx("span",{className:"admin-body",children:h(((B=l==null?void 0:l.cursor)==null?void 0:B.lastMessageAt)??null)})]}),e.jsxs("span",{children:["Live events webhook last seen:"," ",e.jsx("span",{className:"admin-body",children:h((S==null?void 0:S.lastEventAt)??null)})]}),(s==null?void 0:s.started)&&e.jsxs("span",{"data-testid":"text-backfill-status",children:["History backfill:"," ",s.complete?e.jsxs("span",{className:"admin-body",children:["complete · ",s.totalIngested.toLocaleString()," rows ingested"]}):e.jsxs("span",{className:"admin-body",children:["in progress · ",s.totalIngested.toLocaleString()," rows so far · back to ",h(s.oldestMessageAt)]}),(s.complete||s.totalIngested>0)&&e.jsx("button",{type:"button",onClick:()=>f.mutate({reset:!0}),disabled:w,"data-testid":"button-restart-backfill",className:"ml-2 underline hover:no-underline disabled:opacity-50",title:"Clear backfill progress and walk the full history again from the newest end",children:"Restart backfill"})]})]}),e.jsx("div",{className:"admin-card !p-4","data-testid":"bookmobile-cutover-status",children:e.jsxs("div",{className:"flex flex-wrap items-center gap-x-5 gap-y-1 text-sm",children:[e.jsx("strong",{children:"Bookmobile signup cutover"}),e.jsxs("span",{children:["Owner: ",e.jsx("span",{className:"admin-body",children:(i==null?void 0:i.confirmationOwner)??"â"})]}),e.jsxs("span",{children:["Contract: ",e.jsx("span",{className:"admin-body",children:(i==null?void 0:i.contractVersion)??"â"})]}),e.jsxs("span",{className:(H=i==null?void 0:i.legacyContractTelemetry)!=null&&H.totalCount?"text-amber-700":"admin-muted",children:["Legacy callers: ",((z=i==null?void 0:i.legacyContractTelemetry)==null?void 0:z.totalCount)??0]}),e.jsxs("span",{className:i!=null&&i.productionSendEnabled?"text-emerald-700":"text-amber-700",children:["Production send: ",i!=null&&i.productionSendEnabled?"enabled":"disabled"]})]})}),e.jsx("div",{className:"flex flex-wrap gap-2",children:Object.keys(X).map(a=>e.jsx("button",{onClick:()=>Y(a),"data-testid":`button-range-${a}`,className:`px-3 py-1.5 rounded-md text-sm font-medium border transition-colors ${u===a?"bg-[var(--admin-primary-blue)] border-[var(--admin-primary-blue)] text-white":"bg-white border-[var(--admin-border)] admin-muted hover:border-[var(--admin-border-dark)]"}`,children:X[a]},a))}),e.jsx("div",{className:"grid grid-cols-2 md:grid-cols-4 gap-3",children:te.map(a=>{const r=a.icon;return e.jsxs("div",{className:"admin-card !p-4","data-testid":`tile-${a.key}`,children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"admin-label",children:a.label}),e.jsx(r,{className:`h-4 w-4 ${a.accent}`})]}),e.jsx("div",{className:"mt-2 text-2xl font-bold admin-heading",children:ee?"â¦":a.value.toLocaleString()}),a.sub&&e.jsx("div",{className:"text-xs admin-muted mt-0.5",children:a.sub})]},a.key)})}),e.jsxs("div",{className:"admin-card !p-0 overflow-hidden",children:[e.jsxs("div",{className:"p-4 border-b border-[var(--admin-border)] flex flex-wrap items-center gap-3",children:[e.jsx("h2",{className:"admin-subheading mr-auto",children:"Activity log"}),e.jsxs("div",{className:"flex flex-1 sm:flex-none items-center gap-2",children:[e.jsxs("div",{className:"relative flex-1 sm:flex-none",children:[e.jsx(me,{className:"absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 admin-muted"}),e.jsx(ne,{value:A,onChange:a=>W(a.target.value),onKeyDown:a=>a.key==="Enter"&&R(),placeholder:"Search email or subjectâ¦","data-testid":"input-search-activity",className:"pl-8 w-full sm:w-64 text-base sm:text-sm bg-white border-[var(--admin-border)]"})]}),e.jsx(g,{onClick:R,"data-testid":"button-search-activity",className:"admin-btn-outline",children:"Search"})]})]}),e.jsxs("div",{className:"px-4 py-3 border-b border-[var(--admin-border)] flex flex-wrap gap-2",children:[e.jsx("button",{onClick:()=>{P("all"),y(0)},"data-testid":"chip-event-all",className:_(x==="all"),children:"All"}),ye.map(a=>e.jsx("button",{onClick:()=>{P(a),y(0)},"data-testid":`chip-event-${a}`,className:_(x===a),children:Z[a]??a},a))]}),e.jsx("div",{className:"admin-table-scroll",children:e.jsxs("table",{className:"w-full min-w-[720px] text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left admin-muted border-b border-[var(--admin-border)]",children:[e.jsx("th",{className:"px-4 py-2 font-medium",children:"When"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Event"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Email"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Subject"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Link"})]})}),e.jsxs("tbody",{children:[T&&e.jsx("tr",{children:e.jsx("td",{colSpan:5,className:"px-4 py-8 text-center admin-muted",children:"Loadingâ¦"})}),!T&&(((K=d==null?void 0:d.rows)==null?void 0:K.length)??0)===0&&e.jsx("tr",{children:e.jsx("td",{colSpan:5,className:"px-4 py-8 text-center admin-muted","data-testid":"text-no-activity",children:"No activity found."})}),(U=d==null?void 0:d.rows)==null?void 0:U.map(a=>e.jsxs("tr",{className:"border-b border-[var(--admin-border)] hover:bg-zinc-50","data-testid":`row-activity-${a.id}`,children:[e.jsx("td",{className:"px-4 py-2 admin-muted whitespace-nowrap",children:h(a.occurredAt)}),e.jsx("td",{className:"px-4 py-2",children:e.jsx("span",{className:"admin-body",children:Z[a.eventType]??a.eventType})}),e.jsx("td",{className:"px-4 py-2 admin-body",children:a.email}),e.jsx("td",{className:"px-4 py-2 admin-muted max-w-xs truncate",children:a.subject||"â"}),e.jsx("td",{className:"px-4 py-2 admin-muted max-w-xs truncate",children:a.linkUrl||"â"})]},a.id))]})]})}),e.jsxs("div",{className:"p-4 border-t border-[var(--admin-border)] flex items-center justify-between text-sm admin-muted",children:[e.jsxs("span",{"data-testid":"text-activity-total",children:[q.toLocaleStr
16ing()," events"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(g,{size:"sm",disabled:b===0,onClick:()=>y(a=>Math.max(0,a-1)),"data-testid":"button-prev-page",className:"admin-btn-outline !px-2 !py-2",children:e.jsx(ue,{className:"h-4 w-4"})}),e.jsxs("span",{"data-testid":"text-page-indicator",children:["Page ",b+1," of ",O]}),e.jsx(g,{size:"sm",disabled:b+1>=O,onClick:()=>y(a=>a+1),"data-testid":"button-next-page",className:"admin-btn-outline !px-2 !py-2",children:e.jsx(pe,{className:"h-4 w-4"})})]})]})]})]})})}export{Te 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.