@easypayment/medusa-payment-paypal 0.9.20 → 0.9.22

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.
@@ -224,9 +224,6 @@ 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
- }
230
227
  const DEFAULT_FORM = {
231
228
  enabled: true,
232
229
  title: "Credit or Debit Card",
@@ -311,6 +308,12 @@ function AdvancedCardPaymentsTab() {
311
308
  )
312
309
  ] }) });
313
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
+ }
314
317
  const config = adminSdk.defineRouteConfig({
315
318
  label: "PayPal Connection"
316
319
  });
@@ -319,9 +322,9 @@ const PARTNER_JS_URLS = {
319
322
  live: "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js"
320
323
  };
321
324
  const SERVICE_URL = "/admin/paypal/onboarding-link";
322
- const POPUP_NAME = "PPMiniBrowser";
325
+ const POPUP_NAME = "PPFrame";
323
326
  const CACHE_PREFIX = "pp_onboard_cache";
324
- const CACHE_EXPIRY = 10 * 60 * 1e3;
327
+ const CACHE_EXPIRY = 6 * 60 * 60 * 1e3;
325
328
  const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
326
329
  const STATUS_ENDPOINT = "/admin/paypal/status";
327
330
  const SAVE_CREDENTIALS_ENDPOINT = "/admin/paypal/save-credentials";
