@easypayment/medusa-payment-paypal 0.9.25 → 0.9.27

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.
Files changed (30) hide show
  1. package/.medusa/server/src/admin/index.js +183 -297
  2. package/.medusa/server/src/admin/index.mjs +183 -297
  3. package/.medusa/server/src/admin/routes/settings/paypal/connection/page.d.ts +0 -1
  4. package/.medusa/server/src/admin/routes/settings/paypal/connection/page.d.ts.map +1 -1
  5. package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js +204 -368
  6. package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js.map +1 -1
  7. package/.medusa/server/src/api/store/paypal/onboard-return/route.d.ts +11 -9
  8. package/.medusa/server/src/api/store/paypal/onboard-return/route.d.ts.map +1 -1
  9. package/.medusa/server/src/api/store/paypal/onboard-return/route.js +28 -9
  10. package/.medusa/server/src/api/store/paypal/onboard-return/route.js.map +1 -1
  11. package/.medusa/server/src/modules/paypal/payment-provider/card-service.d.ts.map +1 -1
  12. package/.medusa/server/src/modules/paypal/payment-provider/card-service.js +67 -55
  13. package/.medusa/server/src/modules/paypal/payment-provider/card-service.js.map +1 -1
  14. package/.medusa/server/src/modules/paypal/payment-provider/service.d.ts.map +1 -1
  15. package/.medusa/server/src/modules/paypal/payment-provider/service.js +15 -5
  16. package/.medusa/server/src/modules/paypal/payment-provider/service.js.map +1 -1
  17. package/.medusa/server/src/modules/paypal/service.d.ts.map +1 -1
  18. package/.medusa/server/src/modules/paypal/service.js +32 -6
  19. package/.medusa/server/src/modules/paypal/service.js.map +1 -1
  20. package/.medusa/server/src/modules/paypal/utils/amounts.d.ts +10 -0
  21. package/.medusa/server/src/modules/paypal/utils/amounts.d.ts.map +1 -1
  22. package/.medusa/server/src/modules/paypal/utils/amounts.js +36 -0
  23. package/.medusa/server/src/modules/paypal/utils/amounts.js.map +1 -1
  24. package/package.json +1 -1
  25. package/src/admin/routes/settings/paypal/connection/page.tsx +230 -389
  26. package/src/api/store/paypal/onboard-return/route.ts +34 -9
  27. package/src/modules/paypal/payment-provider/card-service.ts +85 -65
  28. package/src/modules/paypal/payment-provider/service.ts +22 -7
  29. package/src/modules/paypal/service.ts +34 -7
  30. package/src/modules/paypal/utils/amounts.ts +36 -0
@@ -308,21 +308,11 @@ function AdvancedCardPaymentsTab() {
308
308
  )
309
309
  ] }) });
310
310
  }
311
- function PayPalApplePayPage() {
312
- return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
313
- }
314
- function PayPalGooglePayPage() {
315
- return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
316
- }
317
311
  const config = adminSdk.defineRouteConfig({
318
312
  label: "PayPal Connection"
319
313
  });
320
- const PARTNER_JS_URLS = {
321
- sandbox: "https://www.sandbox.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js",
322
- live: "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js"
323
- };
314
+ const PARTNER_JS_URL = "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js";
324
315
  const SERVICE_URL = "/admin/paypal/onboarding-link";
325
- const POPUP_NAME = "PPFrame";
326
316
  const CACHE_PREFIX = "pp_onboard_cache";
327
317
  const CACHE_EXPIRY = 6 * 60 * 60 * 1e3;
328
318
  const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
