@easypayment/medusa-paypal-ui 1.1.0 → 1.2.0
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/CHANGELOG.md +97 -25
- package/README.md +781 -759
- package/dist/index.cjs +366 -170
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -2
- package/dist/index.d.ts +74 -2
- package/dist/index.mjs +352 -170
- package/dist/index.mjs.map +1 -1
- package/dist/order.cjs +14 -3
- package/dist/order.cjs.map +1 -1
- package/dist/order.d.cts +13 -4
- package/dist/order.d.ts +13 -4
- package/dist/order.mjs +13 -4
- package/dist/order.mjs.map +1 -1
- package/package.json +76 -65
- package/src/adapters/MedusaNextPayPalAdapter.tsx +34 -5
- package/src/client/http.ts +63 -11
- package/src/client/paypal.ts +27 -1
- package/src/client/types.ts +10 -0
- package/src/components/PayPalAdvancedCard.tsx +138 -24
- package/src/components/PayPalPaymentSection.tsx +95 -202
- package/src/components/PayPalSmartButtons.tsx +136 -7
- package/src/constants.ts +22 -0
- package/src/hooks/usePayPalPaymentMethods.ts +15 -1
- package/src/index.ts +5 -0
- package/src/order.ts +7 -10
- package/src/utils/captured-state.ts +44 -0
- package/src/utils/next-errors.ts +5 -1
- package/src/utils/processing-overlay.ts +12 -0
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
9
|
var __export = (target, all) => {
|
|
8
10
|
for (var name in all)
|
|
@@ -16,6 +18,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
18
|
}
|
|
17
19
|
return to;
|
|
18
20
|
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
19
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
30
|
|
|
21
31
|
// src/index.ts
|
|
@@ -29,13 +39,17 @@ __export(index_exports, {
|
|
|
29
39
|
PayPalPaymentSection: () => PayPalPaymentSection,
|
|
30
40
|
PayPalProvider: () => PayPalProvider,
|
|
31
41
|
PayPalSmartButtons: () => PayPalSmartButtons,
|
|
42
|
+
clearCartCaptured: () => clearCartCaptured,
|
|
32
43
|
createPayPalStoreApi: () => createPayPalStoreApi,
|
|
44
|
+
generateIdempotencyKey: () => generateIdempotencyKey,
|
|
33
45
|
hideProcessingOverlay: () => hideProcessingOverlay,
|
|
34
46
|
isPayPalProviderId: () => isPayPalProviderId,
|
|
47
|
+
markCartCaptured: () => markCartCaptured,
|
|
35
48
|
markPaymentComplete: () => markPaymentComplete,
|
|
36
49
|
showProcessingOverlay: () => showProcessingOverlay,
|
|
37
50
|
usePayPalConfig: () => usePayPalConfig,
|
|
38
|
-
usePayPalPaymentMethods: () => usePayPalPaymentMethods
|
|
51
|
+
usePayPalPaymentMethods: () => usePayPalPaymentMethods,
|
|
52
|
+
wasCartCaptured: () => wasCartCaptured
|
|
39
53
|
});
|
|
40
54
|
module.exports = __toCommonJS(index_exports);
|
|
41
55
|
|
|
@@ -55,6 +69,18 @@ function isRetryableError(err) {
|
|
|
55
69
|
return err instanceof Error && !(err instanceof HttpError);
|
|
56
70
|
}
|
|
57
71
|
var wait = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
72
|
+
function extractJsonMessage(text) {
|
|
73
|
+
if (!text) return null;
|
|
74
|
+
try {
|
|
75
|
+
const parsed = JSON.parse(text);
|
|
76
|
+
const message = parsed?.message;
|
|
77
|
+
if (typeof message === "string" && message.trim()) {
|
|
78
|
+
return message.trim().slice(0, 500);
|
|
79
|
+
}
|
|
80
|
+
} catch {
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
58
84
|
function toHeaderRecord(headers) {
|
|
59
85
|
if (!headers) {
|
|
60
86
|
return {};
|
|
@@ -79,39 +105,49 @@ function createHttpClient(opts) {
|
|
|
79
105
|
headers["x-publishable-api-key"] = opts.publishableApiKey;
|
|
80
106
|
}
|
|
81
107
|
const timeoutMs = 3e4;
|
|
82
|
-
let timeoutId;
|
|
83
108
|
const controller = new AbortController();
|
|
84
|
-
|
|
85
|
-
|
|
109
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
110
|
+
const callerSignal = init?.signal ?? null;
|
|
111
|
+
const onCallerAbort = () => controller.abort();
|
|
112
|
+
if (callerSignal) {
|
|
113
|
+
if (callerSignal.aborted) controller.abort();
|
|
114
|
+
else callerSignal.addEventListener("abort", onCallerAbort);
|
|
86
115
|
}
|
|
87
|
-
const effectiveSignal = init?.signal || controller.signal;
|
|
88
116
|
let res;
|
|
117
|
+
let text;
|
|
89
118
|
try {
|
|
90
|
-
res = await fetch(url, {
|
|
119
|
+
res = await fetch(url, {
|
|
120
|
+
...init,
|
|
121
|
+
headers,
|
|
122
|
+
credentials: opts.credentials ?? "include",
|
|
123
|
+
signal: controller.signal
|
|
124
|
+
});
|
|
125
|
+
text = await res.text().catch(() => "");
|
|
91
126
|
} catch (err) {
|
|
92
|
-
if (err instanceof Error && err.name === "AbortError" && !
|
|
127
|
+
if (err instanceof Error && err.name === "AbortError" && !(callerSignal && callerSignal.aborted)) {
|
|
93
128
|
throw new Error(`[PayPal] Request to ${path} timed out after ${timeoutMs / 1e3}s`);
|
|
94
129
|
}
|
|
95
130
|
throw err;
|
|
96
131
|
} finally {
|
|
97
|
-
|
|
132
|
+
clearTimeout(timeoutId);
|
|
133
|
+
if (callerSignal) callerSignal.removeEventListener("abort", onCallerAbort);
|
|
98
134
|
}
|
|
99
|
-
const text = await res.text().catch(() => "");
|
|
100
135
|
if (!res.ok) {
|
|
136
|
+
const parsedMessage = extractJsonMessage(text);
|
|
101
137
|
if (res.status === 401) {
|
|
102
138
|
throw new HttpError(
|
|
103
|
-
"[PayPal] Unauthorized (401) \u2014 check that your publishable API key is correct and set in NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY",
|
|
139
|
+
parsedMessage || "[PayPal] Unauthorized (401) \u2014 check that your publishable API key is correct and set in NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY",
|
|
104
140
|
401
|
|
105
141
|
);
|
|
106
142
|
}
|
|
107
143
|
if (res.status === 403) {
|
|
108
144
|
throw new HttpError(
|
|
109
|
-
"[PayPal] Forbidden (403) \u2014 this request is not allowed. Check your CORS and API key settings.",
|
|
145
|
+
parsedMessage || "[PayPal] Forbidden (403) \u2014 this request is not allowed. Check your CORS and API key settings.",
|
|
110
146
|
403
|
|
111
147
|
);
|
|
112
148
|
}
|
|
113
149
|
throw new HttpError(
|
|
114
|
-
text.slice(0, 500).replace(/<[^>]*>/g, "") || `Request failed (${res.status})`,
|
|
150
|
+
parsedMessage || text.slice(0, 500).replace(/<[^>]*>/g, "") || `Request failed (${res.status})`,
|
|
115
151
|
res.status
|
|
116
152
|
);
|
|
117
153
|
}
|
|
@@ -152,6 +188,14 @@ function createHttpClient(opts) {
|
|
|
152
188
|
}
|
|
153
189
|
|
|
154
190
|
// src/client/paypal.ts
|
|
191
|
+
function generateIdempotencyKey() {
|
|
192
|
+
try {
|
|
193
|
+
const c = globalThis.crypto;
|
|
194
|
+
if (c?.randomUUID) return c.randomUUID();
|
|
195
|
+
} catch {
|
|
196
|
+
}
|
|
197
|
+
return `pp-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
|
|
198
|
+
}
|
|
155
199
|
async function markPaymentComplete(baseUrl, cartId, publishableApiKey) {
|
|
156
200
|
const http = createHttpClient({ baseUrl, publishableApiKey });
|
|
157
201
|
return http.request(
|
|
@@ -177,7 +221,13 @@ function createPayPalStoreApi(opts) {
|
|
|
177
221
|
createOrder(cartId, isCardPayment = false) {
|
|
178
222
|
return http.request(`/store/paypal/create-order`, {
|
|
179
223
|
method: "POST",
|
|
180
|
-
headers: {
|
|
224
|
+
headers: {
|
|
225
|
+
"Content-Type": "application/json",
|
|
226
|
+
// One key per attempt — see generateIdempotencyKey. Deliberately NOT
|
|
227
|
+
// sent for capture-order: there the server's deterministic
|
|
228
|
+
// per-order-id fallback is the correct idempotency scope.
|
|
229
|
+
"Idempotency-Key": generateIdempotencyKey()
|
|
230
|
+
},
|
|
181
231
|
body: JSON.stringify({ cart_id: cartId, is_card_payment: isCardPayment })
|
|
182
232
|
});
|
|
183
233
|
},
|
|
@@ -310,11 +360,38 @@ function PayPalCurrencyNotice({ config }) {
|
|
|
310
360
|
var import_react3 = require("react");
|
|
311
361
|
var import_react_paypal_js2 = require("@paypal/react-paypal-js");
|
|
312
362
|
|
|
363
|
+
// src/utils/captured-state.ts
|
|
364
|
+
var KEY_PREFIX = "__pp_captured::";
|
|
365
|
+
function markCartCaptured(cartId) {
|
|
366
|
+
if (!cartId) return;
|
|
367
|
+
try {
|
|
368
|
+
window.sessionStorage.setItem(`${KEY_PREFIX}${cartId}`, String(Date.now()));
|
|
369
|
+
} catch {
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
function wasCartCaptured(cartId) {
|
|
373
|
+
if (!cartId) return false;
|
|
374
|
+
try {
|
|
375
|
+
return window.sessionStorage.getItem(`${KEY_PREFIX}${cartId}`) !== null;
|
|
376
|
+
} catch {
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
function clearCartCaptured(cartId) {
|
|
381
|
+
if (!cartId) return;
|
|
382
|
+
try {
|
|
383
|
+
window.sessionStorage.removeItem(`${KEY_PREFIX}${cartId}`);
|
|
384
|
+
} catch {
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
313
388
|
// src/utils/next-errors.ts
|
|
314
389
|
function isNextRouterError(e) {
|
|
315
390
|
if (typeof e !== "object" || e === null || !("digest" in e)) return false;
|
|
316
391
|
const digest = e.digest;
|
|
317
|
-
return typeof digest === "string" && (digest.startsWith("NEXT_REDIRECT") || digest.startsWith("NEXT_NOT_FOUND"))
|
|
392
|
+
return typeof digest === "string" && (digest.startsWith("NEXT_REDIRECT") || digest.startsWith("NEXT_NOT_FOUND") || // Next.js 15: notFound()/forbidden()/unauthorized() throw
|
|
393
|
+
// HTTPAccessFallbackError with digest "NEXT_HTTP_ERROR_FALLBACK;<status>".
|
|
394
|
+
digest.startsWith("NEXT_HTTP_ERROR_FALLBACK"));
|
|
318
395
|
}
|
|
319
396
|
|
|
320
397
|
// src/utils/processing-overlay.ts
|
|
@@ -378,8 +455,13 @@ function showProcessingOverlay() {
|
|
|
378
455
|
origReplace(...args);
|
|
379
456
|
onNav();
|
|
380
457
|
};
|
|
458
|
+
const onPageShow = (e) => {
|
|
459
|
+
if (e.persisted) hideProcessingOverlay();
|
|
460
|
+
};
|
|
461
|
+
window.addEventListener("pageshow", onPageShow);
|
|
381
462
|
cleanupNavListener = () => {
|
|
382
463
|
window.removeEventListener("popstate", onNav);
|
|
464
|
+
window.removeEventListener("pageshow", onPageShow);
|
|
383
465
|
history.pushState = origPush;
|
|
384
466
|
history.replaceState = origReplace;
|
|
385
467
|
};
|
|
@@ -412,11 +494,56 @@ function PayPalSmartButtons(props) {
|
|
|
412
494
|
const [error, setError] = (0, import_react3.useState)(null);
|
|
413
495
|
const [processing, setProcessing] = (0, import_react3.useState)(false);
|
|
414
496
|
const [buttonsReady, setButtonsReady] = (0, import_react3.useState)(false);
|
|
497
|
+
const [loadTimedOut, setLoadTimedOut] = (0, import_react3.useState)(false);
|
|
498
|
+
const capturedRef = (0, import_react3.useRef)(null);
|
|
499
|
+
const [completionPending, setCompletionPending] = (0, import_react3.useState)(false);
|
|
415
500
|
const [{ isPending, isResolved, isRejected }] = (0, import_react_paypal_js2.usePayPalScriptReducer)();
|
|
416
501
|
const handleInit = (0, import_react3.useCallback)(() => {
|
|
417
502
|
setButtonsReady(true);
|
|
418
503
|
}, []);
|
|
419
|
-
|
|
504
|
+
(0, import_react3.useEffect)(() => {
|
|
505
|
+
const onPageShow = (e) => {
|
|
506
|
+
if (e.persisted) setProcessing(false);
|
|
507
|
+
};
|
|
508
|
+
window.addEventListener("pageshow", onPageShow);
|
|
509
|
+
return () => window.removeEventListener("pageshow", onPageShow);
|
|
510
|
+
}, []);
|
|
511
|
+
(0, import_react3.useEffect)(() => {
|
|
512
|
+
if (capturedRef.current || !wasCartCaptured(cartId)) return;
|
|
513
|
+
capturedRef.current = {};
|
|
514
|
+
setCompletionPending(true);
|
|
515
|
+
const msg = "Your payment was already received for this cart. Please use the button below to finish placing your order \u2014 do not pay again.";
|
|
516
|
+
setError(msg);
|
|
517
|
+
}, [cartId]);
|
|
518
|
+
(0, import_react3.useEffect)(() => {
|
|
519
|
+
if (!isResolved || buttonsReady) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
const t = setTimeout(() => setLoadTimedOut(true), 1e4);
|
|
523
|
+
return () => clearTimeout(t);
|
|
524
|
+
}, [isResolved, buttonsReady]);
|
|
525
|
+
const finalizeCapturedPayment = (0, import_react3.useCallback)(async () => {
|
|
526
|
+
const captured = capturedRef.current;
|
|
527
|
+
if (!captured) return;
|
|
528
|
+
setProcessing(true);
|
|
529
|
+
showProcessingOverlay();
|
|
530
|
+
setError(null);
|
|
531
|
+
try {
|
|
532
|
+
const completeResult = await markPaymentComplete(baseUrl, cartId, publishableApiKey);
|
|
533
|
+
clearCartCaptured(cartId);
|
|
534
|
+
await onPaid?.({ ...captured, ...completeResult });
|
|
535
|
+
setCompletionPending(false);
|
|
536
|
+
} catch (e) {
|
|
537
|
+
if (isNextRouterError(e)) return;
|
|
538
|
+
hideProcessingOverlay();
|
|
539
|
+
setProcessing(false);
|
|
540
|
+
setCompletionPending(true);
|
|
541
|
+
const msg = "Your payment was received, but finalizing your order failed. Please use the Retry button below \u2014 do not pay again.";
|
|
542
|
+
setError(msg);
|
|
543
|
+
onError?.(msg);
|
|
544
|
+
}
|
|
545
|
+
}, [baseUrl, cartId, publishableApiKey, onPaid, onError]);
|
|
546
|
+
const showSpinner = (isPending || isResolved && !buttonsReady) && !loadTimedOut;
|
|
420
547
|
if (!config.currency_supported) return null;
|
|
421
548
|
const containerWidth = BUTTON_WIDTH_MAP[config.button_width ?? "responsive"] ?? "100%";
|
|
422
549
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { width: containerWidth, position: "relative" }, children: [
|
|
@@ -555,6 +682,28 @@ function PayPalSmartButtons(props) {
|
|
|
555
682
|
]
|
|
556
683
|
}
|
|
557
684
|
),
|
|
685
|
+
loadTimedOut && !buttonsReady && !isRejected && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
686
|
+
"div",
|
|
687
|
+
{
|
|
688
|
+
role: "alert",
|
|
689
|
+
style: {
|
|
690
|
+
display: "flex",
|
|
691
|
+
alignItems: "flex-start",
|
|
692
|
+
gap: 8,
|
|
693
|
+
padding: "10px 14px",
|
|
694
|
+
background: "#fef2f2",
|
|
695
|
+
border: "1px solid #fecaca",
|
|
696
|
+
borderRadius: 8,
|
|
697
|
+
fontSize: 13,
|
|
698
|
+
color: "#b91c1c",
|
|
699
|
+
lineHeight: 1.5
|
|
700
|
+
},
|
|
701
|
+
children: [
|
|
702
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { flexShrink: 0, fontSize: 15 }, children: "\u26A0\uFE0F" }),
|
|
703
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "PayPal is not available for this purchase. Please try a different payment method." })
|
|
704
|
+
]
|
|
705
|
+
}
|
|
706
|
+
),
|
|
558
707
|
isRejected && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
559
708
|
"div",
|
|
560
709
|
{
|
|
@@ -615,7 +764,7 @@ function PayPalSmartButtons(props) {
|
|
|
615
764
|
]
|
|
616
765
|
}
|
|
617
766
|
),
|
|
618
|
-
isResolved && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: buttonsReady ? void 0 : { position: "absolute", left: -9999, opacity: 0, pointerEvents: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
767
|
+
isResolved && !completionPending && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: buttonsReady ? void 0 : { position: "absolute", left: -9999, opacity: 0, pointerEvents: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
619
768
|
import_react_paypal_js2.PayPalButtons,
|
|
620
769
|
{
|
|
621
770
|
forceReRender: [config.currency, config.intent, cartId],
|
|
@@ -629,6 +778,10 @@ function PayPalSmartButtons(props) {
|
|
|
629
778
|
},
|
|
630
779
|
createOrder: async () => {
|
|
631
780
|
if (processing) throw new Error("Payment already processing");
|
|
781
|
+
if (capturedRef.current) {
|
|
782
|
+
void finalizeCapturedPayment();
|
|
783
|
+
throw new Error("Your payment was already received \u2014 finalizing your order.");
|
|
784
|
+
}
|
|
632
785
|
setError(null);
|
|
633
786
|
setProcessing(true);
|
|
634
787
|
try {
|
|
@@ -647,8 +800,8 @@ function PayPalSmartButtons(props) {
|
|
|
647
800
|
const orderId = String(data?.orderID || "");
|
|
648
801
|
if (!orderId) throw new Error("PayPal order ID is missing from approval response");
|
|
649
802
|
const result = await api.captureOrder(cartId, orderId);
|
|
650
|
-
|
|
651
|
-
|
|
803
|
+
capturedRef.current = result || {};
|
|
804
|
+
markCartCaptured(cartId);
|
|
652
805
|
} catch (e) {
|
|
653
806
|
if (isNextRouterError(e)) return;
|
|
654
807
|
hideProcessingOverlay();
|
|
@@ -656,7 +809,9 @@ function PayPalSmartButtons(props) {
|
|
|
656
809
|
const msg = e instanceof Error ? e.message : "Payment capture failed";
|
|
657
810
|
setError(msg);
|
|
658
811
|
onError?.(msg);
|
|
812
|
+
return;
|
|
659
813
|
}
|
|
814
|
+
await finalizeCapturedPayment();
|
|
660
815
|
},
|
|
661
816
|
onCancel: () => {
|
|
662
817
|
hideProcessingOverlay();
|
|
@@ -671,6 +826,29 @@ function PayPalSmartButtons(props) {
|
|
|
671
826
|
}
|
|
672
827
|
}
|
|
673
828
|
) }),
|
|
829
|
+
completionPending && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
830
|
+
"button",
|
|
831
|
+
{
|
|
832
|
+
type: "button",
|
|
833
|
+
onClick: () => void finalizeCapturedPayment(),
|
|
834
|
+
disabled: processing,
|
|
835
|
+
"aria-busy": processing,
|
|
836
|
+
style: {
|
|
837
|
+
width: "100%",
|
|
838
|
+
padding: "12px 16px",
|
|
839
|
+
marginTop: 4,
|
|
840
|
+
background: "#0070ba",
|
|
841
|
+
color: "#ffffff",
|
|
842
|
+
border: "none",
|
|
843
|
+
borderRadius: 8,
|
|
844
|
+
fontSize: 14,
|
|
845
|
+
fontWeight: 600,
|
|
846
|
+
cursor: processing ? "not-allowed" : "pointer",
|
|
847
|
+
opacity: processing ? 0.7 : 1
|
|
848
|
+
},
|
|
849
|
+
children: "Retry \u2014 finish placing my order"
|
|
850
|
+
}
|
|
851
|
+
),
|
|
674
852
|
error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
675
853
|
"div",
|
|
676
854
|
{
|
|
@@ -698,7 +876,7 @@ function PayPalSmartButtons(props) {
|
|
|
698
876
|
}
|
|
699
877
|
|
|
700
878
|
// src/components/PayPalAdvancedCard.tsx
|
|
701
|
-
var import_react4 = require("react");
|
|
879
|
+
var import_react4 = __toESM(require("react"), 1);
|
|
702
880
|
var import_react_paypal_js3 = require("@paypal/react-paypal-js");
|
|
703
881
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
704
882
|
var SPIN_STYLE2 = `
|
|
@@ -750,7 +928,8 @@ var labelStyle = {
|
|
|
750
928
|
function SubmitButton({
|
|
751
929
|
disabled,
|
|
752
930
|
label,
|
|
753
|
-
onSubmit
|
|
931
|
+
onSubmit,
|
|
932
|
+
onSubmitError
|
|
754
933
|
}) {
|
|
755
934
|
const { cardFieldsForm } = (0, import_react_paypal_js3.usePayPalCardFields)();
|
|
756
935
|
const isDisabled = disabled || !cardFieldsForm;
|
|
@@ -762,10 +941,10 @@ function SubmitButton({
|
|
|
762
941
|
"aria-busy": disabled,
|
|
763
942
|
onClick: () => {
|
|
764
943
|
onSubmit();
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
}
|
|
944
|
+
Promise.resolve(cardFieldsForm?.submit()).catch((e) => {
|
|
945
|
+
const msg = e instanceof Error && e.message ? e.message : "Card payment could not be submitted. Please check your card details.";
|
|
946
|
+
onSubmitError(msg);
|
|
947
|
+
});
|
|
769
948
|
},
|
|
770
949
|
style: {
|
|
771
950
|
width: "100%",
|
|
@@ -811,7 +990,54 @@ function PayPalAdvancedCard(props) {
|
|
|
811
990
|
const [submitting, setSubmitting] = (0, import_react4.useState)(false);
|
|
812
991
|
const submittingRef = (0, import_react4.useRef)(false);
|
|
813
992
|
const creatingOrderRef = (0, import_react4.useRef)(false);
|
|
993
|
+
const capturedRef = (0, import_react4.useRef)(null);
|
|
994
|
+
const [completionPending, setCompletionPending] = (0, import_react4.useState)(false);
|
|
814
995
|
const [{ isPending, isResolved, isRejected }] = (0, import_react_paypal_js3.usePayPalScriptReducer)();
|
|
996
|
+
const resetSubmitState = import_react4.default.useCallback(() => {
|
|
997
|
+
hideProcessingOverlay();
|
|
998
|
+
creatingOrderRef.current = false;
|
|
999
|
+
submittingRef.current = false;
|
|
1000
|
+
setSubmitting(false);
|
|
1001
|
+
}, []);
|
|
1002
|
+
import_react4.default.useEffect(() => {
|
|
1003
|
+
const onPageShow = (e) => {
|
|
1004
|
+
if (e.persisted) {
|
|
1005
|
+
creatingOrderRef.current = false;
|
|
1006
|
+
submittingRef.current = false;
|
|
1007
|
+
setSubmitting(false);
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
1010
|
+
window.addEventListener("pageshow", onPageShow);
|
|
1011
|
+
return () => window.removeEventListener("pageshow", onPageShow);
|
|
1012
|
+
}, []);
|
|
1013
|
+
import_react4.default.useEffect(() => {
|
|
1014
|
+
if (capturedRef.current || !wasCartCaptured(cartId)) return;
|
|
1015
|
+
capturedRef.current = {};
|
|
1016
|
+
setCompletionPending(true);
|
|
1017
|
+
setError(
|
|
1018
|
+
"Your payment was already received for this cart. Please use the button below to finish placing your order \u2014 do not pay again."
|
|
1019
|
+
);
|
|
1020
|
+
}, [cartId]);
|
|
1021
|
+
const finalizeCapturedPayment = import_react4.default.useCallback(async () => {
|
|
1022
|
+
const captured = capturedRef.current;
|
|
1023
|
+
if (!captured) return;
|
|
1024
|
+
setSubmitting(true);
|
|
1025
|
+
showProcessingOverlay();
|
|
1026
|
+
setError(null);
|
|
1027
|
+
try {
|
|
1028
|
+
const completeResult = await markPaymentComplete(baseUrl, cartId, publishableApiKey);
|
|
1029
|
+
clearCartCaptured(cartId);
|
|
1030
|
+
await onPaid?.({ ...captured, ...completeResult });
|
|
1031
|
+
setCompletionPending(false);
|
|
1032
|
+
} catch (e) {
|
|
1033
|
+
if (isNextRouterError(e)) return;
|
|
1034
|
+
resetSubmitState();
|
|
1035
|
+
setCompletionPending(true);
|
|
1036
|
+
const msg = "Your payment was received, but finalizing your order failed. Please use the Retry button below \u2014 do not pay again.";
|
|
1037
|
+
setError(msg);
|
|
1038
|
+
onError?.(msg);
|
|
1039
|
+
}
|
|
1040
|
+
}, [baseUrl, cartId, publishableApiKey, onPaid, onError, resetSubmitState]);
|
|
815
1041
|
if (!config.currency_supported) return null;
|
|
816
1042
|
if (isRejected) {
|
|
817
1043
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
@@ -1000,6 +1226,10 @@ function PayPalAdvancedCard(props) {
|
|
|
1000
1226
|
style: cardStyle,
|
|
1001
1227
|
createOrder: async () => {
|
|
1002
1228
|
if (creatingOrderRef.current) throw new Error("Payment already processing");
|
|
1229
|
+
if (capturedRef.current) {
|
|
1230
|
+
void finalizeCapturedPayment();
|
|
1231
|
+
throw new Error("Your payment was already received \u2014 finalizing your order.");
|
|
1232
|
+
}
|
|
1003
1233
|
creatingOrderRef.current = true;
|
|
1004
1234
|
try {
|
|
1005
1235
|
setError(null);
|
|
@@ -1015,19 +1245,19 @@ function PayPalAdvancedCard(props) {
|
|
|
1015
1245
|
setError(null);
|
|
1016
1246
|
showProcessingOverlay();
|
|
1017
1247
|
const orderId = String(data?.orderID || "");
|
|
1248
|
+
if (!orderId) throw new Error("PayPal order ID is missing from approval response");
|
|
1018
1249
|
const result = await api.captureOrder(cartId, orderId);
|
|
1019
|
-
|
|
1020
|
-
|
|
1250
|
+
capturedRef.current = result || {};
|
|
1251
|
+
markCartCaptured(cartId);
|
|
1021
1252
|
} catch (e) {
|
|
1022
1253
|
if (isNextRouterError(e)) return;
|
|
1023
|
-
|
|
1024
|
-
creatingOrderRef.current = false;
|
|
1025
|
-
submittingRef.current = false;
|
|
1026
|
-
setSubmitting(false);
|
|
1254
|
+
resetSubmitState();
|
|
1027
1255
|
const msg = e instanceof Error ? e.message : "Card payment failed";
|
|
1028
1256
|
setError(msg);
|
|
1029
1257
|
onError?.(msg);
|
|
1258
|
+
return;
|
|
1030
1259
|
}
|
|
1260
|
+
await finalizeCapturedPayment();
|
|
1031
1261
|
},
|
|
1032
1262
|
onCancel: () => {
|
|
1033
1263
|
hideProcessingOverlay();
|
|
@@ -1134,7 +1364,29 @@ function PayPalAdvancedCard(props) {
|
|
|
1134
1364
|
]
|
|
1135
1365
|
}
|
|
1136
1366
|
),
|
|
1137
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1367
|
+
completionPending ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1368
|
+
"button",
|
|
1369
|
+
{
|
|
1370
|
+
type: "button",
|
|
1371
|
+
onClick: () => void finalizeCapturedPayment(),
|
|
1372
|
+
disabled: submitting,
|
|
1373
|
+
"aria-busy": submitting,
|
|
1374
|
+
style: {
|
|
1375
|
+
width: "100%",
|
|
1376
|
+
height: 48,
|
|
1377
|
+
padding: "0 20px",
|
|
1378
|
+
borderRadius: 8,
|
|
1379
|
+
border: "none",
|
|
1380
|
+
background: "#0070ba",
|
|
1381
|
+
color: "#ffffff",
|
|
1382
|
+
fontSize: 15,
|
|
1383
|
+
fontWeight: 600,
|
|
1384
|
+
cursor: submitting ? "not-allowed" : "pointer",
|
|
1385
|
+
opacity: submitting ? 0.7 : 1
|
|
1386
|
+
},
|
|
1387
|
+
children: "Retry \u2014 finish placing my order"
|
|
1388
|
+
}
|
|
1389
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1138
1390
|
SubmitButton,
|
|
1139
1391
|
{
|
|
1140
1392
|
disabled: submitting,
|
|
@@ -1145,6 +1397,11 @@ function PayPalAdvancedCard(props) {
|
|
|
1145
1397
|
setError(null);
|
|
1146
1398
|
setSubmitting(true);
|
|
1147
1399
|
showProcessingOverlay();
|
|
1400
|
+
},
|
|
1401
|
+
onSubmitError: (msg) => {
|
|
1402
|
+
resetSubmitState();
|
|
1403
|
+
setError(msg);
|
|
1404
|
+
onError?.(msg);
|
|
1148
1405
|
}
|
|
1149
1406
|
}
|
|
1150
1407
|
),
|
|
@@ -1180,9 +1437,23 @@ function PayPalAdvancedCard(props) {
|
|
|
1180
1437
|
|
|
1181
1438
|
// src/adapters/MedusaNextPayPalAdapter.tsx
|
|
1182
1439
|
var import_react5 = require("react");
|
|
1440
|
+
|
|
1441
|
+
// src/constants.ts
|
|
1442
|
+
var PAYPAL_WALLET_PROVIDER_ID = "pp_paypal_paypal";
|
|
1443
|
+
var PAYPAL_CARD_PROVIDER_ID = "pp_paypal_card_paypal_card";
|
|
1444
|
+
var PAYPAL_PROVIDER_IDS = [
|
|
1445
|
+
PAYPAL_WALLET_PROVIDER_ID,
|
|
1446
|
+
PAYPAL_CARD_PROVIDER_ID
|
|
1447
|
+
];
|
|
1448
|
+
function isPayPalProviderId(providerId) {
|
|
1449
|
+
if (!providerId) return false;
|
|
1450
|
+
return PAYPAL_PROVIDER_IDS.includes(
|
|
1451
|
+
providerId
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// src/adapters/MedusaNextPayPalAdapter.tsx
|
|
1183
1456
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1184
|
-
var DEFAULT_PAYPAL_PROVIDER_ID = "pp_paypal_paypal";
|
|
1185
|
-
var DEFAULT_PAYPAL_CARD_PROVIDER_ID = "pp_paypal_card_paypal_card";
|
|
1186
1457
|
var SPIN_STYLE3 = `@keyframes _pp_spin { to { transform: rotate(360deg) } }`;
|
|
1187
1458
|
function PayPalLoadingCard() {
|
|
1188
1459
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
@@ -1240,6 +1511,26 @@ function PayPalErrorCard({ message }) {
|
|
|
1240
1511
|
}
|
|
1241
1512
|
);
|
|
1242
1513
|
}
|
|
1514
|
+
function PayPalUnavailableCard({ label }) {
|
|
1515
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1516
|
+
"div",
|
|
1517
|
+
{
|
|
1518
|
+
role: "status",
|
|
1519
|
+
style: {
|
|
1520
|
+
padding: "12px 16px",
|
|
1521
|
+
background: "#f9fafb",
|
|
1522
|
+
border: "1px solid #e5e7eb",
|
|
1523
|
+
borderRadius: 10,
|
|
1524
|
+
fontSize: 13,
|
|
1525
|
+
color: "#6b7280"
|
|
1526
|
+
},
|
|
1527
|
+
children: [
|
|
1528
|
+
label,
|
|
1529
|
+
" is currently unavailable. Please choose a different payment method."
|
|
1530
|
+
]
|
|
1531
|
+
}
|
|
1532
|
+
);
|
|
1533
|
+
}
|
|
1243
1534
|
function MedusaNextPayPalAdapter(props) {
|
|
1244
1535
|
const {
|
|
1245
1536
|
cartId,
|
|
@@ -1251,8 +1542,8 @@ function MedusaNextPayPalAdapter(props) {
|
|
|
1251
1542
|
onError,
|
|
1252
1543
|
onPaid
|
|
1253
1544
|
} = props;
|
|
1254
|
-
const paypalProviderId = providerIds?.paypal ||
|
|
1255
|
-
const paypalCardProviderId = providerIds?.paypalCard ||
|
|
1545
|
+
const paypalProviderId = providerIds?.paypal || PAYPAL_WALLET_PROVIDER_ID;
|
|
1546
|
+
const paypalCardProviderId = providerIds?.paypalCard || PAYPAL_CARD_PROVIDER_ID;
|
|
1256
1547
|
const shouldRender = selectedProviderId === paypalProviderId || selectedProviderId === paypalCardProviderId;
|
|
1257
1548
|
const { config, loading, error } = usePayPalConfig({
|
|
1258
1549
|
baseUrl,
|
|
@@ -1272,8 +1563,12 @@ function MedusaNextPayPalAdapter(props) {
|
|
|
1272
1563
|
if (error) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PayPalErrorCard, { message: error });
|
|
1273
1564
|
if (!config) return null;
|
|
1274
1565
|
const isCardProvider = selectedProviderId === paypalCardProviderId;
|
|
1275
|
-
if (config.paypal_enabled === false && !isCardProvider)
|
|
1276
|
-
|
|
1566
|
+
if (config.paypal_enabled === false && !isCardProvider) {
|
|
1567
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PayPalUnavailableCard, { label: config.paypal_title || "PayPal" });
|
|
1568
|
+
}
|
|
1569
|
+
if (isCardProvider && config.card_enabled === false) {
|
|
1570
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PayPalUnavailableCard, { label: config.card_title || "Card payment" });
|
|
1571
|
+
}
|
|
1277
1572
|
const disableFunding = Array.isArray(config.disable_buttons) ? config.disable_buttons.join(",") : void 0;
|
|
1278
1573
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "grid", gap: 12 }, children: [
|
|
1279
1574
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PayPalCurrencyNotice, { config }),
|
|
@@ -1310,18 +1605,7 @@ function MedusaNextPayPalAdapter(props) {
|
|
|
1310
1605
|
}
|
|
1311
1606
|
|
|
1312
1607
|
// src/components/PayPalPaymentSection.tsx
|
|
1313
|
-
var import_react6 = require("react");
|
|
1314
1608
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1315
|
-
var PAYPAL_WALLET_PROVIDER_ID = "pp_paypal_paypal";
|
|
1316
|
-
var PAYPAL_CARD_PROVIDER_ID = "pp_paypal_card_paypal_card";
|
|
1317
|
-
var PAYPAL_PROVIDER_IDS = [
|
|
1318
|
-
PAYPAL_WALLET_PROVIDER_ID,
|
|
1319
|
-
PAYPAL_CARD_PROVIDER_ID
|
|
1320
|
-
];
|
|
1321
|
-
function isPayPalProviderId(id) {
|
|
1322
|
-
if (!id) return false;
|
|
1323
|
-
return PAYPAL_PROVIDER_IDS.includes(id);
|
|
1324
|
-
}
|
|
1325
1609
|
var SPIN_STYLE4 = `@keyframes _pp_section_spin { to { transform: rotate(360deg) } }`;
|
|
1326
1610
|
function SessionInitCard() {
|
|
1327
1611
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
@@ -1360,62 +1644,6 @@ function SessionInitCard() {
|
|
|
1360
1644
|
}
|
|
1361
1645
|
);
|
|
1362
1646
|
}
|
|
1363
|
-
function ConfigLoadingCard() {
|
|
1364
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1365
|
-
"div",
|
|
1366
|
-
{
|
|
1367
|
-
role: "status",
|
|
1368
|
-
"aria-label": "Connecting to PayPal",
|
|
1369
|
-
style: {
|
|
1370
|
-
display: "flex",
|
|
1371
|
-
alignItems: "center",
|
|
1372
|
-
gap: 12,
|
|
1373
|
-
padding: "14px 16px",
|
|
1374
|
-
background: "#f9fafb",
|
|
1375
|
-
border: "1px solid #e5e7eb",
|
|
1376
|
-
borderRadius: 10
|
|
1377
|
-
},
|
|
1378
|
-
children: [
|
|
1379
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: SPIN_STYLE4 }),
|
|
1380
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1381
|
-
"div",
|
|
1382
|
-
{
|
|
1383
|
-
style: {
|
|
1384
|
-
width: 22,
|
|
1385
|
-
height: 22,
|
|
1386
|
-
borderRadius: "50%",
|
|
1387
|
-
border: "2.5px solid #e5e7eb",
|
|
1388
|
-
borderTopColor: "#0070ba",
|
|
1389
|
-
animation: "_pp_section_spin .7s linear infinite",
|
|
1390
|
-
flexShrink: 0
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1393
|
-
),
|
|
1394
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
|
|
1395
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { fontSize: 13, fontWeight: 500, color: "#111827" }, children: "Connecting to PayPal\u2026" }),
|
|
1396
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { fontSize: 12, color: "#6b7280", marginTop: 2 }, children: "Setting up secure payment" })
|
|
1397
|
-
] })
|
|
1398
|
-
]
|
|
1399
|
-
}
|
|
1400
|
-
);
|
|
1401
|
-
}
|
|
1402
|
-
function ErrorCard({ message }) {
|
|
1403
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1404
|
-
"div",
|
|
1405
|
-
{
|
|
1406
|
-
role: "alert",
|
|
1407
|
-
style: {
|
|
1408
|
-
padding: "12px 16px",
|
|
1409
|
-
background: "#fef2f2",
|
|
1410
|
-
border: "1px solid #fecaca",
|
|
1411
|
-
borderRadius: 10,
|
|
1412
|
-
fontSize: 13,
|
|
1413
|
-
color: "#b91c1c"
|
|
1414
|
-
},
|
|
1415
|
-
children: message
|
|
1416
|
-
}
|
|
1417
|
-
);
|
|
1418
|
-
}
|
|
1419
1647
|
function PayPalPaymentSection({
|
|
1420
1648
|
cartId,
|
|
1421
1649
|
selectedProviderId,
|
|
@@ -1426,67 +1654,24 @@ function PayPalPaymentSection({
|
|
|
1426
1654
|
onError,
|
|
1427
1655
|
onPaid
|
|
1428
1656
|
}) {
|
|
1429
|
-
|
|
1430
|
-
const { config, loading, error } = usePayPalConfig({
|
|
1431
|
-
baseUrl,
|
|
1432
|
-
publishableApiKey,
|
|
1433
|
-
cartId,
|
|
1434
|
-
enabled: shouldRender
|
|
1435
|
-
});
|
|
1436
|
-
const handlePaid = (0, import_react6.useCallback)(
|
|
1437
|
-
async (captureResult) => {
|
|
1438
|
-
onPaid?.(captureResult);
|
|
1439
|
-
await onSuccess?.(cartId);
|
|
1440
|
-
},
|
|
1441
|
-
[cartId, onPaid, onSuccess]
|
|
1442
|
-
);
|
|
1443
|
-
if (!shouldRender) return null;
|
|
1657
|
+
if (!isPayPalProviderId(selectedProviderId)) return null;
|
|
1444
1658
|
if (sessionLoading) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SessionInitCard, {});
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
PayPalProvider,
|
|
1458
|
-
{
|
|
1459
|
-
config,
|
|
1460
|
-
intent: config.intent === "authorize" ? "authorize" : "capture",
|
|
1461
|
-
disableFunding,
|
|
1462
|
-
children: isCardProvider ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1463
|
-
PayPalAdvancedCard,
|
|
1464
|
-
{
|
|
1465
|
-
baseUrl,
|
|
1466
|
-
publishableApiKey,
|
|
1467
|
-
cartId,
|
|
1468
|
-
config,
|
|
1469
|
-
onPaid: handlePaid,
|
|
1470
|
-
onError
|
|
1471
|
-
}
|
|
1472
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1473
|
-
PayPalSmartButtons,
|
|
1474
|
-
{
|
|
1475
|
-
baseUrl,
|
|
1476
|
-
publishableApiKey,
|
|
1477
|
-
cartId,
|
|
1478
|
-
config,
|
|
1479
|
-
onPaid: handlePaid,
|
|
1480
|
-
onError
|
|
1481
|
-
}
|
|
1482
|
-
)
|
|
1483
|
-
}
|
|
1484
|
-
)
|
|
1485
|
-
] }, selectedProviderId);
|
|
1659
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1660
|
+
MedusaNextPayPalAdapter,
|
|
1661
|
+
{
|
|
1662
|
+
cartId,
|
|
1663
|
+
selectedProviderId,
|
|
1664
|
+
baseUrl,
|
|
1665
|
+
publishableApiKey,
|
|
1666
|
+
onSuccess,
|
|
1667
|
+
onError,
|
|
1668
|
+
onPaid
|
|
1669
|
+
}
|
|
1670
|
+
);
|
|
1486
1671
|
}
|
|
1487
1672
|
|
|
1488
1673
|
// src/hooks/usePayPalPaymentMethods.ts
|
|
1489
|
-
var
|
|
1674
|
+
var import_react6 = require("react");
|
|
1490
1675
|
var MAX_CACHE_ENTRIES2 = 50;
|
|
1491
1676
|
var _cache2 = /* @__PURE__ */ new Map();
|
|
1492
1677
|
var CACHE_TTL2 = 5 * 60 * 1e3;
|
|
@@ -1505,7 +1690,8 @@ var DEFAULT_RESULT = {
|
|
|
1505
1690
|
paypalTitle: "PayPal",
|
|
1506
1691
|
cardEnabled: true,
|
|
1507
1692
|
cardTitle: "Credit or Debit Card",
|
|
1508
|
-
loading: false
|
|
1693
|
+
loading: false,
|
|
1694
|
+
error: null
|
|
1509
1695
|
};
|
|
1510
1696
|
function usePayPalPaymentMethods({
|
|
1511
1697
|
baseUrl,
|
|
@@ -1513,16 +1699,16 @@ function usePayPalPaymentMethods({
|
|
|
1513
1699
|
cartId,
|
|
1514
1700
|
enabled = true
|
|
1515
1701
|
}) {
|
|
1516
|
-
const api = (0,
|
|
1702
|
+
const api = (0, import_react6.useMemo)(
|
|
1517
1703
|
() => createPayPalStoreApi({ baseUrl, publishableApiKey }),
|
|
1518
1704
|
[baseUrl, publishableApiKey]
|
|
1519
1705
|
);
|
|
1520
1706
|
const key = cacheKey2(baseUrl, cartId);
|
|
1521
1707
|
const hit = _cache2.get(key);
|
|
1522
1708
|
const seed = hit && Date.now() - hit.at < CACHE_TTL2 ? hit.result : null;
|
|
1523
|
-
const [result, setResult] = (0,
|
|
1524
|
-
const fetchIdRef = (0,
|
|
1525
|
-
(0,
|
|
1709
|
+
const [result, setResult] = (0, import_react6.useState)(seed ?? { ...DEFAULT_RESULT, loading: enabled });
|
|
1710
|
+
const fetchIdRef = (0, import_react6.useRef)(0);
|
|
1711
|
+
(0, import_react6.useEffect)(() => {
|
|
1526
1712
|
if (!enabled) {
|
|
1527
1713
|
setResult((prev) => ({ ...prev, loading: false }));
|
|
1528
1714
|
return;
|
|
@@ -1546,7 +1732,8 @@ function usePayPalPaymentMethods({
|
|
|
1546
1732
|
paypalTitle: typeof cfg.paypal_title === "string" && cfg.paypal_title ? cfg.paypal_title : "PayPal",
|
|
1547
1733
|
cardEnabled: cfg.card_enabled !== false,
|
|
1548
1734
|
cardTitle: typeof cfg.card_title === "string" && cfg.card_title ? cfg.card_title : "Credit or Debit Card",
|
|
1549
|
-
loading: false
|
|
1735
|
+
loading: false,
|
|
1736
|
+
error: null
|
|
1550
1737
|
};
|
|
1551
1738
|
cacheSet2(k, { result: next, at: Date.now() });
|
|
1552
1739
|
setResult(next);
|
|
@@ -1559,12 +1746,17 @@ function usePayPalPaymentMethods({
|
|
|
1559
1746
|
...DEFAULT_RESULT,
|
|
1560
1747
|
paypalEnabled: false,
|
|
1561
1748
|
cardEnabled: false,
|
|
1562
|
-
loading: false
|
|
1749
|
+
loading: false,
|
|
1750
|
+
error: msg || "PayPal is disabled"
|
|
1563
1751
|
};
|
|
1564
1752
|
setResult(disabled);
|
|
1565
1753
|
return;
|
|
1566
1754
|
}
|
|
1567
|
-
setResult({
|
|
1755
|
+
setResult({
|
|
1756
|
+
...DEFAULT_RESULT,
|
|
1757
|
+
loading: false,
|
|
1758
|
+
error: msg || "Failed to load PayPal payment methods"
|
|
1759
|
+
});
|
|
1568
1760
|
}
|
|
1569
1761
|
})();
|
|
1570
1762
|
return () => {
|
|
@@ -1584,12 +1776,16 @@ function usePayPalPaymentMethods({
|
|
|
1584
1776
|
PayPalPaymentSection,
|
|
1585
1777
|
PayPalProvider,
|
|
1586
1778
|
PayPalSmartButtons,
|
|
1779
|
+
clearCartCaptured,
|
|
1587
1780
|
createPayPalStoreApi,
|
|
1781
|
+
generateIdempotencyKey,
|
|
1588
1782
|
hideProcessingOverlay,
|
|
1589
1783
|
isPayPalProviderId,
|
|
1784
|
+
markCartCaptured,
|
|
1590
1785
|
markPaymentComplete,
|
|
1591
1786
|
showProcessingOverlay,
|
|
1592
1787
|
usePayPalConfig,
|
|
1593
|
-
usePayPalPaymentMethods
|
|
1788
|
+
usePayPalPaymentMethods,
|
|
1789
|
+
wasCartCaptured
|
|
1594
1790
|
});
|
|
1595
1791
|
//# sourceMappingURL=index.cjs.map
|