Skip to content

Commit 758b6dd

Browse files
fix: premount loader race condition
1 parent f8ee6f6 commit 758b6dd

File tree

3 files changed

+73
-25
lines changed

3 files changed

+73
-25
lines changed

src/Payments/PreMountLoader.res

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,36 @@ let sendPromiseData = (promise, key) => {
1212

1313
let useMessageHandler = getPromisesAndHandler => {
1414
React.useEffect(_ => {
15-
let (promises, messageHandler) = getPromisesAndHandler()
15+
let messageHandler = getPromisesAndHandler()
16+
1617
let setupMessageListener = _ => {
17-
Utils.messageParentWindow([("preMountLoaderIframeMountedCallback", true->JSON.Encode.bool)])
1818
Window.addEventListener("message", messageHandler)
19+
Utils.messageParentWindow([("preMountLoaderIframeMountedCallback", true->JSON.Encode.bool)])
1920
}
2021

2122
let cleanupMessageListener = _ => {
22-
Utils.messageParentWindow([("preMountLoaderIframeUnMount", true->JSON.Encode.bool)])
2323
Window.removeEventListener("message", messageHandler)
24+
Utils.messageParentWindow([("preMountLoaderIframeUnMount", true->JSON.Encode.bool)])
2425
}
2526

26-
setupMessageListener()
27-
28-
let executeAllPromises = async () => {
29-
try {
30-
let _ = await Promise.all(promises)
31-
} catch {
32-
| error => Console.error2("Error in message handler:", error)
27+
let handleCleanUpEventListener = (ev: Window.event) => {
28+
open Utils
29+
let dict = ev.data->safeParse->getDictFromJson
30+
if dict->Dict.get("cleanUpPreMountLoaderIframe")->Option.isSome {
31+
cleanupMessageListener()
3332
}
34-
cleanupMessageListener()
3533
}
36-
executeAllPromises()->ignore
3734

38-
Some(cleanupMessageListener)
35+
Window.addEventListener("message", handleCleanUpEventListener)
36+
37+
setupMessageListener()
38+
39+
Some(
40+
() => {
41+
cleanupMessageListener()
42+
Window.removeEventListener("message", handleCleanUpEventListener)
43+
},
44+
)
3945
}, [])
4046
}
4147

@@ -87,8 +93,7 @@ module PreMountLoaderForElements = {
8793
}
8894
}
8995

90-
let promises = [paymentMethodsPromise, customerPaymentMethodsPromise, sessionTokensPromise]
91-
(promises, messageHandler)
96+
messageHandler
9297
})
9398

9499
React.null
@@ -114,8 +119,7 @@ module PreMountLoaderForPMMElements = {
114119
}
115120
}
116121

117-
let promises = [savedPaymentMethodsPromise]
118-
(promises, messageHandler)
122+
messageHandler
119123
})
120124

121125
React.null

src/hyper-loader/Elements.res

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,13 @@ let make = (
142142
}
143143
}
144144

