@easypayment/medusa-payment-paypal 0.9.22 → 0.9.25
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/.medusa/server/src/admin/index.js +264 -80
- package/.medusa/server/src/admin/index.mjs +264 -80
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.d.ts.map +1 -1
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js +340 -146
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js.map +1 -1
- package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.js +6 -8
- package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/environment/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/paypal/environment/route.js +11 -3
- package/.medusa/server/src/api/admin/paypal/environment/route.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/onboard-complete/route.d.ts +7 -0
- package/.medusa/server/src/api/admin/paypal/onboard-complete/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/paypal/onboard-complete/route.js +7 -0
- package/.medusa/server/src/api/admin/paypal/onboard-complete/route.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/onboarding-status/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/paypal/onboarding-status/route.js +4 -1
- package/.medusa/server/src/api/admin/paypal/onboarding-status/route.js.map +1 -1
- package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -1
- package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js +6 -8
- package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js.map +1 -1
- package/.medusa/server/src/api/store/paypal/capture-order/route.d.ts.map +1 -1
- package/.medusa/server/src/api/store/paypal/capture-order/route.js +11 -0
- package/.medusa/server/src/api/store/paypal/capture-order/route.js.map +1 -1
- package/.medusa/server/src/api/store/paypal/onboard-return/route.d.ts +23 -0
- package/.medusa/server/src/api/store/paypal/onboard-return/route.d.ts.map +1 -0
- package/.medusa/server/src/api/store/paypal/onboard-return/route.js +63 -0
- package/.medusa/server/src/api/store/paypal/onboard-return/route.js.map +1 -0
- package/.medusa/server/src/api/store/paypal-complete/route.d.ts.map +1 -1
- package/.medusa/server/src/api/store/paypal-complete/route.js +2 -4
- package/.medusa/server/src/api/store/paypal-complete/route.js.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/card-service.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/card-service.js +55 -34
- package/.medusa/server/src/modules/paypal/payment-provider/card-service.js.map +1 -1
- package/.medusa/server/src/modules/paypal/service.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/service.js +5 -1
- package/.medusa/server/src/modules/paypal/service.js.map +1 -1
- package/.medusa/server/src/modules/paypal/utils/core-workflow.d.ts +32 -0
- package/.medusa/server/src/modules/paypal/utils/core-workflow.d.ts.map +1 -0
- package/.medusa/server/src/modules/paypal/utils/core-workflow.js +40 -0
- package/.medusa/server/src/modules/paypal/utils/core-workflow.js.map +1 -0
- package/package.json +1 -1
- package/src/admin/routes/settings/paypal/connection/page.tsx +364 -160
- package/src/api/admin/payment-collections/[id]/payment-sessions/route.ts +6 -8
- package/src/api/admin/paypal/environment/route.ts +10 -3
- package/src/api/admin/paypal/onboard-complete/route.ts +7 -0
- package/src/api/admin/paypal/onboarding-status/route.ts +4 -1
- package/src/api/store/payment-collections/[id]/payment-sessions/route.ts +6 -8
- package/src/api/store/paypal/capture-order/route.ts +15 -0
- package/src/api/store/paypal/onboard-return/route.ts +63 -0
- package/src/api/store/paypal-complete/route.ts +6 -4
- package/src/modules/paypal/payment-provider/card-service.ts +72 -38
- package/src/modules/paypal/service.ts +5 -1
- package/src/modules/paypal/utils/core-workflow.ts +46 -0
|
@@ -363,12 +363,62 @@ function clearCachedUrl(env) {
|
|
|
363
363
|
} catch {
|
|
364
364
|
}
|
|
365
365
|
}
|
|
366
|
+
function isPayPalOrigin(origin) {
|
|
367
|
+
try {
|
|
368
|
+
const host = new URL(origin).hostname.toLowerCase();
|
|
369
|
+
return host === "www.paypal.com" || host === "www.sandbox.paypal.com" || host.endsWith(".paypal.com") || host.endsWith(".paypalobjects.com");
|
|
370
|
+
} catch {
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
function extractAuth(data) {
|
|
375
|
+
if (!data) return {};
|
|
376
|
+
if (typeof data === "object") {
|
|
377
|
+
const obj = data;
|
|
378
|
+
const authCode = obj.authCode ?? obj.auth_code ?? obj.authcode ?? obj.code;
|
|
379
|
+
const sharedId = obj.sharedId ?? obj.shared_id ?? obj.sharedid;
|
|
380
|
+
if (authCode && sharedId) {
|
|
381
|
+
return { authCode: String(authCode), sharedId: String(sharedId) };
|
|
382
|
+
}
|
|
383
|
+
for (const key of ["data", "payload", "message", "detail", "body", "params"]) {
|
|
384
|
+
if (obj[key] && typeof obj[key] === "object") {
|
|
385
|
+
const inner = extractAuth(obj[key]);
|
|
386
|
+
if (inner.authCode && inner.sharedId) return inner;
|
|
387
|
+
}
|
|
388
|
+
if (typeof obj[key] === "string") {
|
|
389
|
+
const inner = extractAuth(obj[key]);
|
|
390
|
+
if (inner.authCode && inner.sharedId) return inner;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
return {};
|
|
394
|
+
}
|
|
395
|
+
if (typeof data === "string") {
|
|
396
|
+
const s = data.trim();
|
|
397
|
+
if (!s) return {};
|
|
398
|
+
if (s.startsWith("{") || s.startsWith("[")) {
|
|
399
|
+
try {
|
|
400
|
+
return extractAuth(JSON.parse(s));
|
|
401
|
+
} catch {
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (/auth_?code/i.test(s) && /shared_?id/i.test(s)) {
|
|
405
|
+
try {
|
|
406
|
+
const sp = new URLSearchParams(s.replace(/^[?#]/, ""));
|
|
407
|
+
const authCode = sp.get("authCode") || sp.get("auth_code") || void 0;
|
|
408
|
+
const sharedId = sp.get("sharedId") || sp.get("shared_id") || void 0;
|
|
409
|
+
if (authCode && sharedId) return { authCode, sharedId };
|
|
410
|
+
} catch {
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return {};
|
|
415
|
+
}
|
|
366
416
|
function PayPalConnectionPage() {
|
|
367
417
|
const [env, setEnv] = react.useState("live");
|
|
368
418
|
const [envReady, setEnvReady] = react.useState(false);
|
|
369
419
|
const [connState, setConnState] = react.useState("loading");
|
|
370
|
-
const [partnerReady, setPartnerReady] = react.useState(false);
|
|
371
420
|
const [error, setError] = react.useState(null);
|
|
421
|
+
const [popupBlocked, setPopupBlocked] = react.useState(false);
|
|
372
422
|
const [finalUrl, setFinalUrl] = react.useState("");
|
|
373
423
|
const [showManual, setShowManual] = react.useState(false);
|
|
374
424
|
const [clientId, setClientId] = react.useState("");
|
|
@@ -376,11 +426,20 @@ function PayPalConnectionPage() {
|
|
|
376
426
|
const [statusInfo, setStatusInfo] = react.useState(null);
|
|
377
427
|
const [onboardingInProgress, setOnboardingInProgress] = react.useState(false);
|
|
378
428
|
const initLoaderRef = react.useRef(null);
|
|
429
|
+
const paypalButtonRef = react.useRef(null);
|
|
379
430
|
const errorLogRef = react.useRef(null);
|
|
380
431
|
const runIdRef = react.useRef(0);
|
|
381
432
|
const currentRunId = react.useRef(0);
|
|
382
433
|
const envRef = react.useRef(env);
|
|
383
434
|
envRef.current = env;
|
|
435
|
+
const finalUrlRef = react.useRef(finalUrl);
|
|
436
|
+
finalUrlRef.current = finalUrl;
|
|
437
|
+
const connStateRef = react.useRef(connState);
|
|
438
|
+
connStateRef.current = connState;
|
|
439
|
+
const inProgressRef = react.useRef(onboardingInProgress);
|
|
440
|
+
inProgressRef.current = onboardingInProgress;
|
|
441
|
+
const popupRef = react.useRef(null);
|
|
442
|
+
const pollRef = react.useRef(null);
|
|
384
443
|
const completedRef = react.useRef(false);
|
|
385
444
|
const ppBtnMeasureRef = react.useRef(null);
|
|
386
445
|
const [ppBtnWidth, setPpBtnWidth] = react.useState(null);
|
|
@@ -391,13 +450,139 @@ function PayPalConnectionPage() {
|
|
|
391
450
|
setConnState("error");
|
|
392
451
|
setError(msg);
|
|
393
452
|
}, []);
|
|
453
|
+
const stopPoll = react.useCallback(() => {
|
|
454
|
+
if (pollRef.current) {
|
|
455
|
+
clearInterval(pollRef.current);
|
|
456
|
+
pollRef.current = null;
|
|
457
|
+
}
|
|
458
|
+
}, []);
|
|
459
|
+
const openOnboardingPopup = react.useCallback((url) => {
|
|
460
|
+
const w = 450;
|
|
461
|
+
const h = 600;
|
|
462
|
+
const baseLeft = typeof window.screenX === "number" ? window.screenX : window.screenLeft || 0;
|
|
463
|
+
const baseTop = typeof window.screenY === "number" ? window.screenY : window.screenTop || 0;
|
|
464
|
+
const outerW = window.outerWidth || document.documentElement.clientWidth || 1024;
|
|
465
|
+
const outerH = window.outerHeight || document.documentElement.clientHeight || 768;
|
|
466
|
+
const left = Math.round(baseLeft + Math.max(0, (outerW - w) / 2));
|
|
467
|
+
const top = Math.round(baseTop + Math.max(0, (outerH - h) / 2));
|
|
468
|
+
const features = `popup=yes,width=${w},height=${h},left=${left},top=${top},scrollbars=yes,resizable=yes`;
|
|
469
|
+
let popup = null;
|
|
470
|
+
try {
|
|
471
|
+
popup = window.open(url, POPUP_NAME, features);
|
|
472
|
+
} catch {
|
|
473
|
+
popup = null;
|
|
474
|
+
}
|
|
475
|
+
if (popup) {
|
|
476
|
+
popupRef.current = popup;
|
|
477
|
+
try {
|
|
478
|
+
popup.focus();
|
|
479
|
+
} catch {
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return popup;
|
|
483
|
+
}, []);
|
|
484
|
+
const completeOnboarding = react.useCallback(
|
|
485
|
+
async (authCode, sharedId) => {
|
|
486
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
487
|
+
if (!authCode || !sharedId) return;
|
|
488
|
+
if (completedRef.current) return;
|
|
489
|
+
completedRef.current = true;
|
|
490
|
+
stopPoll();
|
|
491
|
+
try {
|
|
492
|
+
window.onbeforeunload = null;
|
|
493
|
+
} catch {
|
|
494
|
+
}
|
|
495
|
+
const activeEnv = envRef.current === "sandbox" ? "sandbox" : "live";
|
|
496
|
+
setOnboardingInProgress(true);
|
|
497
|
+
setConnState("loading");
|
|
498
|
+
setError(null);
|
|
499
|
+
setPopupBlocked(false);
|
|
500
|
+
try {
|
|
501
|
+
const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
|
|
502
|
+
method: "POST",
|
|
503
|
+
headers: { "content-type": "application/json" },
|
|
504
|
+
credentials: "include",
|
|
505
|
+
body: JSON.stringify({ authCode, sharedId, env: activeEnv })
|
|
506
|
+
});
|
|
507
|
+
if (!res.ok) {
|
|
508
|
+
const txt = await res.text().catch(() => "");
|
|
509
|
+
throw new Error(txt || `Onboarding exchange failed (${res.status})`);
|
|
510
|
+
}
|
|
511
|
+
try {
|
|
512
|
+
(_a = popupRef.current) == null ? void 0 : _a.close();
|
|
513
|
+
} catch {
|
|
514
|
+
}
|
|
515
|
+
try {
|
|
516
|
+
const close1 = (_e = (_d = (_c = (_b = window.PAYPAL) == null ? void 0 : _b.apps) == null ? void 0 : _c.Signup) == null ? void 0 : _d.MiniBrowser) == null ? void 0 : _e.closeFlow;
|
|
517
|
+
if (typeof close1 === "function") close1();
|
|
518
|
+
} catch {
|
|
519
|
+
}
|
|
520
|
+
try {
|
|
521
|
+
const close2 = ((_h = (_g = (_f = window.PAYPAL) == null ? void 0 : _f.apps) == null ? void 0 : _g.Signup) == null ? void 0 : _h.miniBrowser) && window.PAYPAL.apps.Signup.miniBrowser.closeFlow;
|
|
522
|
+
if (typeof close2 === "function") close2();
|
|
523
|
+
} catch {
|
|
524
|
+
}
|
|
525
|
+
clearCachedUrl(activeEnv);
|
|
526
|
+
try {
|
|
527
|
+
const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${activeEnv}`, {
|
|
528
|
+
method: "GET",
|
|
529
|
+
credentials: "include"
|
|
530
|
+
});
|
|
531
|
+
const refreshedStatus = await statusRes.json().catch(() => ({}));
|
|
532
|
+
setStatusInfo(refreshedStatus || null);
|
|
533
|
+
} catch {
|
|
534
|
+
}
|
|
535
|
+
setConnState("connected");
|
|
536
|
+
setShowManual(false);
|
|
537
|
+
} catch (e) {
|
|
538
|
+
completedRef.current = false;
|
|
539
|
+
console.error(e);
|
|
540
|
+
setConnState("error");
|
|
541
|
+
setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
|
|
542
|
+
} finally {
|
|
543
|
+
setOnboardingInProgress(false);
|
|
544
|
+
}
|
|
545
|
+
},
|
|
546
|
+
[stopPoll]
|
|
547
|
+
);
|
|
548
|
+
const startStatusPoll = react.useCallback(() => {
|
|
549
|
+
stopPoll();
|
|
550
|
+
let ticks = 0;
|
|
551
|
+
pollRef.current = setInterval(async () => {
|
|
552
|
+
var _a;
|
|
553
|
+
ticks += 1;
|
|
554
|
+
if (completedRef.current || ticks > 150) {
|
|
555
|
+
stopPoll();
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
try {
|
|
559
|
+
const r = await fetch(`${STATUS_ENDPOINT}?environment=${envRef.current}`, {
|
|
560
|
+
method: "GET",
|
|
561
|
+
credentials: "include"
|
|
562
|
+
});
|
|
563
|
+
const st = await r.json().catch(() => ({}));
|
|
564
|
+
if ((st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true) {
|
|
565
|
+
completedRef.current = true;
|
|
566
|
+
stopPoll();
|
|
567
|
+
try {
|
|
568
|
+
(_a = popupRef.current) == null ? void 0 : _a.close();
|
|
569
|
+
} catch {
|
|
570
|
+
}
|
|
571
|
+
clearCachedUrl(envRef.current);
|
|
572
|
+
setStatusInfo(st);
|
|
573
|
+
setConnState("connected");
|
|
574
|
+
setShowManual(false);
|
|
575
|
+
setOnboardingInProgress(false);
|
|
576
|
+
}
|
|
577
|
+
} catch {
|
|
578
|
+
}
|
|
579
|
+
}, 2e3);
|
|
580
|
+
}, [stopPoll]);
|
|
394
581
|
const generateLinkAndReload = react.useCallback(
|
|
395
582
|
async (targetEnv, runId) => {
|
|
396
583
|
if (initLoaderRef.current) {
|
|
397
584
|
const loaderText = initLoaderRef.current.querySelector("#loader-text");
|
|
398
|
-
if (loaderText)
|
|
399
|
-
loaderText.textContent = "Generating onboarding session...";
|
|
400
|
-
}
|
|
585
|
+
if (loaderText) loaderText.textContent = "Generating onboarding session...";
|
|
401
586
|
}
|
|
402
587
|
try {
|
|
403
588
|
const res = await fetch(SERVICE_URL, {
|
|
@@ -451,6 +636,7 @@ function PayPalConnectionPage() {
|
|
|
451
636
|
const run = async () => {
|
|
452
637
|
setConnState("loading");
|
|
453
638
|
setError(null);
|
|
639
|
+
setPopupBlocked(false);
|
|
454
640
|
setFinalUrl("");
|
|
455
641
|
try {
|
|
456
642
|
const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
@@ -489,13 +675,6 @@ function PayPalConnectionPage() {
|
|
|
489
675
|
const scriptUrl = PARTNER_JS_URLS[env];
|
|
490
676
|
let cancelled = false;
|
|
491
677
|
let pollTimer;
|
|
492
|
-
setPartnerReady(false);
|
|
493
|
-
const readyFallback = setTimeout(() => {
|
|
494
|
-
if (!cancelled) setPartnerReady(true);
|
|
495
|
-
}, 6e3);
|
|
496
|
-
const markReady = () => {
|
|
497
|
-
if (!cancelled) setPartnerReady(true);
|
|
498
|
-
};
|
|
499
678
|
const initPartner = (attempt = 0) => {
|
|
500
679
|
var _a2, _b2;
|
|
501
680
|
if (cancelled) return;
|
|
@@ -507,7 +686,6 @@ function PayPalConnectionPage() {
|
|
|
507
686
|
} catch (e) {
|
|
508
687
|
console.error("[paypal] partner.js init failed:", e);
|
|
509
688
|
}
|
|
510
|
-
markReady();
|
|
511
689
|
return;
|
|
512
690
|
}
|
|
513
691
|
if (typeof (signup == null ? void 0 : signup.render) === "function") {
|
|
@@ -516,7 +694,6 @@ function PayPalConnectionPage() {
|
|
|
516
694
|
} catch (e) {
|
|
517
695
|
console.error("[paypal] partner.js render failed:", e);
|
|
518
696
|
}
|
|
519
|
-
markReady();
|
|
520
697
|
return;
|
|
521
698
|
}
|
|
522
699
|
if (attempt < 40) {
|
|
@@ -527,7 +704,6 @@ function PayPalConnectionPage() {
|
|
|
527
704
|
document.dispatchEvent(new Event("DOMContentLoaded"));
|
|
528
705
|
} catch {
|
|
529
706
|
}
|
|
530
|
-
markReady();
|
|
531
707
|
};
|
|
532
708
|
const existingScript = document.getElementById("paypal-partner-js");
|
|
533
709
|
if (existingScript) {
|
|
@@ -544,74 +720,54 @@ function PayPalConnectionPage() {
|
|
|
544
720
|
ppScript.src = scriptUrl;
|
|
545
721
|
ppScript.async = true;
|
|
546
722
|
ppScript.onload = () => initPartner();
|
|
547
|
-
ppScript.onerror = () => markReady();
|
|
548
723
|
document.body.appendChild(ppScript);
|
|
549
724
|
return () => {
|
|
550
725
|
cancelled = true;
|
|
551
|
-
clearTimeout(
|
|
552
|
-
if (
|
|
553
|
-
clearTimeout(pollTimer);
|
|
554
|
-
}
|
|
555
|
-
if (ppScript.parentNode) {
|
|
556
|
-
ppScript.parentNode.removeChild(ppScript);
|
|
557
|
-
}
|
|
726
|
+
if (pollTimer) clearTimeout(pollTimer);
|
|
727
|
+
if (ppScript.parentNode) ppScript.parentNode.removeChild(ppScript);
|
|
558
728
|
};
|
|
559
729
|
}, [connState, finalUrl, env]);
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
completedRef.current = true;
|
|
565
|
-
try {
|
|
566
|
-
window.onbeforeunload = null;
|
|
567
|
-
} catch {
|
|
568
|
-
}
|
|
569
|
-
const activeEnv = envRef.current === "sandbox" ? "sandbox" : "live";
|
|
570
|
-
setOnboardingInProgress(true);
|
|
571
|
-
setConnState("loading");
|
|
572
|
-
setError(null);
|
|
573
|
-
try {
|
|
574
|
-
const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
|
|
575
|
-
method: "POST",
|
|
576
|
-
headers: { "content-type": "application/json" },
|
|
577
|
-
credentials: "include",
|
|
578
|
-
body: JSON.stringify({ authCode, sharedId, env: activeEnv })
|
|
579
|
-
});
|
|
580
|
-
if (!res.ok) {
|
|
581
|
-
const txt = await res.text().catch(() => "");
|
|
582
|
-
throw new Error(txt || `Onboarding exchange failed (${res.status})`);
|
|
583
|
-
}
|
|
730
|
+
react.useEffect(() => {
|
|
731
|
+
const onMessage = (ev) => {
|
|
732
|
+
var _a;
|
|
733
|
+
let serialized = "";
|
|
584
734
|
try {
|
|
585
|
-
|
|
586
|
-
if (typeof close1 === "function") close1();
|
|
735
|
+
serialized = typeof ev.data === "string" ? ev.data : JSON.stringify(ev.data);
|
|
587
736
|
} catch {
|
|
737
|
+
serialized = String(ev.data);
|
|
588
738
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
739
|
+
const looksRelevant = isPayPalOrigin(ev.origin) || /auth_?code|shared_?id|onboard|merchantId/i.test(serialized || "");
|
|
740
|
+
if (looksRelevant) {
|
|
741
|
+
console.info(
|
|
742
|
+
"[PayPal onboarding] message from",
|
|
743
|
+
ev.origin,
|
|
744
|
+
"·",
|
|
745
|
+
(serialized || "").slice(0, 500)
|
|
746
|
+
);
|
|
593
747
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
}
|
|
600
|
-
const
|
|
601
|
-
|
|
602
|
-
|
|
748
|
+
const d = ev.data;
|
|
749
|
+
if (d && typeof d === "object" && d.source === "paypal-onboarding-return") {
|
|
750
|
+
try {
|
|
751
|
+
(_a = popupRef.current) == null ? void 0 : _a.close();
|
|
752
|
+
} catch {
|
|
753
|
+
}
|
|
754
|
+
const fromReturn = extractAuth(d.params);
|
|
755
|
+
if (fromReturn.authCode && fromReturn.sharedId) {
|
|
756
|
+
completeOnboarding(fromReturn.authCode, fromReturn.sharedId);
|
|
757
|
+
} else if (!completedRef.current) {
|
|
758
|
+
startStatusPoll();
|
|
759
|
+
}
|
|
760
|
+
return;
|
|
603
761
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
}
|
|
614
|
-
}, []);
|
|
762
|
+
if (!isPayPalOrigin(ev.origin)) return;
|
|
763
|
+
const { authCode, sharedId } = extractAuth(ev.data);
|
|
764
|
+
if (authCode && sharedId) {
|
|
765
|
+
completeOnboarding(authCode, sharedId);
|
|
766
|
+
}
|
|
767
|
+
};
|
|
768
|
+
window.addEventListener("message", onMessage);
|
|
769
|
+
return () => window.removeEventListener("message", onMessage);
|
|
770
|
+
}, [completeOnboarding, startStatusPoll]);
|
|
615
771
|
react.useLayoutEffect(() => {
|
|
616
772
|
window.onboardingCallback = (authCode, sharedId) => {
|
|
617
773
|
completeOnboarding(authCode, sharedId);
|
|
@@ -620,6 +776,31 @@ function PayPalConnectionPage() {
|
|
|
620
776
|
window.onboardingCallback = void 0;
|
|
621
777
|
};
|
|
622
778
|
}, [completeOnboarding]);
|
|
779
|
+
react.useEffect(() => {
|
|
780
|
+
const onCaptureClick = (e) => {
|
|
781
|
+
const btn = paypalButtonRef.current;
|
|
782
|
+
if (!btn) return;
|
|
783
|
+
const target = e.target;
|
|
784
|
+
if (!target || !btn.contains(target)) return;
|
|
785
|
+
e.preventDefault();
|
|
786
|
+
if (connStateRef.current !== "ready" || !finalUrlRef.current || inProgressRef.current) {
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
completedRef.current = false;
|
|
790
|
+
const popup = openOnboardingPopup(finalUrlRef.current);
|
|
791
|
+
if (!popup) {
|
|
792
|
+
setPopupBlocked(true);
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
setPopupBlocked(false);
|
|
796
|
+
startStatusPoll();
|
|
797
|
+
};
|
|
798
|
+
document.addEventListener("click", onCaptureClick, true);
|
|
799
|
+
return () => document.removeEventListener("click", onCaptureClick, true);
|
|
800
|
+
}, [openOnboardingPopup, startStatusPoll]);
|
|
801
|
+
react.useEffect(() => {
|
|
802
|
+
return () => stopPoll();
|
|
803
|
+
}, [stopPoll]);
|
|
623
804
|
react.useLayoutEffect(() => {
|
|
624
805
|
const el = ppBtnMeasureRef.current;
|
|
625
806
|
if (!el) return;
|
|
@@ -640,6 +821,9 @@ function PayPalConnectionPage() {
|
|
|
640
821
|
else window.removeEventListener("resize", update);
|
|
641
822
|
};
|
|
642
823
|
}, [connState, env, finalUrl]);
|
|
824
|
+
const handleConnectClick = (e) => {
|
|
825
|
+
e.preventDefault();
|
|
826
|
+
};
|
|
643
827
|
const handleSaveManual = async () => {
|
|
644
828
|
if (!canSaveManual || onboardingInProgress) return;
|
|
645
829
|
setOnboardingInProgress(true);
|
|
@@ -714,6 +898,7 @@ function PayPalConnectionPage() {
|
|
|
714
898
|
if (next === env || onboardingInProgress) return;
|
|
715
899
|
completedRef.current = false;
|
|
716
900
|
clearCachedUrl();
|
|
901
|
+
setPopupBlocked(false);
|
|
717
902
|
setConnState("loading");
|
|
718
903
|
try {
|
|
719
904
|
await fetch(ENVIRONMENT_ENDPOINT, {
|
|
@@ -784,6 +969,7 @@ function PayPalConnectionPage() {
|
|
|
784
969
|
"a",
|
|
785
970
|
{
|
|
786
971
|
ref: (node) => {
|
|
972
|
+
paypalButtonRef.current = node;
|
|
787
973
|
ppBtnMeasureRef.current = node;
|
|
788
974
|
},
|
|
789
975
|
id: "paypal-button",
|
|
@@ -791,19 +977,17 @@ function PayPalConnectionPage() {
|
|
|
791
977
|
"data-paypal-button": "true",
|
|
792
978
|
href: finalUrl || "#",
|
|
793
979
|
"data-paypal-onboard-complete": "onboardingCallback",
|
|
794
|
-
|
|
980
|
+
onClick: handleConnectClick,
|
|
795
981
|
className: "transition-fg relative inline-flex w-fit items-center justify-center overflow-hidden rounded-md outline-none no-underline shadow-buttons-neutral text-ui-fg-base bg-ui-button-neutral after:transition-fg after:absolute after:inset-0 after:content-[''] after:button-neutral-gradient hover:bg-ui-button-neutral-hover hover:after:button-neutral-hover-gradient active:bg-ui-button-neutral-pressed active:after:button-neutral-pressed-gradient focus-visible:shadow-buttons-neutral-focus disabled:bg-ui-bg-disabled disabled:border-ui-border-base disabled:text-ui-fg-disabled disabled:shadow-buttons-neutral disabled:after:hidden txt-compact-small-plus px-3 py-1.5",
|
|
796
982
|
style: {
|
|
797
|
-
cursor: onboardingInProgress
|
|
798
|
-
opacity: onboardingInProgress
|
|
799
|
-
|
|
800
|
-
// but un-clickable until partner.js has taken over the
|
|
801
|
-
// click — so it can never open a tab via the native href.
|
|
802
|
-
pointerEvents: onboardingInProgress || !partnerReady ? "none" : "auto"
|
|
983
|
+
cursor: onboardingInProgress ? "not-allowed" : "pointer",
|
|
984
|
+
opacity: onboardingInProgress ? 0.6 : 1,
|
|
985
|
+
pointerEvents: onboardingInProgress ? "none" : "auto"
|
|
803
986
|
},
|
|
804
|
-
children:
|
|
987
|
+
children: "Connect to PayPal"
|
|
805
988
|
}
|
|
806
989
|
),
|
|
990
|
+
popupBlocked && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 text-left text-xs bg-amber-50 text-amber-700 p-3 border border-amber-200 rounded", children: "Your browser blocked the PayPal popup. Please allow popups for this site, then click “Connect to PayPal” again." }),
|
|
807
991
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
808
992
|
"div",
|
|
809
993
|
{
|