@easypayment/medusa-paypal 0.2.2 → 0.2.3
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 +657 -657
- package/.medusa/server/src/admin/index.mjs +657 -657
- package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -1
- package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js +18 -8
- package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/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 +19 -2
- package/.medusa/server/src/modules/paypal/payment-provider/service.js.map +1 -1
- package/package.json +1 -1
- package/src/api/store/payment-collections/[id]/payment-sessions/route.ts +24 -8
- package/src/modules/paypal/payment-provider/service.ts +19 -2
|
@@ -336,392 +336,98 @@ 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
|
-
|
|
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)."
|
|
339
|
+
const config = adminSdk.defineRouteConfig({
|
|
340
|
+
label: "PayPal Connection",
|
|
341
|
+
hide: true
|
|
342
|
+
});
|
|
343
|
+
if (typeof window !== "undefined") {
|
|
344
|
+
const preloadHref = "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js";
|
|
345
|
+
const existingPreload = document.head.querySelector(
|
|
346
|
+
`link[rel="preload"][href="${preloadHref}"]`
|
|
347
|
+
);
|
|
348
|
+
if (!existingPreload) {
|
|
349
|
+
const preloadLink = document.createElement("link");
|
|
350
|
+
preloadLink.rel = "preload";
|
|
351
|
+
preloadLink.href = preloadHref;
|
|
352
|
+
preloadLink.as = "script";
|
|
353
|
+
document.head.appendChild(preloadLink);
|
|
354
|
+
}
|
|
355
|
+
const existingScript = document.getElementById(
|
|
356
|
+
"paypal-partner-js"
|
|
357
|
+
);
|
|
358
|
+
if (!existingScript) {
|
|
359
|
+
const ppScript = document.createElement("script");
|
|
360
|
+
ppScript.id = "paypal-partner-js";
|
|
361
|
+
ppScript.src = preloadHref;
|
|
362
|
+
ppScript.async = true;
|
|
363
|
+
document.head.appendChild(ppScript);
|
|
378
364
|
}
|
|
379
|
-
];
|
|
380
|
-
function cx$1(...parts) {
|
|
381
|
-
return parts.filter(Boolean).join(" ");
|
|
382
365
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
366
|
+
const SERVICE_URL = "/admin/paypal/onboarding-link";
|
|
367
|
+
const CACHE_KEY = "pp_onboard_cache";
|
|
368
|
+
const RELOAD_KEY = "pp_onboard_reloaded_once";
|
|
369
|
+
const CACHE_EXPIRY = 10 * 60 * 1e3;
|
|
370
|
+
const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
|
|
371
|
+
const STATUS_ENDPOINT = "/admin/paypal/status";
|
|
372
|
+
const SAVE_CREDENTIALS_ENDPOINT = "/admin/paypal/save-credentials";
|
|
373
|
+
const DISCONNECT_ENDPOINT = "/admin/paypal/disconnect";
|
|
374
|
+
let cachedUrl = null;
|
|
375
|
+
if (typeof window !== "undefined") {
|
|
376
|
+
try {
|
|
377
|
+
const cached = localStorage.getItem(CACHE_KEY);
|
|
378
|
+
if (cached) {
|
|
379
|
+
const data = JSON.parse(cached);
|
|
380
|
+
if ((/* @__PURE__ */ new Date()).getTime() - data.ts < CACHE_EXPIRY) {
|
|
381
|
+
cachedUrl = data.url;
|
|
397
382
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
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
|
-
] });
|
|
383
|
+
}
|
|
384
|
+
} catch (e) {
|
|
385
|
+
console.error("Cache read error:", e);
|
|
386
|
+
}
|
|
430
387
|
}
|
|
431
|
-
function
|
|
432
|
-
|
|
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);
|
|
388
|
+
function PayPalConnectionPage() {
|
|
389
|
+
const [env, setEnv] = react.useState("sandbox");
|
|
438
390
|
react.useEffect(() => {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
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);
|
|
457
|
-
}
|
|
458
|
-
})();
|
|
391
|
+
fetch("/admin/paypal/environment", { method: "GET" }).then((r) => r.json()).then((d) => {
|
|
392
|
+
const v = (d == null ? void 0 : d.environment) === "live" ? "live" : "sandbox";
|
|
393
|
+
setEnv(v);
|
|
394
|
+
}).catch(() => {
|
|
395
|
+
});
|
|
459
396
|
}, []);
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
}
|
|
484
|
-
setToast({ type: "success", message: "Settings saved" });
|
|
485
|
-
window.setTimeout(() => setToast(null), 2500);
|
|
486
|
-
} finally {
|
|
487
|
-
setSaving(false);
|
|
397
|
+
const [connState, setConnState] = react.useState("loading");
|
|
398
|
+
const [error, setError] = react.useState(null);
|
|
399
|
+
const [finalUrl, setFinalUrl] = react.useState("");
|
|
400
|
+
const [showManual, setShowManual] = react.useState(false);
|
|
401
|
+
const [clientId, setClientId] = react.useState("");
|
|
402
|
+
const [secret, setSecret] = react.useState("");
|
|
403
|
+
const [merchantId, setMerchantId] = react.useState("");
|
|
404
|
+
const [statusInfo, setStatusInfo] = react.useState(null);
|
|
405
|
+
const [onboardingInProgress, setOnboardingInProgress] = react.useState(false);
|
|
406
|
+
const initLoaderRef = react.useRef(null);
|
|
407
|
+
const paypalButtonRef = react.useRef(null);
|
|
408
|
+
const errorLogRef = react.useRef(null);
|
|
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);
|
|
488
420
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
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 })
|
|
516
|
-
}
|
|
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(
|
|
525
|
-
"button",
|
|
526
|
-
{
|
|
527
|
-
type: "button",
|
|
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"
|
|
532
|
-
}
|
|
533
|
-
),
|
|
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: [
|
|
538
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
539
|
-
"input",
|
|
540
|
-
{
|
|
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"
|
|
545
|
-
}
|
|
546
|
-
),
|
|
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",
|
|
551
|
-
{
|
|
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"
|
|
556
|
-
}
|
|
557
|
-
) }),
|
|
558
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
559
|
-
FieldRow$1,
|
|
560
|
-
{
|
|
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
|
-
] })
|
|
595
|
-
}
|
|
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: [
|
|
617
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
618
|
-
"input",
|
|
619
|
-
{
|
|
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"
|
|
624
|
-
}
|
|
625
|
-
),
|
|
626
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable card saving at checkout" })
|
|
627
|
-
] }) })
|
|
628
|
-
] })
|
|
629
|
-
}
|
|
630
|
-
)
|
|
631
|
-
] }) });
|
|
632
|
-
}
|
|
633
|
-
const config = adminSdk.defineRouteConfig({
|
|
634
|
-
label: "PayPal Connection",
|
|
635
|
-
hide: true
|
|
636
|
-
});
|
|
637
|
-
if (typeof window !== "undefined") {
|
|
638
|
-
const preloadHref = "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js";
|
|
639
|
-
const existingPreload = document.head.querySelector(
|
|
640
|
-
`link[rel="preload"][href="${preloadHref}"]`
|
|
641
|
-
);
|
|
642
|
-
if (!existingPreload) {
|
|
643
|
-
const preloadLink = document.createElement("link");
|
|
644
|
-
preloadLink.rel = "preload";
|
|
645
|
-
preloadLink.href = preloadHref;
|
|
646
|
-
preloadLink.as = "script";
|
|
647
|
-
document.head.appendChild(preloadLink);
|
|
648
|
-
}
|
|
649
|
-
const existingScript = document.getElementById(
|
|
650
|
-
"paypal-partner-js"
|
|
651
|
-
);
|
|
652
|
-
if (!existingScript) {
|
|
653
|
-
const ppScript = document.createElement("script");
|
|
654
|
-
ppScript.id = "paypal-partner-js";
|
|
655
|
-
ppScript.src = preloadHref;
|
|
656
|
-
ppScript.async = true;
|
|
657
|
-
document.head.appendChild(ppScript);
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
const SERVICE_URL = "/admin/paypal/onboarding-link";
|
|
661
|
-
const CACHE_KEY = "pp_onboard_cache";
|
|
662
|
-
const RELOAD_KEY = "pp_onboard_reloaded_once";
|
|
663
|
-
const CACHE_EXPIRY = 10 * 60 * 1e3;
|
|
664
|
-
const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
|
|
665
|
-
const STATUS_ENDPOINT = "/admin/paypal/status";
|
|
666
|
-
const SAVE_CREDENTIALS_ENDPOINT = "/admin/paypal/save-credentials";
|
|
667
|
-
const DISCONNECT_ENDPOINT = "/admin/paypal/disconnect";
|
|
668
|
-
let cachedUrl = null;
|
|
669
|
-
if (typeof window !== "undefined") {
|
|
670
|
-
try {
|
|
671
|
-
const cached = localStorage.getItem(CACHE_KEY);
|
|
672
|
-
if (cached) {
|
|
673
|
-
const data = JSON.parse(cached);
|
|
674
|
-
if ((/* @__PURE__ */ new Date()).getTime() - data.ts < CACHE_EXPIRY) {
|
|
675
|
-
cachedUrl = data.url;
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
} catch (e) {
|
|
679
|
-
console.error("Cache read error:", e);
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
function PayPalConnectionPage() {
|
|
683
|
-
const [env, setEnv] = react.useState("sandbox");
|
|
684
|
-
react.useEffect(() => {
|
|
685
|
-
fetch("/admin/paypal/environment", { method: "GET" }).then((r) => r.json()).then((d) => {
|
|
686
|
-
const v = (d == null ? void 0 : d.environment) === "live" ? "live" : "sandbox";
|
|
687
|
-
setEnv(v);
|
|
688
|
-
}).catch(() => {
|
|
689
|
-
});
|
|
690
|
-
}, []);
|
|
691
|
-
const [connState, setConnState] = react.useState("loading");
|
|
692
|
-
const [error, setError] = react.useState(null);
|
|
693
|
-
const [finalUrl, setFinalUrl] = react.useState("");
|
|
694
|
-
const [showManual, setShowManual] = react.useState(false);
|
|
695
|
-
const [clientId, setClientId] = react.useState("");
|
|
696
|
-
const [secret, setSecret] = react.useState("");
|
|
697
|
-
const [merchantId, setMerchantId] = react.useState("");
|
|
698
|
-
const [statusInfo, setStatusInfo] = react.useState(null);
|
|
699
|
-
const [onboardingInProgress, setOnboardingInProgress] = react.useState(false);
|
|
700
|
-
const initLoaderRef = react.useRef(null);
|
|
701
|
-
const paypalButtonRef = react.useRef(null);
|
|
702
|
-
const errorLogRef = react.useRef(null);
|
|
703
|
-
const runIdRef = react.useRef(0);
|
|
704
|
-
const currentRunId = react.useRef(0);
|
|
705
|
-
const ppBtnMeasureRef = react.useRef(null);
|
|
706
|
-
const [ppBtnWidth, setPpBtnWidth] = react.useState(null);
|
|
707
|
-
const canSaveManual = react.useMemo(() => {
|
|
708
|
-
return clientId.trim().length > 0 && secret.trim().length > 0;
|
|
709
|
-
}, [clientId, secret]);
|
|
710
|
-
const maskValue = react.useCallback((value, visibleChars = 4) => {
|
|
711
|
-
if (!value) return "";
|
|
712
|
-
if (value.length <= visibleChars) {
|
|
713
|
-
return "•".repeat(value.length);
|
|
714
|
-
}
|
|
715
|
-
return `${"•".repeat(Math.max(0, value.length - visibleChars))}${value.slice(
|
|
716
|
-
-visibleChars
|
|
717
|
-
)}`;
|
|
718
|
-
}, []);
|
|
719
|
-
const fetchFreshLink = react.useCallback(
|
|
720
|
-
(runId) => {
|
|
721
|
-
if (initLoaderRef.current) {
|
|
722
|
-
const loaderText = initLoaderRef.current.querySelector("#loader-text");
|
|
723
|
-
if (loaderText)
|
|
724
|
-
loaderText.textContent = "Generating onboarding session...";
|
|
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...";
|
|
725
431
|
}
|
|
726
432
|
fetch(SERVICE_URL, {
|
|
727
433
|
method: "POST",
|
|
@@ -921,301 +627,592 @@ function PayPalConnectionPage() {
|
|
|
921
627
|
const txt = await res.text().catch(() => "");
|
|
922
628
|
throw new Error(txt || `Save credentials failed (${res.status})`);
|
|
923
629
|
}
|
|
924
|
-
setConnState("connected");
|
|
925
|
-
setStatusInfo({
|
|
926
|
-
seller_client_id_masked: maskValue(clientId.trim()),
|
|
927
|
-
seller_client_secret_masked: "••••••••"
|
|
928
|
-
});
|
|
929
|
-
setShowManual(false);
|
|
630
|
+
setConnState("connected");
|
|
631
|
+
setStatusInfo({
|
|
632
|
+
seller_client_id_masked: maskValue(clientId.trim()),
|
|
633
|
+
seller_client_secret_masked: "••••••••"
|
|
634
|
+
});
|
|
635
|
+
setShowManual(false);
|
|
636
|
+
try {
|
|
637
|
+
localStorage.removeItem(CACHE_KEY);
|
|
638
|
+
localStorage.removeItem(RELOAD_KEY);
|
|
639
|
+
} catch {
|
|
640
|
+
}
|
|
641
|
+
} catch (e) {
|
|
642
|
+
console.error(e);
|
|
643
|
+
setConnState("error");
|
|
644
|
+
setError((e == null ? void 0 : e.message) || "Failed to save credentials.");
|
|
645
|
+
} finally {
|
|
646
|
+
setOnboardingInProgress(false);
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
const handleDisconnect = async () => {
|
|
650
|
+
if (onboardingInProgress) return;
|
|
651
|
+
if (!window.confirm("Disconnect PayPal for this environment?")) return;
|
|
652
|
+
setOnboardingInProgress(true);
|
|
653
|
+
setConnState("loading");
|
|
654
|
+
setError(null);
|
|
655
|
+
setFinalUrl("");
|
|
656
|
+
setShowManual(false);
|
|
657
|
+
try {
|
|
658
|
+
const res = await fetch(DISCONNECT_ENDPOINT, {
|
|
659
|
+
method: "POST",
|
|
660
|
+
headers: { "content-type": "application/json" },
|
|
661
|
+
body: JSON.stringify({ environment: env })
|
|
662
|
+
});
|
|
663
|
+
if (!res.ok) {
|
|
664
|
+
const t = await res.text().catch(() => "");
|
|
665
|
+
throw new Error(t || `Disconnect failed (${res.status})`);
|
|
666
|
+
}
|
|
667
|
+
try {
|
|
668
|
+
localStorage.removeItem(CACHE_KEY);
|
|
669
|
+
localStorage.removeItem(RELOAD_KEY);
|
|
670
|
+
} catch {
|
|
671
|
+
}
|
|
672
|
+
currentRunId.current = ++runIdRef.current;
|
|
673
|
+
const runId = currentRunId.current;
|
|
674
|
+
fetchFreshLink(runId);
|
|
675
|
+
} catch (e) {
|
|
676
|
+
console.error(e);
|
|
677
|
+
setConnState("error");
|
|
678
|
+
setError((e == null ? void 0 : e.message) || "Failed to disconnect.");
|
|
679
|
+
} finally {
|
|
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(
|
|
744
|
+
"button",
|
|
745
|
+
{
|
|
746
|
+
type: "button",
|
|
747
|
+
onClick: handleDisconnect,
|
|
748
|
+
disabled: onboardingInProgress,
|
|
749
|
+
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",
|
|
750
|
+
children: "Disconnect"
|
|
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
|
+
]
|
|
764
|
+
}
|
|
765
|
+
),
|
|
766
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${connState === "ready" ? "block" : "hidden"}`, children: [
|
|
767
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
768
|
+
"a",
|
|
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
|
+
),
|
|
793
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
794
|
+
"div",
|
|
795
|
+
{
|
|
796
|
+
className: "mt-2",
|
|
797
|
+
style: {
|
|
798
|
+
width: ppBtnWidth ? `${ppBtnWidth}px` : "auto",
|
|
799
|
+
marginTop: "20px",
|
|
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" }) })
|
|
803
|
+
}
|
|
804
|
+
),
|
|
805
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
806
|
+
"button",
|
|
807
|
+
{
|
|
808
|
+
type: "button",
|
|
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",
|
|
818
|
+
{
|
|
819
|
+
type: "button",
|
|
820
|
+
onClick: () => setShowManual(!showManual),
|
|
821
|
+
disabled: onboardingInProgress,
|
|
822
|
+
className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
|
|
823
|
+
children: "Click here to insert credentials manually"
|
|
824
|
+
}
|
|
825
|
+
) }),
|
|
826
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
827
|
+
"div",
|
|
828
|
+
{
|
|
829
|
+
ref: errorLogRef,
|
|
830
|
+
id: "error-log",
|
|
831
|
+
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"}`,
|
|
832
|
+
children: error
|
|
833
|
+
}
|
|
834
|
+
)
|
|
835
|
+
] }) }),
|
|
836
|
+
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: [
|
|
837
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
838
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Client ID" }),
|
|
839
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
840
|
+
"input",
|
|
841
|
+
{
|
|
842
|
+
type: "text",
|
|
843
|
+
value: clientId,
|
|
844
|
+
onChange: (e) => setClientId(e.target.value),
|
|
845
|
+
disabled: onboardingInProgress,
|
|
846
|
+
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
847
|
+
placeholder: env === "sandbox" ? "Sandbox Client ID" : "Live Client ID"
|
|
848
|
+
}
|
|
849
|
+
)
|
|
850
|
+
] }),
|
|
851
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
852
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Client Secret" }),
|
|
853
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
854
|
+
"input",
|
|
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)" }),
|
|
867
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
868
|
+
"input",
|
|
869
|
+
{
|
|
870
|
+
type: "text",
|
|
871
|
+
value: merchantId,
|
|
872
|
+
onChange: (e) => setMerchantId(e.target.value),
|
|
873
|
+
disabled: onboardingInProgress,
|
|
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"
|
|
888
|
+
}
|
|
889
|
+
),
|
|
890
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
891
|
+
"button",
|
|
892
|
+
{
|
|
893
|
+
type: "button",
|
|
894
|
+
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",
|
|
895
|
+
disabled: !canSaveManual || onboardingInProgress,
|
|
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
|
+
] });
|
|
922
|
+
}
|
|
923
|
+
const DEFAULT_FORM = {
|
|
924
|
+
enabled: true,
|
|
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
|
+
};
|
|
937
|
+
}
|
|
938
|
+
const CARD_BRANDS = [
|
|
939
|
+
{ value: "visa", label: "Visa" },
|
|
940
|
+
{ value: "mastercard", label: "Mastercard" },
|
|
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)."
|
|
962
|
+
}
|
|
963
|
+
];
|
|
964
|
+
function cx$1(...parts) {
|
|
965
|
+
return parts.filter(Boolean).join(" ");
|
|
966
|
+
}
|
|
967
|
+
function Pill$1({
|
|
968
|
+
children,
|
|
969
|
+
onRemove
|
|
970
|
+
}) {
|
|
971
|
+
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: [
|
|
972
|
+
children,
|
|
973
|
+
onRemove ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
974
|
+
"button",
|
|
975
|
+
{
|
|
976
|
+
type: "button",
|
|
977
|
+
onClick: onRemove,
|
|
978
|
+
className: "ml-1 rounded px-1 text-ui-fg-subtle hover:text-ui-fg-base",
|
|
979
|
+
"aria-label": "Remove",
|
|
980
|
+
children: "×"
|
|
981
|
+
}
|
|
982
|
+
) : null
|
|
983
|
+
] });
|
|
984
|
+
}
|
|
985
|
+
function SectionCard$1({
|
|
986
|
+
title,
|
|
987
|
+
description,
|
|
988
|
+
right,
|
|
989
|
+
children
|
|
990
|
+
}) {
|
|
991
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
|
|
992
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
|
|
993
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
994
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: title }),
|
|
995
|
+
description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-sm text-ui-fg-subtle", children: description }) : null
|
|
996
|
+
] }),
|
|
997
|
+
right
|
|
998
|
+
] }),
|
|
999
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children })
|
|
1000
|
+
] });
|
|
1001
|
+
}
|
|
1002
|
+
function FieldRow$1({
|
|
1003
|
+
label,
|
|
1004
|
+
hint,
|
|
1005
|
+
children
|
|
1006
|
+
}) {
|
|
1007
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
|
|
1008
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 md:col-span-4", children: [
|
|
1009
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
|
|
1010
|
+
hint ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: hint }) : null
|
|
1011
|
+
] }),
|
|
1012
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-12 md:col-span-8", children })
|
|
1013
|
+
] });
|
|
1014
|
+
}
|
|
1015
|
+
function AdvancedCardPaymentsTab() {
|
|
1016
|
+
var _a, _b;
|
|
1017
|
+
const [form, setForm] = react.useState(() => ({ ...DEFAULT_FORM }));
|
|
1018
|
+
const [loading, setLoading] = react.useState(false);
|
|
1019
|
+
const [saving, setSaving] = react.useState(false);
|
|
1020
|
+
const [toast, setToast] = react.useState(null);
|
|
1021
|
+
const didInit = react.useRef(false);
|
|
1022
|
+
react.useEffect(() => {
|
|
1023
|
+
if (didInit.current) return;
|
|
1024
|
+
didInit.current = true;
|
|
1025
|
+
(async () => {
|
|
930
1026
|
try {
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
1027
|
+
setLoading(true);
|
|
1028
|
+
const r = await fetch("/admin/paypal/settings", {
|
|
1029
|
+
credentials: "include",
|
|
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);
|
|
934
1041
|
}
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
setError((e == null ? void 0 : e.message) || "Failed to save credentials.");
|
|
939
|
-
} finally {
|
|
940
|
-
setOnboardingInProgress(false);
|
|
941
|
-
}
|
|
942
|
-
};
|
|
943
|
-
const handleDisconnect = async () => {
|
|
944
|
-
if (onboardingInProgress) return;
|
|
945
|
-
if (!window.confirm("Disconnect PayPal for this environment?")) return;
|
|
946
|
-
setOnboardingInProgress(true);
|
|
947
|
-
setConnState("loading");
|
|
948
|
-
setError(null);
|
|
949
|
-
setFinalUrl("");
|
|
950
|
-
setShowManual(false);
|
|
1042
|
+
})();
|
|
1043
|
+
}, []);
|
|
1044
|
+
async function onSave() {
|
|
951
1045
|
try {
|
|
952
|
-
|
|
1046
|
+
setSaving(true);
|
|
1047
|
+
const r = await fetch("/admin/paypal/settings", {
|
|
953
1048
|
method: "POST",
|
|
954
|
-
|
|
955
|
-
|
|
1049
|
+
credentials: "include",
|
|
1050
|
+
headers: {
|
|
1051
|
+
"Content-Type": "application/json",
|
|
1052
|
+
"Accept": "application/json"
|
|
1053
|
+
},
|
|
1054
|
+
body: JSON.stringify({ advanced_card_payments: form })
|
|
956
1055
|
});
|
|
957
|
-
if (!
|
|
958
|
-
const t = await
|
|
959
|
-
|
|
1056
|
+
if (!r.ok) {
|
|
1057
|
+
const t = await r.text();
|
|
1058
|
+
setToast({ type: "error", message: "Failed to save settings. " + t });
|
|
1059
|
+
window.setTimeout(() => setToast(null), 3500);
|
|
1060
|
+
return;
|
|
960
1061
|
}
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1062
|
+
const json = await r.json().catch(() => null);
|
|
1063
|
+
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
1064
|
+
const saved = payload == null ? void 0 : payload.advanced_card_payments;
|
|
1065
|
+
if (saved && typeof saved === "object") {
|
|
1066
|
+
setForm(mergeWithDefaults(saved));
|
|
965
1067
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
fetchFreshLink(runId);
|
|
969
|
-
} catch (e) {
|
|
970
|
-
console.error(e);
|
|
971
|
-
setConnState("error");
|
|
972
|
-
setError((e == null ? void 0 : e.message) || "Failed to disconnect.");
|
|
1068
|
+
setToast({ type: "success", message: "Settings saved" });
|
|
1069
|
+
window.setTimeout(() => setToast(null), 2500);
|
|
973
1070
|
} finally {
|
|
974
|
-
|
|
975
|
-
}
|
|
976
|
-
};
|
|
977
|
-
const handleEnvChange = async (e) => {
|
|
978
|
-
const next = e.target.value;
|
|
979
|
-
setEnv(next);
|
|
980
|
-
cachedUrl = null;
|
|
981
|
-
try {
|
|
982
|
-
await fetch("/admin/paypal/environment", {
|
|
983
|
-
method: "POST",
|
|
984
|
-
headers: { "content-type": "application/json" },
|
|
985
|
-
body: JSON.stringify({ environment: next })
|
|
986
|
-
});
|
|
987
|
-
} catch {
|
|
988
|
-
}
|
|
989
|
-
try {
|
|
990
|
-
localStorage.removeItem(CACHE_KEY);
|
|
991
|
-
localStorage.removeItem(RELOAD_KEY);
|
|
992
|
-
} catch {
|
|
1071
|
+
setSaving(false);
|
|
993
1072
|
}
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1038
|
-
"button",
|
|
1039
|
-
{
|
|
1040
|
-
type: "button",
|
|
1041
|
-
onClick: handleDisconnect,
|
|
1042
|
-
disabled: onboardingInProgress,
|
|
1043
|
-
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",
|
|
1044
|
-
children: "Disconnect"
|
|
1045
|
-
}
|
|
1046
|
-
) })
|
|
1047
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1048
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1049
|
-
"div",
|
|
1050
|
-
{
|
|
1051
|
-
ref: initLoaderRef,
|
|
1052
|
-
id: "init-loader",
|
|
1053
|
-
className: `status-msg mb-4 ${connState !== "loading" ? "hidden" : "block"}`,
|
|
1054
|
-
children: [
|
|
1055
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "loader inline-block align-middle mr-2" }),
|
|
1056
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { id: "loader-text", className: "text-sm", children: onboardingInProgress ? "Configuring connection to PayPal…" : "Checking connection..." })
|
|
1057
|
-
]
|
|
1073
|
+
}
|
|
1074
|
+
const disabledSet = react.useMemo(() => new Set(form.disabledCards), [form.disabledCards]);
|
|
1075
|
+
function toggleDisabledCard(value) {
|
|
1076
|
+
setForm((prev) => {
|
|
1077
|
+
const exists = prev.disabledCards.includes(value);
|
|
1078
|
+
return {
|
|
1079
|
+
...prev,
|
|
1080
|
+
disabledCards: exists ? prev.disabledCards.filter((v) => v !== value) : [...prev.disabledCards, value]
|
|
1081
|
+
};
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
function removeDisabledCard(value) {
|
|
1085
|
+
setForm((prev) => ({
|
|
1086
|
+
...prev,
|
|
1087
|
+
disabledCards: prev.disabledCards.filter((v) => v !== value)
|
|
1088
|
+
}));
|
|
1089
|
+
}
|
|
1090
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
1091
|
+
/* @__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" }) }) }),
|
|
1092
|
+
/* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
|
|
1093
|
+
toast ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1094
|
+
"div",
|
|
1095
|
+
{
|
|
1096
|
+
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",
|
|
1097
|
+
role: "status",
|
|
1098
|
+
"aria-live": "polite",
|
|
1099
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: toast.type === "success" ? "text-ui-fg-base" : "text-ui-fg-error", children: toast.message })
|
|
1100
|
+
}
|
|
1101
|
+
) : null,
|
|
1102
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1103
|
+
SectionCard$1,
|
|
1104
|
+
{
|
|
1105
|
+
title: "Advanced Card Payments",
|
|
1106
|
+
description: "Control card checkout settings, 3D Secure behavior, and card saving.",
|
|
1107
|
+
right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1108
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1109
|
+
"button",
|
|
1110
|
+
{
|
|
1111
|
+
type: "button",
|
|
1112
|
+
onClick: onSave,
|
|
1113
|
+
disabled: saving || loading,
|
|
1114
|
+
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",
|
|
1115
|
+
children: saving ? "Saving..." : "Save settings"
|
|
1058
1116
|
}
|
|
1059
1117
|
),
|
|
1060
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
ref: (node) => {
|
|
1065
|
-
paypalButtonRef.current = node;
|
|
1066
|
-
ppBtnMeasureRef.current = node;
|
|
1067
|
-
},
|
|
1068
|
-
id: "paypal-button",
|
|
1069
|
-
"data-paypal-button": "true",
|
|
1070
|
-
href: finalUrl || "#",
|
|
1071
|
-
"data-paypal-onboard-complete": "onboardingCallback",
|
|
1072
|
-
onClick: handleConnectClick,
|
|
1073
|
-
className: "btn-paypal",
|
|
1074
|
-
style: {
|
|
1075
|
-
borderRadius: "50px",
|
|
1076
|
-
textDecoration: "none",
|
|
1077
|
-
display: "inline-block",
|
|
1078
|
-
fontWeight: "bold",
|
|
1079
|
-
border: "none",
|
|
1080
|
-
cursor: onboardingInProgress ? "not-allowed" : "pointer",
|
|
1081
|
-
opacity: onboardingInProgress ? 0.6 : 1,
|
|
1082
|
-
pointerEvents: onboardingInProgress ? "none" : "auto"
|
|
1083
|
-
},
|
|
1084
|
-
children: "Connect to PayPal"
|
|
1085
|
-
}
|
|
1086
|
-
),
|
|
1118
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading…" }) : null
|
|
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: [
|
|
1087
1122
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1088
|
-
"
|
|
1123
|
+
"input",
|
|
1089
1124
|
{
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
marginBottom: "10px"
|
|
1095
|
-
},
|
|
1096
|
-
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" }) })
|
|
1125
|
+
type: "checkbox",
|
|
1126
|
+
checked: form.enabled,
|
|
1127
|
+
onChange: (e) => setForm((p) => ({ ...p, enabled: e.target.checked })),
|
|
1128
|
+
className: "h-4 w-4 rounded border-ui-border-base"
|
|
1097
1129
|
}
|
|
1098
1130
|
),
|
|
1099
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
onClick: () => setShowManual(!showManual),
|
|
1104
|
-
disabled: onboardingInProgress,
|
|
1105
|
-
className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1106
|
-
children: "Click here to insert credentials manually"
|
|
1107
|
-
}
|
|
1108
|
-
) })
|
|
1109
|
-
] }),
|
|
1110
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `${connState === "ready" ? "hidden" : "block"} mt-3`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1111
|
-
"button",
|
|
1131
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable Advanced Credit/Debit Card" })
|
|
1132
|
+
] }) }),
|
|
1133
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Title", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1134
|
+
"input",
|
|
1112
1135
|
{
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
children: "Click here to insert credentials manually"
|
|
1136
|
+
value: form.title,
|
|
1137
|
+
onChange: (e) => setForm((p) => ({ ...p, title: e.target.value })),
|
|
1138
|
+
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",
|
|
1139
|
+
placeholder: "Credit or Debit Card"
|
|
1118
1140
|
}
|
|
1119
1141
|
) }),
|
|
1120
1142
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1121
|
-
|
|
1143
|
+
FieldRow$1,
|
|
1122
1144
|
{
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
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
|
+
] })
|
|
1127
1179
|
}
|
|
1128
|
-
)
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
"
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
{
|
|
1150
|
-
type: "password",
|
|
1151
|
-
value: secret,
|
|
1152
|
-
onChange: (e) => setSecret(e.target.value),
|
|
1153
|
-
disabled: onboardingInProgress,
|
|
1154
|
-
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
1155
|
-
placeholder: env === "sandbox" ? "Sandbox Secret" : "Live Secret"
|
|
1156
|
-
}
|
|
1157
|
-
)
|
|
1158
|
-
] }),
|
|
1159
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 md:col-span-2", children: [
|
|
1160
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Merchant ID (optional)" }),
|
|
1180
|
+
),
|
|
1181
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1182
|
+
FieldRow$1,
|
|
1183
|
+
{
|
|
1184
|
+
label: "Contingency for 3D Secure",
|
|
1185
|
+
hint: "Choose when 3D Secure should be triggered during card payments.",
|
|
1186
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
1187
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
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
|
+
] })
|
|
1198
|
+
}
|
|
1199
|
+
),
|
|
1200
|
+
/* @__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: [
|
|
1161
1201
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1162
1202
|
"input",
|
|
1163
1203
|
{
|
|
1164
|
-
type: "
|
|
1165
|
-
|
|
1166
|
-
onChange: (e) =>
|
|
1167
|
-
|
|
1168
|
-
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
1169
|
-
placeholder: "Merchant ID"
|
|
1170
|
-
}
|
|
1171
|
-
)
|
|
1172
|
-
] }),
|
|
1173
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:col-span-2 flex items-center gap-2 mt-2", children: [
|
|
1174
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1175
|
-
"button",
|
|
1176
|
-
{
|
|
1177
|
-
type: "button",
|
|
1178
|
-
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",
|
|
1179
|
-
onClick: () => setShowManual(false),
|
|
1180
|
-
disabled: onboardingInProgress,
|
|
1181
|
-
children: "Cancel"
|
|
1204
|
+
type: "checkbox",
|
|
1205
|
+
checked: form.cardSaveEnabled,
|
|
1206
|
+
onChange: (e) => setForm((p) => ({ ...p, cardSaveEnabled: e.target.checked })),
|
|
1207
|
+
className: "h-4 w-4 rounded border-ui-border-base"
|
|
1182
1208
|
}
|
|
1183
1209
|
),
|
|
1184
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
onClick: handleSaveManual,
|
|
1191
|
-
children: "Save credentials"
|
|
1192
|
-
}
|
|
1193
|
-
)
|
|
1194
|
-
] })
|
|
1195
|
-
] }) })
|
|
1196
|
-
] }) })
|
|
1197
|
-
] }),
|
|
1198
|
-
/* @__PURE__ */ jsxRuntime.jsx("style", { children: `
|
|
1199
|
-
.loader {
|
|
1200
|
-
border: 3px solid #f3f3f3;
|
|
1201
|
-
border-top: 3px solid #0070ba;
|
|
1202
|
-
border-radius: 50%;
|
|
1203
|
-
width: 18px;
|
|
1204
|
-
height: 18px;
|
|
1205
|
-
animation: spin 1s linear infinite;
|
|
1206
|
-
display: inline-block;
|
|
1207
|
-
vertical-align: middle;
|
|
1208
|
-
margin-right: 8px;
|
|
1209
|
-
}
|
|
1210
|
-
@keyframes spin {
|
|
1211
|
-
0% { transform: rotate(0deg); }
|
|
1212
|
-
100% { transform: rotate(360deg); }
|
|
1213
|
-
}
|
|
1214
|
-
` })
|
|
1215
|
-
] });
|
|
1216
|
-
}
|
|
1217
|
-
function PayPalApplePayPage() {
|
|
1218
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
1210
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable card saving at checkout" })
|
|
1211
|
+
] }) })
|
|
1212
|
+
] })
|
|
1213
|
+
}
|
|
1214
|
+
)
|
|
1215
|
+
] }) });
|
|
1219
1216
|
}
|
|
1220
1217
|
function formatDate$2(value) {
|
|
1221
1218
|
if (!value) {
|
|
@@ -1296,7 +1293,7 @@ function PayPalAuditLogsPage() {
|
|
|
1296
1293
|
] })
|
|
1297
1294
|
] }) });
|
|
1298
1295
|
}
|
|
1299
|
-
function
|
|
1296
|
+
function PayPalApplePayPage() {
|
|
1300
1297
|
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
1301
1298
|
}
|
|
1302
1299
|
const EMPTY_FILTERS = {
|
|
@@ -1491,6 +1488,9 @@ function PayPalDisputesPage() {
|
|
|
1491
1488
|
] })
|
|
1492
1489
|
] }) });
|
|
1493
1490
|
}
|
|
1491
|
+
function PayPalGooglePayPage() {
|
|
1492
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
1493
|
+
}
|
|
1494
1494
|
function PayPalPayLaterMessagingPage() {
|
|
1495
1495
|
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
1496
1496
|
}
|
|
@@ -2052,30 +2052,30 @@ const routeModule = {
|
|
|
2052
2052
|
Component: AdditionalSettingsTab,
|
|
2053
2053
|
path: "/settings/paypal/additional-settings"
|
|
2054
2054
|
},
|
|
2055
|
-
{
|
|
2056
|
-
Component: AdvancedCardPaymentsTab,
|
|
2057
|
-
path: "/settings/paypal/advanced-card-payments"
|
|
2058
|
-
},
|
|
2059
2055
|
{
|
|
2060
2056
|
Component: PayPalConnectionPage,
|
|
2061
2057
|
path: "/settings/paypal/connection"
|
|
2062
2058
|
},
|
|
2063
2059
|
{
|
|
2064
|
-
Component:
|
|
2065
|
-
path: "/settings/paypal/
|
|
2060
|
+
Component: AdvancedCardPaymentsTab,
|
|
2061
|
+
path: "/settings/paypal/advanced-card-payments"
|
|
2066
2062
|
},
|
|
2067
2063
|
{
|
|
2068
2064
|
Component: PayPalAuditLogsPage,
|
|
2069
2065
|
path: "/settings/paypal/audit-logs"
|
|
2070
2066
|
},
|
|
2071
2067
|
{
|
|
2072
|
-
Component:
|
|
2073
|
-
path: "/settings/paypal/
|
|
2068
|
+
Component: PayPalApplePayPage,
|
|
2069
|
+
path: "/settings/paypal/apple-pay"
|
|
2074
2070
|
},
|
|
2075
2071
|
{
|
|
2076
2072
|
Component: PayPalDisputesPage,
|
|
2077
2073
|
path: "/settings/paypal/disputes"
|
|
2078
2074
|
},
|
|
2075
|
+
{
|
|
2076
|
+
Component: PayPalGooglePayPage,
|
|
2077
|
+
path: "/settings/paypal/google-pay"
|
|
2078
|
+
},
|
|
2079
2079
|
{
|
|
2080
2080
|
Component: PayPalPayLaterMessagingPage,
|
|
2081
2081
|
path: "/settings/paypal/pay-later-messaging"
|