@easypayment/medusa-paypal 0.2.6 → 0.2.8

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 (63) hide show
  1. package/.medusa/server/src/admin/index.js +689 -934
  2. package/.medusa/server/src/admin/index.mjs +689 -934
  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 +62 -74
  8. package/.medusa/server/src/api/store/paypal/capture-order/route.js.map +1 -1
  9. package/.medusa/server/src/api/store/paypal/config/route.d.ts.map +1 -1
  10. package/.medusa/server/src/api/store/paypal/config/route.js +9 -2
  11. package/.medusa/server/src/api/store/paypal/config/route.js.map +1 -1
  12. package/.medusa/server/src/api/store/paypal/create-order/route.d.ts.map +1 -1
  13. package/.medusa/server/src/api/store/paypal/create-order/route.js +3 -24
  14. package/.medusa/server/src/api/store/paypal/create-order/route.js.map +1 -1
  15. package/.medusa/server/src/api/store/paypal/settings/route.d.ts.map +1 -1
  16. package/.medusa/server/src/api/store/paypal/settings/route.js +7 -1
  17. package/.medusa/server/src/api/store/paypal/settings/route.js.map +1 -1
  18. package/.medusa/server/src/api/store/paypal-complete/route.d.ts +1 -8
  19. package/.medusa/server/src/api/store/paypal-complete/route.d.ts.map +1 -1
  20. package/.medusa/server/src/api/store/paypal-complete/route.js +47 -39
  21. package/.medusa/server/src/api/store/paypal-complete/route.js.map +1 -1
  22. package/.medusa/server/src/jobs/paypal-reconcile.d.ts.map +1 -1
  23. package/.medusa/server/src/jobs/paypal-reconcile.js +19 -5
  24. package/.medusa/server/src/jobs/paypal-reconcile.js.map +1 -1
  25. package/.medusa/server/src/modules/paypal/payment-provider/card-service.d.ts.map +1 -1
  26. package/.medusa/server/src/modules/paypal/payment-provider/card-service.js +54 -4
  27. package/.medusa/server/src/modules/paypal/payment-provider/card-service.js.map +1 -1
  28. package/.medusa/server/src/modules/paypal/payment-provider/service.d.ts +4 -1
  29. package/.medusa/server/src/modules/paypal/payment-provider/service.d.ts.map +1 -1
  30. package/.medusa/server/src/modules/paypal/payment-provider/service.js +35 -8
  31. package/.medusa/server/src/modules/paypal/payment-provider/service.js.map +1 -1
  32. package/.medusa/server/src/modules/paypal/service.d.ts +67 -61
  33. package/.medusa/server/src/modules/paypal/service.d.ts.map +1 -1
  34. package/.medusa/server/src/modules/paypal/service.js +34 -4
  35. package/.medusa/server/src/modules/paypal/service.js.map +1 -1
  36. package/.medusa/server/src/modules/paypal/utils/paypal-auth.d.ts +14 -0
  37. package/.medusa/server/src/modules/paypal/utils/paypal-auth.d.ts.map +1 -0
  38. package/.medusa/server/src/modules/paypal/utils/paypal-auth.js +32 -0
  39. package/.medusa/server/src/modules/paypal/utils/paypal-auth.js.map +1 -0
  40. package/.medusa/server/src/modules/paypal/webhook-processor.d.ts +9 -9
  41. package/.medusa/server/src/modules/paypal/webhook-processor.d.ts.map +1 -1
  42. package/.medusa/server/src/modules/paypal/webhook-processor.js +20 -7
  43. package/.medusa/server/src/modules/paypal/webhook-processor.js.map +1 -1
  44. package/package.json +1 -1
  45. package/src/admin/routes/settings/paypal/additional-settings/page.tsx +226 -346
  46. package/src/admin/routes/settings/paypal/advanced-card-payments/page.tsx +227 -381
  47. package/src/admin/routes/settings/paypal/audit-logs/page.tsx +127 -131
  48. package/src/admin/routes/settings/paypal/disputes/page.tsx +186 -259
  49. package/src/admin/routes/settings/paypal/paypal-settings/page.tsx +599 -557
  50. package/src/admin/routes/settings/paypal/reconciliation-status/page.tsx +120 -165
  51. package/src/api/store/payment-collections/[id]/payment-sessions/route.ts +12 -1
  52. package/src/api/store/paypal/capture-order/route.ts +276 -284
  53. package/src/api/store/paypal/config/route.ts +12 -8
  54. package/src/api/store/paypal/create-order/route.ts +2 -32
  55. package/src/api/store/paypal/settings/route.ts +8 -1
  56. package/src/api/store/paypal-complete/route.ts +76 -65
  57. package/src/jobs/paypal-reconcile.ts +21 -6
  58. package/src/modules/paypal/payment-provider/card-service.ts +54 -4
  59. package/src/modules/paypal/payment-provider/service.ts +47 -20
  60. package/src/modules/paypal/service.ts +39 -4
  61. package/src/modules/paypal/utils/paypal-auth.ts +32 -0
  62. package/src/modules/paypal/webhook-processor.ts +22 -8
  63. package/tsconfig.json +1 -1
@@ -40,6 +40,39 @@ function PayPalTabs() {
40
40
  );
41
41
  }) }) });
42
42
  }
43
+ async function adminFetch$5(path, opts = {}) {
44
+ var _a;
45
+ const { method = "GET", body, query } = opts;
46
+ let url = path;
47
+ if (query && Object.keys(query).length > 0) {
48
+ const params = new URLSearchParams(query);
49
+ url = `${path}?${params.toString()}`;
50
+ }
51
+ const headers = { Accept: "application/json" };
52
+ if (body !== void 0) headers["Content-Type"] = "application/json";
53
+ if (typeof window !== "undefined") {
54
+ const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
55
+ if (token) headers["Authorization"] = `Bearer ${token}`;
56
+ }
57
+ const res = await fetch(url, {
58
+ method,
59
+ headers,
60
+ credentials: "include",
61
+ body: body !== void 0 ? JSON.stringify(body) : void 0
62
+ });
63
+ const text = await res.text().catch(() => "");
64
+ if (!res.ok) {
65
+ if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
66
+ if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
67
+ throw new Error(text || `Request failed with status ${res.status}`);
68
+ }
69
+ if (!text) return {};
70
+ try {
71
+ return JSON.parse(text);
72
+ } catch {
73
+ return {};
74
+ }
75
+ }
43
76
  const DEFAULT_FORM$1 = {
44
77
  paymentAction: "capture",
45
78
  brandName: "PayPal",
@@ -56,17 +89,9 @@ const DEFAULT_FORM$1 = {
56
89
  function mergeWithDefaults$1(saved) {
57
90
  if (!saved) return { ...DEFAULT_FORM$1 };
58
91
  const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
59
- return {
60
- ...DEFAULT_FORM$1,
61
- ...Object.fromEntries(entries)
62
- };
92
+ return { ...DEFAULT_FORM$1, ...Object.fromEntries(entries) };
63
93
  }
64
- function SectionCard$2({
65
- title,
66
- description,
67
- right,
68
- children
69
- }) {
94
+ function SectionCard$2({ title, description, right, children }) {
70
95
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
71
96
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
72
97
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
@@ -78,11 +103,7 @@ function SectionCard$2({
78
103
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children })
79
104
  ] });
80
105
  }
