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,42 @@ type PurchaseCreditsProps = {
34
33
onBack ?: ( ) => void ;
35
34
} ;
36
35
36
+ // Lazy load stripe components
37
+ const StripeElements = lazy ( ( ) =>
38
+ import ( "@stripe/react-stripe-js" ) . then ( ( mod ) => ( {
39
+ default : mod . Elements ,
40
+ } ) ) ,
41
+ ) ;
42
+
43
+ const loadStripeAsync = async ( ) => {
44
+ const { loadStripe } = await import ( "@stripe/stripe-js" ) ;
45
+ return loadStripe ;
46
+ } ;
47
+
37
48
export function PurchaseCredits ( { isSlot, onBack } : PurchaseCreditsProps ) {
38
49
const { closeModal, chainId, controller } = useConnection ( ) ;
39
50
40
51
const [ clientSecret , setClientSecret ] = useState ( "" ) ;
41
52
const [ isLoading , setisLoading ] = useState < boolean > ( false ) ;
42
53
const [ state , setState ] = useState < PurchaseState > ( PurchaseState . SELECTION ) ;
43
54
const [ creditsAmount , setCreditsAmount ] = useState < number > ( DEFAULT_AMOUNT ) ;
44
- const stripePromise = useMemo ( ( ) => loadStripe ( STRIPE_API_PUBKEY ) , [ ] ) ;
55
+ const [ stripePromise ] = useState ( ( ) =>
56
+ loadStripeAsync ( ) . then ( ( load ) => load ( STRIPE_API_PUBKEY ) ) ,
57
+ ) ;
45
58
const [ error , setError ] = useState < Error > ( ) ;
46
59
60
+ const appearance = useMemo (
61
+ ( ) : Appearance => ( {
62
+ theme : "night" as const ,
63
+ variables : {
64
+ colorPrimary : "#FBCB4A" ,
65
+ colorBackground : "#161A17" ,
66
+ focusBoxShadow : "none" ,
67
+ } ,
68
+ } ) ,
69
+ [ ] ,
70
+ ) ;
71
+
47
72
const onAmountChanged = useCallback (
48
73
( amount : number ) => setCreditsAmount ( amount ) ,
49
74
[ setCreditsAmount ] ,
@@ -79,27 +104,20 @@ export function PurchaseCredits({ isSlot, onBack }: PurchaseCreditsProps) {
79
104
}
80
105
} , [ controller , creditsAmount ] ) ;
81
106
82
- const appearance = {
83
- theme : "night" ,
84
- variables : {
85
- colorPrimary : "#FBCB4A" ,
86
- colorBackground : "#161A17" ,
87
- focusBoxShadow : "none" ,
88
- } ,
89
- } as Appearance ;
90
-
91
107
if ( state === PurchaseState . STRIPE_CHECKOUT ) {
92
108
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 >
109
+ < Suspense fallback = { < div > Loading payment system...</ div > } >
110
+ < StripeElements
111
+ options = { { clientSecret, appearance, loader : "auto" } }
112
+ stripe = { stripePromise }
113
+ >
114
+ < CheckoutForm
115
+ onBack = { ( ) => setState ( PurchaseState . SELECTION ) }
116
+ onComplete = { ( ) => setState ( PurchaseState . SUCCESS ) }
117
+ creditsAmount = { creditsAmount }
118
+ />
119
+ </ StripeElements >
120
+ </ Suspense >
103
121
) ;
104
122
}
105
123
0 commit comments