@easypayment/medusa-paypal 0.2.7 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/.medusa/server/src/admin/index.js +536 -938
  2. package/.medusa/server/src/admin/index.mjs +536 -938
  3. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -1
  4. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js +1 -0
  5. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js.map +1 -1
  6. package/.medusa/server/src/api/store/paypal/capture-order/route.d.ts.map +1 -1
  7. package/.medusa/server/src/api/store/paypal/capture-order/route.js +61 -74
  8. package/.medusa/server/src/api/store/paypal/capture-order/route.js.map +1 -1
  9. package/.medusa/server/src/api/store/paypal/create-order/route.d.ts.map +1 -1
  10. package/.medusa/server/src/api/store/paypal/create-order/route.js +3 -24
  11. package/.medusa/server/src/api/store/paypal/create-order/route.js.map +1 -1
  12. package/.medusa/server/src/api/store/paypal/settings/route.d.ts.map +1 -1
  13. package/.medusa/server/src/api/store/paypal/settings/route.js +7 -1
  14. package/.medusa/server/src/api/store/paypal/settings/route.js.map +1 -1
  15. package/.medusa/server/src/api/store/paypal/webhook/route.d.ts.map +1 -1
  16. package/.medusa/server/src/api/store/paypal/webhook/route.js +1 -1
  17. package/.medusa/server/src/api/store/paypal/webhook/route.js.map +1 -1
  18. package/.medusa/server/src/api/store/paypal-complete/route.d.ts.map +1 -1
  19. package/.medusa/server/src/api/store/paypal-complete/route.js +46 -24
  20. package/.medusa/server/src/api/store/paypal-complete/route.js.map +1 -1
  21. package/.medusa/server/src/jobs/paypal-reconcile.d.ts.map +1 -1
  22. package/.medusa/server/src/jobs/paypal-reconcile.js +19 -5
  23. package/.medusa/server/src/jobs/paypal-reconcile.js.map +1 -1
  24. package/.medusa/server/src/jobs/paypal-webhook-retry.d.ts.map +1 -1
  25. package/.medusa/server/src/jobs/paypal-webhook-retry.js +1 -1
  26. package/.medusa/server/src/jobs/paypal-webhook-retry.js.map +1 -1
  27. package/.medusa/server/src/modules/paypal/index.d.ts +0 -14
  28. package/.medusa/server/src/modules/paypal/index.d.ts.map +1 -1
  29. package/.medusa/server/src/modules/paypal/service.d.ts +56 -93
  30. package/.medusa/server/src/modules/paypal/service.d.ts.map +1 -1
  31. package/.medusa/server/src/modules/paypal/service.js +34 -47
  32. package/.medusa/server/src/modules/paypal/service.js.map +1 -1
  33. package/.medusa/server/src/modules/paypal/utils/paypal-auth.d.ts +14 -0
  34. package/.medusa/server/src/modules/paypal/utils/paypal-auth.d.ts.map +1 -0
  35. package/.medusa/server/src/modules/paypal/utils/paypal-auth.js +32 -0
  36. package/.medusa/server/src/modules/paypal/utils/paypal-auth.js.map +1 -0
  37. package/.medusa/server/src/modules/paypal/webhook-processor.d.ts +2 -15
  38. package/.medusa/server/src/modules/paypal/webhook-processor.d.ts.map +1 -1
  39. package/.medusa/server/src/modules/paypal/webhook-processor.js +17 -100
  40. package/.medusa/server/src/modules/paypal/webhook-processor.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/admin/routes/settings/paypal/_components/Tabs.tsx +0 -1
  43. package/src/admin/routes/settings/paypal/additional-settings/page.tsx +226 -346
  44. package/src/admin/routes/settings/paypal/advanced-card-payments/page.tsx +227 -381
  45. package/src/admin/routes/settings/paypal/audit-logs/page.tsx +127 -131
  46. package/src/admin/routes/settings/paypal/paypal-settings/page.tsx +599 -557
  47. package/src/admin/routes/settings/paypal/reconciliation-status/page.tsx +120 -165
  48. package/src/api/store/payment-collections/[id]/payment-sessions/route.ts +12 -1
  49. package/src/api/store/paypal/capture-order/route.ts +276 -284
  50. package/src/api/store/paypal/create-order/route.ts +2 -32
  51. package/src/api/store/paypal/settings/route.ts +8 -1
  52. package/src/api/store/paypal/webhook/route.ts +1 -2
  53. package/src/api/store/paypal-complete/route.ts +75 -45
  54. package/src/jobs/paypal-reconcile.ts +21 -6
  55. package/src/jobs/paypal-webhook-retry.ts +1 -2
  56. package/src/modules/paypal/service.ts +39 -62
  57. package/src/modules/paypal/utils/paypal-auth.ts +32 -0
  58. package/src/modules/paypal/webhook-processor.ts +18 -116
  59. package/tsconfig.json +1 -1
  60. package/.medusa/server/src/api/admin/paypal/disputes/[id]/route.d.ts +0 -3
  61. package/.medusa/server/src/api/admin/paypal/disputes/[id]/route.d.ts.map +0 -1
  62. package/.medusa/server/src/api/admin/paypal/disputes/[id]/route.js +0 -17
  63. package/.medusa/server/src/api/admin/paypal/disputes/[id]/route.js.map +0 -1
  64. package/.medusa/server/src/api/admin/paypal/disputes/route.d.ts +0 -3
  65. package/.medusa/server/src/api/admin/paypal/disputes/route.d.ts.map +0 -1
  66. package/.medusa/server/src/api/admin/paypal/disputes/route.js +0 -27
  67. package/.medusa/server/src/api/admin/paypal/disputes/route.js.map +0 -1
  68. package/.medusa/server/src/api/admin/paypal/disputes/summary/route.d.ts +0 -3
  69. package/.medusa/server/src/api/admin/paypal/disputes/summary/route.d.ts.map +0 -1
  70. package/.medusa/server/src/api/admin/paypal/disputes/summary/route.js +0 -17
  71. package/.medusa/server/src/api/admin/paypal/disputes/summary/route.js.map +0 -1
  72. package/.medusa/server/src/api/store/paypal/disputes/route.d.ts +0 -3
  73. package/.medusa/server/src/api/store/paypal/disputes/route.d.ts.map +0 -1
  74. package/.medusa/server/src/api/store/paypal/disputes/route.js +0 -46
  75. package/.medusa/server/src/api/store/paypal/disputes/route.js.map +0 -1
  76. package/.medusa/server/src/modules/paypal/migrations/20260501090000_create_paypal_dispute.d.ts +0 -6
  77. package/.medusa/server/src/modules/paypal/migrations/20260501090000_create_paypal_dispute.d.ts.map +0 -1
  78. package/.medusa/server/src/modules/paypal/migrations/20260501090000_create_paypal_dispute.js +0 -43
  79. package/.medusa/server/src/modules/paypal/migrations/20260501090000_create_paypal_dispute.js.map +0 -1
  80. package/.medusa/server/src/modules/paypal/models/paypal_dispute.d.ts +0 -16
  81. package/.medusa/server/src/modules/paypal/models/paypal_dispute.d.ts.map +0 -1
  82. package/.medusa/server/src/modules/paypal/models/paypal_dispute.js +0 -19
  83. package/.medusa/server/src/modules/paypal/models/paypal_dispute.js.map +0 -1
  84. package/src/admin/routes/settings/paypal/disputes/page.tsx +0 -259
  85. package/src/api/admin/paypal/disputes/[id]/route.ts +0 -19
  86. package/src/api/admin/paypal/disputes/route.ts +0 -30
  87. package/src/api/admin/paypal/disputes/summary/route.ts +0 -18
  88. package/src/api/store/paypal/disputes/route.ts +0 -67
  89. package/src/modules/paypal/migrations/20260501090000_create_paypal_dispute.ts +0 -40
  90. package/src/modules/paypal/models/paypal_dispute.ts +0 -18
