1import{w as K,j as e,cM as js,s as h,$ as cs,bS as De,r,u as fs,cq as vs,B as g,aL as Ve,aF as _s,aI as ys,aM as bs,C as qe,c as Ee,d as Fe,e as Oe,aU as ws,I as x,f as Be,aa as es,aO as We,R as Ns,N as Ss,D as ms,x as us,y as Ye,z as Je,F as hs,h as l,G as Ze,T as Cs,ab as Ue,ag as ps,H as Ae}from"./index-CnpT2L3h.js";import{S as P,f as ks,s as ss,p as ze}from"./smpp-gateway-CEm4Wp8I.js";import{C as Ps}from"./checkbox-Bl-6Ju2h.js";import{T as He,a as Ge,b as Se,c as k,d as Qe,e as S}from"./table-BwSZRhSE.js";import{S as ts,a as as,b as ns,c as rs,d as Re}from"./select-DOryJ5RD.js";import{S as Te}from"./switch-BaH1nQ1x.js";import{B as b}from"./badge-B_awFKIr.js";import{S as As}from"./SmppBindControls-DooHZV4r.js";import{P as is}from"./play-B3J_hbK2.js";import{B as os}from"./ban-RDoMJept.js";import{L as ls}from"./log-in-Ce6oracu.js";import{W as Ts}from"./wand-sparkles-BrCaeHKk.js";import{L as Is}from"./layers-Bmtks7Ue.js";import"./index-DE5r3BXW.js";import"./chevron-up-DX2f010j.js";import"./alert-dialog-CU9ZR6i-.js";import"./circle-pause-D0K69bIL.js";import"./circle-play-BtwffQtb.js";import"./trash-2-BNqJXUUR.js";const $s=n=>n?new Date(n).toLocaleString("en-US",{timeZone:"America/New_York",month:"short",day:"numeric",hour:"numeric",minute:"2-digit"})+" ET":"â";function Ls({apiKeyId:n,systemId:w}){const{data:d}=K({queryKey:["api-key-slot",n],queryFn:async()=>{const{data:N}=await h.from("smpp_account_slots").select("slot_code, system_id, tps, status, assigned_at, pushed_at").eq("assigned_api_key_id",n).maybeSingle();return N},staleTime:3e4});return e.jsxs("div",{className:"p-4 border rounded space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx(js,{className:"h-4 w-4 text-muted-foreground"}),e.jsx("strong",{className:"text-sm",children:"Their connection"}),d?e.jsxs(e.Fragment,{children:[e.jsx(b,{variant:"secondary",children:d.slot_code}),e.jsx(b,{variant:"outline",className:"bg-success/10 text-success border-success/20",children:"from the ready pool"})]}):e.jsx(b,{variant:"outline",children:"one-off connection"})]}),e.jsxs("div",{className:"text-xs text-muted-foreground space-y-0.5",children:[e.jsxs("div",{children:["Login name: ",e.jsx("code",{children:(d==null?void 0:d.system_id)||w||"not set yet"}),d?` · ${d.tps}/sec`:""]}),d?e.jsxs("div",{children:["Handed out from the ready pool on ",$s(d.assigned_at)," â nothing was restarted and no other customer was touched."]}):e.jsx("div",{children:"Set up before the ready pool existed, so it lives in the gateway on its own. Nothing to change â it keeps working as is."})]})]})}async function Us(n){const w=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(n));return Array.from(new Uint8Array(w)).map(d=>d.toString(16).padStart(2,"0")).join("")}function Rs(){const n=new Uint8Array(32);return crypto.getRandomValues(n),"otxt_"+Array.from(n).map(w=>w.toString(16).padStart(2,"0")).join("")}const ds=[{value:"transactional",label:"Transactional (OTP, receipts, alerts)"},{value:"marketing_opted_in",label:"Marketing â Opted-in lists only"},{value:"cold_outreach",label:"Cold outreach (â ï¸ manual approval required)"}];function nt(){const n=cs(),{toast:w}=De(),[d,N]=r.useState(!1),[j,D]=r.useState(null),[L,re]=r.useState("all"),[M,me]=r.useState(""),[$,z]=r.useState(null),[Q,ue]=fs(),{data:U=[]}=K({queryKey:["admin-api-keys"],queryFn:async()=>{const{data:s,error:c}=await h.from("api_keys").select("*").order("created_at",{ascending:!1});if(c)throw c;return s||[]}}),O=Q.get("key");r.useEffect(()=>{if(!O||j)return;const s=U.find(c=>c.id===O);s&&D(s)},[O,U,j]);const{data:V=[]}=K({queryKey:["admin-api-key-users"],queryFn:async()=>{const{data:s}=await h.from("profiles").select("user_id, email, display_name").order("email",{ascending:!0}).limit(500);return s||[]}}),F=U.filter(s=>s.connection_type==="smpp").length,ee=U.length-F,B=M.trim().toLowerCase(),se=B?U.filter(s=>(s.name||"").toLowerCase().includes(B)||(s.key_prefix||"").toLowerCase().includes(B)||(s.smpp_system_id||"").toLowerCase().includes(B)):U,H=L==="all"?se:se.filter(s=>L==="smpp"?s.connection_type==="smpp":s.connection_type!=="smpp"),te=(()=>{const s=(m,u)=>(u.credit_balance_cents||0)-(m.credit_balance_cents||0),c=H.filter(m=>!m.billing_api_key_id||!H.some(u=>u.id===m.billing_api_key_id)).sort(s),v=m=>H.filter(u=>u.billing_api_key_id===m).sort(s),A=[];for(const m of c){A.push({key:m,isChild:!1});
1for(const u of v(m.id))A.push({key:u,isChild:!0})}return A})(),{data:G=[],refetch:Y}=K({queryKey:["admin-api-invoices"],queryFn:async()=>{const{data:s,error:c}=await h.from("api_invoices").select("id, invoice_number, recipient_email, recipient_name, company, amount_usd, currency, credits_note, due_date, pdf_url, status, created_at, api_key_id").order("created_at",{ascending:!1}).limit(200);if(c)throw c;return s||[]}}),{data:J=[]}=K({queryKey:["admin-rewrite-stats"],queryFn:async()=>{const{data:s,error:c}=await h.rpc("admin_rewrite_stats");if(c)throw c;return s||[]},staleTime:6e4,refetchInterval:6e4});async function W(s){z(s.id);try{const{data:c,error:v}=await h.functions.invoke("admin-impersonate",{body:{target_user_id:s.user_id}});if(v)throw v;if(!(c!=null&&c.url))throw new Error((c==null?void 0:c.error)||"No login link returned");Ss(c.url)}catch(c){w({title:"Could not open their dashboard",description:c.message,variant:"destructive"})}finally{z(null)}}async function ae(s){if(s.suspended_at)await h.from("api_keys").update({suspended_at:null,suspended_reason:null}).eq("id",s.id),w({title:"Key resumed"});else{const c=prompt("Suspend reason (visible to admins only):");if(c===null)return;await h.from("api_keys").update({suspended_at:new Date().toISOString(),suspended_reason:c}).eq("id",s.id),w({title:"Key suspended â instant 401 on all requests"})}n.invalidateQueries({queryKey:["admin-api-keys"]})}async function he(s){var v;const{data:c}=await h.auth.getUser();await h.from("api_keys").update({approval_status:"approved",approved_by:(v=c.user)==null?void 0:v.id,approved_at:new Date().toISOString(),is_active:!1,terms_hold_at:new Date().toISOString()}).eq("id",s.id),w({title:"Key approved"}),n.invalidateQueries({queryKey:["admin-api-keys"]})}return e.jsxs("div",{className:"container max-w-7xl px-3 py-5 sm:px-6 sm:py-8 space-y-5 sm:space-y-6",children:[e.jsxs("div",{className:"flex flex-col gap-4 md:flex-row md:items-center md:justify-between",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("h1",{className:"text-2xl sm:text-3xl font-bold flex items-center gap-2",children:[e.jsx(vs,{className:"h-6 w-6 sm:h-7 sm:w-7 shrink-0"})," API Customers"]}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"Enterprise API keys â dedicated pools, per-key rates, kill switch, and credit ledger."})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 md:flex md:gap-2",children:[e.jsx(g,{asChild:!0,variant:"outline",className:"h-11 md:h-10",children:e.jsxs(Ve,{to:"/admin/api-signups",children:["Signups ",e.jsx(_s,{className:"h-4 w-4 ml-1"})]})}),e.jsx(g,{asChild:!0,variant:"outline",className:"h-11 md:h-10",children:e.jsxs(Ve,{to:"/admin/api-keys/logs",children:["Logs ",e.jsx(ys,{className:"h-4 w-4 ml-1"})]})}),e.jsxs(g,{onClick:()=>N(!0),className:"col-span-2 h-11 md:col-span-1 md:h-10",children:[e.jsx(bs,{className:"h-4 w-4 mr-1"})," Onboard Customer"]})]})]}),e.jsxs(qe,{children:[e.jsxs(Ee,{className:"p-4 sm:p-6",children:[e.jsx(Fe,{children:"All API Customers"}),e.jsxs(Oe,{children:[U.length," total ⢠",F," on SMPP ⢠",ee," on HTTP API â tap a row to manage"]}),e.jsx("div",{className:"grid grid-cols-3 gap-2 pt-2",children:[["all",`All (${U.length})`],["smpp",`SMPP (${F})`],["http",`HTTP (${ee})`]].map(([s,c])=>e.jsx(g,{size:"sm",className:"h-10 w-full text-xs sm:text-sm",variant:L===s?"default":"outline",onClick:()=>re(s),children:c},s))}),e.jsxs("div",{className:"relative pt-2",children:[e.jsx(ws,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(x,{value:M,onChange:s=>me(s.target.value),placeholder:"Search by name, key or system IDâ¦",className:"pl-9 h-10"})]})]}),e.jsxs(Be,{className:"p-4 pt-0 sm:p-6 sm:pt-0",children:[e.jsx("div",{className:"space-y-2 md:hidden",children:te.length===0?e.jsx("p",{className:"text-center text-sm text-muted-foreground py-8",children:"No API customers here yet."}):te.map(({key:s,isChild:c})=>{const v=s.suspended_at?"suspended":s.approval_status??"pending",A=s.connection_type==="smpp",m=s.credit_balance_cents||0,u=s.sms_rate_cents>0?Math.floor(m/s.sms_rate_cents):0;return e.jsxs("div",{role:"button",tabIndex:0,onClick:()=>D(s),onKeyDown:R=>
1{(R.key==="Enter"||R.key===" ")&&(R.preventDefault(),D(s))},className:"rounded-lg border bg-card p-3 active:bg-accent/60",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:`font-medium truncate ${c?"pl-4 text-muted-foreground":""}`,children:[c?"â³ ":"",s.name]}),e.jsxs("code",{className:"text-[11px] text-muted-foreground break-all",children:[s.key_prefix,"â¦"]})]}),e.jsxs("div",{className:"flex flex-col items-end gap-1 shrink-0",children:[A?e.jsx(b,{className:"bg-indigo-600",children:"SMPP"}):e.jsx(b,{variant:"outline",children:"HTTP API"}),v==="approved"&&e.jsx(b,{className:"bg-green-600",children:"Approved"}),v==="pending"&&e.jsx(b,{variant:"secondary",children:"Pending"}),v==="suspended"&&e.jsx(b,{variant:"destructive",children:"Suspended"}),v==="revoked"&&e.jsx(b,{variant:"outline",children:"Revoked"}),s.terms_activation_error?e.jsx(b,{variant:"destructive",className:"text-[10px]",children:"Signed / activation pending"}):s.terms_activated_at?e.jsx(b,{variant:"outline",className:"text-[10px]",children:"Signed / active"}):e.jsx(b,{variant:"secondary",className:"text-[10px]",children:"Waiting for signature"})]})]}),e.jsxs("div",{className:"mt-2 grid grid-cols-2 gap-x-3 gap-y-1 text-xs",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"Balance "}),e.jsxs("span",{className:"font-mono",children:["$",(m/100).toFixed(2)]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"Left "}),e.jsx("span",{className:`font-mono ${u<5e3&&s.sms_rate_cents>0?"text-destructive font-medium":""}`,children:s.sms_rate_cents>0?`${u.toLocaleString()} SMS`:"â"})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"Rates "}),s.sms_rate_cents,"¢ / ",s.mms_rate_cents,"¢"]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"Pool "}),s.dedicated_number_pool_id?"Assigned":"â"]})]}),e.jsxs("div",{className:"mt-3 flex gap-2",onClick:R=>R.stopPropagation(),children:[v==="pending"&&e.jsxs(g,{size:"sm",variant:"outline",className:"h-10 flex-1",onClick:()=>he(s),children:[e.jsx(es,{className:"h-4 w-4 mr-1"})," Approve"]}),e.jsx(g,{size:"sm",variant:s.suspended_at?"outline":"destructive",className:"h-10 flex-1",onClick:()=>ae(s),children:s.suspended_at?e.jsxs(e.Fragment,{children:[e.jsx(is,{className:"h-4 w-4 mr-1"})," Resume"]}):e.jsxs(e.Fragment,{children:[e.jsx(os,{className:"h-4 w-4 mr-1"})," Suspend"]})}),e.jsx(g,{size:"sm",variant:"secondary",className:"h-10 flex-1",onClick:()=>D(s),children:"Manage"}),e.jsxs(g,{size:"sm",variant:"outline",className:"h-10 flex-1",disabled:$===s.id,onClick:()=>W(s),children:[e.jsx(ls,{className:"h-4 w-4 mr-1"})," ",$===s.id?"Openingâ¦":"Log in"]})]})]},s.id)})}),e.jsx("div",{className:"hidden md:block overflow-x-auto",children:e.jsxs(He,{className:"min-w-[1200px]",children:[e.jsx(Ge,{children:e.jsxs(Se,{children:[e.jsx(k,{children:"Name"}),e.jsx(k,{children:"Connection"}),e.jsx(k,{children:"Status"}),e.jsx(k,{children:"Balance"}),e.jsx(k,{children:"Messages Left"}),e.jsx(k,{children:"Rates"}),e.jsx(k,{children:"Pool"}),e.jsx(k,{children:"Last Used"}),e.jsx(k,{children:"Actions"})]})}),e.jsx(Qe,{children:H.length===0?e.jsx(Se,{children:e.jsx(S,{colSpan:9,className:"text-center text-muted-foreground py-8",children:"No API customers here yet."})}):te.map(({key:s,isChild:c})=>{const v=s.suspended_at?"suspended":s.approval_status??"pending",A=s.connection_type==="smpp",m=s.credit_balance_cents||0,u=s.sms_rate_cents>0?Math.floor(m/s.sms_rate_cents):0;return e.jsxs(Se,{className:`cursor-pointer ${c?"bg-muted/40":""}`,onClick:()=>D(s),children:[e.jsxs(S,{className:"font-medium",children:[e.jsxs("div",{className:c?"pl-5 text-muted-foreground":"",children:[c?"â³ ":"",s.name]}),e.jsxs("code",{className:"text-xs text-muted-foreground",children:[s.key_prefix,"â¦"]})]}),e.jsx(S,{className:"text-xs",children:A?e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(b,{className:"bg-indigo-600",children:"SMPP"}),s.smpp_system_id&&e.jsx("div",{children:e.jsx("code",{className:"text-[11px] text-muted-foreground",children:s.smpp_system_id})})]}):e.jsx(b,{variant:"outline",children:"HTTP API"})}),e.jsxs(S,{children:[v==="approved"&&e.jsx(b,{className:"bg-green-600",children:"Approved"}),v==="pending"&&e.jsx(b,{variant:"secondary",children:"Pending"}),v==="suspended"&&e.jsx(b,{variant:"destructive",children:"Suspended"}),v==="revoked"&&e.jsx(b,{variant:"outline",children:"Revoked"}),s.terms_activation_error?e.jsx(b,{variant:"destructive",className:"text-[10px]",children:"Signed / activation pending"}):s.terms_activated_at?e.jsx(b,{variant:"outline",className:"text-[10px]",children:"Signed / active"}):e.jsx(b,{variant:"secondary",className:"text-[10px]",children:"Waiting for signature"})]}),e.jsxs(S,{className:"text-sm font-mono",children:["$",((s.credit_balance_cents||0)/100).toFixed(2)]}),e.jsx(S,{className:"text-xs font-mono",children:s.sms_rate_cents>
10?e.jsxs("span",{className:u<5e3?"text-destructive font-medium":"",children:[u.toLocaleString()," SMS"]}):"â"}),e.jsxs(S,{className:"text-xs",children:[s.sms_rate_cents,"¢ / ",s.mms_rate_cents,"¢"]}),e.jsx(S,{className:"text-xs",children:s.dedicated_number_pool_id?e.jsx(b,{variant:"outline",children:"Assigned"}):e.jsx("span",{className:"text-muted-foreground",children:"â"})}),e.jsx(S,{className:"text-xs",children:s.last_used_at?new Date(s.last_used_at).toLocaleString():"Never"}),e.jsx(S,{onClick:R=>R.stopPropagation(),children:e.jsxs("div",{className:"flex gap-1",children:[v==="pending"&&e.jsx(g,{size:"sm",variant:"outline",onClick:()=>he(s),title:"Approve",children:e.jsx(es,{className:"h-3.5 w-3.5"})}),e.jsx(g,{size:"sm",variant:s.suspended_at?"outline":"destructive",onClick:()=>ae(s),title:s.suspended_at?"Resume":"Suspend",children:s.suspended_at?e.jsx(is,{className:"h-3.5 w-3.5"}):e.jsx(os,{className:"h-3.5 w-3.5"})}),e.jsx(g,{size:"sm",variant:"outline",disabled:$===s.id,onClick:()=>W(s),title:"Log in as this customer",children:e.jsx(ls,{className:"h-3.5 w-3.5"})})]})})]},s.id)})})]})})]})]}),(()=>{const s=m=>J.find(u=>u.api_key_id===m),c=U.map(m=>({k:m,s:s(m.id)})).filter(m=>m.s&&((m.s.r24h||0)>0||(m.s.r7d||0)>0||(m.s.r30d||0)>0)).sort((m,u)=>(u.s.r7d||0)-(m.s.r7d||0)||(u.s.r30d||0)-(m.s.r30d||0)),v=J.reduce((m,u)=>m+(u.r24h||0),0),A=J.reduce((m,u)=>m+(u.r7d||0),0);return e.jsxs(qe,{children:[e.jsxs(Ee,{className:"p-4 sm:p-6",children:[e.jsxs(Fe,{className:"flex items-center gap-2",children:[e.jsx(Ts,{className:"h-5 w-5"})," Auto-rewrite Activity"]}),e.jsxs(Oe,{children:[v.toLocaleString()," messages reworded in the last 24h ⢠",A.toLocaleString()," in the last 7 days â auto-rewrite is on for every customer. A customer being rewritten over and over is a signal to review their content."]})]}),e.jsx(Be,{className:"p-4 sm:p-6 pt-0",children:c.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No rewrites in the last 30 days."}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(He,{className:"min-w-[900px]",children:[e.jsx(Ge,{children:e.jsxs(Se,{children:[e.jsx(k,{children:"Customer"}),e.jsx(k,{className:"text-right",children:"Last 24h"}),e.jsx(k,{className:"text-right",children:"Last 7 days"}),e.jsx(k,{className:"text-right",children:"Last 30 days"}),e.jsx(k,{children:"Last rewrite"}),e.jsx(k,{children:"Status"})]})}),e.jsx(Qe,{children:c.map(({k:m,s:u})=>e.jsxs(Se,{children:[e.jsxs(S,{className:"text-xs font-medium",children:[m.name||"â",m.customer_code&&e.jsx(b,{variant:"outline",className:"ml-1.5",children:m.customer_code})]}),e.jsx(S,{className:"text-xs text-right",children:(u.r24h||0).toLocaleString()}),e.jsx(S,{className:"text-xs text-right",children:(u.r7d||0).toLocaleString()}),e.jsx(S,{className:"text-xs text-right",children:(u.r30d||0).toLocaleString()}),e.jsx(S,{className:"text-xs",children:u.last_rewrite_at?`${new Date(u.last_rewrite_at).toLocaleString("en-US",{timeZone:"America/New_York",month:"short",day:"numeric",hour:"numeric",minute:"2-digit"})} ET`:"â"}),e.jsx(S,{children:(u.r7d||0)>=50?e.jsx(b,{variant:"destructive",children:"Heavy â review"}):(u.r7d||0)>0?e.jsx(b,{variant:"outline",children:"Normal"}):null})]},m.id))})]})})})]})})(),e.jsxs(qe,{children:[e.jsx(Ee,{className:"p-4 sm:p-6",children:e.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs("div",{children:[e.jsxs(Fe,{className:"flex items-center gap-2",children:[e.jsx(We,{className:"h-5 w-5"})," Sent Invoices"]}),e.jsxs(Oe,{children:[G.length," invoices sent via wire / crypto"]})]}),e.jsxs(g,{size:"sm",variant:"outline",className:"h-10 w-full sm:w-auto",onClick:()=>Y(),children:[e.jsx(Ns,{className:"h-3.5 w-3.5 mr-1.5"})," Refresh"]})]})}),e.jsx(Be,{className:"p-4 pt-0 sm:p-6 sm:pt-0",children:G.length===0?e.jsx("p",{className:"text-sm text-muted-foreground py-8 text-center",children:"No invoices sent yet."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"space-y-2 md:hidden",children:G.map(s=>e.jsxs("div",{className:"rounded-lg border bg-card p-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("code",{className:"text-xs",children:s.invoice_number}),s.recipient_name&&e.jsx("div",{className:"text-sm font-medium truncate",children:s.recipient_name}),e.jsx("div",{className:"text-xs text-muted-foreground break-all",children:s.recipient_email})]}),e.jsxs("div",{className:"text-right shrink-0",children:[e.jsx("div",{className:"font-mono text-sm font-medium",children:Number(s.amount_usd).toLocaleStr
1ing("en-US",{style:"currency",currency:s.currency||"USD"})}),e.jsx(b,{variant:s.status==="paid"?"default":s.status==="void"?"outline":"secondary",children:s.status})]})]}),e.jsxs("div",{className:"mt-2 flex items-center justify-between text-xs text-muted-foreground",children:[e.jsx("span",{children:new Date(s.created_at).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}),s.pdf_url&&e.jsx("a",{href:s.pdf_url,target:"_blank",rel:"noopener noreferrer",children:e.jsxs(g,{size:"sm",variant:"ghost",className:"h-9",children:[e.jsx(We,{className:"h-4 w-4 mr-1"})," PDF"]})})]})]},s.id))}),e.jsx("div",{className:"hidden md:block overflow-x-auto",children:e.jsxs(He,{className:"min-w-[900px]",children:[e.jsx(Ge,{children:e.jsxs(Se,{children:[e.jsx(k,{children:"Invoice #"}),e.jsx(k,{children:"Recipient"}),e.jsx(k,{children:"Company"}),e.jsx(k,{className:"text-right",children:"Amount"}),e.jsx(k,{children:"Date"}),e.jsx(k,{children:"Status"}),e.jsx(k,{children:"PDF"})]})}),e.jsx(Qe,{children:G.map(s=>e.jsxs(Se,{children:[e.jsx(S,{className:"font-mono text-xs",children:s.invoice_number}),e.jsxs(S,{className:"text-sm",children:[s.recipient_name&&e.jsx("div",{children:s.recipient_name}),e.jsx("div",{className:"text-xs text-muted-foreground",children:s.recipient_email})]}),e.jsx(S,{className:"text-sm",children:s.company||"â"}),e.jsx(S,{className:"text-right font-mono text-sm font-medium",children:Number(s.amount_usd).toLocaleString("en-US",{style:"currency",currency:s.currency||"USD"})}),e.jsx(S,{className:"text-xs text-muted-foreground",children:new Date(s.created_at).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}),e.jsx(S,{children:e.jsx(b,{variant:s.status==="paid"?"default":s.status==="void"?"outline":"secondary",children:s.status})}),e.jsx(S,{children:s.pdf_url?e.jsx("a",{href:s.pdf_url,target:"_blank",rel:"noopener noreferrer",children:e.jsx(g,{size:"sm",variant:"ghost",className:"h-8 w-8 p-0",title:"Download PDF",children:e.jsx(We,{className:"h-4 w-4"})})}):e.jsx("span",{className:"text-muted-foreground",children:"â"})})]},s.id))})]})})]})})]}),d&&e.jsx(Ds,{open:d,onClose:()=>{N(!1),n.invalidateQueries({queryKey:["admin-api-keys"]})},users:V}),j&&e.jsx(Ms,{apiKey:j,onClose:()=>{if(D(null),Q.get("key")){const s=new URLSearchParams(Q);s.delete("key"),ue(s,{replace:!0})}n.invalidateQueries({queryKey:["admin-api-keys"]})}})]})}function Ds({open:n,onClose:w,users:d}){var xe,we;const{toast:N}=De(),[j,D]=r.useState(1),[L,re]=r.useState(""),[M,me]=r.useState(""),[$,z]=r.useState(""),[Q,ue]=r.useState(2),[U,O]=r.useState(4),[V,F]=r.useState(""),[ee,B]=r.useState(""),[se,H]=r.useState(!1),[te,G]=r.useState("0"),[Y,J]=r.useState([]),[W,ae]=r.useState(null),[he,s]=r.useState(null),[c,v]=r.useState(!1),[A,m]=r.useState(!1),[u,R]=r.useState(""),[q,ie]=r.useState(""),[oe,E]=r.useState(String(P.defaultTps)),[ge,be]=r.useState(""),[je,T]=r.useState(null),[le,fe]=r.useState(!0),[pe,o]=r.useState(""),[ve,Ce]=r.useState(""),[Z,de]=r.useState(null),[_e,Ie]=r.useState(!1),[$e,Pe]=r.useState(!1),[t,i]=r.useState(null);async function f(){Ie(!0);try{const{data:a,error:p}=await h.functions.invoke("admin-create-api-user",{body:{email:pe.trim(),contact_name:ve.trim(),company:L.trim()}});if(p)throw p;if(a!=null&&a.error)throw new Error(a.error);const _=a;me(_.user_id),de(_.password||null),N({title:_.existing?"Existing account linked":_.emailed?"Account created & login emailed":"Account created",description:_.existing?"That email already had an account â using it.":_.emailed?`Login details sent to ${_.email}.`:`Email failed to send â share the password manually. ${_.email_error||""}`})}catch(a){N({title:"Could not create account",description:a.message,variant:"destructive"})}finally{Ie(!1)}}async function y(){if(!(!je||!W)){try{const{data:a}=await h.functions.invoke("smpp-gateway-sync",{body:{action:"preview"}}),p=(a==null?void 0:a.live)||[],_=(a==null?void 0:a.total_sends_last_5m)||0,I=p.length?p.map(ye=>`${ye.name} (${ye.sends_last_5m.toLocaleString()} in 5 min)`).join(", "):"nobody is connected or sending right now";if(!window.confirm(`Adding this bind restarts the gateway. Every connected customer drops for roughly 10-40 seconds and reconnects on its own; sends attempted in that window are refused. 2 3Connected/active now: ${I}
4Total last 5 minutes: ${_.toLocaleString()} messages 5 6Go ahead?`))return}catch{if(!window.confirm("Adding this bind restarts the gateway and briefly drops every connected customer. Couldn't check who is live right now. Go ahead?"))return}Pe(!0),i(null);try{const{data:a,error:p}=await h.functions.invoke("smpp-gateway-sync",{body:{action:"register",api_key_id:je,system_id:u,password:q,send_key:W,tps:parseInt(oe,10)||P.defaultTps,allowed_ips:ze(ge)}});if(p)throw p;if(a!=null&&a.error)throw new Error(a.error);const _=a==null?void 0:a.gateway_healthy,I=a==null?void 0:a.total_accounts;i(_===!1?`Pushed, but the gateway hasn't confirmed healthy yet: ${(a==null?void 0:a.gateway_error)||"still restarting"}`:`Live on the gateway (${I} binds active). ${u} can connect now.`),N({title:_===!1?"Pushed â verify gateway":"Bind is live"})}catch(a){i(null),N({title:"Push failed",description:a.message,variant:"destructive"})}finally{Pe(!1)}}}const{data:C=[]}=K({queryKey:["unassigned-supplier-numbers"],queryFn:async()=>{const{data:a}=await h.from("api_number_pool_members").select("sending_number_id"),p=new Set((a||[]).map(I=>I.sending_number_id)),{data:_}=await h.from("sending_numbers").select("id, phone_number, supplier_account_id, status").eq("status","active").not("supplier_account_id","is",null).limit(500);return(_||[]).filter(I=>!p.has(I.id))}});async function ce(){var a,p,_;if(!L||!M||!$||!se){N({title:"Missing required fields",variant:"destructive"});return}v(!0);try{let I=null;if(Y.length>0){const Me=(a=C.find(gs=>gs.id===Y[0]))==null?void 0:a.supplier_account_id,{data:xs,error:Ke}=await h.from("api_number_pools").insert({name:`${L} Pool`,owner_api_key_id:"00000000-0000-0000-0000-000000000000",supplier_account_id:Me}).select("id").single();if(Ke)throw Ke;I=xs.id}const ne=Rs(),ye=await Us(ne),ke=ne.slice(0,12),Le=await h.auth.getUser(),Ne=Math.max(0,Math.round(parseFloat(te||"0")*100)),{data:X,error:Xe}=await h.from("api_keys").insert({user_id:M,name:L,key_hash:ye,key_prefix:ke,webhook_url:ee||null,use_case:$,sms_rate_cents:Q,mms_rate_cents:U,rate_limit_rps:V?parseInt(V,10):null,tcpa_signed_at:new Date().toISOString(),credit_balance_cents:Ne,approval_status:$==="cold_outreach"?"pending":"approved",is_active:!1,terms_hold_at:new Date().toISOString(),approved_by:$==="cold_outreach"?null:(p=Le.data.user)==null?void 0:p.id,approved_at:$==="cold_outreach"?null:new Date().toISOString(),dedicated_number_pool_id:I,connection_type:A?"smpp":"http",smpp_system_id:A&&u||null}).select("id, webhook_secret").single();if(Xe)throw Xe;I&&(await h.from("api_number_pools").update({owner_api_key_id:X.id}).eq("id",I),await h.from("api_number_pool_members").insert(Y.map(Me=>({pool_id:I,sending_number_id:Me})))),Ne>0&&await h.from("api_credit_ledger").insert({api_key_id:X.id,delta_cents:Ne,reason:"manual_grant",reference_id:"onboarding",admin_id:(_=Le.data.user)==null?void 0:_.id,balance_after_cents:Ne}),T(X.id),ae(ne),s(X.webhook_secret),D(99)}catch(I){N({title:"Failed",description:I.message,variant:"destructive"})}finally{v(!1)}}return e.jsx(ms,{open:n,onOpenChange:a=>{a||w()},children:e.jsx(us,{className:"w-[calc(100vw-1.5rem)] max-w-2xl max-h-[88vh] overflow-y-auto p-4 sm:p-6",children:j!==99?e.jsxs(e.Fragment,{children:[e.jsxs(Ye,{children:[e.jsxs(Je,{children:["Onboard API Customer â Step ",j," of 6"]}),e.jsxs(hs,{children:[j===1&&"Account & contact",j===2&&"Declared use case & TCPA",j===3&&"Assign supplier numbers to dedicated pool",j===4&&"Pricing & rate limits",j===5&&"Webhook & initial credits",j===6&&"Review & generate key"]})]}),j===1&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(l,{children:"Customer Name"}),e.jsx(x,{placeholder:"e.g. Acme Media",value:L,onChange:a=>re(a.target.value)})]}),e.jsxs("div",{className:"flex items-start justify-between gap-4 p-3 border rounded",children:[e.jsxs("div",{children:[e.jsx(l,{className:"text-sm",children:"Create their login for them"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"Makes the account, sets a temporary password and emails it to them so they can sign in and see credits, traffic and receipts. Leave off to bind to an account that already exists."})]}),e.jsx(Te,{checked:le,onCheckedChange:a=>{fe(a),de(null)}})]}),le?e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-3",children:[e.jsxs("div",{children:[e.jsx(l,{children:"Their email"}),e.jsx(x,{type:"email",placeholder:"[email protected]",value:pe,onCh
6ange:a=>o(a.target.value),disabled:!!M})]}),e.jsxs("div",{children:[e.jsx(l,{children:"Contact name"}),e.jsx(x,{placeholder:"Olha",value:ve,onChange:a=>Ce(a.target.value),disabled:!!M})]})]}),M?e.jsxs("div",{className:"p-3 border rounded bg-muted/40 space-y-1",children:[e.jsxs("p",{className:"text-sm font-medium",children:["Account ready â ",pe]}),Z?e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Temporary password: ",e.jsx("code",{children:Z})," â emailed to them. Copy it in case the email is delayed."]}):e.jsx("p",{className:"text-xs text-muted-foreground",children:"Existing account reused â no new password sent."})]}):e.jsx(g,{variant:"outline",onClick:f,disabled:_e||!pe,children:_e?"Creating accountâ¦":"Create account & email login"})]}):e.jsxs("div",{children:[e.jsx(l,{children:"Bind to User Account"}),e.jsxs("select",{className:"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm",value:M,onChange:a=>me(a.target.value),children:[e.jsx("option",{value:"",children:"Select userâ¦"}),d.map(a=>e.jsx("option",{value:a.user_id,children:a.email||a.display_name||a.user_id.slice(0,8)},a.user_id))]})]})]}),j===2&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(l,{children:"Declared Use Case"}),e.jsx("div",{className:"space-y-2 mt-2",children:ds.map(a=>e.jsxs("label",{className:"flex items-start gap-2 p-3 border rounded cursor-pointer hover:bg-muted/50",children:[e.jsx("input",{type:"radio",name:"uc",value:a.value,checked:$===a.value,onChange:()=>z(a.value)}),e.jsx("span",{className:"text-sm",children:a.label})]},a.value))}),$==="cold_outreach"&&e.jsx("p",{className:"text-xs text-destructive mt-2",children:"â ï¸ Cold outreach requires manual admin approval before the key becomes usable. Pool contamination risk is high."})]}),e.jsxs("label",{className:"flex items-start gap-2 p-3 border rounded",children:[e.jsx("input",{type:"checkbox",checked:se,onChange:a=>H(a.target.checked),className:"mt-1"}),e.jsx("span",{className:"text-sm",children:"Customer has signed TCPA/DNC compliance terms. Customer assumes full liability for the messages they send. OpenTxt will scrub for DNC & carrier-blocked phrases before dispatch."})]})]}),j===3&&e.jsxs("div",{className:"space-y-4",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:"Assign supplier numbers to this customer's dedicated pool. Numbers already in another pool are hidden. At ~1M/day you'll want 12â15 numbers minimum."}),e.jsx("div",{className:"border rounded max-h-80 overflow-y-auto",children:C.length===0?e.jsx("p",{className:"text-center text-muted-foreground py-8 text-sm",children:"No unassigned supplier numbers available."}):C.map(a=>e.jsxs("label",{className:"flex items-center gap-2 p-2 border-b hover:bg-muted/50 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:Y.includes(a.id),onChange:p=>J(_=>p.target.checked?[..._,a.id]:_.filter(I=>I!==a.id))}),e.jsx("code",{className:"text-xs",children:a.phone_number})]},a.id))}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Selected: ",Y.length]})]}),j===4&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{children:[e.jsx(l,{children:"SMS rate (¢ / segment)"}),e.jsx(x,{type:"number",value:Q,onChange:a=>ue(parseInt(a.target.value)||0)})]}),e.jsxs("div",{children:[e.jsx(l,{children:"MMS rate (¢ / message)"}),e.jsx(x,{type:"number",value:U,onChange:a=>O(parseInt(a.target.value)||0)})]})]}),e.jsxs("div",{children:[e.jsx(l,{children:"Rate limit (requests / second)"}),e.jsx(x,{type:"number",placeholder:"leave blank until supplier confirms ceiling",value:V,onChange:a=>F(a.target.value)}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"Blank = no limit (rely on supplier throttle for now)."})]})]}),j===5&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-start justify-between gap-4 p-3 border rounded",children:[e.jsxs("div",{children:[e.jsx(l,{className:"text-sm",children:"SMPP customer"}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["Customer connects over SMPP instead of HTTP. Auto-fills the gateway webhook URL and generates bind credentials + the ",e.jsx("code",{children:"SMPP_ACCOUNTS"})," JSON on the final screen."]})]}),e.jsx(Te,{checked:A,onCheckedChange:a=>{m(a),a?(ks().then(p=>
6B(p)).catch(()=>N({title:"Could not load the gateway webhook URL",variant:"destructive"})),u||R((L||"customer").toLowerCase().replace(/[^a-z0-9]+/g,"").slice(0,15)||"customer"),q||ie(Math.random().toString(36).slice(2,10)+Math.random().toString(36).slice(2,4))):ee.includes("/webhook/")&&B("")}})]}),A&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-3 gap-4",children:[e.jsxs("div",{children:[e.jsx(l,{children:"system_id"}),e.jsx(x,{value:u,onChange:a=>R(a.target.value.toLowerCase()),maxLength:15})]}),e.jsxs("div",{children:[e.jsx(l,{children:"password"}),e.jsx(x,{value:q,onChange:a=>ie(a.target.value),maxLength:16})]}),e.jsxs("div",{children:[e.jsx(l,{children:"TPS"}),e.jsx(x,{type:"number",value:oe,onChange:a=>E(a.target.value)})]})]}),e.jsxs("div",{children:[e.jsx(l,{children:"Allowed IPs (optional)"}),e.jsx(x,{placeholder:"162.55.134.156, 94.130.19.118",value:ge,onChange:a=>be(a.target.value)}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"Comma or space separated. Leave blank to allow binds from any source IP."})]})]}),e.jsxs("div",{children:[e.jsx(l,{children:"Default Webhook URL"}),e.jsx(x,{placeholder:"https://customer.com/webhooks/opentxt",value:ee,onChange:a=>B(a.target.value)}),A&&e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["Points at the SMPP gateway so DLRs/replies come back as ",e.jsx("code",{children:"deliver_sm"}),"."]})]}),e.jsxs("div",{children:[e.jsx(l,{children:"Initial Credit Grant ($)"}),e.jsx(x,{type:"number",step:"0.01",placeholder:"0.00",value:te,onChange:a=>G(a.target.value)}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"Enter dollars. At 2¢/SMS, $1,000 = 50,000 SMS segments."})]})]}),j===6&&e.jsx("div",{className:"space-y-3 text-sm",children:e.jsxs("div",{className:"p-3 border rounded space-y-1",children:[e.jsxs("div",{children:[e.jsx("strong",{children:"Customer:"})," ",L]}),e.jsxs("div",{children:[e.jsx("strong",{children:"User:"})," ",((xe=d.find(a=>a.user_id===M))==null?void 0:xe.email)||M]}),e.jsxs("div",{children:[e.jsx("strong",{children:"Use Case:"})," ",(we=ds.find(a=>a.value===$))==null?void 0:we.label]}),e.jsxs("div",{children:[e.jsx("strong",{children:"Rates:"})," ",Q,"¢/SMS · ",U,"¢/MMS"]}),e.jsxs("div",{children:[e.jsx("strong",{children:"Rate Limit:"})," ",V||"unlimited (supplier-throttled)"]}),e.jsxs("div",{children:[e.jsx("strong",{children:"Pool Numbers:"})," ",Y.length]}),e.jsxs("div",{children:[e.jsx("strong",{children:"Initial Credit:"})," $",parseFloat(te||"0").toFixed(2)]}),e.jsxs("div",{children:[e.jsx("strong",{children:"Webhook:"})," ",e.jsx("code",{className:"text-xs",children:ee||"â"})]}),e.jsxs("div",{children:[e.jsx("strong",{children:"TCPA:"})," â Accepted"]}),e.jsxs("div",{children:[e.jsx("strong",{children:"Approval:"})," ",$==="cold_outreach"?"â³ Pending manual review":"â Auto-approved"]})]})}),e.jsxs(Ze,{className:"flex justify-between",children:[e.jsx(g,{variant:"outline",onClick:j===1?w:()=>D(j-1),children:j===1?"Cancel":"Back"}),j<6?e.jsx(g,{onClick:()=>D(j+1),disabled:j===1&&(!L||!M)||j===2&&(!$||!se),children:"Next"}):e.jsx(g,{onClick:ce,disabled:c,children:c?"Creating...":"Generate API Key"})]})]}):e.jsxs(e.Fragment,{children:[e.jsx(Ye,{children:e.jsxs(Je,{className:"flex items-center gap-2",children:[e.jsx(Cs,{className:"h-5 w-5 text-warning"}),"Save these now â they won't be shown again"]})}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx(l,{children:"API Key"}),e.jsxs("div",{className:"flex gap-2 mt-1",children:[e.jsx("code",{className:"flex-1 text-xs bg-muted px-3 py-2 rounded break-all",children:W}),e.jsx(g,{size:"icon",variant:"outline",onClick:()=>{navigator.clipboard.writeText(W),N({title:"Copied"})},children:e.jsx(Ue,{className:"h-4 w-4"})})]})]}),e.jsxs("div",{children:[e.jsx(l,{children:"Webhook Signing Secret"}),e.jsxs("div",{className:"flex gap-2 mt-1",children:[e.jsx("code",{className:"flex-1 text-xs bg-muted px-3 py-2 rounded break-all",children:he}),e.jsx(g,{size:"icon",variant:"outline",onClick:()=>{navigator.clipboard.writeText(he),N({title:"Copied"})},children:e.jsx(Ue,{className:"h-4 w-4"})})]})]}),A&&W&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"rounded border p-3 space-y-2",children:[e.jsx(l,{className:"text-sm",children:"Activate the bind"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"One tap stores these credentials securely, adds this bind to the gateway alongside every existing customer, restarts it and confirms it came back up."}),e.jsx(g,{size:"sm",onClick:y,disabled:$e||!je||!u||!q,children:$e?"Pushing to gatewayâ¦":"Push bind to gateway"}),t&&e.jsx("p",{className:"text-xs text-success",children:t})]}),e.jsxs("div",{className:"rounded border p-3 space-y-2",children:[e.jsx(l,{className:"text-sm",children:"SMPP_ACCOUNTS (manual fallback only)"}),e.jsx("pre",{className:"text-xs bg-muted p-3 rounded overflow-x-auto whitespace-pre-wrap break-all",children:ss([{system_id:u,password:q,api_key:W,tps:parseInt(oe,10)||P.defaultTps,allowed_ips:ze(ge)}])}),e.jsxs(g,{size:"sm",variant:"outline",onClick:()=>{navigator.clipboard.writeText(ss([{system_id:u,password:q,api_key:W,tps:parseInt(oe,10)||P.defaultTps,allowed_ips:ze(ge)}])),N({title:"SMPP_ACCOUNTS copied"})},children:[e.jsx(Ue,{className:"h-4 w-4 mr-1"})," Copy JSON"]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Remember: Railway holds one JSON array with ",e.jsx("em",{children:"every"})," SMPP customer â paste this object alongside the existing entries, don't replace them."]})]}),e.jsxs("div",{className:"rounded border p-3 space-y-2",children:[e.jsx(l,{className:"text-sm",children:"Customer connection details (send to customer)"}),e.jsx("pre",{className:"text-xs bg-muted p-3 rounded overflow-x-auto whitespace-pre-wrap break-all",children:`Host: ${P.tcpHost} (IP: ${P.tcpIp}) 7Port: ${P.tcpPort} 8Bind type: ${P.bindType} 9system_id: ${u} 10password: ${q} 11Throughput: ${parseInt(oe,10)||P.defaultTps} TPS 12Encoding: GSM-7/default (data_coding 0), IA5/ASCII (1), Latin-1 (3), or UCS-2 (8) 13Source addr: leave blank â OpenTxt rotates the sender number 14DLRs: registered_delivery=1 (returned as deliver_sm)`}),e.jsxs(g,{size:"sm",variant:"outline",onClick:()=>{navigator.clipboard.writeText(`Host: ${P.tcpHost} 15Port: ${P.tcpPort} 16Bind type: ${P.bindType} 17system_id: ${u} 18password: ${q} 19Throughput: ${parseInt(oe,10)||P.defaultTps} TPS 20Encoding: GSM-7/default (data_coding 0), IA5/ASCII (1), Latin-1 (3), or UCS-2 (8) 21Source addr: leave blank â OpenTxt rotates the sender number 22DLRs: registered_delivery=1 (returned as deliver_sm)`),N({title:"Customer credentials copied"})},children:[e.jsx(Ue,{className:"h-4 w-4 mr-1"})," Copy credentials"]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Only needed if the one-tap pu
22sh above fails: paste ",e.jsx("code",{children:"SMPP_ACCOUNTS"})," into Railway â Variables, redeploy, then confirm ",e.jsxs("code",{children:[P.httpBaseUrl,"/health"]})," returns OK."]})]})]}),e.jsx(Ze,{children:e.jsx(g,{onClick:w,children:"Done"})})]})})})}function Ms({apiKey:n,onClose:w}){var Pe;const{toast:d}=De(),[N,j]=r.useState(""),[D,L]=r.useState("wire transfer"),[re,M]=r.useState(!0),[me,$]=r.useState((n.allowed_ips||[]).join(` 23`)),[z,Q]=r.useState((n.opt_out_keywords||[]).join(` 24`)),[ue,U]=r.useState(n.sandbox_mode),[O,V]=r.useState(n.auto_fix_compliance===!0),[F,ee]=r.useState((n.auto_fix_countries||[]).join(", ")),[B,se]=r.useState(n.mms_from_link_enabled===!0),[H,te]=r.useState(((Pe=n.rate_limit_rps)==null?void 0:Pe.toString())||""),[G,Y]=r.useState(String(n.sms_rate_cents??"")),[J,W]=r.useState(String(n.mms_rate_cents??"")),[ae,he]=r.useState(String(n.ca_sms_rate_cents??3)),[s,c]=r.useState(String(n.ca_mms_rate_cents??4)),[v,A]=r.useState(n.quote_currency||"USD"),[m,u]=r.useState(n.rates_email||""),[R,q]=r.useState(!1),[ie,oe]=r.useState(n.webhook_url||""),[E,ge]=r.useState(n.assigned_supplier_account_id||"none"),[be,je]=r.useState(!1),[T,le]=r.useState(null),fe=async()=>{var t;je(!0),le(null);try{const{data:i,error:f}=await h.functions.invoke("smpp-gateway-sync",{body:{action:"add_bind",api_key_id:n.id}});if(f){let y="";try{const C=f.context;C&&typeof C.json=="function"&&(y=((t=await C.json())==null?void 0:t.error)||"")}catch{}throw new Error(y||f.message)}if(i!=null&&i.error)throw new Error(i.error);le(i),i!=null&&i.live?d({title:`Bind ${i.system_id} is live`,description:i.emailed?`Credentials emailed to ${i.email_to}`:`Not emailed: ${i.email_error||"no address on file"} â copy them below.`}):d({title:`Bind ${i.system_id} saved â not live yet`,description:"The connection service needs its one-time update before a bind can be added without a restart. It's saved and will come up on the next restart; the customer has not been emailed yet."})}catch(i){d({title:"Could not add the bind",description:i.message,variant:"destructive"})}finally{je(!1)}},{data:pe=[]}=K({queryKey:["admin-supplier-accounts-select"],queryFn:async()=>{const{data:t}=await h.from("supplier_accounts").select("id, label, is_active").order("label");return t||[]}}),{data:o=[]}=K({queryKey:["supplier-numbers-for-pool",E],queryFn:async()=>{if(E==="none"||!E)return[];const{data:t}=await h.from("api_number_pool_members").select("sending_number_id"),i=new Set((t||[]).map(y=>y.sending_number_id)),{data:f}=await h.from("sending_numbers").select("id, phone_number, status").eq("supplier_account_id",E).eq("status","active").order("phone_number");return(f||[]).filter(y=>!i.has(y.id))},enabled:E!=="none"&&!!E}),{data:ve}=K({queryKey:["api-pool",n.dedicated_number_pool_id],queryFn:async()=>{if(!n.dedicated_number_pool_id)return null;const{data:t}=await h.from("api_number_pool_members").select("sending_number_id, sending_numbers(phone_number, status, daily_send_count)").eq("pool_id",n.dedicated_number_pool_id);return t||[]}}),{data:Ce={}}=K({queryKey:["api-pool-sent-today",n.id],refetchInterval:3e4,queryFn:async()=>{const t=new Date(new Date().toLocaleString("en-US",{timeZone:"America/New_York"})),i=new Date(t);i.setHours(0,0,0,0);const f=new Date().getTime()-t.getTime(),y=new Date(i.getTime()+f).toISOString(),C={};let ce=0;for(;;){const{data:xe,error:we}=await h.from("api_sms_log").select("from_phone").eq("api_key_id",n.id).gte("created_at",y).not("status","in","(inbound,opt_out)").range(ce,ce+999);if(we||!xe||xe.length===0)break;for(const a of xe){const p=a.from_phone;if(!p)continue;const _=p.startsWith("+")?p:`+${p.replace(/\D/g,"")}`;C[_]=(C[_]||0)+1}if(xe.length<1e3)break;ce+=1e3}return C}}),{data:Z=[]}=K({queryKey:["api-ledger",n.id],queryFn:async()=>{const{data:t}=await h.from("api_credit_ledger").select("*").eq("api_key_id",n.id).order("created_at",{ascending:!1}).limit(20);return t||[]}});function de(t){const i=t.replace(/[^\d.]/g,""),[f,y]=i.split("."),C=f.replace(/\B(?=(\d{3})+(?!\d))/g,",");return y!==void 0?`${C}.${y.slice(0,2)}`:C}function _e(t){return parseFloat(t.replace(/,/g,"")||"0")}async function Ie(){var C;const t=Math.round(_e(N)*100);if(!t)return;const i=await h.auth.getUser(),f=re?`manual_grant [SALE] [$${(t/100).toFixed(2)}]`:"manual_grant",{error:y}=await h.rpc("api_grant_credits",{_api_key_id:n.id,_cents:t,_reason:f,_reference_id:D,_admin_id:(C=i.data.user)==null?void 0:C.id});if(y)return d({title:"Failed",description:y.message,variant:"destructive"});d({title:`Granted $${(t/100).toFixed(2)}`,description:re?"Recorded in Sales":"Not counted as a sale"}),j(""),w()}async function $e(){var a;const t=me.split(` 25`).map(p=>
25p.trim()).filter(Boolean),i=z.split(` 26`).map(p=>p.trim()).filter(Boolean),f=E==="none"?null:E;let y=n.dedicated_number_pool_id;if(f&&f!==n.assigned_supplier_account_id){const{data:p}=await h.from("sending_numbers").select("id").eq("supplier_account_id",f);if(!p||p.length===0){d({title:"No numbers found",description:"That supplier has no sending numbers yet. Add numbers to the supplier first.",variant:"destructive"});return}const{data:_}=await h.from("api_number_pool_members").select("sending_number_id"),I=new Set((_||[]).map(X=>X.sending_number_id)),ne=p.filter(X=>!I.has(X.id));if(ne.length===0){d({title:"No free numbers on this supplier",description:`All ${p.length} numbers are already assigned to other customers' pools. Add new numbers to this supplier, or remove some from an existing pool first.`,variant:"destructive"});return}const{data:ye,error:ke}=await h.from("api_number_pools").insert({name:`${n.name} â ${((a=pe.find(X=>X.id===f))==null?void 0:a.label)||"Pool"}`,owner_api_key_id:n.id,supplier_account_id:f}).select("id").single();if(ke||!ye){d({title:"Pool create failed",description:ke==null?void 0:ke.message,variant:"destructive"});return}y=ye.id;const Le=ne.map(X=>({pool_id:y,sending_number_id:X.id})),{error:Ne}=await h.from("api_number_pool_members").insert(Le);if(Ne){await h.from("api_number_pools").delete().eq("id",ye.id),d({title:"Pool member insert failed",description:Ne.message,variant:"destructive"});return}d({title:`Pool created with ${ne.length} number${ne.length===1?"":"s"}`,description:p.length!==ne.length?`${p.length-ne.length} number(s) skipped â already in another pool.`:void 0})}else f||(y=null);const C=parseFloat(G)||0,ce=parseFloat(ae)||0,xe=C!==Number(n.sms_rate_cents??0)||ce!==Number(n.ca_sms_rate_cents??0),{error:we}=await h.from("api_keys").update({rates_email:m.trim()||null,allowed_ips:t.length?t:null,opt_out_keywords:i.length?i:null,sandbox_mode:ue,auto_fix_compliance:O,auto_fix_countries:(()=>{const p=F.split(/[,\s]+/).map(_=>_.trim().toUpperCase()).filter(Boolean);return p.length?p:null})(),mms_from_link_enabled:B,rate_limit_rps:H?parseInt(H,10):null,sms_rate_cents:parseFloat(G)||0,mms_rate_cents:parseFloat(J)||0,ca_sms_rate_cents:parseFloat(ae)||0,ca_mms_rate_cents:parseFloat(s)||0,quote_currency:v==="EUR"?"EUR":"USD",webhook_url:ie.trim()||null,assigned_supplier_account_id:f,dedicated_number_pool_id:y}).eq("id",n.id);if(we)return d({title:"Save failed",description:we.message,variant:"destructive"});if(d({title:"Settings saved"}),xe&&C>0){const{data:p,error:_}=await h.functions.invoke("send-api-rate-notification",{body:{api_key_id:n.id,trigger:"rate_change"}});_?d({title:"Rate saved, notification failed",description:_.message,variant:"destructive"}):p!=null&&p.sent&&d({title:"Updated rate notification sent",description:`Sent to ${p.to}`})}w()}return e.jsx(ms,{open:!0,onOpenChange:t=>{t||w()},children:e.jsxs(us,{className:"w-[calc(100vw-1.5rem)] max-w-3xl max-h-[88vh] overflow-y-auto p-4 sm:p-6",children:[e.jsxs(Ye,{children:[e.jsx(Je,{children:n.name}),e.jsx(hs,{children:e.jsxs("code",{className:"text-xs",children:[n.key_prefix,"â¦"]})})]}),e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"p-4 border rounded space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm text-muted-foreground",children:"Current Balance"}),e.jsxs("div",{className:"text-2xl font-bold",children:["$",(n.credit_balance_cents/100).toLocaleString(void 0,{minimumFractionDigits:2,maximumFractionDigits:2})]})]}),e.jsx(ps,{className:"h-6 w-6 text-muted-foreground"})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(x,{placeholder:"$0.00",type:"text",inputMode:"decimal",value:N?`$${de(N)}`:"",onChange:t=>{const i=t.target.value.startsWith("$")?t.target.value.slice(1):t.target.value;j(de(i))}}),e.jsx(x,{placeholder:"Reason / reference",value:D,onChange:t=>L(t.target.value)}),e.jsx(g,{onClick:Ie,children:"Grant"})]}),e.jsxs("label",{className:"flex items-center gap-2 text-xs text-muted-foreground cursor-pointer select-none",children:[e.jsx(Ps,{checked:re,onCheckedChange:t=>M(t===!0)}),"Count as a sale (adds to Sales revenue). Uncheck for free test credits."]})]}),e.jsx(qs,{apiKey:n}),e.jsxs("div",{className:"p-4 border rounded",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(Is,{className:"h-4 w-4"})," ",e.jsx("strong",{children:"Dedicated Pool"})]}),ve&&ve.length>0?e.jsx("div",{className:"text-xs space-y-1",children:ve.map(t=>{var i,f;return e.jsxs("div",{className:"flex justify-between",children:[e.jsx("code",{children:(i=t.sending_numbers)==null?void 0:i.phone_number}),e.jsxs("span",{className:"text-muted-foreground",children:[(()=>{var ce;const y=((ce=t.sending_numbers)==null?void 0:ce.phone_number)||"",C=y.startsWith("+")?y:`+${y.replace(/\D/g,"")}`;return Ce[C]||0}
26)()," sent today · ",(f=t.sending_numbers)==null?void 0:f.status]})]},t.sending_number_id)})}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"No pool assigned â falls back to user's first active number."})]}),e.jsxs("div",{className:"p-4 border rounded space-y-3",children:[e.jsx("strong",{children:"Settings"}),e.jsxs("div",{children:[e.jsx(l,{children:"Dedicated Supplier"}),e.jsxs(ts,{value:E,onValueChange:ge,children:[e.jsx(as,{children:e.jsx(ns,{placeholder:"Select supplier"})}),e.jsxs(rs,{children:[e.jsx(Re,{value:"none",children:"â None (fallback to user's number) â"}),pe.map(t=>e.jsxs(Re,{value:t.id,children:[t.label,t.is_active?"":" (inactive)"]},t.id))]})]}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["Selecting a supplier auto-creates a dedicated pool from that supplierâs active numbers. Manage or upload numbers on the"," ",e.jsx(Ve,{to:"/supplier-numbers",className:"underline",target:"_blank",children:"Supplier Numbers"})," ","page before assigning them here."]}),E!=="none"&&e.jsxs("div",{className:"mt-3 rounded border bg-muted/40 p-3",children:[e.jsx("div",{className:"text-xs font-medium mb-2",children:o.length===0?"No available numbers":`${o.length} active number${o.length===1?"":"s"} will join this pool`}),o.length>0&&e.jsx("div",{className:"max-h-28 overflow-y-auto space-y-0.5",children:o.map(t=>e.jsxs("div",{className:"flex items-center justify-between text-xs",children:[e.jsx("code",{className:"text-[11px]",children:t.phone_number}),e.jsx(b,{variant:"outline",className:"text-[10px] h-4 px-1",children:t.status})]},t.id))}),o.length===0&&e.jsx("p",{className:"text-xs text-destructive",children:"No active, unassigned numbers for this supplier. Add numbers in Supplier Numbers, or free numbers from another pool first."})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("div",{children:[e.jsx(l,{children:"SMS rate (¢)"}),e.jsx(x,{type:"number",step:"0.01",value:G,onChange:t=>Y(t.target.value)})]}),e.jsxs("div",{children:[e.jsx(l,{children:"MMS rate (¢)"}),e.jsx(x,{type:"number",step:"0.01",value:J,onChange:t=>W(t.target.value)})]}),e.jsxs("div",{children:[e.jsx(l,{children:"Canada SMS rate (¢)"}),e.jsx(x,{type:"number",step:"0.01",value:ae,onChange:t=>he(t.target.value)})]}),e.jsxs("div",{children:[e.jsx(l,{children:"Canada MMS rate (¢)"}),e.jsx(x,{type:"number",step:"0.01",value:s,onChange:t=>c(t.target.value)})]}),e.jsxs("div",{children:[e.jsx(l,{children:"Rate limit (rps)"}),e.jsx(x,{type:"number",value:H,onChange:t=>te(t.target.value),placeholder:"unlimited"})]}),e.jsxs("div",{className:"flex items-center gap-2 pt-6",children:[e.jsx(Te,{checked:ue,onCheckedChange:U}),e.jsx(l,{className:"!mt-0",children:"Sandbox mode"})]})]}),e.jsxs("div",{className:"rounded-md border p-3 space-y-2",children:[e.jsx(l,{children:"Rates email (their rate department)"}),e.jsx(x,{placeholder:"[email protected]",value:m,onChange:t=>u(t.target.value)}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(l,{className:"!mt-0 text-xs",children:"Quote currency"}),e.jsxs(ts,{value:v,onValueChange:A,children:[e.jsx(as,{className:"h-8 w-28",children:e.jsx(ns,{})}),e.jsxs(rs,{children:[e.jsx(Re,{value:"USD",children:"USD"}),e.jsx(Re,{value:"EUR",children:"EUR"})]})]}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"EUR converts from USD at the ECB daily reference rate."})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Official USA + Canada rate sheet (MCC 310/311/312/313/316 and 302, MNC all, per segment) with a CSV download goes here. Sent automatically at onboarding and whenever you change the US or Canada SMS rate.",n.rates_notified_at?` Last sent ${new Date(n.rates_notified_at).toLocaleString("en-US",{timeZone:"America/New_York",month:"short",day:"numeric",hour:"numeric",minute:"2-digit"})} ET at ${n.rates_notified_rate_cents??"â"}¢.`:" Not sent yet."]}),e.jsx(g,{variant:"outline",size:"sm",disabled:R,onClick:async()=>{const t=m.trim();if(!t)return d({title:"Enter a rates email first",variant:"destructive"});if(q(!0),t!==(n.rates_email||"")){const{error:y}=await h.from("api_keys").update({rates_email:t}).eq("id",n.id);if(y)return q(!1),d({title:"Could not save rates email",description:y.message,variant:"destructive"})}const{data:i,error:f}=await h.functions.invoke("send-api-rate-notification",{body:{api_key_id:n.id,trigger:"manual",force:!0}});if(q(!1),f)return d({title:"Send failed",description:f.message,variant:"destructive"});i!=null&&i.sent?d({title:"Rate notification sent",description:`Sent to ${i.to}`}):d({title:"Not sent",description:String((i==null?void 0:i.reason)||"No recipient or rate set"),variant:"destructive"})},children:R?"Sendingâ¦":"Send rate notification"}),e.jsx(g,{variant:"secondary",size:"sm",className:"ml-2",disabled:R,onClick:async()=>{q(!0);const{data:t,error:i}=await h.functions.invoke("send-api-rate-notification",{body:{api_key_id:n.id,trigger:"manual",force:!0,test_to:"[email protected]",currency:v}});if(q(!1),i)return d({title:"Test send failed",description:i.message,variant:"destructive"});t!=null&&t.sent?d({title:"Test sent to [email protected]"}):d({title:"Not sent",description:String((t==null?void 0:t.reason)||"unknown"),variant:"destructive"})},children:"Send test to me"})]}),e.jsxs("div",{className:"rounded-md border p-3 space-y-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Te,{checked:O,onCheckedChange:async t=>{V(t);const i=F.split(/[,\s]+/).map(y=>
26y.trim().toUpperCase()).filter(Boolean),{error:f}=await h.from("api_keys").update({auto_fix_compliance:t,auto_fix_countries:i.length?i:null}).eq("id",n.id);f?(V(!t),d({title:"Save failed",description:f.message,variant:"destructive"})):d({title:t?"Auto-rewrite turned on â saved":"Auto-rewrite turned off â saved"})}}),e.jsx(l,{className:"!mt-0",children:"Auto-rewrite blocked wording"}),O&&e.jsx(b,{variant:"outline",className:"ml-1",children:F.trim()?`${F.trim().toUpperCase()} only`:"All countries"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"On: any message our carrier-spam guard would reject is automatically reworded by AI (money amounts, rates and loan/approval pitch language removed, links and STOP text kept) and sent instead of being rejected. Applies to API and SMPP traffic. Off: the send is rejected with a suggested rewrite the customer can resend."}),O&&e.jsxs("div",{className:"pt-1 space-y-1",children:[e.jsx(l,{className:"text-xs",children:"Only these destination countries (blank = all)"}),e.jsx(x,{value:F,onChange:t=>ee(t.target.value),onBlur:async()=>{const t=F.split(/[,\s]+/).map(f=>f.trim().toUpperCase()).filter(Boolean),{error:i}=await h.from("api_keys").update({auto_fix_countries:t.length?t:null}).eq("id",n.id);d(i?{title:"Save failed",description:i.message,variant:"destructive"}:{title:"Countries saved",description:t.length?t.join(", "):"All countries"})},placeholder:"CA",className:"h-8"}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Comma-separated ISO country codes, e.g. ",e.jsx("code",{children:"CA"}),". Anything outside this list is rejected as before, never rewritten."]})]})]}),e.jsxs("div",{className:"rounded-md border p-3 space-y-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Te,{checked:B,onCheckedChange:async t=>{se(t);const{error:i}=await h.from("api_keys").update({mms_from_link_enabled:t}).eq("id",n.id);i?(se(!t),d({title:"Save failed",description:i.message,variant:"destructive"})):d({title:t?"Picture messages turned on â saved":"Picture messages turned off â saved"})}}),e.jsx(l,{className:"!mt-0",children:"Picture messages from image links"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Off by default. On: when this customer's message text contains an image link (.jpg/.png/.gif), we remove the link from the text and send it as a real picture message â the recipient sees the image with their offer link and STOP wording under it. Works over SMPP with no change on their side. Billed once at the MMS rate above; if the image is unreachable or the carrier refuses it, the original text is sent instead and the difference is refunded."})]}),e.jsxs("div",{children:[e.jsx(l,{children:"Webhook URL (customer's endpoint for DLRs & inbound replies)"}),e.jsx(x,{value:ie,onChange:t=>oe(t.target.value),placeholder:"https://customer.com/webhooks/opentxt"}),e.jsx("p",{className:"text-xs text-muted-foreground mt-1",children:"Optional. The customer sends this to you â paste it here so we POST delivery receipts and inbound replies to their server."})]}),e.jsxs("div",{children:[e.jsx(l,{children:"Allowed IPs (one per line, CIDR OK, blank = all)"}),e.jsx(Ae,{rows:3,value:me,onChange:t=>$(t.target.value),placeholder:`1.2.3.4 2710.0.0.0/24`})]}),e.jsxs("div",{children:[e.jsx(l,{children:"Custom opt-out phrases (one per line)"}),e.jsx(Ae,{rows:3,value:z,onChange:t=>Q(t.target.value),placeholder:`Stop 2 Optout 28Reply STOP 2 END`}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["Whatever opt-out wording this customer prints in their messages. Replies matching any of these are treated as a STOP: recipient goes on the global DNC list, an ",e.jsx("code",{children:"opt_out"}),' webhook fires, and the number appears in their daily opt-out CSV. Punctuation and spacing are ignored, and generic phrases (STOP, STOPALL, unsubscribe, "stop 2 optout", "stop all texts") are always detected even if left blank.']})]}),e.jsx(g,{onClick:$e,children:"Save Settings"})]}),n.connection_type==="smpp"&&e.jsx(Ls,{apiKeyId:n.id,systemId:n.smpp_system_id}),n.connection_type==="smpp"&&e.jsx(As,{apiKeyId:n.id,systemId:n.smpp_system_id||null,isSuspended:!!n.suspended_at}),n.smpp_system_id&&e.jsxs("div",{className:"p-4 border rounded space-y-3",children:[e.jsxs("div",{children:[e.jsx("strong",{className:"block",children:"Add another SMPP bind"}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["Creates a second (or third) set of bind credentials on ",e.jsx("em",{children:"this same API key"})," â same balance, rates, pool, caps and opt-out list. Applied to the live gateway instantly, no restart, no dropped traffic, and the credentials are emailed to the customer automatically."]})]}),e.jsx(g,{onClick:fe,disabled:be,children:be?"Adding bind...":"Add bind & email customer"}),T&&e.jsxs(e.Fragment,{children:[e.jsx("pre",{className:"text-[11px] bg-muted p-3 rounded overflow-x-auto",children:`Host: ${P.tcpHost} (${P.tcpIp}) 29Port: ${P.tcpPort} 30Bind type: ${P.bindType} 31system_id: ${T.system_id} 32password: ${T.password} 33Throughput: ${T.tps} msg/sec 34Same balance, rates and opt-out list as ${n.smpp_system_id}.`}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Live on the gateway: ",T.confirmed_on_gateway?"confirmed":"applied (not yet visible in health)"," · survives restarts: ",T.persisted?"yes":`no â ${T.persist_error}`," · emailed: ",T.emailed?T.email_to:`no (${T.email_error})`]}),e.jsx(g,{variant:"secondary",onClick:()=>{navigator.clipboard.writeText(`Host: ${P.tcpHost} 35Port: ${P.tcpPort} 36Bind type: ${P.bindType} 37system_id: ${T.system_id} 38password: ${T.password} 39Same balance, rates and opt-out list as ${n.smpp_system_id}.`),d({title:"Customer credentials copied"})},children:"Copy customer credentials"})]})]}),e.jsxs("div",{className:"p-4 border rounded",children:[e.jsx("strong",{className:"block mb-2",children:"Recent
39Credit Activity"}),Z.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No transactions yet."}):e.jsx("div",{className:"text-xs space-y-1 max-h-48 overflow-y-auto",children:Z.map(t=>{var i;return e.jsxs("div",{className:"flex justify-between border-b py-1",children:[e.jsxs("span",{children:[t.reason," ",e.jsx("code",{className:"text-muted-foreground",children:(i=t.reference_id)==null?void 0:i.slice(0,20)})]}),e.jsxs("span",{className:t.delta_cents>=0?"text-green-600":"text-destructive",children:[t.delta_cents>=0?"+":"","$",(t.delta_cents/100).toFixed(2)]})]},t.id)})})]})]}),e.jsx(Ze,{children:e.jsx(g,{variant:"outline",onClick:w,children:"Close"})})]})})}function qs({apiKey:n}){const{toast:w}=De(),d=cs(),[N,j]=r.useState(!1),[D,L]=r.useState(!1),re=(n.name||"").toLowerCase().replace(/\s+/g,"").includes("smsedge"),M="[email protected], [email protected], [email protected], [email protected]",me="USDC (ERC-20)",$="0xE6e97C57C25f2e3fC11f84ab014ad15B9E6183b3",[z,Q]=r.useState(re?M:""),[ue,U]=r.useState("[email protected]"),[O,V]=r.useState(""),[F,ee]=r.useState(n.name||""),[B,se]=r.useState(""),[H,te]=r.useState(""),[G,Y]=r.useState(""),[J,W]=r.useState(`OTX-${Date.now().toString().slice(-6)}`),[ae,he]=r.useState(""),[s,c]=r.useState("USD"),[v,A]=r.useState(""),[m,u]=r.useState(""),[R,q]=r.useState(me),[ie,oe]=r.useState($),[E,ge]=r.useState(""),[be,je]=r.useState("");K({queryKey:["api-key-owner",n.user_id],queryFn:async()=>{const{data:o}=await h.from("profiles").select("email, display_name").eq("user_id",n.user_id
39).maybeSingle();return o!=null&&o.email&&!z&&!re&&Q(o.email),o!=null&&o.display_name&&!O&&V(o.display_name),o}});const T=n.sms_rate_cents||0,le=parseFloat(ae||"0"),fe=T>0&&le>0?Math.floor(le*100/T):0;async function pe(){if(!z.trim()||!le){w({title:"Email and amount required",variant:"destructive"});return}if(!ie.trim()&&!E.trim()){w({title:"Add a wallet address or wire instructions",variant:"destructive"});return}const o=z.split(/[,;]/).map(_e=>_e.trim()).filter(Boolean),ve=o[0],Ce=[...o.slice(1),...ue.split(/[,;]/).map(_e=>_e.trim()).filter(Boolean)];L(!0);const{data:Z,error:de}=await h.functions.invoke("send-api-invoice",{body:{api_key_id:n.id,to:ve,cc:Ce.length?Ce.join(", "):void 0,recipient_name:O.trim()||void 0,company:F.trim()||void 0,company_address:B.trim()||void 0,company_phone:H.trim()||void 0,tax_id:G.trim()||void 0,invoice_number:J.trim(),amount_usd:le,currency:s,fx_note:v.trim()||void 0,credits_note:s==="USD"&&fe?`${fe.toLocaleString()} SMS at ${T}c each`:void 0,due_date:m.trim()||void 0,crypto_network:ie.trim()?R.trim():void 0,wallet_address:ie.trim()||void 0,wire_instructions:E.trim()||void 0,notes:be.trim()||void 0}});if(L(!1),de||Z!=null&&Z.error){w({title:"Send failed",description:(de==null?void 0:de.message)||(Z==null?void 0:Z.error),variant:"destructive"});return}w({title:`Invoice ${J} sent to ${z}`}),j(!1),d.invalidateQueries({queryKey:["admin-api-invoices"]})}return e.jsxs("div",{className:"p-4 border rounded space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ps,{className:"h-4 w-4"}),e.jsx("strong",{children:"Invoice (wire / crypto)"})]}),e.jsx(g,{size:"sm",variant:"outline",onClick:()=>j(o=>!o),children:N?"Close":"Create invoice"})]}),N&&e.jsxs("div",{className:"space-y-3",children:[e.jsx("p",{className:"text-xs text-muted-foreground",children:"Emails the customer a payable invoice. Credits are not granted automatically â use Grant above once payment clears."}),e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsxs("div",{children:[e.jsx(l,{className:"text-xs",children:"Send to"}),e.jsx(x,{value:z,onChange:o=>Q(o.target.value),placeholder:"[email protected]"})]}),e.jsxs("div",{children:[e.jsx(l,{className:"text-xs",children:"CC"}),e.jsx(x,{value:ue,onChange:o=>U(o.target.value)})]}),e.jsxs("div",{children:[e.jsx(l,{className:"text-xs",children:"Contact name"}),e.jsx(x,{value:O,onChange:o=>V(o.target.value)})]}),e.jsxs("div",{children:[e.jsx(l,{className:"text-xs",children:"Company"}),e.jsx(x,{value:F,onChange:o=>ee(o.target.value)})]}),e.jsxs("div",{children:[e.jsx(l,{className:"text-xs",children:"Invoice #"}),e.jsx(x,{value:J,onChange:o=>W(o.target.value)})]}),e.jsxs("div",{children:[e.jsxs(l,{className:"text-xs",children:["Amount (",s,")"]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(x,{type:"number",step:"0.01",value:ae,onChange:o=>he(o.target.value),placeholder:"1000.00"}),e.jsxs("select",{value:s,onChange:o=>c(o.target.value==="EUR"?"EUR":"USD"),className:"h-10 rounded-md border border-input bg-background px-2 text-sm","aria-label":"Currency",children:[e.jsx("option",{value:"USD",children:"$ USD"}),e.jsx("option",{value:"EUR",children:"⬠EUR"})]})]})]}),e.jsxs("div",{children:[e.jsx(l,{className:"text-xs",children:"Due date (optional)"}),e.jsx(x,{value:m,onChange:o=>u(o.target.value),placeholder:"Net 7 / Aug 15, 2026"})]}),e.jsxs("div",{children:[e.jsx(l,{className:"text-xs",children:"Crypto network"}),e.jsx(x,{value:R,onChange:o=>q(o.target.value),placeholder:"USDC (ERC-20)"})]})]}),e.jsxs("div",{children:[e.jsx(l,{className:"text-xs",children:"Company address (appears on the invoice)"}),e.jsx(Ae,{rows:2,value:B,onChange:o=>se(o.target.value),placeholder:`123 Main St, Suite 200 40New York, NY 10001, USA`})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsxs("div",{children:[e.jsx(l,{className:"text-xs",children:"Company phone (optional)"}),e.jsx(x,{value:H,onChange:o=>te(o.target.value),placeholder:"+1 555 123 4567"})]}),e.jsxs("div",{children:[e.jsx(l,{className:"text-xs",children:"Tax ID / VAT (optional)"}),e.jsx(x,{value:G,onChange:o=>Y(o.target.value),placeholder:"EIN / VAT number"})]})]}),e.jsxs("div",{children:[e.jsx(l,{className:"text-xs",children:"Wallet address"}),e.jsx(x,{value:ie,onChange:o=>oe(o.target.value),placeholder:"Paste wallet address"})]}),e.jsxs("div",{children:[e.jsx(l,{className:"text-xs",children:"Bank / wire instructions (optional)"}),e.jsx(Ae,{rows:3,value:E,onChange:o=>ge(o.target.value),placeholder:"Bank name, account, routing, SWIFTâ¦"})]}),e.jsxs("div",{children:[e.jsx(l,{className:"text-xs",children:"Notes (optional)"}),e.jsx(Ae,{rows:2,value:be,onChange:o=>je(o.target.value)})]}),e.jsxs("div",{children:[e.jsx(l,{className:"text-xs",children:"Conversion note (optional â shown under the amount)"}
40),e.jsx(x,{value:v,onChange:o=>A(o.target.value),placeholder:"Equivalent to $1,400.00 USD at 1.13"})]}),fe>0&&e.jsxs("div",{className:"text-xs text-muted-foreground",children:["â ",fe.toLocaleString()," SMS at ",T,"¢ each"]}),e.jsx(g,{onClick:pe,disabled:D,className:"w-full",children:D?"Sendingâ¦":"Send invoice"})]})]})}export{nt 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.