81
- function FieldRow$2({
82
- label,
83
- hint,
84
- children
85
- }) {
106
+ function FieldRow$2({ label, hint, children }) {
86
107
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
87
108
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 md:col-span-4", children: [
88
109
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
@@ -95,6 +116,7 @@ function AdditionalSettingsTab() {
95
116
  const [form, setForm] = react.useState(() => ({ ...DEFAULT_FORM$1 }));
96
117
  const [loading, setLoading] = react.useState(false);
97
118
  const [saving, setSaving] = react.useState(false);
119
+ const [toast, setToast] = react.useState(null);
98
120
  const didInit = react.useRef(false);
99
121
  react.useEffect(() => {
100
122
  if (didInit.current) return;
@@ -102,52 +124,28 @@ function AdditionalSettingsTab() {
102
124
  (async () => {
103
125
  try {
104
126
  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();
127
+ const json = await adminFetch$5("/admin/paypal/settings");
111
128
  const payload = (json == null ? void 0 : json.data) ?? json;
112
129
  const saved = payload == null ? void 0 : payload.additional_settings;
113
- if (saved && typeof saved === "object") {
114
- setForm(mergeWithDefaults$1(saved));
115
- }
130
+ if (saved && typeof saved === "object") setForm(mergeWithDefaults$1(saved));
131
+ } catch {
116
132
  } finally {
117
133
  setLoading(false);
118
134
  }
119
135
  })();
120
136
  }, []);
121
- const [toast, setToast] = react.useState(null);
122
137
  async function onSave() {
123
138
  try {
124
139
  setSaving(true);
125
140
  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(() => ({}));
141
+ const json = await adminFetch$5("/admin/paypal/settings", { method: "POST", body: { additional_settings: form } });
142
142
  const payload = (json == null ? void 0 : json.data) ?? json;
143
143
  const saved = payload == null ? void 0 : payload.additional_settings;
144
- if (saved && typeof saved === "object") {
145
- setForm(mergeWithDefaults$1(saved));
146
- }
144
+ if (saved && typeof saved === "object") setForm(mergeWithDefaults$1(saved));
147
145
  setToast({ type: "success", message: "Settings saved" });
148
146
  window.setTimeout(() => setToast(null), 2500);
149
147
  } catch (e) {
150
- setToast({ type: "error", message: (e == null ? void 0 : e.message) || "Failed to save settings" });
148
+ setToast({ type: "error", message: e instanceof Error ? e.message : "Failed to save settings" });
151
149
  window.setTimeout(() => setToast(null), 3500);
152
150
  } finally {
153
151
  setSaving(false);
@@ -156,181 +154,226 @@ function AdditionalSettingsTab() {
156
154
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
157
155
  /* @__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
156
  /* @__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,
157
+ 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
158
  /* @__PURE__ */ jsxRuntime.jsx(
169
159
  SectionCard$2,
170
160
  {
171
161
  title: "Additional Settings",
172
162
  description: "These settings control checkout behavior, PayPal experience, and logging.",
173
163
  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
164
+ /* @__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" }),
165
+ loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading..." }) : null
185
166
  ] }),
186
167
  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
- ) }),
168
+ /* @__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: [
169
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "capture", children: "Capture" }),
170
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "authorize", children: "Authorize" })
171
+ ] }) }),
172
+ /* @__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" }) }),
173
+ /* @__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: [
174
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "no_preference", children: "No Preference" }),
175
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "login", children: "Login" }),
176
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "billing", children: "Billing" })
177
+ ] }) }),
221
178
  /* @__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
- ),
179
+ /* @__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
180
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Require Instant Payment" })
232
181
  ] }) }),
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
- )
182
+ /* @__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: [
183
+ /* @__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" }),
184
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Use PayPal Shipping Address as Billing" })
185
+ ] }) }),
186
+ /* @__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: [
187
+ /* @__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" }),
188
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Send line item details to PayPal" })
189
+ ] }) }),
190
+ /* @__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: [
191
+ /* @__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" }),
192
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Skip Order Review Page" })
193
+ ] }) }),
194
+ /* @__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-" }) }),
195
+ /* @__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" }) }),
196
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Debug log", hint: /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
197
+ "Log PayPal events such as Webhook, Payment, Refund. ",
198
+ form.logPath ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
199
+ "Log location: ",
200
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: form.logPath })
201
+ ] }) : null
202
+ ] }), children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
203
+ /* @__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" }),
204
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable logging" })
205
+ ] }) })
206
+ ] })
207
+ }
208
+ )
209
+ ] }) });
210
+ }
211
+ async function adminFetch$4(path, opts = {}) {
212
+ var _a;
213
+ const { method = "GET", body, query } = opts;
214
+ let url = path;
215
+ if (query && Object.keys(query).length > 0) {
216
+ const params = new URLSearchParams(query);
217
+ url = `${path}?${params.toString()}`;
218
+ }
219
+ const headers = { Accept: "application/json" };
220
+ if (body !== void 0) headers["Content-Type"] = "application/json";
221
+ if (typeof window !== "undefined") {
222
+ const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
223
+ if (token) headers["Authorization"] = `Bearer ${token}`;
224
+ }
225
+ const res = await fetch(url, {
226
+ method,
227
+ headers,
228
+ credentials: "include",
229
+ body: body !== void 0 ? JSON.stringify(body) : void 0
230
+ });
231
+ const text = await res.text().catch(() => "");
232
+ if (!res.ok) {
233
+ if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
234
+ if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
235
+ throw new Error(text || `Request failed with status ${res.status}`);
236
+ }
237
+ if (!text) return {};
238
+ try {
239
+ return JSON.parse(text);
240
+ } catch {
241
+ return {};
242
+ }
243
+ }
244
+ const DEFAULT_FORM = { enabled: true, title: "Credit or Debit Card", disabledCards: [], threeDS: "when_required", cardSaveEnabled: false };
245
+ function mergeWithDefaults(saved) {
246
+ if (!saved) return { ...DEFAULT_FORM };
247
+ const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
248
+ return { ...DEFAULT_FORM, ...Object.fromEntries(entries) };
249
+ }
250
+ const CARD_BRANDS = [
251
+ { value: "visa", label: "Visa" },
252
+ { value: "mastercard", label: "Mastercard" },
253
+ { value: "amex", label: "American Express" },
254
+ { value: "discover", label: "Discover" },
255
+ { value: "diners", label: "Diners Club" },
256
+ { value: "jcb", label: "JCB" },
257
+ { value: "unionpay", label: "UnionPay" }
258
+ ];
259
+ const THREE_DS_OPTIONS = [
260
+ { value: "when_required", label: "3D Secure when required", hint: "Triggers 3DS only when the card / issuer requires it." },
261
+ { value: "sli", label: "3D Secure (SCA) / liability shift (recommended)", hint: "Attempts to optimize for liability shift while remaining compliant." },
262
+ { value: "always", label: "Always request 3D Secure", hint: "Forces 3DS challenge whenever possible (may reduce conversion)." }
263
+ ];
264
+ function Pill$1({ children, onRemove }) {
265
+ 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: [
266
+ children,
267
+ 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
268
+ ] });
269
+ }
270
+ function SectionCard$1({ title, description, right, children }) {
271
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
272
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
273
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
274
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: title }),
275
+ description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-sm text-ui-fg-subtle", children: description }) : null
276
+ ] }),
277
+ right
278
+ ] }),
279
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children })
280
+ ] });
281
+ }
282
+ function FieldRow$1({ label, hint, children }) {
283
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
284
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 md:col-span-4", children: [
285
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
286
+ hint ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: hint }) : null
287
+ ] }),
288
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-12 md:col-span-8", children })
289
+ ] });
290
+ }
291
+ function AdvancedCardPaymentsTab() {
292
+ var _a, _b;
293
+ const [form, setForm] = react.useState(() => ({ ...DEFAULT_FORM }));
294
+ const [loading, setLoading] = react.useState(false);
295
+ const [saving, setSaving] = react.useState(false);
296
+ const [toast, setToast] = react.useState(null);
297
+ const didInit = react.useRef(false);
298
+ react.useEffect(() => {
299
+ if (didInit.current) return;
300
+ didInit.current = true;
301
+ (async () => {
302
+ try {
303
+ setLoading(true);
304
+ const json = await adminFetch$4("/admin/paypal/settings");
305
+ const payload = (json == null ? void 0 : json.data) ?? json;
306
+ const saved = payload == null ? void 0 : payload.advanced_card_payments;
307
+ if (saved && typeof saved === "object") setForm(mergeWithDefaults(saved));
308
+ } catch {
309
+ } finally {
310
+ setLoading(false);
311
+ }
312
+ })();
313
+ }, []);
314
+ async function onSave() {
315
+ try {
316
+ setSaving(true);
317
+ const json = await adminFetch$4("/admin/paypal/settings", { method: "POST", body: { advanced_card_payments: form } });
318
+ const payload = (json == null ? void 0 : json.data) ?? json;
319
+ const saved = payload == null ? void 0 : payload.advanced_card_payments;
320
+ if (saved && typeof saved === "object") setForm(mergeWithDefaults(saved));
321
+ setToast({ type: "success", message: "Settings saved" });
322
+ window.setTimeout(() => setToast(null), 2500);
323
+ } catch (e) {
324
+ setToast({ type: "error", message: (e instanceof Error ? e.message : "") || "Failed to save settings." });
325
+ window.setTimeout(() => setToast(null), 3500);
326
+ } finally {
327
+ setSaving(false);
328
+ }
329
+ }
330
+ const disabledSet = react.useMemo(() => new Set(form.disabledCards), [form.disabledCards]);
331
+ function toggleDisabledCard(value) {
332
+ setForm((prev) => {
333
+ const exists = prev.disabledCards.includes(value);
334
+ return { ...prev, disabledCards: exists ? prev.disabledCards.filter((v) => v !== value) : [...prev.disabledCards, value] };
335
+ });
336
+ }
337
+ function removeDisabledCard(value) {
338
+ setForm((prev) => ({ ...prev, disabledCards: prev.disabledCards.filter((v) => v !== value) }));
339
+ }
340
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
341
+ /* @__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" }) }) }),
342
+ /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
343
+ 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,
344
+ /* @__PURE__ */ jsxRuntime.jsx(
345
+ SectionCard$1,
346
+ {
347
+ title: "Advanced Card Payments",
348
+ description: "Control card checkout settings, 3D Secure behavior, and card saving.",
349
+ right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
350
+ /* @__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" }),
351
+ loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading..." }) : null
352
+ ] }),
353
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
354
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Enable/Disable", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
355
+ /* @__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" }),
356
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable Advanced Credit/Debit Card" })
357
+ ] }) }),
358
+ /* @__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" }) }),
359
+ /* @__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: [
360
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: form.disabledCards.length ? form.disabledCards.map((v) => {
361
+ var _a2;
362
+ 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);
363
+ }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "No card brands disabled." }) }),
364
+ /* @__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: [
365
+ /* @__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" }),
366
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: b.label })
367
+ ] }, b.value)) }) })
368
+ ] }) }),
369
+ /* @__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: [
370
+ /* @__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)) }),
371
+ ((_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
372
+ ] }) }),
373
+ /* @__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: [
374
+ /* @__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" }),
375
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable card saving at checkout" })
376
+ ] }) })
334
377
  ] })
335
378
  }
336
379
  )
@@ -923,308 +966,195 @@ function PayPalConnectionPage() {
923
966
  ` })
924
967
  ] });
925
968
  }
926
- const DEFAULT_FORM = {
927
- enabled: true,
928
- title: "Credit or Debit Card",
929
- disabledCards: [],
930
- threeDS: "when_required",
931
- cardSaveEnabled: false
932
- };
933
- function mergeWithDefaults(saved) {
934
- if (!saved) return { ...DEFAULT_FORM };
935
- const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
936
- return {
937
- ...DEFAULT_FORM,
938
- ...Object.fromEntries(entries)
939
- };
940
- }
941
- const CARD_BRANDS = [
942
- { value: "visa", label: "Visa" },
943
- { value: "mastercard", label: "Mastercard" },
944
- { value: "amex", label: "American Express" },
945
- { value: "discover", label: "Discover" },
946
- { value: "diners", label: "Diners Club" },
947
- { value: "jcb", label: "JCB" },
948
- { value: "unionpay", label: "UnionPay" }
949
- ];
950
- const THREE_DS_OPTIONS = [
951
- {
952
- value: "when_required",
953
- label: "3D Secure when required",
954
- hint: "Triggers 3DS only when the card / issuer requires it."
955
- },
956
- {
957
- value: "sli",
958
- label: "3D Secure (SCA) / liability shift (recommended)",
959
- hint: "Attempts to optimize for liability shift while remaining compliant."
960
- },
961
- {
962
- value: "always",
963
- label: "Always request 3D Secure",
964
- hint: "Forces 3DS challenge whenever possible (may reduce conversion)."
969
+ async function adminFetch$3(path, opts = {}) {
970
+ var _a;
971
+ const { method = "GET", body, query } = opts;
972
+ let url = path;
973
+ if (query && Object.keys(query).length > 0) {
974
+ const params = new URLSearchParams(query);
975
+ url = `${path}?${params.toString()}`;
976
+ }
977
+ const headers = { Accept: "application/json" };
978
+ if (body !== void 0) headers["Content-Type"] = "application/json";
979
+ if (typeof window !== "undefined") {
980
+ const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
981
+ if (token) headers["Authorization"] = `Bearer ${token}`;
982
+ }
983
+ const res = await fetch(url, {
984
+ method,
985
+ headers,
986
+ credentials: "include",
987
+ body: body !== void 0 ? JSON.stringify(body) : void 0
988
+ });
989
+ const text = await res.text().catch(() => "");
990
+ if (!res.ok) {
991
+ if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
992
+ if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
993
+ throw new Error(text || `Request failed with status ${res.status}`);
994
+ }
995
+ if (!text) return {};
996
+ try {
997
+ return JSON.parse(text);
998
+ } catch {
999
+ return {};
965
1000
  }
966
- ];
967
- function cx$1(...parts) {
968
- return parts.filter(Boolean).join(" ");
969
- }
970
- function Pill$1({
971
- children,
972
- onRemove
973
- }) {
974
- 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: [
975
- children,
976
- onRemove ? /* @__PURE__ */ jsxRuntime.jsx(
977
- "button",
978
- {
979
- type: "button",
980
- onClick: onRemove,
981
- className: "ml-1 rounded px-1 text-ui-fg-subtle hover:text-ui-fg-base",
982
- "aria-label": "Remove",
983
- children: "×"
984
- }
985
- ) : null
986
- ] });
987
1001
  }
988
- function SectionCard$1({
989
- title,
990
- description,
991
- right,
992
- children
993
- }) {
994
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
995
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
996
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
997
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: title }),
998
- description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-sm text-ui-fg-subtle", children: description }) : null
999
- ] }),
1000
- right
1001
- ] }),
1002
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children })
1003
- ] });
1004
- }
1005
- function FieldRow$1({
1006
- label,
1007
- hint,
1008
- children
1009
- }) {
1010
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
1011
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 md:col-span-4", children: [
1012
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
1013
- hint ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: hint }) : null
1014
- ] }),
1015
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-12 md:col-span-8", children })
1016
- ] });
1002
+ const EMPTY_FILTERS = { dispute_id: "", status: "", order_id: "", cart_id: "" };
1003
+ function formatDate$2(value) {
1004
+ if (!value) return "";
1005
+ const parsed = new Date(value);
1006
+ if (Number.isNaN(parsed.getTime())) return value;
1007
+ return parsed.toLocaleString();
1017
1008
  }
