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