@@ -347,9 +337,7 @@ function readCachedUrl(env) {
347
337
  function writeCachedUrl(env, url) {
348
338
  try {
349
339
  localStorage.setItem(cacheKeyFor(env), JSON.stringify({ url, ts: Date.now() }));
350
- return readCachedUrl(env) === url;
351
340
  } catch {
352
- return false;
353
341
  }
354
342
  }
355
343
  function clearCachedUrl(env) {
@@ -363,62 +351,11 @@ function clearCachedUrl(env) {
363
351
  } catch {
364
352
  }
365
353
  }
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
- }
416
354
  function PayPalConnectionPage() {
417
355
  const [env, setEnv] = react.useState("live");
418
356
  const [envReady, setEnvReady] = react.useState(false);
419
357
  const [connState, setConnState] = react.useState("loading");
420
358
  const [error, setError] = react.useState(null);
421
- const [popupBlocked, setPopupBlocked] = react.useState(false);
422
359
  const [finalUrl, setFinalUrl] = react.useState("");
423
360
  const [showManual, setShowManual] = react.useState(false);
424
361
  const [clientId, setClientId] = react.useState("");
@@ -430,17 +367,11 @@ function PayPalConnectionPage() {
430
367
  const errorLogRef = react.useRef(null);
431
368
  const runIdRef = react.useRef(0);
432
369
  const currentRunId = react.useRef(0);
370
+ const completedRef = react.useRef(false);
433
371
  const envRef = react.useRef(env);
434
372
  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);
443
- const completedRef = react.useRef(false);
373
+ const pollTimerRef = react.useRef(null);
374
+ const pollAttemptsRef = react.useRef(0);
444
375
  const ppBtnMeasureRef = react.useRef(null);
445
376
  const [ppBtnWidth, setPpBtnWidth] = react.useState(null);
446
377
  const canSaveManual = react.useMemo(() => {
@@ -450,44 +381,72 @@ function PayPalConnectionPage() {
450
381
  setConnState("error");
451
382
  setError(msg);
452
383
  }, []);
453
- const stopPoll = react.useCallback(() => {
454
- if (pollRef.current) {
455
- clearInterval(pollRef.current);
456
- pollRef.current = null;
384
+ const closeMiniBrowser = react.useCallback(() => {
385
+ var _a, _b, _c, _d, _e, _f, _g, _h;
386
+ try {
387
+ 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;
388
+ if (typeof close1 === "function") close1();
389
+ } catch {
457
390
  }
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
391
  try {
471
- popup = window.open(url, POPUP_NAME, features);
392
+ const close2 = (_h = (_g = (_f = (_e = window.PAYPAL) == null ? void 0 : _e.apps) == null ? void 0 : _f.Signup) == null ? void 0 : _g.miniBrowser) == null ? void 0 : _h.closeFlow;
393
+ if (typeof close2 === "function") close2();
472
394
  } catch {
473
- popup = null;
474
395
  }
475
- if (popup) {
476
- popupRef.current = popup;
396
+ }, []);
397
+ const stopStatusPolling = react.useCallback(() => {
398
+ if (pollTimerRef.current) {
399
+ clearTimeout(pollTimerRef.current);
400
+ pollTimerRef.current = null;
401
+ }
402
+ pollAttemptsRef.current = 0;
403
+ }, []);
404
+ const refreshStatusAndMaybeConnect = react.useCallback(
405
+ async (activeEnv) => {
477
406
  try {
478
- popup.focus();
407
+ const res = await fetch(`${STATUS_ENDPOINT}?environment=${activeEnv}`, {
408
+ method: "GET",
409
+ credentials: "include"
410
+ });
411
+ const st = await res.json().catch(() => ({}));
412
+ const connected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
413
+ if (connected) {
414
+ completedRef.current = true;
415
+ setStatusInfo(st);
416
+ setConnState("connected");
417
+ setShowManual(false);
418
+ setOnboardingInProgress(false);
419
+ clearCachedUrl(activeEnv);
420
+ closeMiniBrowser();
421
+ stopStatusPolling();
422
+ }
423
+ return connected;
479
424
  } catch {
425
+ return false;
480
426
  }
481
- }
482
- return popup;
483
- }, []);
427
+ },
428
+ [closeMiniBrowser, stopStatusPolling]
429
+ );
430
+ const startStatusPolling = react.useCallback(() => {
431
+ stopStatusPolling();
432
+ const MAX_ATTEMPTS = 100;
433
+ const tick = async () => {
434
+ pollAttemptsRef.current += 1;
435
+ const connected = await refreshStatusAndMaybeConnect(envRef.current);
436
+ if (connected || completedRef.current) return;
437
+ if (pollAttemptsRef.current >= MAX_ATTEMPTS) {
438
+ stopStatusPolling();
439
+ return;
440
+ }
441
+ pollTimerRef.current = setTimeout(tick, 3e3);
442
+ };
443
+ pollTimerRef.current = setTimeout(tick, 3e3);
444
+ }, [refreshStatusAndMaybeConnect, stopStatusPolling]);
484
445
  const completeOnboarding = react.useCallback(
485
446
  async (authCode, sharedId) => {
486
- var _a, _b, _c, _d, _e, _f, _g, _h;
487
447
  if (!authCode || !sharedId) return;
488
448
  if (completedRef.current) return;
489
449
  completedRef.current = true;
490
- stopPoll();
491
450
  try {
492
451
  window.onbeforeunload = null;
493
452
  } catch {
@@ -496,7 +455,6 @@ function PayPalConnectionPage() {
496
455
  setOnboardingInProgress(true);
497
456
  setConnState("loading");
498
457
  setError(null);
499
- setPopupBlocked(false);
500
458
  try {
501
459
  const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
502
460
  method: "POST",
@@ -508,32 +466,20 @@ function PayPalConnectionPage() {
508
466
  const txt = await res.text().catch(() => "");
509
467
  throw new Error(txt || `Onboarding exchange failed (${res.status})`);
510
468
  }
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
- }
469
+ closeMiniBrowser();
525
470
  clearCachedUrl(activeEnv);
526
471
  try {
527
- const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${activeEnv}`, {
528
- method: "GET",
529
- credentials: "include"
530
- });
472
+ const statusRes = await fetch(
473
+ `${STATUS_ENDPOINT}?environment=${activeEnv}`,
474
+ { method: "GET", credentials: "include" }
475
+ );
531
476
  const refreshedStatus = await statusRes.json().catch(() => ({}));
532
477
  setStatusInfo(refreshedStatus || null);
533
478
  } catch {
534
479
  }
535
480
  setConnState("connected");
536
481
  setShowManual(false);
482
+ stopStatusPolling();
537
483
  } catch (e) {
538
484
  completedRef.current = false;
539
485
  console.error(e);
@@ -543,42 +489,72 @@ function PayPalConnectionPage() {
543
489
  setOnboardingInProgress(false);
544
490
  }
545
491
  },
546
- [stopPoll]
492
+ [closeMiniBrowser, stopStatusPolling]
547
493
  );
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
- }
494
+ const initPartner = react.useCallback(() => {
495
+ var _a, _b;
496
+ const signup = (_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup;
497
+ const init = (signup == null ? void 0 : signup.miniBrowser) && signup.miniBrowser.init || (signup == null ? void 0 : signup.MiniBrowser) && signup.MiniBrowser.init;
498
+ if (typeof init === "function") {
558
499
  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 {
500
+ init();
501
+ } catch (e) {
502
+ console.error("[paypal] partner.js init failed:", e);
503
+ }
504
+ }
505
+ }, []);
506
+ react.useEffect(() => {
507
+ const existingScript = document.getElementById("paypal-partner-js");
508
+ if (existingScript) return;
509
+ const preloadHref = PARTNER_JS_URL;
510
+ let preloadLink = null;
511
+ if (!document.head.querySelector(`link[rel="preload"][href="${preloadHref}"]`)) {
512
+ preloadLink = document.createElement("link");
513
+ preloadLink.rel = "preload";
514
+ preloadLink.href = preloadHref;
515
+ preloadLink.as = "script";
516
+ document.head.appendChild(preloadLink);
517
+ }
518
+ const ppScript = document.createElement("script");
519
+ ppScript.id = "paypal-partner-js";
520
+ ppScript.src = preloadHref;
521
+ ppScript.async = true;
522
+ document.head.appendChild(ppScript);
523
+ return () => {
524
+ if (preloadLink == null ? void 0 : preloadLink.parentNode) preloadLink.parentNode.removeChild(preloadLink);
525
+ if (ppScript.parentNode) ppScript.parentNode.removeChild(ppScript);
526
+ };
527
+ }, []);
528
+ const activatePayPal = react.useCallback(
529
+ (url, runId) => {
530
+ if (paypalButtonRef.current) {
531
+ paypalButtonRef.current.href = url;
578
532
  }
579
- }, 2e3);
580
- }, [stopPoll]);
581
- const generateLinkAndReload = react.useCallback(
533
+ setFinalUrl(url);
534
+ let attempts = 0;
535
+ const MAX_ATTEMPTS = 200;
536
+ const tryInit = () => {
537
+ var _a, _b;
538
+ if (runId !== currentRunId.current) return;
539
+ if ((_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) {
540
+ initPartner();
541
+ setConnState("ready");
542
+ return;
543
+ }
544
+ attempts++;
545
+ if (attempts >= MAX_ATTEMPTS) {
546
+ showError(
547
+ "PayPal partner script failed to load. Please refresh and try again."
548
+ );
549
+ return;
550
+ }
551
+ setTimeout(tryInit, 50);
552
+ };
553
+ tryInit();
554
+ },
555
+ [initPartner, showError]
556
+ );
557
+ const fetchFreshLink = react.useCallback(
582
558
  async (targetEnv, runId) => {
583
559
  if (initLoaderRef.current) {
584
560
  const loaderText = initLoaderRef.current.querySelector("#loader-text");
@@ -600,19 +576,14 @@ function PayPalConnectionPage() {
600
576
  return;
601
577
  }
602
578
  const url = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
603
- const persisted = writeCachedUrl(targetEnv, url);
604
- if (persisted) {
605
- window.location.reload();
606
- return;
607
- }
608
- setFinalUrl(url);
609
- setConnState("ready");
579
+ writeCachedUrl(targetEnv, url);
580
+ activatePayPal(url, runId);
610
581
  } catch {
611
582
  if (runId !== currentRunId.current) return;
612
583
  showError("Unable to connect to service.");
613
584
  }
614
585
  },
615
- [showError]
586
+ [activatePayPal, showError]
616
587
  );
617
588
  react.useEffect(() => {
618
589
  let alive = true;
@@ -636,7 +607,6 @@ function PayPalConnectionPage() {
636
607
  const run = async () => {
637
608
  setConnState("loading");
638
609
  setError(null);
639
- setPopupBlocked(false);
640
610
  setFinalUrl("");
641
611
  try {
642
612
  const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
@@ -658,149 +628,43 @@ function PayPalConnectionPage() {
658
628
  if (cancelled || runId !== currentRunId.current) return;
659
629
  const cached = readCachedUrl(env);
660
630
  if (cached) {
661
- setFinalUrl(cached);
662
- setConnState("ready");
631
+ activatePayPal(cached, runId);
663
632
  return;
664
633
  }
665
- await generateLinkAndReload(env, runId);
634
+ await fetchFreshLink(env, runId);
666
635
  };
667
636
  run();
668
637
  return () => {
669
638
  cancelled = true;
670
639
  };
671
- }, [env, envReady, generateLinkAndReload]);
672
- react.useEffect(() => {
673
- var _a, _b, _c;
674
- if (connState !== "ready" || !finalUrl) return;
675
- const scriptUrl = PARTNER_JS_URLS[env];
676
- let cancelled = false;
677
- let pollTimer;
678
- const initPartner = (attempt = 0) => {
679
- var _a2, _b2;
680
- if (cancelled) return;
681
- const signup = (_b2 = (_a2 = window.PAYPAL) == null ? void 0 : _a2.apps) == null ? void 0 : _b2.Signup;
682
- const target = (signup == null ? void 0 : signup.miniBrowser) && typeof signup.miniBrowser.init === "function" ? signup.miniBrowser : (signup == null ? void 0 : signup.MiniBrowser) && typeof signup.MiniBrowser.init === "function" ? signup.MiniBrowser : null;
683
- if (target == null ? void 0 : target.init) {
684
- try {
685
- target.init();
686
- } catch (e) {
687
- console.error("[paypal] partner.js init failed:", e);
688
- }
689
- return;
690
- }
691
- if (typeof (signup == null ? void 0 : signup.render) === "function") {
692
- try {
693
- signup.render();
694
- } catch (e) {
695
- console.error("[paypal] partner.js render failed:", e);
696
- }
697
- return;
698
- }
699
- if (attempt < 40) {
700
- pollTimer = setTimeout(() => initPartner(attempt + 1), 50);
701
- return;
702
- }
703
- try {
704
- document.dispatchEvent(new Event("DOMContentLoaded"));
705
- } catch {
706
- }
707
- };
708
- const existingScript = document.getElementById("paypal-partner-js");
709
- if (existingScript) {
710
- (_a = existingScript.parentNode) == null ? void 0 : _a.removeChild(existingScript);
711
- }
712
- if ((_c = (_b = window.PAYPAL) == null ? void 0 : _b.apps) == null ? void 0 : _c.Signup) {
713
- try {
714
- delete window.PAYPAL.apps.Signup;
715
- } catch {
716
- }
717
- }
718
- const ppScript = document.createElement("script");
719
- ppScript.id = "paypal-partner-js";
720
- ppScript.src = scriptUrl;
721
- ppScript.async = true;
722
- ppScript.onload = () => initPartner();
723
- document.body.appendChild(ppScript);
724
- return () => {
725
- cancelled = true;
726
- if (pollTimer) clearTimeout(pollTimer);
727
- if (ppScript.parentNode) ppScript.parentNode.removeChild(ppScript);
728
- };
729
- }, [connState, finalUrl, env]);
730
- react.useEffect(() => {
731
- const onMessage = (ev) => {
732
- var _a;
733
- let serialized = "";
734
- try {
735
- serialized = typeof ev.data === "string" ? ev.data : JSON.stringify(ev.data);
736
- } catch {
737
- serialized = String(ev.data);
738
- }
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
- );
747
- }
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;
761
- }
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]);
640
+ }, [env, envReady, fetchFreshLink, activatePayPal]);
771
641
  react.useLayoutEffect(() => {
772
642
  window.onboardingCallback = (authCode, sharedId) => {
773
- completeOnboarding(authCode, sharedId);
643
+ void completeOnboarding(authCode, sharedId);
774
644
  };
775
645
  return () => {
776
646
  window.onboardingCallback = void 0;
777
647
  };
778
648
  }, [completeOnboarding]);
779
649
  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();
650
+ const onMessage = (event) => {
651
+ const data = event == null ? void 0 : event.data;
652
+ if (!data || data.source !== "paypal-onboarding-return") return;
653
+ const params = data.params || {};
654
+ const authCode = params.authCode || params.auth_code;
655
+ const sharedId = params.sharedId || params.shared_id;
656
+ const activeEnv = envRef.current;
657
+ void (async () => {
658
+ const connected = await refreshStatusAndMaybeConnect(activeEnv);
659
+ if (!connected && authCode && sharedId) {
660
+ await completeOnboarding(authCode, sharedId);
661
+ }
662
+ })();
797
663
  };
798
- document.addEventListener("click", onCaptureClick, true);
799
- return () => document.removeEventListener("click", onCaptureClick, true);
800
- }, [openOnboardingPopup, startStatusPoll]);
801
- react.useEffect(() => {
802
- return () => stopPoll();
803
- }, [stopPoll]);
664
+ window.addEventListener("message", onMessage);
665
+ return () => window.removeEventListener("message", onMessage);
666
+ }, [completeOnboarding, refreshStatusAndMaybeConnect]);
667
+ react.useEffect(() => stopStatusPolling, [stopStatusPolling]);
804
668
  react.useLayoutEffect(() => {
805
669
  const el = ppBtnMeasureRef.current;
806
670
  if (!el) return;
@@ -822,7 +686,12 @@ function PayPalConnectionPage() {
822
686
  };
823
687
  }, [connState, env, finalUrl]);
824
688
  const handleConnectClick = (e) => {
825
- e.preventDefault();
689
+ if (connState !== "ready" || !finalUrl || onboardingInProgress) {
690
+ e.preventDefault();
691
+ return;
692
+ }
693
+ completedRef.current = false;
694
+ startStatusPolling();
826
695
  };
827
696
  const handleSaveManual = async () => {
828
697
  if (!canSaveManual || onboardingInProgress) return;
@@ -864,6 +733,7 @@ function PayPalConnectionPage() {
864
733
  const handleDisconnect = async () => {
865
734
  if (onboardingInProgress) return;
866
735
  if (!window.confirm("Disconnect PayPal for this environment?")) return;
736
+ stopStatusPolling();
867
737
  setOnboardingInProgress(true);
868
738
  setConnState("loading");
869
739
  setError(null);
@@ -884,7 +754,7 @@ function PayPalConnectionPage() {
884
754
  clearCachedUrl(env);
885
755
  completedRef.current = false;
886
756
  currentRunId.current = ++runIdRef.current;
887
- await generateLinkAndReload(env, currentRunId.current);
757
+ await fetchFreshLink(env, currentRunId.current);
888
758
  } catch (e) {
889
759
  console.error(e);
890
760
  setConnState("error");
@@ -896,9 +766,9 @@ function PayPalConnectionPage() {
896
766
  const handleEnvChange = async (e) => {
897
767
  const next = e.target.value;
898
768
  if (next === env || onboardingInProgress) return;
769
+ stopStatusPolling();
899
770
  completedRef.current = false;
900
771
  clearCachedUrl();
901
- setPopupBlocked(false);
902
772
  setConnState("loading");
903
773
  try {
904
774
  await fetch(ENVIRONMENT_ENDPOINT, {
@@ -932,7 +802,19 @@ function PayPalConnectionPage() {
932
802
  ) }),
933
803
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium pt-2", children: env === "sandbox" ? "Connect to PayPal (Sandbox)" : "Connect to PayPal" }),
934
804
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xl", children: connState === "connected" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
935
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: "✅ Successfully connected to PayPal!" }),
805
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: [
806
+ "✅ Successfully connected to PayPal!",
807
+ /* @__PURE__ */ jsxRuntime.jsx(
808
+ "a",
809
+ {
810
+ "data-paypal-button": "true",
811
+ "data-paypal-onboard-complete": "onboardingCallback",
812
+ href: "#",
813
+ style: { display: "none" },
814
+ children: "PayPal"
815
+ }
816
+ )
817
+ ] }),
936
818
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 rounded-md border border-ui-border-base bg-ui-bg-subtle p-3 text-xs text-ui-fg-subtle", children: [
937
819
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-ui-fg-base", children: "Connected PayPal account" }),
938
820
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1", children: [
@@ -973,7 +855,6 @@ function PayPalConnectionPage() {
973
855
  ppBtnMeasureRef.current = node;
974
856
  },
975
857
  id: "paypal-button",
976
- target: POPUP_NAME,
977
858
  "data-paypal-button": "true",
978
859
  href: finalUrl || "#",
979
860
  "data-paypal-onboard-complete": "onboardingCallback",
@@ -987,7 +868,6 @@ function PayPalConnectionPage() {
987
868
  children: "Connect to PayPal"
988
869
  }
989
870
  ),
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." }),
991
871
  /* @__PURE__ */ jsxRuntime.jsx(
992
872
  "div",
993
873
  {
@@ -1143,6 +1023,12 @@ function PayPalConnectionPage() {
1143
1023
  ` })
1144
1024
  ] });
1145
1025
  }
1026
+ function PayPalApplePayPage() {
1027
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1028
+ }
1029
+ function PayPalGooglePayPage() {
1030
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1031
+ }
1146
1032
  function PayPalPayLaterMessagingPage() {
1147
1033
  return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1148
1034
  }
@@ -1368,6 +1254,10 @@ const routeModule = {
1368
1254
  Component: AdvancedCardPaymentsTab,
1369
1255
  path: "/settings/paypal/advanced-card-payments"
1370
1256
  },
1257
+ {
1258
+ Component: PayPalConnectionPage,
1259
+ path: "/settings/paypal/connection"
1260
+ },
1371
1261
  {
1372
1262
  Component: PayPalApplePayPage,
1373
1263
  path: "/settings/paypal/apple-pay"
@@ -1376,10 +1266,6 @@ const routeModule = {
1376
1266
  Component: PayPalGooglePayPage,
1377
1267
  path: "/settings/paypal/google-pay"
1378
1268
  },
1379
- {
1380
- Component: PayPalConnectionPage,
1381
- path: "/settings/paypal/connection"
1382
- },
1383
1269
  {
1384
1270
  Component: PayPalPayLaterMessagingPage,
1385
1271
  path: "/settings/paypal/pay-later-messaging"