@easypayment/medusa-payment-paypal 0.9.22 → 0.9.24

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 (40) hide show
  1. package/.medusa/server/src/admin/index.js +262 -92
  2. package/.medusa/server/src/admin/index.mjs +262 -92
  3. package/.medusa/server/src/admin/routes/settings/paypal/connection/page.d.ts.map +1 -1
  4. package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js +304 -146
  5. package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js.map +1 -1
  6. package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -1
  7. package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.js +6 -8
  8. package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.js.map +1 -1
  9. package/.medusa/server/src/api/admin/paypal/environment/route.d.ts.map +1 -1
  10. package/.medusa/server/src/api/admin/paypal/environment/route.js +11 -3
  11. package/.medusa/server/src/api/admin/paypal/environment/route.js.map +1 -1
  12. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.d.ts.map +1 -1
  13. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.js +4 -1
  14. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.js.map +1 -1
  15. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -1
  16. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js +6 -8
  17. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js.map +1 -1
  18. package/.medusa/server/src/api/store/paypal/capture-order/route.d.ts.map +1 -1
  19. package/.medusa/server/src/api/store/paypal/capture-order/route.js +11 -0
  20. package/.medusa/server/src/api/store/paypal/capture-order/route.js.map +1 -1
  21. package/.medusa/server/src/api/store/paypal-complete/route.d.ts.map +1 -1
  22. package/.medusa/server/src/api/store/paypal-complete/route.js +2 -4
  23. package/.medusa/server/src/api/store/paypal-complete/route.js.map +1 -1
  24. package/.medusa/server/src/modules/paypal/payment-provider/card-service.d.ts.map +1 -1
  25. package/.medusa/server/src/modules/paypal/payment-provider/card-service.js +55 -34
  26. package/.medusa/server/src/modules/paypal/payment-provider/card-service.js.map +1 -1
  27. package/.medusa/server/src/modules/paypal/utils/core-workflow.d.ts +32 -0
  28. package/.medusa/server/src/modules/paypal/utils/core-workflow.d.ts.map +1 -0
  29. package/.medusa/server/src/modules/paypal/utils/core-workflow.js +40 -0
  30. package/.medusa/server/src/modules/paypal/utils/core-workflow.js.map +1 -0
  31. package/package.json +1 -1
  32. package/src/admin/routes/settings/paypal/connection/page.tsx +330 -161
  33. package/src/api/admin/payment-collections/[id]/payment-sessions/route.ts +6 -8
  34. package/src/api/admin/paypal/environment/route.ts +10 -3
  35. package/src/api/admin/paypal/onboarding-status/route.ts +4 -1
  36. package/src/api/store/payment-collections/[id]/payment-sessions/route.ts +6 -8
  37. package/src/api/store/paypal/capture-order/route.ts +15 -0
  38. package/src/api/store/paypal-complete/route.ts +6 -4
  39. package/src/modules/paypal/payment-provider/card-service.ts +72 -38
  40. package/src/modules/paypal/utils/core-workflow.ts +46 -0
@@ -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",
@@ -308,12 +311,6 @@ function AdvancedCardPaymentsTab() {
308
311
  )
309
312
  ] }) });
310
313
  }
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
314
  const config = adminSdk.defineRouteConfig({
318
315
  label: "PayPal Connection"
319
316
  });
@@ -363,12 +360,62 @@ function clearCachedUrl(env) {
363
360
  } catch {
364
361
  }
365
362
  }
