PageSourceSearch

https://getasearch.com/assets/AdminAffiliateLinks-DXvGR7je.js

js getasearch.com collected 2026-10-06 13:21:18 UTC 17,052 bytes, 7 lines download raw bytes

vendor: 4,511 bytes, lines 1-7
1import{j as e,b as Le,u as q,c as b}from"./react-query-Br9_NlfO.js";import{r as l}from"./react-vendor-DZkXyRe8.js";import{L as z}from"./react-router-Cc9AxZTJ.js";import{A as Oe,M as Me,S as Fe}from"./AdminLayout-EJf-QRQ9.js";import{C as S,b as P,c as T,a as E}from"./card-GwDPSfZc.js";import{B as Ie}from"./badge-DKagaWvU.js";import{b as Y,B as D,I as p}from"./input-Cph_Ex22.js";import{S as $e}from"./switch-DXsJq3GX.js";import{s as _}from"./client-DE87q3gr.js";import{h as qe,k as X,j as ze,a0 as Qe,m as j,X as Ve,a1 as y}from"./index-CSnxIWtb.js";import{D as Ke,a as Be,b as Ge,c as He,d as Ue}from"./dialog-ct_EF4N6.js";import{L as g}from"./label-Dd65Khbj.js";import{S as Q,a as V,b as K,c as B,d as G}from"./select-f8lMmx9P.js";import{c as J,b as We,O as Ye,W as Xe,C as Je,T as Ze,D as es,a as Z,R as ss,P as as}from"./index-BlcGjADQ.js";import{C as H}from"./chart-column-CQRjtPvx.js";import{P as ts}from"./plus-C-H9EbQE.js";import{S as rs}from"./Combination-B8_CmWI-.js";import{C as os}from"./check-DiItZnjw.js";import{C as is}from"./copy-Dx6poKT5.js";import{E as ls}from"./external-link-BjaPn3J9.js";import{S as ns}from"./save-Ce0z3-9n.js";import"./use-mobile-BFYSgWyL.js";import"./useAuth-0FMbkzgw.js";import"./layout-dashboard-2SgE-LaP.js";import"./dollar-sign-Hn2N_DN1.js";import"./activity-DnwJNe1o.js";import"./link-2-CoZoy-IR.js";import"./bot-CmEyFW9F.js";import"./index-CrtxyJRT.js";import"./supabase-nOMv1ksJ.js";import"./index-BdQq_4o_.js";import"./index-CGUmMvnP.js";import"./chevron-down-BsAGxCDq.js";import"./chevron-up-Ckg9TmBm.js";var ee="AlertDialog",[cs,ta]=qe(ee,[J]),x=J(),se=t=>{const{__scopeAlertDialog:a,...r}=t,n=x(a);return e.jsx(ss,{...n,...r,modal:!0})};se.displayName=ee;var ds="AlertDialogTrigger",ms=l.forwardRef((t,a)=>{const{__scopeAlertDialog:r,...n}=t,c=x(r);return e.jsx(We,{...c,...n,ref:a})});ms.displayName=ds;var us="AlertDialogPortal",ae=t=>{const{__scopeAlertDialog:a,...r}=t,n=x(a);return e.jsx(as,{...n,...r})};ae.displayName=us;var gs="AlertDialogOverlay",te=l.forwardRef((t,a)=>{const{__scopeAlertDialog:r,...n}=t,c=x(r);return e.jsx(Ye,{...c,...n,ref:a})});te.displayName=gs;var w="AlertDialogContent",[ps,xs]=cs(w),fs=Qe("AlertDialogContent"),re=l.forwardRef((t,a)=>{const{__scopeAlertDialog:r,children:n,...c}=t,v=x(r),f=l.useRef(null),k=X(a,f),C=l.useRef(null);return e.jsx(Xe,{contentName:w,titleName:oe,docsSlug:"alert-dialog",children:e.jsx(ps,{scope:r,cancelRef:C,children:e.jsxs(Je,{role:"alertdialog",...v,...c,ref:k,onOpenAutoFocus:ze(c.onOpenAutoFocus,d=>{d.preventDefault(),C.current?.focus({preventScroll:!0})}),onPointerDownOutside:d=>d.preventDefault(),onInteractOutside:d=>d.preventDefault(),children:[e.jsx(fs,{children:n}),e.jsx(js,{contentRef:f})]})})})});re.displayName=w;var oe="AlertDialogTitle",ie=l.forwardRef((t,a)=>{const{__scopeAlertDialog:r,...n}=t,c=x(r);return e.jsx(Ze,{...c,...n,ref:a})});ie.displayName=oe;var le="AlertDialogDescription",ne=l.forwardRef((t,a)=>{const{__scopeAlertDialog:r,...n}=t,c=x(r);return e.jsx(es,{...c,...n,ref:a})});ne.displayName=le;var hs="AlertDialogAction",ce=l.forwardRef((t,a)=>{const{__scopeAlertDialog:r,...n}=t,c=x(r);return e.jsx(Z,{...c,...n,ref:a})});ce.displayName=hs;var de="AlertDialogCancel",me=l.forwardRef((t,a)=>{const{__scopeAlertDialog:r,...n}=t,{cancelRef:c}=xs(de,r),v=x(r),f=X(a,c);return e.jsx(Z,{...v,...n,ref:f})});me.displayName=de;var js=({contentRef:t})=>{const a=`\`${w}\` requires a description for the component to be accessible for screen reader users.
2
3You can add a description to the \`${w}\` by passing a \`${le}\` component as a child, which also benefits sighted users by adding visible context to the dialog.
4
5Alternatively, you can use your own component as a description by assigning it an \`id\` and passing the same value to the \`aria-describedby\` prop in \`${w}\`. If the description is confusing or duplicative for sighted users, you can use the \`@radix-ui/react-visually-hidden\` primitive as a wrapper around your description component.
6
7For more information, see https://radix-ui.com/primitives/docs/components/alert-dialog`;return l.useEffect(()=>{document.getElementById(t.current?.getAttribute("aria-describedby"))||console.warn(a)},[a,t]),null},vs=se,Ns=ae,ue=te,ge=re,pe=ce,xe=me,fe=ie,he=ne;const ys=vs,Cs=Ns,je=l.forwardRef(({className:t,...a},r)=>e.jsx(ue,{className:j("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",t),...a,ref:r}));
7je.displayName=ue.displayName;const ve=l.forwardRef(({className:t,...a},r)=>e.jsxs(Cs,{children:[e.jsx(je,{}),e.jsx(ge,{ref:r,className:j("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",t),...a})]}));ve.displayName=ge.displayName;const Ne=({className:t,...a})=>e.jsx("div",{className:j("flex flex-col space-y-2 text-center sm:text-left",t),...a});Ne.displayName="AlertDialogHeader";const ye=({className:t,...a})=>e.jsx("div",{className:j("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",t),...a});ye.displayName="AlertDialogFooter";const Ce=l.forwardRef(({className:t,...a},r)=>e.jsx(fe,{ref:r,className:j("text-lg font-semibold",t),...a}));Ce.displayName=fe.displayName;const Ae=l.forwardRef(({className:t,...a},r)=>e.jsx(he,{ref:r,className:j("text-sm text-muted-foreground",t),...a}));Ae.displayName=he.displayName;const De=l.forwardRef(({className:t,...a},r)=>e.jsx(pe,{ref:r,className:j(Y(),t),...a}));De.displayName=pe.displayName;const _e=l.forwardRef(({className:t,...a},r)=>e.jsx(xe,{ref:r,className:j(Y({variant:"outline"}),"mt-2 sm:mt-0",t),...a}));_e.displayName=xe.displayName;const U={slug:"",software_slug:"",program_name:"",destination_url:"",commission:"",category:"",notes:"",is_active:!0},W=["crypto-exchanges","trading-platforms","forex-brokers","robo-advisors","seo-tools","crm","ai-writing","vpn","tax-software","accounting","crypto-tax","ecommerce","budgeting-apps","ai-tools"];function ra(){const t=Le(),[a,r]=l.useState(""),[n,c]=l.useState(!1),[v,f]=l.useState(null),[k,C]=l.useState(null),[d,N]=l.useState({}),[m,h]=l.useState(U),[we,L]=l.useState(null),{data:A=[],isLoading:be}=q({queryKey:["admin-affiliate-links"],queryFn:async()=>{const{data:s,error:i}=await _.from("affiliate_links").select("*").order("program_name",{ascending:!0});if(i)throw i;return s||[]}}),{data:O={}}=q({queryKey:["admin-affiliate-click-counts"],queryFn:async()=>{const{data:s,error:i}=await _.from("affiliate_clicks").select("slug");if(i)return{};const u={};return(s||[]).forEach(o=>{u[o.slug]=(u[o.slug]||0)+1}),u}}),M=b({mutationFn:async({id:s,...i})=>{const{error:u}=await _.from("affiliate_links").update(i).eq("id",s);if(u)throw u},onSuccess:()=>{t.invalidateQueries({queryKey:["admin-affiliate-links"]}),C(null),N({}),y.success("Saved")},onError:s=>y.error(s.message)}),R=b({mutationFn:async s=>{const i={slug:s.slug.trim().toLowerCase(),software_slug:s.software_slug?.trim()||null,program_name:s.program_name.trim(),destination_url:s.destination_url.trim(),commission:s.commission?.trim()||null,category:s.category||null,notes:s.notes?.trim()||null,is_active:s.is_active},{error:u}=await _.from("affiliate_links").insert(i);if(u)throw u},onSuccess:()=>{t.invalidateQueries({queryKey:["admin-affiliate-links"]}),c(!1),h(U),y.success("Link created")},onError:s=>y.error(s.message)}),Se=b({mutationFn:async({id:s,is_active:i})=>{const{error:u}=await _.from("affiliate_links").update({is_active:i}).eq("id",s);if(u)throw u},onSuccess:()=>{t.invalidateQueries({queryKey:["admin-affiliate-links"]})},onError:s=>y.error(s.message)}),Ee=b({mutationFn:async s=>{const{error:i}=await _.from("affiliate_links").delete().eq("id",s);if(i)throw i},onSuccess:()=>{t.invalidateQueries({queryKey:["admin-affiliate-links"]}),f(null),y.success("Link deleted")},onError:s=>y.error(s.message)}),ke=s=>{C(s.id),N({destination_url:s.destination_url,commission:s.commission||"",category:s.category||"",notes:s.notes||""})},Re=()=>{C(null),N({})},Pe=s=>{M.mutate({id:s,destination_url:d.destination_url,commission:d.commission||null,category:d.category||null,notes:d.notes||null})},Te=s=>{navigator.clipboard.writeText(`https://getasearch.com/go/${s}`),L(s),setTimeout(()=>L(null),2e3)},F=l.useMemo(()=>
7{if(!a)return A;const s=a.toLowerCase();return A.filter(i=>i.program_name.toLowerCase().includes(s)||i.slug.toLowerCase().includes(s)||(i.category||"").toLowerCase().includes(s))},[A,a]),I=A.filter(s=>s.is_active).length,$=Object.values(O).reduce((s,i)=>s+i,0);return e.jsxs(Oe,{children:[e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl sm:text-2xl font-bold text-foreground",children:"Affiliate Links"}),e.jsxs("p",{className:"text-sm text-muted-foreground mt-1",children:[A.length," total · ",I," active · ",$," clicks ·"," ",e.jsxs(z,{to:"/admin/affiliate-stats/",className:"text-primary hover:underline inline-flex items-center gap-1",children:[e.jsx(H,{className:"h-3 w-3"})," View stats"]})]})]}),e.jsxs(D,{onClick:()=>c(!0),size:"sm",className:"gap-2",children:[e.jsx(ts,{className:"h-4 w-4"})," Add Link"]})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-3",children:[e.jsxs(S,{className:"border-l-4 border-l-primary",children:[e.jsx(P,{className:"pb-2",children:e.jsx(T,{className:"text-sm font-medium text-muted-foreground",children:"Total Links"})}),e.jsx(E,{children:e.jsx("div",{className:"text-2xl font-bold",children:A.length})})]}),e.jsxs(S,{className:"border-l-4 border-l-accent",children:[e.jsx(P,{className:"pb-2",children:e.jsx(T,{className:"text-sm font-medium text-muted-foreground",children:"Active"})}),e.jsx(E,{children:e.jsx("div",{className:"text-2xl font-bold",children:I})})]}),e.jsxs(S,{className:"border-l-4 border-l-secondary",children:[e.jsx(P,{className:"pb-2",children:e.jsxs(T,{className:"text-sm font-medium text-muted-foreground flex items-center gap-1",children:[e.jsx(Me,{className:"h-3.5 w-3.5"})," Clicks"]})}),e.jsx(E,{children:e.jsx("div",{className:"text-2xl font-bold",children:$})})]})]}),e.jsxs("div",{className:"relative w-full sm:w-80",children:[e.jsx(rs,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(p,{placeholder:"Search programs, slugs, categories...",value:a,onChange:s=>r(s.target.value),className:"pl-9 h-9 text-sm"})]}),be?e.jsx("div",{className:"space-y-3",children:Array.from({length:6}).map((s,i)=>e.jsx(Fe,{className:"h-20 w-full"},i))}):F.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:a?"No links match your search.":"No affiliate links yet."}):e.jsx("div",{className:"space-y-2",children:F.map(s=>{const i=k===s.id,u=O[s.slug]||0;return e.jsx(S,{className:`transition-all ${i?"ring-2 ring-primary":"cursor-pointer hover:bg-muted/30"}`,onClick:()=>!i&&ke(s),children:e.jsxs(E,{className:"p-4",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[e.jsx("span",{className:"font-semibold text-sm",children:s.program_name}),e.jsxs("button",{onClick:o=>{o.stopPropagation(),Te(s.slug)},className:"flex items-center gap-1 text-xs font-mono text-muted-foreground hover:text-foreground transition-colors",title:"Copy /go/ URL",children:[we===s.slug?e.jsx(os,{className:"h-3 w-3 text-green-500"}):e.jsx(is,{className:"h-3 w-3"}),"/go/",s.slug]}),s.category&&e.jsx(Ie,{variant:"secondary",className:"text-xs",children:s.category}),e.jsxs("div",{className:"ml-auto flex items-center gap-3",children:[e.jsxs(z,{to:"/admin/affiliate-stats/",onClick:o=>o.stopPropagation(),className:"flex items-center gap-1 text-xs text-muted-foreground hover:text-primary transition-colors",title:"View detailed stats",children:[e.jsx(H,{className:"h-3 w-3"}),e.jsx("span",{className:"font-mono tabular-nums",children:u})]}),e.jsx($e,{checked:s.is_active,onCheckedChange:o=>{Se.mutate({id:s.id,is_active:o})},onClick:o=>o.stopPropagation()}),e.jsx("a",{href:s.destination_url,target:"_blank",rel:"noopener noreferrer",onClick:o=>o.stopPropagation(),className:"text-muted-foreground hover:text-foreground",children:e.jsx(ls,{className:"h-3.5 w-3.5"})})]})]}),i&&e.jsxs("div",{className:"mt-3 pt-3 border-t space-y-3",onClick:o=>o.stopPropagation(),children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(g,{className:"text-xs text-muted-foreground",children:"Destination URL"}),e.jsx(p,{value:d.destination_url||"",onChange:o=>N({...d,destination_url:o.target.value}),className:"h-8 text-sm",placeholder:"https://..."})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(g,{className:"text-xs text-muted-foreground",children:"Commission"}),e.jsx(p,{value:d.commission||"",onChange:o=>N({...d,commission:o.target.value}),className:"h-8 text-sm",placeholder:"$10/signup"})]})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(g,{className:"text-xs text-muted-foreground",children:"Category"}),e.jsxs(Q,{value:d.category||"",onValueChange:o=>N({...d,category:o}),children:[e.jsx(V,{className:"h-8 text-sm",children:e.jsx(K,{placeholder:"Select..."})}),e.jsx(B,{children:W.map(o=>e.jsx(G,{value:o,children:o},o))})]})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(g,{className:"text-xs text-muted-foreground",children:"Notes"}),e.jsx(p,{value:d.notes||"",onChange:o=>N({...d,notes:o.target.value}),className:"h-8 text-sm",placeholder:"Notes..."})]})]}),e.jsxs("div",{className:"flex items-center justify-between pt-1",children:[e.jsx(D,{variant:"ghost",size:"sm",className:"text-destructive hover:text-destructive text-xs h-7",onClick:()=>f(s.id),children:"Delete"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(D,{variant:"outline",size:"sm",className:"h-7 text-xs",onClick:Re,children:[e.jsx(Ve,{className:"h-3 w-3 mr-1"})," Cancel"]}),e.jsxs(D,{size:"sm",className:"h-7 text-xs",onClick:()=>Pe(s.id),disabled:M.isPending,children:[e.jsx(ns,{className:"h-3 w-3 mr-1"})," Save"]})]})]})]})]})},s.id)})})]}),e.jsx(Ke,{open:n,onOpenChange:c,children:e.jsxs(Be,{className:"sm:max-w-lg",children:[e.jsx(Ge,{children:e.jsx(He,{children:"Add Affiliate Link"})}),e.jsxs("div",{className:"grid gap-4 py-2",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(g,{children:"Program Name *"}),e.jsx(p,{value:m.program_name,onChange:s=>h({...m,program_name:s.target.value}),placeholder:"Coinbase"})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(g,{children:"Slug *"}),e.jsx(p,{value:m.slug,onChange:s=>h({...m,slug:s.target.value}),placeholder:"coinbase"})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(g,{children:"Destination URL *"}),e.jsx(p,{value:m.destination_url,onChange:s=>h({...m,destination_url:s.target.value}),placeholder:"https://..."})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(g,{children:"Category"}),e.jsxs(Q,{value:m.category,onValueChange:s=>h({...m,category:s}),children:[e.jsx(V,{children:e.jsx(K,{placeholder:"Select..."})}),e.jsx(B,{children:W.map(s=>e.jsx(G,{value:s,children:s},s))})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(g,{children:"Commission"}),e.jsx(p,{value:m.commission,onChange:s=>h({...m,commission:s.target.value}),placeholder:"$10/signup"})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(g,{children:"Software Slug"}),e.jsx(p,{value:m.software_slug,onChange:s=>h({...m,software_slug:s.target.value}),placeholder:"coinbase"})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(g,{children:"Notes"}),e.jsx(p,{value:m.notes,onChange:s=>h({...m,notes:s.target.value}),placeholder:"Applied Feb 18..."})]})]})]}),e.jsxs(Ue,{children:[e.jsx(D,{variant:"outline",onClick:()=>c(!1),children:"Cancel"}),e.jsx(D,{onClick:()=>R.mutate(m),disabled:!m.slug||!m.program_name||!m.destination_url||R.isPending,children:R.isPending?"Creating...":"Create"})]})]})}),e.jsx(ys,{open:!!v,onOpenChange:()=>f(null),children:e.jsxs(ve,{children:[e.jsxs(Ne,{children:[e.jsx(Ce,{children:"Delete affiliate link?"}),e.jsx(Ae,{children:"This will permanently remove this /go/ redirect. Click data is preserved."})]}),e.jsxs(ye,{children:[e.jsx(_e,{children:"Cancel"}),e.jsx(De,{className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",onClick:()=>v&&Ee.mutate(v),children:"Delete"})]})]})})]})}export{ra 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.