1import{ai as W,al as X,aj as Y,u as ae,aQ as G,o as te,s as M,j as e,w as U,c as d,d as v,aT as re,B as w,r as i,a8 as ne,aS as ie,a9 as oe,aa as ce,ab as le,ac as de,V as c,W as x,an as z,ao as V,ap as H,aq as Z,ar as p,e as me,ad as xe,L as ue,t as r}from"./index-SKnbGGv2.js";import{S as he}from"./switch-CWtuZN_7.js";import{C as pe,b as fe,c as je,d as ge,a as ve}from"./card-CwTg_SLo.js";import{S as Ne}from"./shield-alert-2jrd_ANw.js";import{A as ye}from"./arrow-left-DDi8puBt.js";import{T as be}from"./tag-D2weZsV_.js";import{C as Ce}from"./copy-Bb7wzQPF.js";import{T as we}from"./trash-2-CFHEbXO7.js";const Se=W({method:"POST"}).middleware([X]).handler(Y("f90c782926a63ae37719ee42e5d452817d93cabbf61fb361b2cea09a9a7371bc")),_e=W({method:"POST"}).middleware([X]).handler(Y("2f55fc66fb1a73a96a8cbc50d49b63f048ffaca6cf6651581f98bf05da154106"));function De(o){const f=o.kind==="percent"?`${o.percent_off}% off`:o.kind==="fixed"?`$${((o.amount_off_cents??0)/100).toFixed(0)} off`:"Free (100%)",j=o.duration==="forever"?" · forever":o.duration==="repeating"?` · for ${o.duration_in_months} mo`:" · one-time";return f+j}function Ee(){const{user:o,roles:f,loading:j}=ae(),u=f.includes("admin"),h=G(),{data:m,isLoading:N}=te({queryKey:["admin-promo-codes"],queryFn:async()=>{const{data:s,error:n}=await M.from("promo_codes").select("*").order("created_at",{ascending:!1});if(n)throw n;return s??[]},enabled:u}),y=async s=>{const{error:n}=await M.from("promo_codes").update({active:!s.active}).eq("id",s.id);if(n)return r.error(n.message);h.invalidateQueries({queryKey:["admin-promo-codes"]})},g=async s=>{if(!confirm(`Delete promo code "${s.code}"? This cannot be undone.`))return;const n=await _e({data:{id:s.id}});if("error"in n)return r.error(n.error);r.success("Promo code deleted"),h.invalidateQueries({queryKey:["admin-promo-codes"]})},b=async s=>{try{await navigator.clipboard.writeText(s),r.success(`Copied "${s}"`)}catch{r.error("Couldn't copy")}};return j||N?e.jsxs("div",{className:"container mx-auto max-w-5xl px-4 py-10",children:[e.jsx(U,{className:"h-10 w-72 mb-6"}),e.jsx(U,{className:"h-96"})]}):!o||!u?e.jsxs("div",{className:"container mx-auto max-w-2xl px-4 py-16 text-center",children:[e.jsx(Ne,{className:"h-10 w-10 mx-auto text-muted-foreground"}),e.jsx("h1",{className:"text-2xl font-semibold mt-4",children:"Admins only"}),e.jsx(d,{asChild:!0,variant:"outline",className:"mt-6",children:e.jsx(v,{to:"/dashboard",children:"Back to dashboard"})})]}):e.jsxs("div",{className:"container mx-auto max-w-5xl px-4 py-10 space-y-6",children:[e.jsx("div",{children:e.jsxs(v,{to:"/admin",className:"inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors",children:[e.jsx(ye,{className:"h-3.5 w-3.5"})," Back to admin"]})}),e.jsxs("header",{className:"flex flex-wrap items-start justify-between gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-3xl font-bold tracking-tight",children:"Promo codes"}),e.jsx("p",{className:"text-muted-foreground mt-1",children:"Create codes for individual businesses, partners, conferences, or campaigns."})]}),e.jsxs("nav",{className:"flex flex-wrap gap-2",children:[e.jsx(d,{asChild:!0,variant:"ghost",size:"sm",children:e.jsx(v,{to:"/admin/review",children:"Review"})}),e.jsx(d,{asChild:!0,variant:"ghost",size:"sm",children:e.jsx(v,{to:"/admin/places",children:"Places"})}),e.jsx(d,{asChild:!0,variant:"ghost",size:"sm",children:e.jsx(v,{to:"/admin/pricing",children:"Pricing"})})]})]}),e.jsx("div",{className:"flex justify-end",children:e.jsx(Ae,{trigger:e.jsxs(d,{children:[e.jsx(re,{className:"h-4 w-4"})," New promo code"]})})}),e.jsxs(pe,{children:[e.jsxs(fe,{children:[e.jsxs(je,{children:[m?.length??0," codes"]}),e.jsx(ge,{children:"Inactive codes won't be honored at checkout."})]}),e.jsxs(ve,{className:"divide-y",children:[(!m||m.length===0)&&e.jsx("p",{className:"text-sm text-muted-foreground py-6",children:"No promo codes yet."}),m?.map(s=>{const n=s.expires_at&&new Date(s.expires_at)<new Date,l=s.max_redemptions!=null&&s.redemption_count>=s.max_redemptions;return e.jsxs("div",{className:"py-3 flex items-start justify-between gap-3 flex-wrap",children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsxs("button",{onClick:()=>b(s.code),className:"font-mono font-semibold inline-flex items-center gap-1 hover:underline",title:"Copy code",children:[e.jsx(be,{className:"h-3.5 w-3.5"})," ",s.code," ",e.jsx(Ce,{className:"h-3 w-3 opacity-60"})]}),e.jsx(w,{variant:"secondary",children:De(s)}),!s.active&&e.jsx(w,{variant:"outline",children:"Inactive"}),n&&e.jsx(w,{variant:"destructive",children:"Expired"}),l&&e.jsx(w,{variant:"destructive",children:"Exhausted"})]}),e.jsx("p",{className:"text-sm mt-1",children:s.label}),s.notes&&e.jsx("p",{className:"text-xs text-muted-foreground mt-0.5",children:s.notes}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["Used ",s.redemption_count,s.max_redemptions!=null?` / ${s.max_redemptions}`:" (no cap)",s.expires_at?` · expires ${new Date(s.expires_at).toLocaleDateString()}`:""]})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(he,{checked:s.active,onCheckedChange:()=>y(s)}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"Active"})]}),e.jsx(d,{variant:"ghost",size:"icon",onClick:()=>g(s),title:"Delete",children:e.jsx(we,{className:"h-4 w-4"})})]})]},s.id)})]})]})]})}function Ae({trigger:o}){const f=G(),[j,u]=i.useState(!1),[h,m]=i.useState(!1),[N,y]=i.useState(""),[g,b]=i.useState(""),[s,n]=i.useState(""),[l,D]=i.useState("percent"),[A,T]=i.useState("20"),[P,k]=i.useState("100"),[C,F]=i.useState("once"),[L,I]=i.useState("3"),[S,q]=i.useState(""),[_,$]=i.useState(""),J=()=>{y(""),b(""),n(""),D("percent"),T("20"),k("100"),F("once"),I("3"),q(""),$("")},ee=a=>{u(a),a&&J()},se=async()=>{const a=N.trim().toUpperCase();if(!/^[A-Z0-9_-]{3,40}$/.test(a)){r.error("Code: 3â40 chars, AâZ, 0â9, _ or -");return}if(!g.trim()){r.error("Label is required");return}let E=null,B=null;if(l==="percent"){const t=parseInt(A,10);if(!Number.isFinite(t)||t<1||t>100){r.error("Percent must be 1â100");return}E=t}else if(l==="fixed"){const t=parseFloat(P);if(!Number.isFinite(t)||t<=0){r.error("Amount must be > 0");return}B=Math.round(t*100)}let O=null;if(S.trim()){const t=parseInt(S,10);if(!Number.isFinite(t)||t<1){r.error("Max redemptions must be a positive integer");return}O=t}let Q=null;if(C==="repeating"){const t=parseInt(L,10);if(!Number.isFinite(t)||t<1||t>60){r.error("Duration months must be 1â60");return}Q=t}let R=null;if(_){const t=new Date(_);if(Number.isNaN(t.getTime())){r.error("Invalid expiry date");return}R=t.toISOString()}m(!0);const K=await Se({data:{code:a,label:g.trim(),notes:s.trim()||null,kind:l,percent_off:E,amount_off_cents:B,duration:C,duration_in_months:Q,max_redemptions:O,expires_at:R}});if(m(!1),"error"in K){r.error(K.error);return}r.success("Promo code created & synced to Stripe"),f.invalidateQueries({queryKey:["admin-promo-codes"]}),u(!1)};return e.jsxs(ne,{open:j,onOpenChange:ee,children:[e.jsx(ie,{asChild:!0,children:o}),e.jsxs(oe,{className:"max-w-lg",children:[e.jsxs(ce,{children:[e.jsx(le,{children:"New promo code"}),e.jsx(de,{children:"Share with a business, partner, or conference attendees."})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid sm:grid-cols-2 gap-3",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(c,{children:"Code"}),e.jsx(x,{value:N,onChange:a=>y(a.target.value.toUpperCase()),placeholder:"ABILITY2026",maxLength:40,className:"font-mono"})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(c,{children:"Discount type"}),e.jsxs(z,{value:l,onValueChange:a=>D(a),children:[e.jsx(V,{children:e.jsx(H,{})}),e.jsxs(Z,{children:[e.jsx(p,{value:"percent",children:"Percent off"}),e.jsx(p,{value:"fixed",children:"Fixed amount off ($)"}),e.jsx(p,{value:"comp",children:"Free / comp (100%)"})]})]})]})]}),l==="percent"&&e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(c,{children:"Percent off (1â100)"}),e.jsx(x,{type:"number",min:1,max:100,value:A,onChange:a=>T(a.target.value)})]}),l==="fixed"&&e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(c,{children:"Amount off (USD)"}),e.jsx(x,{type:"number",min:1,step:"1",value:P,onChange:a=>k(a.target.value)})]}),e.jsxs("div",{className:"grid sm:grid-cols-2 gap-3",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(c,{children:"Duration"}),e.jsxs(z,{value:C,onValueChange:a=>F(a),children:[e.jsx(V,{children:e.jsx(H,{})}),e.jsxs(Z,{children:[e.jsx(p,{value:"once",children:"One-time (first invoice)"}),e.jsx(p,{value:"repeating",children:"Repeating (X months)"}),e.jsx(p,{value:"forever",children:"Forever (every renewal)"})]})]})]}),C==="repeating"&&e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(c,{children:"Number of months (1â60)"}),e.jsx(x,{type:"number",min:1,max:60,value:L,onChange:a=>I(a.target.value),placeholder:"3"})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(c,{children:"Label (internal)"}),e.jsx(x,{value:g,onChange:a=>b(a.target.value),placeholder:"Abilities Expo 2026 attendees",maxLength:120})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(c,{children:"Notes (optional)"}),e.jsx(me,{rows:2,value:s,onChange:a=>n(a.target.value),placeholder:"Distributed at booth â expires 90 days post-event",maxLength:500})]}),e.jsxs("div",{className:"grid sm:grid-cols-2 gap-3",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(c,{children:"Total uses cap (optional)"}),e.jsx(x,{type:"number",min:1,value:S,onChange:a=>q(a.target.value),placeholder:"Unlimited"})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(c,{children:"Expires (optional)"}
1),e.jsx(x,{type:"date",value:_,onChange:a=>$(a.target.value)})]})]})]}),e.jsxs(xe,{children:[e.jsx(d,{variant:"outline",onClick:()=>u(!1),disabled:h,children:"Cancel"}),e.jsxs(d,{onClick:se,disabled:h,children:[h?e.jsx(ue,{className:"h-4 w-4 animate-spin"}):null,"Create code"]})]})]})]})}export{Ee as component};
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.