@@ -14,7 +14,6 @@ const TABS = [
14
14
  { label: "PayPal Connection", to: `${BASE}/connection` },
15
15
  { label: "PayPal Settings", to: `${BASE}/paypal-settings` },
16
16
  { label: "Advanced Card Payments", to: `${BASE}/advanced-card-payments` },
17
- { label: "Disputes", to: `${BASE}/disputes` },
18
17
  { label: "Reconciliation Status", to: `${BASE}/reconciliation-status` },
19
18
  /* { label: "Google Pay", to: `${BASE}/google-pay` },
20
19
  { label: "Apple Pay", to: `${BASE}/apple-pay` },
@@ -40,6 +39,39 @@ function PayPalTabs() {
40
39
  );
41
40
  }) }) });
42
41
  }
42
+ async function adminFetch$4(path, opts = {}) {
43
+ var _a;
44
+ const { method = "GET", body, query } = opts;
45
+ let url = path;
46
+ if (query && Object.keys(query).length > 0) {
47
+ const params = new URLSearchParams(query);
48
+ url = `${path}?${params.toString()}`;
49
+ }
50
+ const headers = { Accept: "application/json" };
51
+ if (body !== void 0) headers["Content-Type"] = "application/json";
52
+ if (typeof window !== "undefined") {
53
+ const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
54
+ if (token) headers["Authorization"] = `Bearer ${token}`;
55
+ }
56
+ const res = await fetch(url, {
57
+ method,
58
+ headers,
59
+ credentials: "include",
60
+ body: body !== void 0 ? JSON.stringify(body) : void 0
61
+ });
62
+ const text = await res.text().catch(() => "");
63
+ if (!res.ok) {
64
+ if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
65
+ if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
66
+ throw new Error(text || `Request failed with status ${res.status}`);
67
+ }
68
+ if (!text) return {};
69
+ try {
70
+ return JSON.parse(text);
71
+ } catch {
72
+ return {};
73
+ }
74
+ }
43
75
  const DEFAULT_FORM$1 = {
44
76
  paymentAction: "capture",
45
77
  brandName: "PayPal",
@@ -56,17 +88,9 @@ const DEFAULT_FORM$1 = {
56
88
  function mergeWithDefaults$1(saved) {
57
89
  if (!saved) return { ...DEFAULT_FORM$1 };
58
90
  const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
59
- return {
60
- ...DEFAULT_FORM$1,
61
- ...Object.fromEntries(entries)
62
- };
91
+ return { ...DEFAULT_FORM$1, ...Object.fromEntries(entries) };
63
92
  }
64
- function SectionCard$2({
65
- title,
66
- description,
67
- right,
68
- children
69
- }) {
93
+ function SectionCard$2({ title, description, right, children }) {
70
94
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
71
95
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
72
96
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
@@ -78,11 +102,7 @@ function SectionCard$2({
78
102
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children })
79
103
  ] });
80
104
  }
81
- function FieldRow$2({
82
- label,
83
- hint,
84
- children
85
- }) {
105
+ function FieldRow$2({ label, hint, children }) {
86
106
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
87
107
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 md:col-span-4", children: [
88
108
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
@@ -95,6 +115,7 @@ function AdditionalSettingsTab() {
95
115
  const [form, setForm] = react.useState(() => ({ ...DEFAULT_FORM$1 }));
96
116
  const [loading, setLoading] = react.useState(false);
97
117
  const [saving, setSaving] = react.useState(false);
118
+ const [toast, setToast] = react.useState(null);
98
119
  const didInit = react.useRef(false);
99
120
  react.useEffect(() => {
100
121
  if (didInit.current) return;
@@ -102,52 +123,28 @@ function AdditionalSettingsTab() {
102
123
  (async () => {
103
124
  try {
104
125
  setLoading(true);
105
- const r = await fetch("/admin/paypal/settings", {
106
- credentials: "include",
107
- headers: { "Accept": "application/json" }
108
- });
109
- if (!r.ok) return;
110
- const json = await r.json();
126
+ const json = await adminFetch$4("/admin/paypal/settings");
111
127
  const payload = (json == null ? void 0 : json.data) ?? json;
112
128
  const saved = payload == null ? void 0 : payload.additional_settings;
113
- if (saved && typeof saved === "object") {
114
- setForm(mergeWithDefaults$1(saved));
115
- }
129
+ if (saved && typeof saved === "object") setForm(mergeWithDefaults$1(saved));
130
+ } catch {
116
131
  } finally {
117
132
  setLoading(false);
118
133
  }
119
134
  })();
120
135
  }, []);
121
- const [toast, setToast] = react.useState(null);
122
136
  async function onSave() {
123
137
  try {
124
138
  setSaving(true);
125
139
  setToast(null);
126
- const r = await fetch("/admin/paypal/settings", {
127
- method: "POST",
128
- credentials: "include",
129
- headers: {
130
- "Content-Type": "application/json",
131
- "Accept": "application/json"
132
- },
133
- body: JSON.stringify({
134
- additional_settings: form
135
- })
136
- });
137
- if (!r.ok) {
138
- const errText = await r.text().catch(() => "");
139
- throw new Error(errText || "Failed to save settings");
140
- }
141
- const json = await r.json().catch(() => ({}));
140
+ const json = await adminFetch$4("/admin/paypal/settings", { method: "POST", body: { additional_settings: form } });
142
141
  const payload = (json == null ? void 0 : json.data) ?? json;
143
142
  const saved = payload == null ? void 0 : payload.additional_settings;
144
- if (saved && typeof saved === "object") {
145
- setForm(mergeWithDefaults$1(saved));
146
- }
143
+ if (saved && typeof saved === "object") setForm(mergeWithDefaults$1(saved));
147
144
  setToast({ type: "success", message: "Settings saved" });
148
145
  window.setTimeout(() => setToast(null), 2500);
149
146
  } catch (e) {
150
- setToast({ type: "error", message: (e == null ? void 0 : e.message) || "Failed to save settings" });
147
+ setToast({ type: "error", message: e instanceof Error ? e.message : "Failed to save settings" });
151
148
  window.setTimeout(() => setToast(null), 3500);
152
149
  } finally {
153
150
  setSaving(false);
@@ -156,200 +153,98 @@ function AdditionalSettingsTab() {
156
153
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
157
154
  /* @__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" }) }) }),
158
155
  /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
159
- toast ? /* @__PURE__ */ jsxRuntime.jsx(
160
- "div",
161
- {
162
- 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",
163
- role: "status",
164
- "aria-live": "polite",
165
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: toast.type === "success" ? "text-ui-fg-base" : "text-ui-fg-error", children: toast.message })
166
- }
167
- ) : null,
156
+ toast ? /* @__PURE__ */ jsxRuntime.jsx("div", { 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", role: "status", "aria-live": "polite", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: toast.type === "success" ? "text-ui-fg-base" : "text-ui-fg-error", children: toast.message }) }) : null,
168
157
  /* @__PURE__ */ jsxRuntime.jsx(
169
158
  SectionCard$2,
170
159
  {
171
160
  title: "Additional Settings",
172
161
  description: "These settings control checkout behavior, PayPal experience, and logging.",
173
162
  right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
174
- /* @__PURE__ */ jsxRuntime.jsx(
175
- "button",
176
- {
177
- type: "button",
178
- onClick: onSave,
179
- disabled: saving || loading,
180
- 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",
181
- children: saving ? "Saving..." : "Save settings"
182
- }
183
- ),
184
- loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading…" }) : null
163
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onSave, disabled: saving || loading, 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", children: saving ? "Saving..." : "Save settings" }),
164
+ loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading..." }) : null
185
165
  ] }),
186
166
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
187
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Payment action", children: /* @__PURE__ */ jsxRuntime.jsxs(
188
- "select",
189
- {
190
- value: form.paymentAction,
191
- onChange: (e) => setForm((p) => ({ ...p, paymentAction: e.target.value })),
192
- 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",
193
- children: [
194
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "capture", children: "Capture" }),
195
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "authorize", children: "Authorize" })
196
- ]
197
- }
198
- ) }),
199
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Brand Name", children: /* @__PURE__ */ jsxRuntime.jsx(
200
- "input",
201
- {
202
- value: form.brandName,
203
- onChange: (e) => setForm((p) => ({ ...p, brandName: e.target.value })),
204
- 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",
205
- placeholder: "PayPal"
206
- }
207
- ) }),
208
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Landing Page", children: /* @__PURE__ */ jsxRuntime.jsxs(
209
- "select",
210
- {
211
- value: form.landingPage,
212
- onChange: (e) => setForm((p) => ({ ...p, landingPage: e.target.value })),
213
- 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",
214
- children: [
215
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "no_preference", children: "No Preference" }),
216
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "login", children: "Login" }),
217
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "billing", children: "Billing" })
218
- ]
219
- }
220
- ) }),
167
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Payment action", children: /* @__PURE__ */ jsxRuntime.jsxs("select", { value: form.paymentAction, onChange: (e) => setForm((p) => ({ ...p, paymentAction: e.target.value })), 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", children: [
168
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "capture", children: "Capture" }),
169
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "authorize", children: "Authorize" })
170
+ ] }) }),
171
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Brand Name", children: /* @__PURE__ */ jsxRuntime.jsx("input", { value: form.brandName, onChange: (e) => setForm((p) => ({ ...p, brandName: e.target.value })), 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", placeholder: "PayPal" }) }),
172
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Landing Page", children: /* @__PURE__ */ jsxRuntime.jsxs("select", { value: form.landingPage, onChange: (e) => setForm((p) => ({ ...p, landingPage: e.target.value })), 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", children: [
173
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "no_preference", children: "No Preference" }),
174
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "login", children: "Login" }),
175
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "billing", children: "Billing" })
176
+ ] }) }),
221
177
  /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Instant Payments", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
