@easypayment/medusa-paypal 0.2.3 → 0.2.4
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 +893 -893
- package/.medusa/server/src/admin/index.mjs +893 -893
- package/.medusa/server/src/api/store/paypal/config/route.js +1 -1
- package/.medusa/server/src/api/store/paypal/create-order/route.js +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/card-service.js +9 -9
- package/.medusa/server/src/modules/paypal/payment-provider/service.js +10 -10
- package/.medusa/server/src/modules/paypal/service.js +1 -1
- package/.medusa/server/src/modules/paypal/utils/currencies.js +1 -1
- package/package.json +1 -1
- package/src/api/store/paypal/config/route.ts +1 -1
- package/src/api/store/paypal/create-order/route.ts +1 -1
- package/src/modules/paypal/payment-provider/card-service.ts +9 -9
- package/src/modules/paypal/payment-provider/service.ts +10 -10
- package/src/modules/paypal/service.ts +1 -1
- package/src/modules/paypal/utils/currencies.ts +1 -1
|
@@ -336,965 +336,965 @@ function AdditionalSettingsTab() {
|
|
|
336
336
|
)
|
|
337
337
|
] }) });
|
|
338
338
|
}
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
);
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
339
|
+
const DEFAULT_FORM = {
|
|
340
|
+
enabled: true,
|
|
341
|
+
title: "Credit or Debit Card",
|
|
342
|
+
disabledCards: [],
|
|
343
|
+
threeDS: "when_required",
|
|
344
|
+
cardSaveEnabled: false
|
|
345
|
+
};
|
|
346
|
+
function mergeWithDefaults(saved) {
|
|
347
|
+
if (!saved) return { ...DEFAULT_FORM };
|
|
348
|
+
const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
|
|
349
|
+
return {
|
|
350
|
+
...DEFAULT_FORM,
|
|
351
|
+
...Object.fromEntries(entries)
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
const CARD_BRANDS = [
|
|
355
|
+
{ value: "visa", label: "Visa" },
|
|
356
|
+
{ value: "mastercard", label: "Mastercard" },
|
|
357
|
+
{ value: "amex", label: "American Express" },
|
|
358
|
+
{ value: "discover", label: "Discover" },
|
|
359
|
+
{ value: "diners", label: "Diners Club" },
|
|
360
|
+
{ value: "jcb", label: "JCB" },
|
|
361
|
+
{ value: "unionpay", label: "UnionPay" }
|
|
362
|
+
];
|
|
363
|
+
const THREE_DS_OPTIONS = [
|
|
364
|
+
{
|
|
365
|
+
value: "when_required",
|
|
366
|
+
label: "3D Secure when required",
|
|
367
|
+
hint: "Triggers 3DS only when the card / issuer requires it."
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
value: "sli",
|
|
371
|
+
label: "3D Secure (SCA) / liability shift (recommended)",
|
|
372
|
+
hint: "Attempts to optimize for liability shift while remaining compliant."
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
value: "always",
|
|
376
|
+
label: "Always request 3D Secure",
|
|
377
|
+
hint: "Forces 3DS challenge whenever possible (may reduce conversion)."
|
|
364
378
|
}
|
|
379
|
+
];
|
|
380
|
+
function cx$1(...parts) {
|
|
381
|
+
return parts.filter(Boolean).join(" ");
|
|
365
382
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
if ((/* @__PURE__ */ new Date()).getTime() - data.ts < CACHE_EXPIRY) {
|
|
381
|
-
cachedUrl = data.url;
|
|
383
|
+
function Pill$1({
|
|
384
|
+
children,
|
|
385
|
+
onRemove
|
|
386
|
+
}) {
|
|
387
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 rounded-md border border-ui-border-base bg-ui-bg-base px-2 py-1 text-sm text-ui-fg-base", children: [
|
|
388
|
+
children,
|
|
389
|
+
onRemove ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
390
|
+
"button",
|
|
391
|
+
{
|
|
392
|
+
type: "button",
|
|
393
|
+
onClick: onRemove,
|
|
394
|
+
className: "ml-1 rounded px-1 text-ui-fg-subtle hover:text-ui-fg-base",
|
|
395
|
+
"aria-label": "Remove",
|
|
396
|
+
children: "×"
|
|
382
397
|
}
|
|
383
|
-
|
|
384
|
-
}
|
|
385
|
-
console.error("Cache read error:", e);
|
|
386
|
-
}
|
|
398
|
+
) : null
|
|
399
|
+
] });
|
|
387
400
|
}
|
|
388
|
-
function
|
|
389
|
-
|
|
401
|
+
function SectionCard$1({
|
|
402
|
+
title,
|
|
403
|
+
description,
|
|
404
|
+
right,
|
|
405
|
+
children
|
|
406
|
+
}) {
|
|
407
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
|
|
408
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
|
|
409
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
410
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: title }),
|
|
411
|
+
description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-sm text-ui-fg-subtle", children: description }) : null
|
|
412
|
+
] }),
|
|
413
|
+
right
|
|
414
|
+
] }),
|
|
415
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children })
|
|
416
|
+
] });
|
|
417
|
+
}
|
|
418
|
+
function FieldRow$1({
|
|
419
|
+
label,
|
|
420
|
+
hint,
|
|
421
|
+
children
|
|
422
|
+
}) {
|
|
423
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
|
|
424
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 md:col-span-4", children: [
|
|
425
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
|
|
426
|
+
hint ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: hint }) : null
|
|
427
|
+
] }),
|
|
428
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-12 md:col-span-8", children })
|
|
429
|
+
] });
|
|
430
|
+
}
|
|
431
|
+
function AdvancedCardPaymentsTab() {
|
|
432
|
+
var _a, _b;
|
|
433
|
+
const [form, setForm] = react.useState(() => ({ ...DEFAULT_FORM }));
|
|
434
|
+
const [loading, setLoading] = react.useState(false);
|
|
435
|
+
const [saving, setSaving] = react.useState(false);
|
|
436
|
+
const [toast, setToast] = react.useState(null);
|
|
437
|
+
const didInit = react.useRef(false);
|
|
390
438
|
react.useEffect(() => {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
const runIdRef = react.useRef(0);
|
|
410
|
-
const currentRunId = react.useRef(0);
|
|
411
|
-
const ppBtnMeasureRef = react.useRef(null);
|
|
412
|
-
const [ppBtnWidth, setPpBtnWidth] = react.useState(null);
|
|
413
|
-
const canSaveManual = react.useMemo(() => {
|
|
414
|
-
return clientId.trim().length > 0 && secret.trim().length > 0;
|
|
415
|
-
}, [clientId, secret]);
|
|
416
|
-
const maskValue = react.useCallback((value, visibleChars = 4) => {
|
|
417
|
-
if (!value) return "";
|
|
418
|
-
if (value.length <= visibleChars) {
|
|
419
|
-
return "•".repeat(value.length);
|
|
420
|
-
}
|
|
421
|
-
return `${"•".repeat(Math.max(0, value.length - visibleChars))}${value.slice(
|
|
422
|
-
-visibleChars
|
|
423
|
-
)}`;
|
|
424
|
-
}, []);
|
|
425
|
-
const fetchFreshLink = react.useCallback(
|
|
426
|
-
(runId) => {
|
|
427
|
-
if (initLoaderRef.current) {
|
|
428
|
-
const loaderText = initLoaderRef.current.querySelector("#loader-text");
|
|
429
|
-
if (loaderText)
|
|
430
|
-
loaderText.textContent = "Generating onboarding session...";
|
|
439
|
+
if (didInit.current) return;
|
|
440
|
+
didInit.current = true;
|
|
441
|
+
(async () => {
|
|
442
|
+
try {
|
|
443
|
+
setLoading(true);
|
|
444
|
+
const r = await fetch("/admin/paypal/settings", {
|
|
445
|
+
credentials: "include",
|
|
446
|
+
headers: { "Accept": "application/json" }
|
|
447
|
+
});
|
|
448
|
+
if (!r.ok) return;
|
|
449
|
+
const json = await r.json();
|
|
450
|
+
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
451
|
+
const saved = payload == null ? void 0 : payload.advanced_card_payments;
|
|
452
|
+
if (saved && typeof saved === "object") {
|
|
453
|
+
setForm(mergeWithDefaults(saved));
|
|
454
|
+
}
|
|
455
|
+
} finally {
|
|
456
|
+
setLoading(false);
|
|
431
457
|
}
|
|
432
|
-
|
|
458
|
+
})();
|
|
459
|
+
}, []);
|
|
460
|
+
async function onSave() {
|
|
461
|
+
try {
|
|
462
|
+
setSaving(true);
|
|
463
|
+
const r = await fetch("/admin/paypal/settings", {
|
|
433
464
|
method: "POST",
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
const href = data == null ? void 0 : data.onboarding_url;
|
|
441
|
-
if (!href) {
|
|
442
|
-
showError("Onboarding URL not returned.");
|
|
443
|
-
return;
|
|
444
|
-
}
|
|
445
|
-
const finalUrl2 = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
|
|
446
|
-
localStorage.setItem(
|
|
447
|
-
CACHE_KEY,
|
|
448
|
-
JSON.stringify({
|
|
449
|
-
url: finalUrl2,
|
|
450
|
-
ts: Date.now()
|
|
451
|
-
})
|
|
452
|
-
);
|
|
453
|
-
if (!localStorage.getItem(RELOAD_KEY)) {
|
|
454
|
-
localStorage.setItem(RELOAD_KEY, "1");
|
|
455
|
-
window.location.reload();
|
|
456
|
-
return;
|
|
457
|
-
}
|
|
458
|
-
activatePayPal(finalUrl2, runId);
|
|
459
|
-
}).catch(() => {
|
|
460
|
-
if (runId !== currentRunId.current) return;
|
|
461
|
-
showError("Unable to connect to service.");
|
|
465
|
+
credentials: "include",
|
|
466
|
+
headers: {
|
|
467
|
+
"Content-Type": "application/json",
|
|
468
|
+
"Accept": "application/json"
|
|
469
|
+
},
|
|
470
|
+
body: JSON.stringify({ advanced_card_payments: form })
|
|
462
471
|
});
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
const btn = document.querySelector('[data-paypal-button="true"]');
|
|
469
|
-
if (btn && ((_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.init)) {
|
|
470
|
-
window.PAYPAL.apps.Signup.miniBrowser.init();
|
|
471
|
-
}
|
|
472
|
-
setConnState("ready");
|
|
473
|
-
}, []);
|
|
474
|
-
const showError = react.useCallback((msg) => {
|
|
475
|
-
setConnState("error");
|
|
476
|
-
setError(msg);
|
|
477
|
-
}, []);
|
|
478
|
-
const activatePayPal = react.useCallback(
|
|
479
|
-
(url, runId) => {
|
|
480
|
-
if (paypalButtonRef.current) {
|
|
481
|
-
paypalButtonRef.current.href = url;
|
|
482
|
-
}
|
|
483
|
-
setFinalUrl(url);
|
|
484
|
-
const tryInit = () => {
|
|
485
|
-
var _a, _b;
|
|
486
|
-
if (runId !== currentRunId.current) return;
|
|
487
|
-
if ((_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) {
|
|
488
|
-
showUI();
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
setTimeout(tryInit, 50);
|
|
492
|
-
};
|
|
493
|
-
tryInit();
|
|
494
|
-
},
|
|
495
|
-
[showUI]
|
|
496
|
-
);
|
|
497
|
-
react.useEffect(() => {
|
|
498
|
-
currentRunId.current = ++runIdRef.current;
|
|
499
|
-
const runId = currentRunId.current;
|
|
500
|
-
let cancelled = false;
|
|
501
|
-
const run = async () => {
|
|
502
|
-
setConnState("loading");
|
|
503
|
-
setError(null);
|
|
504
|
-
setFinalUrl("");
|
|
505
|
-
try {
|
|
506
|
-
const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
507
|
-
method: "GET"
|
|
508
|
-
});
|
|
509
|
-
const st = await r.json().catch(() => ({}));
|
|
510
|
-
if (cancelled || runId !== currentRunId.current) return;
|
|
511
|
-
setStatusInfo(st);
|
|
512
|
-
const isConnected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
|
|
513
|
-
if (isConnected) {
|
|
514
|
-
setConnState("connected");
|
|
515
|
-
setShowManual(false);
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
|
-
} catch (e) {
|
|
519
|
-
console.error(e);
|
|
520
|
-
}
|
|
521
|
-
if (cachedUrl) {
|
|
522
|
-
console.log("Using prioritized cache...");
|
|
523
|
-
activatePayPal(cachedUrl, runId);
|
|
524
|
-
} else {
|
|
525
|
-
fetchFreshLink(runId);
|
|
526
|
-
}
|
|
527
|
-
};
|
|
528
|
-
run();
|
|
529
|
-
return () => {
|
|
530
|
-
cancelled = true;
|
|
531
|
-
currentRunId.current = 0;
|
|
532
|
-
};
|
|
533
|
-
}, [env, fetchFreshLink, activatePayPal]);
|
|
534
|
-
react.useLayoutEffect(() => {
|
|
535
|
-
window.onboardingCallback = async function(authCode, sharedId) {
|
|
536
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
537
|
-
try {
|
|
538
|
-
;
|
|
539
|
-
window.onbeforeunload = "";
|
|
540
|
-
} catch {
|
|
541
|
-
}
|
|
542
|
-
setOnboardingInProgress(true);
|
|
543
|
-
setConnState("loading");
|
|
544
|
-
setError(null);
|
|
545
|
-
const payload = {
|
|
546
|
-
authCode,
|
|
547
|
-
sharedId,
|
|
548
|
-
env: env === "sandbox" ? "sandbox" : "live"
|
|
549
|
-
};
|
|
550
|
-
try {
|
|
551
|
-
const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
|
|
552
|
-
method: "POST",
|
|
553
|
-
headers: { "content-type": "application/json" },
|
|
554
|
-
body: JSON.stringify(payload)
|
|
555
|
-
});
|
|
556
|
-
if (!res.ok) {
|
|
557
|
-
const txt = await res.text().catch(() => "");
|
|
558
|
-
throw new Error(txt || `Onboarding exchange failed (${res.status})`);
|
|
559
|
-
}
|
|
560
|
-
try {
|
|
561
|
-
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;
|
|
562
|
-
if (typeof close1 === "function") close1();
|
|
563
|
-
} catch {
|
|
564
|
-
}
|
|
565
|
-
try {
|
|
566
|
-
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;
|
|
567
|
-
if (typeof close2 === "function") close2();
|
|
568
|
-
} catch {
|
|
569
|
-
}
|
|
570
|
-
try {
|
|
571
|
-
localStorage.removeItem(CACHE_KEY);
|
|
572
|
-
localStorage.removeItem(RELOAD_KEY);
|
|
573
|
-
} catch {
|
|
574
|
-
}
|
|
575
|
-
window.location.href = window.location.href;
|
|
576
|
-
} catch (e) {
|
|
577
|
-
console.error(e);
|
|
578
|
-
setConnState("error");
|
|
579
|
-
setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
|
|
580
|
-
setOnboardingInProgress(false);
|
|
581
|
-
}
|
|
582
|
-
};
|
|
583
|
-
return () => {
|
|
584
|
-
window.onboardingCallback = void 0;
|
|
585
|
-
};
|
|
586
|
-
}, [env]);
|
|
587
|
-
react.useLayoutEffect(() => {
|
|
588
|
-
const el = ppBtnMeasureRef.current;
|
|
589
|
-
if (!el) return;
|
|
590
|
-
const update = () => {
|
|
591
|
-
const w = Math.round(el.getBoundingClientRect().width || 0);
|
|
592
|
-
if (w > 0) setPpBtnWidth(w);
|
|
593
|
-
};
|
|
594
|
-
update();
|
|
595
|
-
let ro = null;
|
|
596
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
597
|
-
ro = new ResizeObserver(() => update());
|
|
598
|
-
ro.observe(el);
|
|
599
|
-
} else {
|
|
600
|
-
window.addEventListener("resize", update);
|
|
601
|
-
}
|
|
602
|
-
return () => {
|
|
603
|
-
if (ro) ro.disconnect();
|
|
604
|
-
else window.removeEventListener("resize", update);
|
|
605
|
-
};
|
|
606
|
-
}, [connState, env, finalUrl]);
|
|
607
|
-
const handleConnectClick = (e) => {
|
|
608
|
-
if (connState !== "ready" || !finalUrl || onboardingInProgress) {
|
|
609
|
-
e.preventDefault();
|
|
610
|
-
}
|
|
611
|
-
};
|
|
612
|
-
const handleSaveManual = async () => {
|
|
613
|
-
if (!canSaveManual || onboardingInProgress) return;
|
|
614
|
-
setOnboardingInProgress(true);
|
|
615
|
-
setConnState("loading");
|
|
616
|
-
setError(null);
|
|
617
|
-
try {
|
|
618
|
-
const res = await fetch(SAVE_CREDENTIALS_ENDPOINT, {
|
|
619
|
-
method: "POST",
|
|
620
|
-
headers: { "content-type": "application/json" },
|
|
621
|
-
body: JSON.stringify({
|
|
622
|
-
clientId: clientId.trim(),
|
|
623
|
-
clientSecret: secret.trim()
|
|
624
|
-
})
|
|
625
|
-
});
|
|
626
|
-
if (!res.ok) {
|
|
627
|
-
const txt = await res.text().catch(() => "");
|
|
628
|
-
throw new Error(txt || `Save credentials failed (${res.status})`);
|
|
472
|
+
if (!r.ok) {
|
|
473
|
+
const t = await r.text();
|
|
474
|
+
setToast({ type: "error", message: "Failed to save settings. " + t });
|
|
475
|
+
window.setTimeout(() => setToast(null), 3500);
|
|
476
|
+
return;
|
|
629
477
|
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
setShowManual(false);
|
|
636
|
-
try {
|
|
637
|
-
localStorage.removeItem(CACHE_KEY);
|
|
638
|
-
localStorage.removeItem(RELOAD_KEY);
|
|
639
|
-
} catch {
|
|
478
|
+
const json = await r.json().catch(() => null);
|
|
479
|
+
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
480
|
+
const saved = payload == null ? void 0 : payload.advanced_card_payments;
|
|
481
|
+
if (saved && typeof saved === "object") {
|
|
482
|
+
setForm(mergeWithDefaults(saved));
|
|
640
483
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
setConnState("error");
|
|
644
|
-
setError((e == null ? void 0 : e.message) || "Failed to save credentials.");
|
|
484
|
+
setToast({ type: "success", message: "Settings saved" });
|
|
485
|
+
window.setTimeout(() => setToast(null), 2500);
|
|
645
486
|
} finally {
|
|
646
|
-
|
|
487
|
+
setSaving(false);
|
|
647
488
|
}
|
|
648
|
-
}
|
|
649
|
-
const
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
489
|
+
}
|
|
490
|
+
const disabledSet = react.useMemo(() => new Set(form.disabledCards), [form.disabledCards]);
|
|
491
|
+
function toggleDisabledCard(value) {
|
|
492
|
+
setForm((prev) => {
|
|
493
|
+
const exists = prev.disabledCards.includes(value);
|
|
494
|
+
return {
|
|
495
|
+
...prev,
|
|
496
|
+
disabledCards: exists ? prev.disabledCards.filter((v) => v !== value) : [...prev.disabledCards, value]
|
|
497
|
+
};
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
function removeDisabledCard(value) {
|
|
501
|
+
setForm((prev) => ({
|
|
502
|
+
...prev,
|
|
503
|
+
disabledCards: prev.disabledCards.filter((v) => v !== value)
|
|
504
|
+
}));
|
|
505
|
+
}
|
|
506
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
507
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start justify-between gap-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Gateway By Easy Payment" }) }) }),
|
|
508
|
+
/* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
|
|
509
|
+
toast ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
510
|
+
"div",
|
|
511
|
+
{
|
|
512
|
+
className: "fixed right-6 top-6 z-50 rounded-md border border-ui-border-base bg-ui-bg-base px-4 py-3 text-sm shadow-lg",
|
|
513
|
+
role: "status",
|
|
514
|
+
"aria-live": "polite",
|
|
515
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: toast.type === "success" ? "text-ui-fg-base" : "text-ui-fg-error", children: toast.message })
|
|
671
516
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
setOnboardingInProgress(false);
|
|
681
|
-
}
|
|
682
|
-
};
|
|
683
|
-
const handleEnvChange = async (e) => {
|
|
684
|
-
const next = e.target.value;
|
|
685
|
-
setEnv(next);
|
|
686
|
-
cachedUrl = null;
|
|
687
|
-
try {
|
|
688
|
-
await fetch("/admin/paypal/environment", {
|
|
689
|
-
method: "POST",
|
|
690
|
-
headers: { "content-type": "application/json" },
|
|
691
|
-
body: JSON.stringify({ environment: next })
|
|
692
|
-
});
|
|
693
|
-
} catch {
|
|
694
|
-
}
|
|
695
|
-
try {
|
|
696
|
-
localStorage.removeItem(CACHE_KEY);
|
|
697
|
-
localStorage.removeItem(RELOAD_KEY);
|
|
698
|
-
} catch {
|
|
699
|
-
}
|
|
700
|
-
};
|
|
701
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6", children: [
|
|
702
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
703
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold", children: "PayPal Gateway By Easy Payment" }),
|
|
704
|
-
/* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
|
|
705
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-ui-border-base p-4 shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-y-6 md:grid-cols-[260px_1fr] md:items-start", children: [
|
|
706
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium pt-2", children: "Environment" }),
|
|
707
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xl", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
708
|
-
"select",
|
|
709
|
-
{
|
|
710
|
-
value: env,
|
|
711
|
-
onChange: handleEnvChange,
|
|
712
|
-
disabled: onboardingInProgress,
|
|
713
|
-
className: "w-full rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm",
|
|
714
|
-
children: [
|
|
715
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "sandbox", children: "Sandbox (Test Mode)" }),
|
|
716
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "live", children: "Live (Production)" })
|
|
717
|
-
]
|
|
718
|
-
}
|
|
719
|
-
) }),
|
|
720
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium pt-2", children: env === "sandbox" ? "Connect to PayPal Sandbox" : "Connect to PayPal Live" }),
|
|
721
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xl", children: connState === "connected" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
722
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: [
|
|
723
|
-
"✅ Successfully connected to PayPal!",
|
|
724
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
725
|
-
"a",
|
|
726
|
-
{
|
|
727
|
-
"data-paypal-button": "true",
|
|
728
|
-
"data-paypal-onboard-complete": "onboardingCallback",
|
|
729
|
-
href: "#",
|
|
730
|
-
style: { display: "none" },
|
|
731
|
-
children: "PayPal"
|
|
732
|
-
}
|
|
733
|
-
)
|
|
734
|
-
] }),
|
|
735
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 rounded-md border border-ui-border-base bg-ui-bg-subtle p-3 text-xs text-ui-fg-subtle", children: [
|
|
736
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-ui-fg-base", children: "Connected PayPal account" }),
|
|
737
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1", children: [
|
|
738
|
-
"Email:",
|
|
739
|
-
" ",
|
|
740
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-ui-fg-base", children: (statusInfo == null ? void 0 : statusInfo.seller_email) || "Unavailable" })
|
|
741
|
-
] })
|
|
742
|
-
] }),
|
|
743
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
517
|
+
) : null,
|
|
518
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
519
|
+
SectionCard$1,
|
|
520
|
+
{
|
|
521
|
+
title: "Advanced Card Payments",
|
|
522
|
+
description: "Control card checkout settings, 3D Secure behavior, and card saving.",
|
|
523
|
+
right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
524
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
744
525
|
"button",
|
|
745
526
|
{
|
|
746
527
|
type: "button",
|
|
747
|
-
onClick:
|
|
748
|
-
disabled:
|
|
749
|
-
className: "rounded-md
|
|
750
|
-
children: "
|
|
751
|
-
}
|
|
752
|
-
) })
|
|
753
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
754
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
755
|
-
"div",
|
|
756
|
-
{
|
|
757
|
-
ref: initLoaderRef,
|
|
758
|
-
id: "init-loader",
|
|
759
|
-
className: `status-msg mb-4 ${connState !== "loading" ? "hidden" : "block"}`,
|
|
760
|
-
children: [
|
|
761
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "loader inline-block align-middle mr-2" }),
|
|
762
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { id: "loader-text", className: "text-sm", children: onboardingInProgress ? "Configuring connection to PayPal…" : "Checking connection..." })
|
|
763
|
-
]
|
|
528
|
+
onClick: onSave,
|
|
529
|
+
disabled: saving || loading,
|
|
530
|
+
className: "rounded-md bg-ui-button-neutral px-4 py-2 text-sm font-medium text-ui-fg-on-color shadow-sm hover:opacity-90 disabled:opacity-60",
|
|
531
|
+
children: saving ? "Saving..." : "Save settings"
|
|
764
532
|
}
|
|
765
533
|
),
|
|
766
|
-
/* @__PURE__ */ jsxRuntime.
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
ref: (node) => {
|
|
771
|
-
paypalButtonRef.current = node;
|
|
772
|
-
ppBtnMeasureRef.current = node;
|
|
773
|
-
},
|
|
774
|
-
id: "paypal-button",
|
|
775
|
-
"data-paypal-button": "true",
|
|
776
|
-
href: finalUrl || "#",
|
|
777
|
-
"data-paypal-onboard-complete": "onboardingCallback",
|
|
778
|
-
onClick: handleConnectClick,
|
|
779
|
-
className: "btn-paypal",
|
|
780
|
-
style: {
|
|
781
|
-
borderRadius: "50px",
|
|
782
|
-
textDecoration: "none",
|
|
783
|
-
display: "inline-block",
|
|
784
|
-
fontWeight: "bold",
|
|
785
|
-
border: "none",
|
|
786
|
-
cursor: onboardingInProgress ? "not-allowed" : "pointer",
|
|
787
|
-
opacity: onboardingInProgress ? 0.6 : 1,
|
|
788
|
-
pointerEvents: onboardingInProgress ? "none" : "auto"
|
|
789
|
-
},
|
|
790
|
-
children: "Connect to PayPal"
|
|
791
|
-
}
|
|
792
|
-
),
|
|
534
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading…" }) : null
|
|
535
|
+
] }),
|
|
536
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
|
|
537
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Enable/Disable", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
793
538
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
794
|
-
"
|
|
539
|
+
"input",
|
|
795
540
|
{
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
marginBottom: "10px"
|
|
801
|
-
},
|
|
802
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] text-ui-fg-muted leading-none", children: "OR" }) })
|
|
541
|
+
type: "checkbox",
|
|
542
|
+
checked: form.enabled,
|
|
543
|
+
onChange: (e) => setForm((p) => ({ ...p, enabled: e.target.checked })),
|
|
544
|
+
className: "h-4 w-4 rounded border-ui-border-base"
|
|
803
545
|
}
|
|
804
546
|
),
|
|
805
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
onClick: () => setShowManual(!showManual),
|
|
810
|
-
disabled: onboardingInProgress,
|
|
811
|
-
className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
|
|
812
|
-
children: "Click here to insert credentials manually"
|
|
813
|
-
}
|
|
814
|
-
) })
|
|
815
|
-
] }),
|
|
816
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `${connState === "ready" ? "hidden" : "block"} mt-3`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
817
|
-
"button",
|
|
547
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable Advanced Credit/Debit Card" })
|
|
548
|
+
] }) }),
|
|
549
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Title", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
550
|
+
"input",
|
|
818
551
|
{
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
children: "Click here to insert credentials manually"
|
|
552
|
+
value: form.title,
|
|
553
|
+
onChange: (e) => setForm((p) => ({ ...p, title: e.target.value })),
|
|
554
|
+
className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
|
|
555
|
+
placeholder: "Credit or Debit Card"
|
|
824
556
|
}
|
|
825
557
|
) }),
|
|
826
558
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
827
|
-
|
|
559
|
+
FieldRow$1,
|
|
828
560
|
{
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
561
|
+
label: "Disable specific credit cards",
|
|
562
|
+
hint: "Select card brands to hide from the card form.",
|
|
563
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
564
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: form.disabledCards.length ? form.disabledCards.map((v) => {
|
|
565
|
+
var _a2;
|
|
566
|
+
const label = ((_a2 = CARD_BRANDS.find((b) => b.value === v)) == null ? void 0 : _a2.label) ?? v;
|
|
567
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Pill$1, { onRemove: () => removeDisabledCard(v), children: label }, v);
|
|
568
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "No card brands disabled." }) }),
|
|
569
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-ui-border-base p-3", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-2 md:grid-cols-2", children: CARD_BRANDS.map((b) => {
|
|
570
|
+
const checked = disabledSet.has(b.value);
|
|
571
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
572
|
+
"label",
|
|
573
|
+
{
|
|
574
|
+
className: cx$1(
|
|
575
|
+
"flex items-center gap-2 rounded-md p-2",
|
|
576
|
+
"hover:bg-ui-bg-subtle"
|
|
577
|
+
),
|
|
578
|
+
children: [
|
|
579
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
580
|
+
"input",
|
|
581
|
+
{
|
|
582
|
+
type: "checkbox",
|
|
583
|
+
checked,
|
|
584
|
+
onChange: () => toggleDisabledCard(b.value),
|
|
585
|
+
className: "h-4 w-4 rounded border-ui-border-base"
|
|
586
|
+
}
|
|
587
|
+
),
|
|
588
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: b.label })
|
|
589
|
+
]
|
|
590
|
+
},
|
|
591
|
+
b.value
|
|
592
|
+
);
|
|
593
|
+
}) }) })
|
|
594
|
+
] })
|
|
833
595
|
}
|
|
834
|
-
)
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
"
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
{
|
|
856
|
-
type: "password",
|
|
857
|
-
value: secret,
|
|
858
|
-
onChange: (e) => setSecret(e.target.value),
|
|
859
|
-
disabled: onboardingInProgress,
|
|
860
|
-
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
861
|
-
placeholder: env === "sandbox" ? "Sandbox Secret" : "Live Secret"
|
|
862
|
-
}
|
|
863
|
-
)
|
|
864
|
-
] }),
|
|
865
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 md:col-span-2", children: [
|
|
866
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Merchant ID (optional)" }),
|
|
596
|
+
),
|
|
597
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
598
|
+
FieldRow$1,
|
|
599
|
+
{
|
|
600
|
+
label: "Contingency for 3D Secure",
|
|
601
|
+
hint: "Choose when 3D Secure should be triggered during card payments.",
|
|
602
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
603
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
604
|
+
"select",
|
|
605
|
+
{
|
|
606
|
+
value: form.threeDS,
|
|
607
|
+
onChange: (e) => setForm((p) => ({ ...p, threeDS: e.target.value })),
|
|
608
|
+
className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
|
|
609
|
+
children: THREE_DS_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
|
|
610
|
+
}
|
|
611
|
+
),
|
|
612
|
+
((_a = THREE_DS_OPTIONS.find((o) => o.value === form.threeDS)) == null ? void 0 : _a.hint) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-ui-fg-subtle", children: (_b = THREE_DS_OPTIONS.find((o) => o.value === form.threeDS)) == null ? void 0 : _b.hint }) : null
|
|
613
|
+
] })
|
|
614
|
+
}
|
|
615
|
+
),
|
|
616
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Card Save Enabled", hint: "Allow customers to save a card at checkout for future use.", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
867
617
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
868
618
|
"input",
|
|
869
619
|
{
|
|
870
|
-
type: "
|
|
871
|
-
|
|
872
|
-
onChange: (e) =>
|
|
873
|
-
|
|
874
|
-
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
875
|
-
placeholder: "Merchant ID"
|
|
876
|
-
}
|
|
877
|
-
)
|
|
878
|
-
] }),
|
|
879
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:col-span-2 flex items-center gap-2 mt-2", children: [
|
|
880
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
881
|
-
"button",
|
|
882
|
-
{
|
|
883
|
-
type: "button",
|
|
884
|
-
className: "rounded-md border border-ui-border-base px-3 py-2 text-sm font-medium hover:bg-ui-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed",
|
|
885
|
-
onClick: () => setShowManual(false),
|
|
886
|
-
disabled: onboardingInProgress,
|
|
887
|
-
children: "Cancel"
|
|
620
|
+
type: "checkbox",
|
|
621
|
+
checked: form.cardSaveEnabled,
|
|
622
|
+
onChange: (e) => setForm((p) => ({ ...p, cardSaveEnabled: e.target.checked })),
|
|
623
|
+
className: "h-4 w-4 rounded border-ui-border-base"
|
|
888
624
|
}
|
|
889
625
|
),
|
|
890
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
onClick: handleSaveManual,
|
|
897
|
-
children: "Save credentials"
|
|
898
|
-
}
|
|
899
|
-
)
|
|
900
|
-
] })
|
|
901
|
-
] }) })
|
|
902
|
-
] }) })
|
|
903
|
-
] }),
|
|
904
|
-
/* @__PURE__ */ jsxRuntime.jsx("style", { children: `
|
|
905
|
-
.loader {
|
|
906
|
-
border: 3px solid #f3f3f3;
|
|
907
|
-
border-top: 3px solid #0070ba;
|
|
908
|
-
border-radius: 50%;
|
|
909
|
-
width: 18px;
|
|
910
|
-
height: 18px;
|
|
911
|
-
animation: spin 1s linear infinite;
|
|
912
|
-
display: inline-block;
|
|
913
|
-
vertical-align: middle;
|
|
914
|
-
margin-right: 8px;
|
|
915
|
-
}
|
|
916
|
-
@keyframes spin {
|
|
917
|
-
0% { transform: rotate(0deg); }
|
|
918
|
-
100% { transform: rotate(360deg); }
|
|
919
|
-
}
|
|
920
|
-
` })
|
|
921
|
-
] });
|
|
626
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable card saving at checkout" })
|
|
627
|
+
] }) })
|
|
628
|
+
] })
|
|
629
|
+
}
|
|
630
|
+
)
|
|
631
|
+
] }) });
|
|
922
632
|
}
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
title: "Credit or Debit Card",
|
|
926
|
-
disabledCards: [],
|
|
927
|
-
threeDS: "when_required",
|
|
928
|
-
cardSaveEnabled: false
|
|
929
|
-
};
|
|
930
|
-
function mergeWithDefaults(saved) {
|
|
931
|
-
if (!saved) return { ...DEFAULT_FORM };
|
|
932
|
-
const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
|
|
933
|
-
return {
|
|
934
|
-
...DEFAULT_FORM,
|
|
935
|
-
...Object.fromEntries(entries)
|
|
936
|
-
};
|
|
633
|
+
function PayPalApplePayPage() {
|
|
634
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
937
635
|
}
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
{ value: "amex", label: "American Express" },
|
|
942
|
-
{ value: "discover", label: "Discover" },
|
|
943
|
-
{ value: "diners", label: "Diners Club" },
|
|
944
|
-
{ value: "jcb", label: "JCB" },
|
|
945
|
-
{ value: "unionpay", label: "UnionPay" }
|
|
946
|
-
];
|
|
947
|
-
const THREE_DS_OPTIONS = [
|
|
948
|
-
{
|
|
949
|
-
value: "when_required",
|
|
950
|
-
label: "3D Secure when required",
|
|
951
|
-
hint: "Triggers 3DS only when the card / issuer requires it."
|
|
952
|
-
},
|
|
953
|
-
{
|
|
954
|
-
value: "sli",
|
|
955
|
-
label: "3D Secure (SCA) / liability shift (recommended)",
|
|
956
|
-
hint: "Attempts to optimize for liability shift while remaining compliant."
|
|
957
|
-
},
|
|
958
|
-
{
|
|
959
|
-
value: "always",
|
|
960
|
-
label: "Always request 3D Secure",
|
|
961
|
-
hint: "Forces 3DS challenge whenever possible (may reduce conversion)."
|
|
636
|
+
function formatDate$2(value) {
|
|
637
|
+
if (!value) {
|
|
638
|
+
return "";
|
|
962
639
|
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
640
|
+
const parsed = new Date(value);
|
|
641
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
642
|
+
return value;
|
|
643
|
+
}
|
|
644
|
+
return parsed.toLocaleString();
|
|
966
645
|
}
|
|
967
|
-
function
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
{
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
646
|
+
function PayPalAuditLogsPage() {
|
|
647
|
+
const [logs, setLogs] = react.useState([]);
|
|
648
|
+
const [loading, setLoading] = react.useState(false);
|
|
649
|
+
const [error, setError] = react.useState(null);
|
|
650
|
+
const fetchLogs = react.useCallback(async () => {
|
|
651
|
+
try {
|
|
652
|
+
setLoading(true);
|
|
653
|
+
setError(null);
|
|
654
|
+
const response = await fetch("/admin/paypal/audit-logs?limit=50", {
|
|
655
|
+
credentials: "include",
|
|
656
|
+
headers: {
|
|
657
|
+
Accept: "application/json"
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
if (!response.ok) {
|
|
661
|
+
const message = await response.text().catch(() => "");
|
|
662
|
+
throw new Error(message || "Failed to load audit logs.");
|
|
981
663
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
})
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
664
|
+
const data = await response.json().catch(() => ({}));
|
|
665
|
+
setLogs((data == null ? void 0 : data.logs) || []);
|
|
666
|
+
} catch (fetchError) {
|
|
667
|
+
setError((fetchError == null ? void 0 : fetchError.message) || "Failed to load audit logs.");
|
|
668
|
+
setLogs([]);
|
|
669
|
+
} finally {
|
|
670
|
+
setLoading(false);
|
|
671
|
+
}
|
|
672
|
+
}, []);
|
|
673
|
+
react.useEffect(() => {
|
|
674
|
+
fetchLogs();
|
|
675
|
+
}, [fetchLogs]);
|
|
676
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
677
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
678
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Audit Logs" }),
|
|
679
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-ui-fg-subtle", children: "Track administrative changes and credential events for PayPal configuration." })
|
|
998
680
|
] }),
|
|
999
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1000
|
-
|
|
681
|
+
/* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
|
|
682
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
|
|
683
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-ui-border-base p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4", children: [
|
|
684
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: "Latest events" }),
|
|
685
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
686
|
+
"button",
|
|
687
|
+
{
|
|
688
|
+
type: "button",
|
|
689
|
+
onClick: fetchLogs,
|
|
690
|
+
className: "rounded-md border border-ui-border-base px-3 py-2 text-sm text-ui-fg-base",
|
|
691
|
+
disabled: loading,
|
|
692
|
+
children: loading ? "Refreshing..." : "Refresh"
|
|
693
|
+
}
|
|
694
|
+
)
|
|
695
|
+
] }) }),
|
|
696
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
|
|
697
|
+
error ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-red-200 bg-red-50 p-3 text-sm text-red-600", children: error }) : null,
|
|
698
|
+
!error && logs.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-ui-fg-subtle", children: loading ? "Loading audit logs..." : "No audit log entries found yet." }) : null,
|
|
699
|
+
logs.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full text-left text-sm", children: [
|
|
700
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "text-ui-fg-muted", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
701
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 pr-4 font-medium", children: "Timestamp" }),
|
|
702
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 pr-4 font-medium", children: "Event" }),
|
|
703
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 font-medium", children: "Details" })
|
|
704
|
+
] }) }),
|
|
705
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: logs.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-t border-ui-border-base", children: [
|
|
706
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: formatDate$2(entry.created_at) || "—" }),
|
|
707
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: entry.event_type || "—" }),
|
|
708
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 text-ui-fg-subtle", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre-wrap rounded-md bg-ui-bg-subtle p-2 text-xs text-ui-fg-subtle", children: JSON.stringify(entry.metadata || {}, null, 2) }) })
|
|
709
|
+
] }, entry.id)) })
|
|
710
|
+
] }) }) : null
|
|
711
|
+
] })
|
|
712
|
+
] })
|
|
713
|
+
] }) });
|
|
1001
714
|
}
|
|
1002
|
-
|
|
1003
|
-
label,
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
715
|
+
const config = adminSdk.defineRouteConfig({
|
|
716
|
+
label: "PayPal Connection",
|
|
717
|
+
hide: true
|
|
718
|
+
});
|
|
719
|
+
if (typeof window !== "undefined") {
|
|
720
|
+
const preloadHref = "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js";
|
|
721
|
+
const existingPreload = document.head.querySelector(
|
|
722
|
+
`link[rel="preload"][href="${preloadHref}"]`
|
|
723
|
+
);
|
|
724
|
+
if (!existingPreload) {
|
|
725
|
+
const preloadLink = document.createElement("link");
|
|
726
|
+
preloadLink.rel = "preload";
|
|
727
|
+
preloadLink.href = preloadHref;
|
|
728
|
+
preloadLink.as = "script";
|
|
729
|
+
document.head.appendChild(preloadLink);
|
|
730
|
+
}
|
|
731
|
+
const existingScript = document.getElementById(
|
|
732
|
+
"paypal-partner-js"
|
|
733
|
+
);
|
|
734
|
+
if (!existingScript) {
|
|
735
|
+
const ppScript = document.createElement("script");
|
|
736
|
+
ppScript.id = "paypal-partner-js";
|
|
737
|
+
ppScript.src = preloadHref;
|
|
738
|
+
ppScript.async = true;
|
|
739
|
+
document.head.appendChild(ppScript);
|
|
740
|
+
}
|
|
1014
741
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
742
|
+
const SERVICE_URL = "/admin/paypal/onboarding-link";
|
|
743
|
+
const CACHE_KEY = "pp_onboard_cache";
|
|
744
|
+
const RELOAD_KEY = "pp_onboard_reloaded_once";
|
|
745
|
+
const CACHE_EXPIRY = 10 * 60 * 1e3;
|
|
746
|
+
const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
|
|
747
|
+
const STATUS_ENDPOINT = "/admin/paypal/status";
|
|
748
|
+
const SAVE_CREDENTIALS_ENDPOINT = "/admin/paypal/save-credentials";
|
|
749
|
+
const DISCONNECT_ENDPOINT = "/admin/paypal/disconnect";
|
|
750
|
+
let cachedUrl = null;
|
|
751
|
+
if (typeof window !== "undefined") {
|
|
752
|
+
try {
|
|
753
|
+
const cached = localStorage.getItem(CACHE_KEY);
|
|
754
|
+
if (cached) {
|
|
755
|
+
const data = JSON.parse(cached);
|
|
756
|
+
if ((/* @__PURE__ */ new Date()).getTime() - data.ts < CACHE_EXPIRY) {
|
|
757
|
+
cachedUrl = data.url;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
} catch (e) {
|
|
761
|
+
console.error("Cache read error:", e);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
function PayPalConnectionPage() {
|
|
765
|
+
const [env, setEnv] = react.useState("sandbox");
|
|
1022
766
|
react.useEffect(() => {
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
767
|
+
fetch("/admin/paypal/environment", { method: "GET" }).then((r) => r.json()).then((d) => {
|
|
768
|
+
const v = (d == null ? void 0 : d.environment) === "live" ? "live" : "sandbox";
|
|
769
|
+
setEnv(v);
|
|
770
|
+
}).catch(() => {
|
|
771
|
+
});
|
|
772
|
+
}, []);
|
|
773
|
+
const [connState, setConnState] = react.useState("loading");
|
|
774
|
+
const [error, setError] = react.useState(null);
|
|
775
|
+
const [finalUrl, setFinalUrl] = react.useState("");
|
|
776
|
+
const [showManual, setShowManual] = react.useState(false);
|
|
777
|
+
const [clientId, setClientId] = react.useState("");
|
|
778
|
+
const [secret, setSecret] = react.useState("");
|
|
779
|
+
const [merchantId, setMerchantId] = react.useState("");
|
|
780
|
+
const [statusInfo, setStatusInfo] = react.useState(null);
|
|
781
|
+
const [onboardingInProgress, setOnboardingInProgress] = react.useState(false);
|
|
782
|
+
const initLoaderRef = react.useRef(null);
|
|
783
|
+
const paypalButtonRef = react.useRef(null);
|
|
784
|
+
const errorLogRef = react.useRef(null);
|
|
785
|
+
const runIdRef = react.useRef(0);
|
|
786
|
+
const currentRunId = react.useRef(0);
|
|
787
|
+
const ppBtnMeasureRef = react.useRef(null);
|
|
788
|
+
const [ppBtnWidth, setPpBtnWidth] = react.useState(null);
|
|
789
|
+
const canSaveManual = react.useMemo(() => {
|
|
790
|
+
return clientId.trim().length > 0 && secret.trim().length > 0;
|
|
791
|
+
}, [clientId, secret]);
|
|
792
|
+
const maskValue = react.useCallback((value, visibleChars = 4) => {
|
|
793
|
+
if (!value) return "";
|
|
794
|
+
if (value.length <= visibleChars) {
|
|
795
|
+
return "•".repeat(value.length);
|
|
796
|
+
}
|
|
797
|
+
return `${"•".repeat(Math.max(0, value.length - visibleChars))}${value.slice(
|
|
798
|
+
-visibleChars
|
|
799
|
+
)}`;
|
|
800
|
+
}, []);
|
|
801
|
+
const fetchFreshLink = react.useCallback(
|
|
802
|
+
(runId) => {
|
|
803
|
+
if (initLoaderRef.current) {
|
|
804
|
+
const loaderText = initLoaderRef.current.querySelector("#loader-text");
|
|
805
|
+
if (loaderText)
|
|
806
|
+
loaderText.textContent = "Generating onboarding session...";
|
|
807
|
+
}
|
|
808
|
+
fetch(SERVICE_URL, {
|
|
809
|
+
method: "POST",
|
|
810
|
+
headers: { "content-type": "application/json" },
|
|
811
|
+
body: JSON.stringify({
|
|
812
|
+
products: ["PPCP"]
|
|
813
|
+
})
|
|
814
|
+
}).then((r) => r.json()).then((data) => {
|
|
815
|
+
if (runId !== currentRunId.current) return;
|
|
816
|
+
const href = data == null ? void 0 : data.onboarding_url;
|
|
817
|
+
if (!href) {
|
|
818
|
+
showError("Onboarding URL not returned.");
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
const finalUrl2 = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
|
|
822
|
+
localStorage.setItem(
|
|
823
|
+
CACHE_KEY,
|
|
824
|
+
JSON.stringify({
|
|
825
|
+
url: finalUrl2,
|
|
826
|
+
ts: Date.now()
|
|
827
|
+
})
|
|
828
|
+
);
|
|
829
|
+
if (!localStorage.getItem(RELOAD_KEY)) {
|
|
830
|
+
localStorage.setItem(RELOAD_KEY, "1");
|
|
831
|
+
window.location.reload();
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
activatePayPal(finalUrl2, runId);
|
|
835
|
+
}).catch(() => {
|
|
836
|
+
if (runId !== currentRunId.current) return;
|
|
837
|
+
showError("Unable to connect to service.");
|
|
838
|
+
});
|
|
839
|
+
},
|
|
840
|
+
[env]
|
|
841
|
+
);
|
|
842
|
+
const showUI = react.useCallback(() => {
|
|
843
|
+
var _a, _b, _c, _d;
|
|
844
|
+
const btn = document.querySelector('[data-paypal-button="true"]');
|
|
845
|
+
if (btn && ((_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.init)) {
|
|
846
|
+
window.PAYPAL.apps.Signup.miniBrowser.init();
|
|
847
|
+
}
|
|
848
|
+
setConnState("ready");
|
|
849
|
+
}, []);
|
|
850
|
+
const showError = react.useCallback((msg) => {
|
|
851
|
+
setConnState("error");
|
|
852
|
+
setError(msg);
|
|
853
|
+
}, []);
|
|
854
|
+
const activatePayPal = react.useCallback(
|
|
855
|
+
(url, runId) => {
|
|
856
|
+
if (paypalButtonRef.current) {
|
|
857
|
+
paypalButtonRef.current.href = url;
|
|
858
|
+
}
|
|
859
|
+
setFinalUrl(url);
|
|
860
|
+
const tryInit = () => {
|
|
861
|
+
var _a, _b;
|
|
862
|
+
if (runId !== currentRunId.current) return;
|
|
863
|
+
if ((_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) {
|
|
864
|
+
showUI();
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
setTimeout(tryInit, 50);
|
|
868
|
+
};
|
|
869
|
+
tryInit();
|
|
870
|
+
},
|
|
871
|
+
[showUI]
|
|
872
|
+
);
|
|
873
|
+
react.useEffect(() => {
|
|
874
|
+
currentRunId.current = ++runIdRef.current;
|
|
875
|
+
const runId = currentRunId.current;
|
|
876
|
+
let cancelled = false;
|
|
877
|
+
const run = async () => {
|
|
878
|
+
setConnState("loading");
|
|
879
|
+
setError(null);
|
|
880
|
+
setFinalUrl("");
|
|
881
|
+
try {
|
|
882
|
+
const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
883
|
+
method: "GET"
|
|
884
|
+
});
|
|
885
|
+
const st = await r.json().catch(() => ({}));
|
|
886
|
+
if (cancelled || runId !== currentRunId.current) return;
|
|
887
|
+
setStatusInfo(st);
|
|
888
|
+
const isConnected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
|
|
889
|
+
if (isConnected) {
|
|
890
|
+
setConnState("connected");
|
|
891
|
+
setShowManual(false);
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
} catch (e) {
|
|
895
|
+
console.error(e);
|
|
896
|
+
}
|
|
897
|
+
if (cachedUrl) {
|
|
898
|
+
console.log("Using prioritized cache...");
|
|
899
|
+
activatePayPal(cachedUrl, runId);
|
|
900
|
+
} else {
|
|
901
|
+
fetchFreshLink(runId);
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
run();
|
|
905
|
+
return () => {
|
|
906
|
+
cancelled = true;
|
|
907
|
+
currentRunId.current = 0;
|
|
908
|
+
};
|
|
909
|
+
}, [env, fetchFreshLink, activatePayPal]);
|
|
910
|
+
react.useLayoutEffect(() => {
|
|
911
|
+
window.onboardingCallback = async function(authCode, sharedId) {
|
|
912
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
913
|
+
try {
|
|
914
|
+
;
|
|
915
|
+
window.onbeforeunload = "";
|
|
916
|
+
} catch {
|
|
917
|
+
}
|
|
918
|
+
setOnboardingInProgress(true);
|
|
919
|
+
setConnState("loading");
|
|
920
|
+
setError(null);
|
|
921
|
+
const payload = {
|
|
922
|
+
authCode,
|
|
923
|
+
sharedId,
|
|
924
|
+
env: env === "sandbox" ? "sandbox" : "live"
|
|
925
|
+
};
|
|
926
|
+
try {
|
|
927
|
+
const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
|
|
928
|
+
method: "POST",
|
|
929
|
+
headers: { "content-type": "application/json" },
|
|
930
|
+
body: JSON.stringify(payload)
|
|
931
|
+
});
|
|
932
|
+
if (!res.ok) {
|
|
933
|
+
const txt = await res.text().catch(() => "");
|
|
934
|
+
throw new Error(txt || `Onboarding exchange failed (${res.status})`);
|
|
935
|
+
}
|
|
936
|
+
try {
|
|
937
|
+
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;
|
|
938
|
+
if (typeof close1 === "function") close1();
|
|
939
|
+
} catch {
|
|
940
|
+
}
|
|
941
|
+
try {
|
|
942
|
+
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;
|
|
943
|
+
if (typeof close2 === "function") close2();
|
|
944
|
+
} catch {
|
|
945
|
+
}
|
|
946
|
+
try {
|
|
947
|
+
localStorage.removeItem(CACHE_KEY);
|
|
948
|
+
localStorage.removeItem(RELOAD_KEY);
|
|
949
|
+
} catch {
|
|
950
|
+
}
|
|
951
|
+
window.location.href = window.location.href;
|
|
952
|
+
} catch (e) {
|
|
953
|
+
console.error(e);
|
|
954
|
+
setConnState("error");
|
|
955
|
+
setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
|
|
956
|
+
setOnboardingInProgress(false);
|
|
957
|
+
}
|
|
958
|
+
};
|
|
959
|
+
return () => {
|
|
960
|
+
window.onboardingCallback = void 0;
|
|
961
|
+
};
|
|
962
|
+
}, [env]);
|
|
963
|
+
react.useLayoutEffect(() => {
|
|
964
|
+
const el = ppBtnMeasureRef.current;
|
|
965
|
+
if (!el) return;
|
|
966
|
+
const update = () => {
|
|
967
|
+
const w = Math.round(el.getBoundingClientRect().width || 0);
|
|
968
|
+
if (w > 0) setPpBtnWidth(w);
|
|
969
|
+
};
|
|
970
|
+
update();
|
|
971
|
+
let ro = null;
|
|
972
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
973
|
+
ro = new ResizeObserver(() => update());
|
|
974
|
+
ro.observe(el);
|
|
975
|
+
} else {
|
|
976
|
+
window.addEventListener("resize", update);
|
|
977
|
+
}
|
|
978
|
+
return () => {
|
|
979
|
+
if (ro) ro.disconnect();
|
|
980
|
+
else window.removeEventListener("resize", update);
|
|
981
|
+
};
|
|
982
|
+
}, [connState, env, finalUrl]);
|
|
983
|
+
const handleConnectClick = (e) => {
|
|
984
|
+
if (connState !== "ready" || !finalUrl || onboardingInProgress) {
|
|
985
|
+
e.preventDefault();
|
|
986
|
+
}
|
|
987
|
+
};
|
|
988
|
+
const handleSaveManual = async () => {
|
|
989
|
+
if (!canSaveManual || onboardingInProgress) return;
|
|
990
|
+
setOnboardingInProgress(true);
|
|
991
|
+
setConnState("loading");
|
|
992
|
+
setError(null);
|
|
993
|
+
try {
|
|
994
|
+
const res = await fetch(SAVE_CREDENTIALS_ENDPOINT, {
|
|
995
|
+
method: "POST",
|
|
996
|
+
headers: { "content-type": "application/json" },
|
|
997
|
+
body: JSON.stringify({
|
|
998
|
+
clientId: clientId.trim(),
|
|
999
|
+
clientSecret: secret.trim()
|
|
1000
|
+
})
|
|
1001
|
+
});
|
|
1002
|
+
if (!res.ok) {
|
|
1003
|
+
const txt = await res.text().catch(() => "");
|
|
1004
|
+
throw new Error(txt || `Save credentials failed (${res.status})`);
|
|
1005
|
+
}
|
|
1006
|
+
setConnState("connected");
|
|
1007
|
+
setStatusInfo({
|
|
1008
|
+
seller_client_id_masked: maskValue(clientId.trim()),
|
|
1009
|
+
seller_client_secret_masked: "••••••••"
|
|
1010
|
+
});
|
|
1011
|
+
setShowManual(false);
|
|
1026
1012
|
try {
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
headers: { "Accept": "application/json" }
|
|
1031
|
-
});
|
|
1032
|
-
if (!r.ok) return;
|
|
1033
|
-
const json = await r.json();
|
|
1034
|
-
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
1035
|
-
const saved = payload == null ? void 0 : payload.advanced_card_payments;
|
|
1036
|
-
if (saved && typeof saved === "object") {
|
|
1037
|
-
setForm(mergeWithDefaults(saved));
|
|
1038
|
-
}
|
|
1039
|
-
} finally {
|
|
1040
|
-
setLoading(false);
|
|
1013
|
+
localStorage.removeItem(CACHE_KEY);
|
|
1014
|
+
localStorage.removeItem(RELOAD_KEY);
|
|
1015
|
+
} catch {
|
|
1041
1016
|
}
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1017
|
+
} catch (e) {
|
|
1018
|
+
console.error(e);
|
|
1019
|
+
setConnState("error");
|
|
1020
|
+
setError((e == null ? void 0 : e.message) || "Failed to save credentials.");
|
|
1021
|
+
} finally {
|
|
1022
|
+
setOnboardingInProgress(false);
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
const handleDisconnect = async () => {
|
|
1026
|
+
if (onboardingInProgress) return;
|
|
1027
|
+
if (!window.confirm("Disconnect PayPal for this environment?")) return;
|
|
1028
|
+
setOnboardingInProgress(true);
|
|
1029
|
+
setConnState("loading");
|
|
1030
|
+
setError(null);
|
|
1031
|
+
setFinalUrl("");
|
|
1032
|
+
setShowManual(false);
|
|
1045
1033
|
try {
|
|
1046
|
-
|
|
1047
|
-
const r = await fetch("/admin/paypal/settings", {
|
|
1034
|
+
const res = await fetch(DISCONNECT_ENDPOINT, {
|
|
1048
1035
|
method: "POST",
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
"Content-Type": "application/json",
|
|
1052
|
-
"Accept": "application/json"
|
|
1053
|
-
},
|
|
1054
|
-
body: JSON.stringify({ advanced_card_payments: form })
|
|
1036
|
+
headers: { "content-type": "application/json" },
|
|
1037
|
+
body: JSON.stringify({ environment: env })
|
|
1055
1038
|
});
|
|
1056
|
-
if (!
|
|
1057
|
-
const t = await
|
|
1058
|
-
|
|
1059
|
-
window.setTimeout(() => setToast(null), 3500);
|
|
1060
|
-
return;
|
|
1039
|
+
if (!res.ok) {
|
|
1040
|
+
const t = await res.text().catch(() => "");
|
|
1041
|
+
throw new Error(t || `Disconnect failed (${res.status})`);
|
|
1061
1042
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
setForm(mergeWithDefaults(saved));
|
|
1043
|
+
try {
|
|
1044
|
+
localStorage.removeItem(CACHE_KEY);
|
|
1045
|
+
localStorage.removeItem(RELOAD_KEY);
|
|
1046
|
+
} catch {
|
|
1067
1047
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1048
|
+
currentRunId.current = ++runIdRef.current;
|
|
1049
|
+
const runId = currentRunId.current;
|
|
1050
|
+
fetchFreshLink(runId);
|
|
1051
|
+
} catch (e) {
|
|
1052
|
+
console.error(e);
|
|
1053
|
+
setConnState("error");
|
|
1054
|
+
setError((e == null ? void 0 : e.message) || "Failed to disconnect.");
|
|
1070
1055
|
} finally {
|
|
1071
|
-
|
|
1056
|
+
setOnboardingInProgress(false);
|
|
1072
1057
|
}
|
|
1073
|
-
}
|
|
1074
|
-
const
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
"
|
|
1095
|
-
{
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
"
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1058
|
+
};
|
|
1059
|
+
const handleEnvChange = async (e) => {
|
|
1060
|
+
const next = e.target.value;
|
|
1061
|
+
setEnv(next);
|
|
1062
|
+
cachedUrl = null;
|
|
1063
|
+
try {
|
|
1064
|
+
await fetch("/admin/paypal/environment", {
|
|
1065
|
+
method: "POST",
|
|
1066
|
+
headers: { "content-type": "application/json" },
|
|
1067
|
+
body: JSON.stringify({ environment: next })
|
|
1068
|
+
});
|
|
1069
|
+
} catch {
|
|
1070
|
+
}
|
|
1071
|
+
try {
|
|
1072
|
+
localStorage.removeItem(CACHE_KEY);
|
|
1073
|
+
localStorage.removeItem(RELOAD_KEY);
|
|
1074
|
+
} catch {
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6", children: [
|
|
1078
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
1079
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold", children: "PayPal Gateway By Easy Payment" }),
|
|
1080
|
+
/* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
|
|
1081
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-ui-border-base p-4 shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-y-6 md:grid-cols-[260px_1fr] md:items-start", children: [
|
|
1082
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium pt-2", children: "Environment" }),
|
|
1083
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xl", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1084
|
+
"select",
|
|
1085
|
+
{
|
|
1086
|
+
value: env,
|
|
1087
|
+
onChange: handleEnvChange,
|
|
1088
|
+
disabled: onboardingInProgress,
|
|
1089
|
+
className: "w-full rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm",
|
|
1090
|
+
children: [
|
|
1091
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "sandbox", children: "Sandbox (Test Mode)" }),
|
|
1092
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "live", children: "Live (Production)" })
|
|
1093
|
+
]
|
|
1094
|
+
}
|
|
1095
|
+
) }),
|
|
1096
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium pt-2", children: env === "sandbox" ? "Connect to PayPal Sandbox" : "Connect to PayPal Live" }),
|
|
1097
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xl", children: connState === "connected" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1098
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: [
|
|
1099
|
+
"✅ Successfully connected to PayPal!",
|
|
1100
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1101
|
+
"a",
|
|
1102
|
+
{
|
|
1103
|
+
"data-paypal-button": "true",
|
|
1104
|
+
"data-paypal-onboard-complete": "onboardingCallback",
|
|
1105
|
+
href: "#",
|
|
1106
|
+
style: { display: "none" },
|
|
1107
|
+
children: "PayPal"
|
|
1108
|
+
}
|
|
1109
|
+
)
|
|
1110
|
+
] }),
|
|
1111
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 rounded-md border border-ui-border-base bg-ui-bg-subtle p-3 text-xs text-ui-fg-subtle", children: [
|
|
1112
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-ui-fg-base", children: "Connected PayPal account" }),
|
|
1113
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1", children: [
|
|
1114
|
+
"Email:",
|
|
1115
|
+
" ",
|
|
1116
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-ui-fg-base", children: (statusInfo == null ? void 0 : statusInfo.seller_email) || "Unavailable" })
|
|
1117
|
+
] })
|
|
1118
|
+
] }),
|
|
1119
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1109
1120
|
"button",
|
|
1110
1121
|
{
|
|
1111
1122
|
type: "button",
|
|
1112
|
-
onClick:
|
|
1113
|
-
disabled:
|
|
1114
|
-
className: "rounded-md
|
|
1115
|
-
children:
|
|
1123
|
+
onClick: handleDisconnect,
|
|
1124
|
+
disabled: onboardingInProgress,
|
|
1125
|
+
className: "rounded-md border border-ui-border-base px-3 py-2 text-sm font-medium hover:bg-ui-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1126
|
+
children: "Disconnect"
|
|
1127
|
+
}
|
|
1128
|
+
) })
|
|
1129
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1130
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1131
|
+
"div",
|
|
1132
|
+
{
|
|
1133
|
+
ref: initLoaderRef,
|
|
1134
|
+
id: "init-loader",
|
|
1135
|
+
className: `status-msg mb-4 ${connState !== "loading" ? "hidden" : "block"}`,
|
|
1136
|
+
children: [
|
|
1137
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "loader inline-block align-middle mr-2" }),
|
|
1138
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { id: "loader-text", className: "text-sm", children: onboardingInProgress ? "Configuring connection to PayPal…" : "Checking connection..." })
|
|
1139
|
+
]
|
|
1116
1140
|
}
|
|
1117
1141
|
),
|
|
1118
|
-
|
|
1119
|
-
] }),
|
|
1120
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
|
|
1121
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Enable/Disable", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
1142
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${connState === "ready" ? "block" : "hidden"}`, children: [
|
|
1122
1143
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1123
|
-
"
|
|
1144
|
+
"a",
|
|
1124
1145
|
{
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1146
|
+
ref: (node) => {
|
|
1147
|
+
paypalButtonRef.current = node;
|
|
1148
|
+
ppBtnMeasureRef.current = node;
|
|
1149
|
+
},
|
|
1150
|
+
id: "paypal-button",
|
|
1151
|
+
"data-paypal-button": "true",
|
|
1152
|
+
href: finalUrl || "#",
|
|
1153
|
+
"data-paypal-onboard-complete": "onboardingCallback",
|
|
1154
|
+
onClick: handleConnectClick,
|
|
1155
|
+
className: "btn-paypal",
|
|
1156
|
+
style: {
|
|
1157
|
+
borderRadius: "50px",
|
|
1158
|
+
textDecoration: "none",
|
|
1159
|
+
display: "inline-block",
|
|
1160
|
+
fontWeight: "bold",
|
|
1161
|
+
border: "none",
|
|
1162
|
+
cursor: onboardingInProgress ? "not-allowed" : "pointer",
|
|
1163
|
+
opacity: onboardingInProgress ? 0.6 : 1,
|
|
1164
|
+
pointerEvents: onboardingInProgress ? "none" : "auto"
|
|
1165
|
+
},
|
|
1166
|
+
children: "Connect to PayPal"
|
|
1129
1167
|
}
|
|
1130
1168
|
),
|
|
1131
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1169
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1170
|
+
"div",
|
|
1171
|
+
{
|
|
1172
|
+
className: "mt-2",
|
|
1173
|
+
style: {
|
|
1174
|
+
width: ppBtnWidth ? `${ppBtnWidth}px` : "auto",
|
|
1175
|
+
marginTop: "20px",
|
|
1176
|
+
marginBottom: "10px"
|
|
1177
|
+
},
|
|
1178
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] text-ui-fg-muted leading-none", children: "OR" }) })
|
|
1179
|
+
}
|
|
1180
|
+
),
|
|
1181
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1182
|
+
"button",
|
|
1183
|
+
{
|
|
1184
|
+
type: "button",
|
|
1185
|
+
onClick: () => setShowManual(!showManual),
|
|
1186
|
+
disabled: onboardingInProgress,
|
|
1187
|
+
className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1188
|
+
children: "Click here to insert credentials manually"
|
|
1189
|
+
}
|
|
1190
|
+
) })
|
|
1191
|
+
] }),
|
|
1192
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `${connState === "ready" ? "hidden" : "block"} mt-3`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1193
|
+
"button",
|
|
1135
1194
|
{
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1195
|
+
type: "button",
|
|
1196
|
+
onClick: () => setShowManual(!showManual),
|
|
1197
|
+
disabled: onboardingInProgress,
|
|
1198
|
+
className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1199
|
+
children: "Click here to insert credentials manually"
|
|
1140
1200
|
}
|
|
1141
1201
|
) }),
|
|
1142
1202
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1143
|
-
|
|
1144
|
-
{
|
|
1145
|
-
label: "Disable specific credit cards",
|
|
1146
|
-
hint: "Select card brands to hide from the card form.",
|
|
1147
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
1148
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: form.disabledCards.length ? form.disabledCards.map((v) => {
|
|
1149
|
-
var _a2;
|
|
1150
|
-
const label = ((_a2 = CARD_BRANDS.find((b) => b.value === v)) == null ? void 0 : _a2.label) ?? v;
|
|
1151
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Pill$1, { onRemove: () => removeDisabledCard(v), children: label }, v);
|
|
1152
|
-
}) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "No card brands disabled." }) }),
|
|
1153
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-ui-border-base p-3", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-2 md:grid-cols-2", children: CARD_BRANDS.map((b) => {
|
|
1154
|
-
const checked = disabledSet.has(b.value);
|
|
1155
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1156
|
-
"label",
|
|
1157
|
-
{
|
|
1158
|
-
className: cx$1(
|
|
1159
|
-
"flex items-center gap-2 rounded-md p-2",
|
|
1160
|
-
"hover:bg-ui-bg-subtle"
|
|
1161
|
-
),
|
|
1162
|
-
children: [
|
|
1163
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1164
|
-
"input",
|
|
1165
|
-
{
|
|
1166
|
-
type: "checkbox",
|
|
1167
|
-
checked,
|
|
1168
|
-
onChange: () => toggleDisabledCard(b.value),
|
|
1169
|
-
className: "h-4 w-4 rounded border-ui-border-base"
|
|
1170
|
-
}
|
|
1171
|
-
),
|
|
1172
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: b.label })
|
|
1173
|
-
]
|
|
1174
|
-
},
|
|
1175
|
-
b.value
|
|
1176
|
-
);
|
|
1177
|
-
}) }) })
|
|
1178
|
-
] })
|
|
1179
|
-
}
|
|
1180
|
-
),
|
|
1181
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1182
|
-
FieldRow$1,
|
|
1203
|
+
"div",
|
|
1183
1204
|
{
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
"select",
|
|
1189
|
-
{
|
|
1190
|
-
value: form.threeDS,
|
|
1191
|
-
onChange: (e) => setForm((p) => ({ ...p, threeDS: e.target.value })),
|
|
1192
|
-
className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive",
|
|
1193
|
-
children: THREE_DS_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
|
|
1194
|
-
}
|
|
1195
|
-
),
|
|
1196
|
-
((_a = THREE_DS_OPTIONS.find((o) => o.value === form.threeDS)) == null ? void 0 : _a.hint) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-ui-fg-subtle", children: (_b = THREE_DS_OPTIONS.find((o) => o.value === form.threeDS)) == null ? void 0 : _b.hint }) : null
|
|
1197
|
-
] })
|
|
1205
|
+
ref: errorLogRef,
|
|
1206
|
+
id: "error-log",
|
|
1207
|
+
className: `mt-4 text-left text-xs bg-red-50 text-red-600 p-3 border border-red-200 rounded ${connState === "error" && error ? "block" : "hidden"}`,
|
|
1208
|
+
children: error
|
|
1198
1209
|
}
|
|
1199
|
-
)
|
|
1200
|
-
|
|
1210
|
+
)
|
|
1211
|
+
] }) }),
|
|
1212
|
+
showManual && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:col-span-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-[260px] max-w-xl mt-4 grid grid-cols-1 gap-3 md:grid-cols-2", children: [
|
|
1213
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
1214
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Client ID" }),
|
|
1201
1215
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1202
1216
|
"input",
|
|
1203
1217
|
{
|
|
1204
|
-
type: "
|
|
1205
|
-
|
|
1206
|
-
onChange: (e) =>
|
|
1207
|
-
|
|
1218
|
+
type: "text",
|
|
1219
|
+
value: clientId,
|
|
1220
|
+
onChange: (e) => setClientId(e.target.value),
|
|
1221
|
+
disabled: onboardingInProgress,
|
|
1222
|
+
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
1223
|
+
placeholder: env === "sandbox" ? "Sandbox Client ID" : "Live Client ID"
|
|
1224
|
+
}
|
|
1225
|
+
)
|
|
1226
|
+
] }),
|
|
1227
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
1228
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Client Secret" }),
|
|
1229
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1230
|
+
"input",
|
|
1231
|
+
{
|
|
1232
|
+
type: "password",
|
|
1233
|
+
value: secret,
|
|
1234
|
+
onChange: (e) => setSecret(e.target.value),
|
|
1235
|
+
disabled: onboardingInProgress,
|
|
1236
|
+
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
1237
|
+
placeholder: env === "sandbox" ? "Sandbox Secret" : "Live Secret"
|
|
1238
|
+
}
|
|
1239
|
+
)
|
|
1240
|
+
] }),
|
|
1241
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 md:col-span-2", children: [
|
|
1242
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Merchant ID (optional)" }),
|
|
1243
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1244
|
+
"input",
|
|
1245
|
+
{
|
|
1246
|
+
type: "text",
|
|
1247
|
+
value: merchantId,
|
|
1248
|
+
onChange: (e) => setMerchantId(e.target.value),
|
|
1249
|
+
disabled: onboardingInProgress,
|
|
1250
|
+
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
1251
|
+
placeholder: "Merchant ID"
|
|
1252
|
+
}
|
|
1253
|
+
)
|
|
1254
|
+
] }),
|
|
1255
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:col-span-2 flex items-center gap-2 mt-2", children: [
|
|
1256
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1257
|
+
"button",
|
|
1258
|
+
{
|
|
1259
|
+
type: "button",
|
|
1260
|
+
className: "rounded-md border border-ui-border-base px-3 py-2 text-sm font-medium hover:bg-ui-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1261
|
+
onClick: () => setShowManual(false),
|
|
1262
|
+
disabled: onboardingInProgress,
|
|
1263
|
+
children: "Cancel"
|
|
1208
1264
|
}
|
|
1209
1265
|
),
|
|
1210
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
return value;
|
|
1224
|
-
}
|
|
1225
|
-
return parsed.toLocaleString();
|
|
1226
|
-
}
|
|
1227
|
-
function PayPalAuditLogsPage() {
|
|
1228
|
-
const [logs, setLogs] = react.useState([]);
|
|
1229
|
-
const [loading, setLoading] = react.useState(false);
|
|
1230
|
-
const [error, setError] = react.useState(null);
|
|
1231
|
-
const fetchLogs = react.useCallback(async () => {
|
|
1232
|
-
try {
|
|
1233
|
-
setLoading(true);
|
|
1234
|
-
setError(null);
|
|
1235
|
-
const response = await fetch("/admin/paypal/audit-logs?limit=50", {
|
|
1236
|
-
credentials: "include",
|
|
1237
|
-
headers: {
|
|
1238
|
-
Accept: "application/json"
|
|
1239
|
-
}
|
|
1240
|
-
});
|
|
1241
|
-
if (!response.ok) {
|
|
1242
|
-
const message = await response.text().catch(() => "");
|
|
1243
|
-
throw new Error(message || "Failed to load audit logs.");
|
|
1244
|
-
}
|
|
1245
|
-
const data = await response.json().catch(() => ({}));
|
|
1246
|
-
setLogs((data == null ? void 0 : data.logs) || []);
|
|
1247
|
-
} catch (fetchError) {
|
|
1248
|
-
setError((fetchError == null ? void 0 : fetchError.message) || "Failed to load audit logs.");
|
|
1249
|
-
setLogs([]);
|
|
1250
|
-
} finally {
|
|
1251
|
-
setLoading(false);
|
|
1252
|
-
}
|
|
1253
|
-
}, []);
|
|
1254
|
-
react.useEffect(() => {
|
|
1255
|
-
fetchLogs();
|
|
1256
|
-
}, [fetchLogs]);
|
|
1257
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
1258
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1259
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Audit Logs" }),
|
|
1260
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-ui-fg-subtle", children: "Track administrative changes and credential events for PayPal configuration." })
|
|
1266
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1267
|
+
"button",
|
|
1268
|
+
{
|
|
1269
|
+
type: "button",
|
|
1270
|
+
className: "rounded-md border border-ui-border-base px-3 py-2 text-sm font-medium bg-ui-bg-base hover:bg-ui-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1271
|
+
disabled: !canSaveManual || onboardingInProgress,
|
|
1272
|
+
onClick: handleSaveManual,
|
|
1273
|
+
children: "Save credentials"
|
|
1274
|
+
}
|
|
1275
|
+
)
|
|
1276
|
+
] })
|
|
1277
|
+
] }) })
|
|
1278
|
+
] }) })
|
|
1261
1279
|
] }),
|
|
1262
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
logs.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full text-left text-sm", children: [
|
|
1281
|
-
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "text-ui-fg-muted", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
1282
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 pr-4 font-medium", children: "Timestamp" }),
|
|
1283
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 pr-4 font-medium", children: "Event" }),
|
|
1284
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 font-medium", children: "Details" })
|
|
1285
|
-
] }) }),
|
|
1286
|
-
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: logs.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-t border-ui-border-base", children: [
|
|
1287
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: formatDate$2(entry.created_at) || "—" }),
|
|
1288
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: entry.event_type || "—" }),
|
|
1289
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 text-ui-fg-subtle", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre-wrap rounded-md bg-ui-bg-subtle p-2 text-xs text-ui-fg-subtle", children: JSON.stringify(entry.metadata || {}, null, 2) }) })
|
|
1290
|
-
] }, entry.id)) })
|
|
1291
|
-
] }) }) : null
|
|
1292
|
-
] })
|
|
1293
|
-
] })
|
|
1294
|
-
] }) });
|
|
1295
|
-
}
|
|
1296
|
-
function PayPalApplePayPage() {
|
|
1297
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
1280
|
+
/* @__PURE__ */ jsxRuntime.jsx("style", { children: `
|
|
1281
|
+
.loader {
|
|
1282
|
+
border: 3px solid #f3f3f3;
|
|
1283
|
+
border-top: 3px solid #0070ba;
|
|
1284
|
+
border-radius: 50%;
|
|
1285
|
+
width: 18px;
|
|
1286
|
+
height: 18px;
|
|
1287
|
+
animation: spin 1s linear infinite;
|
|
1288
|
+
display: inline-block;
|
|
1289
|
+
vertical-align: middle;
|
|
1290
|
+
margin-right: 8px;
|
|
1291
|
+
}
|
|
1292
|
+
@keyframes spin {
|
|
1293
|
+
0% { transform: rotate(0deg); }
|
|
1294
|
+
100% { transform: rotate(360deg); }
|
|
1295
|
+
}
|
|
1296
|
+
` })
|
|
1297
|
+
] });
|
|
1298
1298
|
}
|
|
1299
1299
|
const EMPTY_FILTERS = {
|
|
1300
1300
|
dispute_id: "",
|
|
@@ -2052,21 +2052,21 @@ const routeModule = {
|
|
|
2052
2052
|
Component: AdditionalSettingsTab,
|
|
2053
2053
|
path: "/settings/paypal/additional-settings"
|
|
2054
2054
|
},
|
|
2055
|
-
{
|
|
2056
|
-
Component: PayPalConnectionPage,
|
|
2057
|
-
path: "/settings/paypal/connection"
|
|
2058
|
-
},
|
|
2059
2055
|
{
|
|
2060
2056
|
Component: AdvancedCardPaymentsTab,
|
|
2061
2057
|
path: "/settings/paypal/advanced-card-payments"
|
|
2062
2058
|
},
|
|
2059
|
+
{
|
|
2060
|
+
Component: PayPalApplePayPage,
|
|
2061
|
+
path: "/settings/paypal/apple-pay"
|
|
2062
|
+
},
|
|
2063
2063
|
{
|
|
2064
2064
|
Component: PayPalAuditLogsPage,
|
|
2065
2065
|
path: "/settings/paypal/audit-logs"
|
|
2066
2066
|
},
|
|
2067
2067
|
{
|
|
2068
|
-
Component:
|
|
2069
|
-
path: "/settings/paypal/
|
|
2068
|
+
Component: PayPalConnectionPage,
|
|
2069
|
+
path: "/settings/paypal/connection"
|
|
2070
2070
|
},
|
|
2071
2071
|
{
|
|
2072
2072
|
Component: PayPalDisputesPage,
|