1018
- function AdvancedCardPaymentsTab() {
1019
- var _a, _b;
1020
- const [form, setForm] = react.useState(() => ({ ...DEFAULT_FORM }));
1009
+ function PayPalDisputesPage() {
1010
+ const [filters, setFilters] = react.useState({ ...EMPTY_FILTERS });
1011
+ const [disputes, setDisputes] = react.useState([]);
1021
1012
  const [loading, setLoading] = react.useState(false);
1022
- const [saving, setSaving] = react.useState(false);
1023
- const [toast, setToast] = react.useState(null);
1024
- const didInit = react.useRef(false);
1025
- react.useEffect(() => {
1026
- if (didInit.current) return;
1027
- didInit.current = true;
1028
- (async () => {
1029
- try {
1030
- setLoading(true);
1031
- const r = await fetch("/admin/paypal/settings", {
1032
- credentials: "include",
1033
- headers: { "Accept": "application/json" }
1034
- });
1035
- if (!r.ok) return;
1036
- const json = await r.json();
1037
- const payload = (json == null ? void 0 : json.data) ?? json;
1038
- const saved = payload == null ? void 0 : payload.advanced_card_payments;
1039
- if (saved && typeof saved === "object") {
1040
- setForm(mergeWithDefaults(saved));
1041
- }
1042
- } finally {
1043
- setLoading(false);
1044
- }
1045
- })();
1046
- }, []);
1047
- async function onSave() {
1013
+ const [error, setError] = react.useState(null);
1014
+ const queryString = react.useMemo(() => {
1015
+ const params = new URLSearchParams();
1016
+ Object.entries(filters).forEach(([key, value]) => {
1017
+ if (value.trim()) params.set(key, value.trim());
1018
+ });
1019
+ const qs = params.toString();
1020
+ return qs ? `?${qs}` : "";
1021
+ }, [filters]);
1022
+ const fetchDisputes = react.useCallback(async (source) => {
1048
1023
  try {
1049
- setSaving(true);
1050
- const r = await fetch("/admin/paypal/settings", {
1051
- method: "POST",
1052
- credentials: "include",
1053
- headers: {
1054
- "Content-Type": "application/json",
1055
- "Accept": "application/json"
1056
- },
1057
- body: JSON.stringify({ advanced_card_payments: form })
1024
+ setLoading(true);
1025
+ setError(null);
1026
+ const query = {};
1027
+ Object.entries(source).forEach(([key, value]) => {
1028
+ if (value.trim()) query[key] = value.trim();
1058
1029
  });
1059
- if (!r.ok) {
1060
- const t = await r.text();
1061
- setToast({ type: "error", message: "Failed to save settings. " + t });
1062
- window.setTimeout(() => setToast(null), 3500);
1063
- return;
1064
- }
1065
- const json = await r.json().catch(() => null);
1066
- const payload = (json == null ? void 0 : json.data) ?? json;
1067
- const saved = payload == null ? void 0 : payload.advanced_card_payments;
1068
- if (saved && typeof saved === "object") {
1069
- setForm(mergeWithDefaults(saved));
1070
- }
1071
- setToast({ type: "success", message: "Settings saved" });
1072
- window.setTimeout(() => setToast(null), 2500);
1030
+ const json = await adminFetch$3("/admin/paypal/disputes", { query });
1031
+ setDisputes((json == null ? void 0 : json.disputes) ?? []);
1032
+ } catch (fetchError) {
1033
+ setError(fetchError instanceof Error ? fetchError.message : "Failed to load disputes");
1034
+ setDisputes([]);
1073
1035
  } finally {
1074
- setSaving(false);
1036
+ setLoading(false);
1075
1037
  }
1076
- }
1077
- const disabledSet = react.useMemo(() => new Set(form.disabledCards), [form.disabledCards]);
1078
- function toggleDisabledCard(value) {
1079
- setForm((prev) => {
1080
- const exists = prev.disabledCards.includes(value);
1081
- return {
1082
- ...prev,
1083
- disabledCards: exists ? prev.disabledCards.filter((v) => v !== value) : [...prev.disabledCards, value]
1084
- };
1085
- });
1086
- }
1087
- function removeDisabledCard(value) {
1088
- setForm((prev) => ({
1089
- ...prev,
1090
- disabledCards: prev.disabledCards.filter((v) => v !== value)
1091
- }));
1092
- }
1038
+ }, []);
1039
+ react.useEffect(() => {
1040
+ fetchDisputes(EMPTY_FILTERS);
1041
+ }, [fetchDisputes]);
1042
+ const onSubmit = (event) => {
1043
+ event.preventDefault();
1044
+ fetchDisputes(filters);
1045
+ };
1046
+ const onReset = () => {
1047
+ setFilters({ ...EMPTY_FILTERS });
1048
+ fetchDisputes(EMPTY_FILTERS);
1049
+ };
1093
1050
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
1094
- /* @__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" }) }) }),
1051
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1052
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Disputes" }),
1053
+ /* @__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." })
1054
+ ] }),
1095
1055
  /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
1096
- toast ? /* @__PURE__ */ jsxRuntime.jsx(
1097
- "div",
1098
- {
1099
- 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",
1100
- role: "status",
1101
- "aria-live": "polite",
1102
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: toast.type === "success" ? "text-ui-fg-base" : "text-ui-fg-error", children: toast.message })
1103
- }
1104
- ) : null,
1105
- /* @__PURE__ */ jsxRuntime.jsx(
1106
- SectionCard$1,
1107
- {
1108
- title: "Advanced Card Payments",
1109
- description: "Control card checkout settings, 3D Secure behavior, and card saving.",
1110
- right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
1111
- /* @__PURE__ */ jsxRuntime.jsx(
1112
- "button",
1113
- {
1114
- type: "button",
1115
- onClick: onSave,
1116
- disabled: saving || loading,
1117
- 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",
1118
- children: saving ? "Saving..." : "Save settings"
1119
- }
1120
- ),
1121
- loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading…" }) : null
1056
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
1057
+ /* @__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" }) }),
1058
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit, className: "flex flex-col gap-4", children: [
1059
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-4", children: [
1060
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
1061
+ "Dispute ID",
1062
+ /* @__PURE__ */ jsxRuntime.jsx("input", { className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base", value: filters.dispute_id, onChange: (e) => setFilters((p) => ({ ...p, dispute_id: e.target.value })), placeholder: "PP-D-123" })
1063
+ ] }),
1064
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
1065
+ "Status",
1066
+ /* @__PURE__ */ jsxRuntime.jsx("input", { className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base", value: filters.status, onChange: (e) => setFilters((p) => ({ ...p, status: e.target.value })), placeholder: "OPEN" })
1067
+ ] }),
1068
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
1069
+ "Order ID",
1070
+ /* @__PURE__ */ jsxRuntime.jsx("input", { className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base", value: filters.order_id, onChange: (e) => setFilters((p) => ({ ...p, order_id: e.target.value })), placeholder: "order_..." })
1071
+ ] }),
1072
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
1073
+ "Cart ID",
1074
+ /* @__PURE__ */ jsxRuntime.jsx("input", { className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base", value: filters.cart_id, onChange: (e) => setFilters((p) => ({ ...p, cart_id: e.target.value })), placeholder: "cart_..." })
1075
+ ] })
1122
1076
  ] }),
