1import{j as e,J as A,I as G,r as v,e2 as X,a4 as Z,a5 as ee,t as se,u as y,C as o,w as x,x as u,a7 as m,L as K,V as b,B as E,au as te,ba as ae,bb as re,bc as T,bd as k,v as ne,ag as ie,a9 as P,aa as le,aT as de,s as p}from"./index-DFWWEXI0.js";import{u as ce}from"./useRequireAuth-D5Xeaj5U.js";import{S as oe}from"./switch-qs7FPU3i.js";import{B as R}from"./BackNav-Dq_bZWmp.js";import{T as O,a as H,b as _,c,d as Q,e as d}from"./table-DO8hGtvD.js";import{T as xe}from"./tag-B6m9cVNb.js";import{f as ue}from"./format-UreEc-k6.js";import"./safeBack-DC2FPZmg.js";function me(i){const[a,g]=v.useState(()=>Date.now());X(()=>g(Date.now()),1e3);const l=Math.max(0,new Date(i).getTime()-a),h=Math.floor(l/864e5),f=Math.floor(l%864e5/36e5),N=Math.floor(l%36e5/6e4),w=Math.floor(l%6e4/1e3);return{d:h,h:f,m:N,s:w,expired:l===0}}const q=({value:i,label:a})=>e.jsxs("div",{className:"flex flex-col items-center justify-center min-w-[3rem] rounded-md bg-background/40 backdrop-blur px-2 py-1.5 border border-white/10",children:[e.jsx("span",{className:"text-xl font-bold tabular-nums leading-none text-foreground",children:String(i).padStart(2,"0")}),e.jsx("span",{className:"text-[10px] uppercase tracking-wider text-muted-foreground mt-0.5",children:a})]});function he({promo:i}){const{d:a,h:g,m:l,s:h,expired:f}=me(i.ends_at);return f?null:e.jsxs("div",{className:"relative overflow-hidden rounded-xl border border-primary/40 bg-gradient-to-br from-primary/20 via-primary/10 to-fuchsia-500/10 p-5 shadow-lg",children:[e.jsx("div",{className:"pointer-events-none absolute -top-12 -right-12 h-40 w-40 rounded-full bg-primary/30 blur-3xl animate-pulse"}),e.jsx("div",{className:"pointer-events-none absolute -bottom-12 -left-12 h-40 w-40 rounded-full bg-fuchsia-500/20 blur-3xl"}),e.jsxs("div",{className:"relative flex flex-col md:flex-row md:items-center md:justify-between gap-4",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"rounded-lg bg-primary/20 p-2 border border-primary/30",children:e.jsx(xe,{className:"h-6 w-6 text-primary"})}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsxs("span",{className:"inline-flex items-center gap-1 rounded-full bg-primary px-2.5 py-0.5 text-xs font-bold text-primary-foreground",children:[e.jsx(A,{className:"h-3 w-3"})," LIMITED OFFER"]}),e.jsxs("span",{className:"text-2xl font-extrabold bg-gradient-to-r from-primary to-fuchsia-400 bg-clip-text text-transparent",children:["â",i.discount_pct,"% OFF"]})]}),e.jsx("h3",{className:"text-lg font-semibold mt-1 text-foreground",children:i.name}),e.jsxs("p",{className:"text-xs text-muted-foreground flex items-center gap-1 mt-0.5",children:[e.jsx(G,{className:"h-3 w-3"}),i.pack_id?"Applies to selected pack":"Applies to all credit packs"]})]})]}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[a>0&&e.jsx(q,{value:a,label:"days"}),e.jsx(q,{value:g,label:"hrs"}),e.jsx(q,{value:l,label:"min"}),e.jsx(q,{value:h,label:"sec"})]})]})]})}const j=i=>(i??0).toLocaleString("en-US");function Ne(){const{isAuthenticated:i}=ce(),{tenantId:a,role:g}=Z(),{toast:l}=ee(),h=se(),[f,N]=v.useState(null),[w,U]=v.useState(""),[V,M]=v.useState(!1),C=g==="admin"||g==="superadmin",{data:r,isLoading:W}=y({queryKey:["credit-wallet",a],enabled:!!a&&C,queryFn:async()=>{const{data:s}=await p.from("tenant_credit_wallet").select("*").eq("tenant_id",a).maybeSingle();return s??{tenant_id:a,balance_credits:0,low_balance_threshold:1e3,auto_topup_enabled:!1,auto_topup_pack_id:null,updated_at:new Date().toISOString()}}}),{data:$=[]}=y({queryKey:["credit-packages"],queryFn:async()=>{const{data:s}=await p.from("credit_packages").select("*").eq("active",!0).order("sort_order");return s??[]}}),{data:L=[]}=y({queryKey:["credit-promotions-active"],queryFn:async()=>{const s=new Date().toISOString(),{data:t}=await p.from("credit_promotions").select("id, name, discount_pct, ends_at, pack_id, active, starts_at").eq("active",!0).lte("starts_at",s).gte("ends_at",s);return t??[]}}),z=s=>{const t=L.filter(n=>n.pack_id===null||n.pack_id===s);return t.length===0?null:t.reduce((n,S)=>S.discount_pct>n.discount_pct?S:n)},{data:F=[]}=y({queryKey:["credit-ledger",a],enabled:!!a&&C,queryFn:async()=>{const{data:s}=await p.from("credit_ledger").select("*").eq("tenant_id",a).order("created_at",{ascending:!1}).limit(100);return s??[]}}),{data:B=[]}=y({queryKey:["credit-caps",a],enabled:!!a&&C,queryFn:async()=>{const{data:s}=await p.from("tenant_user_credit_caps").select("user_id, monthly_cap_credits, period_consumed, period_start").eq("tenant_id",a);return s??[]}}),I=v.useMemo(()=>{const s=Date.now()-2592e6;return F.filter(t=>t.kind==="debit"&&new Date(t.created_at).getTime()>=s).reduce((t,n)=>t+Math.abs(n.delta),0)},[F]),J=r?r.balance_credits<r.low_balance_threshold:!1,Y=async s=>{N(s);try{const{data:t,error:n}=await p.functions.invoke("create-credit-checkout",{body:{pack_id:s}});if(n)throw n;t!=null&&t.demo?(l({title:"Demo top-up applied",description:"Credits added to your demo wallet."}),h.invalidateQueries({queryKey:["credit-wallet"]}),h.invalidateQueries({queryKey:["credit-ledger"]})):t!=null&&t.url&&(window.location.href=t.url)}catch(t){l({title:"Checkout failed",description:t instanceof Error?t.message:String(t),variant:"destructive"})}finally{N(null)}},D=async s=>{if(!a)return;M(!0);const{error:t}=await p.from("tenant_credit_wallet").upsert({tenant_id:a,...r,...s,updated_at:new Date().toISOString()},{onConflict:"tenant_id"});M(!1),t?l({title:"Save failed",description:t.message,variant:"destructive"}):(h.invalidateQueries({queryKey:["credit-wallet"]}),l({title:"Settings saved"}))};return i?C?e.jsxs("div",{className:"container mx-auto py-8 space-y-6",children:[e.jsx(R,{}),e.jsxs("header",{children:[e.jsxs("h1",{className:"text-3xl font-bold flex items-center gap-2",children:[e.jsx(A,{className:"h-7 w-7 text-primary"}),"AI Credits"]}),e.jsx("p",{className:"text-muted-foreground",children:"Buy coin packs and set per-user limits to keep AI features available across your team."})]}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-3",children:[e.jsxs(o,{children:[e.jsxs(x,{children:[e.jsx(m,{children:"Current balance"}),e.jsx(u,{className:"text-3xl",children:W?e.jsx(K,{className:"h-6 w-6 animate-spin"}):j(r==null?void 0:r.balance_credits)})]}),e.jsx(b,{children:J&&e.jsxs(E,{variant:"destructive",className:"gap-1",children:[e.jsx(te,{className:"h-3 w-3"})," Low balance"]})})]}),e.jsx(o,{children:e.jsxs(x,{children:[e.jsx(m,{children:"Last 30 days consumption"}),e.jsx(u,{className:"text-3xl",children:j(I)})]})}),e.jsx(o,{children:e.jsxs(x,{children:[e.jsx(m,{children:"Estimated days remaining"}),e.jsx(u,{className:"text-3xl",children:I>0&&r?Math.max(0,Math.floor(r.balance_credits/I*30)):"â"})]})})]}),e.jsxs(ae,{defaultValue:"buy",children:[e.jsxs(re,{children:[e.jsx(T,{value:"buy",children:"Buy credits"}),e.jsx(T,{value:"settings",children:"Auto top-up"}),e.jsx(T,{value:"caps",children:"User caps"}),e.jsx(T,{value:"ledger",children:"Activity log"})]}),e.jsxs(k,{value:"buy",className:"space-y-4",children:[L.filter(s=>s.pack_id===null).slice(0,1).map(s=>e.jsx(he,{promo:s},s.id)),e.jsxs("div",{className:"rounded-lg border border-emerald-500/30 bg-emerald-500/5 px-4 py-2 text-xs text-muted-foreground flex items-center gap-2",children:[e.jsx(A,{className:"h-3.5 w-3.5 text-emerald-500"}),e.jsxs("span",{children:[e.jsx("strong",{className:"text-foreground",children:"Credits never expire."})," Top-up credits stay in your wallet for as long as your workspace is active."]})]}),e.jsx("div",{className:"grid gap-4 md:grid-cols-2 lg:grid-cols-4",children:$.map(s=>{const t=z(s.id),n=t?s.eur_amount*(1-t.discount_pct/100):s.eur_amount,S=s.eur_amount-n;return e.jsxs(o,{className:`flex flex-col relative overflow-hidden transition-all ${t?"border-primary/50 shadow-[0_0_24px_-8px_hsl(var(--primary)/0.5)] ring-1 ring-primary/20":""}`,children:[t&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"absolute top-0 right-0 left-0 h-1 bg-gradient-to-r from-primary via-fuchsia-500 to-primary animate-pulse"}),e.jsx("div",{className:"absolute -top-1 -right-1 z-10",children:e.jsxs("div",{className:"bg-gradient-to-br from-primary to-fuchsia-500 text-primary-foreground text-xs font-bold px-3 py-1 rounded-bl-lg rounded-tr-md shadow-md",children:["â",t.discount_pct,"%"]})})]}),e.jsxs(x,{children:[e.jsx(u,{children:s.name}),e.jsxs(m,{children:[j(s.credits)," credits"]})]}),e.jsxs(b,{className:"flex-1",children:[t?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-baseline gap-2",children:[e.jsxs("p",{className:"text-3xl font-bold text-primary",children:["â¬",n.toFixed(2)]}),e.jsxs("p",{className:"text-sm text-muted-foreground line-through",children:["â¬",s.eur_amount.toFixed(2)]})]}),e.jsxs("p",{className:"text-xs font-semibold text-emerald-500 mt-1",children:["You save â¬",S.toFixed(2)]})]}):e.jsxs("p",{className:"text-3xl font-bold",children:["â¬",s.eur_amount.toFixed(2)]}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["â¬",(n/s.credits*1e3).toFixed(3)," / 1k credits"]})]}),e.jsxs(b,{children:[e.jsx(ne,{className:"w-full",disabled:f===s.id||!s.stripe_price_id,onClick:()=>Y(s.id),children:f===s.id?e.jsx(K,{className:"h-4 w-4 animate-spin"}):e.jsxs(e.Fragment,{children:[e.jsx(ie,{className:"h-4 w-4 mr-1"})," ",t?"Claim offer":"Buy"]})}),!s.stripe_price_id&&e.jsx("p",{className:"text-xs text-muted-foreground mt-2",children:"Stripe price not configured"})]})]},s.id)})})]}),e.jsx(k,{value:"settings",children:e.jsxs(o,{children:[e.jsxs(x,{children:[e.jsx(u,{children:"Low balance & auto top-up"}),e.jsx(m,{children:"We'll alert tenant admins by email when the wallet drops below the threshold."})]}),e.jsxs(b,{className:"space-y-4 max-w-md",children:[e.jsxs("div",{children:[e.jsx(P,{children:"Low balance threshold"}),e.jsx(le,{type:"number",value:w||(r==null?void 0:r.low_balance_threshold)||"",onChange:s=>U(s.target.value),onBlur:()=>{const s=parseInt(w,10);!Number.isNaN(s)&&s!==(r==null?void 0:r.low_balance_threshold)&&D({low_balance_threshold:s})}})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(oe,{checked:(r==null?void 0:r.auto_topup_enabled)??!1,disabled:V,onCheckedChange:s=>D({auto_topup_enabled:s})}),e.jsx(P,{children:"Enable auto top-up when threshold reached"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Auto top-up uses your saved Stripe payment method to charge the selected pack automatically. Requires at least one prior successful purchase."})]})]})}),e.jsx(k,{value:"caps",children:e.jsxs(o,{children:[e.jsxs(x,{children:[e.jsx(u,{children:"Per-user monthly caps"}),e.jsx(m,{children:"Limit how many credits each user can spend per calendar month. Add caps via the API or set them per-user in Team settings."})]}),e.jsx(b,{children:e.jsxs(O,{children:[e.jsx(H,{children:e.jsxs(_,{children:[e.jsx(c,{children:"User ID"}),e.jsx(c,{className:"text-right",children:"Monthly cap"}),e.jsx(c,{className:"text-right",children:"Used this month"}),e.jsx(c,{className:"text-right",children:"Remaining"})]})}),e.jsxs(Q,{children:[B.length===0&&e.jsx(_,{children:e.jsx(d,{colSpan:4,className:"text-center text-muted-foreground",children:"No caps configured â all users share the tenant pool."})}),B.map(s=>e.jsxs(_,{children:[e.jsxs(d,{className:"font-mono text-xs",children:[s.user_id.slice(0,8),"â¦"]}),e.jsx(d,{className:"text-right",children:j(s.monthly_cap_credits)}),e.jsx(d,{className:"text-right",children:j(s.period_consumed)}),e.jsx(d,{className:"text-right",children:j(Math.max(0,s.monthly_cap_credits-s.period_consumed))})]}
1,s.user_id))]})]})})]})}),e.jsx(k,{value:"ledger",children:e.jsxs(o,{children:[e.jsxs(x,{children:[e.jsx(u,{children:"Recent activity"}),e.jsx(m,{children:"Last 100 credit movements."})]}),e.jsx(b,{children:e.jsxs(O,{children:[e.jsx(H,{children:e.jsxs(_,{children:[e.jsx(c,{children:"When"}),e.jsx(c,{children:"Kind"}),e.jsx(c,{children:"Feature / Model"}),e.jsx(c,{className:"text-right",children:"Tokens (in/out)"}),e.jsx(c,{className:"text-right",children:"Î Credits"})]})}),e.jsx(Q,{children:F.map(s=>e.jsxs(_,{children:[e.jsx(d,{className:"text-xs",children:ue(new Date(s.created_at),"MMM d, HH:mm")}),e.jsx(d,{children:e.jsx(E,{variant:s.kind==="debit"?"secondary":"default",children:s.kind})}),e.jsxs(d,{className:"text-xs",children:[s.feature||"â",s.model&&e.jsx("div",{className:"text-muted-foreground",children:s.model})]}),e.jsxs(d,{className:"text-right text-xs",children:[s.tokens_in??0," / ",s.tokens_out??0]}),e.jsxs(d,{className:`text-right font-mono ${s.delta<0?"text-destructive":"text-primary"}`,children:[s.delta>0?"+":"",j(s.delta)]})]},s.id))})]})})]})})]}),e.jsxs("p",{className:"text-xs text-muted-foreground flex items-center gap-1",children:[e.jsx(de,{className:"h-3 w-3"}),"Need a custom volume? Contact sales for enterprise pricing."]})]}):e.jsxs("div",{className:"container mx-auto py-8",children:[e.jsx(R,{}),e.jsx(o,{children:e.jsxs(x,{children:[e.jsx(u,{children:"AI Credits"}),e.jsx(m,{children:"Only tenant administrators can view AI credit usage."})]})})]}):null}export{Ne 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.