@easypayment/medusa-payment-paypal 0.9.18 → 0.9.20
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 +270 -114
- package/.medusa/server/src/admin/index.mjs +270 -114
- 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 +384 -126
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/onboarding-link/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/paypal/onboarding-link/route.js +4 -0
- package/.medusa/server/src/api/admin/paypal/onboarding-link/route.js.map +1 -1
- package/.medusa/server/src/modules/paypal/service.d.ts +1 -0
- 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/package.json +1 -1
- package/src/admin/routes/settings/paypal/connection/page.tsx +420 -131
- package/src/api/admin/paypal/onboarding-link/route.ts +6 -0
- package/src/modules/paypal/service.ts +7 -2
|
@@ -224,6 +224,9 @@ function AdditionalSettingsTab() {
|
|
|
224
224
|
)
|
|
225
225
|
] }) });
|
|
226
226
|
}
|
|
227
|
+
function PayPalApplePayPage() {
|
|
228
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
229
|
+
}
|
|
227
230
|
const DEFAULT_FORM = {
|
|
228
231
|
enabled: true,
|
|
229
232
|
title: "Credit or Debit Card",
|
|
@@ -316,37 +319,97 @@ const PARTNER_JS_URLS = {
|
|
|
316
319
|
live: "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js"
|
|
317
320
|
};
|
|
318
321
|
const SERVICE_URL = "/admin/paypal/onboarding-link";
|
|
319
|
-
const
|
|
322
|
+
const POPUP_NAME = "PPMiniBrowser";
|
|
323
|
+
const CACHE_PREFIX = "pp_onboard_cache";
|
|
320
324
|
const CACHE_EXPIRY = 10 * 60 * 1e3;
|
|
321
325
|
const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
|
|
322
326
|
const STATUS_ENDPOINT = "/admin/paypal/status";
|
|
323
327
|
const SAVE_CREDENTIALS_ENDPOINT = "/admin/paypal/save-credentials";
|
|
324
328
|
const DISCONNECT_ENDPOINT = "/admin/paypal/disconnect";
|
|
325
|
-
|
|
326
|
-
|
|
329
|
+
const ENVIRONMENT_ENDPOINT = "/admin/paypal/environment";
|
|
330
|
+
const cacheKeyFor = (env) => `${CACHE_PREFIX}_${env}`;
|
|
331
|
+
function readCachedUrl(env) {
|
|
332
|
+
if (typeof window === "undefined") return null;
|
|
327
333
|
try {
|
|
328
|
-
const
|
|
329
|
-
if (
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
334
|
+
const raw = localStorage.getItem(cacheKeyFor(env));
|
|
335
|
+
if (!raw) return null;
|
|
336
|
+
const data = JSON.parse(raw);
|
|
337
|
+
if (data && typeof data.url === "string" && Date.now() - (Number(data.ts) || 0) < CACHE_EXPIRY) {
|
|
338
|
+
return data.url;
|
|
339
|
+
}
|
|
340
|
+
} catch {
|
|
341
|
+
}
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
function writeCachedUrl(env, url) {
|
|
345
|
+
try {
|
|
346
|
+
localStorage.setItem(cacheKeyFor(env), JSON.stringify({ url, ts: Date.now() }));
|
|
347
|
+
} catch {
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
function clearCachedUrl(env) {
|
|
351
|
+
try {
|
|
352
|
+
if (env) {
|
|
353
|
+
localStorage.removeItem(cacheKeyFor(env));
|
|
354
|
+
} else {
|
|
355
|
+
localStorage.removeItem(cacheKeyFor("sandbox"));
|
|
356
|
+
localStorage.removeItem(cacheKeyFor("live"));
|
|
357
|
+
}
|
|
358
|
+
} catch {
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
function isPayPalOrigin(origin) {
|
|
362
|
+
try {
|
|
363
|
+
const host = new URL(origin).hostname.toLowerCase();
|
|
364
|
+
return host === "www.paypal.com" || host === "www.sandbox.paypal.com" || host.endsWith(".paypal.com") || host.endsWith(".paypalobjects.com");
|
|
365
|
+
} catch {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
function extractAuth(data) {
|
|
370
|
+
if (!data) return {};
|
|
371
|
+
if (typeof data === "object") {
|
|
372
|
+
const obj = data;
|
|
373
|
+
const authCode = obj.authCode ?? obj.auth_code ?? obj.authcode;
|
|
374
|
+
const sharedId = obj.sharedId ?? obj.shared_id ?? obj.sharedid;
|
|
375
|
+
if (authCode && sharedId) {
|
|
376
|
+
return { authCode: String(authCode), sharedId: String(sharedId) };
|
|
377
|
+
}
|
|
378
|
+
for (const key of ["data", "payload", "message", "detail", "body"]) {
|
|
379
|
+
if (obj[key] && typeof obj[key] === "object") {
|
|
380
|
+
const inner = extractAuth(obj[key]);
|
|
381
|
+
if (inner.authCode && inner.sharedId) return inner;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return {};
|
|
385
|
+
}
|
|
386
|
+
if (typeof data === "string") {
|
|
387
|
+
const s = data.trim();
|
|
388
|
+
if (!s) return {};
|
|
389
|
+
if (s.startsWith("{")) {
|
|
390
|
+
try {
|
|
391
|
+
return extractAuth(JSON.parse(s));
|
|
392
|
+
} catch {
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if (/auth_?code/i.test(s) && /shared_?id/i.test(s)) {
|
|
396
|
+
try {
|
|
397
|
+
const sp = new URLSearchParams(s.replace(/^[?#]/, ""));
|
|
398
|
+
const authCode = sp.get("authCode") || sp.get("auth_code") || void 0;
|
|
399
|
+
const sharedId = sp.get("sharedId") || sp.get("shared_id") || void 0;
|
|
400
|
+
if (authCode && sharedId) return { authCode, sharedId };
|
|
401
|
+
} catch {
|
|
333
402
|
}
|
|
334
403
|
}
|
|
335
|
-
} catch (e) {
|
|
336
|
-
console.error("Cache read error:", e);
|
|
337
404
|
}
|
|
405
|
+
return {};
|
|
338
406
|
}
|
|
339
407
|
function PayPalConnectionPage() {
|
|
340
408
|
const [env, setEnv] = react.useState("live");
|
|
341
|
-
react.
|
|
342
|
-
fetch("/admin/paypal/environment", { method: "GET", credentials: "include" }).then((r) => r.json()).then((d) => {
|
|
343
|
-
const v = (d == null ? void 0 : d.environment) === "sandbox" ? "sandbox" : "live";
|
|
344
|
-
setEnv(v);
|
|
345
|
-
}).catch(() => {
|
|
346
|
-
});
|
|
347
|
-
}, []);
|
|
409
|
+
const [envReady, setEnvReady] = react.useState(false);
|
|
348
410
|
const [connState, setConnState] = react.useState("loading");
|
|
349
411
|
const [error, setError] = react.useState(null);
|
|
412
|
+
const [popupBlocked, setPopupBlocked] = react.useState(false);
|
|
350
413
|
const [finalUrl, setFinalUrl] = react.useState("");
|
|
351
414
|
const [showManual, setShowManual] = react.useState(false);
|
|
352
415
|
const [clientId, setClientId] = react.useState("");
|
|
@@ -358,6 +421,18 @@ function PayPalConnectionPage() {
|
|
|
358
421
|
const errorLogRef = react.useRef(null);
|
|
359
422
|
const runIdRef = react.useRef(0);
|
|
360
423
|
const currentRunId = react.useRef(0);
|
|
424
|
+
const finalUrlRef = react.useRef(finalUrl);
|
|
425
|
+
finalUrlRef.current = finalUrl;
|
|
426
|
+
const connStateRef = react.useRef(connState);
|
|
427
|
+
connStateRef.current = connState;
|
|
428
|
+
const inProgressRef = react.useRef(onboardingInProgress);
|
|
429
|
+
inProgressRef.current = onboardingInProgress;
|
|
430
|
+
const envRef = react.useRef(env);
|
|
431
|
+
envRef.current = env;
|
|
432
|
+
const popupRef = react.useRef(null);
|
|
433
|
+
const popupPollRef = react.useRef(null);
|
|
434
|
+
const completedRef = react.useRef(false);
|
|
435
|
+
const partnerBoundRef = react.useRef(false);
|
|
361
436
|
const ppBtnMeasureRef = react.useRef(null);
|
|
362
437
|
const [ppBtnWidth, setPpBtnWidth] = react.useState(null);
|
|
363
438
|
const canSaveManual = react.useMemo(() => {
|
|
@@ -367,8 +442,112 @@ function PayPalConnectionPage() {
|
|
|
367
442
|
setConnState("error");
|
|
368
443
|
setError(msg);
|
|
369
444
|
}, []);
|
|
445
|
+
const stopPopupPoll = react.useCallback(() => {
|
|
446
|
+
if (popupPollRef.current) {
|
|
447
|
+
clearInterval(popupPollRef.current);
|
|
448
|
+
popupPollRef.current = null;
|
|
449
|
+
}
|
|
450
|
+
}, []);
|
|
451
|
+
const openOnboardingPopup = react.useCallback(
|
|
452
|
+
(url) => {
|
|
453
|
+
const w = 450;
|
|
454
|
+
const h = 600;
|
|
455
|
+
const baseLeft = typeof window.screenX === "number" ? window.screenX : window.screenLeft || 0;
|
|
456
|
+
const baseTop = typeof window.screenY === "number" ? window.screenY : window.screenTop || 0;
|
|
457
|
+
const outerW = window.outerWidth || document.documentElement.clientWidth || 1024;
|
|
458
|
+
const outerH = window.outerHeight || document.documentElement.clientHeight || 768;
|
|
459
|
+
const left = Math.round(baseLeft + Math.max(0, (outerW - w) / 2));
|
|
460
|
+
const top = Math.round(baseTop + Math.max(0, (outerH - h) / 2));
|
|
461
|
+
const features = `popup=yes,width=${w},height=${h},left=${left},top=${top},scrollbars=yes,resizable=yes`;
|
|
462
|
+
let popup = null;
|
|
463
|
+
try {
|
|
464
|
+
popup = window.open(url, POPUP_NAME, features);
|
|
465
|
+
} catch {
|
|
466
|
+
popup = null;
|
|
467
|
+
}
|
|
468
|
+
if (popup) {
|
|
469
|
+
popupRef.current = popup;
|
|
470
|
+
try {
|
|
471
|
+
popup.focus();
|
|
472
|
+
} catch {
|
|
473
|
+
}
|
|
474
|
+
stopPopupPoll();
|
|
475
|
+
popupPollRef.current = setInterval(() => {
|
|
476
|
+
if (!popupRef.current || popupRef.current.closed) {
|
|
477
|
+
stopPopupPoll();
|
|
478
|
+
}
|
|
479
|
+
}, 1e3);
|
|
480
|
+
}
|
|
481
|
+
return popup;
|
|
482
|
+
},
|
|
483
|
+
[stopPopupPoll]
|
|
484
|
+
);
|
|
485
|
+
const completeOnboarding = react.useCallback(
|
|
486
|
+
async (authCode, sharedId) => {
|
|
487
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
488
|
+
if (!authCode || !sharedId) return;
|
|
489
|
+
if (completedRef.current) return;
|
|
490
|
+
completedRef.current = true;
|
|
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
|
+
stopPopupPoll();
|
|
516
|
+
try {
|
|
517
|
+
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;
|
|
518
|
+
if (typeof close1 === "function") close1();
|
|
519
|
+
} catch {
|
|
520
|
+
}
|
|
521
|
+
try {
|
|
522
|
+
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;
|
|
523
|
+
if (typeof close2 === "function") close2();
|
|
524
|
+
} catch {
|
|
525
|
+
}
|
|
526
|
+
clearCachedUrl(activeEnv);
|
|
527
|
+
try {
|
|
528
|
+
const statusRes = await fetch(
|
|
529
|
+
`${STATUS_ENDPOINT}?environment=${activeEnv}`,
|
|
530
|
+
{ method: "GET", credentials: "include" }
|
|
531
|
+
);
|
|
532
|
+
const refreshedStatus = await statusRes.json().catch(() => ({}));
|
|
533
|
+
setStatusInfo(refreshedStatus || null);
|
|
534
|
+
} catch {
|
|
535
|
+
}
|
|
536
|
+
setConnState("connected");
|
|
537
|
+
setShowManual(false);
|
|
538
|
+
} catch (e) {
|
|
539
|
+
completedRef.current = false;
|
|
540
|
+
console.error(e);
|
|
541
|
+
setConnState("error");
|
|
542
|
+
setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
|
|
543
|
+
} finally {
|
|
544
|
+
setOnboardingInProgress(false);
|
|
545
|
+
}
|
|
546
|
+
},
|
|
547
|
+
[stopPopupPoll]
|
|
548
|
+
);
|
|
370
549
|
const fetchFreshLink = react.useCallback(
|
|
371
|
-
(runId) => {
|
|
550
|
+
(runId, targetEnv) => {
|
|
372
551
|
if (initLoaderRef.current) {
|
|
373
552
|
const loaderText = initLoaderRef.current.querySelector("#loader-text");
|
|
374
553
|
if (loaderText)
|
|
@@ -379,7 +558,10 @@ function PayPalConnectionPage() {
|
|
|
379
558
|
headers: { "content-type": "application/json" },
|
|
380
559
|
credentials: "include",
|
|
381
560
|
body: JSON.stringify({
|
|
382
|
-
products: ["PPCP"]
|
|
561
|
+
products: ["PPCP"],
|
|
562
|
+
// Generate the link for the explicitly selected environment so it can
|
|
563
|
+
// never depend on a racing POST /environment having landed yet.
|
|
564
|
+
environment: targetEnv
|
|
383
565
|
})
|
|
384
566
|
}).then((r) => {
|
|
385
567
|
if (!r.ok) throw new Error(`Service returned ${r.status}`);
|
|
@@ -392,10 +574,7 @@ function PayPalConnectionPage() {
|
|
|
392
574
|
return;
|
|
393
575
|
}
|
|
394
576
|
const url = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
|
|
395
|
-
|
|
396
|
-
CACHE_KEY,
|
|
397
|
-
JSON.stringify({ url, ts: Date.now() })
|
|
398
|
-
);
|
|
577
|
+
writeCachedUrl(targetEnv, url);
|
|
399
578
|
setFinalUrl(url);
|
|
400
579
|
setConnState("ready");
|
|
401
580
|
}).catch(() => {
|
|
@@ -403,8 +582,21 @@ function PayPalConnectionPage() {
|
|
|
403
582
|
showError("Unable to connect to service.");
|
|
404
583
|
});
|
|
405
584
|
},
|
|
406
|
-
[
|
|
585
|
+
[showError]
|
|
407
586
|
);
|
|
587
|
+
react.useEffect(() => {
|
|
588
|
+
let alive = true;
|
|
589
|
+
fetch(ENVIRONMENT_ENDPOINT, { method: "GET", credentials: "include" }).then((r) => r.json()).then((d) => {
|
|
590
|
+
if (!alive) return;
|
|
591
|
+
setEnv((d == null ? void 0 : d.environment) === "sandbox" ? "sandbox" : "live");
|
|
592
|
+
}).catch(() => {
|
|
593
|
+
}).finally(() => {
|
|
594
|
+
if (alive) setEnvReady(true);
|
|
595
|
+
});
|
|
596
|
+
return () => {
|
|
597
|
+
alive = false;
|
|
598
|
+
};
|
|
599
|
+
}, []);
|
|
408
600
|
react.useEffect(() => {
|
|
409
601
|
var _a, _b, _c;
|
|
410
602
|
if (connState !== "ready" || !finalUrl) return;
|
|
@@ -419,6 +611,7 @@ function PayPalConnectionPage() {
|
|
|
419
611
|
if (target == null ? void 0 : target.init) {
|
|
420
612
|
try {
|
|
421
613
|
target.init();
|
|
614
|
+
partnerBoundRef.current = true;
|
|
422
615
|
} catch (e) {
|
|
423
616
|
console.error("[paypal] partner.js init failed:", e);
|
|
424
617
|
}
|
|
@@ -427,6 +620,7 @@ function PayPalConnectionPage() {
|
|
|
427
620
|
if (typeof (signup == null ? void 0 : signup.render) === "function") {
|
|
428
621
|
try {
|
|
429
622
|
signup.render();
|
|
623
|
+
partnerBoundRef.current = true;
|
|
430
624
|
} catch (e) {
|
|
431
625
|
console.error("[paypal] partner.js render failed:", e);
|
|
432
626
|
}
|
|
@@ -441,6 +635,7 @@ function PayPalConnectionPage() {
|
|
|
441
635
|
} catch {
|
|
442
636
|
}
|
|
443
637
|
};
|
|
638
|
+
partnerBoundRef.current = false;
|
|
444
639
|
const existingScript = document.getElementById("paypal-partner-js");
|
|
445
640
|
if (existingScript) {
|
|
446
641
|
(_a = existingScript.parentNode) == null ? void 0 : _a.removeChild(existingScript);
|
|
@@ -468,12 +663,26 @@ function PayPalConnectionPage() {
|
|
|
468
663
|
};
|
|
469
664
|
}, [connState, finalUrl, env]);
|
|
470
665
|
react.useEffect(() => {
|
|
666
|
+
const onMessage = (ev) => {
|
|
667
|
+
if (!isPayPalOrigin(ev.origin)) return;
|
|
668
|
+
const { authCode, sharedId } = extractAuth(ev.data);
|
|
669
|
+
if (authCode && sharedId) {
|
|
670
|
+
completeOnboarding(authCode, sharedId);
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
window.addEventListener("message", onMessage);
|
|
674
|
+
return () => window.removeEventListener("message", onMessage);
|
|
675
|
+
}, [completeOnboarding]);
|
|
676
|
+
react.useEffect(() => {
|
|
677
|
+
if (!envReady) return;
|
|
471
678
|
currentRunId.current = ++runIdRef.current;
|
|
472
679
|
const runId = currentRunId.current;
|
|
473
680
|
let cancelled = false;
|
|
681
|
+
completedRef.current = false;
|
|
474
682
|
const run = async () => {
|
|
475
683
|
setConnState("loading");
|
|
476
684
|
setError(null);
|
|
685
|
+
setPopupBlocked(false);
|
|
477
686
|
setFinalUrl("");
|
|
478
687
|
try {
|
|
479
688
|
const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
@@ -492,84 +701,33 @@ function PayPalConnectionPage() {
|
|
|
492
701
|
} catch (e) {
|
|
493
702
|
console.error(e);
|
|
494
703
|
}
|
|
495
|
-
if (
|
|
496
|
-
|
|
704
|
+
if (cancelled || runId !== currentRunId.current) return;
|
|
705
|
+
const cached = readCachedUrl(env);
|
|
706
|
+
if (cached) {
|
|
707
|
+
setFinalUrl(cached);
|
|
497
708
|
setConnState("ready");
|
|
498
709
|
} else {
|
|
499
|
-
fetchFreshLink(runId);
|
|
710
|
+
fetchFreshLink(runId, env);
|
|
500
711
|
}
|
|
501
712
|
};
|
|
502
713
|
run();
|
|
503
714
|
return () => {
|
|
504
715
|
cancelled = true;
|
|
505
|
-
currentRunId.current = 0;
|
|
506
716
|
};
|
|
507
|
-
}, [env, fetchFreshLink]);
|
|
717
|
+
}, [env, envReady, fetchFreshLink]);
|
|
508
718
|
react.useLayoutEffect(() => {
|
|
509
|
-
window.onboardingCallback =
|
|
510
|
-
|
|
511
|
-
try {
|
|
512
|
-
window.onbeforeunload = null;
|
|
513
|
-
} catch {
|
|
514
|
-
}
|
|
515
|
-
setOnboardingInProgress(true);
|
|
516
|
-
setConnState("loading");
|
|
517
|
-
setError(null);
|
|
518
|
-
const payload = {
|
|
519
|
-
authCode,
|
|
520
|
-
sharedId,
|
|
521
|
-
env: env === "sandbox" ? "sandbox" : "live"
|
|
522
|
-
};
|
|
523
|
-
try {
|
|
524
|
-
const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
|
|
525
|
-
method: "POST",
|
|
526
|
-
headers: { "content-type": "application/json" },
|
|
527
|
-
credentials: "include",
|
|
528
|
-
body: JSON.stringify(payload)
|
|
529
|
-
});
|
|
530
|
-
if (!res.ok) {
|
|
531
|
-
const txt = await res.text().catch(() => "");
|
|
532
|
-
throw new Error(txt || `Onboarding exchange failed (${res.status})`);
|
|
533
|
-
}
|
|
534
|
-
try {
|
|
535
|
-
const close1 = (_d = (_c = (_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) == null ? void 0 : _c.MiniBrowser) == null ? void 0 : _d.closeFlow;
|
|
536
|
-
if (typeof close1 === "function") close1();
|
|
537
|
-
} catch {
|
|
538
|
-
}
|
|
539
|
-
try {
|
|
540
|
-
const close2 = ((_g = (_f = (_e = window.PAYPAL) == null ? void 0 : _e.apps) == null ? void 0 : _f.Signup) == null ? void 0 : _g.miniBrowser) && window.PAYPAL.apps.Signup.miniBrowser.closeFlow;
|
|
541
|
-
if (typeof close2 === "function") close2();
|
|
542
|
-
} catch {
|
|
543
|
-
}
|
|
544
|
-
try {
|
|
545
|
-
localStorage.removeItem(CACHE_KEY);
|
|
546
|
-
} catch {
|
|
547
|
-
}
|
|
548
|
-
try {
|
|
549
|
-
const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
550
|
-
method: "GET",
|
|
551
|
-
credentials: "include"
|
|
552
|
-
});
|
|
553
|
-
const refreshedStatus = await statusRes.json().catch(() => ({}));
|
|
554
|
-
setStatusInfo(refreshedStatus || null);
|
|
555
|
-
setConnState("connected");
|
|
556
|
-
setShowManual(false);
|
|
557
|
-
} catch {
|
|
558
|
-
setConnState("connected");
|
|
559
|
-
setShowManual(false);
|
|
560
|
-
}
|
|
561
|
-
setOnboardingInProgress(false);
|
|
562
|
-
} catch (e) {
|
|
563
|
-
console.error(e);
|
|
564
|
-
setConnState("error");
|
|
565
|
-
setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
|
|
566
|
-
setOnboardingInProgress(false);
|
|
567
|
-
}
|
|
719
|
+
window.onboardingCallback = (authCode, sharedId) => {
|
|
720
|
+
completeOnboarding(authCode, sharedId);
|
|
568
721
|
};
|
|
569
722
|
return () => {
|
|
570
723
|
window.onboardingCallback = void 0;
|
|
571
724
|
};
|
|
572
|
-
}, [
|
|
725
|
+
}, [completeOnboarding]);
|
|
726
|
+
react.useEffect(() => {
|
|
727
|
+
return () => {
|
|
728
|
+
stopPopupPoll();
|
|
729
|
+
};
|
|
730
|
+
}, [stopPopupPoll]);
|
|
573
731
|
react.useLayoutEffect(() => {
|
|
574
732
|
const el = ppBtnMeasureRef.current;
|
|
575
733
|
if (!el) return;
|
|
@@ -591,9 +749,16 @@ function PayPalConnectionPage() {
|
|
|
591
749
|
};
|
|
592
750
|
}, [connState, env, finalUrl]);
|
|
593
751
|
const handleConnectClick = (e) => {
|
|
594
|
-
|
|
595
|
-
|
|
752
|
+
e.preventDefault();
|
|
753
|
+
if (connStateRef.current !== "ready" || !finalUrlRef.current || inProgressRef.current) {
|
|
754
|
+
return;
|
|
596
755
|
}
|
|
756
|
+
if (partnerBoundRef.current) {
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
completedRef.current = false;
|
|
760
|
+
const popup = openOnboardingPopup(finalUrlRef.current);
|
|
761
|
+
setPopupBlocked(!popup);
|
|
597
762
|
};
|
|
598
763
|
const handleSaveManual = async () => {
|
|
599
764
|
if (!canSaveManual || onboardingInProgress) return;
|
|
@@ -623,10 +788,7 @@ function PayPalConnectionPage() {
|
|
|
623
788
|
setConnState("connected");
|
|
624
789
|
setStatusInfo(refreshedStatus || null);
|
|
625
790
|
setShowManual(false);
|
|
626
|
-
|
|
627
|
-
localStorage.removeItem(CACHE_KEY);
|
|
628
|
-
} catch {
|
|
629
|
-
}
|
|
791
|
+
clearCachedUrl(env);
|
|
630
792
|
} catch (e) {
|
|
631
793
|
console.error(e);
|
|
632
794
|
setConnState("error");
|
|
@@ -655,13 +817,11 @@ function PayPalConnectionPage() {
|
|
|
655
817
|
const t = await res.text().catch(() => "");
|
|
656
818
|
throw new Error(t || `Disconnect failed (${res.status})`);
|
|
657
819
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
} catch {
|
|
661
|
-
}
|
|
820
|
+
clearCachedUrl(env);
|
|
821
|
+
completedRef.current = false;
|
|
662
822
|
currentRunId.current = ++runIdRef.current;
|
|
663
823
|
const runId = currentRunId.current;
|
|
664
|
-
fetchFreshLink(runId);
|
|
824
|
+
fetchFreshLink(runId, env);
|
|
665
825
|
} catch (e) {
|
|
666
826
|
console.error(e);
|
|
667
827
|
setConnState("error");
|
|
@@ -672,10 +832,12 @@ function PayPalConnectionPage() {
|
|
|
672
832
|
};
|
|
673
833
|
const handleEnvChange = async (e) => {
|
|
674
834
|
const next = e.target.value;
|
|
835
|
+
completedRef.current = false;
|
|
836
|
+
setPopupBlocked(false);
|
|
837
|
+
clearCachedUrl();
|
|
675
838
|
setEnv(next);
|
|
676
|
-
cachedUrl = null;
|
|
677
839
|
try {
|
|
678
|
-
await fetch(
|
|
840
|
+
await fetch(ENVIRONMENT_ENDPOINT, {
|
|
679
841
|
method: "POST",
|
|
680
842
|
headers: { "content-type": "application/json" },
|
|
681
843
|
credentials: "include",
|
|
@@ -683,10 +845,6 @@ function PayPalConnectionPage() {
|
|
|
683
845
|
});
|
|
684
846
|
} catch {
|
|
685
847
|
}
|
|
686
|
-
try {
|
|
687
|
-
localStorage.removeItem(CACHE_KEY);
|
|
688
|
-
} catch {
|
|
689
|
-
}
|
|
690
848
|
};
|
|
691
849
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6", children: [
|
|
692
850
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
@@ -750,7 +908,7 @@ function PayPalConnectionPage() {
|
|
|
750
908
|
ppBtnMeasureRef.current = node;
|
|
751
909
|
},
|
|
752
910
|
id: "paypal-button",
|
|
753
|
-
target:
|
|
911
|
+
target: POPUP_NAME,
|
|
754
912
|
"data-paypal-button": "true",
|
|
755
913
|
href: finalUrl || "#",
|
|
756
914
|
"data-paypal-onboard-complete": "onboardingCallback",
|
|
@@ -764,6 +922,7 @@ function PayPalConnectionPage() {
|
|
|
764
922
|
children: "Connect to PayPal"
|
|
765
923
|
}
|
|
766
924
|
),
|
|
925
|
+
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." }),
|
|
767
926
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
768
927
|
"div",
|
|
769
928
|
{
|
|
@@ -919,9 +1078,6 @@ function PayPalConnectionPage() {
|
|
|
919
1078
|
` })
|
|
920
1079
|
] });
|
|
921
1080
|
}
|
|
922
|
-
function PayPalApplePayPage() {
|
|
923
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
924
|
-
}
|
|
925
1081
|
function PayPalGooglePayPage() {
|
|
926
1082
|
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
927
1083
|
}
|
|
@@ -1146,6 +1302,10 @@ const routeModule = {
|
|
|
1146
1302
|
Component: AdditionalSettingsTab,
|
|
1147
1303
|
path: "/settings/paypal/additional-settings"
|
|
1148
1304
|
},
|
|
1305
|
+
{
|
|
1306
|
+
Component: PayPalApplePayPage,
|
|
1307
|
+
path: "/settings/paypal/apple-pay"
|
|
1308
|
+
},
|
|
1149
1309
|
{
|
|
1150
1310
|
Component: AdvancedCardPaymentsTab,
|
|
1151
1311
|
path: "/settings/paypal/advanced-card-payments"
|
|
@@ -1154,10 +1314,6 @@ const routeModule = {
|
|
|
1154
1314
|
Component: PayPalConnectionPage,
|
|
1155
1315
|
path: "/settings/paypal/connection"
|
|
1156
1316
|
},
|
|
1157
|
-
{
|
|
1158
|
-
Component: PayPalApplePayPage,
|
|
1159
|
-
path: "/settings/paypal/apple-pay"
|
|
1160
|
-
},
|
|
1161
1317
|
{
|
|
1162
1318
|
Component: PayPalGooglePayPage,
|
|
1163
1319
|
path: "/settings/paypal/google-pay"
|