1123
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
1124
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Enable/Disable", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
1125
- /* @__PURE__ */ jsxRuntime.jsx(
1126
- "input",
1127
- {
1128
- type: "checkbox",
1129
- checked: form.enabled,
1130
- onChange: (e) => setForm((p) => ({ ...p, enabled: e.target.checked })),
1131
- className: "h-4 w-4 rounded border-ui-border-base"
1132
- }
1133
- ),
1134
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable Advanced Credit/Debit Card" })
1135
- ] }) }),
1136
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Title", children: /* @__PURE__ */ jsxRuntime.jsx(
1137
- "input",
1138
- {
1139
- value: form.title,
1140
- onChange: (e) => setForm((p) => ({ ...p, title: e.target.value })),
1141
- 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",
1142
- placeholder: "Credit or Debit Card"
1143
- }
1144
- ) }),
1145
- /* @__PURE__ */ jsxRuntime.jsx(
1146
- FieldRow$1,
1147
- {
1148
- label: "Disable specific credit cards",
1149
- hint: "Select card brands to hide from the card form.",
1150
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
1151
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: form.disabledCards.length ? form.disabledCards.map((v) => {
1152
- var _a2;
1153
- const label = ((_a2 = CARD_BRANDS.find((b) => b.value === v)) == null ? void 0 : _a2.label) ?? v;
1154
- return /* @__PURE__ */ jsxRuntime.jsx(Pill$1, { onRemove: () => removeDisabledCard(v), children: label }, v);
1155
- }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "No card brands disabled." }) }),
1156
- /* @__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) => {
1157
- const checked = disabledSet.has(b.value);
1158
- return /* @__PURE__ */ jsxRuntime.jsxs(
1159
- "label",
1160
- {
1161
- className: cx$1(
1162
- "flex items-center gap-2 rounded-md p-2",
1163
- "hover:bg-ui-bg-subtle"
1164
- ),
1165
- children: [
1166
- /* @__PURE__ */ jsxRuntime.jsx(
1167
- "input",
1168
- {
1169
- type: "checkbox",
1170
- checked,
1171
- onChange: () => toggleDisabledCard(b.value),
1172
- className: "h-4 w-4 rounded border-ui-border-base"
1173
- }
1174
- ),
1175
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: b.label })
1176
- ]
1177
- },
1178
- b.value
1179
- );
1180
- }) }) })
1181
- ] })
1182
- }
1183
- ),
1184
- /* @__PURE__ */ jsxRuntime.jsx(
1185
- FieldRow$1,
1186
- {
1187
- label: "Contingency for 3D Secure",
1188
- hint: "Choose when 3D Secure should be triggered during card payments.",
1189
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
1190
- /* @__PURE__ */ jsxRuntime.jsx(
1191
- "select",
1192
- {
1193
- value: form.threeDS,
1194
- onChange: (e) => setForm((p) => ({ ...p, threeDS: e.target.value })),
1195
- 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",
1196
- children: THREE_DS_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1197
- }
1198
- ),
1199
- ((_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
1200
- ] })
1201
- }
1202
- ),
1203
- /* @__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: [
1204
- /* @__PURE__ */ jsxRuntime.jsx(
1205
- "input",
1206
- {
1207
- type: "checkbox",
1208
- checked: form.cardSaveEnabled,
1209
- onChange: (e) => setForm((p) => ({ ...p, cardSaveEnabled: e.target.checked })),
1210
- className: "h-4 w-4 rounded border-ui-border-base"
1211
- }
1212
- ),
1213
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable card saving at checkout" })
1214
- ] }) })
1077
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-3", children: [
1078
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", className: "rounded-md bg-ui-fg-base px-4 py-2 text-sm font-medium text-ui-bg-base", disabled: loading, children: loading ? "Loading..." : "Apply filters" }),
1079
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "rounded-md border border-ui-border-base px-4 py-2 text-sm text-ui-fg-base", onClick: onReset, disabled: loading, children: "Reset" }),
1080
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-ui-fg-subtle", children: [
1081
+ "Showing ",
1082
+ disputes.length,
1083
+ " dispute",
1084
+ disputes.length === 1 ? "" : "s",
1085
+ queryString ? " (filtered)" : ""
1086
+ ] })
1215
1087
  ] })