145-
let fetchPaymentsList = (mountedIframeRef, componentType) => {
145+
let fetchPaymentsList = (mountedIframeRef, componentType, promiseResolve) => {
146146
let handlePaymentMethodsLoaded = (event: Types.event) => {
147147
let json = event.data->anyTypeToJson
148148
let dict = json->getDictFromJson
149149
let isPaymentMethodsData = dict->getString("data", "") === "payment_methods"
150150
if isPaymentMethodsData {
151+
promiseResolve()
151152
isTaxCalculationEnabled.contents =
152153
dict->getDictFromDict("response")->getBool("is_tax_calculation_enabled", false)
153154
addSmartEventListener("message", onPlaidCallback(mountedIframeRef), "onPlaidCallback")
@@ -212,6 +213,7 @@ let make = (
212213
mountedIframeRef,
213214
disableSavedPaymentMethods,
214215
componentType,
216+
promiseResolve,
215217
) => {
216218
if !disableSavedPaymentMethods {
217219
let handleCustomerPaymentMethodsLoaded = (event: Types.event) => {
@@ -223,13 +225,16 @@ let make = (
223225
let json = dict->getJsonFromDict("response", JSON.Encode.null)
224226
let msg = [("customerPaymentMethods", json)]->Dict.fromArray
225227
mountedIframeRef->Window.iframePostMessage(msg)
228+
promiseResolve()
226229
}
227230
}
228231
addSmartEventListener(
229232
"message",
230233
handleCustomerPaymentMethodsLoaded,
231234
`onCustomerPaymentMethodsLoaded-${componentType}`,
232235
)
236+
} else {
237+
promiseResolve()
233238
}
234239
let msg =
235240
[
@@ -809,13 +814,14 @@ let make = (
809814
addSmartEventListener("message", handleGooglePayThirdPartyFlow, "onGooglePayThirdParty")
810815
addSmartEventListener("message", handleApplePayThirdPartyFlow, "onApplePayThirdParty")
811816

812-
let fetchSessionTokens = mountedIframeRef => {
817+
let fetchSessionTokens = (mountedIframeRef, promiseResolve) => {
813818
let handleSessionTokensLoaded = (event: Types.event) => {
814819
let json = event.data->anyTypeToJson
815820
let dict = json->getDictFromJson
816821
let sessionTokensData = dict->getString("data", "") === "session_tokens"
817822
if sessionTokensData {
818823
let json = dict->getJsonFromDict("response", JSON.Encode.null)
824+
promiseResolve()
819825

820826
{
821827
let sessionsArr =
@@ -1288,22 +1294,42 @@ let make = (
12881294
}
12891295
preMountLoaderMountedPromise
12901296
->then(_ => {
1291-
fetchPaymentsList(mountedIframeRef, componentType)
1297+
let paymentMethodsPromise = Promise.make((resolve, _) => {
1298+
fetchPaymentsList(mountedIframeRef, componentType, resolve)
1299+
})
12921300
let disableSavedPaymentMethods =
12931301
newOptions
12941302
->getDictFromJson
12951303
->getBool("displaySavedPaymentMethods", true) &&
12961304
!(spmComponents->Array.includes(componentType))->not
1297-
fetchCustomerPaymentMethods(mountedIframeRef, disableSavedPaymentMethods, componentType)
1298-
fetchSessionTokens(mountedIframeRef)
1299-
resolve()
1305+
let customerPaymentMethodsPromise = Promise.make((resolve, _) => {
1306+
fetchCustomerPaymentMethods(
1307+
mountedIframeRef,
1308+
disableSavedPaymentMethods,
1309+
componentType,
1310+
resolve,
1311+
)
1312+
})
1313+
let sessionTokensPromise = Promise.make((resolve, _) => {
1314+
fetchSessionTokens(mountedIframeRef, resolve)
1315+
})
1316+
Promise.all([
1317+
paymentMethodsPromise,
1318+
customerPaymentMethodsPromise,
1319+
sessionTokensPromise,
1320+
])->then(_ => {
1321+
let msg = [("cleanUpPreMountLoaderIframe", true->JSON.Encode.bool)]->Dict.fromArray
1322+
preMountLoaderIframeDiv->Window.iframePostMessage(msg)
1323+
resolve()
1324+
})
13001325
})
13011326
->catch(_ => resolve())
13021327
->ignore
13031328

13041329
mountedIframeRef->Window.iframePostMessage(message)
13051330
}
13061331

1332+
Console.log("Creating payment element")
13071333
let paymentElement = LoaderPaymentElement.make(
13081334
componentType,
13091335
newOptions,
@@ -1315,6 +1341,7 @@ let make = (
13151341
savedPaymentElement->Dict.set(componentType, paymentElement)
13161342
paymentElement
13171343
}
1344+
Console.log("Elements initialization completed")
13181345
{
13191346
getElement,
13201347
update,
@@ -1323,6 +1350,7 @@ let make = (
13231350
}
13241351
} catch {
13251352
| e => {
1353+
Console.log2(`Elements initialization failed: `, e)
13261354
Sentry.captureException(e)
13271355
defaultElement
13281356
}

src/hyper-loader/PaymentMethodsManagementElements.res

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,19 @@ let make = (
9898
)
9999
})
100100

101-
let fetchSavedPaymentMethods = (mountedIframeRef, disableSaveCards, componentType) => {
101+
let fetchSavedPaymentMethods = (
102+
mountedIframeRef,
103+
disableSaveCards,
104+
componentType,
105+
resolvePromise,
106+
) => {
102107
if !disableSaveCards {
103108
let handleSavedPaymentMethodsLoaded = (event: Types.event) => {
104109
let json = event.data->Identity.anyTypeToJson
105110
let dict = json->getDictFromJson
106111
let isSavedPaymentMethodsData = dict->getString("data", "") === "saved_payment_methods"
107112
if isSavedPaymentMethodsData {
113+
resolvePromise()
108114
let json = dict->getJsonFromDict("response", JSON.Encode.null)
109115
let msg = [("savedPaymentMethods", json)]->Dict.fromArray
110116
mountedIframeRef->Window.iframePostMessage(msg)
@@ -115,6 +121,8 @@ let make = (
115121
handleSavedPaymentMethodsLoaded,
116122
`onSavedPaymentMethodsLoaded-${componentType}`,
117123
)
124+
} else {
125+
resolvePromise()
118126
}
119127
let msg =
120128
[("sendSavedPaymentMethodsResponse", !disableSaveCards->JSON.Encode.bool)]->Dict.fromArray
@@ -208,7 +216,15 @@ let make = (
208216
disableSavedPaymentMethods &&
209217
!(expressCheckoutComponents->Array.includes(componentType))
210218
) {
211-
fetchSavedPaymentMethods(mountedIframeRef, false, componentType)
219+
Promise.make((resolve, _) => {
220+
fetchSavedPaymentMethods(mountedIframeRef, false, componentType, resolve)
221+
})
222+
->then(_ => {
223+
let msg = [("cleanUpPreMountLoaderIframe", true->JSON.Encode.bool)]->Dict.fromArray
224+
preMountLoaderIframeDiv->Window.iframePostMessage(msg)
225+
resolve()
226+
})
227+
->ignore
212228
}
213229
resolve()
214230
})

0 commit comments

Comments
 (0)