222
- /* @__PURE__ */ jsxRuntime.jsx(
223
- "input",
224
- {
225
- type: "checkbox",
226
- checked: form.requireInstantPayment,
227
- onChange: (e) => setForm((p) => ({ ...p, requireInstantPayment: e.target.checked })),
228
- className: "h-4 w-4 rounded border-ui-border-base"
229
- }
230
- ),
178
+ /* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: form.requireInstantPayment, onChange: (e) => setForm((p) => ({ ...p, requireInstantPayment: e.target.checked })), className: "h-4 w-4 rounded border-ui-border-base" }),
231
179
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Require Instant Payment" })
232
180
  ] }) }),
233
- /* @__PURE__ */ jsxRuntime.jsx(
234
- FieldRow$2,
235
- {
236
- label: "Billing Address",
237
- hint: "If the billing address is empty and PayPal provides a shipping address, the order will use the shipping address as the billing address.",
238
- children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
239
- /* @__PURE__ */ jsxRuntime.jsx(
240
- "input",
241
- {
242
- type: "checkbox",
243
- checked: form.useShippingAsBilling,
244
- onChange: (e) => setForm((p) => ({ ...p, useShippingAsBilling: e.target.checked })),
245
- className: "h-4 w-4 rounded border-ui-border-base"
246
- }
247
- ),
248
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Use PayPal Shipping Address as Billing" })
249
- ] })
250
- }
251
- ),
252
- /* @__PURE__ */ jsxRuntime.jsx(
253
- FieldRow$2,
254
- {
255
- label: "Send Item Details",
256
- hint: "Include all line item details in the payment request to PayPal so that they can be seen from the PayPal transaction details page.",
257
- children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
258
- /* @__PURE__ */ jsxRuntime.jsx(
259
- "input",
260
- {
261
- type: "checkbox",
262
- checked: form.sendItemDetails,
263
- onChange: (e) => setForm((p) => ({ ...p, sendItemDetails: e.target.checked })),
264
- className: "h-4 w-4 rounded border-ui-border-base"
265
- }
266
- ),
267
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Send line item details to PayPal" })
268
- ] })
269
- }
270
- ),
271
- /* @__PURE__ */ jsxRuntime.jsx(
272
- FieldRow$2,
273
- {
274
- label: "Order Review Page",
275
- hint: "Payments from the Product or Cart page skip the review step and go straight to the Thank You page.",
276
- children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
277
- /* @__PURE__ */ jsxRuntime.jsx(
278
- "input",
279
- {
280
- type: "checkbox",
281
- checked: form.skipOrderReviewPage,
282
- onChange: (e) => setForm((p) => ({ ...p, skipOrderReviewPage: e.target.checked })),
283
- className: "h-4 w-4 rounded border-ui-border-base"
284
- }
285
- ),
286
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Skip Order Review Page" })
287
- ] })
288
- }
289
- ),
290
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Invoice prefix", children: /* @__PURE__ */ jsxRuntime.jsx(
291
- "input",
292
- {
293
- value: form.invoicePrefix,
294
- onChange: (e) => setForm((p) => ({ ...p, invoicePrefix: e.target.value })),
295
- 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",
296
- placeholder: "WC-"
297
- }
298
- ) }),
299
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Credit Card Statement Name", children: /* @__PURE__ */ jsxRuntime.jsx(
300
- "input",
301
- {
302
- value: form.creditCardStatementName,
303
- onChange: (e) => setForm((p) => ({ ...p, creditCardStatementName: e.target.value })),
304
- 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",
305
- placeholder: "PayPal"
306
- }
307
- ) }),
308
- /* @__PURE__ */ jsxRuntime.jsx(
309
- FieldRow$2,
310
- {
311
- label: "Debug log",
312
- hint: /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
313
- "Log PayPal events such as Webhook, Payment, Refund.",
314
- " ",
315
- form.logPath ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
316
- "Log location: ",
317
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: form.logPath })
318
- ] }) : null
319
- ] }),
320
- children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
321
- /* @__PURE__ */ jsxRuntime.jsx(
322
- "input",
323
- {
324
- type: "checkbox",
325
- checked: form.enableLogging,
326
- onChange: (e) => setForm((p) => ({ ...p, enableLogging: e.target.checked })),
327
- className: "h-4 w-4 rounded border-ui-border-base"
328
- }
329
- ),
330
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable logging" })
331
- ] })
332
- }
333
- )
181
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Billing Address", hint: "If the billing address is empty and PayPal provides a shipping address, the order will use the shipping address as the billing address.", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
182
+ /* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: form.useShippingAsBilling, onChange: (e) => setForm((p) => ({ ...p, useShippingAsBilling: e.target.checked })), className: "h-4 w-4 rounded border-ui-border-base" }),
183
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Use PayPal Shipping Address as Billing" })
184
+ ] }) }),
185
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Send Item Details", hint: "Include all line item details in the payment request to PayPal so that they can be seen from the PayPal transaction details page.", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
186
+ /* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: form.sendItemDetails, onChange: (e) => setForm((p) => ({ ...p, sendItemDetails: e.target.checked })), className: "h-4 w-4 rounded border-ui-border-base" }),
187
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Send line item details to PayPal" })
188
+ ] }) }),
189
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Order Review Page", hint: "Payments from the Product or Cart page skip the review step and go straight to the Thank You page.", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
190
+ /* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: form.skipOrderReviewPage, onChange: (e) => setForm((p) => ({ ...p, skipOrderReviewPage: e.target.checked })), className: "h-4 w-4 rounded border-ui-border-base" }),
191
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Skip Order Review Page" })
192
+ ] }) }),
193
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Invoice prefix", children: /* @__PURE__ */ jsxRuntime.jsx("input", { value: form.invoicePrefix, onChange: (e) => setForm((p) => ({ ...p, invoicePrefix: e.target.value })), 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", placeholder: "WC-" }) }),
194
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Credit Card Statement Name", children: /* @__PURE__ */ jsxRuntime.jsx("input", { value: form.creditCardStatementName, onChange: (e) => setForm((p) => ({ ...p, creditCardStatementName: e.target.value })), 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", placeholder: "PayPal" }) }),
195
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Debug log", hint: /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
196
+ "Log PayPal events such as Webhook, Payment, Refund. ",
197
+ form.logPath ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
198
+ "Log location: ",
199
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: form.logPath })
200
+ ] }) : null
201
+ ] }), children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
202
+ /* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: form.enableLogging, onChange: (e) => setForm((p) => ({ ...p, enableLogging: e.target.checked })), className: "h-4 w-4 rounded border-ui-border-base" }),
203
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable logging" })
204
+ ] }) })
334
205
  ] })
335
206
  }
336
207
  )
337
208
  ] }) });
338
209
  }
339
- const DEFAULT_FORM = {
340
- enabled: true,
341
- title: "Credit or Debit Card",
342
- disabledCards: [],
343
- threeDS: "when_required",
344
- cardSaveEnabled: false
345
- };
210
+ async function adminFetch$3(path, opts = {}) {
211
+ var _a;
212
+ const { method = "GET", body, query } = opts;
213
+ let url = path;
214
+ if (query && Object.keys(query).length > 0) {
215
+ const params = new URLSearchParams(query);
216
+ url = `${path}?${params.toString()}`;
217
+ }
218
+ const headers = { Accept: "application/json" };
219
+ if (body !== void 0) headers["Content-Type"] = "application/json";
220
+ if (typeof window !== "undefined") {
221
+ const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
222
+ if (token) headers["Authorization"] = `Bearer ${token}`;
223
+ }
224
+ const res = await fetch(url, {
225
+ method,
226
+ headers,
227
+ credentials: "include",
228
+ body: body !== void 0 ? JSON.stringify(body) : void 0
229
+ });
230
+ const text = await res.text().catch(() => "");
231
+ if (!res.ok) {
232
+ if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
233
+ if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
234
+ throw new Error(text || `Request failed with status ${res.status}`);
235
+ }
236
+ if (!text) return {};
237
+ try {
238
+ return JSON.parse(text);
239
+ } catch {
240
+ return {};
241
+ }
242
+ }
243
+ const DEFAULT_FORM = { enabled: true, title: "Credit or Debit Card", disabledCards: [], threeDS: "when_required", cardSaveEnabled: false };
346
244
  function mergeWithDefaults(saved) {
347
245
  if (!saved) return { ...DEFAULT_FORM };
348
246
  const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
349
- return {
350
- ...DEFAULT_FORM,
351
- ...Object.fromEntries(entries)
352
- };
247
+ return { ...DEFAULT_FORM, ...Object.fromEntries(entries) };
353
248
  }
354
249
  const CARD_BRANDS = [
355
250
  { value: "visa", label: "Visa" },
@@ -361,49 +256,17 @@ const CARD_BRANDS = [
361
256
  { value: "unionpay", label: "UnionPay" }
362
257
  ];
363
258
  const THREE_DS_OPTIONS = [
364
- {
365
- value: "when_required",
366
- label: "3D Secure when required",
367
- hint: "Triggers 3DS only when the card / issuer requires it."
368
- },
369
- {
370
- value: "sli",
371
- label: "3D Secure (SCA) / liability shift (recommended)",
372
- hint: "Attempts to optimize for liability shift while remaining compliant."
373
- },
374
- {
375
- value: "always",
376
- label: "Always request 3D Secure",
377
- hint: "Forces 3DS challenge whenever possible (may reduce conversion)."
378
- }
259
+ { value: "when_required", label: "3D Secure when required", hint: "Triggers 3DS only when the card / issuer requires it." },
260
+ { value: "sli", label: "3D Secure (SCA) / liability shift (recommended)", hint: "Attempts to optimize for liability shift while remaining compliant." },
261
+ { value: "always", label: "Always request 3D Secure", hint: "Forces 3DS challenge whenever possible (may reduce conversion)." }
379
262
  ];
380
- function cx$1(...parts) {
381
- return parts.filter(Boolean).join(" ");
382
- }
383
- function Pill$1({
384
- children,
385
- onRemove
386
- }) {
263
+ function Pill$1({ children, onRemove }) {
387
264
  return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 rounded-md border border-ui-border-base bg-ui-bg-base px-2 py-1 text-sm text-ui-fg-base", children: [
388
265
  children,
389
- onRemove ? /* @__PURE__ */ jsxRuntime.jsx(
390
- "button",
391
- {
392
- type: "button",
393
- onClick: onRemove,
394
- className: "ml-1 rounded px-1 text-ui-fg-subtle hover:text-ui-fg-base",
395
- "aria-label": "Remove",
396
- children: "×"
397
- }
398
- ) : null
266
+ onRemove ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onRemove, className: "ml-1 rounded px-1 text-ui-fg-subtle hover:text-ui-fg-base", "aria-label": "Remove", children: "x" }) : null
399
267
  ] });