1216
- }
1217
- )
1088
+ ] }) })
1089
+ ] }),
1090
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
1091
+ /* @__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" }) }),
1092
+ /* @__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: [
1093
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "text-left text-ui-fg-subtle", children: [
1094
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Dispute" }),
1095
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Status" }),
1096
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Reason" }),
1097
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Stage" }),
1098
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Amount" }),
1099
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Order" }),
1100
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Cart" }),
1101
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Updated" })
1102
+ ] }) }),
1103
+ /* @__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: [
1104
+ /* @__PURE__ */ jsxRuntime.jsxs("td", { className: "px-4 py-3", children: [
1105
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-ui-fg-base", children: dispute.dispute_id }),
1106
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-ui-fg-subtle", children: dispute.transaction_id || "No transaction" })
1107
+ ] }),
1108
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.status || "Unknown" }),
1109
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.reason || "-" }),
1110
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.stage || "-" }),
1111
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.amount ? `${dispute.amount} ${dispute.currency_code || ""}` : "-" }),
1112
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.order_id || "-" }),
1113
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.cart_id || "-" }),
1114
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 text-ui-fg-subtle", children: formatDate$2(dispute.updated_at || dispute.created_at) })
1115
+ ] }, dispute.id)) })
1116
+ ] }) }),
1117
+ 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
1118
+ ] })
1218
1119
  ] }) });
1219
1120
  }
