1- import { useAutumn } from 'autumn-js/react' ;
1+ import type { Customer , CustomerProduct } from 'autumn-js' ;
2+ import { useAutumn , useCustomer , usePricingTable } from 'autumn-js/react' ;
23import dayjs from 'dayjs' ;
34import { useState } from 'react' ;
45import { toast } from 'sonner' ;
56import AttachDialog from '@/components/autumn/attach-dialog' ;
6- import type { Customer , CustomerProduct } from '../data/billing-data' ;
7+
8+ export type FeatureUsage = {
9+ id : string ;
10+ name : string ;
11+ used : number ;
12+ limit : number ;
13+ unlimited : boolean ;
14+ nextReset : string | null ;
15+ interval : string | null ;
16+ } ;
17+
18+ export type Usage = {
19+ features : FeatureUsage [ ] ;
20+ } ;
21+
22+ // Re-export types for compatibility
23+ export type { Customer , CustomerInvoice as Invoice } from 'autumn-js' ;
724
825export function useBilling ( refetch ?: ( ) => void ) {
926 const { attach, cancel, check, track, openBillingPortal } = useAutumn ( ) ;
@@ -26,8 +43,12 @@ export function useBilling(refetch?: () => void) {
2643 dialog : AttachDialog ,
2744 successUrl : `${ window . location . origin } /billing` ,
2845 } ) ;
29- } catch ( error : any ) {
30- toast . error ( error . message || 'An unexpected error occurred.' ) ;
46+ } catch ( error ) {
47+ const message =
48+ error instanceof Error
49+ ? error . message
50+ : 'An unexpected error occurred.' ;
51+ toast . error ( message ) ;
3152 } finally {
3253 setIsActionLoading ( false ) ;
3354 }
@@ -48,8 +69,12 @@ export function useBilling(refetch?: () => void) {
4869 if ( refetch ) {
4970 setTimeout ( ( ) => refetch ( ) , 500 ) ;
5071 }
51- } catch ( error : any ) {
52- toast . error ( error . message || 'Failed to cancel subscription.' ) ;
72+ } catch ( error ) {
73+ const message =
74+ error instanceof Error
75+ ? error . message
76+ : 'Failed to cancel subscription.' ;
77+ toast . error ( message ) ;
5378 } finally {
5479 setIsLoading ( false ) ;
5580 }
@@ -79,15 +104,12 @@ export function useBilling(refetch?: () => void) {
79104 } ;
80105
81106 const getSubscriptionStatus = ( product : CustomerProduct ) => {
82- if ( product . status === 'canceled' ) {
83- return 'Cancelled ' ;
107+ if ( product . canceled_at ) {
108+ return 'Cancelling ' ;
84109 }
85110 if ( product . status === 'scheduled' ) {
86111 return 'Scheduled' ;
87112 }
88- if ( product . canceled_at ) {
89- return 'Cancelling' ;
90- }
91113 return 'Active' ;
92114 } ;
93115
@@ -114,13 +136,19 @@ export function useBilling(refetch?: () => void) {
114136 return null ;
115137 }
116138
139+ const includedUsage = feature . included_usage || 0 ;
140+ const balance = feature . balance || 0 ;
141+ // Calculate used amount: included_usage - balance
142+ // If usage field exists and is greater, use that instead (for accuracy)
143+ const calculatedUsed = Math . max ( 0 , includedUsage - balance ) ;
144+ const reportedUsage = feature . usage || 0 ;
145+ const actualUsed = Math . max ( calculatedUsed , reportedUsage ) ;
146+
117147 return {
118148 id : feature . id ,
119149 name : feature . name ,
120- used : feature . usage ,
121- limit : feature . unlimited
122- ? Number . POSITIVE_INFINITY
123- : feature . included_usage ,
150+ used : actualUsed ,
151+ limit : feature . unlimited ? Number . POSITIVE_INFINITY : includedUsage ,
124152 unlimited : feature . unlimited ,
125153 nextReset : feature . next_reset_at
126154 ? dayjs ( feature . next_reset_at ) . format ( 'MMM D, YYYY' )
@@ -148,3 +176,64 @@ export function useBilling(refetch?: () => void) {
148176 getFeatureUsage,
149177 } ;
150178}
179+
180+ // Consolidated billing data hook
181+ export function useBillingData ( ) {
182+ const {
183+ customer,
184+ isLoading : isCustomerLoading ,
185+ refetch : refetchCustomer ,
186+ } = useCustomer ( {
187+ expand : [ 'invoices' ] ,
188+ } ) ;
189+
190+ const {
191+ products,
192+ isLoading : isPricingLoading ,
193+ refetch : refetchPricing ,
194+ } = usePricingTable ( ) ;
195+
196+ const isLoading = isCustomerLoading || isPricingLoading ;
197+
198+ const refetch = ( ) => {
199+ refetchCustomer ( ) ;
200+ if ( typeof refetchPricing === 'function' ) {
201+ refetchPricing ( ) ;
202+ }
203+ } ;
204+
205+ const usage : Usage = {
206+ features : customer
207+ ? Object . values ( customer . features ) . map ( ( feature ) => {
208+ const includedUsage = feature . included_usage || 0 ;
209+ const balance = feature . balance || 0 ;
210+ // Calculate used amount: included_usage - balance
211+ // If usage field exists and is greater, use that instead (for accuracy)
212+ const calculatedUsed = Math . max ( 0 , includedUsage - balance ) ;
213+ const reportedUsage = feature . usage || 0 ;
214+ const actualUsed = Math . max ( calculatedUsed , reportedUsage ) ;
215+
216+ return {
217+ id : feature . id ,
218+ name : feature . name ,
219+ used : actualUsed ,
220+ limit : feature . unlimited ? Number . POSITIVE_INFINITY : includedUsage ,
221+ unlimited : ! ! feature . unlimited ,
222+ nextReset : feature . next_reset_at
223+ ? new Date ( feature . next_reset_at ) . toLocaleDateString ( )
224+ : null ,
225+ interval : feature . interval || null ,
226+ } ;
227+ } )
228+ : [ ] ,
229+ } ;
230+
231+ return {
232+ products : products || [ ] ,
233+ usage,
234+ customer,
235+ customerData : customer , // Alias for backward compatibility
236+ isLoading,
237+ refetch,
238+ } ;
239+ }
0 commit comments