1import{v as ie,as as le,o as v,A as B,al as J,a4 as O,a5 as $,U as b,j as e,C as k,G as u,X as U,$ as V,E as X,a0 as ce,aa as de,D as ne,L as pe,B as y,ae as ue,aP as me,W as he,F,T as D,a2 as ge,aL as fe,am as ye}from"./index-dE8a1mPK.js";import{A as xe}from"./AccountPicker-M2R_QSt1.js";import{a as ve,c as H,f as we}from"./draftStorage-BA_l97c0.js";import{u as je}from"./useDraftAutosave-BRfAYMIp.js";import{I as be}from"./IconArrowLeft-cAVPTBNq.js";import{I as Ie}from"./IconDeviceFloppy-DgEyIcAH.js";import{S as N}from"./Select-DebRlW67.js";import{S as Z}from"./Switch-Bm85N10X.js";import{I as Se}from"./IconUserPlus-zPvIjFMg.js";import{I as ke}from"./IconHeart-CFNXoJCy.js";import{I as Ce}from"./IconMessageReply-B0QqDoCF.js";import{I as _e}from"./IconAt-o0rM45xa.js";import{I as ze}from"./IconPlus-B47PY1MC.js";import{I as Ae}from"./IconArrowDown-DMfekS2f.js";import{I as ee}from"./IconTrash-DIXYcrq7.js";import{N as Ee}from"./NumberInput-EbCp_odp.js";import{T as Te}from"./Textarea-BtbUvWWM.js";import{F as Me}from"./FileButton-CykIGdWi.js";import{I as Re}from"./Image-Ia4YApv6.js";import"./Checkbox-CVTqs_Fd.js";import"./InputsGroupFieldset-C0syow2C.js";import"./CheckIcon-DkMc45y2.js";import"./OptionsDropdown-wonErrz5.js";import"./get-env-uyVen0u2.js";/** 2 * @license @tabler/icons-react v3.43.0 - MIT 3 * 4 * This source code is licensed under the MIT license. 5 * See the LICENSE file in the root directory of this source tree. 6 */const De=[["path",{d:"M15 7l-6.5 6.5a1.5 1.5 0 0 0 3 3l6.5 -6.5a3 3 0 0 0 -6 -6l-6.5 6.5a4.5 4.5 0 0 0 9 9l6.5 -6.5",key:"svg-0"}]],te=ie("outline","paperclip","Paperclip",De),P="campaign:sequence",G=[{value:"follow",label:"Follow target",icon:e.jsx(Se,{size:14}),needsContent:!1},{value:"like",label:"Like target's latest tweet",icon:e.jsx(ke,{size:14}),needsContent:!1},{value:"reply",label:"Reply to target's latest tweet",icon:e.jsx(Ce,{size:14}),needsContent:!0},{value:"post-mention",label:"Post a tweet @-mentioning target",icon:e.jsx(_e,{size:14}),needsContent:!0},{value:"send-dm",label:"Send DM",icon:e.jsx(me,{size:14}),needsContent:!0}],ae=[{value:"always_run",label:"Always run this step"},{value:"no_dm_reply",label:"Skip if they already replied to my DM"},{value:"no_at_reply",label:"Skip if they already @-replied to my posts"},{value:"no_followback",label:"Skip if they already followed me back"},{value:"no_like_on_my_tweet",label:"Skip if they already liked one of my tweets"}],Pe={type:"follow",delayHours:0,content:"",skipIf:"always_run",media:[]},Ue=4,K={image:5*1024*1024,gif:15*1024*1024,video:512*1024*1024},Fe=["reply","post-mention","send-dm"],qe="image/png,image/jpeg,image/webp,image/gif,video/mp4,video/quicktime,video/webm";function L(n,t=[]){return n==="send-dm"||t.some(o=>String(o.mime||"").startsWith("video"))?1:Ue}const Le=n=>String(n).startsWith("video/")?"video":n==="image/gif"?"gif":"image";function Ne(n){return!n.type.startsWith("image/")||n.type==="image/gif"||n.size<=K.image?Promise.resolve(n):new Promise((t,o)=>{const i=new window.Image,c=URL.createObjectURL(n);i.onerror=()=>{URL.revokeObjectURL(c),o(new Error(`Could not read ${n.name}`))},i.onload=()=>{const g=Math.min(1,2048/Math.max(i.width,i.height)),m=document.createElement("canvas");m.width=Math.round(i.width*g),m.height=Math.round(i.height*g),m.getContext("2d").drawImage(i,0,0,m.width,m.height),URL.revokeObjectURL(c),m.toBlob(x=>x?t(new File([x],n.name.replace(/\.\w+$/,"")+".jpg",{type:"image/jpeg"})):o(new Error("Could not compress image")),"image/jpeg",.85)},i.src=c})}async function Oe(n){const t=await Ne(n),o=Le(t.type);if(t.size>K[o])throw new Error(`${t.name} is ${(t.size/1048576).toFixed(1)} MB â X caps ${o} at ${K[o]/1048576} MB`);const{path:i,uploadUrl:c}=await b.mediaAssetUrl({mime:t.type,sizeBytes:t.size});return await b.uploadToStorage(c,t),{storagePath:i,mime:t.type,name:t.name||null,previewUrl:URL.createObjectURL(t)}}function Be(n){return n==="send-dm"?"dm":n==="reply"?"reply":"post"}const W=[{type:"follow",delayHours:0,content:"",skipIf:"always_run",media:[]},{type:"like",delayHours:24,content:"",skipIf:"always_run",media:[]},{type:"reply",delayHours:48,content:"Just saw your post on {{recent_topic}} â that resonated.",skipIf:"always_run",media:[]},{type:"send-dm",delayHours:72,content:"Hey {{name}}, loved your take on {{recent_topic}}. Quick question â open to a 15-min chat?",skipIf:"always_run",media:[]},{type:"post-mention",delayHours:168,content:"still curious about your thoughts on this @{{handle}}
6 â",skipIf:"no_dm_reply",media:[]}];function yt(){const n=le(),t=v.useMemo(()=>ve(P),[]),o=(t==null?void 0:t.value)||{},[i,c]=v.useState(o.name||""),[g,m]=v.useState(o.accountIds||[]),[x,h]=v.useState(o.accountGroup||""),[C,_]=v.useState(o.listId||null),[l,w]=v.useState(o.steps&&o.steps.length?o.steps:W),[z,q]=v.useState(!!o.approvalMode),[E,T]=v.useState(o.stopOnReply!==void 0?o.stopOnReply:!0);je(P,{name:i,accountIds:g,accountGroup:x,listId:C,steps:l,approvalMode:z,stopOnReply:E},{isEmpty:a=>!a.name.trim()&&!a.accountIds.length&&!a.listId&&!a.approvalMode&&JSON.stringify(a.steps)===JSON.stringify(W)&&a.stopOnReply===!0});const{data:s}=B({queryKey:["accounts"],queryFn:()=>b.listAccounts()}),{data:d}=B({queryKey:["lists"],queryFn:()=>b.listLists()}),{data:j}=B({queryKey:["templates-all"],queryFn:()=>b.listTemplates()}),I=()=>({listId:C,sequenceSteps:l,stopOnReply:E}),A=J({mutationFn:async()=>b.createCampaign({type:"sequence",name:i,accountIds:g,accountGroup:x,approvalMode:z,config:I()}),onSuccess:a=>{$("Sequence saved as draft"),H(P),n(`/campaigns/${a.id}`)},onError:a=>O(a)}),M=J({mutationFn:async()=>{const a=await b.createCampaign({type:"sequence",name:i,accountIds:g,accountGroup:x,approvalMode:z,config:I()}
6),r=await b.startCampaign(a.id);return{id:a.id,...r}},onSuccess:a=>{$(`Sequence started â ${a.enrolled||0} prospects enrolled`),H(P),n(`/campaigns/${a.id}`)},onError:a=>O(a)}),R=l.length&&l.every(a=>{const r=G.find(p=>p.value===a.type);return!(!r||r.needsContent&&!(a.content&&a.content.trim()))}),f=i.trim()&&g.length>0&&C&&R;function oe(a,r){w(l.map((p,S)=>S===a?{...p,...r}:p))}function Y(a){const r=[...l];r.splice(a,0,{...Pe,delayHours:a===0?0:24}),w(r)}function re(a){l.length!==1&&w(l.filter((r,p)=>p!==a))}function Q(a,r){const p=a+r;if(p<0||p>=l.length)return;const S=[...l];[S[a],S[p]]=[S[p],S[a]],w(S)}return((s==null?void 0:s.accounts)||[]).filter(a=>a.status==="active"&&a.executionMode==="cookie"),e.jsxs(k,{gap:"md",children:[e.jsxs(u,{children:[e.jsx(U,{variant:"subtle",leftSection:e.jsx(be,{size:14}),onClick:()=>n("/campaigns"),children:"Back"}),e.jsx(V,{order:2,children:"New Sequence campaign"}),(t==null?void 0:t.ts)&&e.jsxs(X,{color:"blue",variant:"light",leftSection:e.jsx(Ie,{size:12}),children:["Resumed from ",we(t.ts)]})]}),e.jsx(ce,{color:"gray",variant:"light",icon:e.jsx(de,{size:16}),children:"Each prospect runs through these steps in order. Delays are measured from when the previous step's action was enqueued. If a step's skip-if condition is true at evaluation time, that step is skipped and the next step's delay starts from the previous successful action. Sequence is snapshotted on enrollment â editing the steps later won't affect already-enrolled prospects."}),e.jsx(ne,{withBorder:!0,p:"lg",children:e.jsxs(k,{gap:"md",children:[e.jsx(pe,{label:"Campaign name",placeholder:"Q2 Shopify operator drip",value:i,onChange:a=>c(a.currentTarget.value),required:!0}),e.jsx(xe,{label:"Accounts to enroll from",description:"Pick one or more. Enrollments load-balance across the pool â each prospect locks to one account for their whole sequence so the prospect always hears from the same handle, but the campaign as a whole distributes load.",value:g,group:x,onGroupChange:h,onChange:m,mode:"multi"}),e.jsx("div",{children:e.jsx(N,{label:"Prospect list",description:"Every handle in this list gets enrolled on start",data:((d==null?void 0:d.lists)||[]).map(a=>({value:a.id,label:`${a.name} · ${a.handleCount||0} handles`})),value:C,onChange:_,placeholder:"Pick a list",searchable:!0,required:!0})}),e.jsx(Z,{label:"Stop on reply",description:"End the whole sequence the moment they reply via DM or @-mention. Default ON â best practice for cold outreach. Turn off if you specifically want to keep nudging past a reply.",checked:E,onChange:a=>T(a.currentTarget.checked)}),e.jsx(Z,{label:"Approval mode",description:"When ON, every step's action queues as awaiting-approval instead of auto-executing.",checked:z,onChange:a=>q(a.currentTarget.checked)})]})}),e.jsxs(k,{gap:0,children:[e.jsx(u,{justify:"space-between",mb:"xs",children:e.jsxs(V,{order:4,children:["Flow (",l.length," ",l.length===1?"step":"steps",")"]})}),e.jsxs(y,{style:{display:"flex",flexDirection:"column",alignItems:"center"},children:[e.jsx(We,{}),l.map((a,r)=>e.jsxs(He,{children:[e.jsx(se,{label:r===0?"on enrollment":`wait ${a.delayHours}h`,onInsertBefore:()=>Y(r)}),e.jsx(Ge,{index:r,step:a,total:l.length,templates:(j==null?void 0:j.templates)||[],onChange:p=>oe(r,p),onRemove:()=>re(r),onMoveUp:()=>Q(r,-1),onMoveDown:()=>Q(r,1)})]},r)),e.jsx(se,{label:"end",onInsertBefore:()=>Y(l.length),terminal:!0})]})]}),e.jsxs(u,{justify:"flex-end",mt:"md",gap:"xs",children:[(t==null?void 0:t.ts)&&e.jsx(U,{variant:"subtle",color:"gray",onClick:()=>{H(P),c(""),m([]),_(null),w(W),q(!1),T(!0),$("Draft discarded")},children:"Discard draft"}),e.jsx(U,{variant:"subtle",onClick:()=>A.mutate(),loading:A.isPending,disabled:!f,children:"Save as draft"}),e.jsx(U,{leftSection:e.jsx(ue,{size:14}),onClick:()=>M.mutate(),loading:M.isPending,disabled:!f,children:"Create + start"})]})]})}const $e=520;function He({children:n}){return e.jsx(y,{style:{display:"flex",flexDirection:"column",alignItems:"center",width:"100%"},children:n})}function We(){return e.jsx(y,{style:{width:"auto",padding:"6px 14px",borderRadius:999,background:"var(--mantine-color-text)",color:"var(--mantine-color-body)",fontSize:11,fontWeight:700,letterSpacing:.5,textTransform:"uppercase"},children:"start"})}function se({label:n,onInsertBefore:t,terminal:o}){return e.jsxs(y,{style:{display:"flex",flexDirection:"column",alignItems:"center",position:"relative",padding:"4px 0"},children:[e.jsx(y,{style:{width:2,height:18,background:"var(--mantine-color-gray-3)"}}),e.jsx(he,{label:"Insert step here",withArrow:!0,position:"right",children:e.jsx(F,{variant:"default",size:"xs",radius:"xl",onClick:t,"aria-label":"Insert step",style:{position:"relative",zIndex:1,width:20,height:20,minWidth:20},children:e.jsx(ze,{size:11})})}),e.jsx(y,{style:{width:2,height:8,background:"var(--mantine-color-gray-3)"}}),e.jsx(X,{size:"xs",variant:"light",color:o?"gray":"blue",style:{textTransform:"none"},children:n}),!o&&e.jsxs(e.Fragment,{children:[e.jsx(y,{style:{width:2,height:8,background:"var(--mantine-color-gray-3)"}}),e.jsx(y,{style:{width:0,height:0,borderLeft:"5px solid transparent",borderRight:"5px solid transparent",borderTop:"6px solid var(--mantine-color-gray-3)"}})]})]})}function Ge({index:n,step:t,total:o,templates:i,onChange:c,onRemove:g,onMoveUp:m,onMoveDown:x}){var T;const h=G.find(s=>
6s.value===t.type),C=Fe.includes(t.type),_=(i||[]).filter(s=>s.type===Be(t.type)),[l,w]=v.useState(!1),z=s=>{const d=_.find(j=>j.id===s);d&&c({content:d.body})},q=s=>{const j=(Array.isArray(s)?s:[s]).filter(Boolean);if(!j.length)return;const I=t.media||[],A=L(t.type,I),M=A-I.length;if(M<=0){ye.show({color:"orange",message:A===1?"One attachment on this step":`Max ${A} attachments per step`});return}const R=j.slice(0,M);if(R.some(f=>String(f.type||"").startsWith("video"))&&(R.length>1||I.length)){O("X won't mix video with other media â attach the video on its own");return}w(!0),Promise.all(R.map(Oe)).then(f=>c({media:[...I,...f]})).catch(f=>O((f==null?void 0:f.message)||"Upload failed")).finally(()=>w(!1))},E=s=>{const d=[...t.media||[]];d.splice(s,1),c({media:d})};return e.jsxs(ne,{withBorder:!0,p:"md",w:$e,maw:"100%",children:[e.jsxs(u,{justify:"space-between",align:"flex-start",wrap:"nowrap",mb:"xs",children:[e.jsxs(u,{gap:"xs",wrap:"nowrap",children:[e.jsx(y,{style:{width:28,height:28,borderRadius:999,background:"var(--mantine-color-text)",color:"var(--mantine-color-body)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:13,fontWeight:700},children:n+1}),e.jsxs(k,{gap:0,children:[e.jsxs(u,{gap:6,children:[h==null?void 0:h.icon,e.jsx(D,{fw:600,size:"sm",children:(h==null?void 0:h.label)||t.type})]}),e.jsx(D,{size:"xs",c:"dimmed",children:n===0?"Runs immediately on enrollment":`Waits ${t.delayHours}h after step ${n}`})]})]}),e.jsxs(u,{gap:4,children:[e.jsx(F,{variant:"subtle",disabled:n===0,onClick:m,"aria-label":"Move up",children:e.jsx(ge,{size:14})}),e.jsx(F,{variant:"subtle",disabled:n===o-1,onClick:x,"aria-label":"Move down",children:e.jsx(Ae,{size:14})}),e.jsx(F,{variant:"subtle",color:"red",disabled:o===1,onClick:g,"aria-label":"Remove step",children:e.jsx(ee,{size:14})})]})]}),e.jsxs(k,{gap:"xs",children:[e.jsxs(u,{grow:!0,align:"flex-end",children:[e.jsx(N,{label:"Action",data:G.map(s=>({value:s.value,label:s.label})),value:t.type,onChange:s=>c({type:s}),size:"xs"}),n>0&&e.jsx(Ee,{label:"Delay after previous step",description:"Hours",value:t.delayHours,onChange:s=>c({delayHours:Math.max(0,Math.min(720,Number(s)||0))}),min:0,max:720,size:"xs"})]}),(h==null?void 0:h.needsContent)&&e.jsxs(k,{gap:6,children:[e.jsxs(u,{justify:"space-between",align:"flex-end",gap:"xs",children:[e.jsx(D,{size:"xs",fw:500,children:"Message"}),_.length>0&&e.jsx(N,{placeholder:"Insert from template",data:_.map(s=>({value:s.id,label:s.name})),value:null,onChange:s=>s&&z(s),size:"xs",w:220,leftSection:e.jsx(fe,{size:12}),clearable:!1,searchable:!0})]}),e.jsx(Te,{description:t.type==="post-mention"?"Use {{handle}} to insert their @. Vars from the list pre-fill at send time.":"Vars: {{name}}, {{handle}}, {{recent_topic}}, {{last_tweet}}, {{follower_count}}, {{location}}.",value:t.content,onChange:s=>c({content:s.currentTarget.value}),autosize:!0,minRows:2,maxLength:t.type==="send-dm"?1500:280}),C&&e.jsxs(k,{gap:6,children:[e.jsxs(u,{justify:"space-between",children:[e.jsxs(u,{gap:6,children:[e.jsx(te,{size:12}),e.jsxs(D,{size:"xs",c:"dimmed",children:["Attachments ",(t.media||[]).length,"/",L(t.type,t.media)]})]}),e.jsx(Me,{onChange:q,accept:qe,multiple:L(t.type,t.media)>1,children:s=>e.jsx(U,{...s,size:"xs",variant:"default",leftSection:e.jsx(te,{size:12}),loading:l,disabled:l||(t.media||[]).length>=L(t.type,t.media),children:"Attach image / video / gif"})})]}),(t.media||[]).length>0&&e.jsx(u,{gap:"xs",wrap:"wrap",children:(t.media||[]).map((s,d)=>e.jsxs(y,{style:{position:"relative",width:80,height:80,borderRadius:4,overflow:"hidden",border:"1px solid var(--mantine-color-gray-3)"},children:[String(s.mime||"").startsWith("video")?e.jsx("video",{src:s.previewUrl||s.dataUrl,muted:!0,playsInline:!0,preload:"metadata",style:{width:"100%",height:"100%",objectFit:"cover",background:"#000"}}):e.jsx(Re,{src:s.previewUrl||s.dataUrl,alt:s.name||"",w:80,h:80,fit:"cover"}),e.jsx(F,{size:"xs",variant:"filled",color:"dark",onClick:()=>E(d),style:{position:"absolute",top:2,right:2},"aria-label":"Remove attachment",children:e.jsx(ee,{size:10})})]},d))}),e.jsx(D,{size:"xs",c:"dimmed",children:"Stored once, then uploaded to X fresh from the assigned account at dispatch â mediaIds are per-account and expire in ~24h, so a multi-week drip needs the re-upload. Oversized photos are downscaled for you."})]})]}
6),e.jsx(N,{label:"Skip this step ifâ¦",description:"Condition is checked at the moment this step becomes due. If true, this step is skipped and the next step starts its delay from the last successful action.",data:ae,value:t.skipIf,onChange:s=>c({skipIf:s}),size:"xs"}),t.skipIf!=="always_run"&&e.jsxs(X,{variant:"light",color:"grape",size:"xs",w:"fit-content",children:["Conditional · ",(T=ae.find(s=>s.value===t.skipIf))==null?void 0:T.label]})]})]})}export{yt 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.