1220
- function formatDate$2(value) {
1221
- if (!value) {
1222
- return "";
1121
+ async function adminFetch$2(path, opts = {}) {
1122
+ var _a;
1123
+ const { method = "GET", body, query } = opts;
1124
+ let url = path;
1125
+ if (query && Object.keys(query).length > 0) {
1126
+ const params = new URLSearchParams(query);
1127
+ url = `${path}?${params.toString()}`;
1223
1128
  }
1224
- const parsed = new Date(value);
1225
- if (Number.isNaN(parsed.getTime())) {
1226
- return value;
1129
+ const headers = { Accept: "application/json" };
1130
+ if (body !== void 0) headers["Content-Type"] = "application/json";
1131
+ if (typeof window !== "undefined") {
1132
+ const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
1133
+ if (token) headers["Authorization"] = `Bearer ${token}`;
1134
+ }
1135
+ const res = await fetch(url, {
1136
+ method,
1137
+ headers,
1138
+ credentials: "include",
1139
+ body: body !== void 0 ? JSON.stringify(body) : void 0
1140
+ });
1141
+ const text = await res.text().catch(() => "");
1142
+ if (!res.ok) {
1143
+ if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
1144
+ if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
1145
+ throw new Error(text || `Request failed with status ${res.status}`);
1227
1146
  }
1147
+ if (!text) return {};
1148
+ try {
1149
+ return JSON.parse(text);
1150
+ } catch {
1151
+ return {};
1152
+ }
1153
+ }
1154
+ function formatDate$1(value) {
1155
+ if (!value) return "";
1156
+ const parsed = new Date(value);
1157
+ if (Number.isNaN(parsed.getTime())) return value;
1228
1158
  return parsed.toLocaleString();
1229
1159
  }
1230
1160
  function PayPalAuditLogsPage() {
@@ -1235,20 +1165,10 @@ function PayPalAuditLogsPage() {
1235
1165
  try {
1236
1166
  setLoading(true);
1237
1167
  setError(null);
1238
- const response = await fetch("/admin/paypal/audit-logs?limit=50", {
1239
- credentials: "include",
1240
- headers: {
1241
- Accept: "application/json"
1242
- }
1243
- });
1244
- if (!response.ok) {
1245
- const message = await response.text().catch(() => "");
1246
- throw new Error(message || "Failed to load audit logs.");
1247
- }
1248
- const data = await response.json().catch(() => ({}));
1249
- setLogs((data == null ? void 0 : data.logs) || []);
1168
+ const data = await adminFetch$2("/admin/paypal/audit-logs", { query: { limit: "50" } });
1169
+ setLogs((data == null ? void 0 : data.logs) ?? []);
1250
1170
  } catch (fetchError) {
1251
- setError((fetchError == null ? void 0 : fetchError.message) || "Failed to load audit logs.");
1171
+ setError(fetchError instanceof Error ? fetchError.message : "Failed to load audit logs.");
1252
1172
  setLogs([]);
1253
1173
  } finally {
1254
1174
  setLoading(false);
@@ -1266,16 +1186,7 @@ function PayPalAuditLogsPage() {
1266
1186
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
1267
1187
  /* @__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: [
1268
1188
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: "Latest events" }),
1269
- /* @__PURE__ */ jsxRuntime.jsx(
1270
- "button",
1271
- {
1272
- type: "button",
1273
- onClick: fetchLogs,
1274
- className: "rounded-md border border-ui-border-base px-3 py-2 text-sm text-ui-fg-base",
1275
- disabled: loading,
1276
- children: loading ? "Refreshing..." : "Refresh"
1277
- }
1278
- )
1189
+ /* @__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" })
1279
1190
  ] }) }),
1280
1191
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
1281
1192
  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,
@@ -1287,7 +1198,7 @@ function PayPalAuditLogsPage() {
1287
1198
  /* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 font-medium", children: "Details" })
1288
1199
  ] }) }),
1289
1200
  /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: logs.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-t border-ui-border-base", children: [
1290
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: formatDate$2(entry.created_at) || "—" }),
1201
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: formatDate$1(entry.created_at) || "—" }),
1291
1202
  /* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: entry.event_type || "—" }),
1292
1203
  /* @__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) }) })
1293
1204
  ] }, entry.id)) })
@@ -1299,200 +1210,161 @@ function PayPalAuditLogsPage() {
1299
1210
  function PayPalGooglePayPage() {
1300
1211
  return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1301
1212
  }
1302
- const EMPTY_FILTERS = {
1303
- dispute_id: "",
1304
- status: "",
1305
- order_id: "",
1306
- cart_id: ""
1307
- };
1308
- function formatDate$1(value) {
1309
- if (!value) {
1310
- return "";
1213
+ function PayPalPayLaterMessagingPage() {
1214
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1215
+ }
1216
+ async function adminFetch$1(path, opts = {}) {
1217
+ var _a;
1218
+ const { method = "GET", body, query } = opts;
1219
+ let url = path;
1220
+ if (query && Object.keys(query).length > 0) {
1221
+ const params = new URLSearchParams(query);
1222
+ url = `${path}?${params.toString()}`;
1311
1223
  }
1312
- const parsed = new Date(value);
1313
- if (Number.isNaN(parsed.getTime())) {
1314
- return value;
1224
+ const headers = { Accept: "application/json" };
1225
+ if (body !== void 0) headers["Content-Type"] = "application/json";
1226
+ if (typeof window !== "undefined") {
1227
+ const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
1228
+ if (token) headers["Authorization"] = `Bearer ${token}`;
1315
1229
  }
1230
+ const res = await fetch(url, {
1231
+ method,
1232
+ headers,
1233
+ credentials: "include",
1234
+ body: body !== void 0 ? JSON.stringify(body) : void 0
1235
+ });
1236
+ const text = await res.text().catch(() => "");
1237
+ if (!res.ok) {
1238
+ if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
1239
+ if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
1240
+ throw new Error(text || `Request failed with status ${res.status}`);
1241
+ }
1242
+ if (!text) return {};
1243
+ try {
1244
+ return JSON.parse(text);
1245
+ } catch {
1246
+ return {};
1247
+ }
1248
+ }
1249
+ function formatDate(value) {
1250
+ if (!value) return "—";
1251
+ const parsed = new Date(value);
1252
+ if (Number.isNaN(parsed.getTime())) return value;
1316
1253
  return parsed.toLocaleString();
1317
1254
  }
1318
- function PayPalDisputesPage() {
1319
- const [filters, setFilters] = react.useState({ ...EMPTY_FILTERS });
1320
- const [disputes, setDisputes] = react.useState([]);
1255
+ function PayPalReconciliationStatusPage() {
1256
+ const [status, setStatus] = react.useState({});
1321
1257
  const [loading, setLoading] = react.useState(false);
1322
1258
  const [error, setError] = react.useState(null);
1323
- const queryString = react.useMemo(() => {
1324
- const params = new URLSearchParams();
1325
- Object.entries(filters).forEach(([key, value]) => {
1326
- if (value.trim()) {
1327
- params.set(key, value.trim());
1328
- }
1329
- });
1330
- const qs = params.toString();
1331
- return qs ? `?${qs}` : "";
1332
- }, [filters]);
1333
- const fetchDisputes = react.useCallback(async (source) => {
1259
+ const fetchStatus = react.useCallback(async () => {
1334
1260
  try {
1335
1261
  setLoading(true);
1336
1262
  setError(null);
1337
- const params = new URLSearchParams();
1338
- Object.entries(source).forEach(([key, value]) => {
1339
- if (value.trim()) {
1340
- params.set(key, value.trim());
1341
- }
1342
- });
1343
- const qs = params.toString();
1344
- const resp = await fetch(`/admin/paypal/disputes${qs ? `?${qs}` : ""}`, {
1345
- credentials: "include",
1346
- headers: {
1347
- Accept: "application/json"
1348
- }
1349
- });
1350
- if (!resp.ok) {
1351
- const message = await resp.text().catch(() => "");
1352
- throw new Error(message || "Failed to load disputes");
1353
- }
1354
- const json = await resp.json().catch(() => ({}));
1355
- setDisputes((json == null ? void 0 : json.disputes) || []);
1263
+ const data = await adminFetch$1("/admin/paypal/reconciliation-status");
1264
+ setStatus((data == null ? void 0 : data.status) ?? {});
1356
1265
  } catch (fetchError) {
1357
- setError((fetchError == null ? void 0 : fetchError.message) || "Failed to load disputes");
1358
- setDisputes([]);
1266
+ setError(fetchError instanceof Error ? fetchError.message : "Failed to load reconciliation status.");
1267
+ setStatus({});
1359
1268
  } finally {
1360
1269
  setLoading(false);
1361
1270
  }
1362
1271
  }, []);
1363
1272
  react.useEffect(() => {
1364
- fetchDisputes(EMPTY_FILTERS);
1365
- }, [fetchDisputes]);
1366
- const onSubmit = (event) => {
1367
- event.preventDefault();
1368
- fetchDisputes(filters);
1369
- };
1370
- const onReset = () => {
1371
- setFilters({ ...EMPTY_FILTERS });
1372
- fetchDisputes(EMPTY_FILTERS);
1373
- };
1273
+ fetchStatus();
1274
+ }, [fetchStatus]);
1374
1275
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
1375
1276
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1376
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Disputes" }),
1377
- /* @__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." })
1277
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Reconciliation Status" }),
1278
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-ui-fg-subtle", children: "Monitor reconciliation health and drift detection for PayPal payment sessions." })
1378
1279
  ] }),
1379
1280
  /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
1380
1281
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
1381
- /* @__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" }) }),
1382
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit, className: "flex flex-col gap-4", children: [
1383
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-4", children: [
1384
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
1385
- "Dispute ID",
1386
- /* @__PURE__ */ jsxRuntime.jsx(
1387
- "input",
1388
- {
1389
- className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
1390
- value: filters.dispute_id,
1391
- onChange: (event) => setFilters((prev) => ({ ...prev, dispute_id: event.target.value })),
1392
- placeholder: "PP-D-123"
1393
- }
1394
- )
1282
+ /* @__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: [
1283
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: "Latest reconciliation run" }),
1284
+ /* @__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" })
1285
+ ] }) }),
1286
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
1287
+ 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,
1288
+ !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,
1289
+ Object.keys(status).length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 text-sm text-ui-fg-base md:grid-cols-2", children: [
1290
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1291
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last run" }),
1292
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_run_at) })
1395
1293
  ] }),
1396
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
1397
- "Status",
1398
- /* @__PURE__ */ jsxRuntime.jsx(
1399
- "input",
1400
- {
1401
- className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
1402
- value: filters.status,
1403
- onChange: (event) => setFilters((prev) => ({ ...prev, status: event.target.value })),
1404
- placeholder: "OPEN"
1405
- }
1406
- )
1294
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1295
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last run status" }),
1296
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium capitalize", children: status.last_run_status || "—" })
1407
1297
  ] }),
1408
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
1409
- "Order ID",
1410
- /* @__PURE__ */ jsxRuntime.jsx(
1411
- "input",
1412
- {
1413
- className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
1414
- value: filters.order_id,
1415
- onChange: (event) => setFilters((prev) => ({ ...prev, order_id: event.target.value })),
1416
- placeholder: "order_..."
1417
- }
1418
- )
1298
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1299
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last success" }),
1300
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_success_at) })
1301
+ ] }),
1302
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1303
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last failure" }),
1304
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_failure_at) })
1305
+ ] }),
1306
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1307
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Sessions checked" }),
1308
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.sessions_checked ?? 0 })
1309
+ ] }),
1310
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1311
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Sessions updated" }),
1312
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.sessions_updated ?? 0 })
1313
+ ] }),
1314
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1315
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Drift detections" }),
1316
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.drift_count ?? 0 })
1317
+ ] }),
1318
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
1319
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last drift order" }),
1320
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.last_drift_order_id || "—" }),
1321
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: formatDate(status.last_drift_at) })
1322
+ ] }),
1323
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3 md:col-span-2", children: [
1324
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last error" }),
1325
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.last_error || "No errors recorded." })
1419
1326
  ] }),