400
268
  }
401
- function SectionCard$1({
402
- title,
403
- description,
404
- right,
405
- children
406
- }) {
269
+ function SectionCard$1({ title, description, right, children }) {
407
270
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
408
271
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
409
272
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
@@ -415,11 +278,7 @@ function SectionCard$1({
415
278
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children })
416
279
  ] });
417
280
  }
418
- function FieldRow$1({
419
- label,
420
- hint,
421
- children
422
- }) {
281
+ function FieldRow$1({ label, hint, children }) {
423
282
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
424
283
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 md:col-span-4", children: [
425
284
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
@@ -441,17 +300,11 @@ function AdvancedCardPaymentsTab() {
441
300
  (async () => {
442
301
  try {
443
302
  setLoading(true);
444
- const r = await fetch("/admin/paypal/settings", {
445
- credentials: "include",
446
- headers: { "Accept": "application/json" }
447
- });
448
- if (!r.ok) return;
449
- const json = await r.json();
303
+ const json = await adminFetch$3("/admin/paypal/settings");
450
304
  const payload = (json == null ? void 0 : json.data) ?? json;
451
305
  const saved = payload == null ? void 0 : payload.advanced_card_payments;
452
- if (saved && typeof saved === "object") {
453
- setForm(mergeWithDefaults(saved));
454
- }
306
+ if (saved && typeof saved === "object") setForm(mergeWithDefaults(saved));
307
+ } catch {
455
308
  } finally {
456
309
  setLoading(false);
457
310
  }
@@ -460,29 +313,15 @@ function AdvancedCardPaymentsTab() {
460
313
  async function onSave() {
461
314
  try {
462
315
  setSaving(true);
463
- const r = await fetch("/admin/paypal/settings", {
464
- method: "POST",
465
- credentials: "include",
466
- headers: {
467
- "Content-Type": "application/json",
468
- "Accept": "application/json"
469
- },
470
- body: JSON.stringify({ advanced_card_payments: form })
471
- });
472
- if (!r.ok) {
473
- const t = await r.text();
474
- setToast({ type: "error", message: "Failed to save settings. " + t });
475
- window.setTimeout(() => setToast(null), 3500);
476
- return;
477
- }
478
- const json = await r.json().catch(() => null);
316
+ const json = await adminFetch$3("/admin/paypal/settings", { method: "POST", body: { advanced_card_payments: form } });
479
317
  const payload = (json == null ? void 0 : json.data) ?? json;
480
318
  const saved = payload == null ? void 0 : payload.advanced_card_payments;
481
- if (saved && typeof saved === "object") {
482
- setForm(mergeWithDefaults(saved));
483
- }
319
+ if (saved && typeof saved === "object") setForm(mergeWithDefaults(saved));
484
320
  setToast({ type: "success", message: "Settings saved" });
485
321
  window.setTimeout(() => setToast(null), 2500);
322
+ } catch (e) {
323
+ setToast({ type: "error", message: (e instanceof Error ? e.message : "") || "Failed to save settings." });
324
+ window.setTimeout(() => setToast(null), 3500);
486
325
  } finally {
487
326
  setSaving(false);
488
327
  }
@@ -491,138 +330,47 @@ function AdvancedCardPaymentsTab() {
491
330
  function toggleDisabledCard(value) {
492
331
  setForm((prev) => {
493
332
  const exists = prev.disabledCards.includes(value);
494
- return {
495
- ...prev,
496
- disabledCards: exists ? prev.disabledCards.filter((v) => v !== value) : [...prev.disabledCards, value]
497
- };
333
+ return { ...prev, disabledCards: exists ? prev.disabledCards.filter((v) => v !== value) : [...prev.disabledCards, value] };
498
334
  });
499
335
  }
500
336
  function removeDisabledCard(value) {
501
- setForm((prev) => ({
502
- ...prev,
503
- disabledCards: prev.disabledCards.filter((v) => v !== value)
504
- }));
337
+ setForm((prev) => ({ ...prev, disabledCards: prev.disabledCards.filter((v) => v !== value) }));
505
338
  }
506
339
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
507
340
  /* @__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
341
  /* @__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,
342
+ toast ? /* @__PURE__ */ jsxRuntime.jsx("div", { 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", role: "status", "aria-live": "polite", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: toast.type === "success" ? "text-ui-fg-base" : "text-ui-fg-error", children: toast.message }) }) : null,
518
343
  /* @__PURE__ */ jsxRuntime.jsx(
519
344
  SectionCard$1,
520
345
  {
521
346
  title: "Advanced Card Payments",
522
347
  description: "Control card checkout settings, 3D Secure behavior, and card saving.",
523
348
  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
349
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onSave, disabled: saving || loading, 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", children: saving ? "Saving..." : "Save settings" }),
350
+ loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading..." }) : null
535
351
  ] }),
536
352
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
537
353
  /* @__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
- ),
354
+ /* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: form.enabled, onChange: (e) => setForm((p) => ({ ...p, enabled: e.target.checked })), className: "h-4 w-4 rounded border-ui-border-base" }),
547
355
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable Advanced Credit/Debit Card" })
548
356
  ] }) }),
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
- ),
357
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Title", children: /* @__PURE__ */ jsxRuntime.jsx("input", { value: form.title, onChange: (e) => setForm((p) => ({ ...p, title: e.target.value })), 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", placeholder: "Credit or Debit Card" }) }),
358
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Disable specific credit cards", hint: "Select card brands to hide from the card form.", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
359
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: form.disabledCards.length ? form.disabledCards.map((v) => {
360
+ var _a2;
361
+ return /* @__PURE__ */ jsxRuntime.jsx(Pill$1, { onRemove: () => removeDisabledCard(v), children: ((_a2 = CARD_BRANDS.find((b) => b.value === v)) == null ? void 0 : _a2.label) ?? v }, v);
362
+ }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "No card brands disabled." }) }),
363
+ /* @__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) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 rounded-md p-2 hover:bg-ui-bg-subtle", children: [
364
+ /* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: disabledSet.has(b.value), onChange: () => toggleDisabledCard(b.value), className: "h-4 w-4 rounded border-ui-border-base" }),
365
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: b.label })
366
+ ] }, b.value)) }) })
367
+ ] }) }),
368
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Contingency for 3D Secure", hint: "Choose when 3D Secure should be triggered during card payments.", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
369
+ /* @__PURE__ */ jsxRuntime.jsx("select", { value: form.threeDS, onChange: (e) => setForm((p) => ({ ...p, threeDS: e.target.value })), 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", children: THREE_DS_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value)) }),
370
+ ((_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
371
+ ] }) }),
616
372
  /* @__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
- ),
373
+ /* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: form.cardSaveEnabled, onChange: (e) => setForm((p) => ({ ...p, cardSaveEnabled: e.target.checked })), className: "h-4 w-4 rounded border-ui-border-base" }),
626
374
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable card saving at checkout" })
627
375
  ] }) })
628
376
  ] })
@@ -630,14 +378,46 @@ function AdvancedCardPaymentsTab() {
630
378
  )
631
379
  ] }) });
632
380
  }
633
- function formatDate$2(value) {
634
- if (!value) {
635
- return "";
381
+ function PayPalApplePayPage() {
382
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
383
+ }
384
+ async function adminFetch$2(path, opts = {}) {
385
+ var _a;
386
+ const { method = "GET", body, query } = opts;
387
+ let url = path;
388
+ if (query && Object.keys(query).length > 0) {
389
+ const params = new URLSearchParams(query);
390
+ url = `${path}?${params.toString()}`;
636
391
  }
637
- const parsed = new Date(value);
638
- if (Number.isNaN(parsed.getTime())) {
639
- return value;
392
+ const headers = { Accept: "application/json" };
393
+ if (body !== void 0) headers["Content-Type"] = "application/json";
394
+ if (typeof window !== "undefined") {
395
+ const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
396
+ if (token) headers["Authorization"] = `Bearer ${token}`;
397
+ }
398
+ const res = await fetch(url, {
399
+ method,
400
+ headers,
401
+ credentials: "include",
402
+ body: body !== void 0 ? JSON.stringify(body) : void 0
403
+ });
404
+ const text = await res.text().catch(() => "");
405
+ if (!res.ok) {
406
+ if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
407
+ if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
408
+ throw new Error(text || `Request failed with status ${res.status}`);
409
+ }
410
+ if (!text) return {};
411
+ try {
412
+ return JSON.parse(text);
413
+ } catch {
414
+ return {};
640
415
  }
416
+ }
417
+ function formatDate$1(value) {
418
+ if (!value) return "";
419
+ const parsed = new Date(value);
420
+ if (Number.isNaN(parsed.getTime())) return value;
641
421
  return parsed.toLocaleString();
642
422
  }
643
423
  function PayPalAuditLogsPage() {
@@ -648,20 +428,10 @@ function PayPalAuditLogsPage() {
648
428
  try {
649
429
  setLoading(true);
650
430
  setError(null);
651
- const response = await fetch("/admin/paypal/audit-logs?limit=50", {
652
- credentials: "include",
653
- headers: {
654
- Accept: "application/json"
655
- }
656
- });
657
- if (!response.ok) {
658
- const message = await response.text().catch(() => "");
659
- throw new Error(message || "Failed to load audit logs.");
660
- }
661
- const data = await response.json().catch(() => ({}));
662
- setLogs((data == null ? void 0 : data.logs) || []);
431
+ const data = await adminFetch$2("/admin/paypal/audit-logs", { query: { limit: "50" } });
432
+ setLogs((data == null ? void 0 : data.logs) ?? []);
663
433
  } catch (fetchError) {
664
- setError((fetchError == null ? void 0 : fetchError.message) || "Failed to load audit logs.");
434
+ setError(fetchError instanceof Error ? fetchError.message : "Failed to load audit logs.");
665
435
  setLogs([]);
666
436
  } finally {
667
437
  setLoading(false);
@@ -679,16 +449,7 @@ function PayPalAuditLogsPage() {
679
449
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
680
450
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-ui-border-base p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4", children: [
681
451
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: "Latest events" }),
682
- /* @__PURE__ */ jsxRuntime.jsx(
683
- "button",
684
- {
685
- type: "button",
686
- onClick: fetchLogs,
687
- className: "rounded-md border border-ui-border-base px-3 py-2 text-sm text-ui-fg-base",
688
- disabled: loading,
689
- children: loading ? "Refreshing..." : "Refresh"
690
- }
691
- )
452
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: fetchLogs, className: "rounded-md border border-ui-border-base px-3 py-2 text-sm text-ui-fg-base", disabled: loading, children: loading ? "Refreshing..." : "Refresh" })
692
453
  ] }) }),
