@easypayment/medusa-paypal-ui 1.0.50 → 1.0.52
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 +0 -60
- package/dist/index.cjs +457 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -17
- package/dist/index.d.ts +11 -17
- package/dist/index.mjs +466 -155
- package/dist/index.mjs.map +1 -1
- package/dist/order.cjs +20 -7
- package/dist/order.cjs.map +1 -1
- package/dist/order.mjs +20 -7
- package/dist/order.mjs.map +1 -1
- package/package.json +6 -1
- package/src/adapters/MedusaNextPayPalAdapter.tsx +6 -14
- package/src/client/http.ts +15 -44
- package/src/client/paypal.ts +7 -37
- package/src/components/PayPalAdvancedCard.tsx +163 -42
- package/src/components/PayPalCurrencyNotice.tsx +1 -1
- package/src/components/PayPalPaymentSection.tsx +8 -14
- package/src/components/PayPalProvider.tsx +1 -1
- package/src/components/PayPalSmartButtons.tsx +192 -54
- package/src/hooks/usePayPalConfig.ts +13 -4
- package/src/hooks/usePayPalPaymentMethods.ts +14 -4
- package/src/index.ts +1 -0
- package/src/order.ts +20 -7
- package/src/utils/next-errors.ts +17 -0
- package/src/utils/processing-overlay.ts +55 -0
package/dist/index.cjs
CHANGED
|
@@ -30,9 +30,10 @@ __export(index_exports, {
|
|
|
30
30
|
PayPalProvider: () => PayPalProvider,
|
|
31
31
|
PayPalSmartButtons: () => PayPalSmartButtons,
|
|
32
32
|
createPayPalStoreApi: () => createPayPalStoreApi,
|
|
33
|
-
|
|
33
|
+
hideProcessingOverlay: () => hideProcessingOverlay,
|
|
34
34
|
isPayPalProviderId: () => isPayPalProviderId,
|
|
35
35
|
markPaymentComplete: () => markPaymentComplete,
|
|
36
|
+
showProcessingOverlay: () => showProcessingOverlay,
|
|
36
37
|
usePayPalConfig: () => usePayPalConfig,
|
|
37
38
|
usePayPalPaymentMethods: () => usePayPalPaymentMethods
|
|
38
39
|
});
|
|
@@ -51,7 +52,6 @@ function toHeaderRecord(headers) {
|
|
|
51
52
|
}
|
|
52
53
|
return { ...headers };
|
|
53
54
|
}
|
|
54
|
-
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
55
55
|
function createHttpClient(opts) {
|
|
56
56
|
const base = opts.baseUrl.replace(/\/+$/, "");
|
|
57
57
|
async function request(path, init) {
|
|
@@ -63,33 +63,25 @@ function createHttpClient(opts) {
|
|
|
63
63
|
if (opts.publishableApiKey) {
|
|
64
64
|
headers["x-publishable-api-key"] = opts.publishableApiKey;
|
|
65
65
|
}
|
|
66
|
+
const timeoutMs = 3e4;
|
|
67
|
+
let timeoutId;
|
|
66
68
|
const controller = new AbortController();
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
timedOut = true;
|
|
70
|
-
controller.abort();
|
|
71
|
-
}, DEFAULT_TIMEOUT_MS);
|
|
72
|
-
const callerSignal = init?.signal;
|
|
73
|
-
if (callerSignal) {
|
|
74
|
-
if (callerSignal.aborted) {
|
|
75
|
-
controller.abort();
|
|
76
|
-
} else {
|
|
77
|
-
callerSignal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
78
|
-
}
|
|
69
|
+
if (!init?.signal) {
|
|
70
|
+
timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
79
71
|
}
|
|
72
|
+
const effectiveSignal = init?.signal || controller.signal;
|
|
80
73
|
let res;
|
|
81
|
-
let text;
|
|
82
74
|
try {
|
|
83
|
-
res = await fetch(url, { ...init, headers, credentials: "include", signal:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
throw new Error("[PayPal] Request timed out. Please check your connection and try again.");
|
|
75
|
+
res = await fetch(url, { ...init, headers, credentials: "include", signal: effectiveSignal });
|
|
76
|
+
} catch (err) {
|
|
77
|
+
if (err instanceof Error && err.name === "AbortError" && !init?.signal) {
|
|
78
|
+
throw new Error(`[PayPal] Request to ${path} timed out after ${timeoutMs / 1e3}s`);
|
|
88
79
|
}
|
|
89
|
-
throw
|
|
80
|
+
throw err;
|
|
90
81
|
} finally {
|
|
91
|
-
clearTimeout(
|
|
82
|
+
if (timeoutId !== void 0) clearTimeout(timeoutId);
|
|
92
83
|
}
|
|
84
|
+
const text = await res.text().catch(() => "");
|
|
93
85
|
if (!res.ok) {
|
|
94
86
|
if (res.status === 401) {
|
|
95
87
|
throw new Error(
|
|
@@ -101,21 +93,9 @@ function createHttpClient(opts) {
|
|
|
101
93
|
"[PayPal] Forbidden (403) \u2014 this request is not allowed. Check your CORS and API key settings."
|
|
102
94
|
);
|
|
103
95
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
} catch {
|
|
108
|
-
parsed = null;
|
|
109
|
-
}
|
|
110
|
-
const backendMessage = typeof parsed?.message === "string" ? parsed.message : "";
|
|
111
|
-
const requestId = typeof parsed?.request_id === "string" ? parsed.request_id : "";
|
|
112
|
-
if (res.status >= 500) {
|
|
113
|
-
console.error(`[PayPal] ${path} failed (${res.status})`, text.slice(0, 1e3));
|
|
114
|
-
throw new Error(
|
|
115
|
-
`Payment service error${requestId ? ` (ref ${requestId})` : ""}. Please try again or contact support.`
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
throw new Error(backendMessage || `Request failed (${res.status})`);
|
|
96
|
+
throw new Error(
|
|
97
|
+
text.slice(0, 500).replace(/<[^>]*>/g, "") || `Request failed (${res.status})`
|
|
98
|
+
);
|
|
119
99
|
}
|
|
120
100
|
if (!text) {
|
|
121
101
|
throw new Error(`[PayPal] Empty response body from ${path} (${res.status})`);
|
|
@@ -136,34 +116,13 @@ function createHttpClient(opts) {
|
|
|
136
116
|
}
|
|
137
117
|
|
|
138
118
|
// src/client/paypal.ts
|
|
139
|
-
function isNextRedirectError(e) {
|
|
140
|
-
if (!e || typeof e !== "object") {
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
const digest = e.digest;
|
|
144
|
-
return typeof digest === "string" && (digest.startsWith("NEXT_REDIRECT") || digest === "NEXT_NOT_FOUND");
|
|
145
|
-
}
|
|
146
119
|
async function markPaymentComplete(baseUrl, cartId, publishableApiKey) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
},
|
|
154
|
-
body: JSON.stringify({ cart_id: cartId }),
|
|
155
|
-
credentials: "include"
|
|
156
|
-
});
|
|
157
|
-
const data = await resp.json().catch(() => ({}));
|
|
158
|
-
if (!resp.ok) {
|
|
159
|
-
console.warn("[PayPal] paypal-complete returned", resp.status, data);
|
|
160
|
-
return { ok: false, ...data || {} };
|
|
161
|
-
}
|
|
162
|
-
return { ok: true, ...data || {} };
|
|
163
|
-
} catch (e) {
|
|
164
|
-
console.warn("[PayPal] paypal-complete call failed:", e);
|
|
165
|
-
return { ok: false };
|
|
166
|
-
}
|
|
120
|
+
const http = createHttpClient({ baseUrl, publishableApiKey });
|
|
121
|
+
return http.request(`/store/paypal-complete`, {
|
|
122
|
+
method: "POST",
|
|
123
|
+
headers: { "Content-Type": "application/json" },
|
|
124
|
+
body: JSON.stringify({ cart_id: cartId })
|
|
125
|
+
});
|
|
167
126
|
}
|
|
168
127
|
function createPayPalStoreApi(opts) {
|
|
169
128
|
const http = createHttpClient(opts);
|
|
@@ -194,8 +153,16 @@ function createPayPalStoreApi(opts) {
|
|
|
194
153
|
|
|
195
154
|
// src/hooks/usePayPalConfig.ts
|
|
196
155
|
var import_react = require("react");
|
|
156
|
+
var MAX_CACHE_ENTRIES = 50;
|
|
197
157
|
var _cache = /* @__PURE__ */ new Map();
|
|
198
158
|
var CACHE_TTL = 5 * 60 * 1e3;
|
|
159
|
+
function cacheSet(key, value) {
|
|
160
|
+
if (_cache.size >= MAX_CACHE_ENTRIES) {
|
|
161
|
+
const oldest = _cache.keys().next().value;
|
|
162
|
+
if (oldest !== void 0) _cache.delete(oldest);
|
|
163
|
+
}
|
|
164
|
+
_cache.set(key, value);
|
|
165
|
+
}
|
|
199
166
|
function cacheKey(baseUrl, cartId) {
|
|
200
167
|
return `${baseUrl}::${cartId ?? ""}`;
|
|
201
168
|
}
|
|
@@ -239,12 +206,12 @@ function usePayPalConfig({
|
|
|
239
206
|
try {
|
|
240
207
|
const cfg = await api.getConfig(cartId, controller.signal);
|
|
241
208
|
if (!mounted || id !== fetchIdRef.current) return;
|
|
242
|
-
|
|
209
|
+
cacheSet(k, { config: cfg, at: Date.now() });
|
|
243
210
|
setConfig(cfg);
|
|
244
211
|
} catch (e) {
|
|
245
|
-
if (e
|
|
212
|
+
if (e instanceof Error && e.name === "AbortError") return;
|
|
246
213
|
if (!mounted || id !== fetchIdRef.current) return;
|
|
247
|
-
setError(e
|
|
214
|
+
setError(e instanceof Error ? e.message : "Failed to load PayPal config");
|
|
248
215
|
} finally {
|
|
249
216
|
if (mounted && id === fetchIdRef.current) setLoading(false);
|
|
250
217
|
}
|
|
@@ -274,7 +241,7 @@ function PayPalProvider(props) {
|
|
|
274
241
|
"disable-funding": disableFunding,
|
|
275
242
|
"data-partner-attribution-id": BN_CODE
|
|
276
243
|
};
|
|
277
|
-
}, [config, intent, disableFunding]);
|
|
244
|
+
}, [config.client_id, config.currency, config.client_token, intent, disableFunding]);
|
|
278
245
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
279
246
|
import_react_paypal_js.PayPalScriptProvider,
|
|
280
247
|
{
|
|
@@ -289,7 +256,7 @@ function PayPalProvider(props) {
|
|
|
289
256
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
290
257
|
function PayPalCurrencyNotice({ config }) {
|
|
291
258
|
if (config.currency_supported) return null;
|
|
292
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { padding: 12, border: "1px solid #ddd", borderRadius: 10 }, children: [
|
|
259
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { role: "alert", style: { padding: 12, border: "1px solid #ddd", borderRadius: 10 }, children: [
|
|
293
260
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontWeight: 600, marginBottom: 6 }, children: "PayPal currency issue" }),
|
|
294
261
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { style: { margin: 0, paddingLeft: 18 }, children: (config.currency_errors || []).map((e) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { children: e }, e)) })
|
|
295
262
|
] });
|
|
@@ -298,8 +265,71 @@ function PayPalCurrencyNotice({ config }) {
|
|
|
298
265
|
// src/components/PayPalSmartButtons.tsx
|
|
299
266
|
var import_react3 = require("react");
|
|
300
267
|
var import_react_paypal_js2 = require("@paypal/react-paypal-js");
|
|
268
|
+
|
|
269
|
+
// src/utils/next-errors.ts
|
|
270
|
+
function isNextRouterError(e) {
|
|
271
|
+
if (typeof e !== "object" || e === null || !("digest" in e)) return false;
|
|
272
|
+
const digest = e.digest;
|
|
273
|
+
return typeof digest === "string" && (digest.startsWith("NEXT_REDIRECT") || digest.startsWith("NEXT_NOT_FOUND"));
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// src/utils/processing-overlay.ts
|
|
277
|
+
var OVERLAY_ID = "__pp_processing_overlay";
|
|
278
|
+
function showProcessingOverlay() {
|
|
279
|
+
if (typeof document === "undefined") return;
|
|
280
|
+
if (document.getElementById(OVERLAY_ID)) return;
|
|
281
|
+
const overlay = document.createElement("div");
|
|
282
|
+
overlay.id = OVERLAY_ID;
|
|
283
|
+
overlay.setAttribute("role", "status");
|
|
284
|
+
overlay.setAttribute("aria-label", "Processing payment");
|
|
285
|
+
overlay.innerHTML = `
|
|
286
|
+
<style>
|
|
287
|
+
@keyframes _pp_spin { to { transform: rotate(360deg) } }
|
|
288
|
+
@keyframes _pp_progress { 0% { transform: translateX(-100%) } 100% { transform: translateX(350%) } }
|
|
289
|
+
</style>
|
|
290
|
+
<div style="position:relative;width:56px;height:56px">
|
|
291
|
+
<div style="position:absolute;inset:0;border-radius:50%;border:3px solid #e5e7eb"></div>
|
|
292
|
+
<div style="position:absolute;inset:0;border-radius:50%;border:3px solid transparent;border-top-color:#0070ba;animation:_pp_spin .8s linear infinite"></div>
|
|
293
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="#0070ba" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"
|
|
294
|
+
style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:24px;height:24px">
|
|
295
|
+
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
|
|
296
|
+
</svg>
|
|
297
|
+
</div>
|
|
298
|
+
<div style="text-align:center">
|
|
299
|
+
<div style="font-size:18px;font-weight:600;color:#111827;letter-spacing:-0.01em">Processing your payment</div>
|
|
300
|
+
<div style="font-size:14px;color:#6b7280;margin-top:6px;line-height:1.5">
|
|
301
|
+
This may take a few moments. Please do not close<br>or refresh this page.
|
|
302
|
+
</div>
|
|
303
|
+
</div>
|
|
304
|
+
<div style="width:200px;height:3px;background:#e5e7eb;border-radius:3px;overflow:hidden;margin-top:4px">
|
|
305
|
+
<div style="width:40%;height:100%;background:linear-gradient(90deg,#0070ba,#003087);border-radius:3px;animation:_pp_progress 1.5s ease-in-out infinite"></div>
|
|
306
|
+
</div>
|
|
307
|
+
`;
|
|
308
|
+
Object.assign(overlay.style, {
|
|
309
|
+
position: "fixed",
|
|
310
|
+
inset: "0",
|
|
311
|
+
zIndex: "99999",
|
|
312
|
+
background: "rgba(255,255,255,0.96)",
|
|
313
|
+
display: "flex",
|
|
314
|
+
flexDirection: "column",
|
|
315
|
+
alignItems: "center",
|
|
316
|
+
justifyContent: "center",
|
|
317
|
+
gap: "20px",
|
|
318
|
+
fontFamily: "-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif"
|
|
319
|
+
});
|
|
320
|
+
document.body.appendChild(overlay);
|
|
321
|
+
}
|
|
322
|
+
function hideProcessingOverlay() {
|
|
323
|
+
if (typeof document === "undefined") return;
|
|
324
|
+
document.getElementById(OVERLAY_ID)?.remove();
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// src/components/PayPalSmartButtons.tsx
|
|
301
328
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
302
|
-
var SPIN_STYLE =
|
|
329
|
+
var SPIN_STYLE = `
|
|
330
|
+
@keyframes _pp_spin { to { transform: rotate(360deg) } }
|
|
331
|
+
@keyframes _pp_progress { 0% { transform: translateX(-100%) } 100% { transform: translateX(350%) } }
|
|
332
|
+
`;
|
|
303
333
|
var BUTTON_WIDTH_MAP = {
|
|
304
334
|
small: "300px",
|
|
305
335
|
medium: "400px",
|
|
@@ -314,6 +344,12 @@ function PayPalSmartButtons(props) {
|
|
|
314
344
|
);
|
|
315
345
|
const [error, setError] = (0, import_react3.useState)(null);
|
|
316
346
|
const [processing, setProcessing] = (0, import_react3.useState)(false);
|
|
347
|
+
const [buttonsReady, setButtonsReady] = (0, import_react3.useState)(false);
|
|
348
|
+
const [{ isPending, isResolved, isRejected }] = (0, import_react_paypal_js2.usePayPalScriptReducer)();
|
|
349
|
+
const handleInit = (0, import_react3.useCallback)(() => {
|
|
350
|
+
setButtonsReady(true);
|
|
351
|
+
}, []);
|
|
352
|
+
const showSpinner = isPending || isResolved && !buttonsReady;
|
|
317
353
|
if (!config.currency_supported) return null;
|
|
318
354
|
const containerWidth = BUTTON_WIDTH_MAP[config.button_width ?? "responsive"] ?? "100%";
|
|
319
355
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { width: containerWidth, position: "relative" }, children: [
|
|
@@ -321,41 +357,160 @@ function PayPalSmartButtons(props) {
|
|
|
321
357
|
processing && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
322
358
|
"div",
|
|
323
359
|
{
|
|
360
|
+
role: "status",
|
|
361
|
+
"aria-label": "Processing payment",
|
|
324
362
|
style: {
|
|
325
|
-
position: "
|
|
363
|
+
position: "fixed",
|
|
326
364
|
inset: 0,
|
|
327
|
-
zIndex:
|
|
328
|
-
background: "rgba(255,255,255,0.
|
|
329
|
-
borderRadius: 8,
|
|
365
|
+
zIndex: 9999,
|
|
366
|
+
background: "rgba(255,255,255,0.96)",
|
|
330
367
|
display: "flex",
|
|
331
368
|
flexDirection: "column",
|
|
332
369
|
alignItems: "center",
|
|
333
370
|
justifyContent: "center",
|
|
371
|
+
gap: 20
|
|
372
|
+
},
|
|
373
|
+
children: [
|
|
374
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { position: "relative", width: 56, height: 56 }, children: [
|
|
375
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
376
|
+
"div",
|
|
377
|
+
{
|
|
378
|
+
style: {
|
|
379
|
+
position: "absolute",
|
|
380
|
+
inset: 0,
|
|
381
|
+
borderRadius: "50%",
|
|
382
|
+
border: "3px solid #e5e7eb"
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
),
|
|
386
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
387
|
+
"div",
|
|
388
|
+
{
|
|
389
|
+
style: {
|
|
390
|
+
position: "absolute",
|
|
391
|
+
inset: 0,
|
|
392
|
+
borderRadius: "50%",
|
|
393
|
+
border: "3px solid transparent",
|
|
394
|
+
borderTopColor: "#0070ba",
|
|
395
|
+
animation: "_pp_spin .8s linear infinite"
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
),
|
|
399
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
400
|
+
"svg",
|
|
401
|
+
{
|
|
402
|
+
viewBox: "0 0 24 24",
|
|
403
|
+
fill: "none",
|
|
404
|
+
stroke: "#0070ba",
|
|
405
|
+
strokeWidth: "1.8",
|
|
406
|
+
strokeLinecap: "round",
|
|
407
|
+
strokeLinejoin: "round",
|
|
408
|
+
style: {
|
|
409
|
+
position: "absolute",
|
|
410
|
+
top: "50%",
|
|
411
|
+
left: "50%",
|
|
412
|
+
transform: "translate(-50%, -50%)",
|
|
413
|
+
width: 24,
|
|
414
|
+
height: 24
|
|
415
|
+
},
|
|
416
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" })
|
|
417
|
+
}
|
|
418
|
+
)
|
|
419
|
+
] }),
|
|
420
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { textAlign: "center" }, children: [
|
|
421
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { fontSize: 18, fontWeight: 600, color: "#111827", letterSpacing: "-0.01em" }, children: "Processing your payment" }),
|
|
422
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { fontSize: 14, color: "#6b7280", marginTop: 6, lineHeight: 1.5 }, children: [
|
|
423
|
+
"This may take a few moments. Please do not close",
|
|
424
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("br", {}),
|
|
425
|
+
"or refresh this page."
|
|
426
|
+
] })
|
|
427
|
+
] }),
|
|
428
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
429
|
+
"div",
|
|
430
|
+
{
|
|
431
|
+
style: {
|
|
432
|
+
width: 200,
|
|
433
|
+
height: 3,
|
|
434
|
+
background: "#e5e7eb",
|
|
435
|
+
borderRadius: 3,
|
|
436
|
+
overflow: "hidden",
|
|
437
|
+
marginTop: 4
|
|
438
|
+
},
|
|
439
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
440
|
+
"div",
|
|
441
|
+
{
|
|
442
|
+
style: {
|
|
443
|
+
width: "40%",
|
|
444
|
+
height: "100%",
|
|
445
|
+
background: "linear-gradient(90deg, #0070ba, #003087)",
|
|
446
|
+
borderRadius: 3,
|
|
447
|
+
animation: "_pp_progress 1.5s ease-in-out infinite"
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
)
|
|
451
|
+
}
|
|
452
|
+
)
|
|
453
|
+
]
|
|
454
|
+
}
|
|
455
|
+
),
|
|
456
|
+
showSpinner && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
457
|
+
"div",
|
|
458
|
+
{
|
|
459
|
+
role: "status",
|
|
460
|
+
"aria-label": "Loading PayPal",
|
|
461
|
+
style: {
|
|
462
|
+
display: "flex",
|
|
463
|
+
alignItems: "center",
|
|
464
|
+
justifyContent: "center",
|
|
334
465
|
gap: 10,
|
|
335
|
-
|
|
466
|
+
padding: "18px 16px",
|
|
467
|
+
background: "#f9fafb",
|
|
468
|
+
border: "1px solid #e5e7eb",
|
|
469
|
+
borderRadius: 8,
|
|
470
|
+
minHeight: 55
|
|
336
471
|
},
|
|
337
472
|
children: [
|
|
338
473
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
339
474
|
"div",
|
|
340
475
|
{
|
|
341
476
|
style: {
|
|
342
|
-
width:
|
|
343
|
-
height:
|
|
477
|
+
width: 22,
|
|
478
|
+
height: 22,
|
|
344
479
|
borderRadius: "50%",
|
|
345
480
|
border: "2.5px solid #e5e7eb",
|
|
346
481
|
borderTopColor: "#0070ba",
|
|
347
|
-
animation: "_pp_spin .7s linear infinite"
|
|
482
|
+
animation: "_pp_spin .7s linear infinite",
|
|
483
|
+
flexShrink: 0
|
|
348
484
|
}
|
|
349
485
|
}
|
|
350
486
|
),
|
|
351
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
487
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { fontSize: 13, fontWeight: 500, color: "#6b7280" }, children: "Loading PayPal\u2026" })
|
|
488
|
+
]
|
|
489
|
+
}
|
|
490
|
+
),
|
|
491
|
+
isRejected && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
492
|
+
"div",
|
|
493
|
+
{
|
|
494
|
+
role: "alert",
|
|
495
|
+
style: {
|
|
496
|
+
display: "flex",
|
|
497
|
+
alignItems: "flex-start",
|
|
498
|
+
gap: 8,
|
|
499
|
+
padding: "10px 14px",
|
|
500
|
+
background: "#fef2f2",
|
|
501
|
+
border: "1px solid #fecaca",
|
|
502
|
+
borderRadius: 8,
|
|
503
|
+
fontSize: 13,
|
|
504
|
+
color: "#b91c1c",
|
|
505
|
+
lineHeight: 1.5
|
|
506
|
+
},
|
|
507
|
+
children: [
|
|
508
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { flexShrink: 0, fontSize: 15 }, children: "\u26A0\uFE0F" }),
|
|
509
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "PayPal failed to load. Please refresh the page or try a different payment method." })
|
|
355
510
|
]
|
|
356
511
|
}
|
|
357
512
|
),
|
|
358
|
-
config.environment === "sandbox" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
513
|
+
config.environment === "sandbox" && buttonsReady && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
359
514
|
"div",
|
|
360
515
|
{
|
|
361
516
|
style: {
|
|
@@ -393,9 +548,11 @@ function PayPalSmartButtons(props) {
|
|
|
393
548
|
]
|
|
394
549
|
}
|
|
395
550
|
),
|
|
396
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
551
|
+
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)(
|
|
397
552
|
import_react_paypal_js2.PayPalButtons,
|
|
398
553
|
{
|
|
554
|
+
forceReRender: [config.currency, config.intent, cartId],
|
|
555
|
+
onInit: handleInit,
|
|
399
556
|
style: {
|
|
400
557
|
layout: "vertical",
|
|
401
558
|
color: config.button_color,
|
|
@@ -404,40 +561,53 @@ function PayPalSmartButtons(props) {
|
|
|
404
561
|
height: config.button_height
|
|
405
562
|
},
|
|
406
563
|
createOrder: async () => {
|
|
564
|
+
if (processing) throw new Error("Payment already processing");
|
|
407
565
|
setError(null);
|
|
408
|
-
|
|
409
|
-
|
|
566
|
+
setProcessing(true);
|
|
567
|
+
try {
|
|
568
|
+
const r = await api.createOrder(cartId);
|
|
569
|
+
return r.id;
|
|
570
|
+
} catch (e) {
|
|
571
|
+
setProcessing(false);
|
|
572
|
+
throw e;
|
|
573
|
+
}
|
|
410
574
|
},
|
|
411
575
|
onApprove: async (data) => {
|
|
412
576
|
try {
|
|
413
577
|
setProcessing(true);
|
|
578
|
+
showProcessingOverlay();
|
|
414
579
|
setError(null);
|
|
415
580
|
const orderId = String(data?.orderID || "");
|
|
581
|
+
if (!orderId) throw new Error("PayPal order ID is missing from approval response");
|
|
416
582
|
const result = await api.captureOrder(cartId, orderId);
|
|
417
583
|
const completeResult = await markPaymentComplete(baseUrl, cartId, publishableApiKey);
|
|
418
|
-
onPaid?.({ ...result, ...completeResult });
|
|
584
|
+
await onPaid?.({ ...result, ...completeResult });
|
|
419
585
|
} catch (e) {
|
|
586
|
+
if (isNextRouterError(e)) throw e;
|
|
587
|
+
hideProcessingOverlay();
|
|
588
|
+
setProcessing(false);
|
|
420
589
|
const msg = e instanceof Error ? e.message : "Payment capture failed";
|
|
421
590
|
setError(msg);
|
|
422
591
|
onError?.(msg);
|
|
423
|
-
} finally {
|
|
424
|
-
setProcessing(false);
|
|
425
592
|
}
|
|
426
593
|
},
|
|
427
594
|
onCancel: () => {
|
|
595
|
+
hideProcessingOverlay();
|
|
428
596
|
setProcessing(false);
|
|
429
597
|
},
|
|
430
598
|
onError: (err) => {
|
|
599
|
+
hideProcessingOverlay();
|
|
431
600
|
setProcessing(false);
|
|
432
601
|
const msg = err instanceof Error ? err.message : err?.message || "PayPal error";
|
|
433
602
|
setError(msg);
|
|
434
603
|
onError?.(msg);
|
|
435
604
|
}
|
|
436
605
|
}
|
|
437
|
-
),
|
|
606
|
+
) }),
|
|
438
607
|
error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
439
608
|
"div",
|
|
440
609
|
{
|
|
610
|
+
role: "alert",
|
|
441
611
|
style: {
|
|
442
612
|
marginTop: 10,
|
|
443
613
|
display: "flex",
|
|
@@ -464,7 +634,10 @@ function PayPalSmartButtons(props) {
|
|
|
464
634
|
var import_react4 = require("react");
|
|
465
635
|
var import_react_paypal_js3 = require("@paypal/react-paypal-js");
|
|
466
636
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
467
|
-
var SPIN_STYLE2 =
|
|
637
|
+
var SPIN_STYLE2 = `
|
|
638
|
+
@keyframes _pp_spin { to { transform: rotate(360deg) } }
|
|
639
|
+
@keyframes _pp_progress { 0% { transform: translateX(-100%) } 100% { transform: translateX(350%) } }
|
|
640
|
+
`;
|
|
468
641
|
var cardStyle = {
|
|
469
642
|
input: {
|
|
470
643
|
"font-size": "15px",
|
|
@@ -510,8 +683,7 @@ var labelStyle = {
|
|
|
510
683
|
function SubmitButton({
|
|
511
684
|
disabled,
|
|
512
685
|
label,
|
|
513
|
-
onSubmit
|
|
514
|
-
onSubmitError
|
|
686
|
+
onSubmit
|
|
515
687
|
}) {
|
|
516
688
|
const { cardFieldsForm } = (0, import_react_paypal_js3.usePayPalCardFields)();
|
|
517
689
|
const isDisabled = disabled || !cardFieldsForm;
|
|
@@ -520,15 +692,12 @@ function SubmitButton({
|
|
|
520
692
|
{
|
|
521
693
|
type: "button",
|
|
522
694
|
disabled: isDisabled,
|
|
695
|
+
"aria-busy": disabled,
|
|
523
696
|
onClick: () => {
|
|
524
697
|
onSubmit();
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
onSubmitError(
|
|
529
|
-
e instanceof Error ? e.message : "Card payment failed. Please try again."
|
|
530
|
-
);
|
|
531
|
-
});
|
|
698
|
+
try {
|
|
699
|
+
cardFieldsForm?.submit();
|
|
700
|
+
} catch {
|
|
532
701
|
}
|
|
533
702
|
},
|
|
534
703
|
style: {
|
|
@@ -573,7 +742,33 @@ function PayPalAdvancedCard(props) {
|
|
|
573
742
|
);
|
|
574
743
|
const [error, setError] = (0, import_react4.useState)(null);
|
|
575
744
|
const [submitting, setSubmitting] = (0, import_react4.useState)(false);
|
|
745
|
+
const submittingRef = (0, import_react4.useRef)(false);
|
|
746
|
+
const [{ isPending, isResolved, isRejected }] = (0, import_react_paypal_js3.usePayPalScriptReducer)();
|
|
576
747
|
if (!config.currency_supported) return null;
|
|
748
|
+
if (isRejected) {
|
|
749
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
750
|
+
"div",
|
|
751
|
+
{
|
|
752
|
+
role: "alert",
|
|
753
|
+
style: {
|
|
754
|
+
display: "flex",
|
|
755
|
+
alignItems: "flex-start",
|
|
756
|
+
gap: 8,
|
|
757
|
+
padding: "10px 14px",
|
|
758
|
+
background: "#fef2f2",
|
|
759
|
+
border: "1px solid #fecaca",
|
|
760
|
+
borderRadius: 8,
|
|
761
|
+
fontSize: 13,
|
|
762
|
+
color: "#b91c1c",
|
|
763
|
+
lineHeight: 1.5
|
|
764
|
+
},
|
|
765
|
+
children: [
|
|
766
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { flexShrink: 0, fontSize: 15 }, children: "\u26A0\uFE0F" }),
|
|
767
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "PayPal failed to load. Please refresh the page or try a different payment method." })
|
|
768
|
+
]
|
|
769
|
+
}
|
|
770
|
+
);
|
|
771
|
+
}
|
|
577
772
|
if (!config.client_token) {
|
|
578
773
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
579
774
|
"div",
|
|
@@ -591,42 +786,143 @@ function PayPalAdvancedCard(props) {
|
|
|
591
786
|
);
|
|
592
787
|
}
|
|
593
788
|
const isSandbox = config.environment === "sandbox";
|
|
789
|
+
if (isPending) {
|
|
790
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
791
|
+
"div",
|
|
792
|
+
{
|
|
793
|
+
role: "status",
|
|
794
|
+
"aria-label": "Loading PayPal",
|
|
795
|
+
style: {
|
|
796
|
+
display: "flex",
|
|
797
|
+
alignItems: "center",
|
|
798
|
+
justifyContent: "center",
|
|
799
|
+
gap: 10,
|
|
800
|
+
padding: "18px 16px",
|
|
801
|
+
background: "#f9fafb",
|
|
802
|
+
border: "1px solid #e5e7eb",
|
|
803
|
+
borderRadius: 8,
|
|
804
|
+
minHeight: 55
|
|
805
|
+
},
|
|
806
|
+
children: [
|
|
807
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: SPIN_STYLE2 }),
|
|
808
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
809
|
+
"div",
|
|
810
|
+
{
|
|
811
|
+
style: {
|
|
812
|
+
width: 22,
|
|
813
|
+
height: 22,
|
|
814
|
+
borderRadius: "50%",
|
|
815
|
+
border: "2.5px solid #e5e7eb",
|
|
816
|
+
borderTopColor: "#0070ba",
|
|
817
|
+
animation: "_pp_spin .7s linear infinite",
|
|
818
|
+
flexShrink: 0
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
),
|
|
822
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: 13, fontWeight: 500, color: "#6b7280" }, children: "Loading card fields\u2026" })
|
|
823
|
+
]
|
|
824
|
+
}
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
if (!isResolved) return null;
|
|
594
828
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { position: "relative" }, children: [
|
|
595
829
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: SPIN_STYLE2 }),
|
|
596
830
|
submitting && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
597
831
|
"div",
|
|
598
832
|
{
|
|
833
|
+
role: "status",
|
|
834
|
+
"aria-label": "Processing payment",
|
|
599
835
|
style: {
|
|
600
|
-
position: "
|
|
836
|
+
position: "fixed",
|
|
601
837
|
inset: 0,
|
|
602
|
-
zIndex:
|
|
603
|
-
background: "rgba(255,255,255,0.
|
|
604
|
-
borderRadius: 12,
|
|
838
|
+
zIndex: 9999,
|
|
839
|
+
background: "rgba(255,255,255,0.96)",
|
|
605
840
|
display: "flex",
|
|
606
841
|
flexDirection: "column",
|
|
607
842
|
alignItems: "center",
|
|
608
843
|
justifyContent: "center",
|
|
609
|
-
gap:
|
|
610
|
-
minHeight: 180
|
|
844
|
+
gap: 20
|
|
611
845
|
},
|
|
612
846
|
children: [
|
|
847
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { position: "relative", width: 56, height: 56 }, children: [
|
|
848
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
849
|
+
"div",
|
|
850
|
+
{
|
|
851
|
+
style: {
|
|
852
|
+
position: "absolute",
|
|
853
|
+
inset: 0,
|
|
854
|
+
borderRadius: "50%",
|
|
855
|
+
border: "3px solid #e5e7eb"
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
),
|
|
859
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
860
|
+
"div",
|
|
861
|
+
{
|
|
862
|
+
style: {
|
|
863
|
+
position: "absolute",
|
|
864
|
+
inset: 0,
|
|
865
|
+
borderRadius: "50%",
|
|
866
|
+
border: "3px solid transparent",
|
|
867
|
+
borderTopColor: "#2563eb",
|
|
868
|
+
animation: "_pp_spin .8s linear infinite"
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
),
|
|
872
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
873
|
+
"svg",
|
|
874
|
+
{
|
|
875
|
+
viewBox: "0 0 24 24",
|
|
876
|
+
fill: "none",
|
|
877
|
+
stroke: "#2563eb",
|
|
878
|
+
strokeWidth: "1.8",
|
|
879
|
+
strokeLinecap: "round",
|
|
880
|
+
strokeLinejoin: "round",
|
|
881
|
+
style: {
|
|
882
|
+
position: "absolute",
|
|
883
|
+
top: "50%",
|
|
884
|
+
left: "50%",
|
|
885
|
+
transform: "translate(-50%, -50%)",
|
|
886
|
+
width: 24,
|
|
887
|
+
height: 24
|
|
888
|
+
},
|
|
889
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" })
|
|
890
|
+
}
|
|
891
|
+
)
|
|
892
|
+
] }),
|
|
893
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { textAlign: "center" }, children: [
|
|
894
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: 18, fontWeight: 600, color: "#111827", letterSpacing: "-0.01em" }, children: "Processing your payment" }),
|
|
895
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { fontSize: 14, color: "#6b7280", marginTop: 6, lineHeight: 1.5 }, children: [
|
|
896
|
+
"This may take a few moments. Please do not close",
|
|
897
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("br", {}),
|
|
898
|
+
"or refresh this page."
|
|
899
|
+
] })
|
|
900
|
+
] }),
|
|
613
901
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
614
902
|
"div",
|
|
615
903
|
{
|
|
616
904
|
style: {
|
|
617
|
-
width:
|
|
618
|
-
height:
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
}
|
|
905
|
+
width: 200,
|
|
906
|
+
height: 3,
|
|
907
|
+
background: "#e5e7eb",
|
|
908
|
+
borderRadius: 3,
|
|
909
|
+
overflow: "hidden",
|
|
910
|
+
marginTop: 4
|
|
911
|
+
},
|
|
912
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
913
|
+
"div",
|
|
914
|
+
{
|
|
915
|
+
style: {
|
|
916
|
+
width: "40%",
|
|
917
|
+
height: "100%",
|
|
918
|
+
background: "linear-gradient(90deg, #2563eb, #1d4ed8)",
|
|
919
|
+
borderRadius: 3,
|
|
920
|
+
animation: "_pp_progress 1.5s ease-in-out infinite"
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
)
|
|
624
924
|
}
|
|
625
|
-
)
|
|
626
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { textAlign: "center" }, children: [
|
|
627
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: 15, fontWeight: 600, color: "#111827" }, children: "Processing your payment\u2026" }),
|
|
628
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: 13, color: "#6b7280", marginTop: 4 }, children: "Please do not close or refresh this page" })
|
|
629
|
-
] })
|
|
925
|
+
)
|
|
630
926
|
]
|
|
631
927
|
}
|
|
632
928
|
),
|
|
@@ -635,6 +931,7 @@ function PayPalAdvancedCard(props) {
|
|
|
635
931
|
{
|
|
636
932
|
style: cardStyle,
|
|
637
933
|
createOrder: async () => {
|
|
934
|
+
if (submittingRef.current) throw new Error("Payment already processing");
|
|
638
935
|
setError(null);
|
|
639
936
|
const r = await api.createOrder(cartId, true);
|
|
640
937
|
return r.id;
|
|
@@ -642,25 +939,32 @@ function PayPalAdvancedCard(props) {
|
|
|
642
939
|
onApprove: async (data) => {
|
|
643
940
|
try {
|
|
644
941
|
setError(null);
|
|
942
|
+
showProcessingOverlay();
|
|
645
943
|
const orderId = String(data?.orderID || "");
|
|
646
944
|
const result = await api.captureOrder(cartId, orderId);
|
|
647
945
|
const completeResult = await markPaymentComplete(baseUrl, cartId, publishableApiKey);
|
|
648
|
-
onPaid?.({ ...result, ...completeResult });
|
|
946
|
+
await onPaid?.({ ...result, ...completeResult });
|
|
649
947
|
} catch (e) {
|
|
948
|
+
if (isNextRouterError(e)) throw e;
|
|
949
|
+
hideProcessingOverlay();
|
|
950
|
+
submittingRef.current = false;
|
|
951
|
+
setSubmitting(false);
|
|
650
952
|
const msg = e instanceof Error ? e.message : "Card payment failed";
|
|
651
953
|
setError(msg);
|
|
652
954
|
onError?.(msg);
|
|
653
|
-
} finally {
|
|
654
|
-
setSubmitting(false);
|
|
655
955
|
}
|
|
656
956
|
},
|
|
657
957
|
onCancel: () => {
|
|
958
|
+
hideProcessingOverlay();
|
|
959
|
+
submittingRef.current = false;
|
|
658
960
|
setSubmitting(false);
|
|
659
961
|
},
|
|
660
962
|
onError: (e) => {
|
|
661
963
|
const msg = e instanceof Error ? e.message : e?.message || "CardFields error";
|
|
662
964
|
setError(msg);
|
|
663
965
|
onError?.(msg);
|
|
966
|
+
hideProcessingOverlay();
|
|
967
|
+
submittingRef.current = false;
|
|
664
968
|
setSubmitting(false);
|
|
665
969
|
},
|
|
666
970
|
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
@@ -759,19 +1063,18 @@ function PayPalAdvancedCard(props) {
|
|
|
759
1063
|
disabled: submitting,
|
|
760
1064
|
label: submitting ? "Processing\u2026" : "Pay by Card",
|
|
761
1065
|
onSubmit: () => {
|
|
1066
|
+
if (submittingRef.current) return;
|
|
1067
|
+
submittingRef.current = true;
|
|
762
1068
|
setError(null);
|
|
763
1069
|
setSubmitting(true);
|
|
764
|
-
|
|
765
|
-
onSubmitError: (msg) => {
|
|
766
|
-
setError(msg);
|
|
767
|
-
onError?.(msg);
|
|
768
|
-
setSubmitting(false);
|
|
1070
|
+
showProcessingOverlay();
|
|
769
1071
|
}
|
|
770
1072
|
}
|
|
771
1073
|
),
|
|
772
1074
|
error && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
773
1075
|
"div",
|
|
774
1076
|
{
|
|
1077
|
+
role: "alert",
|
|
775
1078
|
style: {
|
|
776
1079
|
display: "flex",
|
|
777
1080
|
alignItems: "flex-start",
|
|
@@ -808,6 +1111,8 @@ function PayPalLoadingCard() {
|
|
|
808
1111
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
809
1112
|
"div",
|
|
810
1113
|
{
|
|
1114
|
+
role: "status",
|
|
1115
|
+
"aria-label": "Connecting to PayPal",
|
|
811
1116
|
style: {
|
|
812
1117
|
display: "flex",
|
|
813
1118
|
alignItems: "center",
|
|
@@ -845,6 +1150,7 @@ function PayPalErrorCard({ message }) {
|
|
|
845
1150
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
846
1151
|
"div",
|
|
847
1152
|
{
|
|
1153
|
+
role: "alert",
|
|
848
1154
|
style: {
|
|
849
1155
|
padding: "12px 16px",
|
|
850
1156
|
background: "#fef2f2",
|
|
@@ -878,16 +1184,11 @@ function MedusaNextPayPalAdapter(props) {
|
|
|
878
1184
|
enabled: shouldRender
|
|
879
1185
|
});
|
|
880
1186
|
const handlePaid = (0, import_react5.useCallback)(
|
|
881
|
-
(captureResult) => {
|
|
1187
|
+
async (captureResult) => {
|
|
882
1188
|
onPaid?.(captureResult);
|
|
883
|
-
|
|
884
|
-
if (isNextRedirectError(e)) return;
|
|
885
|
-
onError?.(
|
|
886
|
-
e instanceof Error ? e.message : "Your payment was taken but the order could not be finalized. Please contact support before paying again."
|
|
887
|
-
);
|
|
888
|
-
});
|
|
1189
|
+
await onSuccess?.(cartId);
|
|
889
1190
|
},
|
|
890
|
-
[cartId, onPaid, onSuccess
|
|
1191
|
+
[cartId, onPaid, onSuccess]
|
|
891
1192
|
);
|
|
892
1193
|
if (!shouldRender) return null;
|
|
893
1194
|
if (loading) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PayPalLoadingCard, {});
|
|
@@ -949,6 +1250,8 @@ function SessionInitCard() {
|
|
|
949
1250
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
950
1251
|
"div",
|
|
951
1252
|
{
|
|
1253
|
+
role: "status",
|
|
1254
|
+
"aria-label": "Setting up payment",
|
|
952
1255
|
style: {
|
|
953
1256
|
display: "flex",
|
|
954
1257
|
alignItems: "center",
|
|
@@ -984,6 +1287,8 @@ function ConfigLoadingCard() {
|
|
|
984
1287
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
985
1288
|
"div",
|
|
986
1289
|
{
|
|
1290
|
+
role: "status",
|
|
1291
|
+
"aria-label": "Connecting to PayPal",
|
|
987
1292
|
style: {
|
|
988
1293
|
display: "flex",
|
|
989
1294
|
alignItems: "center",
|
|
@@ -1021,6 +1326,7 @@ function ErrorCard({ message }) {
|
|
|
1021
1326
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1022
1327
|
"div",
|
|
1023
1328
|
{
|
|
1329
|
+
role: "alert",
|
|
1024
1330
|
style: {
|
|
1025
1331
|
padding: "12px 16px",
|
|
1026
1332
|
background: "#fef2f2",
|
|
@@ -1051,16 +1357,11 @@ function PayPalPaymentSection({
|
|
|
1051
1357
|
enabled: shouldRender
|
|
1052
1358
|
});
|
|
1053
1359
|
const handlePaid = (0, import_react6.useCallback)(
|
|
1054
|
-
(captureResult) => {
|
|
1360
|
+
async (captureResult) => {
|
|
1055
1361
|
onPaid?.(captureResult);
|
|
1056
|
-
|
|
1057
|
-
if (isNextRedirectError(e)) return;
|
|
1058
|
-
onError?.(
|
|
1059
|
-
e instanceof Error ? e.message : "Your payment was taken but the order could not be finalized. Please contact support before paying again."
|
|
1060
|
-
);
|
|
1061
|
-
});
|
|
1362
|
+
await onSuccess?.(cartId);
|
|
1062
1363
|
},
|
|
1063
|
-
[cartId, onPaid, onSuccess
|
|
1364
|
+
[cartId, onPaid, onSuccess]
|
|
1064
1365
|
);
|
|
1065
1366
|
if (!shouldRender) return null;
|
|
1066
1367
|
if (sessionLoading) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SessionInitCard, {});
|
|
@@ -1109,8 +1410,16 @@ function PayPalPaymentSection({
|
|
|
1109
1410
|
|
|
1110
1411
|
// src/hooks/usePayPalPaymentMethods.ts
|
|
1111
1412
|
var import_react7 = require("react");
|
|
1413
|
+
var MAX_CACHE_ENTRIES2 = 50;
|
|
1112
1414
|
var _cache2 = /* @__PURE__ */ new Map();
|
|
1113
1415
|
var CACHE_TTL2 = 5 * 60 * 1e3;
|
|
1416
|
+
function cacheSet2(key, value) {
|
|
1417
|
+
if (_cache2.size >= MAX_CACHE_ENTRIES2) {
|
|
1418
|
+
const oldest = _cache2.keys().next().value;
|
|
1419
|
+
if (oldest !== void 0) _cache2.delete(oldest);
|
|
1420
|
+
}
|
|
1421
|
+
_cache2.set(key, value);
|
|
1422
|
+
}
|
|
1114
1423
|
function cacheKey2(baseUrl, cartId) {
|
|
1115
1424
|
return `ppm::${baseUrl}::${cartId ?? ""}`;
|
|
1116
1425
|
}
|
|
@@ -1162,12 +1471,13 @@ function usePayPalPaymentMethods({
|
|
|
1162
1471
|
cardTitle: typeof cfg.card_title === "string" && cfg.card_title ? cfg.card_title : "Credit or Debit Card",
|
|
1163
1472
|
loading: false
|
|
1164
1473
|
};
|
|
1165
|
-
|
|
1474
|
+
cacheSet2(k, { result: next, at: Date.now() });
|
|
1166
1475
|
setResult(next);
|
|
1167
1476
|
} catch (e) {
|
|
1168
|
-
|
|
1477
|
+
const msg = e instanceof Error ? e.message : "";
|
|
1478
|
+
if (e instanceof Error && e.name === "AbortError") return;
|
|
1169
1479
|
if (!mounted || id !== fetchIdRef.current) return;
|
|
1170
|
-
if (
|
|
1480
|
+
if (msg.includes("403") || msg.includes("Forbidden")) {
|
|
1171
1481
|
const disabled = {
|
|
1172
1482
|
...DEFAULT_RESULT,
|
|
1173
1483
|
paypalEnabled: false,
|
|
@@ -1198,9 +1508,10 @@ function usePayPalPaymentMethods({
|
|
|
1198
1508
|
PayPalProvider,
|
|
1199
1509
|
PayPalSmartButtons,
|
|
1200
1510
|
createPayPalStoreApi,
|
|
1201
|
-
|
|
1511
|
+
hideProcessingOverlay,
|
|
1202
1512
|
isPayPalProviderId,
|
|
1203
1513
|
markPaymentComplete,
|
|
1514
|
+
showProcessingOverlay,
|
|
1204
1515
|
usePayPalConfig,
|
|
1205
1516
|
usePayPalPaymentMethods
|
|
1206
1517
|
});
|