1420
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
1421
- "Cart ID",
1422
- /* @__PURE__ */ jsxRuntime.jsx(
1423
- "input",
1424
- {
1425
- className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
1426
- value: filters.cart_id,
1427
- onChange: (event) => setFilters((prev) => ({ ...prev, cart_id: event.target.value })),
1428
- placeholder: "cart_..."
1429
- }
1430
- )
1431
- ] })
1432
- ] }),
1433
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-3", children: [
1434
- /* @__PURE__ */ jsxRuntime.jsx(
1435
- "button",
1436
- {
1437
- type: "submit",
1438
- className: "rounded-md bg-ui-fg-base px-4 py-2 text-sm font-medium text-ui-bg-base",
1439
- disabled: loading,
1440
- children: loading ? "Loading..." : "Apply filters"
1441
- }
1442
- ),
1443
- /* @__PURE__ */ jsxRuntime.jsx(
1444
- "button",
1445
- {
1446
- type: "button",
1447
- className: "rounded-md border border-ui-border-base px-4 py-2 text-sm text-ui-fg-base",
1448
- onClick: onReset,
1449
- disabled: loading,
1450
- children: "Reset"
1451
- }
1452
- ),
1453
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-ui-fg-subtle", children: [
1454
- "Showing ",
1455
- disputes.length,
1456
- " dispute",
1457
- disputes.length === 1 ? "" : "s",
1458
- queryString ? " (filtered)" : ""
1327
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3 md:col-span-2", children: [
1328
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Total runs" }),
1329
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.runs ?? 0 })
1459
1330
  ] })
1460
- ] })
1461
- ] }) })
1462
- ] }),
1463
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
1464
- /* @__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" }) }),
1465
- /* @__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: [
1466
- /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "text-left text-ui-fg-subtle", children: [
1467
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Dispute" }),
1468
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Status" }),
1469
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Reason" }),
1470
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Stage" }),
1471
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Amount" }),
1472
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Order" }),
1473
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Cart" }),
1474
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Updated" })
1475
- ] }) }),
1476
- /* @__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: [
1477
- /* @__PURE__ */ jsxRuntime.jsxs("td", { className: "px-4 py-3", children: [
1478
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-ui-fg-base", children: dispute.dispute_id }),
1479
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-ui-fg-subtle", children: dispute.transaction_id || "No transaction" })
1480
- ] }),
1481
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.status || "Unknown" }),
1482
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.reason || "-" }),
1483
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.stage || "-" }),
1484
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.amount ? `${dispute.amount} ${dispute.currency_code || ""}` : "-" }),
1485
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.order_id || "-" }),
1486
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.cart_id || "-" }),
1487
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 text-ui-fg-subtle", children: formatDate$1(dispute.updated_at || dispute.created_at) })
1488
- ] }, dispute.id)) })
1489
- ] }) }),
1490
- 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
1331
+ ] }) : null
1332
+ ] })
1491
1333
  ] })
1492
1334
  ] }) });
1493
1335
  }