693
454
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
694
455
  error ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-red-200 bg-red-50 p-3 text-sm text-red-600", children: error }) : null,
@@ -700,7 +461,7 @@ function PayPalAuditLogsPage() {
700
461
  /* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 font-medium", children: "Details" })
701
462
  ] }) }),
702
463
  /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: logs.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-t border-ui-border-base", children: [
703
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: formatDate$2(entry.created_at) || "—" }),
464
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: formatDate$1(entry.created_at) || "—" }),
704
465
  /* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: entry.event_type || "—" }),
705
466
  /* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 text-ui-fg-subtle", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre-wrap rounded-md bg-ui-bg-subtle p-2 text-xs text-ui-fg-subtle", children: JSON.stringify(entry.metadata || {}, null, 2) }) })
706
467
  ] }, entry.id)) })
@@ -709,201 +470,6 @@ function PayPalAuditLogsPage() {
709
470
  ] })
710
471
  ] }) });
711
472
  }
712
- function PayPalApplePayPage() {
713
- return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
714
- }
715
- const EMPTY_FILTERS = {
716
- dispute_id: "",
717
- status: "",
718
- order_id: "",
719
- cart_id: ""
720
- };
721
- function formatDate$1(value) {
722
- if (!value) {
723
- return "";
724
- }
725
- const parsed = new Date(value);
726
- if (Number.isNaN(parsed.getTime())) {
727
- return value;
728
- }
729
- return parsed.toLocaleString();
730
- }
731
- function PayPalDisputesPage() {
732
- const [filters, setFilters] = react.useState({ ...EMPTY_FILTERS });
733
- const [disputes, setDisputes] = react.useState([]);
734
- const [loading, setLoading] = react.useState(false);
735
- const [error, setError] = react.useState(null);
736
- const queryString = react.useMemo(() => {
737
- const params = new URLSearchParams();
738
- Object.entries(filters).forEach(([key, value]) => {
739
- if (value.trim()) {
740
- params.set(key, value.trim());
741
- }
742
- });
743
- const qs = params.toString();
744
- return qs ? `?${qs}` : "";
745
- }, [filters]);
746
- const fetchDisputes = react.useCallback(async (source) => {
747
- try {
748
- setLoading(true);
749
- setError(null);
750
- const params = new URLSearchParams();
751
- Object.entries(source).forEach(([key, value]) => {
752
- if (value.trim()) {
753
- params.set(key, value.trim());
754
- }
755
- });
756
- const qs = params.toString();
757
- const resp = await fetch(`/admin/paypal/disputes${qs ? `?${qs}` : ""}`, {
758
- credentials: "include",
759
- headers: {
760
- Accept: "application/json"
761
- }
762
- });
763
- if (!resp.ok) {
764
- const message = await resp.text().catch(() => "");
765
- throw new Error(message || "Failed to load disputes");
766
- }
767
- const json = await resp.json().catch(() => ({}));
768
- setDisputes((json == null ? void 0 : json.disputes) || []);
769
- } catch (fetchError) {
770
- setError((fetchError == null ? void 0 : fetchError.message) || "Failed to load disputes");
771
- setDisputes([]);
772
- } finally {
773
- setLoading(false);
774
- }
775
- }, []);
776
- react.useEffect(() => {
777
- fetchDisputes(EMPTY_FILTERS);
778
- }, [fetchDisputes]);
779
- const onSubmit = (event) => {
780
- event.preventDefault();
781
- fetchDisputes(filters);
782
- };
783
- const onReset = () => {
784
- setFilters({ ...EMPTY_FILTERS });
785
- fetchDisputes(EMPTY_FILTERS);
786
- };
787
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
788
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
789
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Disputes" }),
790
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-ui-fg-subtle", children: "Review PayPal dispute activity tied to your Medusa orders. This view is read-only." })
791
- ] }),
792
- /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
793
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
794
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-ui-border-base p-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: "Filters" }) }),
795
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit, className: "flex flex-col gap-4", children: [
796
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-4", children: [
797
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
798
- "Dispute ID",
799
- /* @__PURE__ */ jsxRuntime.jsx(
800
- "input",
801
- {
802
- className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
803
- value: filters.dispute_id,
804
- onChange: (event) => setFilters((prev) => ({ ...prev, dispute_id: event.target.value })),
805
- placeholder: "PP-D-123"
806
- }
807
- )
808
- ] }),
809
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
810
- "Status",
811
- /* @__PURE__ */ jsxRuntime.jsx(
812
- "input",
813
- {
814
- className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
815
- value: filters.status,
816
- onChange: (event) => setFilters((prev) => ({ ...prev, status: event.target.value })),
817
- placeholder: "OPEN"
818
- }
819
- )
820
- ] }),
821
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
822
- "Order ID",
823
- /* @__PURE__ */ jsxRuntime.jsx(
824
- "input",
825
- {
826
- className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
827
- value: filters.order_id,
828
- onChange: (event) => setFilters((prev) => ({ ...prev, order_id: event.target.value })),
829
- placeholder: "order_..."
830
- }
831
- )
832
- ] }),
833
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
834
- "Cart ID",
835
- /* @__PURE__ */ jsxRuntime.jsx(
836
- "input",
837
- {
838
- className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
839
- value: filters.cart_id,
840
- onChange: (event) => setFilters((prev) => ({ ...prev, cart_id: event.target.value })),
841
- placeholder: "cart_..."
842
- }
843
- )
844
- ] })
845
- ] }),
846
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-3", children: [
847
- /* @__PURE__ */ jsxRuntime.jsx(
848
- "button",
849
- {
850
- type: "submit",
851
- className: "rounded-md bg-ui-fg-base px-4 py-2 text-sm font-medium text-ui-bg-base",
852
- disabled: loading,
853
- children: loading ? "Loading..." : "Apply filters"
854
- }
855
- ),
856
- /* @__PURE__ */ jsxRuntime.jsx(
857
- "button",
858
- {
859
- type: "button",
860
- className: "rounded-md border border-ui-border-base px-4 py-2 text-sm text-ui-fg-base",
861
- onClick: onReset,
862
- disabled: loading,
863
- children: "Reset"
864
- }
865
- ),
866
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-ui-fg-subtle", children: [
867
- "Showing ",
868
- disputes.length,
869
- " dispute",
870
- disputes.length === 1 ? "" : "s",
871
- queryString ? " (filtered)" : ""
872
- ] })
873
- ] })
874
- ] }) })
875
- ] }),
876
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
877
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-ui-border-base p-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: "Dispute Records" }) }),
878
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full divide-y divide-ui-border-base text-sm", children: [
879
- /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "text-left text-ui-fg-subtle", children: [
880
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Dispute" }),
881
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Status" }),
882
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Reason" }),
883
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Stage" }),
884
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Amount" }),
885
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Order" }),
886
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Cart" }),
887
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Updated" })
888
- ] }) }),
889
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-ui-border-base text-ui-fg-base", children: disputes.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-6 text-center text-ui-fg-subtle", colSpan: 8, children: loading ? "Loading disputes..." : "No disputes found." }) }) : disputes.map((dispute) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
890
- /* @__PURE__ */ jsxRuntime.jsxs("td", { className: "px-4 py-3", children: [
891
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-ui-fg-base", children: dispute.dispute_id }),
892
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-ui-fg-subtle", children: dispute.transaction_id || "No transaction" })
893
- ] }),
894
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.status || "Unknown" }),
895
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.reason || "-" }),
896
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.stage || "-" }),
897
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.amount ? `${dispute.amount} ${dispute.currency_code || ""}` : "-" }),
898
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.order_id || "-" }),
899
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.cart_id || "-" }),
900
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 text-ui-fg-subtle", children: formatDate$1(dispute.updated_at || dispute.created_at) })
901
- ] }, dispute.id)) })
902
- ] }) }),
903
- error ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-ui-border-base px-4 py-3 text-sm text-ui-fg-error", children: error }) : null
904
- ] })
905
- ] }) });
906
- }
907
473
  const config = adminSdk.defineRouteConfig({
908
474
  label: "PayPal Connection",
909
475
  hide: true
@@ -1430,69 +996,222 @@ function PayPalConnectionPage() {
1430
996
  }
1431
997
  )
1432
998
  ] }),
