1__d(function(g,r,i,a,m,_e,d){"use strict";Object.defineProperty(_e,'__esModule',{value:!0}),Object.defineProperty(_e,"default",{enumerable:!0,get:function(){return B}});var e=r(d[0]);r(d[1]);var t,n=r(d[2]),s=(t=n)&&t.__esModule?t:{default:t},l=r(d[3]),o=r(d[4]),c=r(d[5]),u=r(d[6]),p=r(d[7]),h=r(d[8]),b=r(d[9]),x=r(d[10]),f=r(d[11]),j=r(d[12]),v=r(d[13]),y=r(d[14]),w=r(d[15]),A=r(d[16]);function S(e){if(!e)return null;const t=new Date(e).getTime()-Date.now();return t>0?Math.ceil(t/864e5):0}function C(e,t=0){return`$${(e/100).toFixed(t)}`}function T(e){return'trial'===e||'trialing'===e?'Free Trial':e.split('_').map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(' ')}function k(e){return'active'===e||'paid'===e?'success':'trial'===e||'trialing'===e||'open'===e?'info':'past_due'===e?'warning':'canceled'===e||'void'===e||'uncollectible'===e?'error':'default'}function B(){const t=(0,f.useCaptureOwner)(),n=(0,u.useClientCallOwner)(),B=(0,l.useRouter)(),{user:R,organization:P,signOut:z}=(0,h.useAuth)(),I=(0,b.useBillingSettings)(),[L,E]=(0,e.useState)(!1),[M,_]=(0,e.useState)(!1),[V,$]=(0,e.useState)(null);if((0,x.useSetBreadcrumbs)(()=>[{label:'Settings',href:'/settings'},{label:'Billing'}],[]),'owner'!==R?.role&&'admin'!==R?.role)return(0,A.jsx)(l.Redirect,{href:"/(app)/settings"});const D=I.billing,W=P?.settings,Y=async()=>{const e=(0,p.beginClientCallExit)(n);if(!e)return;const s=(0,v.beginClinicalDraftExit)();if(!s)return void e();const l=(0,j.beginCaptureExit)(t,()=>window.confirm('Close this workspace and discard the capture saved in this tab? Download available audio first; this account will be deactivated.'));if(!l)return s(),void e();try{if(!await I.endTrial())return;_(!1),await z()&&B.replace('/login')}finally{l(),s(),e(),I.syncRetainedState()}},G=I.reading&&!D?(0,A.jsx)(o.LoadingState,{message:"Loading billing\u2026"}):I.readFailed||!D?(0,A.jsx)(o.ErrorState,{message:"Billing could not be loaded",onRetry:()=>I.refresh()}):null;if(G)return(0,A.jsx)(w.SettingsPage,{title:"Billing & Subscription",description:"Manage your subscription and billing.",children:(0,A.jsx)(w.SettingsSection,{title:"Billing status",children:G})});const H=D.status,N=D.billingCycle,F=D.seatCount,O=D.billableAmou
1nt,U=D.trialEndsAt,q=D.invoices,J=D.capabilities,K='vmg-48'===(D.cohort??W?.cohort??null),Q=S(U),X='trial'===H||'trialing'===H,Z=Boolean(D.id)&&'canceled'!==H,ee='active'===H&&!D.id,ie=c.BILLING_PRICES.monthly.base+Math.max(0,F-1)*c.BILLING_PRICES.monthly.additionalSeat,te=c.BILLING_PRICES.annual.base+Math.max(0,F-1)*c.BILLING_PRICES.annual.additionalSeat,ne=Math.round(100*(1-te/(12*ie))),ae=U?new Intl.DateTimeFormat(void 0,{month:'long',day:'numeric',year:'numeric'}).format(U):null,re=X?'Cancel Trial':'Cancel Subscription',se=I.operation.pending?.kind??null,le=I.operation.outcome;return(0,A.jsxs)(w.SettingsPage,{title:"Billing & Subscription",description:"Manage your subscription and billing.",children:[le&&(0,A.jsxs)(s.default,{role:'succeeded'===le.status?'status':'alert',style:{borderWidth:1,borderColor:'succeeded'===le.status?'#bfdccf':'#f4c7c3',backgroundColor:'succeeded'===le.status?'#f0f8f5':'#fff7f6',borderRadius:14,padding:14,gap:10},children:[(0,A.jsx)(o.AppText,{size:"sm",style:{color:'succeeded'===le.status?'#176b5d':'#8f2f28'},children:le.message}),(0,A.jsxs)(o.AppRow,{spacing:8,wrap:!0,children:[le.continuationUrl&&(0,A.jsx)(o.AppButton,{variant:"outline",size:"sm",onPress:()=>I.continueToStripe(),children:"Continue to Stripe"}),'uncertain'===le.status&&!le.sourceReviewed&&(0,A.jsx)(o.AppButton,{variant:"outline",size:"sm",onPress:()=>I.reviewUnknown(),children:"Review current billing"}),'uncertain'===le.status&&le.sourceReviewed&&(0,A.jsx)(o.AppButton,{variant:"outline",size:"sm",onPress:I.acknowledgeUnknown,children:"Continue after review"}),'uncertain'!==le.status&&(0,A.jsx)(o.AppButton,{variant:"ghost",size:"sm",onPress:I.clearOutcome,children:"Dismiss"})]})]}),(0,A.jsx)(o.AppCard,{style:{padding:24,backgroundColor:'#f3faf7',borderColor:'#dcebe4',borderWidth:1},children:(0,A.jsxs)(o.AppStack,{spacing:16,children:[(0,A.jsxs)(o.AppRow,{justify:"between",align:"start",wrap:!0,spacing:16,children:[(0,A.jsxs)(s.default,{style:{flex:1,minWidth:220,gap:6},children:[(0,A.jsxs)(o.AppRow,{spacing:10,align:"center",wrap:!0,children:[(0,A.jsx)(o.AppHeading,{variant:"title",level:2,children:ee?'CaptiVet Complimentary':D.plan.name}),(0,A.jsx)(o.AppBadge,{variant:k(H),children:T(H)})]}),(0,A.jsx)(o.AppText,{variant:"muted",children:ee?'Your clinic has full access at no charge. Contact CaptiVet support to change your plan.':'annual'===N?`${C(D.plan.price)}/yr base \xb7 ${C(D.plan.seatPrice)}/yr per additional billable seat`:`${C(D.plan.price)}/mo base \xb7 ${C(D.plan.seatPrice)}/mo per additional billable seat`})]}),J.canManagePortal&&(0,A.jsx)(o.AppButton,{variant:"outline",onPress:()=>I.openPortal(),loading:'portal'===se,disabled:I.locked,children:"Manage billing in Stripe"})]}),!ee&&(0,A.jsxs)(s.default,{style:{borderWidth:1,borderColor:'#dcebe4',borderRadius:14,backgroundColor:'rgba(255,255,255,0.82)',padding:16,gap:10},children:[(0,A.jsxs)(o.AppRow,{justify:"between",spacing:12,wrap:!0,children:[(0,A.jsx)(o.AppText,{variant:"muted",size:"sm",style:{flex:1,minWidth:190},children:"Billable seats (owners + admins + vets)"}),(0,A.jsx)(o.AppText,{size:"sm",weight:"semibold",children:F})]}),(0,A.jsxs)(o.AppRow,{justify:"between",spacing:12,wrap:!0,children:[(0,A.jsx)(o.AppText,{variant:"muted",size:"sm",style:{flex:1,minWidth:190},children:'annual'===N?'Annual total':'Monthly total'}),(0,A.jsxs)(o.AppText,{size:"sm",weight:"bold",style:{color:'#0d8775'},children:[C(O),'annual'===N?'/yr':'/mo']})]}),(0,A.jsxs)(o.AppRow,{justify:"between",spacing:12,wrap:!0,children:[(0,A.jsx)(o.AppText,{variant:"muted",size:"sm",style:{flex:1,minWidth:190},children:"Support staff (techs, receptionists, CSRs)"}),(0,A.jsx)(o.AppText,{size:"sm",weight:"semibold",children:"Always free"})]})]}),X&&null!==Q&&(0,A.jsx)(o.AppText,{size:"sm",style:{color:'#176b5d'},children:Q>0?`${Q} day${1===Q?'':'s'} remaining in your free trial.`:'Your trial period has ended.'}),X&&Z&&ae&&!D.cancelAtPeriodEnd&&(0,A.jsxs)(o.AppText,{variant:"muted",size:"sm",children:["Card on file. First charge is scheduled for ",ae,"."]}),J.canResumeSubscription&&(0,A.jsxs)(o.AppStack,{spacing:8,children:[(0,A.jsx)(o.AppText,{variant:"muted",size:"sm",children:X?'Your trial subscription is scheduled to cancel at the trial end date.':'Your subscription is scheduled to cancel at the end of the billing period.'}),(0,A.jsx)(o.AppButton,{onPress:()=>I.resume(),loading:'resume'===se,disabled:I.locked,children:X?'Resume Trial':'Resume Subscription'})]})]})}),J.canStartCheckout&&(0,A.jsxs)(w.SettingsSection,{title:K?'Activate VMG-48 Subscription':'canceled'===H?'Restart Your Subscription':'Start Your Subscription',children:[(0,A.jsx)(o.AppText,{variant:"muted",children:K?'Your CaptiVet subscription is free through VMG-48. Stripe checkout applies the indefinite discount automatically; no card is required.':`${C(c.BILLING_PRICES.monthly.base)}/mo base includes one billable seat. Additional owners, admins or veterinarians are ${C(c.BILLING_PRICES.monthly.additionalSeat)}/mo each. Support staff are always free.`}),(0,A.jsx)(o.AppRow,{spacing:10,wrap:!0,children:K?(0,A.jsx)(o.AppButton,{onPress:()=>I.checkout('monthly'),loading:'checkout-monthly'===se,disabled:I.locked,children:"Activate VMG-48 \xb7 $0"}):(0,A.jsxs)(A.Fragment,{children:[(0,A.jsxs)(o.AppButton,{onPress:()=>I.checkout('monthly'),loading:'checkout-monthly'===se,disabled:I.locked,children:["Subscribe Monthly \xb7 ",C(ie),"/mo"]}),(0,A.jsxs)(o.AppButton,{variant:"outline",onPress:()=>I.checkout('annual'),loading:'checkout-annual'===se,disabled:I.locked,children:["Subscribe Annually \xb7 ",C(te),"/yr \xb7 Save ",ne,"%"]})]})})]}),(0,A.jsxs)(o.AppCard,{style:{overflow:'hidden'},children:[(0,A.jsx)(s.default,{style:{paddingHorizontal:24,paddingTop:20,paddingBottom:14},children:(0,A.jsx)(o.AppHeading,{variant:"heading",level:2,children:"Invoice History"})}),q.length?q.map(e=>(0,A.jsx)(s.default,{style:{borderTopWidth:1,borderTopColor:'#eef3f0',paddingHorizontal:24,paddingVertical:13},children:(0,A.jsxs)(o.AppRow,{spacing:16,align:"center",wrap:!0,children:[(0,A.jsx)(o.AppText,{style:{flex:1,minWidth:140},children:new Date(1e3*e.date).toLocaleDateString()}),(0,A.jsx)(o.AppText,{style:{fontVariant:['tabular-nums']},children:C(e.amount,2)}),(0,A.jsx)(o.AppBadge,{variant:k(e.status),children:T(e.status)}),e.url&&(0,A.jsx)(o.AppButton,{variant:"ghost",size:"sm",accessibilityLabel:`View ${T(e.status)} invoice from ${new Date(1e3*e.date).toLocaleDateString()}`,onPress:async()=>{$(null);try{await(0,y.openBillingUrl)(e.url??'')||$('This invoice link is not a supported Stripe URL.')}catch{$('The invoice could not be opened. Try again.')}},children:"View"})]})},e.id)):(0,A.jsx)(s.default,{style:{borderTopWidth:1,borderTopColor:'#eef3f0',paddingHorizontal:24,paddingVertical:18},children:(0,A.jsx)(o.AppText,{variant:"muted",children:"No invoices yet."})}),V&&(0,A.jsx)(s.default,{style:{paddingHorizontal:24,paddingBottom:16},children:(0,A.jsx)(o.AppText,{accessibilityRole:"alert",variant:"error",size:"sm",children:V})})]}),J.canCancelSubscription&&(0,A.jsxs)(w.SettingsSection,{title:re,children:[(0,A.jsx)(o.AppText,{variant:"muted",children:X?'Your trial access continues until the trial end date unless you resume first.':'Your access continues until the end of the current billing period.'}),(0,A.jsx)(o.AppRow,{children:(0,A.jsx)(o.AppButton,{variant:"destructive",onPress:()=>E(!0),loading:'cancel'===se,disabled:I.locked,children:re})})]}),J.canEndTrial&&(0,A.jsxs)(w.SettingsSection,{title:"Close Workspace",children:[(0,A.jsx)(o.AppText,{variant:"muted",children:"End the free trial immediately, archive this workspace, deactivate users and remove pending invitations."}),(0,A.jsx)(o.AppRow,{children:(0,A.jsx)(o.AppButton,{variant:"destructive",onPress:()=>_(!0),loading:'end-trial'===se,disabled:I.locked,children:"End trial and close workspace"})})]}),(0,A.jsx)(o.ConfirmDialog,{visible:L,title:X?'Cancel trial?':'Cancel subscription?',message:X?'Stripe will cancel at the trial end date. You can resume the trial before then.':'Stripe will cancel at the end of the current billing period. You can resume before that date.',confirmText:re,confirmVariant:"destructive",loading:'cancel'===se,onConfirm:async()=>{await I.cancel(),E(!1)},onCancel:()=>E(!1)}),(0,A.jsx)(o.ConfirmDialog,{visible:M,title:"End trial and close workspace?",message:"This immediately archives the workspace, deactivates every user, removes pending invitations, and signs y
1ou out.",confirmText:"Close workspace",confirmVariant:"destructive",loading:'end-trial'===se,onConfirm:()=>{Y()},onCancel:()=>_(!1)})]})}},1907,[3,104,109,736,1494,480,477,972,970,1908,1683,476,1480,1484,1909,1879,2]); 2__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.billingSettingsQueryKey=w,e.useBillingSettings=function(){const o=(0,f.useAuth)(),{user:y,isAuthenticated:b,mfaRequired:S}=o,k=(0,h.useApi)(),v=(0,n.useQueryClient)(),E=y?`${y.organizationId}:${y.id}:${y.role}`:'',B=(0,s.useClinicalDraftStore)(),R=(0,t.useMemo)(()=>new u.ClinicalDraftStore,[E]),U=(0,l.getBillingSettingsOwner)(B??R),q=Boolean(y&&b&&!S&&('owner'===y.role||'admin'===y.role)),I=(0,t.useRef)({actor:E,permitted:q,mounted:!0});I.current.actor=E,I.current.permitted=q,(0,t.useEffect)(()=>(I.current.mounted=!0,()=>{I.current.mounted=!1,queueMicrotask(()=>{B||I.current.mounted&&I.current.actor===E||R.dispose()})}),[B,E,R]);const Q=(0,t.useSyncExternalStore)(U.subscribe,U.getSnapshot,U.getSnapshot),A=()=>U.active&&I.current.actor===E&&I.current.permitted,T=()=>A()&&I.current.mounted&&!(B??R).exiting,z=w(y),x=(0,n.useQuery)({queryKey:z,enabled:q,retry:!1,staleTime:0,refetchOnMount:'always',queryFn:async()=>{const t=await k.billing.getStatus({identity:{organizationId:y.organizationId,userId:y.id},beforeRequest:()=>{if(!T())throw new Error('Billing settings account access changed.')}});if(!t)throw new Error('Billing settings are unavailable for this clinic.');return t}}),C=q&&x.data?x.data:void 0,K=Boolean(T()&&C&&!x.isError&&!x.isFetching&&'success'===v.getQueryState(z)?.status&&'idle'===v.getQueryState(z)?.fetchStatus&&!v.getQueryState(z)?.isInvalidated),O=(t=!1)=>{if(!y||!t&&!K)throw new Error('Refresh billing settings before making a change.');let n=!0,o=!1;return{context:{identity:{organizationId:y.organizationId,userId:y.id},beforeRequest:()=>{if(!A())throw new Error('Billing settings account access changed.');if(n){if(!I.current.mounted||!t&&!K)throw new Error('Refresh billing settings before making a change.');n=!1}o=!0}},dispatched:()=>o}},F=()=>{A()&&(v.invalidateQueries({queryKey:z}),v.invalidateQueries({queryKey:['billing']}),v.invalidateQueries({queryKey:['billing-setup']}))},L=async(t,n,o,c=!1)=>{if(!c&&!K||!I.current.mounted||U.locked)return!1;let s;try{s=O(c)}catch{return!1}const u=U.begin(t);if(!u)return!1;try{const t=await n(s.context);return!!A()&&(await o(u,t),!0)}catch(t){if(!A())return!1;const n=!s.dispatched()||p(t);return U.fail(u,n?'rejected':'uncertain',s.dispatched()?n?t instanceof Error?t.message:'The billing change was not accepted.':'The request was sent, but its outcome could not be confirmed. Review current billing before continuing.':'The action paused before sending. Refresh billing before trying again.'),s.dispatched()&&F(),!1}},M=async t=>{if(!(0,c.isAllowedBillingUrl)(t))throw new Error('Stripe returned an unsupported billing URL.');if(T())try{await(0,c.openBillingUrl)(t)}catch{}};return{billing:C,reading:x.isLoading||x.isFetching,readFailed:x.isError,ready:K,refresh:()=>x.refetch(),operation:Q,locked:U.locked,checkout:t=>L('monthly'===t?'checkout-monthly':'checkout-annual',n=>k.billing.createCheckoutSession(t,{returnPath:'settings-billing'},n),async(t,n)=>{if(!(0,c.isAllowedBillingUrl)(n.url))throw new Error('Stripe returned an unsupported billing URL.');U.succeed(t,'Secure checkout is ready.',n.url),await M(n.url)}),openPortal:()=>L('portal',t=>k.billing.createPortalSession(t),async(t,n)=>{if(!(0,c.isAllowedBillingUrl)(n.url))throw new Error('Stripe returned an unsupported billing URL.');U.succeed(t,'Your Stripe billing portal is ready.',n.url),await M(n.url)}),cancel:()=>L('cancel',t=>k.billing.cancelSubscription(t),t=>{U.succeed(t,'Subscription cancellation is scheduled.'),F()}),resume:()=>L('resume',t=>k.billing.resumeSubscription(t),t=>{U.succeed(t,'Subscription cancellation was removed.'),F()}),endTrial:()=>L('end-trial',t=>k.billing.endTrial(t),t=>{U.succeed(t,'The workspace was closed.')},!0),reviewUnknown:async()=>{if('uncertain'!==Q.outcome?.status||!T())return!1;const t=await x.refetch();return!(!t.data||t.error||!A())&&U.reviewSource(t.data)},acknowledgeUnknown:()=>U.acknowledgeUnknown(),clearOutcome:()=>U.clearOutcome(),continueToStripe:async()=>{const t=U.getSnapshot().outcome?.continuationUrl;return!!t&&(0,c.openBillingUrl)(t)},syncRetainedState:()=>U.syncActivity()}};var t=r(d[0]),n=r(d[1]),o=r(d[2]),c=r(d[3]),s=r(d[4]),u=r(d[5]),l=r(d[6]),h=r(d[7]),f=r(d[8]);const p=t=>{const n=t instanceof o.AppException?t.appError.statusCode:void 0;return void 0!==n&&n>=400&&n<500};function w(t){return['billing','settings',t?.organizationId,t?.id,t?.role]}},1908,[3,1074,480,1909,1493,1486,1910,1686,970]); 3__d(function(g,r,i,a,m,e,d){"use strict";
3Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"billingSettingsDraftKey",{enumerable:!0,get:function(){return t}}),Object.defineProperty(e,"BillingSettingsOwner",{enumerable:!0,get:function(){return u}}),e.getBillingSettingsOwner=function(t){let n=o.get(t);n||(n=new u(t),o.set(t,n));return n};const t='settings:billing',n=()=>s({pending:null,outcome:null});function s(t){return t.pending&&Object.freeze(t.pending),t.outcome&&Object.freeze(t.outcome),Object.freeze(t)}const c={settingsPage:'billing',label:'Billing settings',dirty:t=>t.dirty,pending:t=>t.pending};class u{#e=n();listeners=new Set;sequence=0;disposed=!1;constructor(t){this.account=t,t.onDispose(()=>{this.disposed=!0,this.#e=n();const t=[...this.listeners];this.listeners.clear(),t.forEach(t=>t())})}get active(){return!this.disposed&&this.account.active}get locked(){return Boolean(this.#e.pending||'uncertain'===this.#e.outcome?.status)}getSnapshot=()=>this.#e;subscribe=t=>this.disposed?()=>{}:(this.listeners.add(t),()=>this.listeners.delete(t));publish(n){if(!this.active)return!1;this.#e=s(n);const u='end-trial'===n.pending?.kind;return this.account.write(t,{dirty:null!==n.outcome,pending:null!==n.pending&&!u},{dirty:!1,pending:!1},c),this.account.releaseClean(t),this.listeners.forEach(t=>t()),!0}begin(t){if(!this.active||this.locked)return null;const n=Object.freeze({id:++this.sequence,kind:t});return this.publish({pending:n,outcome:null}),n}current(t){return this.active&&this.#e.pending===t}succeed(t,n,s=null){return!!this.current(t)&&this.publish({pending:null,outcome:{action:t.kind,status:'succeeded',message:n,continuationUrl:s,sourceReviewed:!1}})}fail(t,n,s){return!!this.current(t)&&this.publish({pending:null,outcome:{action:t.kind,status:n,message:s,continuationUrl:null,sourceReviewed:!1}})}reviewSource(t){const n=this.#e.outcome;return!(!this.active||'uncertain'!==n?.status)&&('cancel'===n.action&&t.cancelAtPeriodEnd?this.publish({pending:null,outcome:{...n,status:'succeeded',message:'The current subscription confirms that cancellation is scheduled.',sourceReviewed:!0}}):'resume'!==n.action||t.cancelAtPeriodEnd?this.publish({pending:null,outcome:{...n,sourceReviewed:!0}}):this.publish({pending:null,outcome:{...n,status:'succeeded',message:'The current subscription confirms that cancellation is no longer scheduled.',sourceReviewed:!0}}))}acknowledgeUnknown(){const t=this.#e.outcome;return!(!this.active||'uncertain'!==t?.status||!t.sourceReviewed)&&this.publish({pending:null,outcome:null})}clearOutcome(){return!(!this.active||this.locked)&&this.publish({pending:null,outcome:null})}syncActivity(){return this.publish(this.#e)}}const o=new WeakMap},1910,[]); 4//# sourceMappingURL=/_expo/static/js/web/billing-479b3e9e0c48cb3c705b001e8e3f3745.js.map 5//# debugId=713daa3a-fa48-4918-9593-9915a869985d
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.