@flopay/react 1.1.0 → 1.1.4
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/README.md +8 -2
- package/dist/index.cjs +163 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +163 -63
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -215,7 +215,8 @@ Use `onButtonClick` to track button interactions, `onDecline` to track declines/
|
|
|
215
215
|
layout="buttons"
|
|
216
216
|
createSession={{
|
|
217
217
|
clientId: 'your-client-id',
|
|
218
|
-
|
|
218
|
+
currency: 'EUR',
|
|
219
|
+
items: [{ providerItemId: 'product-1', providerItemName: 'Widget', totalAmount: 29.99 }],
|
|
219
220
|
account: { userId: 'user_1', email: 'test@email.com' },
|
|
220
221
|
successUrl: '/success',
|
|
221
222
|
cancelUrl: '/cancel',
|
|
@@ -258,7 +259,8 @@ Skip the backend API route — create the session directly in the component:
|
|
|
258
259
|
layout="buttons"
|
|
259
260
|
createSession={{
|
|
260
261
|
clientId: 'your-client-id',
|
|
261
|
-
|
|
262
|
+
currency: 'EUR',
|
|
263
|
+
items: [{ providerItemId: 'product-1', providerItemName: 'Widget', totalAmount: 29.99 }],
|
|
262
264
|
account: { userId: 'user_1', email: 'user@example.com', firstName: 'Jane', lastName: 'Doe' },
|
|
263
265
|
successUrl: '/success',
|
|
264
266
|
cancelUrl: '/cancel',
|
|
@@ -269,6 +271,8 @@ Skip the backend API route — create the session directly in the component:
|
|
|
269
271
|
|
|
270
272
|
The component POSTs to the billing API, gets the full session back, and renders the form — zero backend code needed.
|
|
271
273
|
|
|
274
|
+
Session-level `currency` is now **required**. The backend (#760) enforces `@IsNotEmpty` on the field; the SDK pre-validates and throws `FloPayError({ type: 'validation_error', code: 'CurrencyRequired' })` before issuing the request when neither the session nor any item/subscription/product carries a currency. Pass `currency` at the top of `createSession` (preferred), or rely on the legacy fallback to the first item/subscription/product `currency`.
|
|
275
|
+
|
|
272
276
|
When you use `onBeforeButtonClick` with `createSession`, any returned `InlineSessionPatch` is merged into the draft session params before the selected buttons-layout flow continues. That lets you add tracking data or update account fields just in time without pre-creating a separate backend session.
|
|
273
277
|
|
|
274
278
|
### Advanced: Manual Provider Setup
|
|
@@ -396,6 +400,8 @@ The SDK supports two PayPal paths, selected per-session based on what the billin
|
|
|
396
400
|
|
|
397
401
|
Renderer selection is mutually exclusive per session — direct PayPal takes priority over Stripe-rendered PayPal. Consumer props such as `showPayPal` continue to gate visibility on the client side.
|
|
398
402
|
|
|
403
|
+
**PayPal-only sessions:** When the backend advertises only `gateways.paypal` (no `gateways.stripe`), `FloPayCheckout` skips Stripe Elements entirely and renders `<DirectPayPalButton>` as the sole payment surface. Sessions that advertise no supported gateway at all throw a `validation_error` explaining the expected shape.
|
|
404
|
+
|
|
399
405
|
The SDK exposes the relevant pieces in three ways:
|
|
400
406
|
|
|
401
407
|
- **`SplitCardForm`** / **`FloPayCheckout`**: pick the renderer automatically based on `gateways.*`. No additional configuration needed.
|
package/dist/index.cjs
CHANGED
|
@@ -495,15 +495,37 @@ function mergeInlineSessionPatch(params, patch) {
|
|
|
495
495
|
};
|
|
496
496
|
}
|
|
497
497
|
function buildSyntheticSession(params, checkoutModeOverride) {
|
|
498
|
-
const
|
|
499
|
-
...(params.
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
498
|
+
const inputProducts = params.products ?? [
|
|
499
|
+
...(params.subscriptions ?? []).map((s) => ({
|
|
500
|
+
type: "subscription",
|
|
501
|
+
code: s.code ?? s.providerPlanId,
|
|
502
|
+
name: s.subscriptionName ?? s.providerPlanName ?? s.code ?? s.providerPlanId ?? null,
|
|
503
|
+
quantity: s.quantity ?? 1,
|
|
504
|
+
totalAmount: s.totalAmount,
|
|
505
|
+
overrideAmount: s.overrideAmount,
|
|
506
|
+
currency: s.currency,
|
|
507
|
+
metadata: s.metadata
|
|
508
|
+
})),
|
|
509
|
+
...(params.items ?? []).map((i) => ({
|
|
510
|
+
type: "item",
|
|
511
|
+
code: i.code ?? i.providerItemId,
|
|
512
|
+
name: i.itemName ?? i.providerItemName ?? i.code ?? i.providerItemId ?? null,
|
|
513
|
+
quantity: i.quantity ?? 1,
|
|
514
|
+
totalAmount: i.totalAmount,
|
|
515
|
+
overrideAmount: i.overrideAmount,
|
|
516
|
+
currency: i.currency,
|
|
517
|
+
metadata: i.metadata
|
|
518
|
+
}))
|
|
519
|
+
];
|
|
520
|
+
const totalAmount = inputProducts.reduce(
|
|
521
|
+
(sum, p) => sum + (p.overrideAmount ?? p.totalAmount ?? 0),
|
|
522
|
+
0
|
|
523
|
+
);
|
|
524
|
+
const currency = params.currency ?? inputProducts.find((p) => p.currency)?.currency ?? "USD";
|
|
503
525
|
return {
|
|
504
526
|
id: "",
|
|
505
527
|
clientSecret: "",
|
|
506
|
-
mode: "payment",
|
|
528
|
+
mode: inputProducts.some((p) => p.type === "subscription") ? "subscription" : "payment",
|
|
507
529
|
amount: Math.round(totalAmount * 100),
|
|
508
530
|
currency,
|
|
509
531
|
status: "open",
|
|
@@ -521,40 +543,18 @@ function buildSyntheticSession(params, checkoutModeOverride) {
|
|
|
521
543
|
successUrl: params.successUrl,
|
|
522
544
|
cancelUrl: params.cancelUrl,
|
|
523
545
|
checkoutMode: checkoutModeOverride ?? params.checkoutMode ?? "full",
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
overrideAmount: item.overrideAmount ?? null,
|
|
537
|
-
currency: item.currency ?? currency,
|
|
538
|
-
metadata: item.metadata ?? null
|
|
539
|
-
};
|
|
540
|
-
}),
|
|
541
|
-
subscriptions: (params.subscriptions ?? []).map((subscription, idx) => {
|
|
542
|
-
const code = subscription.code ?? subscription.providerPlanId;
|
|
543
|
-
const subscriptionName = subscription.subscriptionName ?? subscription.providerPlanName ?? code;
|
|
544
|
-
return {
|
|
545
|
-
uuid: `synthetic-sub-${idx}`,
|
|
546
|
-
checkoutSessionId: "",
|
|
547
|
-
code,
|
|
548
|
-
providerPlanId: code,
|
|
549
|
-
subscriptionName,
|
|
550
|
-
providerPlanName: subscriptionName,
|
|
551
|
-
quantity: subscription.quantity ?? 1,
|
|
552
|
-
totalAmount: subscription.totalAmount,
|
|
553
|
-
overrideAmount: subscription.overrideAmount ?? null,
|
|
554
|
-
currency: subscription.currency ?? currency,
|
|
555
|
-
metadata: subscription.metadata ?? null
|
|
556
|
-
};
|
|
557
|
-
})
|
|
546
|
+
products: inputProducts.map((p, idx) => ({
|
|
547
|
+
uuid: `synthetic-${p.type}-${idx}`,
|
|
548
|
+
checkoutSessionId: "",
|
|
549
|
+
type: p.type,
|
|
550
|
+
code: p.code,
|
|
551
|
+
name: p.name ?? null,
|
|
552
|
+
quantity: p.quantity ?? 1,
|
|
553
|
+
totalAmount: p.totalAmount,
|
|
554
|
+
overrideAmount: p.overrideAmount ?? null,
|
|
555
|
+
currency: p.currency ?? currency,
|
|
556
|
+
metadata: p.metadata ?? null
|
|
557
|
+
}))
|
|
558
558
|
};
|
|
559
559
|
}
|
|
560
560
|
function mergeAccountPatch(base, patch) {
|
|
@@ -582,9 +582,25 @@ function readString(payload, key) {
|
|
|
582
582
|
const value = payload?.[key];
|
|
583
583
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
584
584
|
}
|
|
585
|
+
var FRIENDLY_MESSAGE_OVERRIDES = [
|
|
586
|
+
{
|
|
587
|
+
match: /^paypal authorization required\.?$/i,
|
|
588
|
+
replacement: "For your additional security, please re-authenticate this payment via PayPal."
|
|
589
|
+
}
|
|
590
|
+
];
|
|
591
|
+
function applyFriendlyMessageOverride(message) {
|
|
592
|
+
if (typeof message !== "string") return message ?? void 0;
|
|
593
|
+
const trimmed = message.trim();
|
|
594
|
+
if (!trimmed) return message;
|
|
595
|
+
for (const { match, replacement } of FRIENDLY_MESSAGE_OVERRIDES) {
|
|
596
|
+
if (match.test(trimmed)) return replacement;
|
|
597
|
+
}
|
|
598
|
+
return message;
|
|
599
|
+
}
|
|
585
600
|
function buildFloPayApiError(payload, fallbackMessage) {
|
|
586
601
|
const nestedError = isRecord(payload?.error) ? payload.error : null;
|
|
587
|
-
const
|
|
602
|
+
const rawMessage = readString(payload, "message") ?? readString(nestedError, "message") ?? fallbackMessage;
|
|
603
|
+
const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
|
|
588
604
|
const code = readString(payload, "code") ?? readString(payload, "gatewayErrorCode") ?? readString(nestedError, "code");
|
|
589
605
|
const declineCode = readString(payload, "declineCode") ?? readString(payload, "gatewayDeclineReason") ?? readString(payload, "decline_code") ?? readString(nestedError, "decline_code");
|
|
590
606
|
return new import_shared3.FloPayError(message, "api_error", {
|
|
@@ -775,7 +791,7 @@ function DirectPayPalButton({
|
|
|
775
791
|
if (!clientId) {
|
|
776
792
|
appendDebug("FAIL: clientId empty \u2014 gateway misconfigured");
|
|
777
793
|
setFailed(true);
|
|
778
|
-
|
|
794
|
+
console.error("[FloPay] DirectPayPal: clientId empty \u2014 gateway misconfigured");
|
|
779
795
|
return;
|
|
780
796
|
}
|
|
781
797
|
if (!containerRef.current) {
|
|
@@ -886,7 +902,8 @@ function DirectPayPalButton({
|
|
|
886
902
|
const forwardError = (message) => {
|
|
887
903
|
if (cancelled) return;
|
|
888
904
|
if (isZoidLifecycleMessage(message)) return;
|
|
889
|
-
|
|
905
|
+
const friendly = applyFriendlyMessageOverride(message) ?? message;
|
|
906
|
+
onErrorChangeRef.current?.(friendly);
|
|
890
907
|
};
|
|
891
908
|
const markRenderFailed = (message) => {
|
|
892
909
|
if (cancelled) return;
|
|
@@ -895,7 +912,7 @@ function DirectPayPalButton({
|
|
|
895
912
|
return;
|
|
896
913
|
}
|
|
897
914
|
setFailed(true);
|
|
898
|
-
|
|
915
|
+
console.error("[FloPay] DirectPayPal load/render failure:", message);
|
|
899
916
|
};
|
|
900
917
|
setFailed(false);
|
|
901
918
|
const dispatchTokenizedBody = async (body) => {
|
|
@@ -933,14 +950,16 @@ function DirectPayPalButton({
|
|
|
933
950
|
return;
|
|
934
951
|
}
|
|
935
952
|
const json = await response.json().catch(() => null);
|
|
936
|
-
const
|
|
953
|
+
const rawMessage = json?.["message"] ?? "PayPal payment failed.";
|
|
954
|
+
const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
|
|
937
955
|
forwardError(message);
|
|
938
956
|
onDeclineRef.current?.(buildDeclineEvent("paypal", message, {
|
|
939
957
|
code: json?.["code"],
|
|
940
958
|
declineCode: json?.["declineCode"]
|
|
941
959
|
}));
|
|
942
960
|
} catch (err) {
|
|
943
|
-
const
|
|
961
|
+
const rawMessage = err instanceof Error ? err.message : "PayPal payment failed.";
|
|
962
|
+
const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
|
|
944
963
|
forwardError(message);
|
|
945
964
|
onDeclineRef.current?.(buildDeclineEvent("paypal", message));
|
|
946
965
|
}
|
|
@@ -3090,9 +3109,11 @@ function getRedirectResultFromCheckoutProcessError(error) {
|
|
|
3090
3109
|
}
|
|
3091
3110
|
function checkoutProcessErrorToFloPayError(error, fallbackMessage = "Payment failed. Please try again.", options) {
|
|
3092
3111
|
const checkoutMethod = options?.checkoutMethod ?? error?.checkoutMethod ?? (error?.type === "paypal_redirect_required" ? "paypal" : "card");
|
|
3112
|
+
const rawMessage = error?.message ?? fallbackMessage;
|
|
3113
|
+
const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
|
|
3093
3114
|
return Object.assign(
|
|
3094
3115
|
new import_shared7.FloPayError(
|
|
3095
|
-
|
|
3116
|
+
message,
|
|
3096
3117
|
"api_error",
|
|
3097
3118
|
{
|
|
3098
3119
|
code: error?.gatewayErrorCode
|
|
@@ -3549,21 +3570,36 @@ async function handleSavedPaymentRedirectResult(redirectResult, {
|
|
|
3549
3570
|
}
|
|
3550
3571
|
function normalizeSavedPaymentError(err) {
|
|
3551
3572
|
if (err instanceof import_shared7.FloPayError) {
|
|
3573
|
+
const friendly = applyFriendlyMessageOverride(err.message);
|
|
3574
|
+
if (friendly && friendly !== err.message) {
|
|
3575
|
+
return Object.assign(
|
|
3576
|
+
new import_shared7.FloPayError(friendly, err.type, {
|
|
3577
|
+
code: err.code,
|
|
3578
|
+
declineCode: err.declineCode,
|
|
3579
|
+
param: err.param,
|
|
3580
|
+
statusCode: err.statusCode
|
|
3581
|
+
}),
|
|
3582
|
+
{ checkoutMethod: err.checkoutMethod }
|
|
3583
|
+
);
|
|
3584
|
+
}
|
|
3552
3585
|
return err;
|
|
3553
3586
|
}
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
);
|
|
3587
|
+
const rawMessage = err instanceof Error ? err.message : "Payment failed. Please try again.";
|
|
3588
|
+
const message = applyFriendlyMessageOverride(rawMessage) ?? rawMessage;
|
|
3589
|
+
return new import_shared7.FloPayError(message, "api_error");
|
|
3558
3590
|
}
|
|
3559
3591
|
function resolveSavedPaymentPublishableKeys(unified) {
|
|
3560
3592
|
const publishableKey = unified.data.stripe?.publishableKey;
|
|
3561
|
-
|
|
3593
|
+
const hasDirectPaypal = Boolean(unified.data.paypal?.publishableKey);
|
|
3594
|
+
if (!publishableKey && !hasDirectPaypal) {
|
|
3562
3595
|
throw new import_shared7.FloPayError(
|
|
3563
|
-
"
|
|
3596
|
+
"Session advertises no supported gateways (expected `gateways.stripe` and/or `gateways.paypal`).",
|
|
3564
3597
|
"validation_error"
|
|
3565
3598
|
);
|
|
3566
3599
|
}
|
|
3600
|
+
if (!publishableKey) {
|
|
3601
|
+
return {};
|
|
3602
|
+
}
|
|
3567
3603
|
return {
|
|
3568
3604
|
publishableKey,
|
|
3569
3605
|
// Direct-PayPal sessions can still use Stripe's PayPal Element for the
|
|
@@ -3580,6 +3616,9 @@ async function loadSavedPaymentProviders({
|
|
|
3580
3616
|
billingApiUrl,
|
|
3581
3617
|
locale
|
|
3582
3618
|
}) {
|
|
3619
|
+
if (!publishableKey) {
|
|
3620
|
+
return { flopay: null, paypalFlopay: null };
|
|
3621
|
+
}
|
|
3583
3622
|
const needsSeparatePaypal = Boolean(paypalPublishableKey) && paypalPublishableKey !== publishableKey;
|
|
3584
3623
|
const [instance, paypalInstanceOrError] = await Promise.all([
|
|
3585
3624
|
(0, import_js3.loadFloPay)(publishableKey, {
|
|
@@ -3616,6 +3655,11 @@ function resolveDirectPaypalConfig(unified) {
|
|
|
3616
3655
|
environment: unified?.data.paypal?.environment
|
|
3617
3656
|
};
|
|
3618
3657
|
}
|
|
3658
|
+
function isPayPalOnlyUnified(unified) {
|
|
3659
|
+
if (!unified) return false;
|
|
3660
|
+
if (unified.data.stripe?.publishableKey) return false;
|
|
3661
|
+
return Boolean(resolveDirectPaypalConfig(unified)?.clientId);
|
|
3662
|
+
}
|
|
3619
3663
|
function canUseStorage() {
|
|
3620
3664
|
return typeof window !== "undefined" && typeof window.sessionStorage !== "undefined";
|
|
3621
3665
|
}
|
|
@@ -3794,7 +3838,7 @@ function FloPayCheckout({
|
|
|
3794
3838
|
const redirectResult = getRedirectResultFromCheckoutProcessError(options?.initialAutoProcessingError);
|
|
3795
3839
|
let paymentResult;
|
|
3796
3840
|
if (redirectResult) {
|
|
3797
|
-
if (redirectResult.type === "paypal_redirect_required" && savedPaymentKeysRef.current) {
|
|
3841
|
+
if (redirectResult.type === "paypal_redirect_required" && savedPaymentKeysRef.current?.publishableKey) {
|
|
3798
3842
|
persistPayPalResumeState({
|
|
3799
3843
|
sessionId: activeSessionId2,
|
|
3800
3844
|
publishableKey: savedPaymentKeysRef.current.publishableKey,
|
|
@@ -3846,7 +3890,7 @@ function FloPayCheckout({
|
|
|
3846
3890
|
if (result.type === "success") {
|
|
3847
3891
|
paymentResult = result.result;
|
|
3848
3892
|
} else {
|
|
3849
|
-
if (result.type === "paypal_redirect_required" && savedPaymentKeysRef.current) {
|
|
3893
|
+
if (result.type === "paypal_redirect_required" && savedPaymentKeysRef.current?.publishableKey) {
|
|
3850
3894
|
persistPayPalResumeState({
|
|
3851
3895
|
sessionId: activeSessionId2,
|
|
3852
3896
|
publishableKey: savedPaymentKeysRef.current.publishableKey,
|
|
@@ -3937,7 +3981,7 @@ function FloPayCheckout({
|
|
|
3937
3981
|
billingApiUrl: resolvedBillingUrl,
|
|
3938
3982
|
locale
|
|
3939
3983
|
});
|
|
3940
|
-
const paypalStripe = (resumePaypalFlopay ?? resumeFlopay)
|
|
3984
|
+
const paypalStripe = (resumePaypalFlopay ?? resumeFlopay)?.getRawProvider();
|
|
3941
3985
|
if (!paypalStripe) {
|
|
3942
3986
|
throw Object.assign(
|
|
3943
3987
|
new import_shared8.FloPayError("PayPal is not available.", "api_error"),
|
|
@@ -4205,7 +4249,8 @@ function FloPayCheckout({
|
|
|
4205
4249
|
const resolved = await bootstrapInlineSession();
|
|
4206
4250
|
const resolvedSession = resolved.result.data.session ?? null;
|
|
4207
4251
|
savedPaymentKeysRef.current = resolveSavedPaymentPublishableKeys(resolved.result);
|
|
4208
|
-
|
|
4252
|
+
const resolvedPaypalOnly = isPayPalOnlyUnified(resolved.result);
|
|
4253
|
+
if (!cancelled && shouldAutoProcessInlineSession && resolvedSession && !resolvedPaypalOnly) {
|
|
4209
4254
|
autoCheckoutAttempted.current = true;
|
|
4210
4255
|
await runSavedPaymentFlow(resolvedSession, {
|
|
4211
4256
|
attempt3DS: true,
|
|
@@ -4219,6 +4264,9 @@ function FloPayCheckout({
|
|
|
4219
4264
|
return;
|
|
4220
4265
|
}
|
|
4221
4266
|
if (!cancelled && shouldAutoProcessInlineSession) {
|
|
4267
|
+
if (resolvedPaypalOnly) {
|
|
4268
|
+
autoCheckoutAttempted.current = true;
|
|
4269
|
+
}
|
|
4222
4270
|
setModeOverlayStatus(null);
|
|
4223
4271
|
setModeOverlayError(null);
|
|
4224
4272
|
}
|
|
@@ -4273,7 +4321,8 @@ function FloPayCheckout({
|
|
|
4273
4321
|
const effectiveMode = checkoutModeProp ?? sess.checkoutMode ?? "full";
|
|
4274
4322
|
setCurrentMode(effectiveMode);
|
|
4275
4323
|
const hasPayPalRedirectParams = typeof window !== "undefined" && new URLSearchParams(window.location.search).has("payment_intent");
|
|
4276
|
-
|
|
4324
|
+
const paypalOnly = isPayPalOnlyUnified(result);
|
|
4325
|
+
if (effectiveMode === "auto" && !autoCheckoutAttempted.current && !hasPayPalRedirectParams && !paypalOnly) {
|
|
4277
4326
|
autoCheckoutAttempted.current = true;
|
|
4278
4327
|
const stripeInitPromise = initStripe(result);
|
|
4279
4328
|
try {
|
|
@@ -4353,8 +4402,10 @@ function FloPayCheckout({
|
|
|
4353
4402
|
setConfirmProcessing(false);
|
|
4354
4403
|
}
|
|
4355
4404
|
}, [activeSessionId, confirmProcessing, runSavedPaymentFlow, session]);
|
|
4405
|
+
const directPaypalConfig = resolveDirectPaypalConfig(unified);
|
|
4406
|
+
const isPaypalOnlySession = isPayPalOnlyUnified(unified);
|
|
4356
4407
|
const providerOptions = (0, import_react9.useMemo)(() => {
|
|
4357
|
-
if (!unified || !session) return void 0;
|
|
4408
|
+
if (!unified || !session || !unified.data.stripe?.publishableKey) return void 0;
|
|
4358
4409
|
const opts = {
|
|
4359
4410
|
appearance,
|
|
4360
4411
|
paymentMethodCreation: "manual",
|
|
@@ -4393,7 +4444,7 @@ function FloPayCheckout({
|
|
|
4393
4444
|
cardBootstrapPending
|
|
4394
4445
|
]
|
|
4395
4446
|
);
|
|
4396
|
-
const shouldShowInterimButtons = Boolean(createSessionParams) && layout === "buttons" && (!flopay || !providerOptions);
|
|
4447
|
+
const shouldShowInterimButtons = Boolean(createSessionParams) && layout === "buttons" && !isPaypalOnlySession && (!flopay || !providerOptions);
|
|
4397
4448
|
const modeOverlay = modeOverlayStatus ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4398
4449
|
ProcessingOverlay,
|
|
4399
4450
|
{
|
|
@@ -4476,6 +4527,48 @@ function FloPayCheckout({
|
|
|
4476
4527
|
modeOverlay
|
|
4477
4528
|
] });
|
|
4478
4529
|
}
|
|
4530
|
+
if (isPaypalOnlySession && session && directPaypalConfig) {
|
|
4531
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4532
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CheckoutContext.Provider, { value: checkoutValue, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className, style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: [
|
|
4533
|
+
modeError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4534
|
+
"div",
|
|
4535
|
+
{
|
|
4536
|
+
role: "alert",
|
|
4537
|
+
"data-testid": "flopay-error",
|
|
4538
|
+
style: {
|
|
4539
|
+
padding: "0.625rem 0.875rem",
|
|
4540
|
+
background: "#FEF2F2",
|
|
4541
|
+
border: "1px solid #FECACA",
|
|
4542
|
+
borderRadius: "8px",
|
|
4543
|
+
color: "#991B1B",
|
|
4544
|
+
fontSize: "0.85rem",
|
|
4545
|
+
fontWeight: 600
|
|
4546
|
+
},
|
|
4547
|
+
children: modeError
|
|
4548
|
+
}
|
|
4549
|
+
),
|
|
4550
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4551
|
+
DirectPayPalButton,
|
|
4552
|
+
{
|
|
4553
|
+
sessionId: activeSessionId,
|
|
4554
|
+
billingApiUrl: resolvedBillingUrl,
|
|
4555
|
+
email: session.customer?.email,
|
|
4556
|
+
clientId: directPaypalConfig.clientId,
|
|
4557
|
+
environment: directPaypalConfig.environment,
|
|
4558
|
+
currency: (session.currency ?? "usd").toUpperCase(),
|
|
4559
|
+
isSubscription: session.mode === "subscription",
|
|
4560
|
+
onComplete,
|
|
4561
|
+
onErrorChange: setModeError,
|
|
4562
|
+
onDecline,
|
|
4563
|
+
onButtonClick,
|
|
4564
|
+
session,
|
|
4565
|
+
debug
|
|
4566
|
+
}
|
|
4567
|
+
)
|
|
4568
|
+
] }) }),
|
|
4569
|
+
modeOverlay
|
|
4570
|
+
] });
|
|
4571
|
+
}
|
|
4479
4572
|
if (!flopay || !providerOptions) {
|
|
4480
4573
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: modeOverlay });
|
|
4481
4574
|
}
|
|
@@ -5630,7 +5723,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5630
5723
|
publishableKey,
|
|
5631
5724
|
paypalPublishableKey
|
|
5632
5725
|
} = resolveSavedPaymentPublishableKeys(apiResult);
|
|
5633
|
-
if (redirectResult.type === "paypal_redirect_required") {
|
|
5726
|
+
if (redirectResult.type === "paypal_redirect_required" && publishableKey) {
|
|
5634
5727
|
persistPayPalResumeState2({
|
|
5635
5728
|
sessionId: session.id || resolvedSessionId,
|
|
5636
5729
|
publishableKey,
|
|
@@ -5686,7 +5779,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5686
5779
|
publishableKey,
|
|
5687
5780
|
paypalPublishableKey
|
|
5688
5781
|
} = resolveSavedPaymentPublishableKeys(apiResult);
|
|
5689
|
-
if (result.type === "paypal_redirect_required") {
|
|
5782
|
+
if (result.type === "paypal_redirect_required" && publishableKey) {
|
|
5690
5783
|
persistPayPalResumeState2({
|
|
5691
5784
|
sessionId: session.id || resolvedSessionId,
|
|
5692
5785
|
publishableKey,
|
|
@@ -5747,6 +5840,13 @@ function FloPayAutomaticPaymentButton({
|
|
|
5747
5840
|
billingApiUrl: resolvedBillingUrl,
|
|
5748
5841
|
locale
|
|
5749
5842
|
});
|
|
5843
|
+
if (!flopay) {
|
|
5844
|
+
throw new import_shared11.FloPayError(
|
|
5845
|
+
"Stripe is not available for 3DS authentication.",
|
|
5846
|
+
"api_error",
|
|
5847
|
+
{ code: "authentication_required" }
|
|
5848
|
+
);
|
|
5849
|
+
}
|
|
5750
5850
|
const paymentResult = await processSavedPaymentWithIntent({
|
|
5751
5851
|
billingApiUrl: resolvedBillingUrl,
|
|
5752
5852
|
sessionId: fallbackSessionId,
|
|
@@ -5933,7 +6033,7 @@ function FloPayAutomaticPaymentButton({
|
|
|
5933
6033
|
billingApiUrl: resolvedBillingUrl,
|
|
5934
6034
|
locale
|
|
5935
6035
|
});
|
|
5936
|
-
const paypalStripe = (paypalFlopay ?? flopay)
|
|
6036
|
+
const paypalStripe = (paypalFlopay ?? flopay)?.getRawProvider();
|
|
5937
6037
|
if (!paypalStripe) {
|
|
5938
6038
|
throw Object.assign(
|
|
5939
6039
|
new import_shared11.FloPayError("PayPal is not available.", "api_error"),
|