1433
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 md:col-span-2", children: [
1434
- /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Merchant ID (optional)" }),
1435
- /* @__PURE__ */ jsxRuntime.jsx(
1436
- "input",
1437
- {
1438
- type: "text",
1439
- value: merchantId,
1440
- onChange: (e) => setMerchantId(e.target.value),
1441
- disabled: onboardingInProgress,
1442
- className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
1443
- placeholder: "Merchant ID"
1444
- }
1445
- )
999
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 md:col-span-2", children: [
1000
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Merchant ID (optional)" }),
1001
+ /* @__PURE__ */ jsxRuntime.jsx(
1002
+ "input",
1003
+ {
1004
+ type: "text",
1005
+ value: merchantId,
1006
+ onChange: (e) => setMerchantId(e.target.value),
1007
+ disabled: onboardingInProgress,
1008
+ className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
1009
+ placeholder: "Merchant ID"
1010
+ }
1011
+ )
1012
+ ] }),
1013
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:col-span-2 flex items-center gap-2 mt-2", children: [
1014
+ /* @__PURE__ */ jsxRuntime.jsx(
1015
+ "button",
1016
+ {
1017
+ type: "button",
1018
+ 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",
1019
+ onClick: () => setShowManual(false),
1020
+ disabled: onboardingInProgress,
1021
+ children: "Cancel"
1022
+ }
1023
+ ),
1024
+ /* @__PURE__ */ jsxRuntime.jsx(
1025
+ "button",
1026
+ {
1027
+ type: "button",
1028
+ 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",
1029
+ disabled: !canSaveManual || onboardingInProgress,
1030
+ onClick: handleSaveManual,
1031
+ children: "Save credentials"
1032
+ }
1033
+ )
1034
+ ] })
1035
+ ] }) })
1036
+ ] }) })
1037
+ ] }),
1038
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
1039
+ .loader {
1040
+ border: 3px solid #f3f3f3;
1041
+ border-top: 3px solid #0070ba;
1042
+ border-radius: 50%;
1043
+ width: 18px;
1044
+ height: 18px;
1045
+ animation: spin 1s linear infinite;
1046
+ display: inline-block;
1047
+ vertical-align: middle;
1048
+ margin-right: 8px;
1049
+ }
1050
+ @keyframes spin {
1051
+ 0% { transform: rotate(0deg); }
1052
+ 100% { transform: rotate(360deg); }
1053
+ }
1054
+ ` })
1055
+ ] });
1056
+ }
1057
+ function PayPalGooglePayPage() {
1058
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1059
+ }
1060
+ function PayPalPayLaterMessagingPage() {
1061
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1062
+ }
1063
+ async function adminFetch$1(path, opts = {}) {
1064
+ var _a;
1065
+ const { method = "GET", body, query } = opts;
1066
+ let url = path;
1067
+ if (query && Object.keys(query).length > 0) {
1068
+ const params = new URLSearchParams(query);
1069
+ url = `${path}?${params.toString()}`;
1070
+ }
1071
+ const headers = { Accept: "application/json" };
1072
+ if (body !== void 0) headers["Content-Type"] = "application/json";
1073
+ if (typeof window !== "undefined") {
1074
+ const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
1075
+ if (token) headers["Authorization"] = `Bearer ${token}`;
1076
+ }
1077
+ const res = await fetch(url, {
1078
+ method,
1079
+ headers,
1080
+ credentials: "include",
1081
+ body: body !== void 0 ? JSON.stringify(body) : void 0
1082
+ });
1083
+ const text = await res.text().catch(() => "");
1084
+ if (!res.ok) {
1085
+ if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
1086
+ if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
1087
+ throw new Error(text || `Request failed with status ${res.status}`);
1088
+ }
1089
+ if (!text) return {};
1090
+ try {
1091
+ return JSON.parse(text);
1092
+ } catch {
1093
+ return {};
1094
+ }
1095
+ }
1096
+ function formatDate(value) {
1097
+ if (!value) return "—";
1098
+ const parsed = new Date(value);
1099
+ if (Number.isNaN(parsed.getTime())) return value;
1100
+ return parsed.toLocaleString();
1101
+ }
1102
+ function PayPalReconciliationStatusPage() {
1103
+ const [status, setStatus] = react.useState({});
1104
+ const [loading, setLoading] = react.useState(false);
1105
+ const [error, setError] = react.useState(null);
1106
+ const fetchStatus = react.useCallback(async () => {
1107
+ try {
1108
+ setLoading(true);
1109
+ setError(null);
1110
+ const data = await adminFetch$1("/admin/paypal/reconciliation-status");
1111
+ setStatus((data == null ? void 0 : data.status) ?? {});
1112
+ } catch (fetchError) {
1113
+ setError(fetchError instanceof Error ? fetchError.message : "Failed to load reconciliation status.");
1114
+ setStatus({});
1115
+ } finally {
1116
+ setLoading(false);
1117
+ }
1118
+ }, []);
1119
+ react.useEffect(() => {
1120
+ fetchStatus();
1121
+ }, [fetchStatus]);
1122
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
1123
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1124
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Reconciliation Status" }),
1125
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-ui-fg-subtle", children: "Monitor reconciliation health and drift detection for PayPal payment sessions." })
1126
+ ] }),
1127
+ /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
1128
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
1129
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-ui-border-base p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4", children: [
1130
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: "Latest reconciliation run" }),
1131
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: fetchStatus, className: "rounded-md border border-ui-border-base px-3 py-2 text-sm text-ui-fg-base", disabled: loading, children: loading ? "Refreshing..." : "Refresh" })
1132
+ ] }) }),
1133
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
1134
+ error ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-red-200 bg-red-50 p-3 text-sm text-red-600", children: error }) : null,
1135
+ !error && Object.keys(status).length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-ui-fg-subtle", children: loading ? "Loading reconciliation status..." : "No reconciliation data yet." }) : null,
1136
+ Object.keys(status).length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 text-sm text-ui-fg-base md:grid-cols-2", children: [
1137
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1138
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last run" }),
1139
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_run_at) })
1140
+ ] }),
1141
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1142
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last run status" }),
1143
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium capitalize", children: status.last_run_status || "—" })
1144
+ ] }),
1145
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1146
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last success" }),
1147
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_success_at) })
1148
+ ] }),
1149
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1150
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last failure" }),
1151
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_failure_at) })
1152
+ ] }),
1153
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1154
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Sessions checked" }),
1155
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.sessions_checked ?? 0 })
1156
+ ] }),
1157
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1158
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Sessions updated" }),
1159
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.sessions_updated ?? 0 })
1160
+ ] }),
1161
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1162
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Drift detections" }),
1163
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.drift_count ?? 0 })
1164
+ ] }),
1165
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1166
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last drift order" }),
1167
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.last_drift_order_id || "—" }),
1168
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: formatDate(status.last_drift_at) })
1169
+ ] }),
1170
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3 md:col-span-2", children: [
1171
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last error" }),
1172
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.last_error || "No errors recorded." })
1446
1173
  ] }),
1447
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:col-span-2 flex items-center gap-2 mt-2", children: [
1448
- /* @__PURE__ */ jsxRuntime.jsx(
1449
- "button",
1450
- {
1451
- type: "button",
1452
- 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",
1453
- onClick: () => setShowManual(false),
1454
- disabled: onboardingInProgress,
1455
- children: "Cancel"
1456
- }
1457
- ),
1458
- /* @__PURE__ */ jsxRuntime.jsx(
1459
- "button",
1460
- {
1461
- type: "button",
1462
- 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",
1463
- disabled: !canSaveManual || onboardingInProgress,
1464
- onClick: handleSaveManual,
1465
- children: "Save credentials"
1466
- }
1467
- )
1174
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3 md:col-span-2", children: [
1175
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Total runs" }),
1176
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.runs ?? 0 })
1468
1177
  ] })
1469
- ] }) })
1470
- ] }) })
1471
- ] }),
1472
- /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
1473
- .loader {
1474
- border: 3px solid #f3f3f3;
1475
- border-top: 3px solid #0070ba;
1476
- border-radius: 50%;
1477
- width: 18px;
1478
- height: 18px;
1479
- animation: spin 1s linear infinite;
1480
- display: inline-block;
1481
- vertical-align: middle;
1482
- margin-right: 8px;
1483
- }
1484
- @keyframes spin {
1485
- 0% { transform: rotate(0deg); }
1486
- 100% { transform: rotate(360deg); }
1487
- }
1488
- ` })
1489
- ] });
1490
- }
1491
- function PayPalGooglePayPage() {
1492
- return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1178
+ ] }) : null
1179
+ ] })
1180
+ ] })
1181
+ ] }) });
1493
1182
  }
