PageSourceSearch

https://mobilingo.ai/assets/chunks/chunk-BDbTf76m.js

js mobilingo.ai collected 2026-09-24 10:49:57 UTC 33,916 bytes, 2 lines download raw bytes

1import{b as F,g as K,aK as _e,j as e,r as c,n as be,aP as ve,h as C,M as H,T as N,B as A,aQ as ye,I as je,_ as we,m as z,ag as q,a1 as Q,$ as Se,ay as Ne,as as Ae,U as ke,w as ee}from"../entries/pages_index.DwH1fEUc.js";import{S as Ce}from"./chunk-B5przYSq.js";import{D as J}from"./chunk-CIaLFCQO.js";import{T as De}from"./chunk-Ct4DSnPm.js";import{u as Ee}from"./chunk-Dk9tB3xN.js";import{R as Te,a as Pe,X as Ie,Y as te,T as Re}from"./chunk-Di_31zli.js";import{L as Ue,a as Le}from"./chunk-C456wRSt.js";import{T as ce}from"./chunk-Bi54BlzQ.js";import{O as $e}from"./chunk-SMnF6rVS.js";import{F as Oe}from"./chunk-qBSQuzB3.js";import"./chunk-BugajZ7n.js";/* empty css              *//* empty css              *//* empty css              *//* empty css              *//* empty css              */import"./chunk-BOx6UWN_.js";const B=F("aldoo-ads"),R=F("crud"),Me=F("api-keys"),Fe=F("permissions"),P=K(R,"AdCampaign"),E=K(R,"Ad"),I=K(R,"AdAsset"),Ke=K(R,"AdAccount"),oe=async t=>B({stats:t}),Be=async t=>B({series:t}),W=async t=>B({list_accounts:t?{expand:t}:{}}),Ge=async({api_url:t,access_key:a,name:n})=>B({connect_account:{api_url:t,access_key:a,name:n}}),Ve=async(t="Aldoo Ads access key")=>{const a=_e();if(!a?._id)return{error:"not_authenticated"};const n=await Me({create:{targetUserId:a._id,issuedBy:a._id,description:t}});return n?.result&&await Fe({grant_permission:{user:a._id,permissions:["ads:read"]}}),n},He=async()=>(await R({get:{model:"APIKey",match:{},sort:{createdAt:-1},itemsPerPage:50}}))?.data||[],X=(t,a=2500)=>{const{socket:n}=Ee("ads"),s=c.useRef(null);c.useEffect(()=>{if(!n||!t)return;const o=()=>{clearTimeout(s.current),s.current=setTimeout(t,a)};return n.on("ads:kpi",o),()=>{n.off("ads:kpi",o),clearTimeout(s.current)}},[n,t,a])},ze=t=>e.jsx("span",{className:"text-admin_primary font-medium hover:underline cursor-pointer",children:t}),le=({name:t,isOn:a,onToggle:n})=>e.jsxs("div",{className:"flex items-center gap-3",children:[n&&e.jsx("span",{onClick:s=>s.stopPropagation(),className:"shrink-0",children:e.jsx(De,{variant:"admin",isOn:a,onChange:s=>n(s)})}),e.jsx("span",{className:"text-admin_primary font-medium hover:underline cursor-pointer",children:t})]}),M=(t,a)=>be({variant:"admin",title:`Delete ${t}?`,message:`This removes "${t}" and everything under it. This cannot be undone.`,confirmText:"Delete",cancelText:"Cancel",onConfirm:a}),de=({id:t})=>e.jsxs("button",{className:"inline-flex items-center gap-1 text-xs font-mono text-admin_text_secondary hover:text-admin_text",onClick:a=>{a.stopPropagation(),navigator.clipboard?.writeText(t),C({message:"Ad id copied",className:"bg-admin_success text-admin_text_inv"})},title:`Copy id ${t}`,children:[e.jsx(ve,{className:"w-4 h-4"}),String(t).slice(-6)]}),me=t=>t?t.type==="custom"&&t.range?{from:t.range.startDate,to:t.range.endDate}:t.type==="preset"&&t.value?.days?{from:new Date(Date.now()-t.value.days*24*60*60*1e3).toISOString()}:{}:{},O=t=>!Array.isArray(t)||!t.length?"$0":t.map(a=>`${a.currency==="usd"?"$":a.currency.toUpperCase()+" "}${a.amount}`).join(" · "),Y=(t,a={created:-1})=>t?.field?{[t.field]:t.order==="desc"?-1:1}:a,We=(t,a)=>{if(!a?.field)return t;const n=a.order==="desc"?-1:1;return[...t].sort((s,o)=>{const h=s?.[a.field],u=o?.[a.field];return h==null&&u==null?0:h==null?1:u==null?-1:h<u?-n:h>u?n:0})},ae=t=>Array.isArray(t)?t.reduce((a,n)=>a+(n.amount||0),0):0,ue=async({rows:t,level:a,account:n,range:s,params:o})=>{const h=t.map(l=>l._id);let u={};h.length&&(u=(await oe({level:a,ids:h,account:n,...me(s)}).catch(()=>null))?.stats||{});const b=t.map(l=>{const x=u[l._id]||{},i=x.touch==="both";return{...l,_stats:x,_kpi_impressions:x.impressions??0,_kpi_clicks:x.clicks??0,_kpi_ctr:x.ctr??0,_kpi_signups:i?x.last?.signups??0:x.signups??0,_kpi_revenue:ae(i?x.last?.revenue:x.revenue)}}),g=We(b,o.sort),m=(o.page-1)*o.itemsPerPage;return{data:g.slice(m,m+o.itemsPerPage),total:g.length}},pe=(t,a)=>{if(!t)return"…";if(t.touch==="both"&&a==="signups"){const n=t.first?.signups??0,s=t.last?.signups??0;return`${n} / ${s}`}return t[a]??0},U=[{key:"impressions",label:"Impr.",color:"#2563eb",axis:"left",fmt:t=>t},{key:"clicks",label:"Clicks",color:"#dc2626",axis:"left",fmt:t=>t},{key:"ctr",label:"CTR",color:"#d97706",axis:"right",fmt:t=>`${t}%`},{key:"signups",label:"Signups",color:"#059669",axis:"left",fmt:t=>t},{key:"revenue",label:"Revenue",color:"#7c3aed",axis:"right",fmt:t=>`$${t}`}],qe=new Set(["impressions","clicks"]),se=t=>{const[,a,n]=String(t).split("-");return`${a}/${n}`},Z=({level:t,id:a,account:n,range:s})=>{const[o,h]=c.useState(null),[u,b]=c.useState([]),[g,m]=c.useState(qe),[l,x]=c.useState(0);c.useEffect(()=>{if(!a)return;let r=!0;const d={level:t,id:a,account:n,...me(s)};return(async()=>{const[f,j]=await Promise.all([oe(d).catch(()=>null),Be(d).catch(()=>null)]);r&&(h(f?.result?f:null),b(j?.result?j.series||[]:[]))})(),()=>{r=!1}},[t,a,n,s,l]),X(c.useCallback(()=>x(r=>r+1),[]));const i=r=>m(d=>{const f=new Set(d);return f.has(r)?f.delete(r):f.add(r),f}),_=r=>o?r.key==="revenue"?o.touch==="both"?`${O(o.first?.revenue)} / ${O(o.last?.revenue)}`:O(o.revenue):r.key==="ctr"?`${o.ctr??0}%`:r.key==="signups"?pe(o,"signups"):o[r.key]??0:"—",w=U.some(r=>r.axis==="right"&&g.has(r.key));return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx("div",{className:"grid grid-cols-2 md:grid-cols-5 ga
1p-2",children:U.map(r=>{const d=g.has(r.key);return e.jsxs("button",{onClick:()=>i(r.key),className:"text-left rounded-lg p-4 border transition-colors",style:{background:d?r.color:"transparent",borderColor:r.color,color:d?"#fff":"var(--admin-text, #888)"},title:d?"Hide from chart":"Show in chart",children:[e.jsxs("div",{className:"text-xs opacity-80 flex items-center gap-1",children:[e.jsx("span",{className:"inline-block w-2 h-2 rounded-full",style:{background:d?"#fff":r.color}}),r.label,o?.touch==="both"&&(r.key==="signups"||r.key==="revenue")?" (first / last)":""]}),e.jsx("div",{className:"text-2xl font-bold mt-1",children:_(r)})]},r.key)})}),e.jsx("div",{className:"bg-paper border border-admin_bordered rounded-lg p-3",style:{height:280},children:e.jsx(Te,{width:"100%",height:"100%",children:e.jsxs(Ue,{data:u,margin:{top:8,right:16,left:0,bottom:0},children:[e.jsx(Pe,{strokeDasharray:"3 3",stroke:"#e5e7eb",vertical:!1}),e.jsx(Ie,{dataKey:"date",tickFormatter:se,tick:{fontSize:11},minTickGap:24}),e.jsx(te,{yAxisId:"left",tick:{fontSize:11},width:44,allowDecimals:!1}),w&&e.jsx(te,{yAxisId:"right",orientation:"right",tick:{fontSize:11},width:44}),e.jsx(Re,{labelFormatter:se,formatter:(r,d)=>{const f=U.find(j=>j.label===d);return[f?f.fmt(r):r,d]}}),U.filter(r=>g.has(r.key)).map(r=>e.jsx(Le,{yAxisId:r.axis==="right"&&w?"right":"left",type:"monotone",dataKey:r.key,name:r.label,stroke:r.color,strokeWidth:2,dot:!1,isAnimationActive:!1},r.key))]})})})]})},ne=["display","position","top","right","bottom","left","z-index","flex-direction","flex-wrap","flex-grow","flex-shrink","flex-basis","align-items","align-self","justify-content","gap","row-gap","column-gap","grid-template-columns","grid-template-rows","width","min-width","max-width","height","min-height","max-height","margin-top","margin-right","margin-bottom","margin-left","padding-top","padding-right","padding-bottom","padding-left","border-top-width","border-right-width","border-bottom-width","border-left-width","border-top-style","border-right-style","border-bottom-style","border-left-style","border-top-color","border-right-color","border-bottom-color","border-left-color","border-top-left-radius","border-top-right-radius","border-bottom-left-radius","border-bottom-right-radius","background-color","background-image","background-size","background-position","background-repeat","color","font-family","font-size","font-weight","font-style","line-height","letter-spacing","text-align","text-decoration-line","text-transform","white-space","opacity","overflow-x","overflow-y","box-shadow","cursor","object-fit","object-position","transform","transition-property"];function Qe(t){if(typeof window>"u"||!t)return t;const a=document.createElement("div");a.style.cssText="position:fixed;left:-10000px;top:0;width:900px;visibility:hidden;pointer-events:none;",a.innerHTML=t,document.body.appendChild(a);const n=new Map,s=o=>{if(n.has(o))return n.get(o);const h=document.createElement(o);a.appendChild(h);const u=window.getComputedStyle(h),b={};for(const g of ne)b[g]=u.getPropertyValue(g);return h.remove(),n.set(o,b),b};try{const o=h=>{if(h.nodeType!==1)return;const u=window.getComputedStyle(h),b=s(h.tagName.toLowerCase()),g=h.getAttribute("style")||"",m=[];for(const l of ne){const x=u.getPropertyValue(l);!x||x===b[l]||g.includes(l)||m.push(`${l}:${x}`)}m.length&&h.setAttribute("style",g?`${g};${m.join(";")}`:m.join(";")),h.removeAttribute("class");for(const l of[...h.children])o(l)};for(const h of[...a.children])o(h);return a.innerHTML}finally{a.remove()}}const Je=(t,a={})=>(t||"").replace(/\{\{\s*([\w.-]+)\s*\}\}/g,(n,s)=>a[s]===void 0||a[s]===null?"":String(a[s])),Xe=({ad:t,asset:a,onClose:n,onSaved:s})=>{const[o,h]=c.useState(a?.name||""),[u,b]=c.useState(a?.html||""),[g,m]=c.useState(a?.enabled!==!1),[l,x]=c.useState(a?.inline_styles===!0),[i,_]=c.useState(!1),[w,r]=c.useState(!1),d=Object.keys(t?.variables||{}).map(S=>({key:S,type:"text"})),f=()=>M(a?.name||"asset",async()=>{await I.SoftDelete({_id:a._id}),C({message:"Asset deleted",className:"bg-admin_success text-admin_text_inv"}),s?.()}),j=async()=>
1{if(!o.trim()){C({message:"Asset needs a name",className:"bg-admin_error text-admin_text_inv"});return}r(!0);try{const S=l?Qe(u):u,T={ad:t._id,name:o.trim(),html:S,enabled:g,inline_styles:l};a?._id?await I.Update({_id:a._id,...T}):await I.Create(T),C({message:"Asset saved",className:"bg-admin_success text-admin_text_inv"}),s?.()}catch(S){console.error("Asset save failed",S),C({message:"Failed to save asset",className:"bg-admin_error text-admin_text_inv"})}finally{r(!1)}};return e.jsxs(H,{isOpen:!0,onClose:n,closeOnEscape:!0,variant:"admin_compact",title:a?._id?"Edit asset":"New asset",children:[e.jsxs("div",{className:"p-5 flex flex-col gap-4",children:[e.jsx("label",{className:"text-sm text-admin_text_secondary",children:"Name"}),e.jsx("input",{className:"border border-admin_bordered rounded-lg px-3 py-2 bg-transparent",value:o,onChange:S=>h(S.target.value),placeholder:"home-page banner"}),e.jsxs("label",{className:"flex items-center gap-2 text-sm",children:[e.jsx("input",{type:"checkbox",checked:g,onChange:S=>m(S.target.checked)}),"Enabled (served when the ad + campaign are active)"]}),e.jsxs("label",{className:"flex items-start gap-2 text-sm",children:[e.jsx("input",{type:"checkbox",className:"mt-1",checked:l,onChange:S=>x(S.target.checked)}),e.jsxs("span",{children:["Inline Styles",e.jsx("span",{className:"block text-xs text-admin_text_secondary",children:"Off: serve the HTML as authored (the target site provides the classes, e.g. Tailwind). On: bake computed styles into the markup so it renders standalone — only for sites without the source classes."})]})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(N,{variant:"admin_h4",children:"Banner HTML"}),e.jsx(A,{variant:"admin_secondary",onClick:()=>_(!0),children:u?"Edit HTML":"Add HTML"})]}),u&&e.jsx("div",{className:"border border-admin_bordered rounded-lg p-4 bg-white",children:e.jsx("div",{dangerouslySetInnerHTML:{__html:Je(u,t?.variables)}})}),e.jsxs("div",{className:"flex justify-between gap-2 pt-2",children:[a?._id?e.jsx(A,{variant:"admin_error",onClick:f,children:"Delete"}):e.jsx("span",{}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(A,{variant:"admin_secondary",onClick:n,children:"Cancel"}),e.jsx(A,{variant:"admin_primary",onClick:j,disabled:w,children:w?"Saving…":"Save asset"})]})]})]}),i&&e.jsx(H,{isOpen:!0,onClose:()=>_(!1),closeOnEscape:!0,variant:"admin_fullScreen",size:"fullscreen",styleOverrides:{container:"bg-admin_canvas w-full h-full overflow-y-auto",contentWrapper:"overflow-y-auto h-[calc(100vh-80px)]"},children:e.jsx(ye,{title:o||"Ad asset",content:u,save:S=>{b(S),_(!1)},variables:{data:d}})})]})};function Ye({isOpen:t,onSelect:a,onClose:n}){const[s,o]=c.useState(""),[h,u]=c.useState([]),[b,g]=c.useState(!1),m=c.useRef(null);c.useEffect(()=>{t&&(g(!0),(async()=>{const i=await I.Get({match:{deleted:{$ne:!0}},page:1,itemsPerPage:500,sort:{created:-1}}).catch(()=>null);u(i?.data||[]),g(!1)})(),m.current&&m.current.focus())},[t]);const l=h.filter(i=>(i?.name||"").toLowerCase().includes(s.toLowerCase())),x=i=>{a(i),n()};return e.jsx(H,{isOpen:t,onClose:n,variant:"admin_compact",closeOnEscape:!0,className:"w-[600px] h-[80vh] p-6",children:e.jsxs("div",{className:"flex flex-col text-admin_text h-full",children:[e.jsxs("div",{className:"flex-shrink-0 px-3",children:[e.jsx(N,{component:"h2",variant:"admin_h4",className:"text-center mb-4",children:"Load an existing asset"}),e.jsx(je,{variant:"admin",ref:m,value:s,onChange:i=>o(i.target.value),placeholder:"Search assets by name"})]}),e.jsx("div",{className:"h-[55vh] overflow-y-auto scrollbar-thin scrollbar-thumb-neutral_1 scrollbar-track-admin_paper mt-4",children:b?e.jsx(N,{variant:"admin_body1_dim",className:"text-center",children:"Loading…"}):l.length?l.map(i=>e.jsxs("div",{className:"flex justify-between items-center border-b border-admin_bordered hover:bg-admin_canvas cursor-pointer p-3",onClick:()=>x(i),children:[e.jsxs("div",{className:"flex flex-row items-center min-w-0",children:[e.jsx("div",{className:"w-12 h-12 flex items-center justify-center bg-admin_neutral_2 rounded-md mr-4 shrink-0",children:(i.name||"?").charAt(0).toUpperCase()}),e.jsxs("div",{className:"flex flex-col min-w-0",children:[e.jsx(N,{variant:"admin_label",className:"mb-0 truncate",children:i.name}),e.jsxs(N,{variant:"admin_txt1_dim",className:"truncate",children:[i.created?new Date(i.created).toLocaleDateString():"",i.enabled===!1?" · disabled":""]})]})]}),e.jsx(A,{children:e.jsx(we,{className:"w-6 h-6"})})]},i._id)):e.jsx(N,{variant:"admin_body1_dim",className:"text-center",children:"No assets found."})})]})})}const Ze=t=>Object.entries(t||{}).map(([a,n])=>({key:a,value:String(n??"")})),et=t=>(Array.isArray(t)?t:[]).reduce((a,n)=>{const s=(n?.key||"").trim();return s&&(a[s]=n.value??""),a},{}),tt=({account:t,isRemote:a,campaign:n,ad:s,onDeleted:o})=>{const[h,u]=c.useState(s.cta_url||""),[b,g]=c.useState(Ze(s.variables)),[m,l]=c.useState(s.status),[x,i]=c.useState(null),[_,w]=c.useState(!1),[r,d
1]=c.useState(0),[f,j]=c.useState({type:"preset",value:{days:30}}),[S,T]=c.useState(a?"assets":"config"),G=a?[{value:"assets",label:"Assets"}]:[{value:"config",label:"Configuration"},{value:"assets",label:"Assets"}],p=c.useCallback(async v=>{const D=await I.Get({match:{ad:s._id,deleted:{$ne:!0}},page:v.page,itemsPerPage:v.itemsPerPage,sort:Y(v.sort)});return{data:D?.data||[],total:D?.totalItems||D?.total||0}},[s,r]),y=async()=>{const v=et(b);await E.Update({_id:s._id,cta_url:h,variables:v}),s.cta_url=h,s.variables=v,C({message:"Ad saved",className:"bg-admin_success text-admin_text_inv"})},k=async()=>{const v=m==="active"?"stopped":"active";await E.Update({_id:s._id,status:v}),l(v),s.status=v},V=()=>M(s.name,async()=>{await E.SoftDelete({_id:s._id}),C({message:"Ad deleted",className:"bg-admin_success text-admin_text_inv"}),o?.()}),ge=v=>M(v.name,async()=>{await I.SoftDelete({_id:v._id}),C({message:"Asset deleted",className:"bg-admin_success text-admin_text_inv"}),d(D=>D+1)});return e.jsxs("div",{className:"flex flex-col gap-5",children:[e.jsxs("div",{className:"flex items-center justify-between flex-wrap gap-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(N,{variant:"admin_h3",children:s.name}),e.jsx(de,{id:s._id})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(J,{showLabel:!1,value:f,onChange:j,variant:"admin",localUserPreferencesKey:"admin.ads.ad.dateFilter"}),!a&&e.jsxs(e.Fragment,{children:[e.jsx(A,{variant:"admin_secondary",onClick:k,children:m==="active"?"Stop ad":"Start ad"}),e.jsxs(A,{variant:"admin_error",onClick:V,children:[e.jsx(z,{className:"w-5 h-5 mr-1"})," Delete"]})]})]})]}),e.jsx(Z,{level:"ad",id:s._id,account:a?t._id:void 0,range:f}),e.jsx(ce,{variant:"admin",tabs:G,value:S,onChange:T}),S==="config"&&!a&&e.jsxs("div",{className:"bg-paper border border-admin_bordered rounded-lg p-4 flex flex-col gap-4 max-w-3xl",children:[e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("label",{className:"text-sm font-semibold text-admin_text",children:"CTA URL"}),e.jsx("span",{className:"text-xs text-admin_text_secondary",children:"Where a click ultimately lands — utm params are appended automatically."}),e.jsx("input",{className:"border border-admin_bordered rounded-lg px-3 py-2 bg-transparent mt-1",value:h,onChange:v=>u(v.target.value),placeholder:"https://transfer.aldoo.com/"})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("label",{className:"text-sm font-semibold text-admin_text",children:"Variables"}),e.jsxs("span",{className:"text-xs text-admin_text_secondary",children:["Key/value pairs substituted into asset ","{{placeholders}}"," at serve time."]}),e.jsx("div",{className:"mt-1",children:e.jsx($e,{field:{id:"variables",label:"Variables"},value:s.variables||{},onChange:g,showInfo:!1})})]}),e.jsx("div",{children:e.jsx(A,{variant:"admin_primary",onClick:y,children:"Save ad"})})]}),S==="assets"&&e.jsxs("div",{className:"flex flex-col gap-3",children:[!a&&e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsxs(A,{variant:"admin_secondary",onClick:()=>w(!0),children:[e.jsx(Oe,{className:"w-5 h-5 mr-1"})," Load Asset"]}),e.jsxs(A,{variant:"admin_primary",onClick:()=>i({}),children:[e.jsx(q,{className:"w-5 h-5 mr-1"})," New Asset"]})]}),e.jsx(Q,{apiMethod:p,itemsPerPage:25,onRowClick:v=>{a||i(v)},renders:[{id:"name",title:"Asset",sortable:!0,render:ze},{id:"enabled",title:"Enabled",sortable:!0,render:v=>e.jsx("span",{className:v?"text-admin_success font-semibold":"text-admin_text_secondary",children:v?"yes":"no"})},{id:"created",title:"Created",sortable:!0,render:v=>v?new Date(v).toLocaleDateString():""},...a?[]:[{id:"_delete",title:"",render:(v,D)=>e.jsx("button",{className:"text-admin_error hover:opacity-70",title:"Delete asset",onClick:fe=>{fe.stopPropagation(),ge(D)},children:e.jsx(z,{className:"w-4 h-4"})})}]]},`assets-${s._id}-${r}`)]}),x!==null&&e.jsx(Xe,{ad:s,asset:x,onClose:()=>i(null),onSaved:()=>{i(null),d(v=>v+1)}}),_&&e.jsx(Ye,{isOpen:!0,onClose:()=>w(!1),onSelect:v=>i({name:v.name,html:v.html,enabled:!0})})]})},he=()=>[{id:"_kpi_impressions",title:"Impr.",sortable:!0,render:(t,a)=>
1a?._kpi_impressions??0},{id:"_kpi_clicks",title:"Clicks",sortable:!0,render:(t,a)=>a?._kpi_clicks??0},{id:"_kpi_ctr",title:"CTR",sortable:!0,render:(t,a)=>`${a?._kpi_ctr??0}%`},{id:"_kpi_signups",title:"Signups",sortable:!0,render:(t,a)=>pe(a?._stats,"signups")},{id:"_kpi_revenue",title:"Revenue",sortable:!0,render:(t,a)=>O(a?._stats?.revenue)}],xe=t=>e.jsx("span",{className:t==="active"?"text-admin_success font-semibold":"text-admin_text_secondary",children:t}),at="/admin/ads/dashboard",L=()=>{if(typeof window>"u")return{};const t=new URLSearchParams(window.location.search);return{account:t.get("account"),campaign:t.get("campaign"),ad:t.get("ad")}},st=({account:t,campaign:a,ad:n})=>{const s=new URLSearchParams;t&&s.set("account",t),a&&s.set("campaign",a),n&&s.set("ad",n);const o=s.toString();return at+(o?`?${o}`:"")},nt=()=>{const[t,a]=c.useState([]),[n,s]=c.useState(null),[o,h]=c.useState(null),[u,b]=c.useState(null),[g,m]=c.useState(0),[l,x]=c.useState({type:"preset",value:{days:30}});X(c.useCallback(()=>m(p=>p+1),[]));const[i,_]=c.useState(L()),w=(p,y=!1)=>{if(_(p),typeof window<"u"){const k=st(p);y?window.history.replaceState({},"",k):window.history.pushState({},"",k)}};c.useEffect(()=>{const p=()=>_(L());return window.addEventListener("popstate",p),()=>window.removeEventListener("popstate",p)},[]);const r=t.find(p=>p._id===i.account)||null,d=r?.type==="remote",f=d?r._id:void 0,j=i.ad?"ad":i.campaign?"campaign":"campaigns";c.useEffect(()=>{(async()=>{const y=(await W().catch(()=>null))?.accounts||[];if(a(y),!L().account&&y.length){const k=y.find(V=>V.type==="local")||y[0];w({...L(),account:k._id},!0)}})()},[]),c.useEffect(()=>{if(!r||r.type!=="remote"){s(null);return}let p=!0;return(async()=>{const y=await W(r._id).catch(()=>null);if(p){if(y?.expanded?.error){C({message:"Connected account unreachable",className:"bg-admin_error text-admin_text_inv"}),s(null);return}s(y?.expanded||null)}})(),()=>{p=!1}},[i.account,t.length]),c.useEffect(()=>{if(!i.campaign){h(null);return}let p=!0;return(async()=>{if(d){h((n?.campaigns||[]).find(k=>k._id===i.campaign)||null);return}const y=await P.Get({match:{_id:i.campaign},page:1,itemsPerPage:1}).catch(()=>null);p&&h(y?.data?.[0]||null)})(),()=>{p=!1}},[i.campaign,d,n,g]),c.useEffect(()=>{if(!i.ad){b(null);return}let p=!0;return(async()=>{if(d){b((n?.ads||[]).find(k=>k._id===i.ad)||null);return}const y=await E.Get({match:{_id:i.ad},page:1,itemsPerPage:1}).catch(()=>null);p&&b(y?.data?.[0]||null)})(),()=>{p=!1}},[i.ad,d,n]);const S=async()=>{const p=window.prompt("Campaign name");p&&(await P.Create({account:r._id,name:p,status:"active"}),m(y=>y+1))},T=async(p,y)=>{await P.Update({_id:p._id,status:y?"active":"stopped"}),m(k=>k+1)},G=c.useCallback(async p=>{let y;return d?y=n?.campaigns||[]:r?y=(await P.Get({match:{account:r._id,deleted:{$ne:!0}},page:1,itemsPerPage:1e3,sort:Y(p.sort)}))?.data||[]:y=[],ue({rows:y,level:"campaign",account:f,range:l,params:p})},[r,d,n,g,f,l]);return r?e.jsxs("div",{className:"p-6 flex flex-col gap-5",children:[e.jsxs("div",{className:"flex items-center justify-between flex-wrap gap-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(N,{variant:"admin_h3",children:"Aldoo Ads"}),e.jsx("select",{className:"border border-admin_bordered rounded-lg px-3 py-2 bg-paper",value:r._id,onChange:p=>w({account:p.target.value}),children:t.map(p=>e.jsxs("option",{value:p._id,children:[p.name," ",p.type==="remote"?"(connected)":"(this site)"]},p._id))})]}),j==="campaigns"&&e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(J,{showLabel:!1,value:l,onChange:x,variant:"admin",localUserPreferencesKey:"admin.ads.dateFilter"}),!d&&e.jsxs(A,{variant:"admin_primary",onClick:S,children:[e.jsx(q,{className:"w-5 h-5 mr-1"})," New Campaign"]})]})]}),j!=="campaigns"&&e.jsxs("button",{className:"flex items-center gap-1 text-admin_text_secondary text-sm w-fit",onClick:()=>w(j==="ad"?{account:i.account,campaign:i.campaign}:{account:i.account}),children:[e.jsx(Se,{className:"w-4 h-4"}),j==="ad"?`Back to ${o?.name||"campaign"}`:"Back to campaigns"]}),j==="campaigns"&&e.jsxs(e.Fragment,{children:[e.jsx(Z,{level:"account",id:r._id,account:f,range:l}),e.jsx(Q,{title:"Campaigns",apiMethod:G,itemsPerPage:25,onRowClick:p=>w({account:i.account,campaign:p._id}),renders:[{id:"name",title:"Campaign",sortable:!0,render:(p,y)=>e.jsx(le,{name:p,isOn:y.status==="active",onToggle:d?void 0:k=>T(y,k)})},{id:"status",title:"Status",sortable:!0,render:xe},...he(),{id:"created",title:"Created",sortable:!0,render:p=>p?new Date(p).toLocaleDateString():""}]},`campaigns-${r._id}-${g}-${d?n?"r":"l":"x"}-${JSON.stringify(l)}`)]}),j==="campaign"&&(o?e.jsx(rt,{account:r,isRemote:d,remoteTree:n,campaign:o,onOpenAd:p=>w({account:i.account,campaign:i.campaign,ad:p._id}),onDeleted:()=>{w({account:i.account}),m(p=>p+1)}}
1):e.jsx(N,{variant:"admin_body1",children:"Loading campaign…"})),j==="ad"&&(u?e.jsx(tt,{account:r,isRemote:d,campaign:o,ad:u,onDeleted:()=>w({account:i.account,campaign:i.campaign})}):e.jsx(N,{variant:"admin_body1",children:"Loading ad…"}))]}):e.jsx("div",{className:"p-6",children:e.jsx(N,{variant:"admin_body1",children:"Loading accounts…"})})},rt=({account:t,isRemote:a,remoteTree:n,campaign:s,onOpenAd:o,onDeleted:h})=>{const[u,b]=c.useState(0),[g,m]=c.useState({type:"preset",value:{days:30}}),l=a?t._id:void 0;X(c.useCallback(()=>b(d=>d+1),[]));const x=c.useCallback(async d=>{let f;return a?f=(n?.ads||[]).filter(j=>j.campaign===s._id):f=(await E.Get({match:{campaign:s._id,deleted:{$ne:!0}},page:1,itemsPerPage:1e3,sort:Y(d.sort)}))?.data||[],ue({rows:f,level:"ad",account:l,range:g,params:d})},[s,a,n,u,l,g]),i=async()=>{const d=s.status==="active"?"stopped":"active";await P.Update({_id:s._id,status:d}),s.status=d,b(f=>f+1)},_=async()=>{const d=window.prompt("Ad name");d&&(await E.Create({campaign:s._id,name:d,status:"active",cta_url:"",variables:{}}),b(f=>f+1))},w=async(d,f)=>{await E.Update({_id:d._id,status:f?"active":"stopped"}),b(j=>j+1)},r=()=>M(s.name,async()=>{await P.SoftDelete({_id:s._id}),C({message:"Campaign deleted",className:"bg-admin_success text-admin_text_inv"}),h?.()});return e.jsxs("div",{className:"flex flex-col gap-5",children:[e.jsxs("div",{className:"flex items-center justify-between flex-wrap gap-3",children:[e.jsx(N,{variant:"admin_h3",children:s.name}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(J,{showLabel:!1,value:g,onChange:m,variant:"admin",localUserPreferencesKey:"admin.ads.campaign.dateFilter"}),!a&&e.jsxs(e.Fragment,{children:[e.jsx(A,{variant:"admin_secondary",onClick:i,children:s.status==="active"?"Stop campaign":"Start campaign"}),e.jsxs(A,{variant:"admin_primary",onClick:_,children:[e.jsx(q,{className:"w-5 h-5 mr-1"})," New Ad"]}),e.jsxs(A,{variant:"admin_error",onClick:r,children:[e.jsx(z,{className:"w-5 h-5 mr-1"})," Delete"]})]})]})]}),e.jsx(Z,{level:"campaign",id:s._id,account:l,range:g}),e.jsx(Q,{title:"Ads",apiMethod:x,itemsPerPage:25,onRowClick:o,renders:[{id:"name",title:"Ad",sortable:!0,render:(d,f)=>e.jsx(le,{name:d,isOn:f.status==="active",onToggle:a?void 0:j=>w(f,j)})},{id:"_id",title:"Ad ID",render:d=>e.jsx(de,{id:d})},{id:"status",title:"Status",sortable:!0,render:xe},...he(),{id:"created",title:"Created",sortable:!0,render:d=>d?new Date(d).toLocaleDateString():""}]},`ads-${s._id}-${u}-${JSON.stringify(g)}`)]})},re=["ADS_SERVING_ENABLED","ADS_ATTRIBUTION_TOUCH","ADS_IMPRESSION_DEDUP_MINUTES","ADS_UTM_MEDIUM"],ie={ADS_SERVING_ENABLED:!0,ADS_ATTRIBUTION_TOUCH:"last",ADS_IMPRESSION_DEDUP_MINUTES:"30",ADS_UTM_MEDIUM:"aldoo-ads"},$=t=>t===!0||t==="true",it=[{value:"first",label:"First touch — credit the ad that ACQUIRED the user"},{value:"last",label:"Last touch — credit the ad that CONVERTED the user"},{value:"both",label:"Both — report first and last as separate columns"}],ct=()=>{const[t,a]=c.useState(ie),[n,s]=c.useState(!0),[o,h]=c.useState(!1);c.useEffect(()=>{(async()=>{const m={...ie};for(const l of re){const i=(await Ne({match:{address:l}}
1).catch(()=>null))?.data?.[0]?.value;i!==void 0&&(m[l]=l==="ADS_SERVING_ENABLED"?$(i):String(i??""))}a(m),s(!1)})()},[]);const u=m=>l=>a(x=>({...x,[m]:l})),b=async()=>{h(!0);try{const m=re.map(l=>{let x=t[l];return l==="ADS_SERVING_ENABLED"?x=$(x):l==="ADS_IMPRESSION_DEDUP_MINUTES"?x=parseInt(x,10)||0:x=String(x??""),Ae(l).then(i=>i&&i.result!==!1?ke({address:l,value:x}):ee({address:l,value:x})).catch(()=>ee({address:l,value:x}))});await Promise.all(m),C({message:"Ads settings saved",className:"bg-admin_success text-admin_text_inv"})}catch{C({message:"Failed to save ads settings",className:"bg-admin_error text-admin_text_inv"})}finally{h(!1)}};if(n)return e.jsx(N,{variant:"admin_body1",children:"Loading…"});const g=(m,l,x)=>e.jsxs("div",{className:"flex flex-col gap-1 py-3 border-b border-admin_bordered last:border-0",children:[e.jsx("span",{className:"text-sm font-semibold text-admin_text",children:m}),l&&e.jsx("span",{className:"text-xs text-admin_text_secondary",children:l}),e.jsx("div",{className:"mt-1",children:x})]});return e.jsxs("div",{className:"bg-paper rounded-lg border border-admin_bordered p-5 max-w-3xl flex flex-col gap-1",children:[g("Serving Enabled","Master switch. When off, the serve endpoint returns nothing and every <AldooAd/> slot renders empty on all sites.",e.jsxs("label",{className:"inline-flex items-center gap-2 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:$(t.ADS_SERVING_ENABLED),onChange:m=>u("ADS_SERVING_ENABLED")(m.target.checked)}),e.jsx("span",{className:"text-sm",children:$(t.ADS_SERVING_ENABLED)?"On":"Off"})]})),g("Attribution Touch","Which touch credits signups & revenue to an ad. First = the campaign that acquired the user (their first ever campaign visit). Last = the campaign that converted them (most recent visit before signup/purchase). Both = the dashboard shows two columns to compare acquisition vs conversion.",e.jsx("select",{className:"border border-admin_bordered rounded-lg px-3 py-2 bg-transparent w-full",value:t.ADS_ATTRIBUTION_TOUCH,onChange:m=>u("ADS_ATTRIBUTION_TOUCH")(m.target.value),children:it.map(m=>e.jsx("option",{value:m.value,children:m.label},m.value))})),g("Impression Dedup (minutes)","Repeat impressions from the same visitor for the same ad within this window count once. 0 disables deduplication.",e.jsx("input",{type:"number",min:"0",className:"border border-admin_bordered rounded-lg px-3 py-2 bg-transparent w-40",value:t.ADS_IMPRESSION_DEDUP_MINUTES,onChange:m=>u("ADS_IMPRESSION_DEDUP_MINUTES")(m.target.value)})),g("Click UTM Medium","utm_medium stamped on every ad click redirect (default: aldoo-ads).",e.jsx("input",{className:"border border-admin_bordered rounded-lg px-3 py-2 bg-transparent w-full",value:t.ADS_UTM_MEDIUM,onChange:m=>u("ADS_UTM_MEDIUM")(m.target.value)})),e.jsx("div",{className:"pt-4",children:e.jsx(A,{variant:"admin_primary",onClick:b,disabled:o,children:o?"Saving…":"Save settings"})})]})},ot=()=>{const[t,a]=c.useState([]),[n,s]=c.useState(null),o=async()=>a(await He().catch(()=>[]));c.useEffect(()=>{o()},[]);const h=async()=>{const u=await Ve("Aldoo Ads access key (ads:read)");if(!u?.result){C({message:"Failed to create key",className:"bg-admin_error text-admin_text_inv"});return}s(u.key),o()};return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs(N,{variant:"admin_body1",children:["Generate an access key with the ",e.jsx("b",{children:"ads:read"})," permission and give it to a partner site — they paste it in their Connect Account tab (together with this site's API URL) to list this account's campaigns, render its ads and read its stats."]}),e.jsx("div",{children:e.jsx(A,{variant:"admin_primary",onClick:h,children:"Create Access Key"})}),n&&e.jsx("div",{className:"border border-admin_success rounded-lg p-4 bg-admin_success/10",children:e.jsxs(N,{variant:"admin_body1",children:["Key created — copy it now (shown once): ",e.jsx("code",{className:"font-mono select-all",children:n})]})}),e.jsx("div",{className:"flex flex-col gap-2",children:t.map(u=>e.jsxs("div",{className:"border border-admin_bordered rounded-lg p-3 flex justify-between text-sm",children:[e.jsx("span",{className:"font-mono",children:u.key?`${String(u.key).slice(0,8)}…`:u._id}),e.jsx("span",{className:"text-admin_text_secondary",children:u.status})]},u._id))})]})},lt=()=>{const[t,a]=c.useState(""),[n,s]=c.useState(""),[o,h]=c.useState(""),[u,b]=c.useState(!1),[g,m]=c.useState([]),l=async()=>{const _=await W().catch(()=>null);m((_?.accounts||[]).filter(w=>w.type==="remote"))};c.useEffect(()=>{l()},[]);const x=async()=>
1{if(!(!t.trim()||!n.trim())){b(!0);try{const _=await Ge({api_url:t.trim(),access_key:n.trim(),name:o.trim()});_?.result?(C({message:"Account connected",className:"bg-admin_success text-admin_text_inv"}),a(""),s(""),h(""),l()):C({message:_?.error==="remote_unreachable"?"Remote API unreachable":_?.error==="remote_rejected"?"Remote rejected the key (needs ads:read)":"Failed to connect account",className:"bg-admin_error text-admin_text_inv"})}finally{b(!1)}}},i=async _=>{await Ke.SoftDelete({_id:_._id}),l()};return e.jsxs("div",{className:"flex flex-col gap-4 max-w-2xl",children:[e.jsxs(N,{variant:"admin_body1",children:[`Link another aldoo site's ad account ("Link Aldoo Ad Account"): paste its API URL and the access key generated on that site (Settings → Access Keys). Once connected, its campaigns and stats appear in this dashboard and its ads can be served here with`," ",e.jsx("code",{children:"<AldooAd id account/>"}),"."]}),e.jsx("input",{className:"border border-admin_bordered rounded-lg px-3 py-2 bg-transparent",placeholder:"API URL — e.g. https://api-transfer.aldoo.com",value:t,onChange:_=>a(_.target.value)}),e.jsx("input",{className:"border border-admin_bordered rounded-lg px-3 py-2 bg-transparent font-mono",placeholder:"Access key (ads:read)",value:n,onChange:_=>s(_.target.value)}),e.jsx("input",{className:"border border-admin_bordered rounded-lg px-3 py-2 bg-transparent",placeholder:"Display name (optional)",value:o,onChange:_=>h(_.target.value)}),e.jsx("div",{children:e.jsx(A,{variant:"admin_primary",onClick:x,disabled:u,children:u?"Connecting…":"Connect Account"})}),g.length>0&&e.jsxs("div",{className:"flex flex-col gap-2 pt-2",children:[e.jsx(N,{variant:"admin_h4",children:"Connected accounts"}),g.map(_=>e.jsxs("div",{className:"border border-admin_bordered rounded-lg p-3 flex justify-between items-center text-sm",children:[e.jsxs("span",{children:[_.name," — ",e.jsx("span",{className:"text-admin_text_secondary",children:_.api_url})]}),e.jsx(A,{variant:"admin_secondary",onClick:()=>i(_),children:"Remove"})]},_._id))]})]})},dt=()=>{const[t,a]=c.useState("general"),n=[{value:"general",label:"General"},{value:"keys",label:"Access Keys"},{value:"connect",label:"Connect Account"}];return e.jsxs("div",{className:"p-6 flex flex-col gap-5",children:[e.jsx(N,{variant:"admin_h3",children:"Aldoo Ads Settings"}),e.jsx(ce,{variant:"admin",tabs:n,value:t,onChange:a}),t==="general"&&e.jsx(ct,{}),t==="keys"&&e.jsx(ot,{}),t==="connect"&&e.jsx(lt,{})]})},Ct=()=>e.jsx(Ce,{menuName:"AdminAldooAdsMenu",tabs:{dashboard:nt,settings:dt}});export{Ct as default};
2//# sourceMappingURL=chunk-BDbTf76m.js.map

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.