363
+ function isPayPalOrigin(origin) {
364
+ try {
365
+ const host = new URL(origin).hostname.toLowerCase();
366
+ return host === "www.paypal.com" || host === "www.sandbox.paypal.com" || host.endsWith(".paypal.com") || host.endsWith(".paypalobjects.com");
367
+ } catch {
368
+ return false;
369
+ }
370
+ }
371
+ function extractAuth(data) {
372
+ if (!data) return {};
373
+ if (typeof data === "object") {
374
+ const obj = data;
375
+ const authCode = obj.authCode ?? obj.auth_code ?? obj.authcode ?? obj.code;
376
+ const sharedId = obj.sharedId ?? obj.shared_id ?? obj.sharedid;
377
+ if (authCode && sharedId) {
378
+ return { authCode: String(authCode), sharedId: String(sharedId) };
379
+ }
380
+ for (const key of ["data", "payload", "message", "detail", "body", "params"]) {
381
+ if (obj[key] && typeof obj[key] === "object") {
382
+ const inner = extractAuth(obj[key]);
383
+ if (inner.authCode && inner.sharedId) return inner;
384
+ }
385
+ if (typeof obj[key] === "string") {
386
+ const inner = extractAuth(obj[key]);
387
+ if (inner.authCode && inner.sharedId) return inner;
388
+ }
389
+ }
390
+ return {};
391
+ }
392
+ if (typeof data === "string") {
393
+ const s = data.trim();
394
+ if (!s) return {};
395
+ if (s.startsWith("{") || s.startsWith("[")) {
396
+ try {
397
+ return extractAuth(JSON.parse(s));
398
+ } catch {
399
+ }
400
+ }
401
+ if (/auth_?code/i.test(s) && /shared_?id/i.test(s)) {
402
+ try {
403
+ const sp = new URLSearchParams(s.replace(/^[?#]/, ""));
404
+ const authCode = sp.get("authCode") || sp.get("auth_code") || void 0;
405
+ const sharedId = sp.get("sharedId") || sp.get("shared_id") || void 0;
406
+ if (authCode && sharedId) return { authCode, sharedId };
407
+ } catch {
408
+ }
409
+ }
410
+ }
411
+ return {};
412
+ }
366
413
  function PayPalConnectionPage() {
367
414
  const [env, setEnv] = react.useState("live");
368
415
  const [envReady, setEnvReady] = react.useState(false);
369
416
  const [connState, setConnState] = react.useState("loading");
370
- const [partnerReady, setPartnerReady] = react.useState(false);
371
417
  const [error, setError] = react.useState(null);
418
+ const [popupBlocked, setPopupBlocked] = react.useState(false);
372
419
  const [finalUrl, setFinalUrl] = react.useState("");
373
420
  const [showManual, setShowManual] = react.useState(false);
374
421
  const [clientId, setClientId] = react.useState("");
@@ -376,11 +423,20 @@ function PayPalConnectionPage() {
376
423
  const [statusInfo, setStatusInfo] = react.useState(null);
377
424
  const [onboardingInProgress, setOnboardingInProgress] = react.useState(false);
378
425
  const initLoaderRef = react.useRef(null);
426
+ const paypalButtonRef = react.useRef(null);
379
427
  const errorLogRef = react.useRef(null);
380
428
  const runIdRef = react.useRef(0);
381
429
  const currentRunId = react.useRef(0);
382
430
  const envRef = react.useRef(env);
383
431
  envRef.current = env;
432
+ const finalUrlRef = react.useRef(finalUrl);
433
+ finalUrlRef.current = finalUrl;
434
+ const connStateRef = react.useRef(connState);
435
+ connStateRef.current = connState;
436
+ const inProgressRef = react.useRef(onboardingInProgress);
437
+ inProgressRef.current = onboardingInProgress;
438
+ const popupRef = react.useRef(null);
439
+ const pollRef = react.useRef(null);
384
440
  const completedRef = react.useRef(false);
385
441
  const ppBtnMeasureRef = react.useRef(null);
386
442
  const [ppBtnWidth, setPpBtnWidth] = react.useState(null);
@@ -391,13 +447,139 @@ function PayPalConnectionPage() {
391
447
  setConnState("error");
392
448
  setError(msg);
393
449
  }, []);
450
+ const stopPoll = react.useCallback(() => {
451
+ if (pollRef.current) {
452
+ clearInterval(pollRef.current);
453
+ pollRef.current = null;
454
+ }
455
+ }, []);
456
+ const openOnboardingPopup = react.useCallback((url) => {
457
+ const w = 450;
458
+ const h = 600;
459
+ const baseLeft = typeof window.screenX === "number" ? window.screenX : window.screenLeft || 0;
460
+ const baseTop = typeof window.screenY === "number" ? window.screenY : window.screenTop || 0;
461
+ const outerW = window.outerWidth || document.documentElement.clientWidth || 1024;
462
+ const outerH = window.outerHeight || document.documentElement.clientHeight || 768;
463
+ const left = Math.round(baseLeft + Math.max(0, (outerW - w) / 2));
464
+ const top = Math.round(baseTop + Math.max(0, (outerH - h) / 2));
465
+ const features = `popup=yes,width=${w},height=${h},left=${left},top=${top},scrollbars=yes,resizable=yes`;
466
+ let popup = null;
467
+ try {
468
+ popup = window.open(url, POPUP_NAME, features);
469
+ } catch {
470
+ popup = null;
471
+ }
472
+ if (popup) {
473
+ popupRef.current = popup;
474
+ try {
475
+ popup.focus();
476
+ } catch {
477
+ }
478
+ }
479
+ return popup;
480
+ }, []);
481
+ const completeOnboarding = react.useCallback(
482
+ async (authCode, sharedId) => {
483
+ var _a, _b, _c, _d, _e, _f, _g, _h;
484
+ if (!authCode || !sharedId) return;
485
+ if (completedRef.current) return;
486
+ completedRef.current = true;
487
+ stopPoll();
488
+ try {
489
+ window.onbeforeunload = null;
490
+ } catch {
491
+ }
492
+ const activeEnv = envRef.current === "sandbox" ? "sandbox" : "live";
493
+ setOnboardingInProgress(true);
494
+ setConnState("loading");
495
+ setError(null);
496
+ setPopupBlocked(false);
497
+ try {
498
+ const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
499
+ method: "POST",
500
+ headers: { "content-type": "application/json" },
501
+ credentials: "include",
502
+ body: JSON.stringify({ authCode, sharedId, env: activeEnv })
503
+ });
504
+ if (!res.ok) {
505
+ const txt = await res.text().catch(() => "");
506
+ throw new Error(txt || `Onboarding exchange failed (${res.status})`);
507
+ }
508
+ try {
509
+ (_a = popupRef.current) == null ? void 0 : _a.close();
510
+ } catch {
511
+ }
512
+ try {
513
+ 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;
514
+ if (typeof close1 === "function") close1();
515
+ } catch {
516
+ }
517
+ try {
518
+ 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;
519
+ if (typeof close2 === "function") close2();
520
+ } catch {
521
+ }
522
+ clearCachedUrl(activeEnv);
523
+ try {
524
+ const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${activeEnv}`, {
525
+ method: "GET",
526
+ credentials: "include"
527
+ });
528
+ const refreshedStatus = await statusRes.json().catch(() => ({}));
529
+ setStatusInfo(refreshedStatus || null);
530
+ } catch {
531
+ }
532
+ setConnState("connected");
533
+ setShowManual(false);
534
+ } catch (e) {
535
+ completedRef.current = false;
536
+ console.error(e);
537
+ setConnState("error");
538
+ setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
539
+ } finally {
540
+ setOnboardingInProgress(false);
541
+ }
542
+ },
543
+ [stopPoll]
544
+ );
545
+ const startStatusPoll = react.useCallback(() => {
546
+ stopPoll();
547
+ let ticks = 0;
548
+ pollRef.current = setInterval(async () => {
549
+ var _a;
550
+ ticks += 1;
551
+ if (completedRef.current || ticks > 150) {
552
+ stopPoll();
553
+ return;
554
+ }
555
+ try {
556
+ const r = await fetch(`${STATUS_ENDPOINT}?environment=${envRef.current}`, {
557
+ method: "GET",
558
+ credentials: "include"
559
+ });
560
+ const st = await r.json().catch(() => ({}));
561
+ if ((st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true) {
562
+ completedRef.current = true;
563
+ stopPoll();
564
+ try {
565
+ (_a = popupRef.current) == null ? void 0 : _a.close();
566
+ } catch {
567
+ }
568
+ clearCachedUrl(envRef.current);
569
+ setStatusInfo(st);
570
+ setConnState("connected");
571
+ setShowManual(false);
572
+ setOnboardingInProgress(false);
573
+ }
574
+ } catch {
575
+ }
576
+ }, 2e3);
577
+ }, [stopPoll]);
394
578
  const generateLinkAndReload = react.useCallback(
395
579
  async (targetEnv, runId) => {
396
580
  if (initLoaderRef.current) {
397
581
  const loaderText = initLoaderRef.current.querySelector("#loader-text");
398
- if (loaderText) {
399
- loaderText.textContent = "Generating onboarding session...";
400
- }
582
+ if (loaderText) loaderText.textContent = "Generating onboarding session...";
401
583
  }
402
584
  try {
403
585
  const res = await fetch(SERVICE_URL, {
@@ -451,6 +633,7 @@ function PayPalConnectionPage() {
451
633
  const run = async () => {
452
634
  setConnState("loading");
453
635
  setError(null);
636
+ setPopupBlocked(false);
454
637
  setFinalUrl("");
455
638
  try {
456
639
  const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
@@ -489,13 +672,6 @@ function PayPalConnectionPage() {
489
672
  const scriptUrl = PARTNER_JS_URLS[env];
490
673
  let cancelled = false;
491
674
  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
675
  const initPartner = (attempt = 0) => {
500
676
  var _a2, _b2;
501
677
  if (cancelled) return;
@@ -507,7 +683,6 @@ function PayPalConnectionPage() {
507
683
  } catch (e) {
508
684
  console.error("[paypal] partner.js init failed:", e);
509
685
  }
510
- markReady();
511
686
  return;
512
687
  }
513
688
  if (typeof (signup == null ? void 0 : signup.render) === "function") {
@@ -516,7 +691,6 @@ function PayPalConnectionPage() {
516
691
  } catch (e) {
517
692
  console.error("[paypal] partner.js render failed:", e);
518
693
  }
519
- markReady();
520
694
  return;
521
695
  }
522
696
  if (attempt < 40) {
@@ -527,7 +701,6 @@ function PayPalConnectionPage() {
527
701
  document.dispatchEvent(new Event("DOMContentLoaded"));
528
702
  } catch {
529
703
  }
530
- markReady();
531
704
  };
532
705
  const existingScript = document.getElementById("paypal-partner-js");
533
706
  if (existingScript) {
@@ -544,74 +717,39 @@ function PayPalConnectionPage() {
544
717
  ppScript.src = scriptUrl;
545
718
  ppScript.async = true;
546
719
  ppScript.onload = () => initPartner();
547
- ppScript.onerror = () => markReady();
548
720
  document.body.appendChild(ppScript);
549
721
  return () => {
550
722
  cancelled = true;
551
- clearTimeout(readyFallback);
552
- if (pollTimer) {
553
- clearTimeout(pollTimer);
554
- }
555
- if (ppScript.parentNode) {
556
- ppScript.parentNode.removeChild(ppScript);
557
- }
723
+ if (pollTimer) clearTimeout(pollTimer);
724
+ if (ppScript.parentNode) ppScript.parentNode.removeChild(ppScript);
558
725
  };
559
726
  }, [connState, finalUrl, env]);
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})`);
583
- }
727
+ react.useEffect(() => {
728
+ const onMessage = (ev) => {
729
+ let serialized = "";
584
730
  try {
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();
731
+ serialized = typeof ev.data === "string" ? ev.data : JSON.stringify(ev.data);
587
732
  } catch {
733
+ serialized = String(ev.data);
588
734
  }
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 {
735
+ const looksRelevant = isPayPalOrigin(ev.origin) || /auth_?code|shared_?id|onboard|merchantId/i.test(serialized || "");
736
+ if (looksRelevant) {
737
+ console.info(
738
+ "[PayPal onboarding] message from",
739
+ ev.origin,
740
+ "·",
741
+ (serialized || "").slice(0, 500)
742
+ );
593
743
  }
594
- clearCachedUrl(activeEnv);
595
- try {
596
- const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${activeEnv}`, {
597
- method: "GET",
598
- credentials: "include"
599
- });
600
- const refreshedStatus = await statusRes.json().catch(() => ({}));
601
- setStatusInfo(refreshedStatus || null);
602
- } catch {
744
+ if (!isPayPalOrigin(ev.origin)) return;
745
+ const { authCode, sharedId } = extractAuth(ev.data);
746
+ if (authCode && sharedId) {
747
+ completeOnboarding(authCode, sharedId);
603
748
  }
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
- }, []);
749
+ };
750
+ window.addEventListener("message", onMessage);
751
+ return () => window.removeEventListener("message", onMessage);
752
+ }, [completeOnboarding]);
615
753
  react.useLayoutEffect(() => {
616
754
  window.onboardingCallback = (authCode, sharedId) => {
617
755
  completeOnboarding(authCode, sharedId);
@@ -620,6 +758,32 @@ function PayPalConnectionPage() {
620
758
  window.onboardingCallback = void 0;
621
759
  };
622
760
  }, [completeOnboarding]);
761
+ react.useEffect(() => {
762
+ const onCaptureClick = (e) => {
763
+ const btn = paypalButtonRef.current;
764
+ if (!btn) return;
765
+ const target = e.target;
766
+ if (!target || !btn.contains(target)) return;
767
+ e.preventDefault();
768
+ e.stopImmediatePropagation();
769
+ if (connStateRef.current !== "ready" || !finalUrlRef.current || inProgressRef.current) {
770
+ return;
771
+ }
772
+ completedRef.current = false;
773
+ const popup = openOnboardingPopup(finalUrlRef.current);
774
+ if (!popup) {
775
+ setPopupBlocked(true);
776
+ return;
777
+ }
778
+ setPopupBlocked(false);
779
+ startStatusPoll();
780
+ };
781
+ document.addEventListener("click", onCaptureClick, true);
782
+ return () => document.removeEventListener("click", onCaptureClick, true);
783
+ }, [openOnboardingPopup, startStatusPoll]);
784
+ react.useEffect(() => {
785
+ return () => stopPoll();
786
+ }, [stopPoll]);
623
787
  react.useLayoutEffect(() => {
624
788
  const el = ppBtnMeasureRef.current;
625
789
  if (!el) return;
@@ -640,6 +804,9 @@ function PayPalConnectionPage() {
640
804
  else window.removeEventListener("resize", update);
641
805
  };
642
806
  }, [connState, env, finalUrl]);
807
+ const handleConnectClick = (e) => {
808
+ e.preventDefault();
809
+ };
643
810
  const handleSaveManual = async () => {
644
811
  if (!canSaveManual || onboardingInProgress) return;
645
812
  setOnboardingInProgress(true);
@@ -714,6 +881,7 @@ function PayPalConnectionPage() {
714
881
  if (next === env || onboardingInProgress) return;
715
882
  completedRef.current = false;
716
883
  clearCachedUrl();
884
+ setPopupBlocked(false);
717
885
  setConnState("loading");
718
886
  try {
719
887
  await fetch(ENVIRONMENT_ENDPOINT, {
@@ -784,6 +952,7 @@ function PayPalConnectionPage() {
784
952
  "a",
785
953
  {
786
954
  ref: (node) => {
955
+ paypalButtonRef.current = node;
787
956
  ppBtnMeasureRef.current = node;
788
957
  },
789
958
  id: "paypal-button",
@@ -791,19 +960,17 @@ function PayPalConnectionPage() {
791
960
  "data-paypal-button": "true",
792
961
  href: finalUrl || "#",
793
962
  "data-paypal-onboard-complete": "onboardingCallback",
794
- "aria-disabled": onboardingInProgress || !partnerReady,
963
+ onClick: handleConnectClick,
795
964
  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
965
  style: {
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"
966
+ cursor: onboardingInProgress ? "not-allowed" : "pointer",
967
+ opacity: onboardingInProgress ? 0.6 : 1,
968
+ pointerEvents: onboardingInProgress ? "none" : "auto"
803
969
  },
804
- children: partnerReady || onboardingInProgress ? "Connect to PayPal" : "Preparing PayPal…"
970
+ children: "Connect to PayPal"
805
971
  }
806
972
  ),
973
+ 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
974
  /* @__PURE__ */ jsxRuntime.jsx(
808
975
  "div",
809
976
  {
@@ -959,6 +1126,9 @@ function PayPalConnectionPage() {
959
1126
  ` })
960
1127
  ] });
961
1128
  }
1129
+ function PayPalGooglePayPage() {
1130
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1131
+ }
962
1132
  function PayPalPayLaterMessagingPage() {
963
1133
  return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
964
1134
  }
@@ -1180,22 +1350,22 @@ const routeModule = {
1180
1350
  Component: AdditionalSettingsTab,
1181
1351
  path: "/settings/paypal/additional-settings"
1182
1352
  },
1183
- {
1184
- Component: AdvancedCardPaymentsTab,
1185
- path: "/settings/paypal/advanced-card-payments"
1186
- },
1187
1353
  {
1188
1354
  Component: PayPalApplePayPage,
1189
1355
  path: "/settings/paypal/apple-pay"
1190
1356
  },
1191
1357
  {
1192
- Component: PayPalGooglePayPage,
1193
- path: "/settings/paypal/google-pay"
1358
+ Component: AdvancedCardPaymentsTab,
1359
+ path: "/settings/paypal/advanced-card-payments"
1194
1360
  },
1195
1361
  {
1196
1362
  Component: PayPalConnectionPage,
1197
1363
  path: "/settings/paypal/connection"
1198
1364
  },
1365
+ {
1366
+ Component: PayPalGooglePayPage,
1367
+ path: "/settings/paypal/google-pay"
1368
+ },
1199
1369
  {
1200
1370
  Component: PayPalPayLaterMessagingPage,
1201
1371
  path: "/settings/paypal/pay-later-messaging"