1494
- function PayPalPayLaterMessagingPage() {
1495
- return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1183
+ async function adminFetch(path, opts = {}) {
1184
+ var _a;
1185
+ const { method = "GET", body, query } = opts;
1186
+ let url = path;
1187
+ if (query && Object.keys(query).length > 0) {
1188
+ const params = new URLSearchParams(query);
1189
+ url = `${path}?${params.toString()}`;
1190
+ }
1191
+ const headers = { Accept: "application/json" };
1192
+ if (body !== void 0) headers["Content-Type"] = "application/json";
1193
+ if (typeof window !== "undefined") {
1194
+ const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
1195
+ if (token) headers["Authorization"] = `Bearer ${token}`;
1196
+ }
1197
+ const res = await fetch(url, {
1198
+ method,
1199
+ headers,
1200
+ credentials: "include",
1201
+ body: body !== void 0 ? JSON.stringify(body) : void 0
1202
+ });
1203
+ const text = await res.text().catch(() => "");
1204
+ if (!res.ok) {
1205
+ if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
1206
+ if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
1207
+ throw new Error(text || `Request failed with status ${res.status}`);
1208
+ }
1209
+ if (!text) return {};
1210
+ try {
1211
+ return JSON.parse(text);
1212
+ } catch {
1213
+ return {};
1214
+ }
1496
1215
  }
1497
1216
  const DISPLAY_LOCATION_OPTIONS = [
1498
1217
  { value: "product", label: "Product Page" },
@@ -1605,7 +1324,7 @@ function PayPalSettingsTab() {
1605
1324
  const [form, setForm] = react.useState({
1606
1325
  enabled: true,
1607
1326
  title: "PayPal",
1608
- description: "Pay via PayPal; you can pay with your credit card if you dont have a PayPal account",
1327
+ description: "Pay via PayPal; you can pay with your credit card if you don't have a PayPal account",
1609
1328
  displayOn: ["product", "cart", "express", "mini_cart"],
1610
1329
  disableButtons: [],
1611
1330
  buttonColor: "gold",
@@ -1624,12 +1343,9 @@ function PayPalSettingsTab() {
1624
1343
  (async () => {
1625
1344
  try {
1626
1345
  setLoading(true);
1627
- const r = await fetch("/admin/paypal/settings", {
1628
- credentials: "include",
1629
- headers: { Accept: "application/json" }
1630
- });
1631
- if (!r.ok) return;
1632
- const json = await r.json();
1346
+ const json = await adminFetch(
1347
+ "/admin/paypal/settings"
1348
+ );
1633
1349
  const payload = (json == null ? void 0 : json.data) ?? json;
1634
1350
  const saved = payload == null ? void 0 : payload.paypal_settings;
1635
1351
  if (saved && typeof saved === "object") {
@@ -1639,6 +1355,7 @@ function PayPalSettingsTab() {
1639
1355
  disableButtons: filterHiddenDisableButtons(saved.disableButtons)
1640
1356
  }));
1641
1357
  }
1358
+ } catch {
1642
1359
  } finally {
1643
1360
  setLoading(false);
1644
1361
  }
@@ -1651,22 +1368,13 @@ function PayPalSettingsTab() {
1651
1368
  ...form,
1652
1369
  disableButtons: filterHiddenDisableButtons(form.disableButtons)
1653
1370
  };
1654
- const r = await fetch("/admin/paypal/settings", {
1655
- method: "POST",
1656
- credentials: "include",
1657
- headers: {
1658
- "Content-Type": "application/json",
1659
- Accept: "application/json"
1660
- },
1661
- body: JSON.stringify({ paypal_settings: cleaned })
1662
- });
1663
- if (!r.ok) {
1664
- const t = await r.text();
1665
- setToast({ type: "error", message: "Failed to save settings. " + t });
1666
- window.setTimeout(() => setToast(null), 3500);
1667
- return;
1668
- }
1669
- const json = await r.json().catch(() => null);
1371
+ const json = await adminFetch(
1372
+ "/admin/paypal/settings",
1373
+ {
1374
+ method: "POST",
1375
+ body: { paypal_settings: cleaned }
1376
+ }
1377
+ );
1670
1378
  const payload = (json == null ? void 0 : json.data) ?? json;
1671
1379
  const saved = payload == null ? void 0 : payload.paypal_settings;
1672
1380
  if (saved && typeof saved === "object") {
@@ -1678,6 +1386,12 @@ function PayPalSettingsTab() {
1678
1386
  }
1679
1387
  setToast({ type: "success", message: "Settings saved" });
1680
1388
  window.setTimeout(() => setToast(null), 2500);
1389
+ } catch (e) {
1390
+ setToast({
1391
+ type: "error",
1392
+ message: (e instanceof Error ? e.message : "") || "Failed to save settings."
1393
+ });
1394
+ window.setTimeout(() => setToast(null), 3500);
1681
1395
  } finally {
1682
1396
  setSaving(false);
1683
1397
  }
@@ -1817,226 +1531,114 @@ function PayPalSettingsTab() {
1817
1531
  ] })
1818
1532
  }
1819
1533
  ),
1820
- /* @__PURE__ */ jsxRuntime.jsxs(
1534
+ /* @__PURE__ */ jsxRuntime.jsx(
1821
1535
  SectionCard,
1822
1536
  {
1823
1537
  title: "Button Appearance",
1824
1538
  description: "Control PayPal Smart Button styling (color/shape/size/label) and optionally disable specific buttons.",
1825
- children: [
1826
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
1827
- /* @__PURE__ */ jsxRuntime.jsx(
1828
- FieldRow,
1829
- {
1830
- label: "Disable Specific Payment Buttons",
1831
- hint: "Hide individual funding sources (ex: Card, Venmo).",
1832
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
1833
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
1834
- filterHiddenDisableButtons(form.disableButtons).map((v) => {
1835
- const opt = VISIBLE_DISABLE_BUTTON_OPTIONS.find((o) => o.value === v);
1836
- return /* @__PURE__ */ jsxRuntime.jsx(Pill, { onRemove: () => removeMulti("disableButtons", v), children: (opt == null ? void 0 : opt.label) ?? v }, v);
1837
- }),
1838
- filterHiddenDisableButtons(form.disableButtons).length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "No buttons disabled." }) : null
1839
- ] }),
1840
- /* @__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: VISIBLE_DISABLE_BUTTON_OPTIONS.map((o) => {
1841
- const checked = form.disableButtons.includes(o.value);
1842
- return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 rounded-md p-2 hover:bg-ui-bg-subtle", children: [
1843
- /* @__PURE__ */ jsxRuntime.jsx(
1844
- "input",
1845
- {
1846
- type: "checkbox",
1847
- checked,
1848
- onChange: () => toggleMulti("disableButtons", o.value),
1849
- className: "h-4 w-4 rounded border-ui-border-base"
1850
- }
1851
- ),
1852
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: o.label })
1853
- ] }, o.value);
1854
- }) }) })
1855
- ] })
1856
- }
1857
- ),
1858
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Color", children: /* @__PURE__ */ jsxRuntime.jsx(
1859
- "select",
1860
- {
1861
- value: form.buttonColor,
1862
- onChange: (e) => setForm((p) => ({ ...p, buttonColor: e.target.value })),
1863
- 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",
1864
- children: COLOR_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1865
- }
1866
- ) }),
1867
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Shape", children: /* @__PURE__ */ jsxRuntime.jsx(
1868
- "select",
1869
- {
1870
- value: form.buttonShape,
1871
- onChange: (e) => setForm((p) => ({ ...p, buttonShape: e.target.value })),
1872
- 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",
1873
- children: SHAPE_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1874
- }
1875
- ) }),
1876
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Width", children: /* @__PURE__ */ jsxRuntime.jsx(
1877
- "select",
1878
- {
1879
- value: form.buttonWidth,
1880
- onChange: (e) => setForm((p) => ({ ...p, buttonWidth: e.target.value })),
1881
- 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",
1882
- children: WIDTH_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1883
- }
1884
- ) }),
1885
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Height", children: /* @__PURE__ */ jsxRuntime.jsx(
1886
- "select",
1887
- {
1888
- value: String(form.buttonHeight),
1889
- onChange: (e) => setForm((p) => ({ ...p, buttonHeight: Number(e.target.value) })),
1890
- 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",
1891
- children: HEIGHT_OPTIONS.map((h) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: h, children: [
1892
- h,
1893
- " px"
1894
- ] }, h))
1895
- }
1896
- ) }),
1897
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Label", children: /* @__PURE__ */ jsxRuntime.jsx(
1898
- "select",
1899
- {
1900
- value: form.buttonLabel,
1901
- onChange: (e) => setForm((p) => ({ ...p, buttonLabel: e.target.value })),
1902
- 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",
1903
- children: LABEL_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1904
- }
1905
- ) })
1906
- ] }),
1907
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 rounded-md border border-ui-border-base bg-ui-bg-subtle p-4", children: [
1908
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: "Preview (UI only)" }),
1909
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 text-sm text-ui-fg-subtle", children: [
1910
- "Color: ",
1911
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonColor }),
1912
- " · Shape:",
1913
- " ",
1914
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonShape }),
1915
- " · Width:",
1916
- " ",
1917
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonWidth }),
1918
- " · Height:",
1919
- " ",
1920
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-base", children: [
1921
- form.buttonHeight,
1922
- "px"
1923
- ] }),
1924
- " · Label:",
1925
- " ",
1926
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonLabel })
1927
- ] })
1928
- ] })
1929
- ]
1930
- }
1931
- )
1932
- ] }) });
1933
- }
1934
- function formatDate(value) {
1935
- if (!value) {
1936
- return "—";
1937
- }
1938
- const parsed = new Date(value);
1939
- if (Number.isNaN(parsed.getTime())) {
1940
- return value;
1941
- }
1942
- return parsed.toLocaleString();
1943
- }
1944
- function PayPalReconciliationStatusPage() {
1945
- const [status, setStatus] = react.useState({});
1946
- const [loading, setLoading] = react.useState(false);
1947
- const [error, setError] = react.useState(null);
1948
- const fetchStatus = react.useCallback(async () => {
1949
- try {
1950
- setLoading(true);
1951
- setError(null);
1952
- const response = await fetch("/admin/paypal/reconciliation-status", {
1953
- credentials: "include",
1954
- headers: {
1955
- Accept: "application/json"
1956
- }
1957
- });
1958
- if (!response.ok) {
1959
- const message = await response.text().catch(() => "");
1960
- throw new Error(message || "Failed to load reconciliation status.");
1539
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
1540
+ /* @__PURE__ */ jsxRuntime.jsx(
1541
+ FieldRow,
1542
+ {
1543
+ label: "Disable Specific Payment Buttons",
1544
+ hint: "Hide individual funding sources (ex: Card, Venmo).",
1545
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
1546
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
1547
+ filterHiddenDisableButtons(form.disableButtons).map((v) => {
1548
+ const opt = VISIBLE_DISABLE_BUTTON_OPTIONS.find((o) => o.value === v);
1549
+ return /* @__PURE__ */ jsxRuntime.jsx(Pill, { onRemove: () => removeMulti("disableButtons", v), children: (opt == null ? void 0 : opt.label) ?? v }, v);
1550
+ }),
1551
+ filterHiddenDisableButtons(form.disableButtons).length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "No buttons disabled." }) : null
1552
+ ] }),
1553
+ /* @__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: VISIBLE_DISABLE_BUTTON_OPTIONS.map((o) => {
1554
+ const checked = form.disableButtons.includes(o.value);
1555
+ return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 rounded-md p-2 hover:bg-ui-bg-subtle", children: [
1556
+ /* @__PURE__ */ jsxRuntime.jsx(
1557
+ "input",
1558
+ {
1559
+ type: "checkbox",
1560
+ checked,
1561
+ onChange: () => toggleMulti("disableButtons", o.value),
1562
+ className: "h-4 w-4 rounded border-ui-border-base"
1563
+ }
1564
+ ),
1565
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: o.label })
1566
+ ] }, o.value);
1567
+ }) }) })
1568
+ ] })
1569
+ }
1570
+ ),
1571
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Color", children: /* @__PURE__ */ jsxRuntime.jsx(
1572
+ "select",
1573
+ {
1574
+ value: form.buttonColor,
1575
+ onChange: (e) => setForm((p) => ({ ...p, buttonColor: e.target.value })),
1576
+ 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",
1577
+ children: COLOR_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1578
+ }
1579
+ ) }),
1580
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Shape", children: /* @__PURE__ */ jsxRuntime.jsx(
1581
+ "select",
1582
+ {
1583
+ value: form.buttonShape,
1584
+ onChange: (e) => setForm((p) => ({ ...p, buttonShape: e.target.value })),
1585
+ 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",
1586
+ children: SHAPE_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1587
+ }
1588
+ ) }),
1589
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Width", children: /* @__PURE__ */ jsxRuntime.jsx(
1590
+ "select",
1591
+ {
1592
+ value: form.buttonWidth,
1593
+ onChange: (e) => setForm((p) => ({ ...p, buttonWidth: e.target.value })),
1594
+ 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",
1595
+ children: WIDTH_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1596
+ }
1597
+ ) }),
1598
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Height", children: /* @__PURE__ */ jsxRuntime.jsx(
1599
+ "select",
1600
+ {
1601
+ value: String(form.buttonHeight),
1602
+ onChange: (e) => setForm((p) => ({ ...p, buttonHeight: Number(e.target.value) })),
1603
+ 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",
1604
+ children: HEIGHT_OPTIONS.map((h) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: h, children: [
1605
+ h,
1606
+ " px"
1607
+ ] }, h))
1608
+ }
1609
+ ) }),
1610
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Label", children: /* @__PURE__ */ jsxRuntime.jsx(
1611
+ "select",
1612
+ {
1613
+ value: form.buttonLabel,
1614
+ onChange: (e) => setForm((p) => ({ ...p, buttonLabel: e.target.value })),
1615
+ 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",
1616
+ children: LABEL_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1617
+ }
1618
+ ) })
1619
+ ] })
1961
1620
  }
