@flopay/react 0.5.2 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +150 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +150 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -522,6 +522,27 @@ function buildDeclineEvent(method, input, overrides) {
|
|
|
522
522
|
...declineCode ? { declineCode } : {}
|
|
523
523
|
};
|
|
524
524
|
}
|
|
525
|
+
function isRecord(value) {
|
|
526
|
+
return typeof value === "object" && value !== null;
|
|
527
|
+
}
|
|
528
|
+
function readString(payload, key) {
|
|
529
|
+
const value = payload?.[key];
|
|
530
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
531
|
+
}
|
|
532
|
+
function buildFloPayApiError(payload, fallbackMessage) {
|
|
533
|
+
const nestedError = isRecord(payload?.error) ? payload.error : null;
|
|
534
|
+
const message = readString(payload, "message") ?? readString(nestedError, "message") ?? fallbackMessage;
|
|
535
|
+
const code = readString(payload, "code") ?? readString(payload, "gatewayErrorCode") ?? readString(nestedError, "code");
|
|
536
|
+
const declineCode = readString(payload, "declineCode") ?? readString(payload, "gatewayDeclineReason") ?? readString(payload, "decline_code") ?? readString(nestedError, "decline_code");
|
|
537
|
+
return new FloPayError(message, "api_error", {
|
|
538
|
+
...code ? { code } : {},
|
|
539
|
+
...declineCode ? { declineCode } : {}
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
async function buildFloPayApiErrorFromResponse(response, fallbackMessage) {
|
|
543
|
+
const payload = await response.json().catch(() => null);
|
|
544
|
+
return buildFloPayApiError(payload, fallbackMessage);
|
|
545
|
+
}
|
|
525
546
|
function mapPayPalIntentStatusToPaymentResult(status) {
|
|
526
547
|
if (status === "succeeded") {
|
|
527
548
|
return "succeeded";
|
|
@@ -531,6 +552,29 @@ function mapPayPalIntentStatusToPaymentResult(status) {
|
|
|
531
552
|
}
|
|
532
553
|
return "failed";
|
|
533
554
|
}
|
|
555
|
+
function resolvePaymentIntentPaymentMethodId(paymentIntent) {
|
|
556
|
+
const paymentMethod = paymentIntent?.payment_method;
|
|
557
|
+
if (typeof paymentMethod === "string" && paymentMethod.startsWith("pm_")) {
|
|
558
|
+
return paymentMethod;
|
|
559
|
+
}
|
|
560
|
+
if (paymentMethod && typeof paymentMethod === "object" && typeof paymentMethod.id === "string") {
|
|
561
|
+
return paymentMethod.id;
|
|
562
|
+
}
|
|
563
|
+
return void 0;
|
|
564
|
+
}
|
|
565
|
+
async function retrievePaymentIntentFromProvider(provider, clientSecret) {
|
|
566
|
+
const retriever = provider;
|
|
567
|
+
if (!retriever?.retrievePaymentIntent) {
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
const { paymentIntent, error } = await retriever.retrievePaymentIntent(clientSecret);
|
|
571
|
+
if (error) {
|
|
572
|
+
throw new FloPayError(error.message ?? "Failed to retrieve payment intent.", "api_error", {
|
|
573
|
+
...error.code ? { code: error.code } : {}
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
return paymentIntent ?? null;
|
|
577
|
+
}
|
|
534
578
|
function resolveTokenizedPaymentMethodId(tokenizedBody) {
|
|
535
579
|
const candidates = [
|
|
536
580
|
tokenizedBody?.id,
|
|
@@ -775,7 +819,16 @@ function PayPalButtonInner({
|
|
|
775
819
|
setup_future_usage: "off_session"
|
|
776
820
|
})
|
|
777
821
|
});
|
|
778
|
-
if (!intentResponse.ok)
|
|
822
|
+
if (!intentResponse.ok) {
|
|
823
|
+
const intentError = await buildFloPayApiErrorFromResponse(
|
|
824
|
+
intentResponse,
|
|
825
|
+
"Failed to create payment intent"
|
|
826
|
+
);
|
|
827
|
+
onErrorChange?.(intentError.message);
|
|
828
|
+
onDecline?.(buildDeclineEvent("paypal", intentError));
|
|
829
|
+
event.paymentFailed({ reason: "fail", message: intentError.message });
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
779
832
|
const intentJson = await intentResponse.json();
|
|
780
833
|
const intentClientSecret = intentJson.data?.id;
|
|
781
834
|
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
@@ -912,7 +965,16 @@ function WalletButtonInner({
|
|
|
912
965
|
isPaypal: false
|
|
913
966
|
})
|
|
914
967
|
});
|
|
915
|
-
if (!intentResponse.ok)
|
|
968
|
+
if (!intentResponse.ok) {
|
|
969
|
+
const intentError = await buildFloPayApiErrorFromResponse(
|
|
970
|
+
intentResponse,
|
|
971
|
+
"Failed to create payment intent"
|
|
972
|
+
);
|
|
973
|
+
onErrorChange?.(intentError.message);
|
|
974
|
+
onDecline?.(buildDeclineEvent(method, intentError));
|
|
975
|
+
event.paymentFailed({ reason: "fail", message: intentError.message });
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
916
978
|
const intentJson = await intentResponse.json();
|
|
917
979
|
const intentClientSecret = intentJson.data?.id;
|
|
918
980
|
if (!intentClientSecret) throw new Error("No client_secret in payment intent response");
|
|
@@ -1527,7 +1589,18 @@ function SplitCardFormInner({
|
|
|
1527
1589
|
isPaypal: false
|
|
1528
1590
|
})
|
|
1529
1591
|
});
|
|
1530
|
-
if (!intentResponse.ok)
|
|
1592
|
+
if (!intentResponse.ok) {
|
|
1593
|
+
const intentError = await buildFloPayApiErrorFromResponse(
|
|
1594
|
+
intentResponse,
|
|
1595
|
+
"Failed to create payment intent"
|
|
1596
|
+
);
|
|
1597
|
+
setOverlayStatus("error");
|
|
1598
|
+
updateError(intentError.message);
|
|
1599
|
+
onError?.(intentError);
|
|
1600
|
+
emitDecline("card", intentError);
|
|
1601
|
+
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
|
|
1602
|
+
return;
|
|
1603
|
+
}
|
|
1531
1604
|
const intentJson = await intentResponse.json();
|
|
1532
1605
|
const intentClientSecret = intentJson.data?.id;
|
|
1533
1606
|
if (!intentClientSecret) throw new FloPayError2("No client_secret in payment intent response", "api_error");
|
|
@@ -1543,11 +1616,26 @@ function SplitCardFormInner({
|
|
|
1543
1616
|
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
|
|
1544
1617
|
return;
|
|
1545
1618
|
}
|
|
1619
|
+
const rawProvider = typeof flopay.getRawProvider === "function" ? flopay.getRawProvider() : null;
|
|
1620
|
+
const confirmedPaymentIntent = await retrievePaymentIntentFromProvider(
|
|
1621
|
+
rawProvider,
|
|
1622
|
+
intentClientSecret
|
|
1623
|
+
);
|
|
1624
|
+
const paymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
|
|
1625
|
+
const paymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? pmResult.paymentMethodId;
|
|
1626
|
+
if (!paymentIntentId) {
|
|
1627
|
+
const error2 = new FloPayError2("No payment intent returned after confirmation.", "api_error");
|
|
1628
|
+
setOverlayStatus("error");
|
|
1629
|
+
updateError(error2.message);
|
|
1630
|
+
onError?.(error2);
|
|
1631
|
+
await new Promise((r) => setTimeout(r, PROCESSING_OVERLAY_ERROR_DELAY_MS));
|
|
1632
|
+
return;
|
|
1633
|
+
}
|
|
1546
1634
|
handedOff = isSelfContained;
|
|
1547
1635
|
dispatchTokenizedBody({
|
|
1548
|
-
id:
|
|
1636
|
+
id: paymentMethodId,
|
|
1549
1637
|
type: "card",
|
|
1550
|
-
threeDSecureActionResultTokenId:
|
|
1638
|
+
threeDSecureActionResultTokenId: paymentIntentId,
|
|
1551
1639
|
originalPaymentMethodId: pmResult.paymentMethodId
|
|
1552
1640
|
});
|
|
1553
1641
|
} catch (err) {
|
|
@@ -2368,12 +2456,12 @@ async function processSavedPaymentWithIntent({
|
|
|
2368
2456
|
));
|
|
2369
2457
|
const intentJson = await intentResponse.json().catch(() => null);
|
|
2370
2458
|
if (!intentResponse.ok) {
|
|
2459
|
+
const intentError = buildFloPayApiError(
|
|
2460
|
+
intentJson,
|
|
2461
|
+
"Failed to create payment intent."
|
|
2462
|
+
);
|
|
2371
2463
|
throw Object.assign(
|
|
2372
|
-
|
|
2373
|
-
intentJson?.message ?? "Failed to create payment intent.",
|
|
2374
|
-
"api_error",
|
|
2375
|
-
{ code: intentJson?.code ?? intentJson?.gatewayErrorCode }
|
|
2376
|
-
),
|
|
2464
|
+
intentError,
|
|
2377
2465
|
{ checkoutMethod: "card" }
|
|
2378
2466
|
);
|
|
2379
2467
|
}
|
|
@@ -2396,7 +2484,14 @@ async function processSavedPaymentWithIntent({
|
|
|
2396
2484
|
{ checkoutMethod: "card" }
|
|
2397
2485
|
);
|
|
2398
2486
|
}
|
|
2399
|
-
|
|
2487
|
+
const rawProvider = typeof flopay.getRawProvider === "function" ? flopay.getRawProvider() : null;
|
|
2488
|
+
const confirmedPaymentIntent = await retrievePaymentIntentFromProvider(
|
|
2489
|
+
rawProvider,
|
|
2490
|
+
intentClientSecret
|
|
2491
|
+
);
|
|
2492
|
+
const confirmedPaymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
|
|
2493
|
+
const confirmedPaymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? paymentMethodId;
|
|
2494
|
+
if (!confirmedPaymentIntentId || confirmResult.status !== "succeeded" && confirmResult.status !== "processing" && confirmResult.status !== "requires_capture") {
|
|
2400
2495
|
throw Object.assign(
|
|
2401
2496
|
new FloPayError3(
|
|
2402
2497
|
`Unfortunately, your payment could not be processed. Please try again using a different payment method or contact your bank for assistance. If the issue persists, feel free to reach out to us for support.`,
|
|
@@ -2413,9 +2508,9 @@ async function processSavedPaymentWithIntent({
|
|
|
2413
2508
|
sessionId,
|
|
2414
2509
|
session,
|
|
2415
2510
|
tokenizedData: {
|
|
2416
|
-
id:
|
|
2511
|
+
id: confirmedPaymentMethodId,
|
|
2417
2512
|
type: "card",
|
|
2418
|
-
threeDSecureActionResultTokenId:
|
|
2513
|
+
threeDSecureActionResultTokenId: confirmedPaymentIntentId
|
|
2419
2514
|
},
|
|
2420
2515
|
returnUrl
|
|
2421
2516
|
});
|
|
@@ -2430,8 +2525,8 @@ async function processSavedPaymentWithIntent({
|
|
|
2430
2525
|
});
|
|
2431
2526
|
return {
|
|
2432
2527
|
...finalResult,
|
|
2433
|
-
paymentIntentId: finalResult.paymentIntentId ??
|
|
2434
|
-
paymentMethodId: finalResult.paymentMethodId ??
|
|
2528
|
+
paymentIntentId: finalResult.paymentIntentId ?? confirmedPaymentIntentId,
|
|
2529
|
+
paymentMethodId: finalResult.paymentMethodId ?? confirmedPaymentMethodId,
|
|
2435
2530
|
checkoutMethod: finalResult.checkoutMethod ?? "card"
|
|
2436
2531
|
};
|
|
2437
2532
|
}
|
|
@@ -3016,14 +3111,19 @@ function FloPayCheckout({
|
|
|
3016
3111
|
function hashCreateParams(params) {
|
|
3017
3112
|
const key = JSON.stringify({
|
|
3018
3113
|
c: params?.clientId,
|
|
3114
|
+
a: {
|
|
3115
|
+
u: params?.account?.userId ?? "",
|
|
3116
|
+
e: params?.account?.email?.trim().toLowerCase() ?? "",
|
|
3117
|
+
country: params?.account?.country ?? ""
|
|
3118
|
+
},
|
|
3019
3119
|
successUrl: params?.successUrl,
|
|
3020
3120
|
cancelUrl: params?.cancelUrl,
|
|
3021
3121
|
i: params?.items?.map((x) => `${x.providerItemId}:${x.totalAmount}:${x.overrideAmount ?? ""}:${x.quantity ?? 1}`).sort(),
|
|
3022
3122
|
s: params?.subscriptions?.map((x) => `${x.providerPlanId}:${x.totalAmount}:${x.overrideAmount ?? ""}:${x.quantity ?? 1}`).sort(),
|
|
3023
|
-
account: params?.account,
|
|
3024
3123
|
couponCodes: params?.couponCodes,
|
|
3025
3124
|
tagsData: params?.tagsData,
|
|
3026
3125
|
utmMetadata: params?.utmMetadata,
|
|
3126
|
+
tokenizedData: params?.tokenizedData,
|
|
3027
3127
|
m: params?.checkoutMode ?? "full"
|
|
3028
3128
|
});
|
|
3029
3129
|
let h = 0;
|
|
@@ -3178,7 +3278,8 @@ function FloPayCheckout({
|
|
|
3178
3278
|
};
|
|
3179
3279
|
}
|
|
3180
3280
|
(async () => {
|
|
3181
|
-
const
|
|
3281
|
+
const hasPayPalRedirectParams = typeof window !== "undefined" && new URLSearchParams(window.location.search).has("payment_intent");
|
|
3282
|
+
const shouldAutoProcessInlineSession = effectiveCreateSessionMode === "auto" && !autoCheckoutAttempted.current && !hasPayPalRedirectParams;
|
|
3182
3283
|
if (shouldAutoProcessInlineSession) {
|
|
3183
3284
|
setModeError(null);
|
|
3184
3285
|
setModeOverlayError(null);
|
|
@@ -4025,6 +4126,7 @@ function CheckoutFormInner({
|
|
|
4025
4126
|
if (!flopay || !elements || isSubmitting) return;
|
|
4026
4127
|
setProcessing(true);
|
|
4027
4128
|
updateError(null);
|
|
4129
|
+
let handedOff = false;
|
|
4028
4130
|
try {
|
|
4029
4131
|
const submitResult = await flopay.submitElements();
|
|
4030
4132
|
if (submitResult.error) {
|
|
@@ -4054,7 +4156,16 @@ function CheckoutFormInner({
|
|
|
4054
4156
|
isPaypal: false
|
|
4055
4157
|
})
|
|
4056
4158
|
});
|
|
4057
|
-
if (!intentResponse.ok)
|
|
4159
|
+
if (!intentResponse.ok) {
|
|
4160
|
+
const intentError = await buildFloPayApiErrorFromResponse(
|
|
4161
|
+
intentResponse,
|
|
4162
|
+
"Failed to create payment intent"
|
|
4163
|
+
);
|
|
4164
|
+
updateError(intentError.message);
|
|
4165
|
+
onError?.(intentError);
|
|
4166
|
+
emitDecline(intentError);
|
|
4167
|
+
return;
|
|
4168
|
+
}
|
|
4058
4169
|
const intentJson = await intentResponse.json();
|
|
4059
4170
|
const intentClientSecret = intentJson.data?.id;
|
|
4060
4171
|
if (!intentClientSecret) throw new FloPayError5("No client_secret in payment intent response", "api_error");
|
|
@@ -4068,17 +4179,30 @@ function CheckoutFormInner({
|
|
|
4068
4179
|
emitDecline(confirmResult.error);
|
|
4069
4180
|
return;
|
|
4070
4181
|
}
|
|
4182
|
+
const rawProvider = typeof flopay.getRawProvider === "function" ? flopay.getRawProvider() : null;
|
|
4183
|
+
const confirmedPaymentIntent = await retrievePaymentIntentFromProvider(
|
|
4184
|
+
rawProvider,
|
|
4185
|
+
intentClientSecret
|
|
4186
|
+
);
|
|
4187
|
+
const paymentIntentId = confirmResult.paymentIntentId ?? confirmedPaymentIntent?.id;
|
|
4188
|
+
const paymentMethodId = confirmResult.paymentMethodId ?? resolvePaymentIntentPaymentMethodId(confirmedPaymentIntent) ?? pmResult.paymentMethodId;
|
|
4189
|
+
if (!paymentIntentId) {
|
|
4190
|
+
const error2 = new FloPayError5("No payment intent returned after confirmation.", "api_error");
|
|
4191
|
+
updateError(error2.message);
|
|
4192
|
+
onError?.(error2);
|
|
4193
|
+
return;
|
|
4194
|
+
}
|
|
4195
|
+
handedOff = isSelfContained;
|
|
4071
4196
|
dispatchTokenizedBody({
|
|
4072
|
-
id:
|
|
4197
|
+
id: paymentMethodId,
|
|
4073
4198
|
type: "card",
|
|
4074
|
-
threeDSecureActionResultTokenId:
|
|
4199
|
+
threeDSecureActionResultTokenId: paymentIntentId,
|
|
4075
4200
|
originalPaymentMethodId: pmResult.paymentMethodId
|
|
4076
4201
|
});
|
|
4077
4202
|
} catch (err) {
|
|
4078
4203
|
updateError(err instanceof Error ? err.message : "An unexpected error occurred");
|
|
4079
4204
|
} finally {
|
|
4080
|
-
if (
|
|
4081
|
-
} else {
|
|
4205
|
+
if (!handedOff) {
|
|
4082
4206
|
setProcessing(false);
|
|
4083
4207
|
}
|
|
4084
4208
|
}
|
|
@@ -4756,7 +4880,10 @@ function FloPayAutomaticPaymentButton({
|
|
|
4756
4880
|
return;
|
|
4757
4881
|
}
|
|
4758
4882
|
try {
|
|
4759
|
-
const result = await api.createAndFetchSession(
|
|
4883
|
+
const result = await api.createAndFetchSession({
|
|
4884
|
+
...createSessionDraft,
|
|
4885
|
+
...automaticPaymentToken ? { tokenizedData: automaticPaymentToken } : {}
|
|
4886
|
+
});
|
|
4760
4887
|
await processResolvedSession(result, result.data.session?.id ?? null, {
|
|
4761
4888
|
fromCreateSession: true
|
|
4762
4889
|
});
|