1494
- function PayPalPayLaterMessagingPage() {
1495
- return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1336
+ async function adminFetch(path, opts = {}) {
1337
+ var _a;
1338
+ const { method = "GET", body, query } = opts;
1339
+ let url = path;
1340
+ if (query && Object.keys(query).length > 0) {
1341
+ const params = new URLSearchParams(query);
1342
+ url = `${path}?${params.toString()}`;
1343
+ }
1344
+ const headers = { Accept: "application/json" };
1345
+ if (body !== void 0) headers["Content-Type"] = "application/json";
1346
+ if (typeof window !== "undefined") {
1347
+ const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
1348
+ if (token) headers["Authorization"] = `Bearer ${token}`;
1349
+ }
1350
+ const res = await fetch(url, {
1351
+ method,
1352
+ headers,
1353
+ credentials: "include",
1354
+ body: body !== void 0 ? JSON.stringify(body) : void 0
1355
+ });
1356
+ const text = await res.text().catch(() => "");
1357
+ if (!res.ok) {
1358
+ if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
1359
+ if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
1360
+ throw new Error(text || `Request failed with status ${res.status}`);
1361
+ }
1362
+ if (!text) return {};
1363
+ try {
1364
+ return JSON.parse(text);
1365
+ } catch {
1366
+ return {};
1367
+ }
1496
1368
  }
1497
1369
  const DISPLAY_LOCATION_OPTIONS = [
1498
1370
  { value: "product", label: "Product Page" },
@@ -1605,7 +1477,7 @@ function PayPalSettingsTab() {
1605
1477
  const [form, setForm] = react.useState({
1606
1478
  enabled: true,
1607
1479
  title: "PayPal",
1608
- description: "Pay via PayPal; you can pay with your credit card if you dont have a PayPal account",
1480
+ description: "Pay via PayPal; you can pay with your credit card if you don't have a PayPal account",
1609
1481
  displayOn: ["product", "cart", "express", "mini_cart"],
1610
1482
  disableButtons: [],
1611
1483
  buttonColor: "gold",
@@ -1624,12 +1496,9 @@ function PayPalSettingsTab() {
1624
1496
  (async () => {
1625
1497
  try {
1626
1498
  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();
1499
+ const json = await adminFetch(
1500
+ "/admin/paypal/settings"
1501
+ );
1633
1502
  const payload = (json == null ? void 0 : json.data) ?? json;
1634
1503
  const saved = payload == null ? void 0 : payload.paypal_settings;
1635
1504
  if (saved && typeof saved === "object") {
@@ -1639,6 +1508,7 @@ function PayPalSettingsTab() {
1639
1508
  disableButtons: filterHiddenDisableButtons(saved.disableButtons)
1640
1509
  }));
1641
1510
  }
1511
+ } catch {
1642
1512
  } finally {
1643
1513
  setLoading(false);
1644
1514
  }
@@ -1651,22 +1521,13 @@ function PayPalSettingsTab() {
1651
1521
  ...form,
1652
1522
  disableButtons: filterHiddenDisableButtons(form.disableButtons)
1653
1523
  };
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);
1524
+ const json = await adminFetch(
1525
+ "/admin/paypal/settings",
1526
+ {
1527
+ method: "POST",
1528
+ body: { paypal_settings: cleaned }
1529
+ }
1530
+ );
1670
1531
  const payload = (json == null ? void 0 : json.data) ?? json;
1671
1532
  const saved = payload == null ? void 0 : payload.paypal_settings;
1672
1533
  if (saved && typeof saved === "object") {
@@ -1678,6 +1539,12 @@ function PayPalSettingsTab() {
1678
1539
  }
1679
1540
  setToast({ type: "success", message: "Settings saved" });
1680
1541
  window.setTimeout(() => setToast(null), 2500);
1542
+ } catch (e) {
1543
+ setToast({
1544
+ type: "error",
1545
+ message: (e instanceof Error ? e.message : "") || "Failed to save settings."
1546
+ });
1547
+ window.setTimeout(() => setToast(null), 3500);
1681
1548
  } finally {
1682
1549
  setSaving(false);
1683
1550
  }
@@ -1817,226 +1684,114 @@ function PayPalSettingsTab() {
1817
1684
  ] })
1818
1685
  }
1819
1686
  ),
1820
- /* @__PURE__ */ jsxRuntime.jsxs(
1687
+ /* @__PURE__ */ jsxRuntime.jsx(
1821
1688
  SectionCard,
1822
1689
  {
1823
1690
  title: "Button Appearance",
1824
1691
  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.");
1692
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
1693
+ /* @__PURE__ */ jsxRuntime.jsx(
1694
+ FieldRow,
1695
+ {
1696
+ label: "Disable Specific Payment Buttons",
1697
+ hint: "Hide individual funding sources (ex: Card, Venmo).",
1698
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
1699
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
1700
+ filterHiddenDisableButtons(form.disableButtons).map((v) => {
1701
+ const opt = VISIBLE_DISABLE_BUTTON_OPTIONS.find((o) => o.value === v);
1702
+ return /* @__PURE__ */ jsxRuntime.jsx(Pill, { onRemove: () => removeMulti("disableButtons", v), children: (opt == null ? void 0 : opt.label) ?? v }, v);
1703
+ }),
1704
+ filterHiddenDisableButtons(form.disableButtons).length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "No buttons disabled." }) : null
1705
+ ] }),
1706
+ /* @__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) => {
1707
+ const checked = form.disableButtons.includes(o.value);
1708
+ return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 rounded-md p-2 hover:bg-ui-bg-subtle", children: [
1709
+ /* @__PURE__ */ jsxRuntime.jsx(
1710
+ "input",
1711
+ {
1712
+ type: "checkbox",
1713
+ checked,
1714
+ onChange: () => toggleMulti("disableButtons", o.value),
1715
+ className: "h-4 w-4 rounded border-ui-border-base"
1716
+ }
1717
+ ),
1718
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: o.label })
1719
+ ] }, o.value);
1720
+ }) }) })
1721
+ ] })
1722
+ }
1723
+ ),
1724
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Color", children: /* @__PURE__ */ jsxRuntime.jsx(
1725
+ "select",
1726
+ {
1727
+ value: form.buttonColor,
1728
+ onChange: (e) => setForm((p) => ({ ...p, buttonColor: e.target.value })),
1729
+ 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",
1730
+ children: COLOR_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1731
+ }
1732
+ ) }),
1733
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Shape", children: /* @__PURE__ */ jsxRuntime.jsx(
1734
+ "select",
1735
+ {
1736
+ value: form.buttonShape,
1737
+ onChange: (e) => setForm((p) => ({ ...p, buttonShape: e.target.value })),
1738
+ 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",
1739
+ children: SHAPE_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1740
+ }
1741
+ ) }),
1742
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Width", children: /* @__PURE__ */ jsxRuntime.jsx(
1743
+ "select",
1744
+ {
1745
+ value: form.buttonWidth,
1746
+ onChange: (e) => setForm((p) => ({ ...p, buttonWidth: e.target.value })),
1747
+ 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",
1748
+ children: WIDTH_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1749
+ }
1750
+ ) }),
1751
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Height", children: /* @__PURE__ */ jsxRuntime.jsx(
1752
+ "select",
1753
+ {
1754
+ value: String(form.buttonHeight),
1755
+ onChange: (e) => setForm((p) => ({ ...p, buttonHeight: Number(e.target.value) })),
1756
+ 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",
1757
+ children: HEIGHT_OPTIONS.map((h) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: h, children: [
1758
+ h,
1759
+ " px"
1760
+ ] }, h))
1761
+ }
1762
+ ) }),
1763
+ /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Button Label", children: /* @__PURE__ */ jsxRuntime.jsx(
1764
+ "select",
1765
+ {
1766
+ value: form.buttonLabel,
1767
+ onChange: (e) => setForm((p) => ({ ...p, buttonLabel: e.target.value })),
1768
+ 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",
1769
+ children: LABEL_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
1770
+ }
1771
+ ) })
1772
+ ] })
1961
1773
  }
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
1774
+ ),
1775
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-6 rounded-md border border-ui-border-base bg-ui-bg-subtle p-4", children: [
1776
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: "Preview (UI only)" }),
1777
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 text-sm text-ui-fg-subtle", children: [
1778
+ "Color: ",
1779
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonColor }),
1780
+ " · Shape:",
1781
+ " ",
1782
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonShape }),
1783
+ " · Width:",
1784
+ " ",
1785
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonWidth }),
1786
+ " · Height:",
1787
+ " ",
1788
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-base", children: [
1789
+ form.buttonHeight,
1790
+ "px"
1791
+ ] }),
1792
+ " · Label:",
1793
+ " ",
1794
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-base", children: form.buttonLabel })
2040
1795
  ] })
2041
1796
  ] })
2042
1797
  ] }) });
@@ -2052,6 +1807,10 @@ const routeModule = {
2052
1807
  Component: AdditionalSettingsTab,
2053
1808
  path: "/settings/paypal/additional-settings"
2054
1809
  },
1810
+ {
1811
+ Component: AdvancedCardPaymentsTab,
1812
+ path: "/settings/paypal/advanced-card-payments"
1813
+ },
2055
1814
  {
2056
1815
  Component: PayPalApplePayPage,
2057
1816
  path: "/settings/paypal/apple-pay"
@@ -2061,8 +1820,8 @@ const routeModule = {
2061
1820
  path: "/settings/paypal/connection"
2062
1821
  },
2063
1822
  {
2064
- Component: AdvancedCardPaymentsTab,
2065
- path: "/settings/paypal/advanced-card-payments"
1823
+ Component: PayPalDisputesPage,
1824
+ path: "/settings/paypal/disputes"
2066
1825
  },
2067
1826
  {
2068
1827
  Component: PayPalAuditLogsPage,
@@ -2072,21 +1831,17 @@ const routeModule = {
2072
1831
  Component: PayPalGooglePayPage,
2073
1832
  path: "/settings/paypal/google-pay"
2074
1833
  },
2075
- {
2076
- Component: PayPalDisputesPage,
2077
- path: "/settings/paypal/disputes"
2078
- },
2079
1834
  {
2080
1835
  Component: PayPalPayLaterMessagingPage,
2081
1836
  path: "/settings/paypal/pay-later-messaging"
2082
1837
  },
2083
- {
2084
- Component: PayPalSettingsTab,
2085
- path: "/settings/paypal/paypal-settings"
2086
- },
2087
1838
  {
2088
1839
  Component: PayPalReconciliationStatusPage,
2089
1840
  path: "/settings/paypal/reconciliation-status"
1841
+ },
1842
+ {
1843
+ Component: PayPalSettingsTab,
1844
+ path: "/settings/paypal/paypal-settings"
2090
1845
  }
2091
1846
  ]
2092
1847
  };