1
- import { useCallback , useMemo , useState } from "react" ;
1
+ import { useCallback , useMemo , useState , lazy , Suspense } from "react" ;
2
+ import type { Appearance } from "@stripe/stripe-js" ;
2
3
import {
3
4
LayoutContainer ,
4
5
LayoutContent ,
@@ -13,8 +14,6 @@ import {
13
14
import { useConnection } from "@/hooks/connection" ;
14
15
import { AmountSelection } from "./AmountSelection" ;
15
16
import { ErrorAlert } from "@/components/ErrorAlert" ;
16
- import { Elements } from "@stripe/react-stripe-js" ;
17
- import { Appearance , loadStripe } from "@stripe/stripe-js" ;
18
17
import { Balance } from "./Balance" ;
19
18
import CheckoutForm from "./StripeCheckout" ;
20
19
import { isIframe } from "@cartridge/utils" ;
@@ -34,16 +33,35 @@ type PurchaseCreditsProps = {
34
33
onBack ?: ( ) => void ;
35
34
} ;
36
35
36
+ // Lazy load stripe components
37
+ const StripeElements = lazy ( ( ) => import ( "@stripe/react-stripe-js" ) . then ( mod => ( {
38
+ default : mod . Elements
39
+ } ) ) ) ;
40
+
41
+ const loadStripeAsync = async ( ) => {
42
+ const { loadStripe } = await import ( "@stripe/stripe-js" ) ;
43
+ return loadStripe ;
44
+ } ;
45
+
37
46
export function PurchaseCredits ( { isSlot, onBack } : PurchaseCreditsProps ) {
38
47
const { closeModal, chainId, controller } = useConnection ( ) ;
39
48
40
49
const [ clientSecret , setClientSecret ] = useState ( "" ) ;
41
50
const [ isLoading , setisLoading ] = useState < boolean > ( false ) ;
42
51
const [ state , setState ] = useState < PurchaseState > ( PurchaseState . SELECTION ) ;
43
52
const [ creditsAmount , setCreditsAmount ] = useState < number > ( DEFAULT_AMOUNT ) ;
44
- const stripePromise = useMemo ( ( ) => loadStripe ( STRIPE_API_PUBKEY ) , [ ] ) ;
53
+ const [ stripePromise ] = useState ( ( ) => loadStripeAsync ( ) . then ( load => load ( STRIPE_API_PUBKEY ) ) ) ;
45
54
const [ error , setError ] = useState < Error > ( ) ;
46
55
56
+ const appearance = useMemo ( ( ) : Appearance => ( {
57
+ theme : "night" as const ,
58
+ variables : {
59
+ colorPrimary : "#FBCB4A" ,
60
+ colorBackground : "#161A17" ,
61
+ focusBoxShadow : "none" ,
62
+ } ,
63
+ } ) , [ ] ) ;
64
+
47
65
const onAmountChanged = useCallback (
48
66
( amount : number ) => setCreditsAmount ( amount ) ,
49
67
[ setCreditsAmount ] ,
@@ -79,27 +97,20 @@ export function PurchaseCredits({ isSlot, onBack }: PurchaseCreditsProps) {
79
97
}
80
98
} , [ controller , creditsAmount ] ) ;
81
99
82
- const appearance = {
83
- theme : "night" ,
84
- variables : {
85
- colorPrimary : "#FBCB4A" ,
86
- colorBackground : "#161A17" ,
87
- focusBoxShadow : "none" ,
88
- } ,
89
- } as Appearance ;
90
-
91
100
if ( state === PurchaseState . STRIPE_CHECKOUT ) {
92
101
return (
93
- < Elements
94
- options = { { clientSecret, appearance, loader : "auto" } }
95
- stripe = { stripePromise }
96
- >
97
- < CheckoutForm
98
- onBack = { ( ) => setState ( PurchaseState . SELECTION ) }
99
- onComplete = { ( ) => setState ( PurchaseState . SUCCESS ) }
100
- creditsAmount = { creditsAmount }
101
- />
102
- </ Elements >
102
+ < Suspense fallback = { < div > Loading payment system...</ div > } >
103
+ < StripeElements
104
+ options = { { clientSecret, appearance, loader : "auto" } }
105
+ stripe = { stripePromise }
106
+ >
107
+ < CheckoutForm
108
+ onBack = { ( ) => setState ( PurchaseState . SELECTION ) }
109
+ onComplete = { ( ) => setState ( PurchaseState . SUCCESS ) }
110
+ creditsAmount = { creditsAmount }
111
+ />
112
+ </ StripeElements >
113
+ </ Suspense >
103
114
) ;
104
115
}
105
116
0 commit comments