1import{q as X,b3 as Z,u as ee,r as f,b as te,z as se,b5 as ae,b6 as le,b7 as o,b9 as e,b8 as s,bd as b,a6 as m,bx as v,bw as p,ac as _,bI as re,bc as i,aL as S,b1 as oe,bG as M,bO as ne,A as ie,C as q,B as I,f as g,F as E,E as ue,b2 as de,g as ce,e as B,N as D,D as me,h as pe,aN as h}from"./index-ZTZX6O4r.js";import{Q as F}from"./QBanner-CePDC9UD.js";import{Q as y}from"./QBadge-iDo7tbmS.js";import{Q as A}from"./QLinearProgress-UY9rcHYn.js";import{Q as P}from"./QTd-CfsMlHO6.js";import{Q as ve}from"./QTable-CBiO25T1.js";import{Q as be}from"./QSelect-LJn4rxVI.js";import{Q as fe,F as ye}from"./FormValidationSummary-CZ7WGou3.js";import{Q as _e}from"./QPage-OM5JgPVG.js";import{C as ge}from"./ClosePopup-7_Yx9rfi.js";import{c as he,a as we}from"./subscriptions-BiJBoK0V.js";import{f as Se}from"./formatDistanceToNow-DTeh1iPw.js";import{_ as De}from"./_plugin-vue_export-helper-DlAUqK2U.js";import"./QList-DnIjH5wq.js";import"./QMarkupTable-CiCrTXHQ.js";import"./QChip-QkbYP07w.js";import"./QItem-Cmm75ClS.js";import"./QItemLabel-DJJTFmpY.js";import"./QMenu-DeogY-KU.js";import"./position-engine-BaRtYBUc.js";import"./selection-DUEPnI6d.js";import"./format-DyQxkAtJ.js";import"./normalizeDates-CacZHBiA.js";import"./en-US-3LvP7pCn.js";const Ae={class:"q-pa-md"},Pe={class:"page-header q-mb-lg"},Re={class:"text-h4 q-mt-none q-mb-sm"},Ue={class:"row q-col-gutter-md"},xe={class:"col-auto"},Ce={class:"col-auto"},Me={class:"col-auto q-ml-auto"},qe={class:"row q-col-gutter-md q-mb-md"},Ie={class:"col-12 col-sm-6 col-md-3"},Ee={class:"metric-icon bg-positive"},Qe={class:"metric-value"},Ve={class:"col-12 col-sm-6 col-md-3"},Ge={class:"metric-icon bg-secondary"},Te={class:"metric-value"},Be={class:"col-12 col-sm-6 col-md-3"},Fe={class:"metric-icon bg-primary"},ke={class:"metric-value"},Ne={class:"metric-subtext"},je={class:"col-12 col-sm-6 col-md-3"},ze={class:"metric-icon bg-info"},$e={class:"metric-value"},Oe={class:"metric-subtext"},Le={class:"row q-col-gutter-md q-mb-md"},We={class:"col-12 col-md-6"},Ye={class:"text-h6 q-mb-md"},He={class:"tier-stats"},Je={class:"tier-row"},Ke={class:"tier-info"},Xe={class:"tier-count"},Ze={class:"tier-percentage"},et={class:"tier-row"},tt={class:"tier-info"},st={class:"tier-count"},at={class:"tier-percentage"},lt={class:"tier-row"},rt={class:"tier-info"},ot={class:"tier-count"},nt={class:"tier-percentage"},it={class:"tier-row"},ut={class:"tier-info"},dt={class:"tier-count"},ct={class:"tier-percentage"},mt={class:"col-12 col-md-6"},pt={class:"text-h6 q-mb-md"},vt={class:"conversion-stats"},bt={class:"stat-row"},ft={class:"stat-value"},yt={class:"stat-row"},_t={class:"stat-value"},gt={class:"stat-row"},ht={class:"stat-value"},wt={class:"stat-row"},St={class:"stat-value"},Dt={class:"stat-row"},At={class:"stat-value text-positive"},Pt={class:"text-caption te-text-secondary q-mt-xs"},Rt={class:"text-h6 q-mb-md"},Ut={class:"text-weight-medium"},xt={class:"text-caption te-text-secondary"},Ct=X({__name:"SubscriptionsPage",setup(Mt){const k=Z(),N=ee(),R=f(!1),w=f(!1),U=f(!1),a=f({mrr:0,arr:0,totalSubscribers:0,activeSubscribers:0,trialingSubscribers:0,canceledSubscribers:0,freeUsers:0,proUsers:0,premiumUsers:0,earlyAdopterUsers:0,newSubscribersThisMonth:0,canceledThisMonth:0,churnRate:0,trialConversionRate:0,averageRevenuePerUser:0,successfulPayments:0,failedPayments:0,paymentSuccessRate:100}),Q=f([]),d=f({userEmail:"",tier:"pro",durationMonths:1,reason:""}),j=[{label:"Core",value:"core"},{label:"Pro",value:"pro"},{label:"Premium",value:"premium"},{label:"Early Adopter",value:"early_adopter"}],V=f(!1),z=te(()=>{const u=[];return d.value.userEmail||u.push("User Email"),d.value.reason||u.push("Reason"),u}),$=u=>{V.value=!0;const t=u?.$el;t&&typeof t.scrollIntoView=="function"&&t.scrollIntoView({behavior:"smooth",block:"center"})},O=[{name:"user",label:"User",field:"userEmail",align:"left"},{name:"tier",label:"Tier",field:"tier",align:"left"},{name:"status",label:"Status",field:"status",align:"left"},{name:"updatedAt",label:"Updated",field:"updatedAt",align:"left"}],L=u=>{switch(u){case"free":return"grey-6";case"core":return"positive";case"pro":return"primary";case"premium":return"secondary";default:return"grey"}},W=u=>{switch(u){case"active":return"positive";case"trialing":return"info";case"canceled":return"grey-6";case"past_due":case"unpaid":return"negative";default:return"grey"}},Y=u=>Se(u,{addSuffix:!0}),x=async()=>{R.value=!0;try{const u=new Date,t=new Date(u.getFullYear(),u.getMonth(),1),r=q(I(g,"subscriptions")),c=(await E(r)).docs.map(n=>{const l=n.data();return{id:n.id,userId:l.userId??"",tier:l.tier??"free",status:l.status??"active",billingCycle:l.billingCycle??"monthly",currentPeriodStart:l.currentPeriodStart?.toDate()??new Date,currentPeriodEnd:l.currentPeriodEnd?.toDate()??new Date,trialStart:l.trialStart?.toDate()??null,trialEnd:l.trialEnd?.toDate()??null,stripeCustomerId:l.stripeCustomerId??null,stripeSubscriptionId:l.stripeSubscriptionId??null,stripePriceId:l.stripePriceId??null,isManualGrant:l.isManualGrant??!1,manualGrantReason:l.manualGrantReason??null,manualGrantedBy:l.manualGrantedBy??null,manualGrantedAt:l.manualGrantedAt?.toDate()??null,promoCodeUsed:l.promoCodeUsed??null,lastPaymentDate:l.lastPaymentDate?.toDate()??null,lastPaymentAmount:l.lastPaymentAmount??null,nextBillingDate:l.nextBillingDate?.toDate()??null,createdAt:l.createdAt?.toDate()??new Date,updatedAt:l.updatedAt?.toDate()??new Date,canceledAt:l.canceledAt?.toDate()??null,cancelReason:l.cancelReason??null}});a.value.totalSubscribers=c.length,a.value.activeSubscribers=c.filter(n=>n.status==="active").length,a.value.trialingSubscribers=c.filter(n=>n.status==="trialing").length,a.value.canceledSubscribers=c.filter(n=>n.status==="canceled").length,a.value.freeUsers=c.filter(n=>n.tier==="free").length,a.value.proUsers=c.filter(n=>n.tier==="pro").length,a.value.premiumUsers=c.filter(n=>n.tier==="premium").length,a.value.earlyAdopterUsers=c.filter(n=>n.tier==="early_adopter").length,a.value.newSubscribersThisMonth=c.filter(n=>n.createdAt>=t).length,a.value.canceledThisMonth=c.filter(n=>n.canceledAt&&n.canceledAt>=t).length,a.value.churnRate=he(a.value.canceledThisMonth,a.value.totalSubscribers),a.value.mrr=we(c),a.value.arr=a.value.mrr*12,a.value.activeSubscribers>0&&(a.value.averageRevenuePerUser=a.value.mrr/a.value.activeSubscribers),a.value.trialConversionRate=65,a.value.successfulPayments=0,a.value.failedPayments=0,a.value.paymentSuccessRate=100;const H=q(I(g,"subscriptions"),ue("updatedAt","desc"),de(10)),J=(await E(H)).docs.map(n=>{const l=n.data();return{id:n.id,userId:l.userId??"",tier:l.tier??"free",status:l.status??"active",billingCycle:l.billingCycle??"monthly",currentPeriodStart:l.currentPeriodStart?.toDate()??new Date,currentPeriodEnd:l.currentPeriodEnd?.toDate()??new Date,trialStart:l.trialStart?.toDate()??null,trialEnd:l.trialEnd?.toDate()??null,stripeCustomerId:l.stripeCustomerId??null,stripeSubscriptionId:l.stripeSubscriptionId??null,stripePriceId:l.stripePriceId??null,isManualGrant:l.isManualGrant??!1,manualGrantReason:l.manualGrantReason??null,manualGrantedBy:l.manualGrantedBy??null,manualGrantedAt:l.manualGrantedAt?.toDate()??null,promoCodeUsed:l.promoCodeUsed??null,lastPaymentDate:l.lastPaymentDate?.toDate()??null,lastPaymentAmount:l.lastPaymentAmount??null,nextBillingDate:l.nextBillingDate?.toDate()??null,createdAt:l.createdAt?.toDate()??new Date,updatedAt:l.updatedAt?.toDate()??new Date,canceledAt:l.canceledAt?.toDate()??null,cancelReason:l.cancelReason??null}}),K=await Promise.all(J.map(async n=>{const T=(await ce(B(g,"users",n.userId))).data();return{...n,userDisplayName:T?.displayName??"Unknown",userEmail:T?.email??""}}));Q.value=K}catch(u){console.error("Error loading subscription metrics:",u),D.create({type:"negative",message:"Failed to load subscription metrics",position:"top"})}finally{R.value=!1}},G=async()=>{U.value=!0;try{const u=q(I(g,"users"),me("email","==",d.value.userEmail)),t=await E(u);if(t.empty||!t.docs[0]){D.create({type:"negative",message:"User not found with that email",position:"top"});return}const r=t.docs[0].id,C=new Date,c=new Date(C);c.setMonth(c.getMonth()+d.value.durationMonths),await pe(B(g,"subscriptions",r),{userId:r,tier:d.value.tier,status:"active",billingCycle:"monthly",currentPeriodStart:h.fromDate(C),currentPeriodEnd:h.fromDate(c),trialStart:null,trialEnd:null,stripeCustomerId:null,stripeSubscriptionId:null,
1stripePriceId:null,isManualGrant:!0,manualGrantReason:d.value.reason,manualGrantedBy:N.user?.uid??"",manualGrantedAt:h.now(),promoCodeUsed:null,lastPaymentDate:null,lastPaymentAmount:null,nextBillingDate:null,createdAt:h.now(),updatedAt:h.now(),canceledAt:null,cancelReason:null}),D.create({type:"positive",message:"Manual subscription adjustment applied successfully",position:"top"}),w.value=!1,d.value={userEmail:"",tier:"pro",durationMonths:1,reason:""},await x()}catch(u){console.error("Error applying manual adjustment:",u),D.create({type:"negative",message:"Failed to apply manual adjustment",position:"top"})}finally{U.value=!1}};return se(()=>{x()}),(u,t)=>(le(),ae(_e,{class:"subscriptions-page"},{default:o(()=>[e("div",Ae,[e("div",Pe,[e("h4",Re,[s(m,{name:"payments",color:"primary",size:"md",class:"q-mr-sm"}),t[7]||(t[7]=b(" Subscription Overview ",-1))]),t[8]||(t[8]=e("p",{class:"text-subtitle1 te-text-secondary"}," Monitor revenue, subscriptions, and billing metrics ",-1))]),s(F,{rounded:"",class:"bg-info text-white q-mb-md"},{avatar:o(()=>[s(m,{name:"info"})]),default:o(()=>[t[9]||(t[9]=e("div",null,[e("strong",null,"Stripe Integration Pending"),e("br"),b(" Revenue metrics will be populated once Stripe is integrated. See "),e("code",null,"docs/integration/stripe-setup.md"),b(" for integration instructions. ")],-1))]),_:1}),s(v,{class:"te-card q-mb-md"},{default:o(()=>[s(p,null,{default:o(()=>[e("div",Ue,[e("div",xe,[s(_,{color:"primary",label:"Manage Promo Codes",icon:"local_offer",onClick:t[0]||(t[0]=()=>void re(k).push("/admin/promo-codes"))})]),e("div",Ce,[s(_,{outline:"",color:"primary",label:"Manual Adjustments",icon:"tune",onClick:t[1]||(t[1]=r=>w.value=!0)})]),e("div",Me,[s(_,{outline:"",color:"primary",label:"Refresh",icon:"refresh",onClick:x,loading:R.value},null,8,["loading"])])])]),_:1})]),_:1}),e("div",qe,[e("div",Ie,[s(v,{class:"te-card metric-card"},{default:o(()=>[s(p,null,{default:o(()=>[e("div",Ee,[s(m,{name:"attach_money",size:"md",color:"white"})]),t[10]||(t[10]=e("div",{class:"metric-label"},"Monthly Recurring Revenue",-1)),e("div",Qe,"$"+i((a.value.mrr/100).toFixed(2)),1),t[11]||(t[11]=e("div",{class:"metric-subtext"},"MRR",-1))]),_:1})]),_:1})]),e("div",Ve,[s(v,{class:"te-card metric-card"},{default:o(()=>[s(p,null,{default:o(()=>[e("div",Ge,[s(m,{name:"trending_up",size:"md",color:"white"})]),t[12]||(t[12]=e("div",{class:"metric-label"},"Annual Recurring Revenue",-1)),e("div",Te,"$"+i((a.value.arr/100).toLocaleString()),1),t[13]||(t[13]=e("div",{class:"metric-subtext"},"ARR",-1))]),_:1})]),_:1})]),e("div",Be,[s(v,{class:"te-card metric-card"},{default:o(()=>[s(p,null,{default:o(()=>[e("div",Fe,[s(m,{name:"people",size:"md",color:"white"})]),t[14]||(t[14]=e("div",{class:"metric-label"},"Total Subscribers",-1)),e("div",ke,i(a.value.totalSubscribers),1),e("div",Ne,i(a.value.activeSubscribers)+" active",1)]),_:1})]),_:1})]),e("div",je,[s(v,{class:"te-card metric-card"},{default:o(()=>[s(p,null,{default:o(()=>[e("div",ze,[s(m,{name:"money_off",size:"md",color:"white"})]),t[15]||(t[15]=e("div",{class:"metric-label"},"Churn Rate",-1)),e("div",$e,i(a.value.churnRate.toFixed(1))+"%",1),e("div",Oe,i(a.value.canceledThisMonth)+" canceled this month",1)]),_:1})]),_:1})])]),e("div",Le,[e("div",We,[s(v,{class:"te-card"},{default:o(()=>[s(p,null,{default:o(()=>[e("div",Ye,[s(m,{name:"layers",color:"primary",class:"q-mr-sm"}),t[16]||(t[16]=b(" Subscription Tier Breakdown ",-1))]),e("div",He,[e("div",Je,[e("div",Ke,[s(y,{color:"grey-6",label:"Free"}),e("span",Xe,i(a.value.freeUsers)+" users",1)]),e("div",Ze,i((a.value.freeUsers/a.value.totalSubscribers*100).toFixed(1))+"% ",1)]),s(A,{value:a.value.freeUsers/a.value.totalSubscribers,color:"grey-6",class:"q-mb-md"},null,8,["value"]),e("div",et,[e("div",tt,[s(y,{color:"primary",label:"Pro"}),e("span",st,i(a.value.proUsers)+" users",1)]),e("div",at,i((a.value.proUsers/a.value.totalSubscribers*100).toFixed(1))+"% ",1)]),s(A,{value:a.value.proUsers/a.value.totalSubscribers,color:"primary",class:"q-mb-md"},null,8,["value"]),e("div",lt,[e("div",rt,[s(y,{color:"secondary",label:"Premium"}),e("span",ot,i(a.value.premiumUsers)+" users",1)]),e("div",nt,i((a.value.premiumUsers/a.value.totalSubscribers*100).toFixed(1))+"% ",1)]),s(A,{value:a.value.premiumUsers/a.value.totalSubscribers,color:"secondary",class:"q-mb-md"},null,8,["value"]),e("div",it,[e("div",ut,[s(y,{color:"purple",label:"Early Adopter"}),e("span",dt,i(a.value.earlyAdopterUsers)+" users",1)]),e("div",ct,i((a.value.earlyAdopterUsers/a.value.totalSubscribers*100).toFixed(1))+"% ",1)]),s(A,{value:a.value.earlyAdopterUsers/a.value.totalSubscribers,color:"purple"},null,8,["value"])])]),_:1})]),_:1})]),e("div",mt,[s(v,{class:"te-card"},{default:o(()=>[s(p,null,{default:o(()=>[e("div",pt,[s(m,{name:"insights",color:"primary",class:"q-mr-sm"}),t[17]||(t[17]=b(" Conversion & Revenue Metrics ",-1))]),e("div",vt,[e("div",bt,[t[18]||(t[18]=e("div",{class:"stat-label"},"Trial Conversion Rate",-1)),e("div",ft,i(a.value.trialConversionRate.toFixed(1))+"%",1)]),s(S,{class:"q-my-sm"}),e("div",yt,[t[19]||(t[19]=e("div",{class:"stat-label"},"Average Revenue Per User (ARPU)",-1)),e("div",_t," $"+i((a.value.averageRevenuePerUser/100).toFixed(2))+"/mo ",1)]),s(S,{class:"q-my-sm"}),e("div",gt,[t[20]||(t[20]=e("div",{class:"stat-label"},"New Subscribers This Month",-1)),e("div",ht,i(a.value.newSubscribersThisMonth),1)]),s(S,{class:"q-my-sm"}),e("div",wt,[t[21]||(t[21]=e("div",{class:"stat-label"},"Active Trial Users",-1)),e("div",St,i(a.value.trialingSubscribers),1)]),s(S,{class:"q-my-md"}),e("div",Dt,[t[22]||(t[22]=e("div",{class:"stat-label"},"Payment Success Rate",-1)),e("div",At,i(a.value.paymentSuccessRate.toFixed(1))+"% ",1)]),e("div",Pt,i(a.value.successfulPayments)+" successful, "+i(a.value.failedPayments)+" failed ",1)])]),_:1})]),_:1})])]),s(v,{class:"te-card"},{default:o(()=>[s(p,null,{default:o(()=>[e("div",Rt,[s(m,{name:"history",color:"primary",class:"q-mr-sm"}),t[23]||(t[23]=b(" Recent Subscription Changes ",-1))]),s(ve,{rows:Q.value,columns:O,"row-key":"id",flat:"",dense:"","rows-per-page-options":[10]},{"body-cell-user":o(r=>[s(P,{props:r},{default:o(()=>[e("div",Ut,i(r.row.userDisplayName),1),e("div",xt,i(r.row.userEmail),1)]),_:2},1032,["props"])]),"body-cell-tier":o(r=>[s(P,{props:r},{default:o(()=>[s(y,{color:L(r.row.tier),label:r.row.tier.toUpperCase()},null,8,["color","label"])]),_:2},1032,["props"])]),"body-cell-status":o(r=>[s(P,{props:r},{default:o(()=>[s(y,{color:W(r.row.status),label:r.row.status},null,8,["color","label"])]),_:2},1032,["props"])]),"body-cell-updatedAt":o(r=>[s(P,{props:r},{default:o(()=>[b(i(Y(r.row.updatedAt)),1)]),_:2},1032,["props"])]),_:1},8,["rows"])]),_:1})]),_:1})]),s(oe,{modelValue:w.value,"onUpdate:modelValue":t[6]||(t[6]=r=>w.value=r),persistent:""},{default:o(()=>[s(v,{class:"te-card",style:{"min-width":"500px"}},{default:o(()=>[s(p,null,{default:o(()=>[...t[24]||(t[24]=[e("div",{class:"text-h6"},"Manual Subscription Adjustment",-1)])]),_:1}),s(p,{class:"q-pt-none"},{default:o(()=>[s(fe,{greedy:"",onSubmit:G,onValidationError:$,class:"q-gutter-md"},{default:o(()=>[s(M,{modelValue:d.value.userEmail,"onUpdate:modelValue":t[2]||(t[2]=r=>d.value.userEmail=r),label:"User Email *",outlined:"",dense:"",rules:[r=>!!r||"Email is required"]},null,8,["modelValue","rules"]),s(be,{modelValue:d.value.tier,"onUpdate:modelValue":t[3]||(t[3]=r=>d.value.tier=r),options:j,label:"Subscription Tier *",outlined:"",dense:"","emit-value":"","map-options":""},null,8,["modelValue"]),s(M,{modelValue:d.value.durationMonths,"onUpdate:modelValue":t[4]||(t[4]=r=>d.value.durationMonths=r),modelModifiers:{number:!0},label:"Duration (months) *",type:"number",outlined:"",dense:"",min:1,rules:[r=>r>0||"Must be at least 1 month"]},null,8,["modelValue","rules"]),s(M,{modelValue:d.value.reason,"onUpdate:modelValue":t[5]||(t[5]=r=>d.value.reason=r),label:"Reason *",hint:"Internal note about why this adjustment was made",type:"textarea",outlined:"",dense:"",rows:"3",rules:[r=>!!r||"Reason is required"]},null,8,["modelValue","rules"]),s(F,{rounded:"",class:"bg-warning text-dark"},{avatar:o(()=>[s(m,{name:"warning"})]),default:o(()=>[t[25]||(t[25]=b(" This will manually grant premium access without payment. Use only for special circumstances (partnerships, refunds, support, etc.). ",-1))]),_:1}),s(ye,{fields:z.value,show:V.value},null,8,["fields","show"])]),_:1})]),_:1}),s(ne,{align:"right"},{default:o(()=>[ie(s(_,{flat:"",label:"Cancel"},null,512),[[ge]]),s(_,{label:"Grant Access",color:"primary",onClick:G,loading:U.value},null,8,["loading"])]),_:1})]),_:1})]),_:1},8,["modelValue"])]),_:1}))}}),ss=De(Ct,[["__scopeId","data-v-1a215d18"]]);export{ss 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.