@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
@@ -307,21 +307,11 @@ function AdvancedCardPaymentsTab() {
307
307
  )
308
308
  ] }) });
309
309
  }
310
- function PayPalApplePayPage() {
311
- return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
312
- }
313
- function PayPalGooglePayPage() {
314
- return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
315
- }
316
310
  const config = defineRouteConfig({
317
311
  label: "PayPal Connection"
318
312
  });
319
- const PARTNER_JS_URLS = {
320
- sandbox: "https://www.sandbox.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js",
321
- live: "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js"
322
- };
313
+ const PARTNER_JS_URL = "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js";
323
314
  const SERVICE_URL = "/admin/paypal/onboarding-link";
324
- const POPUP_NAME = "PPFrame";
325
315
  const CACHE_PREFIX = "pp_onboard_cache";
326
316
  const CACHE_EXPIRY = 6 * 60 * 60 * 1e3;
327
317
  const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
@@ -346,9 +336,7 @@ function readCachedUrl(env) {
346
336
  function writeCachedUrl(env, url) {
347
337
  try {
348
338
  localStorage.setItem(cacheKeyFor(env), JSON.stringify({ url, ts: Date.now() }));
349
- return readCachedUrl(env) === url;
350
339
  } catch {
351
- return false;
352
340
  }
353
341
  }
354
342
  function clearCachedUrl(env) {
@@ -362,62 +350,11 @@ function clearCachedUrl(env) {
362
350
  } catch {
363
351
  }
364
352
  }
365
- function isPayPalOrigin(origin) {
366
- try {
367
- const host = new URL(origin).hostname.toLowerCase();
368
- return host === "www.paypal.com" || host === "www.sandbox.paypal.com" || host.endsWith(".paypal.com") || host.endsWith(".paypalobjects.com");
369
- } catch {
370
- return false;
371
- }
372
- }
373
- function extractAuth(data) {
374
- if (!data) return {};
375
- if (typeof data === "object") {
376
- const obj = data;
377
- const authCode = obj.authCode ?? obj.auth_code ?? obj.authcode ?? obj.code;
378
- const sharedId = obj.sharedId ?? obj.shared_id ?? obj.sharedid;
379
- if (authCode && sharedId) {
380
- return { authCode: String(authCode), sharedId: String(sharedId) };
381
- }
382
- for (const key of ["data", "payload", "message", "detail", "body", "params"]) {
383
- if (obj[key] && typeof obj[key] === "object") {
384
- const inner = extractAuth(obj[key]);
385
- if (inner.authCode && inner.sharedId) return inner;
386
- }
387
- if (typeof obj[key] === "string") {
388
- const inner = extractAuth(obj[key]);
389
- if (inner.authCode && inner.sharedId) return inner;
390
- }
391
- }
392
- return {};
393
- }
394
- if (typeof data === "string") {
395
- const s = data.trim();
396
- if (!s) return {};
397
- if (s.startsWith("{") || s.startsWith("[")) {
398
- try {
399
- return extractAuth(JSON.parse(s));
400
- } catch {
401
- }
402
- }
403
- if (/auth_?code/i.test(s) && /shared_?id/i.test(s)) {
404
- try {
405
- const sp = new URLSearchParams(s.replace(/^[?#]/, ""));
406
- const authCode = sp.get("authCode") || sp.get("auth_code") || void 0;
407
- const sharedId = sp.get("sharedId") || sp.get("shared_id") || void 0;
408
- if (authCode && sharedId) return { authCode, sharedId };
409
- } catch {
410
- }
411
- }
412
- }
413
- return {};
414
- }
415
353
  function PayPalConnectionPage() {
416
354
  const [env, setEnv] = useState("live");
417
355
  const [envReady, setEnvReady] = useState(false);
418
356
  const [connState, setConnState] = useState("loading");
419
357
  const [error, setError] = useState(null);
420
- const [popupBlocked, setPopupBlocked] = useState(false);
421
358
  const [finalUrl, setFinalUrl] = useState("");
422
359
  const [showManual, setShowManual] = useState(false);
423
360
  const [clientId, setClientId] = useState("");
@@ -429,17 +366,11 @@ function PayPalConnectionPage() {
429
366
  const errorLogRef = useRef(null);
430
367
  const runIdRef = useRef(0);
431
368
  const currentRunId = useRef(0);
369
+ const completedRef = useRef(false);
432
370
  const envRef = useRef(env);
433
371
  envRef.current = env;
434
- const finalUrlRef = useRef(finalUrl);
435
- finalUrlRef.current = finalUrl;
436
- const connStateRef = useRef(connState);
437
- connStateRef.current = connState;
438
- const inProgressRef = useRef(onboardingInProgress);
439
- inProgressRef.current = onboardingInProgress;
440
- const popupRef = useRef(null);
441
- const pollRef = useRef(null);
442
- const completedRef = useRef(false);
372
+ const pollTimerRef = useRef(null);
373
+ const pollAttemptsRef = useRef(0);
443
374
  const ppBtnMeasureRef = useRef(null);
444
375
  const [ppBtnWidth, setPpBtnWidth] = useState(null);
445
376
  const canSaveManual = useMemo(() => {
@@ -449,44 +380,72 @@ function PayPalConnectionPage() {
449
380
  setConnState("error");
450
381
  setError(msg);
451
382
  }, []);
452
- const stopPoll = useCallback(() => {
453
- if (pollRef.current) {
454
- clearInterval(pollRef.current);
455
- pollRef.current = null;
383
+ const closeMiniBrowser = useCallback(() => {
384
+ var _a, _b, _c, _d, _e, _f, _g, _h;
385
+ try {
386
+ 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;
387
+ if (typeof close1 === "function") close1();
388
+ } catch {
456
389
  }
457
- }, []);
458
- const openOnboardingPopup = useCallback((url) => {
459
- const w = 450;
460
- const h = 600;
461
- const baseLeft = typeof window.screenX === "number" ? window.screenX : window.screenLeft || 0;
462
- const baseTop = typeof window.screenY === "number" ? window.screenY : window.screenTop || 0;
463
- const outerW = window.outerWidth || document.documentElement.clientWidth || 1024;
464
- const outerH = window.outerHeight || document.documentElement.clientHeight || 768;
465
- const left = Math.round(baseLeft + Math.max(0, (outerW - w) / 2));
466
- const top = Math.round(baseTop + Math.max(0, (outerH - h) / 2));
467
- const features = `popup=yes,width=${w},height=${h},left=${left},top=${top},scrollbars=yes,resizable=yes`;
468
- let popup = null;
469
390
  try {
470
- popup = window.open(url, POPUP_NAME, features);
391
+ 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;
392
+ if (typeof close2 === "function") close2();
471
393
  } catch {
472
- popup = null;
473
394
  }
474
- if (popup) {
475
- popupRef.current = popup;
395
+ }, []);
396
+ const stopStatusPolling = useCallback(() => {
397
+ if (pollTimerRef.current) {
398
+ clearTimeout(pollTimerRef.current);
399
+ pollTimerRef.current = null;
400
+ }
401
+ pollAttemptsRef.current = 0;
402
+ }, []);
403
+ const refreshStatusAndMaybeConnect = useCallback(
404
+ async (activeEnv) => {
476
405
  try {
477
- popup.focus();
406
+ const res = await fetch(`${STATUS_ENDPOINT}?environment=${activeEnv}`, {
407
+ method: "GET",
408
+ credentials: "include"
409
+ });
410
+ const st = await res.json().catch(() => ({}));
411
+ const connected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
412
+ if (connected) {
413
+ completedRef.current = true;
414
+ setStatusInfo(st);
415
+ setConnState("connected");
416
+ setShowManual(false);
417
+ setOnboardingInProgress(false);
418
+ clearCachedUrl(activeEnv);
419
+ closeMiniBrowser();
420
+ stopStatusPolling();
421
+ }
422
+ return connected;
478
423
  } catch {
424
+ return false;
479
425
  }
480
- }
481
- return popup;
482
- }, []);
426
+ },
427
+ [closeMiniBrowser, stopStatusPolling]
428
+ );
429
+ const startStatusPolling = useCallback(() => {
430
+ stopStatusPolling();
431
+ const MAX_ATTEMPTS = 100;
432
+ const tick = async () => {
433
+ pollAttemptsRef.current += 1;
434
+ const connected = await refreshStatusAndMaybeConnect(envRef.current);
435
+ if (connected || completedRef.current) return;
436
+ if (pollAttemptsRef.current >= MAX_ATTEMPTS) {
437
+ stopStatusPolling();
438
+ return;
439
+ }
440
+ pollTimerRef.current = setTimeout(tick, 3e3);
441
+ };
442
+ pollTimerRef.current = setTimeout(tick, 3e3);
443
+ }, [refreshStatusAndMaybeConnect, stopStatusPolling]);
483
444
  const completeOnboarding = useCallback(
484
445
  async (authCode, sharedId) => {
485
- var _a, _b, _c, _d, _e, _f, _g, _h;
486
446
  if (!authCode || !sharedId) return;
487
447
  if (completedRef.current) return;
488
448
  completedRef.current = true;
489
- stopPoll();
490
449
  try {
491
450
  window.onbeforeunload = null;
492
451
  } catch {
@@ -495,7 +454,6 @@ function PayPalConnectionPage() {
495
454
  setOnboardingInProgress(true);
496
455
  setConnState("loading");
497
456
  setError(null);
498
- setPopupBlocked(false);
499
457
  try {
500
458
  const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
501
459
  method: "POST",
@@ -507,32 +465,20 @@ function PayPalConnectionPage() {
507
465
  const txt = await res.text().catch(() => "");
508
466
  throw new Error(txt || `Onboarding exchange failed (${res.status})`);
509
467
  }
510
- try {
511
- (_a = popupRef.current) == null ? void 0 : _a.close();
512
- } catch {
513
- }
514
- try {
515
- 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;
516
- if (typeof close1 === "function") close1();
517
- } catch {
518
- }
519
- try {
520
- 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;
521
- if (typeof close2 === "function") close2();
522
- } catch {
523
- }
468
+ closeMiniBrowser();
524
469
  clearCachedUrl(activeEnv);
525
470
  try {
526
- const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${activeEnv}`, {
527
- method: "GET",
528
- credentials: "include"
529
- });
471
+ const statusRes = await fetch(
472
+ `${STATUS_ENDPOINT}?environment=${activeEnv}`,
473
+ { method: "GET", credentials: "include" }
474
+ );
530
475
  const refreshedStatus = await statusRes.json().catch(() => ({}));
531
476
  setStatusInfo(refreshedStatus || null);
532
477
  } catch {
533
478
  }
534
479
  setConnState("connected");
535
480
  setShowManual(false);
481
+ stopStatusPolling();
536
482
  } catch (e) {
537
483
  completedRef.current = false;
538
484
  console.error(e);
@@ -542,42 +488,72 @@ function PayPalConnectionPage() {
542
488
  setOnboardingInProgress(false);
543
489
  }
544
490
  },
545
- [stopPoll]
491
+ [closeMiniBrowser, stopStatusPolling]
546
492
  );
547
- const startStatusPoll = useCallback(() => {
548
- stopPoll();
549
- let ticks = 0;
550
- pollRef.current = setInterval(async () => {
551
- var _a;
552
- ticks += 1;
553
- if (completedRef.current || ticks > 150) {
554
- stopPoll();
555
- return;
556
- }
493
+ const initPartner = useCallback(() => {
494
+ var _a, _b;
495
+ const signup = (_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup;
496
+ const init = (signup == null ? void 0 : signup.miniBrowser) && signup.miniBrowser.init || (signup == null ? void 0 : signup.MiniBrowser) && signup.MiniBrowser.init;
497
+ if (typeof init === "function") {
557
498
  try {
558
- const r = await fetch(`${STATUS_ENDPOINT}?environment=${envRef.current}`, {
559
- method: "GET",
560
- credentials: "include"
561
- });
562
- const st = await r.json().catch(() => ({}));
563
- if ((st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true) {
564
- completedRef.current = true;
565
- stopPoll();
566
- try {
567
- (_a = popupRef.current) == null ? void 0 : _a.close();
568
- } catch {
569
- }
570
- clearCachedUrl(envRef.current);
571
- setStatusInfo(st);
572
- setConnState("connected");
573
- setShowManual(false);
574
- setOnboardingInProgress(false);
575
- }
576
- } catch {
499
+ init();
500
+ } catch (e) {
501
+ console.error("[paypal] partner.js init failed:", e);
502
+ }
503
+ }
504
+ }, []);
505
+ useEffect(() => {
506
+ const existingScript = document.getElementById("paypal-partner-js");
507
+ if (existingScript) return;
508
+ const preloadHref = PARTNER_JS_URL;
509
+ let preloadLink = null;
510
+ if (!document.head.querySelector(`link[rel="preload"][href="${preloadHref}"]`)) {
511
+ preloadLink = document.createElement("link");
512
+ preloadLink.rel = "preload";
513
+ preloadLink.href = preloadHref;
514
+ preloadLink.as = "script";
515
+ document.head.appendChild(preloadLink);
516
+ }
517
+ const ppScript = document.createElement("script");
518
+ ppScript.id = "paypal-partner-js";
519
+ ppScript.src = preloadHref;
520
+ ppScript.async = true;
521
+ document.head.appendChild(ppScript);
522
+ return () => {
523
+ if (preloadLink == null ? void 0 : preloadLink.parentNode) preloadLink.parentNode.removeChild(preloadLink);
524
+ if (ppScript.parentNode) ppScript.parentNode.removeChild(ppScript);
525
+ };
526
+ }, []);
527
+ const activatePayPal = useCallback(
528
+ (url, runId) => {
529
+ if (paypalButtonRef.current) {
530
+ paypalButtonRef.current.href = url;
577
531
  }
578
- }, 2e3);
579
- }, [stopPoll]);
580
- const generateLinkAndReload = useCallback(
532
+ setFinalUrl(url);
533
+ let attempts = 0;
534
+ const MAX_ATTEMPTS = 200;
535
+ const tryInit = () => {
536
+ var _a, _b;
537
+ if (runId !== currentRunId.current) return;
538
+ if ((_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) {
539
+ initPartner();
540
+ setConnState("ready");
541
+ return;
542
+ }
543
+ attempts++;
544
+ if (attempts >= MAX_ATTEMPTS) {
545
+ showError(
546
+ "PayPal partner script failed to load. Please refresh and try again."
547
+ );
548
+ return;
549
+ }
550
+ setTimeout(tryInit, 50);
551
+ };
552
+ tryInit();
553
+ },
554
+ [initPartner, showError]
555
+ );
556
+ const fetchFreshLink = useCallback(
581
557
  async (targetEnv, runId) => {
582
558
  if (initLoaderRef.current) {
583
559
  const loaderText = initLoaderRef.current.querySelector("#loader-text");
@@ -599,19 +575,14 @@ function PayPalConnectionPage() {
599
575
  return;
600
576
  }
601
577
  const url = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
602
- const persisted = writeCachedUrl(targetEnv, url);
603
- if (persisted) {
604
- window.location.reload();
605
- return;
606
- }
607
- setFinalUrl(url);
608
- setConnState("ready");
578
+ writeCachedUrl(targetEnv, url);
579
+ activatePayPal(url, runId);
609
580
  } catch {
610
581
  if (runId !== currentRunId.current) return;
611
582
  showError("Unable to connect to service.");
612
583
  }
613
584
  },
614
- [showError]
585
+ [activatePayPal, showError]
615
586
  );
616
587
  useEffect(() => {
617
588
  let alive = true;
@@ -635,7 +606,6 @@ function PayPalConnectionPage() {
635
606
  const run = async () => {
636
607
  setConnState("loading");
637
608
  setError(null);
638
- setPopupBlocked(false);
639
609
  setFinalUrl("");
640
610
  try {
641
611
  const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
@@ -657,149 +627,43 @@ function PayPalConnectionPage() {
657
627
  if (cancelled || runId !== currentRunId.current) return;
658
628
  const cached = readCachedUrl(env);
659
629
  if (cached) {
660
- setFinalUrl(cached);
661
- setConnState("ready");
630
+ activatePayPal(cached, runId);
662
631
  return;
663
632
  }
664
- await generateLinkAndReload(env, runId);
633
+ await fetchFreshLink(env, runId);
665
634
  };
666
635
  run();
667
636
  return () => {
668
637
  cancelled = true;
669
638
  };
670
- }, [env, envReady, generateLinkAndReload]);
671
- useEffect(() => {
672
- var _a, _b, _c;
673
- if (connState !== "ready" || !finalUrl) return;
674
- const scriptUrl = PARTNER_JS_URLS[env];
675
- let cancelled = false;
676
- let pollTimer;
677
- const initPartner = (attempt = 0) => {
678
- var _a2, _b2;
679
- if (cancelled) return;
680
- const signup = (_b2 = (_a2 = window.PAYPAL) == null ? void 0 : _a2.apps) == null ? void 0 : _b2.Signup;
681
- 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;
682
- if (target == null ? void 0 : target.init) {
683
- try {
684
- target.init();
685
- } catch (e) {
686
- console.error("[paypal] partner.js init failed:", e);
687
- }
688
- return;
689
- }
690
- if (typeof (signup == null ? void 0 : signup.render) === "function") {
691
- try {
692
- signup.render();
693
- } catch (e) {
694
- console.error("[paypal] partner.js render failed:", e);
695
- }
696
- return;
697
- }
698
- if (attempt < 40) {
699
- pollTimer = setTimeout(() => initPartner(attempt + 1), 50);
700
- return;
701
- }
702
- try {
703
- document.dispatchEvent(new Event("DOMContentLoaded"));
704
- } catch {
705
- }
706
- };
707
- const existingScript = document.getElementById("paypal-partner-js");
708
- if (existingScript) {
709
- (_a = existingScript.parentNode) == null ? void 0 : _a.removeChild(existingScript);
710
- }
711
- if ((_c = (_b = window.PAYPAL) == null ? void 0 : _b.apps) == null ? void 0 : _c.Signup) {
712
- try {
713
- delete window.PAYPAL.apps.Signup;
714
- } catch {
715
- }
716
- }
717
- const ppScript = document.createElement("script");
718
- ppScript.id = "paypal-partner-js";
719
- ppScript.src = scriptUrl;
720
- ppScript.async = true;
721
- ppScript.onload = () => initPartner();
722
- document.body.appendChild(ppScript);
723
- return () => {
724
- cancelled = true;
725
- if (pollTimer) clearTimeout(pollTimer);
726
- if (ppScript.parentNode) ppScript.parentNode.removeChild(ppScript);
727
- };
728
- }, [connState, finalUrl, env]);
729
- useEffect(() => {
730
- const onMessage = (ev) => {
731
- var _a;
732
- let serialized = "";
733
- try {
734
- serialized = typeof ev.data === "string" ? ev.data : JSON.stringify(ev.data);
735
- } catch {
736
- serialized = String(ev.data);
737
- }
738
- const looksRelevant = isPayPalOrigin(ev.origin) || /auth_?code|shared_?id|onboard|merchantId/i.test(serialized || "");
739
- if (looksRelevant) {
740
- console.info(
741
- "[PayPal onboarding] message from",
742
- ev.origin,
743
- "·",
744
- (serialized || "").slice(0, 500)
745
- );
746
- }
747
- const d = ev.data;
748
- if (d && typeof d === "object" && d.source === "paypal-onboarding-return") {
749
- try {
750
- (_a = popupRef.current) == null ? void 0 : _a.close();
751
- } catch {
752
- }
753
- const fromReturn = extractAuth(d.params);
754
- if (fromReturn.authCode && fromReturn.sharedId) {
755
- completeOnboarding(fromReturn.authCode, fromReturn.sharedId);
756
- } else if (!completedRef.current) {
757
- startStatusPoll();
758
- }
759
- return;
760
- }
761
- if (!isPayPalOrigin(ev.origin)) return;
762
- const { authCode, sharedId } = extractAuth(ev.data);
763
- if (authCode && sharedId) {
764
- completeOnboarding(authCode, sharedId);
765
- }
766
- };
767
- window.addEventListener("message", onMessage);
768
- return () => window.removeEventListener("message", onMessage);
769
- }, [completeOnboarding, startStatusPoll]);
639
+ }, [env, envReady, fetchFreshLink, activatePayPal]);
770
640
  useLayoutEffect(() => {
771
641
  window.onboardingCallback = (authCode, sharedId) => {
772
- completeOnboarding(authCode, sharedId);
642
+ void completeOnboarding(authCode, sharedId);
773
643
  };
774
644
  return () => {
775
645
  window.onboardingCallback = void 0;
776
646
  };
777
647
  }, [completeOnboarding]);
778
648
  useEffect(() => {
779
- const onCaptureClick = (e) => {
780
- const btn = paypalButtonRef.current;
781
- if (!btn) return;
782
- const target = e.target;
783
- if (!target || !btn.contains(target)) return;
784
- e.preventDefault();
785
- if (connStateRef.current !== "ready" || !finalUrlRef.current || inProgressRef.current) {
786
- return;
787
- }
788
- completedRef.current = false;
789
- const popup = openOnboardingPopup(finalUrlRef.current);
790
- if (!popup) {
791
- setPopupBlocked(true);
792
- return;
793
- }
794
- setPopupBlocked(false);
795
- startStatusPoll();
649
+ const onMessage = (event) => {
650
+ const data = event == null ? void 0 : event.data;
651
+ if (!data || data.source !== "paypal-onboarding-return") return;
652
+ const params = data.params || {};
653
+ const authCode = params.authCode || params.auth_code;
654
+ const sharedId = params.sharedId || params.shared_id;
655
+ const activeEnv = envRef.current;
656
+ void (async () => {
657
+ const connected = await refreshStatusAndMaybeConnect(activeEnv);
658
+ if (!connected && authCode && sharedId) {
659
+ await completeOnboarding(authCode, sharedId);
660
+ }
661
+ })();
796
662
  };
797
- document.addEventListener("click", onCaptureClick, true);
798
- return () => document.removeEventListener("click", onCaptureClick, true);
799
- }, [openOnboardingPopup, startStatusPoll]);
800
- useEffect(() => {
801
- return () => stopPoll();
802
- }, [stopPoll]);
663
+ window.addEventListener("message", onMessage);
664
+ return () => window.removeEventListener("message", onMessage);
665
+ }, [completeOnboarding, refreshStatusAndMaybeConnect]);
666
+ useEffect(() => stopStatusPolling, [stopStatusPolling]);
803
667
  useLayoutEffect(() => {
804
668
  const el = ppBtnMeasureRef.current;
805
669
  if (!el) return;
@@ -821,7 +685,12 @@ function PayPalConnectionPage() {
821
685
  };
822
686
  }, [connState, env, finalUrl]);
823
687
  const handleConnectClick = (e) => {
824
- e.preventDefault();
688
+ if (connState !== "ready" || !finalUrl || onboardingInProgress) {
689
+ e.preventDefault();
690
+ return;
691
+ }
692
+ completedRef.current = false;
693
+ startStatusPolling();
825
694
  };
826
695
  const handleSaveManual = async () => {
827
696
  if (!canSaveManual || onboardingInProgress) return;
@@ -863,6 +732,7 @@ function PayPalConnectionPage() {
863
732
  const handleDisconnect = async () => {
864
733
  if (onboardingInProgress) return;
865
734
  if (!window.confirm("Disconnect PayPal for this environment?")) return;
735
+ stopStatusPolling();
866
736
  setOnboardingInProgress(true);
867
737
  setConnState("loading");
868
738
  setError(null);
@@ -883,7 +753,7 @@ function PayPalConnectionPage() {
883
753
  clearCachedUrl(env);
884
754
  completedRef.current = false;
885
755
  currentRunId.current = ++runIdRef.current;
886
- await generateLinkAndReload(env, currentRunId.current);
756
+ await fetchFreshLink(env, currentRunId.current);
887
757
  } catch (e) {
888
758
  console.error(e);
889
759
  setConnState("error");
@@ -895,9 +765,9 @@ function PayPalConnectionPage() {
895
765
  const handleEnvChange = async (e) => {
896
766
  const next = e.target.value;
897
767
  if (next === env || onboardingInProgress) return;
768
+ stopStatusPolling();
898
769
  completedRef.current = false;
899
770
  clearCachedUrl();
900
- setPopupBlocked(false);
901
771
  setConnState("loading");
902
772
  try {
903
773
  await fetch(ENVIRONMENT_ENDPOINT, {
@@ -931,7 +801,19 @@ function PayPalConnectionPage() {
931
801
  ) }),
932
802
  /* @__PURE__ */ jsx("div", { className: "text-sm font-medium pt-2", children: env === "sandbox" ? "Connect to PayPal (Sandbox)" : "Connect to PayPal" }),
933
803
  /* @__PURE__ */ jsx("div", { className: "max-w-xl", children: connState === "connected" ? /* @__PURE__ */ jsxs("div", { children: [
934
- /* @__PURE__ */ jsx("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: "✅ Successfully connected to PayPal!" }),
804
+ /* @__PURE__ */ jsxs("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: [
805
+ "✅ Successfully connected to PayPal!",
806
+ /* @__PURE__ */ jsx(
807
+ "a",
808
+ {
809
+ "data-paypal-button": "true",
810
+ "data-paypal-onboard-complete": "onboardingCallback",
811
+ href: "#",
812
+ style: { display: "none" },
813
+ children: "PayPal"
814
+ }
815
+ )
816
+ ] }),
935
817
  /* @__PURE__ */ 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: [
936
818
  /* @__PURE__ */ jsx("div", { className: "font-medium text-ui-fg-base", children: "Connected PayPal account" }),
937
819
  /* @__PURE__ */ jsxs("div", { className: "mt-1", children: [
@@ -972,7 +854,6 @@ function PayPalConnectionPage() {
972
854
  ppBtnMeasureRef.current = node;
973
855
  },
974
856
  id: "paypal-button",
975
- target: POPUP_NAME,
976
857
  "data-paypal-button": "true",
977
858
  href: finalUrl || "#",
978
859
  "data-paypal-onboard-complete": "onboardingCallback",
@@ -986,7 +867,6 @@ function PayPalConnectionPage() {
986
867
  children: "Connect to PayPal"
987
868
  }
988
869
  ),
989
- popupBlocked && /* @__PURE__ */ 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." }),
990
870
  /* @__PURE__ */ jsx(
991
871
  "div",
992
872
  {
@@ -1142,6 +1022,12 @@ function PayPalConnectionPage() {
1142
1022
  ` })
1143
1023
  ] });
1144
1024
  }
1025
+ function PayPalApplePayPage() {
1026
+ return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
1027
+ }
1028
+ function PayPalGooglePayPage() {
1029
+ return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
1030
+ }
1145
1031
  function PayPalPayLaterMessagingPage() {
1146
1032
  return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
1147
1033
  }
@@ -1367,6 +1253,10 @@ const routeModule = {
1367
1253
  Component: AdvancedCardPaymentsTab,
1368
1254
  path: "/settings/paypal/advanced-card-payments"
1369
1255
  },
1256
+ {
1257
+ Component: PayPalConnectionPage,
1258
+ path: "/settings/paypal/connection"
1259
+ },
1370
1260
  {
1371
1261
  Component: PayPalApplePayPage,
1372
1262
  path: "/settings/paypal/apple-pay"
@@ -1375,10 +1265,6 @@ const routeModule = {
1375
1265
  Component: PayPalGooglePayPage,
1376
1266
  path: "/settings/paypal/google-pay"
1377
1267
  },
1378
- {
1379
- Component: PayPalConnectionPage,
1380
- path: "/settings/paypal/connection"
1381
- },
1382
1268
  {
1383
1269
  Component: PayPalPayLaterMessagingPage,
1384
1270
  path: "/settings/paypal/pay-later-messaging"
@@ -12,7 +12,6 @@ declare global {
12
12
  init?: () => void;
13
13
  closeFlow?: () => void;
14
14
  };
15
- render?: () => void;
16
15
  };
17
16
  };
18
17
  };