@easypayment/medusa-payment-paypal 0.9.17 → 0.9.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.medusa/server/src/admin/index.js +326 -130
- package/.medusa/server/src/admin/index.mjs +326 -130
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.d.ts +4 -1
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.d.ts.map +1 -1
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js +434 -113
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/onboarding-link/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/paypal/onboarding-link/route.js +4 -0
- package/.medusa/server/src/api/admin/paypal/onboarding-link/route.js.map +1 -1
- package/.medusa/server/src/api/middlewares.d.ts.map +1 -1
- package/.medusa/server/src/api/middlewares.js +9 -0
- package/.medusa/server/src/api/middlewares.js.map +1 -1
- package/.medusa/server/src/api/store/paypal/webhook/route.d.ts.map +1 -1
- package/.medusa/server/src/api/store/paypal/webhook/route.js +13 -8
- package/.medusa/server/src/api/store/paypal/webhook/route.js.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/service.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/service.js +54 -31
- package/.medusa/server/src/modules/paypal/payment-provider/service.js.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/status-utils.d.ts +32 -0
- package/.medusa/server/src/modules/paypal/payment-provider/status-utils.d.ts.map +1 -0
- package/.medusa/server/src/modules/paypal/payment-provider/status-utils.js +65 -0
- package/.medusa/server/src/modules/paypal/payment-provider/status-utils.js.map +1 -0
- package/.medusa/server/src/modules/paypal/service.d.ts +13 -1
- package/.medusa/server/src/modules/paypal/service.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/service.js +19 -4
- package/.medusa/server/src/modules/paypal/service.js.map +1 -1
- package/.medusa/server/src/modules/paypal/utils/secret-crypto.d.ts +2 -1
- package/.medusa/server/src/modules/paypal/utils/secret-crypto.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/utils/secret-crypto.js +82 -26
- package/.medusa/server/src/modules/paypal/utils/secret-crypto.js.map +1 -1
- package/.medusa/server/src/modules/paypal/utils/webhook-verify.d.ts +28 -0
- package/.medusa/server/src/modules/paypal/utils/webhook-verify.d.ts.map +1 -0
- package/.medusa/server/src/modules/paypal/utils/webhook-verify.js +58 -0
- package/.medusa/server/src/modules/paypal/utils/webhook-verify.js.map +1 -0
- package/package.json +1 -1
- package/src/admin/routes/settings/paypal/connection/page.tsx +471 -127
- package/src/api/admin/paypal/onboarding-link/route.ts +6 -0
- package/src/api/middlewares.ts +9 -0
- package/src/api/store/paypal/webhook/route.ts +22 -8
- package/src/modules/paypal/payment-provider/service.ts +73 -29
- package/src/modules/paypal/payment-provider/status-utils.ts +59 -0
- package/src/modules/paypal/service.ts +24 -5
- package/src/modules/paypal/utils/secret-crypto.ts +90 -27
- package/src/modules/paypal/utils/webhook-verify.ts +61 -0
|
@@ -310,6 +310,9 @@ function AdvancedCardPaymentsTab() {
|
|
|
310
310
|
function PayPalApplePayPage() {
|
|
311
311
|
return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
312
312
|
}
|
|
313
|
+
function PayPalGooglePayPage() {
|
|
314
|
+
return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
315
|
+
}
|
|
313
316
|
const config = defineRouteConfig({
|
|
314
317
|
label: "PayPal Connection"
|
|
315
318
|
});
|
|
@@ -318,37 +321,97 @@ const PARTNER_JS_URLS = {
|
|
|
318
321
|
live: "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js"
|
|
319
322
|
};
|
|
320
323
|
const SERVICE_URL = "/admin/paypal/onboarding-link";
|
|
321
|
-
const
|
|
324
|
+
const POPUP_NAME = "PPMiniBrowser";
|
|
325
|
+
const CACHE_PREFIX = "pp_onboard_cache";
|
|
322
326
|
const CACHE_EXPIRY = 10 * 60 * 1e3;
|
|
323
327
|
const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
|
|
324
328
|
const STATUS_ENDPOINT = "/admin/paypal/status";
|
|
325
329
|
const SAVE_CREDENTIALS_ENDPOINT = "/admin/paypal/save-credentials";
|
|
326
330
|
const DISCONNECT_ENDPOINT = "/admin/paypal/disconnect";
|
|
327
|
-
|
|
328
|
-
|
|
331
|
+
const ENVIRONMENT_ENDPOINT = "/admin/paypal/environment";
|
|
332
|
+
const cacheKeyFor = (env) => `${CACHE_PREFIX}_${env}`;
|
|
333
|
+
function readCachedUrl(env) {
|
|
334
|
+
if (typeof window === "undefined") return null;
|
|
329
335
|
try {
|
|
330
|
-
const
|
|
331
|
-
if (
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
336
|
+
const raw = localStorage.getItem(cacheKeyFor(env));
|
|
337
|
+
if (!raw) return null;
|
|
338
|
+
const data = JSON.parse(raw);
|
|
339
|
+
if (data && typeof data.url === "string" && Date.now() - (Number(data.ts) || 0) < CACHE_EXPIRY) {
|
|
340
|
+
return data.url;
|
|
341
|
+
}
|
|
342
|
+
} catch {
|
|
343
|
+
}
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
function writeCachedUrl(env, url) {
|
|
347
|
+
try {
|
|
348
|
+
localStorage.setItem(cacheKeyFor(env), JSON.stringify({ url, ts: Date.now() }));
|
|
349
|
+
} catch {
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
function clearCachedUrl(env) {
|
|
353
|
+
try {
|
|
354
|
+
if (env) {
|
|
355
|
+
localStorage.removeItem(cacheKeyFor(env));
|
|
356
|
+
} else {
|
|
357
|
+
localStorage.removeItem(cacheKeyFor("sandbox"));
|
|
358
|
+
localStorage.removeItem(cacheKeyFor("live"));
|
|
359
|
+
}
|
|
360
|
+
} catch {
|
|
361
|
+
}
|
|
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;
|
|
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"]) {
|
|
381
|
+
if (obj[key] && typeof obj[key] === "object") {
|
|
382
|
+
const inner = extractAuth(obj[key]);
|
|
383
|
+
if (inner.authCode && inner.sharedId) return inner;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return {};
|
|
387
|
+
}
|
|
388
|
+
if (typeof data === "string") {
|
|
389
|
+
const s = data.trim();
|
|
390
|
+
if (!s) return {};
|
|
391
|
+
if (s.startsWith("{")) {
|
|
392
|
+
try {
|
|
393
|
+
return extractAuth(JSON.parse(s));
|
|
394
|
+
} catch {
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (/auth_?code/i.test(s) && /shared_?id/i.test(s)) {
|
|
398
|
+
try {
|
|
399
|
+
const sp = new URLSearchParams(s.replace(/^[?#]/, ""));
|
|
400
|
+
const authCode = sp.get("authCode") || sp.get("auth_code") || void 0;
|
|
401
|
+
const sharedId = sp.get("sharedId") || sp.get("shared_id") || void 0;
|
|
402
|
+
if (authCode && sharedId) return { authCode, sharedId };
|
|
403
|
+
} catch {
|
|
335
404
|
}
|
|
336
405
|
}
|
|
337
|
-
} catch (e) {
|
|
338
|
-
console.error("Cache read error:", e);
|
|
339
406
|
}
|
|
407
|
+
return {};
|
|
340
408
|
}
|
|
341
409
|
function PayPalConnectionPage() {
|
|
342
410
|
const [env, setEnv] = useState("live");
|
|
343
|
-
|
|
344
|
-
fetch("/admin/paypal/environment", { method: "GET", credentials: "include" }).then((r) => r.json()).then((d) => {
|
|
345
|
-
const v = (d == null ? void 0 : d.environment) === "sandbox" ? "sandbox" : "live";
|
|
346
|
-
setEnv(v);
|
|
347
|
-
}).catch(() => {
|
|
348
|
-
});
|
|
349
|
-
}, []);
|
|
411
|
+
const [envReady, setEnvReady] = useState(false);
|
|
350
412
|
const [connState, setConnState] = useState("loading");
|
|
351
413
|
const [error, setError] = useState(null);
|
|
414
|
+
const [popupBlocked, setPopupBlocked] = useState(false);
|
|
352
415
|
const [finalUrl, setFinalUrl] = useState("");
|
|
353
416
|
const [showManual, setShowManual] = useState(false);
|
|
354
417
|
const [clientId, setClientId] = useState("");
|
|
@@ -360,6 +423,17 @@ function PayPalConnectionPage() {
|
|
|
360
423
|
const errorLogRef = useRef(null);
|
|
361
424
|
const runIdRef = useRef(0);
|
|
362
425
|
const currentRunId = useRef(0);
|
|
426
|
+
const finalUrlRef = useRef(finalUrl);
|
|
427
|
+
finalUrlRef.current = finalUrl;
|
|
428
|
+
const connStateRef = useRef(connState);
|
|
429
|
+
connStateRef.current = connState;
|
|
430
|
+
const inProgressRef = useRef(onboardingInProgress);
|
|
431
|
+
inProgressRef.current = onboardingInProgress;
|
|
432
|
+
const envRef = useRef(env);
|
|
433
|
+
envRef.current = env;
|
|
434
|
+
const popupRef = useRef(null);
|
|
435
|
+
const popupPollRef = useRef(null);
|
|
436
|
+
const completedRef = useRef(false);
|
|
363
437
|
const ppBtnMeasureRef = useRef(null);
|
|
364
438
|
const [ppBtnWidth, setPpBtnWidth] = useState(null);
|
|
365
439
|
const canSaveManual = useMemo(() => {
|
|
@@ -369,8 +443,124 @@ function PayPalConnectionPage() {
|
|
|
369
443
|
setConnState("error");
|
|
370
444
|
setError(msg);
|
|
371
445
|
}, []);
|
|
446
|
+
const stopPopupPoll = useCallback(() => {
|
|
447
|
+
if (popupPollRef.current) {
|
|
448
|
+
clearInterval(popupPollRef.current);
|
|
449
|
+
popupPollRef.current = null;
|
|
450
|
+
}
|
|
451
|
+
}, []);
|
|
452
|
+
const openOnboardingPopup = useCallback(
|
|
453
|
+
(url) => {
|
|
454
|
+
const w = 450;
|
|
455
|
+
const h = 600;
|
|
456
|
+
const baseLeft = typeof window.screenX === "number" ? window.screenX : window.screenLeft || 0;
|
|
457
|
+
const baseTop = typeof window.screenY === "number" ? window.screenY : window.screenTop || 0;
|
|
458
|
+
const outerW = window.outerWidth || document.documentElement.clientWidth || 1024;
|
|
459
|
+
const outerH = window.outerHeight || document.documentElement.clientHeight || 768;
|
|
460
|
+
const left = Math.round(baseLeft + Math.max(0, (outerW - w) / 2));
|
|
461
|
+
const top = Math.round(baseTop + Math.max(0, (outerH - h) / 2));
|
|
462
|
+
const features = `popup=yes,width=${w},height=${h},left=${left},top=${top},scrollbars=yes,resizable=yes`;
|
|
463
|
+
let popup = null;
|
|
464
|
+
try {
|
|
465
|
+
popup = window.open(url, POPUP_NAME, features);
|
|
466
|
+
} catch {
|
|
467
|
+
popup = null;
|
|
468
|
+
}
|
|
469
|
+
if (popup) {
|
|
470
|
+
popupRef.current = popup;
|
|
471
|
+
try {
|
|
472
|
+
popup.focus();
|
|
473
|
+
} catch {
|
|
474
|
+
}
|
|
475
|
+
stopPopupPoll();
|
|
476
|
+
popupPollRef.current = setInterval(() => {
|
|
477
|
+
if (!popupRef.current || popupRef.current.closed) {
|
|
478
|
+
stopPopupPoll();
|
|
479
|
+
}
|
|
480
|
+
}, 1e3);
|
|
481
|
+
}
|
|
482
|
+
return popup;
|
|
483
|
+
},
|
|
484
|
+
[stopPopupPoll]
|
|
485
|
+
);
|
|
486
|
+
const openConnect = useCallback(() => {
|
|
487
|
+
if (connStateRef.current !== "ready" || !finalUrlRef.current || inProgressRef.current) {
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
completedRef.current = false;
|
|
491
|
+
const popup = openOnboardingPopup(finalUrlRef.current);
|
|
492
|
+
if (!popup) {
|
|
493
|
+
setPopupBlocked(true);
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
setPopupBlocked(false);
|
|
497
|
+
}, [openOnboardingPopup]);
|
|
498
|
+
const completeOnboarding = useCallback(
|
|
499
|
+
async (authCode, sharedId) => {
|
|
500
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
501
|
+
if (!authCode || !sharedId) return;
|
|
502
|
+
if (completedRef.current) return;
|
|
503
|
+
completedRef.current = true;
|
|
504
|
+
try {
|
|
505
|
+
window.onbeforeunload = null;
|
|
506
|
+
} catch {
|
|
507
|
+
}
|
|
508
|
+
const activeEnv = envRef.current === "sandbox" ? "sandbox" : "live";
|
|
509
|
+
setOnboardingInProgress(true);
|
|
510
|
+
setConnState("loading");
|
|
511
|
+
setError(null);
|
|
512
|
+
setPopupBlocked(false);
|
|
513
|
+
try {
|
|
514
|
+
const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
|
|
515
|
+
method: "POST",
|
|
516
|
+
headers: { "content-type": "application/json" },
|
|
517
|
+
credentials: "include",
|
|
518
|
+
body: JSON.stringify({ authCode, sharedId, env: activeEnv })
|
|
519
|
+
});
|
|
520
|
+
if (!res.ok) {
|
|
521
|
+
const txt = await res.text().catch(() => "");
|
|
522
|
+
throw new Error(txt || `Onboarding exchange failed (${res.status})`);
|
|
523
|
+
}
|
|
524
|
+
try {
|
|
525
|
+
(_a = popupRef.current) == null ? void 0 : _a.close();
|
|
526
|
+
} catch {
|
|
527
|
+
}
|
|
528
|
+
stopPopupPoll();
|
|
529
|
+
try {
|
|
530
|
+
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;
|
|
531
|
+
if (typeof close1 === "function") close1();
|
|
532
|
+
} catch {
|
|
533
|
+
}
|
|
534
|
+
try {
|
|
535
|
+
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;
|
|
536
|
+
if (typeof close2 === "function") close2();
|
|
537
|
+
} catch {
|
|
538
|
+
}
|
|
539
|
+
clearCachedUrl(activeEnv);
|
|
540
|
+
try {
|
|
541
|
+
const statusRes = await fetch(
|
|
542
|
+
`${STATUS_ENDPOINT}?environment=${activeEnv}`,
|
|
543
|
+
{ method: "GET", credentials: "include" }
|
|
544
|
+
);
|
|
545
|
+
const refreshedStatus = await statusRes.json().catch(() => ({}));
|
|
546
|
+
setStatusInfo(refreshedStatus || null);
|
|
547
|
+
} catch {
|
|
548
|
+
}
|
|
549
|
+
setConnState("connected");
|
|
550
|
+
setShowManual(false);
|
|
551
|
+
} catch (e) {
|
|
552
|
+
completedRef.current = false;
|
|
553
|
+
console.error(e);
|
|
554
|
+
setConnState("error");
|
|
555
|
+
setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
|
|
556
|
+
} finally {
|
|
557
|
+
setOnboardingInProgress(false);
|
|
558
|
+
}
|
|
559
|
+
},
|
|
560
|
+
[stopPopupPoll]
|
|
561
|
+
);
|
|
372
562
|
const fetchFreshLink = useCallback(
|
|
373
|
-
(runId) => {
|
|
563
|
+
(runId, targetEnv) => {
|
|
374
564
|
if (initLoaderRef.current) {
|
|
375
565
|
const loaderText = initLoaderRef.current.querySelector("#loader-text");
|
|
376
566
|
if (loaderText)
|
|
@@ -381,7 +571,10 @@ function PayPalConnectionPage() {
|
|
|
381
571
|
headers: { "content-type": "application/json" },
|
|
382
572
|
credentials: "include",
|
|
383
573
|
body: JSON.stringify({
|
|
384
|
-
products: ["PPCP"]
|
|
574
|
+
products: ["PPCP"],
|
|
575
|
+
// Generate the link for the explicitly selected environment so it can
|
|
576
|
+
// never depend on a racing POST /environment having landed yet.
|
|
577
|
+
environment: targetEnv
|
|
385
578
|
})
|
|
386
579
|
}).then((r) => {
|
|
387
580
|
if (!r.ok) throw new Error(`Service returned ${r.status}`);
|
|
@@ -394,10 +587,7 @@ function PayPalConnectionPage() {
|
|
|
394
587
|
return;
|
|
395
588
|
}
|
|
396
589
|
const url = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
|
|
397
|
-
|
|
398
|
-
CACHE_KEY,
|
|
399
|
-
JSON.stringify({ url, ts: Date.now() })
|
|
400
|
-
);
|
|
590
|
+
writeCachedUrl(targetEnv, url);
|
|
401
591
|
setFinalUrl(url);
|
|
402
592
|
setConnState("ready");
|
|
403
593
|
}).catch(() => {
|
|
@@ -405,37 +595,104 @@ function PayPalConnectionPage() {
|
|
|
405
595
|
showError("Unable to connect to service.");
|
|
406
596
|
});
|
|
407
597
|
},
|
|
408
|
-
[
|
|
598
|
+
[showError]
|
|
409
599
|
);
|
|
600
|
+
useEffect(() => {
|
|
601
|
+
let alive = true;
|
|
602
|
+
fetch(ENVIRONMENT_ENDPOINT, { method: "GET", credentials: "include" }).then((r) => r.json()).then((d) => {
|
|
603
|
+
if (!alive) return;
|
|
604
|
+
setEnv((d == null ? void 0 : d.environment) === "sandbox" ? "sandbox" : "live");
|
|
605
|
+
}).catch(() => {
|
|
606
|
+
}).finally(() => {
|
|
607
|
+
if (alive) setEnvReady(true);
|
|
608
|
+
});
|
|
609
|
+
return () => {
|
|
610
|
+
alive = false;
|
|
611
|
+
};
|
|
612
|
+
}, []);
|
|
410
613
|
useEffect(() => {
|
|
411
614
|
var _a, _b, _c;
|
|
412
615
|
if (connState !== "ready" || !finalUrl) return;
|
|
413
616
|
const scriptUrl = PARTNER_JS_URLS[env];
|
|
617
|
+
let cancelled = false;
|
|
618
|
+
let pollTimer;
|
|
619
|
+
const initPartner = (attempt = 0) => {
|
|
620
|
+
var _a2, _b2;
|
|
621
|
+
if (cancelled) return;
|
|
622
|
+
const signup = (_b2 = (_a2 = window.PAYPAL) == null ? void 0 : _a2.apps) == null ? void 0 : _b2.Signup;
|
|
623
|
+
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;
|
|
624
|
+
if (target == null ? void 0 : target.init) {
|
|
625
|
+
try {
|
|
626
|
+
target.init();
|
|
627
|
+
} catch (e) {
|
|
628
|
+
console.error("[paypal] partner.js init failed:", e);
|
|
629
|
+
}
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
if (typeof (signup == null ? void 0 : signup.render) === "function") {
|
|
633
|
+
try {
|
|
634
|
+
signup.render();
|
|
635
|
+
} catch (e) {
|
|
636
|
+
console.error("[paypal] partner.js render failed:", e);
|
|
637
|
+
}
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
if (attempt < 40) {
|
|
641
|
+
pollTimer = setTimeout(() => initPartner(attempt + 1), 50);
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
try {
|
|
645
|
+
document.dispatchEvent(new Event("DOMContentLoaded"));
|
|
646
|
+
} catch {
|
|
647
|
+
}
|
|
648
|
+
};
|
|
414
649
|
const existingScript = document.getElementById("paypal-partner-js");
|
|
415
650
|
if (existingScript) {
|
|
416
651
|
(_a = existingScript.parentNode) == null ? void 0 : _a.removeChild(existingScript);
|
|
417
652
|
}
|
|
418
653
|
if ((_c = (_b = window.PAYPAL) == null ? void 0 : _b.apps) == null ? void 0 : _c.Signup) {
|
|
419
|
-
|
|
654
|
+
try {
|
|
655
|
+
delete window.PAYPAL.apps.Signup;
|
|
656
|
+
} catch {
|
|
657
|
+
}
|
|
420
658
|
}
|
|
421
659
|
const ppScript = document.createElement("script");
|
|
422
660
|
ppScript.id = "paypal-partner-js";
|
|
423
661
|
ppScript.src = scriptUrl;
|
|
424
662
|
ppScript.async = true;
|
|
663
|
+
ppScript.onload = () => initPartner();
|
|
425
664
|
document.body.appendChild(ppScript);
|
|
426
665
|
return () => {
|
|
666
|
+
cancelled = true;
|
|
667
|
+
if (pollTimer) {
|
|
668
|
+
clearTimeout(pollTimer);
|
|
669
|
+
}
|
|
427
670
|
if (ppScript.parentNode) {
|
|
428
671
|
ppScript.parentNode.removeChild(ppScript);
|
|
429
672
|
}
|
|
430
673
|
};
|
|
431
674
|
}, [connState, finalUrl, env]);
|
|
432
675
|
useEffect(() => {
|
|
676
|
+
const onMessage = (ev) => {
|
|
677
|
+
if (!isPayPalOrigin(ev.origin)) return;
|
|
678
|
+
const { authCode, sharedId } = extractAuth(ev.data);
|
|
679
|
+
if (authCode && sharedId) {
|
|
680
|
+
completeOnboarding(authCode, sharedId);
|
|
681
|
+
}
|
|
682
|
+
};
|
|
683
|
+
window.addEventListener("message", onMessage);
|
|
684
|
+
return () => window.removeEventListener("message", onMessage);
|
|
685
|
+
}, [completeOnboarding]);
|
|
686
|
+
useEffect(() => {
|
|
687
|
+
if (!envReady) return;
|
|
433
688
|
currentRunId.current = ++runIdRef.current;
|
|
434
689
|
const runId = currentRunId.current;
|
|
435
690
|
let cancelled = false;
|
|
691
|
+
completedRef.current = false;
|
|
436
692
|
const run = async () => {
|
|
437
693
|
setConnState("loading");
|
|
438
694
|
setError(null);
|
|
695
|
+
setPopupBlocked(false);
|
|
439
696
|
setFinalUrl("");
|
|
440
697
|
try {
|
|
441
698
|
const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
@@ -454,84 +711,46 @@ function PayPalConnectionPage() {
|
|
|
454
711
|
} catch (e) {
|
|
455
712
|
console.error(e);
|
|
456
713
|
}
|
|
457
|
-
if (
|
|
458
|
-
|
|
714
|
+
if (cancelled || runId !== currentRunId.current) return;
|
|
715
|
+
const cached = readCachedUrl(env);
|
|
716
|
+
if (cached) {
|
|
717
|
+
setFinalUrl(cached);
|
|
459
718
|
setConnState("ready");
|
|
460
719
|
} else {
|
|
461
|
-
fetchFreshLink(runId);
|
|
720
|
+
fetchFreshLink(runId, env);
|
|
462
721
|
}
|
|
463
722
|
};
|
|
464
723
|
run();
|
|
465
724
|
return () => {
|
|
466
725
|
cancelled = true;
|
|
467
|
-
currentRunId.current = 0;
|
|
468
726
|
};
|
|
469
|
-
}, [env, fetchFreshLink]);
|
|
727
|
+
}, [env, envReady, fetchFreshLink]);
|
|
470
728
|
useLayoutEffect(() => {
|
|
471
|
-
window.onboardingCallback =
|
|
472
|
-
|
|
473
|
-
try {
|
|
474
|
-
window.onbeforeunload = null;
|
|
475
|
-
} catch {
|
|
476
|
-
}
|
|
477
|
-
setOnboardingInProgress(true);
|
|
478
|
-
setConnState("loading");
|
|
479
|
-
setError(null);
|
|
480
|
-
const payload = {
|
|
481
|
-
authCode,
|
|
482
|
-
sharedId,
|
|
483
|
-
env: env === "sandbox" ? "sandbox" : "live"
|
|
484
|
-
};
|
|
485
|
-
try {
|
|
486
|
-
const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
|
|
487
|
-
method: "POST",
|
|
488
|
-
headers: { "content-type": "application/json" },
|
|
489
|
-
credentials: "include",
|
|
490
|
-
body: JSON.stringify(payload)
|
|
491
|
-
});
|
|
492
|
-
if (!res.ok) {
|
|
493
|
-
const txt = await res.text().catch(() => "");
|
|
494
|
-
throw new Error(txt || `Onboarding exchange failed (${res.status})`);
|
|
495
|
-
}
|
|
496
|
-
try {
|
|
497
|
-
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;
|
|
498
|
-
if (typeof close1 === "function") close1();
|
|
499
|
-
} catch {
|
|
500
|
-
}
|
|
501
|
-
try {
|
|
502
|
-
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;
|
|
503
|
-
if (typeof close2 === "function") close2();
|
|
504
|
-
} catch {
|
|
505
|
-
}
|
|
506
|
-
try {
|
|
507
|
-
localStorage.removeItem(CACHE_KEY);
|
|
508
|
-
} catch {
|
|
509
|
-
}
|
|
510
|
-
try {
|
|
511
|
-
const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
512
|
-
method: "GET",
|
|
513
|
-
credentials: "include"
|
|
514
|
-
});
|
|
515
|
-
const refreshedStatus = await statusRes.json().catch(() => ({}));
|
|
516
|
-
setStatusInfo(refreshedStatus || null);
|
|
517
|
-
setConnState("connected");
|
|
518
|
-
setShowManual(false);
|
|
519
|
-
} catch {
|
|
520
|
-
setConnState("connected");
|
|
521
|
-
setShowManual(false);
|
|
522
|
-
}
|
|
523
|
-
setOnboardingInProgress(false);
|
|
524
|
-
} catch (e) {
|
|
525
|
-
console.error(e);
|
|
526
|
-
setConnState("error");
|
|
527
|
-
setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
|
|
528
|
-
setOnboardingInProgress(false);
|
|
529
|
-
}
|
|
729
|
+
window.onboardingCallback = (authCode, sharedId) => {
|
|
730
|
+
completeOnboarding(authCode, sharedId);
|
|
530
731
|
};
|
|
531
732
|
return () => {
|
|
532
733
|
window.onboardingCallback = void 0;
|
|
533
734
|
};
|
|
534
|
-
}, [
|
|
735
|
+
}, [completeOnboarding]);
|
|
736
|
+
useEffect(() => {
|
|
737
|
+
return () => {
|
|
738
|
+
stopPopupPoll();
|
|
739
|
+
};
|
|
740
|
+
}, [stopPopupPoll]);
|
|
741
|
+
useEffect(() => {
|
|
742
|
+
const onCaptureClick = (e) => {
|
|
743
|
+
const btn = paypalButtonRef.current;
|
|
744
|
+
if (!btn) return;
|
|
745
|
+
const target = e.target;
|
|
746
|
+
if (!target || !btn.contains(target)) return;
|
|
747
|
+
e.preventDefault();
|
|
748
|
+
e.stopImmediatePropagation();
|
|
749
|
+
openConnect();
|
|
750
|
+
};
|
|
751
|
+
document.addEventListener("click", onCaptureClick, true);
|
|
752
|
+
return () => document.removeEventListener("click", onCaptureClick, true);
|
|
753
|
+
}, [openConnect]);
|
|
535
754
|
useLayoutEffect(() => {
|
|
536
755
|
const el = ppBtnMeasureRef.current;
|
|
537
756
|
if (!el) return;
|
|
@@ -553,9 +772,8 @@ function PayPalConnectionPage() {
|
|
|
553
772
|
};
|
|
554
773
|
}, [connState, env, finalUrl]);
|
|
555
774
|
const handleConnectClick = (e) => {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
}
|
|
775
|
+
e.preventDefault();
|
|
776
|
+
openConnect();
|
|
559
777
|
};
|
|
560
778
|
const handleSaveManual = async () => {
|
|
561
779
|
if (!canSaveManual || onboardingInProgress) return;
|
|
@@ -585,10 +803,7 @@ function PayPalConnectionPage() {
|
|
|
585
803
|
setConnState("connected");
|
|
586
804
|
setStatusInfo(refreshedStatus || null);
|
|
587
805
|
setShowManual(false);
|
|
588
|
-
|
|
589
|
-
localStorage.removeItem(CACHE_KEY);
|
|
590
|
-
} catch {
|
|
591
|
-
}
|
|
806
|
+
clearCachedUrl(env);
|
|
592
807
|
} catch (e) {
|
|
593
808
|
console.error(e);
|
|
594
809
|
setConnState("error");
|
|
@@ -617,13 +832,11 @@ function PayPalConnectionPage() {
|
|
|
617
832
|
const t = await res.text().catch(() => "");
|
|
618
833
|
throw new Error(t || `Disconnect failed (${res.status})`);
|
|
619
834
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
} catch {
|
|
623
|
-
}
|
|
835
|
+
clearCachedUrl(env);
|
|
836
|
+
completedRef.current = false;
|
|
624
837
|
currentRunId.current = ++runIdRef.current;
|
|
625
838
|
const runId = currentRunId.current;
|
|
626
|
-
fetchFreshLink(runId);
|
|
839
|
+
fetchFreshLink(runId, env);
|
|
627
840
|
} catch (e) {
|
|
628
841
|
console.error(e);
|
|
629
842
|
setConnState("error");
|
|
@@ -634,10 +847,12 @@ function PayPalConnectionPage() {
|
|
|
634
847
|
};
|
|
635
848
|
const handleEnvChange = async (e) => {
|
|
636
849
|
const next = e.target.value;
|
|
850
|
+
completedRef.current = false;
|
|
851
|
+
setPopupBlocked(false);
|
|
852
|
+
clearCachedUrl();
|
|
637
853
|
setEnv(next);
|
|
638
|
-
cachedUrl = null;
|
|
639
854
|
try {
|
|
640
|
-
await fetch(
|
|
855
|
+
await fetch(ENVIRONMENT_ENDPOINT, {
|
|
641
856
|
method: "POST",
|
|
642
857
|
headers: { "content-type": "application/json" },
|
|
643
858
|
credentials: "include",
|
|
@@ -645,10 +860,6 @@ function PayPalConnectionPage() {
|
|
|
645
860
|
});
|
|
646
861
|
} catch {
|
|
647
862
|
}
|
|
648
|
-
try {
|
|
649
|
-
localStorage.removeItem(CACHE_KEY);
|
|
650
|
-
} catch {
|
|
651
|
-
}
|
|
652
863
|
};
|
|
653
864
|
return /* @__PURE__ */ jsxs("div", { className: "p-6", children: [
|
|
654
865
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
@@ -671,20 +882,7 @@ function PayPalConnectionPage() {
|
|
|
671
882
|
) }),
|
|
672
883
|
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium pt-2", children: env === "sandbox" ? "Connect to PayPal (Sandbox)" : "Connect to PayPal" }),
|
|
673
884
|
/* @__PURE__ */ jsx("div", { className: "max-w-xl", children: connState === "connected" ? /* @__PURE__ */ jsxs("div", { children: [
|
|
674
|
-
/* @__PURE__ */
|
|
675
|
-
"✅ Successfully connected to PayPal!",
|
|
676
|
-
/* @__PURE__ */ jsx(
|
|
677
|
-
"a",
|
|
678
|
-
{
|
|
679
|
-
target: "_blank",
|
|
680
|
-
"data-paypal-button": "true",
|
|
681
|
-
"data-paypal-onboard-complete": "onboardingCallback",
|
|
682
|
-
href: "#",
|
|
683
|
-
style: { display: "none" },
|
|
684
|
-
children: "PayPal"
|
|
685
|
-
}
|
|
686
|
-
)
|
|
687
|
-
] }),
|
|
885
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: "✅ Successfully connected to PayPal!" }),
|
|
688
886
|
/* @__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: [
|
|
689
887
|
/* @__PURE__ */ jsx("div", { className: "font-medium text-ui-fg-base", children: "Connected PayPal account" }),
|
|
690
888
|
/* @__PURE__ */ jsxs("div", { className: "mt-1", children: [
|
|
@@ -725,7 +923,7 @@ function PayPalConnectionPage() {
|
|
|
725
923
|
ppBtnMeasureRef.current = node;
|
|
726
924
|
},
|
|
727
925
|
id: "paypal-button",
|
|
728
|
-
target:
|
|
926
|
+
target: POPUP_NAME,
|
|
729
927
|
"data-paypal-button": "true",
|
|
730
928
|
href: finalUrl || "#",
|
|
731
929
|
"data-paypal-onboard-complete": "onboardingCallback",
|
|
@@ -739,6 +937,7 @@ function PayPalConnectionPage() {
|
|
|
739
937
|
children: "Connect to PayPal"
|
|
740
938
|
}
|
|
741
939
|
),
|
|
940
|
+
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." }),
|
|
742
941
|
/* @__PURE__ */ jsx(
|
|
743
942
|
"div",
|
|
744
943
|
{
|
|
@@ -894,9 +1093,6 @@ function PayPalConnectionPage() {
|
|
|
894
1093
|
` })
|
|
895
1094
|
] });
|
|
896
1095
|
}
|
|
897
|
-
function PayPalGooglePayPage() {
|
|
898
|
-
return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
899
|
-
}
|
|
900
1096
|
function PayPalPayLaterMessagingPage() {
|
|
901
1097
|
return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
902
1098
|
}
|
|
@@ -1126,14 +1322,14 @@ const routeModule = {
|
|
|
1126
1322
|
Component: PayPalApplePayPage,
|
|
1127
1323
|
path: "/settings/paypal/apple-pay"
|
|
1128
1324
|
},
|
|
1129
|
-
{
|
|
1130
|
-
Component: PayPalConnectionPage,
|
|
1131
|
-
path: "/settings/paypal/connection"
|
|
1132
|
-
},
|
|
1133
1325
|
{
|
|
1134
1326
|
Component: PayPalGooglePayPage,
|
|
1135
1327
|
path: "/settings/paypal/google-pay"
|
|
1136
1328
|
},
|
|
1329
|
+
{
|
|
1330
|
+
Component: PayPalConnectionPage,
|
|
1331
|
+
path: "/settings/paypal/connection"
|
|
1332
|
+
},
|
|
1137
1333
|
{
|
|
1138
1334
|
Component: PayPalPayLaterMessagingPage,
|
|
1139
1335
|
path: "/settings/paypal/pay-later-messaging"
|
|
@@ -5,11 +5,14 @@ declare global {
|
|
|
5
5
|
apps?: {
|
|
6
6
|
Signup?: {
|
|
7
7
|
miniBrowser?: {
|
|
8
|
-
init
|
|
8
|
+
init?: () => void;
|
|
9
|
+
closeFlow?: () => void;
|
|
9
10
|
};
|
|
10
11
|
MiniBrowser?: {
|
|
12
|
+
init?: () => void;
|
|
11
13
|
closeFlow?: () => void;
|
|
12
14
|
};
|
|
15
|
+
render?: () => void;
|
|
13
16
|
};
|
|
14
17
|
};
|
|
15
18
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../../../../src/admin/routes/settings/paypal/connection/page.tsx"],"names":[],"mappings":"AAWA,eAAO,MAAM,MAAM,2CAEjB,CAAA;AAQF,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,MAAM,CAAC,EAAE;YACP,IAAI,CAAC,EAAE;gBACL,MAAM,CAAC,EAAE;oBACP,WAAW,CAAC,EAAE;wBAAE,IAAI,EAAE,MAAM,IAAI,CAAA;qBAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../../../../src/admin/routes/settings/paypal/connection/page.tsx"],"names":[],"mappings":"AAWA,eAAO,MAAM,MAAM,2CAEjB,CAAA;AAQF,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,MAAM,CAAC,EAAE;YACP,IAAI,CAAC,EAAE;gBACL,MAAM,CAAC,EAAE;oBACP,WAAW,CAAC,EAAE;wBAAE,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC;wBAAC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;qBAAE,CAAA;oBAC3D,WAAW,CAAC,EAAE;wBAAE,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC;wBAAC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;qBAAE,CAAA;oBAC3D,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;iBACpB,CAAA;aACF,CAAA;SACF,CAAA;QACD,kBAAkB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;KAClE;CACF;AAmID,MAAM,CAAC,OAAO,UAAU,oBAAoB,4CAy2B3C"}
|