@@ -344,7 +347,9 @@ function readCachedUrl(env) {
344
347
  function writeCachedUrl(env, url) {
345
348
  try {
346
349
  localStorage.setItem(cacheKeyFor(env), JSON.stringify({ url, ts: Date.now() }));
350
+ return readCachedUrl(env) === url;
347
351
  } catch {
352
+ return false;
348
353
  }
349
354
  }
350
355
  function clearCachedUrl(env) {
@@ -358,58 +363,12 @@ function clearCachedUrl(env) {
358
363
  } catch {
359
364
  }
360
365
  }
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 {
402
- }
403
- }
404
- }
405
- return {};
406
- }
407
366
  function PayPalConnectionPage() {
408
367
  const [env, setEnv] = react.useState("live");
409
368
  const [envReady, setEnvReady] = react.useState(false);
410
369
  const [connState, setConnState] = react.useState("loading");
370
+ const [partnerReady, setPartnerReady] = react.useState(false);
411
371
  const [error, setError] = react.useState(null);
412
- const [popupBlocked, setPopupBlocked] = react.useState(false);
413
372
  const [finalUrl, setFinalUrl] = react.useState("");
414
373
  const [showManual, setShowManual] = react.useState(false);
415
374
  const [clientId, setClientId] = react.useState("");
@@ -417,22 +376,12 @@ function PayPalConnectionPage() {
417
376
  const [statusInfo, setStatusInfo] = react.useState(null);
418
377
  const [onboardingInProgress, setOnboardingInProgress] = react.useState(false);
419
378
  const initLoaderRef = react.useRef(null);
420
- const paypalButtonRef = react.useRef(null);
421
379
  const errorLogRef = react.useRef(null);
422
380
  const runIdRef = react.useRef(0);
423
381
  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
382
  const envRef = react.useRef(env);
431
383
  envRef.current = env;
432
- const popupRef = react.useRef(null);
433
- const popupPollRef = react.useRef(null);
434
384
  const completedRef = react.useRef(false);
435
- const partnerBoundRef = react.useRef(false);
436
385
  const ppBtnMeasureRef = react.useRef(null);
437
386
  const [ppBtnWidth, setPpBtnWidth] = react.useState(null);
438
387
  const canSaveManual = react.useMemo(() => {
@@ -442,131 +391,23 @@ function PayPalConnectionPage() {
442
391
  setConnState("error");
443
392
  setError(msg);
444
393
  }, []);
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 {
394
+ const generateLinkAndReload = react.useCallback(
395
+ async (targetEnv, runId) => {
396
+ if (initLoaderRef.current) {
397
+ const loaderText = initLoaderRef.current.querySelector("#loader-text");
398
+ if (loaderText) {
399
+ loaderText.textContent = "Generating onboarding session...";
473
400
  }
474
- stopPopupPoll();
475
- popupPollRef.current = setInterval(() => {
476
- if (!popupRef.current || popupRef.current.closed) {
477
- stopPopupPoll();
478
- }
479
- }, 1e3);
480
401
  }
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
402
  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, {
403
+ const res = await fetch(SERVICE_URL, {
502
404
  method: "POST",
503
405
  headers: { "content-type": "application/json" },
504
406
  credentials: "include",
505
- body: JSON.stringify({ authCode, sharedId, env: activeEnv })
407
+ body: JSON.stringify({ products: ["PPCP"], environment: targetEnv })
506
408
  });
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
- );
549
- const fetchFreshLink = react.useCallback(
550
- (runId, targetEnv) => {
551
- if (initLoaderRef.current) {
552
- const loaderText = initLoaderRef.current.querySelector("#loader-text");
553
- if (loaderText)
554
- loaderText.textContent = "Generating onboarding session...";
555
- }
556
- fetch(SERVICE_URL, {
557
- method: "POST",
558
- headers: { "content-type": "application/json" },
559
- credentials: "include",
560
- body: JSON.stringify({
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
565
- })
566
- }).then((r) => {
567
- if (!r.ok) throw new Error(`Service returned ${r.status}`);
568
- return r.json();
569
- }).then((data) => {
409
+ if (!res.ok) throw new Error(`Service returned ${res.status}`);
410
+ const data = await res.json();
570
411
  if (runId !== currentRunId.current) return;
571
412
  const href = data == null ? void 0 : data.onboarding_url;
572
413
  if (!href) {
@@ -574,13 +415,17 @@ function PayPalConnectionPage() {
574
415
  return;
575
416
  }
576
417
  const url = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
577
- writeCachedUrl(targetEnv, url);
418
+ const persisted = writeCachedUrl(targetEnv, url);
419
+ if (persisted) {
420
+ window.location.reload();
421
+ return;
422
+ }
578
423
  setFinalUrl(url);
579
424
  setConnState("ready");
580
- }).catch(() => {
425
+ } catch {
581
426
  if (runId !== currentRunId.current) return;
582
427
  showError("Unable to connect to service.");
583
- });
428
+ }
584
429
  },
585
430
  [showError]
586
431
  );
@@ -597,12 +442,60 @@ function PayPalConnectionPage() {
597
442
  alive = false;
598
443
  };
599
444
  }, []);
445
+ react.useEffect(() => {
446
+ if (!envReady) return;
447
+ currentRunId.current = ++runIdRef.current;
448
+ const runId = currentRunId.current;
449
+ let cancelled = false;
450
+ completedRef.current = false;
451
+ const run = async () => {
452
+ setConnState("loading");
453
+ setError(null);
454
+ setFinalUrl("");
455
+ try {
456
+ const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
457
+ method: "GET",
458
+ credentials: "include"
459
+ });
460
+ const st = await r.json().catch(() => ({}));
461
+ if (cancelled || runId !== currentRunId.current) return;
462
+ setStatusInfo(st);
463
+ const isConnected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
464
+ if (isConnected) {
465
+ setConnState("connected");
466
+ setShowManual(false);
467
+ return;
468
+ }
469
+ } catch (e) {
470
+ console.error(e);
471
+ }
472
+ if (cancelled || runId !== currentRunId.current) return;
473
+ const cached = readCachedUrl(env);
474
+ if (cached) {
475
+ setFinalUrl(cached);
476
+ setConnState("ready");
477
+ return;
478
+ }
479
+ await generateLinkAndReload(env, runId);
480
+ };
481
+ run();
482
+ return () => {
483
+ cancelled = true;
484
+ };
485
+ }, [env, envReady, generateLinkAndReload]);
600
486
  react.useEffect(() => {
601
487
  var _a, _b, _c;
602
488
  if (connState !== "ready" || !finalUrl) return;
603
489
  const scriptUrl = PARTNER_JS_URLS[env];
604
490
  let cancelled = false;
605
491
  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
+ };
606
499
  const initPartner = (attempt = 0) => {
607
500
  var _a2, _b2;
608
501
  if (cancelled) return;
@@ -611,19 +504,19 @@ function PayPalConnectionPage() {
611
504
  if (target == null ? void 0 : target.init) {
612
505
  try {
613
506
  target.init();
614
- partnerBoundRef.current = true;
615
507
  } catch (e) {
616
508
  console.error("[paypal] partner.js init failed:", e);
617
509
  }
510
+ markReady();
618
511
  return;
619
512
  }
620
513
  if (typeof (signup == null ? void 0 : signup.render) === "function") {
621
514
  try {
622
515
  signup.render();
623
- partnerBoundRef.current = true;
624
516
  } catch (e) {
625
517
  console.error("[paypal] partner.js render failed:", e);
626
518
  }
519
+ markReady();
627
520
  return;
628
521
  }
629
522
  if (attempt < 40) {
@@ -634,8 +527,8 @@ function PayPalConnectionPage() {
634
527
  document.dispatchEvent(new Event("DOMContentLoaded"));
635
528
  } catch {
636
529
  }
530
+ markReady();
637
531
  };
638
- partnerBoundRef.current = false;
639
532
  const existingScript = document.getElementById("paypal-partner-js");
640
533
  if (existingScript) {
641
534
  (_a = existingScript.parentNode) == null ? void 0 : _a.removeChild(existingScript);
@@ -651,9 +544,11 @@ function PayPalConnectionPage() {
651
544
  ppScript.src = scriptUrl;
652
545
  ppScript.async = true;
653
546
  ppScript.onload = () => initPartner();
547
+ ppScript.onerror = () => markReady();
654
548
  document.body.appendChild(ppScript);
655
549
  return () => {
656
550
  cancelled = true;
551
+ clearTimeout(readyFallback);
657
552
  if (pollTimer) {
658
553
  clearTimeout(pollTimer);
659
554
  }
@@ -662,59 +557,61 @@ function PayPalConnectionPage() {
662
557
  }
663
558
  };
664
559
  }, [connState, finalUrl, env]);
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);
560
+ const completeOnboarding = react.useCallback(async (authCode, sharedId) => {
561
+ var _a, _b, _c, _d, _e, _f, _g;
562
+ if (!authCode || !sharedId) return;
563
+ if (completedRef.current) return;
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})`);
671
583
  }
672
- };
673
- window.addEventListener("message", onMessage);
674
- return () => window.removeEventListener("message", onMessage);
675
- }, [completeOnboarding]);
676
- react.useEffect(() => {
677
- if (!envReady) return;
678
- currentRunId.current = ++runIdRef.current;
679
- const runId = currentRunId.current;
680
- let cancelled = false;
681
- completedRef.current = false;
682
- const run = async () => {
683
- setConnState("loading");
684
- setError(null);
685
- setPopupBlocked(false);
686
- setFinalUrl("");
687
584
  try {
688
- const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
585
+ 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;
586
+ if (typeof close1 === "function") close1();
587
+ } catch {
588
+ }
589
+ try {
590
+ 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;
591
+ if (typeof close2 === "function") close2();
592
+ } catch {
593
+ }
594
+ clearCachedUrl(activeEnv);
595
+ try {
596
+ const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${activeEnv}`, {
689
597
  method: "GET",
690
598
  credentials: "include"
691
599
  });
692
- const st = await r.json().catch(() => ({}));
693
- if (cancelled || runId !== currentRunId.current) return;
694
- setStatusInfo(st);
695
- const isConnected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
696
- if (isConnected) {
697
- setConnState("connected");
698
- setShowManual(false);
699
- return;
700
- }
701
- } catch (e) {
702
- console.error(e);
703
- }
704
- if (cancelled || runId !== currentRunId.current) return;
705
- const cached = readCachedUrl(env);
706
- if (cached) {
707
- setFinalUrl(cached);
708
- setConnState("ready");
709
- } else {
710
- fetchFreshLink(runId, env);
600
+ const refreshedStatus = await statusRes.json().catch(() => ({}));
601
+ setStatusInfo(refreshedStatus || null);
602
+ } catch {
711
603
  }
712
- };
713
- run();
714
- return () => {
715
- cancelled = true;
716
- };
717
- }, [env, envReady, fetchFreshLink]);
604
+ setConnState("connected");
605
+ setShowManual(false);
606
+ } catch (e) {
607
+ completedRef.current = false;
608
+ console.error(e);
609
+ setConnState("error");
610
+ setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
611
+ } finally {
612
+ setOnboardingInProgress(false);
613
+ }
614
+ }, []);
718
615
  react.useLayoutEffect(() => {
719
616
  window.onboardingCallback = (authCode, sharedId) => {
720
617
  completeOnboarding(authCode, sharedId);
@@ -723,11 +620,6 @@ function PayPalConnectionPage() {
723
620
  window.onboardingCallback = void 0;
724
621
  };
725
622
  }, [completeOnboarding]);
726
- react.useEffect(() => {
727
- return () => {
728
- stopPopupPoll();
729
- };
730
- }, [stopPopupPoll]);
731
623
  react.useLayoutEffect(() => {
732
624
  const el = ppBtnMeasureRef.current;
733
625
  if (!el) return;
@@ -748,18 +640,6 @@ function PayPalConnectionPage() {
748
640
  else window.removeEventListener("resize", update);
749
641
  };
750
642
  }, [connState, env, finalUrl]);
751
- const handleConnectClick = (e) => {
752
- e.preventDefault();
753
- if (connStateRef.current !== "ready" || !finalUrlRef.current || inProgressRef.current) {
754
- return;
755
- }
756
- if (partnerBoundRef.current) {
757
- return;
758
- }
759
- completedRef.current = false;
760
- const popup = openOnboardingPopup(finalUrlRef.current);
761
- setPopupBlocked(!popup);
762
- };
763
643
  const handleSaveManual = async () => {
764
644
  if (!canSaveManual || onboardingInProgress) return;
765
645
  setOnboardingInProgress(true);
@@ -820,8 +700,7 @@ function PayPalConnectionPage() {
820
700
  clearCachedUrl(env);
821
701
  completedRef.current = false;
822
702
  currentRunId.current = ++runIdRef.current;
823
- const runId = currentRunId.current;
824
- fetchFreshLink(runId, env);
703
+ await generateLinkAndReload(env, currentRunId.current);
825
704
  } catch (e) {
826
705
  console.error(e);
827
706
  setConnState("error");
@@ -832,10 +711,10 @@ function PayPalConnectionPage() {
832
711
  };
833
712
  const handleEnvChange = async (e) => {
834
713
  const next = e.target.value;
714
+ if (next === env || onboardingInProgress) return;
835
715
  completedRef.current = false;
836
- setPopupBlocked(false);
837
716
  clearCachedUrl();
838
- setEnv(next);
717
+ setConnState("loading");
839
718
  try {
840
719
  await fetch(ENVIRONMENT_ENDPOINT, {
841
720
  method: "POST",
@@ -845,6 +724,7 @@ function PayPalConnectionPage() {
845
724
  });
846
725
  } catch {
847
726
  }
727
+ setEnv(next);
848
728
  };
849
729
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6", children: [
850
730
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
@@ -904,7 +784,6 @@ function PayPalConnectionPage() {
904
784
  "a",
905
785
  {
906
786
  ref: (node) => {
907
- paypalButtonRef.current = node;
908
787
  ppBtnMeasureRef.current = node;
909
788
  },
910
789
  id: "paypal-button",
@@ -912,17 +791,19 @@ function PayPalConnectionPage() {
912
791
  "data-paypal-button": "true",
913
792
  href: finalUrl || "#",
914
793
  "data-paypal-onboard-complete": "onboardingCallback",
915
- onClick: handleConnectClick,
794
+ "aria-disabled": onboardingInProgress || !partnerReady,
916
795
  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",
917
796
  style: {
918
- cursor: onboardingInProgress ? "not-allowed" : "pointer",
919
- opacity: onboardingInProgress ? 0.6 : 1,
920
- pointerEvents: onboardingInProgress ? "none" : "auto"
797
+ cursor: onboardingInProgress || !partnerReady ? "not-allowed" : "pointer",
798
+ opacity: onboardingInProgress || !partnerReady ? 0.6 : 1,
799
+ // Keep the anchor mounted (partner.js must find it to bind)
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"
921
803
  },
922
- children: "Connect to PayPal"
804
+ children: partnerReady || onboardingInProgress ? "Connect to PayPal" : "Preparing PayPal…"
923
805
  }
924
806
  ),
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." }),
926
807
  /* @__PURE__ */ jsxRuntime.jsx(
927
808
  "div",
928
809
  {
@@ -1078,9 +959,6 @@ function PayPalConnectionPage() {
1078
959
  ` })
1079
960
  ] });
1080
961
  }
1081
- function PayPalGooglePayPage() {
1082
- return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1083
- }
1084
962
  function PayPalPayLaterMessagingPage() {
1085
963
  return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1086
964
  }
@@ -1302,22 +1180,22 @@ const routeModule = {
1302
1180
  Component: AdditionalSettingsTab,
1303
1181
  path: "/settings/paypal/additional-settings"
1304
1182
  },
1305
- {
1306
- Component: PayPalApplePayPage,
1307
- path: "/settings/paypal/apple-pay"
1308
- },
1309
1183
  {
1310
1184
  Component: AdvancedCardPaymentsTab,
1311
1185
  path: "/settings/paypal/advanced-card-payments"
1312
1186
  },
1313
1187
  {
1314
- Component: PayPalConnectionPage,
1315
- path: "/settings/paypal/connection"
1188
+ Component: PayPalApplePayPage,
1189
+ path: "/settings/paypal/apple-pay"
1316
1190
  },
1317
1191
  {
1318
1192
  Component: PayPalGooglePayPage,
1319
1193
  path: "/settings/paypal/google-pay"
1320
1194
  },
1195
+ {
1196
+ Component: PayPalConnectionPage,
1197
+ path: "/settings/paypal/connection"
1198
+ },
1321
1199
  {
1322
1200
  Component: PayPalPayLaterMessagingPage,
1323
1201
  path: "/settings/paypal/pay-later-messaging"