@@ -32,8 +32,10 @@ interface Props {
32
32
hideSubheading ?: boolean ;
33
33
}
34
34
35
+ // Guard against multiple calls to subscripe (per page load)
36
+ let didAlreadyCallSubscripe = false ;
37
+
35
38
export default function UsageBasedBillingConfig ( { attributionId, hideSubheading = false } : Props ) {
36
- const location = useLocation ( ) ;
37
39
const currentOrg = useCurrentOrg ( ) . data ;
38
40
const attrId = attributionId ? AttributionId . parse ( attributionId ) : undefined ;
39
41
const [ showUpdateLimitModal , setShowUpdateLimitModal ] = useState < boolean > ( false ) ;
@@ -49,6 +51,10 @@ export default function UsageBasedBillingConfig({ attributionId, hideSubheading
49
51
undefined ,
50
52
) ;
51
53
54
+ // Stripe-controlled parameters
55
+ const location = useLocation ( ) ;
56
+ const [ stripeParams , setStripeParams ] = useState < { setupIntentId ?: string ; redirectStatus ?: string } > ( { } ) ;
57
+
52
58
const now = useMemo ( ( ) => dayjs ( ) . utc ( true ) , [ ] ) ;
53
59
const [ billingCycleFrom , setBillingCycleFrom ] = useState < dayjs . Dayjs > ( now . startOf ( "month" ) ) ;
54
60
const [ billingCycleTo , setBillingCycleTo ] = useState < dayjs . Dayjs > ( now . endOf ( "month" ) ) ;
@@ -90,14 +96,30 @@ export default function UsageBasedBillingConfig({ attributionId, hideSubheading
90
96
} , [ attributionId , refreshSubscriptionDetails ] ) ;
91
97
92
98
useEffect ( ( ) => {
99
+ const params = new URLSearchParams ( location . search ) ;
100
+ setStripeParams ( {
101
+ setupIntentId : params . get ( "setup_intent" ) || undefined ,
102
+ redirectStatus : params . get ( "redirect_status" ) || undefined ,
103
+ } ) ;
104
+ } , [ location . search ] ) ;
105
+
106
+ const subscribeToStripe = useCallback ( ( ) => {
93
107
if ( ! attributionId ) {
94
108
return ;
95
109
}
96
- const params = new URLSearchParams ( location . search ) ;
97
- if ( ! params . get ( "setup_intent" ) || params . get ( "redirect_status" ) !== "succeeded" ) {
110
+ const { setupIntentId , redirectStatus } = stripeParams ;
111
+ if ( ! setupIntentId || redirectStatus !== "succeeded" ) {
98
112
return ;
99
113
}
100
- const setupIntentId = params . get ( "setup_intent" ) ! ;
114
+
115
+ // Guard against multiple execution following the pattern here: https://react.dev/learn/you-might-not-need-an-effect#initializing-the-application
116
+ if ( didAlreadyCallSubscripe ) {
117
+ console . log ( "didAlreadyCallSubscripe, skipping this time." ) ;
118
+ return ;
119
+ }
120
+ didAlreadyCallSubscripe = true ;
121
+ console . log ( "didAlreadyCallSubscripe false, first run." ) ;
122
+
101
123
window . history . replaceState ( { } , "" , location . pathname ) ;
102
124
( async ( ) => {
103
125
const pendingSubscription = { pendingSince : Date . now ( ) } ;
@@ -136,7 +158,8 @@ export default function UsageBasedBillingConfig({ attributionId, hideSubheading
136
158
) ;
137
159
}
138
160
} ) ( ) ;
139
- } , [ attrId ?. kind , attributionId , currentOrg , location . pathname , location . search , refreshSubscriptionDetails ] ) ;
161
+ } , [ attrId ?. kind , attributionId , currentOrg , location . pathname , stripeParams , refreshSubscriptionDetails ] ) ;
162
+ useEffect ( subscribeToStripe , [ subscribeToStripe ] ) ; // Call every time the function changes, and guard in against re-entry in the function itself
140
163
141
164
const showSpinner = ! attributionId || isLoadingStripeSubscription || ! ! pendingStripeSubscription ;
142
165
const showBalance = ! showSpinner ;
0 commit comments