PageSourceSearch

https://chatmerge.ai/assets/Broadcasts-DS89fz9l.js

js chatmerge.ai collected 2026-10-05 13:03:14 UTC 33,753 bytes, 2 lines download raw bytes

1import{j as e,I as ze,P as ae,h as Re,e as Ve,r as N,u as P,c as h,k as L,i as p,E as Be,J as qe,H as Oe,z as ee,a as te,t as Ue,U as Me,N as Qe,n as je}from"./index-aQ_xt8mz.js";import{s as Q}from"./Calendar.es-BIW1Hawf.js";import{i as Ke}from"./MicrosoftExcelLogo.es-BoNZwN4b.js";import{n as ve}from"./Pause.es-4RgjfQCg.js";import{m as Ne}from"./Pencil.es-CSfz6iQ6.js";import{n as Z}from"./Play.es-HNtfGyqC.js";import{n as He}from"./Trash.es-CFsXIJwf.js";import{s as K}from"./XCircle.es-DC44mQOC.js";import{Q as We}from"./QueryError-DK18iD2V.js";import{c as _e}from"./Info.es-CI0jadjD.js";import{v as se,e as Ge,b as Ye,V as Je,P as ye}from"./PhonePreview-BXZNz9Sh.js";import{n as Xe}from"./Star.es-D9KAci_8.js";import{w as Ze}from"./channelMethods-CIwDzMeI.js";import{u as et}from"./useConnectionLines-Dd9dou0U.js";import{b as tt}from"./Skeleton-CnbwKd2D.js";import"./File.es-DJw6xa4A.js";import"./Link.es-CrwP9v5F.js";import"./Phone.es-n4TpSaHE.js";function st({template:i,bindings:f,onChange:E,sampleContact:y,customFieldKeys:A=[]}){const C=i.body||i.content||"",m=se(C),j=i.headerType==="TEXT"?se(i.headerContent||""):[],g=Ge(i.components),T=(r,b)=>{const s=[...f];s[r]={...s[r]||{source:"name"},...b},E(s)},k=m.map((r,b)=>
1Ye(f[b],y)||`{{${r}}}`),S=[...Je,...A.map(r=>({value:`custom:${r}`,label:`Custom field: ${r}`}))],D=m.map((r,b)=>({n:r,b:f[b]})).filter(({b:r})=>r&&r.source!=="static"&&!(r.fallback||"").trim()),w=m.map((r,b)=>({n:r,b:f[b]})).filter(({b:r})=>r&&r.source==="static"&&!(r.value||"").trim());return!m.length&&!j.length?e.jsxs("div",{className:"rounded-lg border border-border p-3",children:[e.jsx("p",{className:"text-xs text-muted-foreground",children:"This template has no variables — everyone receives the same message."}),e.jsx("div",{className:"mt-3",children:e.jsx(ye,{headerType:i.headerType||"NONE",headerContent:i.headerContent||"",headerSample:g.header,body:C,bodySamples:[],footer:i.footer||"",buttons:(i.buttons||[]).map(r=>({...r,type:r.type==="PHONE"?"PHONE_NUMBER":r.type}))})})]}):e.jsxs("div",{className:"grid gap-4 lg:grid-cols-[minmax(0,1fr)_250px]",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium",children:"What goes in the variables"}),e.jsx("p",{className:"mt-0.5 text-xs text-muted-foreground",children:"Each one is filled per person when the broadcast runs. Meta refuses a message with an empty variable, so a contact field needs something to fall back on."})]}),m.map((r,b)=>{const s=f[b]||{source:"name"};return e.jsxs("div",{className:"rounded-lg border border-border p-2.5",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"w-10 shrink-0 font-mono text-[11px] text-muted-foreground",children:`{{${r}}}`}),e.jsx("select",{value:s.source,onChange:c=>T(b,{source:c.target.value}),"aria-label":`Source for variable ${r}`,className:"min-w-0 flex-1 rounded-lg border border-input px-2 py-1.5 text-xs",children:S.map(c=>e.jsx("option",{value:c.value,children:c.label},c.value))})]}),e.jsxs("div",{className:"mt-2 flex items-center gap-2",children:[e.jsx("span",{className:"w-10 shrink-0"}),s.source==="static"?e.jsx("input",{value:s.value||"",onChange:c=>T(b,{value:c.target.value}),placeholder:"The text everyone sees",className:"min-w-0 flex-1 rounded-lg border border-input px-2 py-1.5 text-xs"}):e.jsx("input",{value:s.fallback||"",onChange:c=>T(b,{fallback:c.target.value}),placeholder:"If we don't have it, use… (e.g. there)",className:"min-w-0 flex-1 rounded-lg border border-input px-2 py-1.5 text-xs"})]})]},r)}),(D.length>0||w.length>0)&&e.jsxs("div",{className:"flex items-start gap-2 rounded-lg border border-amber-500/40 bg-amber-500/5 p-2.5",children:[e.jsx(ze,{size:13,className:"mt-0.5 shrink-0 text-amber-700 dark:text-amber-400"}),e.jsxs("p",{className:"text-[11px] leading-snug text-amber-800 dark:text-amber-300",children:[w.length>0&&e.jsx(e.Fragment,{children:`${w.map(r=>`{{${r.n}}}`).join(", ")} has no text yet. `}),D.length>0&&e.jsx(e.Fragment,{children:`${D.map(r=>`{{${r.n}}}`).join(", ")} has no fallback, so anyone missing that field is skipped and reported as failed.`})]})]}),j.length>0&&e.jsxs("p",{className:"flex items-start gap-1.5 text-[11px] leading-snug text-muted-foreground",children:[e.jsx(_e,{size:12,className:"mt-0.5 shrink-0"}),"The header variable uses the sample value Meta approved. Per-person headers are not set here."]})]}),e.jsxs("div",{children:[e.jsx(ye,{headerType:i.headerType||"NONE",headerContent:i.headerContent||"",headerSample:g.header,body:C,bodySamples:k,footer:i.footer||"",buttons:(i.buttons||[]).map(r=>({...r,type:r.type==="PHONE"?"PHONE_NUMBER":r.type}))}),e.jsx("p",{className:"mt-2 text-center text-[11px] leading-snug text-muted-foreground",children:y!=null&&y.name?e.jsxs(e.Fragment,{children:["Filled in for ",e.jsx("span",{className:"font-medium",children:y.name}),", one of your contacts."]}):"Filled in with the sample values Meta approved."})]})]})}function at({lines:i,value:f,onChange:E,requires:y,label:A="Send from"}){if(i.length<2)return null;const C=f?i.find(m=>m.id===f):i.find(m=>m.isDefault);return e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium",children:A}),e.jsxs("p",{className:"mt-0.5 text-xs text-muted-foreground",children:["This channel is connected ",i.length," ways. Replies always answer on the line they arrived on — this is only for the messages you start."]}),e.jsx("div",{className:"mt-2 space-y-2",children:i.map(m=>{const j=y&&m.capabilities&&!m.capabilities[y],g=(C==null?void 0:C.id)===m.id;return e.jsxs("button",{type:"button",disabled:!!j||!m.connected,onClick:()=>E(m.id),"aria-pressed":g,className:`w-full rounded-lg border p-2.5 text-left transition-colors ${g?"border-primary bg-primary/5":"border-input hover:bg-accent"}
1 ${j||!m.connected?"cursor-not-allowed opacity-60 hover:bg-transparent":""}`,children:[e.jsxs("span",{className:"flex flex-wrap items-center gap-2",children:[g&&!j&&e.jsx(ae,{size:13,className:"shrink-0 text-primary"}),e.jsx("span",{className:"font-mono text-xs font-medium",children:m.display}),e.jsx("span",{className:"text-[11px] text-muted-foreground",children:m.methodLabel}),m.isDefault&&e.jsxs("span",{className:"inline-flex items-center gap-1 rounded-full border border-primary/40 px-1.5 py-0.5 text-[10px] text-primary",children:[e.jsx(Xe,{size:9})," Default"]})]}),!m.connected&&e.jsxs("span",{className:"mt-1 flex items-start gap-1 text-[11px] leading-snug text-muted-foreground",children:[e.jsx(K,{size:11,className:"mt-0.5 shrink-0"}),"Not connected right now."]}),j&&m.connected&&e.jsxs("span",{className:"mt-1 flex items-start gap-1 text-[11px] leading-snug text-destructive",children:[e.jsx(K,{size:11,className:"mt-0.5 shrink-0"}),Ze(m.method,y)]})]},m.id)})})]})}const z={DRAFT:{label:"Draft",color:"bg-muted text-foreground",icon:te},QUEUED:{label:"Scheduled",color:"bg-blue-100 text-blue-700 dark:bg-blue-950/50 dark:text-blue-300",icon:Q},SCHEDULED:{label:"Scheduled",color:"bg-blue-100 text-blue-700 dark:bg-blue-950/50 dark:text-blue-300",icon:Q},SENDING:{label:"Sending",color:"bg-yellow-100 text-yellow-700 dark:bg-yellow-950/50 dark:text-yellow-300",icon:ee},COMPLETED:{label:"Completed",color:"bg-green-100 text-green-700 dark:bg-green-950/50 dark:text-green-300",icon:ae},FAILED:{label:"Failed",color:"bg-red-100 text-red-700 dark:bg-red-950/50 dark:text-red-300",icon:K},PAUSED:{label:"Paused",color:"bg-orange-100 text-orange-700 dark:bg-orange-950/50 dark:text-orange-300",icon:ve}};function vt(){var xe,he,ge,be,fe;const i=Re(),{socket:f}=Ve(),[E,y]=N.useState(""),[A,C]=N.useState(""),[m,j]=N.useState(!1),[g,T]=N.useState(null),[k,S]=N.useState(null),[D,w]=N.useState(null),[r,b]=N.useState({}),[s,c]=N.useState({name:"",channel:"WHATSAPP",templateId:"",message:"",recipientType:"all",labelId:"",scheduledAt:"",customRecipients:"",templateVars:[],connectionId:null}),[B,H]=N.useState([]),[re,ne]=N.useState(!1),{data:W,isLoading:le,isError:de,error:we,refetch:Ce,isFetching:ke}=P({queryKey:["broadcasts",E,A],queryFn:()=>h.get("/broadcast",{params:{search:E||void 0,status:A||void 0}}).then(t=>t.data)}),{data:_}=P({queryKey:["templates","approved",s.channel],queryFn:()=>h.get("/templates",{params:{channel:s.channel,status:"APPROVED",limit:100}}).then(t=>t.data)}),{data:G}=P({queryKey:["labels"],queryFn:()=>h.get("/labels").then(t=>t.data)}),{data:Y}=P({queryKey:["contacts","preview-sample"],queryFn:()=>h.get("/contacts",{params:{limit:1}}).then(t=>t.data),staleTime:5*60*1e3}),{data:J}=P({queryKey:["broadcast-audience",s.channel],queryFn:()=>h.get("/broadcast/audience/count",{params:{channel:s.channel}}).then(t=>t.data),enabled:m}),$=J==null?void 0:J.data,{data:X,isLoading:Se}=P({queryKey:["broadcast",k],queryFn:()=>h.get(`/broadcast/${k}`).then(t=>t.data),enabled:!!k}),l=X==null?void 0:X.data,q=L({mutationFn:async t=>{const a=await h.post("/broadcast",t);return t.scheduledAt||await h.post(`/broadcast/${a.data.data.id}/start`),a},onSuccess:()=>{i.invalidateQueries({queryKey:["broadcasts"]}),j(!1),p.success(s.scheduledAt?"Broadcast scheduled":"Broadcast started")},onError:t=>{var n,u,d,x,v,V;const a=(u=(n=t.response)==null?void 0:n.data)==null?void 0:u.error,o=(V=(v=(x=(d=t.response)==null?void 0:d.data)==null?void 0:x.details)==null?void 0:v[0])==null?void 0:V.message;p.error(o||a||t.message||"Failed to create broadcast")}}),Ie=async t=>{var o,n,u;const a=(o=t.target.files)==null?void 0:o[0];if(a){ne(!0);try{const d=new FormData;d.append("file",a);const x=await h.post("/broadcast/import",d,{headers:{"Content-Type":"multipart/form-data"}});H(x.data.data.recipients),p.success(`Imported ${x.data.data.totalCount} recipients`)}catch(d){p.error(((u=(n=d.response)==null?void 0:n.data)==null?void 0:u.error)||d.message||"Failed to import file")}finally{ne(!1),t.target.value=""}}},ie=L({mutationFn:t=>h.post(`/broadcast/${t}/start`),onSuccess:()=>{i.invalidateQueries({queryKey:["broadcasts"]}),p.success("Broadcast started")},onError:t=>{var a,o;return p.error(((o=(a=t.response)==null?void 0:a.data)==null?void 0:o.error)||t.message||"Failed to start")}}),Ee=L({mutationFn:t=>h.post(`/broadcast/${t}/pause`),onSuccess:()=>{i.invalidateQueries({queryKey:["broadcasts"]}),p.success("Paused")}}),Ae=L({mutationFn:t=>h.post(`/broadcast/${t}/resume`),onSuccess:()=>{i.invalidateQueries({queryKey:["broadcasts"]}),p.success("Resumed")}}),Te=L({mutationFn:t=>h.delete(`/broadcast/${t}`),onSuccess:()=>{i.invalidateQueries({queryKey:["broadcasts"]}),p.success("Deleted")}}),R=L({mutationFn:({id:t,data:a})=>h.put(`/broadcast/${t}`,a),onSuccess:(t,a)=>{i.invalidateQueries({queryKey:["broadcasts"]}),i.invalidateQueries({queryKey:["broadcast",a.id]}),O(),p.success("Broadcast updated")},onError:t=>{var o,n,u,d,x,v;const a=(d=(u=(n=(o=t.response)==null?void 0:o.data)==null?void 0:n.details)==null?void 0:u[0])==null?void 0:d.message;p.error(a||((v=(x=t.response)==null?void 0:x.data)==null?void 0:v.error)||t.message||"Failed to update")}}),oe=()=>c({name:"",channel:"WHATSAPP",templateId:"",message:"",recipientType:"all",labelId:"",sc
1heduledAt:"",customRecipients:"",templateVars:[],connectionId:null}),O=()=>{j(!1),T(null),H([]),oe()},ce=async t=>{var a,o;try{const n=(await h.get(`/broadcast/${t}`)).data.data,u=d=>d?new Date(d).toISOString().slice(0,16):"";c({name:n.name||"",channel:n.channel||"WHATSAPP",templateId:n.templateId||"",message:n.content||"",recipientType:"keep",labelId:"",scheduledAt:u(n.scheduledAt),customRecipients:"",templateVars:Array.isArray(n.variables)?n.variables:[],connectionId:n.channelConnectionId||null}),T(t),j(!0)}catch(n){p.error(((o=(a=n.response)==null?void 0:a.data)==null?void 0:o.error)||"Failed to load broadcast")}};N.useEffect(()=>{if(!f)return;const t=a=>{b(o=>({...o,[a.broadcastId]:a})),(a.status==="COMPLETED"||a.status==="FAILED"||a.status==="CANCELLED")&&i.invalidateQueries({queryKey:["broadcasts"]})};return f.on("broadcast:progress",t),()=>{f.off("broadcast:progress",t)}},[f,i]),N.useEffect(()=>Be("broadcasts",[{id:"broadcasts-new",title:"New broadcast",subtitle:"Broadcasts",icon:ee,keywords:"campaign send bulk message",run:()=>j(!0)}]),[]);const me=(W==null?void 0:W.data)||[],{forChannel:De}=et(),$e=De(s.channel),ue=(_==null?void 0:_.data)||[],I=ue.find(t=>t.id===s.templateId),U=(xe=Y==null?void 0:Y.data)==null?void 0:xe[0],Fe=Object.keys((U==null?void 0:U.customFields)||{}),F=se((I==null?void 0:I.body)||(I==null?void 0:I.content)||"").length;N.useEffect(()=>{c(t=>{if(!t.templateId)return t.templateVars.length?{...t,templateVars:[]}:t;if(t.templateVars.length===F)return t;const a=Array.from({length:F},(o,n)=>t.templateVars[n]||{source:n===0?"firstName":"static",fallback:n===0?"there":"",value:""});return{...t,templateVars:a}})},[s.templateId,F]);const pe=(G==null?void 0:G.data)||[],Pe=t=>{const a=r[t.id],o=(a==null?void 0:a.sent)??t.sentCount,n=(a==null?void 0:a.failed)??t.failedCount,u=(a==null?void 0:a.total)??t.totalRecipients;return u===0?0:Math.round((o+n)/u*100)},M=t=>{const a=r[t.id];return{sent:(a==null?void 0:a.sent)??t.sentCount,failed:(a==null?void 0:a.failed)??t.failedCount,total:(a==null?void 0:a.total)??t.totalRecipients}},Le=async t=>{if(t.preventDefault(),q.isPending||R.isPending)return;if(s.templateId&&F>0){const u=Array.from({length:F},(d,x)=>({n:x+1,b:s.templateVars[x]})).filter(({b:d})=>!d||d.source==="static"&&!(d.value||"").trim());if(u.length){p.error(`Nothing to put in ${u.map(d=>`{{${d.n}}}`).join(", ")} — Meta rejects a message with an empty variable, so no one would receive this.`);return}}let a=[],o,n=!1;if(!s.templateId&&!s.message.trim()){p.error("Write the message, or choose a template.");return}if(g&&s.recipientType==="keep"){R.mutate({id:g,data:{name:s.name,channel:s.channel,templateId:s.templateId||null,content:s.message,variables:s.templateId?s.templateVars:void 0,channelConnectionId:s.connectionId,scheduledAt:s.scheduledAt?new Date(s.scheduledAt).toISOString():null}});return}if(s.recipientType==="all"){if($&&$.reachable===0){p.error(`No contacts can be reached on ${s.channel}`);return}n=!0}else if(s.recipientType==="import"){if(B.length===0){p.error("Please import a recipients file first");return}a=B}else if(s.recipientType==="custom"){const u=s.customRecipients.split(`
2`).map(d=>d.trim()).filter(Boolean);if(u.length===0){p.error("Please enter at least one phone number");return}a=u.map(d=>({phoneNumber:d}))}else if(s.recipientType==="label"){if(!s.labelId){p.error("Please select a label");return}const u=pe.find(d=>d.id===s.labelId);o=u?[u.name]:[]}if(g){R.mutate({id:g,data:{name:s.name,channel:s.channel,templateId:s.templateId||null,content:s.message,variables:s.templateId?s.templateVars:void 0,channelConnectionId:s.connectionId,recipients:o||n?void 0:a,labelFilter:o,audience:n?"all":void 0,scheduledAt:s.scheduledAt?new Date(s.scheduledAt).toISOString():null}});return}q.mutate({name:s.name,channel:s.channel,templateId:s.templateId||void 0,content:s.message||void 0,variables:s.templateId?s.templateVars:void 0,channelConnectionId:s.connectionId,recipients:n?void 0:a,labelFilter:o,audience:n?"all":void 0,scheduledAt:s.scheduledAt?new Date(s.scheduledAt).toISOString():void 0})};return e.jsxs("div",{className:"flex h-full flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between border-b border-border px-6 py-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl font-semibold",children:"Broadcasts"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Send bulk messages to contacts"})]}),e.jsxs("button",{onClick:()=>{T(null),oe(),H([]),j(!0)},className:"flex items-center gap-1.5 rounded-lg bg-primary px-3 py-2 text-sm text-primary-foreground hover:bg-primary/90",children:[e.jsx(qe,{size:16})," New Broadcast"]})]}),e.jsxs("div",{className:"flex items-center gap-3 border-b border-border px-6 py-3",children:[e.jsxs("div",{className:"relative flex-1 max-w-md",children:[e.jsx(Oe,{size:16,className:"absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"}),e.jsx("input",{type:"text",value:E,onChange:t=>y(t.target.value),placeholder:"Search broadcasts...",className:"w-full rounded-lg border border-input py-2 pl-9 pr-3 text-sm focus:border-primary"})]}),e.jsxs("select",{value:A,onChange:t=>C(t.target.value),className:"rounded-lg border border-input px-3 py-2 text-sm",children:[e.jsx("option",{value:"",children:"All Status"}),Object.entries(z).map(([t,a])=>e.jsx("option",{value:t,children:a.label},t))]})]}),e.jsx("div",{className:"flex-1 overflow-auto p-6",children:e.jsxs("div",{className:"space-y-3",children:[me.map(t=>{var n,u,d;const a=((n=z[t.status])==null?void 0:n.icon)||te,o=Pe(t);return e.jsxs("div",{className:"rounded-lg border border-border bg-card p-4 hover:shadow-sm transition-shadow",children:[e.jsxs("div",{className:"flex items-start justify-between",children:[e.jsxs("div",{className:"flex-1 cursor-pointer",onClick:()=>S(t.id),title:"View details",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h3",{className:"text-sm font-semibold hover:underline",children:t.name}),e.jsxs("span",{className:`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] font-medium ${(u=z[t.status])==null?void 0:u.color}`,children:[e.jsx(a,{size:10})," ",(d=z[t.status])==null?void 0:d.label]}),(t.status==="SENDING"||r[t.id])&&e.jsxs("span",{className:"inline-flex items-center gap-1 text-[10px] text-primary animate-pulse",children:[e.jsx(Ue,{size:9,className:"animate-spin"})," Live"]}),e.jsx("span",{className:"rounded bg-accent px-1.5 py-0.5 text-[10px]",children:t.channel})]}),t.templateName&&e.jsxs("p",{className:"mt-1 text-xs text-muted-foreground",children:["Template: ",t.templateName]})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx("button",{onClick:()=>S(t.id),className:"rounded-md p-1.5 hover:bg-accent",title:"View details",children:e.jsx(Me,{size:14})}),(t.status==="DRAFT"||t.status==="QUEUED")&&e.jsx("button",{onClick:()=>ce(t.id),className:"rounded-md p-1.5 hover:bg-accent",title:"Edit",children:e.jsx(Ne,{size:14})}),(t.status==="DRAFT"||t.status==="QUEUED")&&(D===`send:${t.id}`?e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsxs("span",{className:"text-[11px] text-foreground",children:["Send to ",M(t).total,"?"]}),e.jsx("button",{onClick:()=>{ie.mutate(t.id),w(null)},className:"rounded px-2 py-0.5 text-[11px] bg-primary text-primary-foreground",children:"Send"}),e.jsx("button",{onClick:()=>w(null),className:"rounded px-2 py-0.5 text-[11px] border border-input hover:bg-accent",children:"No"})]}):e.jsx("button",{onClick:()=>w(`send:${t.id}`),className:"rounded-md p-1.5 hover:bg-accent text-primary",title:`Send to all ${M(t).total} recipients now. It cannot be recalled, and on WhatsApp each conversation it opens is billable.`,children:e.jsx(Z,{size:14})})),t.status==="SENDING"&&e.jsx("button",{onClick:()=>Ee.mutate(t.id),className:"rounded-md p-1.5 hover:bg-accent",title:"Pause",children:e.jsx(ve,{size:14})}),t.status==="PAUSED"&&e.jsx("button",{onClick:()=>Ae.mutate(t.id),className:"rounded-md p-1.5 hover:bg-accent",title:"Resume",children:e.jsx(Z,{size:14})}),["DRAFT","COMPLETED","FAILED","CANCELLED"].includes(t.status)&&(D===`del:${t.id}`?e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx("span",{className:"text-[11px] text-destructive",children:"Delete?"}),e.jsx("button",{onClick:()=>{Te.mutate(t.id),w(null)},className:"rounded px-2 py-0.5 text-[11px] bg-destructive text-destructive-foreground",children:"Yes"}),e.jsx("button",{onClick:()=>w(null),className:"rounded px-2 py-0.5 text-[11px] border border-input hover:bg-accent",children:"No"})]}):e.jsx("button",{onClick:()=>w(`del:${t.id}`),className:"rounded-md p-1.5 hover:bg-accent text-destructive",title:t.status==="COMPLETED"?"Delete this broadcast and its delivery record. Messages already sent are not recalled.":"Delete this broadcast. This cannot be undone.",children:e.jsx(He,{size:14})}))]})]}),(()=>{const{sent:x,failed:v,total:V}=M(t);return e.jsxs("div",{className:"mt-3",children:[e.jsxs("div",{className:"flex items-center justify-between text-xs text-muted-foreground mb-1",children:[e.jsxs("span",{children:[e.jsx(Qe,{size:12,className:"inline mr-1"}),V," recipients"]}),e.jsxs("span",{className:"font-medium text-foreground",children:[x," / ",V," sent (",o,"%)"]})]}),e.jsx("div",{className:"h-2 w-full rounded-full bg-muted overflow-hidden",children:e.jsx("div",{className:"h-full rounded-full bg-primary transition-all duration-300",style:{width:`${o}%`}})}),t.status==="SENDING"&&e.jsxs("p",{className:"mt-1 text-[10px] text-primary animate-pulse",children:["Sending… ",x," sent",v>0?`, ${v} failed`:""]})]})})(),(()=>{const{sent:x,failed:v}=M(t);return e.jsxs("div",{className:"mt-3 flex gap-4 text-xs",children:[e.jsxs("span",{className:"text-muted-foreground",children:["Sent: ",e.jsx("strong",{className:"text-foreground",children:x})]}),e.jsxs("span",{className:"text-muted-foreground",children:["Delivered: ",e.jsx("strong",{className:"text-green-700 dark:text-green-400",children:t.deliveredCount})]}),v>0&&e.jsxs("span",{className:"text-muted-foreground",children:["Failed: ",e.jsx("strong",{className:"text-red-600 dark:text-red-400",children:v})]})]})})(),t.scheduledAt&&(t.status==="SCHEDULED"||t.status==="QUEUED")&&e.jsxs("p",{className:"mt-2 text-xs text-muted-foreground",children:[e.jsx(Q,{size:12,className:"inline mr-1"}
2),"Scheduled: ",new Date(t.scheduledAt).toLocaleString()]})]},t.id)}),le&&e.jsx(tt,{rows:5,what:"your broadcasts"}),de&&e.jsx(We,{error:we,onRetry:()=>Ce(),busy:ke,what:"Your broadcasts"}),!le&&!de&&me.length===0&&e.jsxs("div",{className:"flex flex-col items-center py-12",children:[e.jsx(ee,{size:48,className:"mb-3 text-muted-foreground"}),e.jsx("p",{className:"text-muted-foreground",children:"No broadcasts yet"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Create your first broadcast campaign"})]})]})}),m&&e.jsxs("div",{className:"fixed inset-0 z-50 flex items-center justify-center",children:[e.jsx("div",{className:"fixed inset-0 bg-black/50",onClick:O}),e.jsxs("div",{className:`relative z-50 w-full ${F>0?"max-w-3xl":"max-w-lg"} rounded-xl border border-border bg-background p-6 shadow-xl max-h-[90dvh] overflow-y-auto`,children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsx("h2",{className:"text-lg font-semibold",children:g?"Edit Broadcast":"Create Broadcast"}),e.jsx("button",{onClick:O,className:"rounded-md p-1 hover:bg-accent",children:e.jsx(je,{size:18})})]}),e.jsxs("form",{onSubmit:Le,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium",children:"Campaign Name *"}),e.jsx("input",{value:s.name,onChange:t=>c({...s,name:t.target.value}),required:!0,className:"mt-1 w-full rounded-lg border border-input px-3 py-2 text-sm focus:border-primary",placeholder:"e.g., Summer Sale"})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium",children:"Channel"}),e.jsxs("select",{value:s.channel,onChange:t=>c({...s,channel:t.target.value,templateId:""}),className:"mt-1 w-full rounded-lg border border-input px-3 py-2 text-sm",children:[e.jsx("option",{value:"WHATSAPP",children:"WhatsApp"}),e.jsx("option",{value:"TELEGRAM",children:"Telegram"})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium",children:"Template"}),e.jsxs("select",{value:s.templateId,onChange:t=>c({...s,templateId:t.target.value}),className:"mt-1 w-full rounded-lg border border-input px-3 py-2 text-sm",children:[e.jsx("option",{value:"",children:"Custom message"}),ue.map(t=>e.jsx("option",{value:t.id,children:t.name},t.id))]})]})]}),e.jsx(at,{lines:$e,value:s.connectionId,onChange:t=>c({...s,connectionId:t}),requires:s.templateId?"templates":"broadcasts"}),s.templateId&&I&&e.jsx(st,{template:I,bindings:s.templateVars,onChange:t=>c({...s,templateVars:t}),sampleContact:U,customFieldKeys:Fe}),!s.templateId&&e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium",children:"Message *"}),e.jsx("textarea",{value:s.message,onChange:t=>c({...s,message:t.target.value}),rows:4,className:"mt-1 w-full rounded-lg border border-input px-3 py-2 text-sm focus:border-primary",placeholder:"Type your broadcast message..."})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium",children:"Recipients"}),e.jsxs("div",{className:"mt-2 space-y-2",children:[g&&e.jsxs("label",{className:"flex items-center gap-2 cursor-pointer",children:[e.jsx("input",{type:"radio",name:"recipientType",value:"keep",checked:s.recipientType==="keep",onChange:()=>c({...s,recipientType:"keep"})}),e.jsxs("span",{className:"text-sm",children:["Keep current recipients ",e.jsx("span",{className:"text-xs text-muted-foreground",children:"(pick below to replace)"})]})]}),e.jsxs("label",{className:"flex items-center gap-2 cursor-pointer",children:[e.jsx("input",{type:"radio",name:"recipientType",value:"all",checked:s.recipientType==="all",onChange:()=>c({...s,recipientType:"all"})}),e.jsxs("span",{className:"text-sm",children:["All contacts",$&&e.jsxs("span",{className:"ml-1.5 text-xs text-muted-foreground",children:["— ",$.reachable.toLocaleString()," reachable on ",s.channel.toLowerCase(),$.unreachable>0&&`, ${$.unreachable.toLocaleString()} without an address`]})]})]}),e.jsxs("label",{className:"flex items-center gap-2 cursor-pointer",children:[e.jsx("input",{type:"radio",name:"recipientType",value:"label",checked:s.recipientType==="label",onCh
2ange:()=>c({...s,recipientType:"label"})}),e.jsx("span",{className:"text-sm",children:"By label"})]}),s.recipientType==="label"&&e.jsxs("select",{value:s.labelId,onChange:t=>c({...s,labelId:t.target.value}),className:"ml-6 rounded-lg border border-input px-3 py-2 text-sm",children:[e.jsx("option",{value:"",children:"Select label"}),pe.map(t=>e.jsx("option",{value:t.id,children:t.name},t.id))]}),e.jsxs("label",{className:"flex items-center gap-2 cursor-pointer",children:[e.jsx("input",{type:"radio",name:"recipientType",value:"custom",checked:s.recipientType==="custom",onChange:()=>c({...s,recipientType:"custom"})}),e.jsx("span",{className:"text-sm",children:"Custom list"})]}),s.recipientType==="custom"&&e.jsx("textarea",{value:s.customRecipients,onChange:t=>c({...s,customRecipients:t.target.value}),rows:3,placeholder:"One phone number per line",className:"ml-6 w-[calc(100%-1.5rem)] rounded-lg border border-input px-3 py-2 text-sm focus:border-primary"}),e.jsxs("label",{className:"flex items-center gap-2 cursor-pointer",children:[e.jsx("input",{type:"radio",name:"recipientType",value:"import",checked:s.recipientType==="import",onChange:()=>c({...s,recipientType:"import"})}),e.jsx("span",{className:"text-sm",children:"Import from Excel/CSV"})]}),s.recipientType==="import"&&e.jsxs("div",{className:"ml-6 space-y-2",children:[e.jsxs("label",{className:"flex items-center gap-2 cursor-pointer rounded-lg border border-dashed border-input px-4 py-3 hover:bg-accent/50 transition-colors",children:[e.jsx(Ke,{size:18,className:"text-muted-foreground"}),e.jsx("span",{className:"text-sm text-muted-foreground",children:re?"Importing...":"Click to upload .xlsx, .xls, or .csv"}),e.jsx("input",{type:"file",accept:".xlsx,.xls,.csv",onChange:Ie,className:"hidden",disabled:re})]}),B.length>0&&e.jsxs("div",{className:"rounded-lg bg-green-50 dark:bg-green-900/20 px-3 py-2 text-xs text-green-700 dark:text-green-300",children:[e.jsx("strong",{children:B.length})," recipients imported successfully"]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:'File must have a column named "phone", "mobile", or "number". Optional: "name", "label".'})]})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium",children:"Schedule (optional)"}),e.jsx("input",{type:"datetime-local",value:s.scheduledAt,onChange:t=>c({...s,scheduledAt:t.target.value}),className:"mt-1 w-full rounded-lg border border-input px-3 py-2 text-sm focus:border-primary"}),e.jsx("p",{className:"mt-1 text-xs text-muted-foreground",children:"Leave empty to send immediately"})]}),e.jsxs("div",{className:"flex justify-end gap-2 pt-2",children:[e.jsx("button",{type:"button",onClick:O,className:"rounded-lg border border-input px-4 py-2 text-sm hover:bg-accent",children:"Cancel"}),e.jsx("button",{type:"submit",disabled:q.isPending||R.isPending,className:"rounded-lg bg-primary px-4 py-2 text-sm text-primary-foreground hover:bg-primary/90 disabled:opacity-50",children:g?R.isPending?"Saving...":"Save changes":q.isPending?"Creating...":s.scheduledAt?"Schedule":"Send Now"})]})]})]})]}),k&&e.jsxs("div",{className:"fixed inset-0 z-50 flex items-center justify-center p-4",children:[e.jsx("div",{className:"fixed inset-0 bg-black/50",onClick:()=>S(null)}),e.jsxs("div",{className:"relative z-50 flex max-h-[90dvh] w-full max-w-lg flex-col rounded-xl border border-border bg-background shadow-xl",children:[e.jsxs("div",{className:"flex items-start justify-between border-b border-border px-6 py-4",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h2",{className:"truncate text-lg font-semibold",children:(l==null?void 0:l.name)||"Broadcast"}),l&&e.jsx("span",{className:`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] font-medium ${((he=z[l.status])==null?void 0:he.color)||""}`,children:((ge=z[l.status])==null?void 0:ge.label)||l.status})]}),l&&e.jsxs("p",{className:"mt-0.5 text-xs text-muted-foreground",children:[l.channel," • Created ",new Date(l.createdAt).toLocaleString()]})]}),e.jsx("button",{onClick:()=>S(null),className:"rounded-md p-1 hover:bg-accent",children:e.jsx(je,{size:18})})]}),Se||!l?e.jsx("div",{className:"flex justify-center py-16",children:e.jsx("div",{className:"h-8 w-8 animate-spin rounded-full border-2 border-primary border-t-transparent"})}):e.jsxs("div",{className:"flex-1 space-y-4 overflow-y-auto px-6 py-4",children:[e.jsxs("div",{children:[e.jsx("p",{className:"mb-1 text-xs font-medium text-muted-foreground",children:"Message"}),l.templateName&&e.jsxs("p",{className:"mb-1 text-xs text-primary",children:["Template: ",l.templateName]}),e.jsx("p",{className:"whitespace-pre-wrap rounded-lg bg-muted/50 p-3 text-sm",children:l.content||e.jsx("span",{className:"text-muted-foreground",children:"— no text (template message) —"})})]}),e.jsxs("div",{className:"grid grid-cols-4 gap-2 text-center",children:[e.jsxs("div",{className:"rounded-lg border border-border p-2",children:[e.jsx("p",{className:"text-lg font-semibold",children:l.totalRecipients}),e.jsx("p",{className:"text-[10px] text-muted-foreground",children:"Total"})]}),e.jsxs("div",{className:"rounded-lg border border-border p-2",children:[e.jsx("p",{className:"text-lg font-semibold",children:l.sentCount}),e.jsx("p",{className:"text-[10px] text-muted-foreground",children:"Sent"})]}),e.jsxs("div",{className:"rounded-lg border border-border p-2",children:[e.jsx("p",{className:"text-lg font-semibold text-green-700 dark:text-green-400",children:l.deliveredCount}),e.jsx("p",{className:"text-[10px] text-muted-foreground",children:"Delivered"})]}),e.jsxs("div",{className:"rounded-lg border border-border p-2",children:[e.jsx("p",{className:"text-lg font-semibold text-red-600 dark:text-red-400",children:l.failedCount}),e.jsx("p",{className:"text-[10px] text-muted-foreground",children:"Failed"})]})]}),l.scheduledAt&&e.jsxs("p",{className:"text-xs text-muted-foreground",children:[e.jsx(Q,{size:12,className:"mr-1 inline"}
2),"Scheduled: ",new Date(l.scheduledAt).toLocaleString()]}),e.jsxs("div",{children:[e.jsxs("p",{className:"mb-2 text-xs font-medium text-muted-foreground",children:["Recipients (",((be=l.recipients)==null?void 0:be.length)||0,l.totalRecipients>(((fe=l.recipients)==null?void 0:fe.length)||0)?` of ${l.totalRecipients} shown`:"",")"]}),e.jsxs("div",{className:"divide-y divide-border rounded-lg border border-border",children:[(l.recipients||[]).map(t=>{const a=(t.status||"PENDING").toUpperCase(),o=a==="SENT"||a==="DELIVERED"||a==="READ",n=a==="FAILED";return e.jsxs("div",{className:"flex items-center justify-between gap-2 px-3 py-2",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"truncate text-sm",children:t.name||t.phoneNumber||t.telegramId||"Unknown"}),(t.phoneNumber||t.telegramId)&&t.name&&e.jsx("p",{className:"truncate text-[11px] text-muted-foreground",children:t.phoneNumber||t.telegramId}),n&&t.error&&e.jsx("p",{className:"truncate text-[11px] text-red-600 dark:text-red-400",children:t.error})]}),e.jsxs("span",{className:`inline-flex shrink-0 items-center gap-1 text-xs font-medium ${o?"text-green-700 dark:text-green-400":n?"text-red-600 dark:text-red-400":"text-muted-foreground"}`,children:[o?e.jsx(ae,{size:13}):n?e.jsx(K,{size:13}):e.jsx(te,{size:13}),a.charAt(0)+a.slice(1).toLowerCase()]})]},t.id)}),(!l.recipients||l.recipients.length===0)&&e.jsx("p",{className:"px-3 py-4 text-center text-sm text-muted-foreground",children:"No recipients"})]})]})]}),l&&(l.status==="DRAFT"||l.status==="QUEUED")&&e.jsxs("div",{className:"flex justify-end gap-2 border-t border-border px-6 py-3",children:[e.jsxs("button",{onClick:()=>{const t=k;S(null),ce(t)},className:"flex items-center gap-1.5 rounded-lg border border-input px-3 py-2 text-sm hover:bg-accent",children:[e.jsx(Ne,{size:14})," Edit"]}),e.jsxs("button",{onClick:()=>{ie.mutate(k),S(null)},className:"flex items-center gap-1.5 rounded-lg bg-primary px-3 py-2 text-sm text-primary-foreground hover:bg-primary/90",children:[e.jsx(Z,{size:14})," Send Now"]})]})]})]})]})}export{vt 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.