1962
- const data = await response.json().catch(() => ({}));
1963
- setStatus((data == null ? void 0 : data.status) || {});
1964
- } catch (fetchError) {
1965
- setError((fetchError == null ? void 0 : fetchError.message) || "Failed to load reconciliation status.");
1966
- setStatus({});
1967
- } finally {
1968
- setLoading(false);
1969
- }
1970
- }, []);
1971
- react.useEffect(() => {
1972
- fetchStatus();
1973
- }, [fetchStatus]);
1974
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
1975
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1976
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Reconciliation Status" }),
1977
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-ui-fg-subtle", children: "Monitor reconciliation health and drift detection for PayPal payment sessions." })
1978
- ] }),
1979
- /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
1980
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
1981
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-ui-border-base p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4", children: [
1982
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: "Latest reconciliation run" }),
1983
- /* @__PURE__ */ jsxRuntime.jsx(
1984
- "button",
1985
- {
1986
- type: "button",
1987
- onClick: fetchStatus,
1988
- className: "rounded-md border border-ui-border-base px-3 py-2 text-sm text-ui-fg-base",
1989
- disabled: loading,
1990
- children: loading ? "Refreshing..." : "Refresh"
1991
- }
1992
- )
1993
- ] }) }),
1994
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
1995
- error ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-red-200 bg-red-50 p-3 text-sm text-red-600", children: error }) : null,
1996
- !error && Object.keys(status).length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-ui-fg-subtle", children: loading ? "Loading reconciliation status..." : "No reconciliation data yet." }) : null,
1997
- Object.keys(status).length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 text-sm text-ui-fg-base md:grid-cols-2", children: [
1998
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1999
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last run" }),
2000
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_run_at) })
2001
- ] }),
2002
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2003
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last run status" }),
2004
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium capitalize", children: status.last_run_status || "—" })
2005
- ] }),
2006
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2007
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last success" }),
2008
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_success_at) })
2009
- ] }),
2010
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2011
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last failure" }),
2012
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_failure_at) })
2013
- ] }),
2014
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2015
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Sessions checked" }),
2016
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.sessions_checked ?? 0 })
2017
- ] }),
2018
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2019
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Sessions updated" }),
2020
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.sessions_updated ?? 0 })
2021
- ] }),
2022
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2023
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Drift detections" }),
2024
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.drift_count ?? 0 })
2025
- ] }),
2026
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
2027
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last drift order" }),
2028
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.last_drift_order_id || "—" }),
2029
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: formatDate(status.last_drift_at) })
2030
- ] }),
2031
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3 md:col-span-2", children: [
2032
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last error" }),
2033
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.last_error || "No errors recorded." })
2034
- ] }),
2035
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3 md:col-span-2", children: [
2036
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Total runs" }),
2037
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.runs ?? 0 })
2038
- ] })
2039
- ] }) : null
1621
+ ),
1622
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 rounded-md border border-ui-border-base bg-ui-bg-subtle p-4", children: [
1623
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: "Preview (UI only)" }),
1624
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 text-sm text-ui-fg-subtle", children: [
1625
+ "Color: ",
1626
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonColor }),
1627
+ " · Shape:",
1628
+ " ",
1629
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonShape }),
1630
+ " · Width:",
1631
+ " ",
1632
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonWidth }),
1633
+ " · Height:",
1634
+ " ",
1635
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-base", children: [
1636
+ form.buttonHeight,
1637
+ "px"
1638
+ ] }),
1639
+ " · Label:",
1640
+ " ",
1641
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonLabel })
2040
1642
  ] })
2041
1643
  ] })
2042
1644
  ] }) });
@@ -2056,17 +1658,13 @@ const routeModule = {
2056
1658
  Component: AdvancedCardPaymentsTab,
2057
1659
  path: "/settings/paypal/advanced-card-payments"
2058
1660
  },
2059
- {
2060
- Component: PayPalAuditLogsPage,
2061
- path: "/settings/paypal/audit-logs"
2062
- },
2063
1661
  {
2064
1662
  Component: PayPalApplePayPage,
2065
1663
  path: "/settings/paypal/apple-pay"
2066
1664
  },
2067
1665
  {
2068
- Component: PayPalDisputesPage,
2069
- path: "/settings/paypal/disputes"
1666
+ Component: PayPalAuditLogsPage,
1667
+ path: "/settings/paypal/audit-logs"
2070
1668
  },
2071
1669
  {
2072
1670
  Component: PayPalConnectionPage,
@@ -2080,13 +1678,13 @@ const routeModule = {
2080
1678
  Component: PayPalPayLaterMessagingPage,
2081
1679
  path: "/settings/paypal/pay-later-messaging"
2082
1680
  },
2083
- {
2084
- Component: PayPalSettingsTab,
2085
- path: "/settings/paypal/paypal-settings"
2086
- },
2087
1681
  {
2088
1682
  Component: PayPalReconciliationStatusPage,
2089
1683
  path: "/settings/paypal/reconciliation-status"
1684
+ },
1685
+ {
1686
+ Component: PayPalSettingsTab,
1687
+ path: "/settings/paypal/paypal-settings"
2090
1688
  }
2091
1689
  ]
2092
1690
  };