@easypayment/medusa-paypal 0.1.6 → 0.1.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.
- package/.medusa/server/src/admin/index.js +1318 -1318
- package/.medusa/server/src/admin/index.mjs +1319 -1319
- package/.medusa/server/src/modules/paypal/utils/provider-ids.d.ts +1 -0
- package/.medusa/server/src/modules/paypal/utils/provider-ids.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/utils/provider-ids.js +17 -3
- package/.medusa/server/src/modules/paypal/utils/provider-ids.js.map +1 -1
- package/LICENSE +21 -21
- package/README.md +102 -102
- package/package.json +1 -1
- package/src/admin/routes/settings/paypal/page.tsx +17 -17
- package/src/index.ts +1 -1
- package/src/modules/paypal/utils/provider-ids.ts +17 -2
- package/src/providers/paypal/index.ts +10 -10
- package/src/providers/paypal_card/index.ts +10 -10
- package/tsconfig.json +30 -30
|
@@ -41,11 +41,17 @@ function PayPalTabs() {
|
|
|
41
41
|
}) }) });
|
|
42
42
|
}
|
|
43
43
|
const DEFAULT_FORM$1 = {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
paymentAction: "capture",
|
|
45
|
+
brandName: "PayPal",
|
|
46
|
+
landingPage: "no_preference",
|
|
47
|
+
requireInstantPayment: false,
|
|
48
|
+
useShippingAsBilling: true,
|
|
49
|
+
sendItemDetails: true,
|
|
50
|
+
skipOrderReviewPage: true,
|
|
51
|
+
invoicePrefix: "WC-",
|
|
52
|
+
creditCardStatementName: "PayPal",
|
|
53
|
+
enableLogging: true,
|
|
54
|
+
logPath: "/uploads/wc-logs/"
|
|
49
55
|
};
|
|
50
56
|
function mergeWithDefaults$1(saved) {
|
|
51
57
|
if (!saved) return { ...DEFAULT_FORM$1 };
|
|
@@ -55,53 +61,6 @@ function mergeWithDefaults$1(saved) {
|
|
|
55
61
|
...Object.fromEntries(entries)
|
|
56
62
|
};
|
|
57
63
|
}
|
|
58
|
-
const CARD_BRANDS = [
|
|
59
|
-
{ value: "visa", label: "Visa" },
|
|
60
|
-
{ value: "mastercard", label: "Mastercard" },
|
|
61
|
-
{ value: "amex", label: "American Express" },
|
|
62
|
-
{ value: "discover", label: "Discover" },
|
|
63
|
-
{ value: "diners", label: "Diners Club" },
|
|
64
|
-
{ value: "jcb", label: "JCB" },
|
|
65
|
-
{ value: "unionpay", label: "UnionPay" }
|
|
66
|
-
];
|
|
67
|
-
const THREE_DS_OPTIONS = [
|
|
68
|
-
{
|
|
69
|
-
value: "when_required",
|
|
70
|
-
label: "3D Secure when required",
|
|
71
|
-
hint: "Triggers 3DS only when the card / issuer requires it."
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
value: "sli",
|
|
75
|
-
label: "3D Secure (SCA) / liability shift (recommended)",
|
|
76
|
-
hint: "Attempts to optimize for liability shift while remaining compliant."
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
value: "always",
|
|
80
|
-
label: "Always request 3D Secure",
|
|
81
|
-
hint: "Forces 3DS challenge whenever possible (may reduce conversion)."
|
|
82
|
-
}
|
|
83
|
-
];
|
|
84
|
-
function cx$1(...parts) {
|
|
85
|
-
return parts.filter(Boolean).join(" ");
|
|
86
|
-
}
|
|
87
|
-
function Pill$1({
|
|
88
|
-
children,
|
|
89
|
-
onRemove
|
|
90
|
-
}) {
|
|
91
|
-
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: [
|
|
92
|
-
children,
|
|
93
|
-
onRemove ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
94
|
-
"button",
|
|
95
|
-
{
|
|
96
|
-
type: "button",
|
|
97
|
-
onClick: onRemove,
|
|
98
|
-
className: "ml-1 rounded px-1 text-ui-fg-subtle hover:text-ui-fg-base",
|
|
99
|
-
"aria-label": "Remove",
|
|
100
|
-
children: "×"
|
|
101
|
-
}
|
|
102
|
-
) : null
|
|
103
|
-
] });
|
|
104
|
-
}
|
|
105
64
|
function SectionCard$2({
|
|
106
65
|
title,
|
|
107
66
|
description,
|
|
@@ -132,12 +91,10 @@ function FieldRow$2({
|
|
|
132
91
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-12 md:col-span-8", children })
|
|
133
92
|
] });
|
|
134
93
|
}
|
|
135
|
-
function
|
|
136
|
-
var _a, _b;
|
|
94
|
+
function AdditionalSettingsTab() {
|
|
137
95
|
const [form, setForm] = react.useState(() => ({ ...DEFAULT_FORM$1 }));
|
|
138
96
|
const [loading, setLoading] = react.useState(false);
|
|
139
97
|
const [saving, setSaving] = react.useState(false);
|
|
140
|
-
const [toast, setToast] = react.useState(null);
|
|
141
98
|
const didInit = react.useRef(false);
|
|
142
99
|
react.useEffect(() => {
|
|
143
100
|
if (didInit.current) return;
|
|
@@ -152,7 +109,7 @@ function AdvancedCardPaymentsTab() {
|
|
|
152
109
|
if (!r.ok) return;
|
|
153
110
|
const json = await r.json();
|
|
154
111
|
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
155
|
-
const saved = payload == null ? void 0 : payload.
|
|
112
|
+
const saved = payload == null ? void 0 : payload.additional_settings;
|
|
156
113
|
if (saved && typeof saved === "object") {
|
|
157
114
|
setForm(mergeWithDefaults$1(saved));
|
|
158
115
|
}
|
|
@@ -161,9 +118,11 @@ function AdvancedCardPaymentsTab() {
|
|
|
161
118
|
}
|
|
162
119
|
})();
|
|
163
120
|
}, []);
|
|
121
|
+
const [toast, setToast] = react.useState(null);
|
|
164
122
|
async function onSave() {
|
|
165
123
|
try {
|
|
166
124
|
setSaving(true);
|
|
125
|
+
setToast(null);
|
|
167
126
|
const r = await fetch("/admin/paypal/settings", {
|
|
168
127
|
method: "POST",
|
|
169
128
|
credentials: "include",
|
|
@@ -171,42 +130,29 @@ function AdvancedCardPaymentsTab() {
|
|
|
171
130
|
"Content-Type": "application/json",
|
|
172
131
|
"Accept": "application/json"
|
|
173
132
|
},
|
|
174
|
-
body: JSON.stringify({
|
|
133
|
+
body: JSON.stringify({
|
|
134
|
+
additional_settings: form
|
|
135
|
+
})
|
|
175
136
|
});
|
|
176
137
|
if (!r.ok) {
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
window.setTimeout(() => setToast(null), 3500);
|
|
180
|
-
return;
|
|
138
|
+
const errText = await r.text().catch(() => "");
|
|
139
|
+
throw new Error(errText || "Failed to save settings");
|
|
181
140
|
}
|
|
182
|
-
const json = await r.json().catch(() =>
|
|
141
|
+
const json = await r.json().catch(() => ({}));
|
|
183
142
|
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
184
|
-
const saved = payload == null ? void 0 : payload.
|
|
143
|
+
const saved = payload == null ? void 0 : payload.additional_settings;
|
|
185
144
|
if (saved && typeof saved === "object") {
|
|
186
145
|
setForm(mergeWithDefaults$1(saved));
|
|
187
146
|
}
|
|
188
147
|
setToast({ type: "success", message: "Settings saved" });
|
|
189
148
|
window.setTimeout(() => setToast(null), 2500);
|
|
149
|
+
} catch (e) {
|
|
150
|
+
setToast({ type: "error", message: (e == null ? void 0 : e.message) || "Failed to save settings" });
|
|
151
|
+
window.setTimeout(() => setToast(null), 3500);
|
|
190
152
|
} finally {
|
|
191
153
|
setSaving(false);
|
|
192
154
|
}
|
|
193
155
|
}
|
|
194
|
-
const disabledSet = react.useMemo(() => new Set(form.disabledCards), [form.disabledCards]);
|
|
195
|
-
function toggleDisabledCard(value) {
|
|
196
|
-
setForm((prev) => {
|
|
197
|
-
const exists = prev.disabledCards.includes(value);
|
|
198
|
-
return {
|
|
199
|
-
...prev,
|
|
200
|
-
disabledCards: exists ? prev.disabledCards.filter((v) => v !== value) : [...prev.disabledCards, value]
|
|
201
|
-
};
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
function removeDisabledCard(value) {
|
|
205
|
-
setForm((prev) => ({
|
|
206
|
-
...prev,
|
|
207
|
-
disabledCards: prev.disabledCards.filter((v) => v !== value)
|
|
208
|
-
}));
|
|
209
|
-
}
|
|
210
156
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
211
157
|
/* @__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" }) }) }),
|
|
212
158
|
/* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
|
|
@@ -222,8 +168,8 @@ function AdvancedCardPaymentsTab() {
|
|
|
222
168
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
223
169
|
SectionCard$2,
|
|
224
170
|
{
|
|
225
|
-
title: "
|
|
226
|
-
description: "
|
|
171
|
+
title: "Additional Settings",
|
|
172
|
+
description: "These settings control checkout behavior, PayPal experience, and logging.",
|
|
227
173
|
right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
228
174
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
229
175
|
"button",
|
|
@@ -238,692 +184,161 @@ function AdvancedCardPaymentsTab() {
|
|
|
238
184
|
loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading…" }) : null
|
|
239
185
|
] }),
|
|
240
186
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
|
|
241
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "
|
|
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
|
+
) }),
|
|
221
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Instant Payments", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
242
222
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
243
223
|
"input",
|
|
244
224
|
{
|
|
245
225
|
type: "checkbox",
|
|
246
|
-
checked: form.
|
|
247
|
-
onChange: (e) => setForm((p) => ({ ...p,
|
|
226
|
+
checked: form.requireInstantPayment,
|
|
227
|
+
onChange: (e) => setForm((p) => ({ ...p, requireInstantPayment: e.target.checked })),
|
|
248
228
|
className: "h-4 w-4 rounded border-ui-border-base"
|
|
249
229
|
}
|
|
250
230
|
),
|
|
251
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "
|
|
231
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Require Instant Payment" })
|
|
252
232
|
] }) }),
|
|
253
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
254
|
-
|
|
233
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
234
|
+
FieldRow$2,
|
|
255
235
|
{
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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
|
+
] })
|
|
260
250
|
}
|
|
261
|
-
)
|
|
251
|
+
),
|
|
262
252
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
263
253
|
FieldRow$2,
|
|
264
254
|
{
|
|
265
|
-
label: "
|
|
266
|
-
hint: "
|
|
267
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("
|
|
268
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
className: cx$1(
|
|
279
|
-
"flex items-center gap-2 rounded-md p-2",
|
|
280
|
-
"hover:bg-ui-bg-subtle"
|
|
281
|
-
),
|
|
282
|
-
children: [
|
|
283
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
284
|
-
"input",
|
|
285
|
-
{
|
|
286
|
-
type: "checkbox",
|
|
287
|
-
checked,
|
|
288
|
-
onChange: () => toggleDisabledCard(b.value),
|
|
289
|
-
className: "h-4 w-4 rounded border-ui-border-base"
|
|
290
|
-
}
|
|
291
|
-
),
|
|
292
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: b.label })
|
|
293
|
-
]
|
|
294
|
-
},
|
|
295
|
-
b.value
|
|
296
|
-
);
|
|
297
|
-
}) }) })
|
|
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" })
|
|
298
268
|
] })
|
|
299
269
|
}
|
|
300
270
|
),
|
|
301
271
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
302
272
|
FieldRow$2,
|
|
303
273
|
{
|
|
304
|
-
label: "
|
|
305
|
-
hint: "
|
|
306
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("
|
|
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: [
|
|
307
277
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
308
|
-
"
|
|
278
|
+
"input",
|
|
309
279
|
{
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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"
|
|
314
284
|
}
|
|
315
285
|
),
|
|
316
|
-
|
|
286
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Skip Order Review Page" })
|
|
317
287
|
] })
|
|
318
288
|
}
|
|
319
289
|
),
|
|
320
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const DISCONNECT_ENDPOINT = "/admin/paypal/disconnect";
|
|
372
|
-
let cachedUrl = null;
|
|
373
|
-
if (typeof window !== "undefined") {
|
|
374
|
-
try {
|
|
375
|
-
const cached = localStorage.getItem(CACHE_KEY);
|
|
376
|
-
if (cached) {
|
|
377
|
-
const data = JSON.parse(cached);
|
|
378
|
-
if ((/* @__PURE__ */ new Date()).getTime() - data.ts < CACHE_EXPIRY) {
|
|
379
|
-
cachedUrl = data.url;
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
} catch (e) {
|
|
383
|
-
console.error("Cache read error:", e);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
function PayPalConnectionPage() {
|
|
387
|
-
const [env, setEnv] = react.useState("sandbox");
|
|
388
|
-
react.useEffect(() => {
|
|
389
|
-
fetch("/admin/paypal/environment", { method: "GET" }).then((r) => r.json()).then((d) => {
|
|
390
|
-
const v = (d == null ? void 0 : d.environment) === "live" ? "live" : "sandbox";
|
|
391
|
-
setEnv(v);
|
|
392
|
-
}).catch(() => {
|
|
393
|
-
});
|
|
394
|
-
}, []);
|
|
395
|
-
const [connState, setConnState] = react.useState("loading");
|
|
396
|
-
const [error, setError] = react.useState(null);
|
|
397
|
-
const [finalUrl, setFinalUrl] = react.useState("");
|
|
398
|
-
const [showManual, setShowManual] = react.useState(false);
|
|
399
|
-
const [clientId, setClientId] = react.useState("");
|
|
400
|
-
const [secret, setSecret] = react.useState("");
|
|
401
|
-
const [merchantId, setMerchantId] = react.useState("");
|
|
402
|
-
const [statusInfo, setStatusInfo] = react.useState(null);
|
|
403
|
-
const [onboardingInProgress, setOnboardingInProgress] = react.useState(false);
|
|
404
|
-
const initLoaderRef = react.useRef(null);
|
|
405
|
-
const paypalButtonRef = react.useRef(null);
|
|
406
|
-
const errorLogRef = react.useRef(null);
|
|
407
|
-
const runIdRef = react.useRef(0);
|
|
408
|
-
const currentRunId = react.useRef(0);
|
|
409
|
-
const ppBtnMeasureRef = react.useRef(null);
|
|
410
|
-
const [ppBtnWidth, setPpBtnWidth] = react.useState(null);
|
|
411
|
-
const canSaveManual = react.useMemo(() => {
|
|
412
|
-
return clientId.trim().length > 0 && secret.trim().length > 0;
|
|
413
|
-
}, [clientId, secret]);
|
|
414
|
-
const maskValue = react.useCallback((value, visibleChars = 4) => {
|
|
415
|
-
if (!value) return "";
|
|
416
|
-
if (value.length <= visibleChars) {
|
|
417
|
-
return "•".repeat(value.length);
|
|
418
|
-
}
|
|
419
|
-
return `${"•".repeat(Math.max(0, value.length - visibleChars))}${value.slice(
|
|
420
|
-
-visibleChars
|
|
421
|
-
)}`;
|
|
422
|
-
}, []);
|
|
423
|
-
const fetchFreshLink = react.useCallback(
|
|
424
|
-
(runId) => {
|
|
425
|
-
if (initLoaderRef.current) {
|
|
426
|
-
const loaderText = initLoaderRef.current.querySelector("#loader-text");
|
|
427
|
-
if (loaderText)
|
|
428
|
-
loaderText.textContent = "Generating onboarding session...";
|
|
429
|
-
}
|
|
430
|
-
fetch(SERVICE_URL, {
|
|
431
|
-
method: "POST",
|
|
432
|
-
headers: { "content-type": "application/json" },
|
|
433
|
-
body: JSON.stringify({
|
|
434
|
-
products: ["PPCP"]
|
|
435
|
-
})
|
|
436
|
-
}).then((r) => r.json()).then((data) => {
|
|
437
|
-
if (runId !== currentRunId.current) return;
|
|
438
|
-
const href = data == null ? void 0 : data.onboarding_url;
|
|
439
|
-
if (!href) {
|
|
440
|
-
showError("Onboarding URL not returned.");
|
|
441
|
-
return;
|
|
442
|
-
}
|
|
443
|
-
const finalUrl2 = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
|
|
444
|
-
localStorage.setItem(
|
|
445
|
-
CACHE_KEY,
|
|
446
|
-
JSON.stringify({
|
|
447
|
-
url: finalUrl2,
|
|
448
|
-
ts: Date.now()
|
|
449
|
-
})
|
|
450
|
-
);
|
|
451
|
-
if (!localStorage.getItem(RELOAD_KEY)) {
|
|
452
|
-
localStorage.setItem(RELOAD_KEY, "1");
|
|
453
|
-
window.location.reload();
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
activatePayPal(finalUrl2, runId);
|
|
457
|
-
}).catch(() => {
|
|
458
|
-
if (runId !== currentRunId.current) return;
|
|
459
|
-
showError("Unable to connect to service.");
|
|
460
|
-
});
|
|
461
|
-
},
|
|
462
|
-
[env]
|
|
463
|
-
);
|
|
464
|
-
const showUI = react.useCallback(() => {
|
|
465
|
-
var _a, _b, _c, _d;
|
|
466
|
-
const btn = document.querySelector('[data-paypal-button="true"]');
|
|
467
|
-
if (btn && ((_d = (_c = (_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) == null ? void 0 : _c.miniBrowser) == null ? void 0 : _d.init)) {
|
|
468
|
-
window.PAYPAL.apps.Signup.miniBrowser.init();
|
|
469
|
-
}
|
|
470
|
-
setConnState("ready");
|
|
471
|
-
}, []);
|
|
472
|
-
const showError = react.useCallback((msg) => {
|
|
473
|
-
setConnState("error");
|
|
474
|
-
setError(msg);
|
|
475
|
-
}, []);
|
|
476
|
-
const activatePayPal = react.useCallback(
|
|
477
|
-
(url, runId) => {
|
|
478
|
-
if (paypalButtonRef.current) {
|
|
479
|
-
paypalButtonRef.current.href = url;
|
|
480
|
-
}
|
|
481
|
-
setFinalUrl(url);
|
|
482
|
-
const tryInit = () => {
|
|
483
|
-
var _a, _b;
|
|
484
|
-
if (runId !== currentRunId.current) return;
|
|
485
|
-
if ((_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) {
|
|
486
|
-
showUI();
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
setTimeout(tryInit, 50);
|
|
490
|
-
};
|
|
491
|
-
tryInit();
|
|
492
|
-
},
|
|
493
|
-
[showUI]
|
|
494
|
-
);
|
|
495
|
-
react.useEffect(() => {
|
|
496
|
-
currentRunId.current = ++runIdRef.current;
|
|
497
|
-
const runId = currentRunId.current;
|
|
498
|
-
let cancelled = false;
|
|
499
|
-
const run = async () => {
|
|
500
|
-
setConnState("loading");
|
|
501
|
-
setError(null);
|
|
502
|
-
setFinalUrl("");
|
|
503
|
-
try {
|
|
504
|
-
const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
505
|
-
method: "GET"
|
|
506
|
-
});
|
|
507
|
-
const st = await r.json().catch(() => ({}));
|
|
508
|
-
if (cancelled || runId !== currentRunId.current) return;
|
|
509
|
-
setStatusInfo(st);
|
|
510
|
-
const isConnected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
|
|
511
|
-
if (isConnected) {
|
|
512
|
-
setConnState("connected");
|
|
513
|
-
setShowManual(false);
|
|
514
|
-
return;
|
|
515
|
-
}
|
|
516
|
-
} catch (e) {
|
|
517
|
-
console.error(e);
|
|
518
|
-
}
|
|
519
|
-
if (cachedUrl) {
|
|
520
|
-
console.log("Using prioritized cache...");
|
|
521
|
-
activatePayPal(cachedUrl, runId);
|
|
522
|
-
} else {
|
|
523
|
-
fetchFreshLink(runId);
|
|
524
|
-
}
|
|
525
|
-
};
|
|
526
|
-
run();
|
|
527
|
-
return () => {
|
|
528
|
-
cancelled = true;
|
|
529
|
-
currentRunId.current = 0;
|
|
530
|
-
};
|
|
531
|
-
}, [env, fetchFreshLink, activatePayPal]);
|
|
532
|
-
react.useLayoutEffect(() => {
|
|
533
|
-
window.onboardingCallback = async function(authCode, sharedId) {
|
|
534
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
535
|
-
try {
|
|
536
|
-
;
|
|
537
|
-
window.onbeforeunload = "";
|
|
538
|
-
} catch {
|
|
539
|
-
}
|
|
540
|
-
setOnboardingInProgress(true);
|
|
541
|
-
setConnState("loading");
|
|
542
|
-
setError(null);
|
|
543
|
-
const payload = {
|
|
544
|
-
authCode,
|
|
545
|
-
sharedId,
|
|
546
|
-
env: env === "sandbox" ? "sandbox" : "live"
|
|
547
|
-
};
|
|
548
|
-
try {
|
|
549
|
-
const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
|
|
550
|
-
method: "POST",
|
|
551
|
-
headers: { "content-type": "application/json" },
|
|
552
|
-
body: JSON.stringify(payload)
|
|
553
|
-
});
|
|
554
|
-
if (!res.ok) {
|
|
555
|
-
const txt = await res.text().catch(() => "");
|
|
556
|
-
throw new Error(txt || `Onboarding exchange failed (${res.status})`);
|
|
557
|
-
}
|
|
558
|
-
try {
|
|
559
|
-
const close1 = (_d = (_c = (_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) == null ? void 0 : _c.MiniBrowser) == null ? void 0 : _d.closeFlow;
|
|
560
|
-
if (typeof close1 === "function") close1();
|
|
561
|
-
} catch {
|
|
562
|
-
}
|
|
563
|
-
try {
|
|
564
|
-
const close2 = ((_g = (_f = (_e = window.PAYPAL) == null ? void 0 : _e.apps) == null ? void 0 : _f.Signup) == null ? void 0 : _g.miniBrowser) && window.PAYPAL.apps.Signup.miniBrowser.closeFlow;
|
|
565
|
-
if (typeof close2 === "function") close2();
|
|
566
|
-
} catch {
|
|
567
|
-
}
|
|
568
|
-
try {
|
|
569
|
-
localStorage.removeItem(CACHE_KEY);
|
|
570
|
-
localStorage.removeItem(RELOAD_KEY);
|
|
571
|
-
} catch {
|
|
572
|
-
}
|
|
573
|
-
window.location.href = window.location.href;
|
|
574
|
-
} catch (e) {
|
|
575
|
-
console.error(e);
|
|
576
|
-
setConnState("error");
|
|
577
|
-
setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
|
|
578
|
-
setOnboardingInProgress(false);
|
|
579
|
-
}
|
|
580
|
-
};
|
|
581
|
-
return () => {
|
|
582
|
-
window.onboardingCallback = void 0;
|
|
583
|
-
};
|
|
584
|
-
}, [env]);
|
|
585
|
-
react.useLayoutEffect(() => {
|
|
586
|
-
const el = ppBtnMeasureRef.current;
|
|
587
|
-
if (!el) return;
|
|
588
|
-
const update = () => {
|
|
589
|
-
const w = Math.round(el.getBoundingClientRect().width || 0);
|
|
590
|
-
if (w > 0) setPpBtnWidth(w);
|
|
591
|
-
};
|
|
592
|
-
update();
|
|
593
|
-
let ro = null;
|
|
594
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
595
|
-
ro = new ResizeObserver(() => update());
|
|
596
|
-
ro.observe(el);
|
|
597
|
-
} else {
|
|
598
|
-
window.addEventListener("resize", update);
|
|
599
|
-
}
|
|
600
|
-
return () => {
|
|
601
|
-
if (ro) ro.disconnect();
|
|
602
|
-
else window.removeEventListener("resize", update);
|
|
603
|
-
};
|
|
604
|
-
}, [connState, env, finalUrl]);
|
|
605
|
-
const handleConnectClick = (e) => {
|
|
606
|
-
if (connState !== "ready" || !finalUrl || onboardingInProgress) {
|
|
607
|
-
e.preventDefault();
|
|
608
|
-
}
|
|
609
|
-
};
|
|
610
|
-
const handleSaveManual = async () => {
|
|
611
|
-
if (!canSaveManual || onboardingInProgress) return;
|
|
612
|
-
setOnboardingInProgress(true);
|
|
613
|
-
setConnState("loading");
|
|
614
|
-
setError(null);
|
|
615
|
-
try {
|
|
616
|
-
const res = await fetch(SAVE_CREDENTIALS_ENDPOINT, {
|
|
617
|
-
method: "POST",
|
|
618
|
-
headers: { "content-type": "application/json" },
|
|
619
|
-
body: JSON.stringify({
|
|
620
|
-
clientId: clientId.trim(),
|
|
621
|
-
clientSecret: secret.trim()
|
|
622
|
-
})
|
|
623
|
-
});
|
|
624
|
-
if (!res.ok) {
|
|
625
|
-
const txt = await res.text().catch(() => "");
|
|
626
|
-
throw new Error(txt || `Save credentials failed (${res.status})`);
|
|
627
|
-
}
|
|
628
|
-
setConnState("connected");
|
|
629
|
-
setStatusInfo({
|
|
630
|
-
seller_client_id_masked: maskValue(clientId.trim()),
|
|
631
|
-
seller_client_secret_masked: "••••••••"
|
|
632
|
-
});
|
|
633
|
-
setShowManual(false);
|
|
634
|
-
try {
|
|
635
|
-
localStorage.removeItem(CACHE_KEY);
|
|
636
|
-
localStorage.removeItem(RELOAD_KEY);
|
|
637
|
-
} catch {
|
|
638
|
-
}
|
|
639
|
-
} catch (e) {
|
|
640
|
-
console.error(e);
|
|
641
|
-
setConnState("error");
|
|
642
|
-
setError((e == null ? void 0 : e.message) || "Failed to save credentials.");
|
|
643
|
-
} finally {
|
|
644
|
-
setOnboardingInProgress(false);
|
|
645
|
-
}
|
|
646
|
-
};
|
|
647
|
-
const handleDisconnect = async () => {
|
|
648
|
-
if (onboardingInProgress) return;
|
|
649
|
-
if (!window.confirm("Disconnect PayPal for this environment?")) return;
|
|
650
|
-
setOnboardingInProgress(true);
|
|
651
|
-
setConnState("loading");
|
|
652
|
-
setError(null);
|
|
653
|
-
setFinalUrl("");
|
|
654
|
-
setShowManual(false);
|
|
655
|
-
try {
|
|
656
|
-
const res = await fetch(DISCONNECT_ENDPOINT, {
|
|
657
|
-
method: "POST",
|
|
658
|
-
headers: { "content-type": "application/json" },
|
|
659
|
-
body: JSON.stringify({ environment: env })
|
|
660
|
-
});
|
|
661
|
-
if (!res.ok) {
|
|
662
|
-
const t = await res.text().catch(() => "");
|
|
663
|
-
throw new Error(t || `Disconnect failed (${res.status})`);
|
|
664
|
-
}
|
|
665
|
-
try {
|
|
666
|
-
localStorage.removeItem(CACHE_KEY);
|
|
667
|
-
localStorage.removeItem(RELOAD_KEY);
|
|
668
|
-
} catch {
|
|
669
|
-
}
|
|
670
|
-
currentRunId.current = ++runIdRef.current;
|
|
671
|
-
const runId = currentRunId.current;
|
|
672
|
-
fetchFreshLink(runId);
|
|
673
|
-
} catch (e) {
|
|
674
|
-
console.error(e);
|
|
675
|
-
setConnState("error");
|
|
676
|
-
setError((e == null ? void 0 : e.message) || "Failed to disconnect.");
|
|
677
|
-
} finally {
|
|
678
|
-
setOnboardingInProgress(false);
|
|
679
|
-
}
|
|
680
|
-
};
|
|
681
|
-
const handleEnvChange = async (e) => {
|
|
682
|
-
const next = e.target.value;
|
|
683
|
-
setEnv(next);
|
|
684
|
-
cachedUrl = null;
|
|
685
|
-
try {
|
|
686
|
-
await fetch("/admin/paypal/environment", {
|
|
687
|
-
method: "POST",
|
|
688
|
-
headers: { "content-type": "application/json" },
|
|
689
|
-
body: JSON.stringify({ environment: next })
|
|
690
|
-
});
|
|
691
|
-
} catch {
|
|
692
|
-
}
|
|
693
|
-
try {
|
|
694
|
-
localStorage.removeItem(CACHE_KEY);
|
|
695
|
-
localStorage.removeItem(RELOAD_KEY);
|
|
696
|
-
} catch {
|
|
697
|
-
}
|
|
698
|
-
};
|
|
699
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6", children: [
|
|
700
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
701
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold", children: "PayPal Gateway By Easy Payment" }),
|
|
702
|
-
/* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
|
|
703
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-ui-border-base p-4 shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-y-6 md:grid-cols-[260px_1fr] md:items-start", children: [
|
|
704
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium pt-2", children: "Environment" }),
|
|
705
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xl", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
706
|
-
"select",
|
|
707
|
-
{
|
|
708
|
-
value: env,
|
|
709
|
-
onChange: handleEnvChange,
|
|
710
|
-
disabled: onboardingInProgress,
|
|
711
|
-
className: "w-full rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm",
|
|
712
|
-
children: [
|
|
713
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "sandbox", children: "Sandbox (Test Mode)" }),
|
|
714
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "live", children: "Live (Production)" })
|
|
715
|
-
]
|
|
716
|
-
}
|
|
717
|
-
) }),
|
|
718
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium pt-2", children: env === "sandbox" ? "Connect to PayPal Sandbox" : "Connect to PayPal Live" }),
|
|
719
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xl", children: connState === "connected" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
720
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: [
|
|
721
|
-
"✅ Successfully connected to PayPal!",
|
|
722
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
723
|
-
"a",
|
|
724
|
-
{
|
|
725
|
-
"data-paypal-button": "true",
|
|
726
|
-
"data-paypal-onboard-complete": "onboardingCallback",
|
|
727
|
-
href: "#",
|
|
728
|
-
style: { display: "none" },
|
|
729
|
-
children: "PayPal"
|
|
730
|
-
}
|
|
731
|
-
)
|
|
732
|
-
] }),
|
|
733
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 rounded-md border border-ui-border-base bg-ui-bg-subtle p-3 text-xs text-ui-fg-subtle", children: [
|
|
734
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-ui-fg-base", children: "Connected PayPal account" }),
|
|
735
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1", children: [
|
|
736
|
-
"Email:",
|
|
737
|
-
" ",
|
|
738
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-ui-fg-base", children: (statusInfo == null ? void 0 : statusInfo.seller_email) || "Unavailable" })
|
|
739
|
-
] })
|
|
740
|
-
] }),
|
|
741
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
742
|
-
"button",
|
|
743
|
-
{
|
|
744
|
-
type: "button",
|
|
745
|
-
onClick: handleDisconnect,
|
|
746
|
-
disabled: onboardingInProgress,
|
|
747
|
-
className: "rounded-md border border-ui-border-base px-3 py-2 text-sm font-medium hover:bg-ui-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed",
|
|
748
|
-
children: "Disconnect"
|
|
749
|
-
}
|
|
750
|
-
) })
|
|
751
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
752
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
753
|
-
"div",
|
|
754
|
-
{
|
|
755
|
-
ref: initLoaderRef,
|
|
756
|
-
id: "init-loader",
|
|
757
|
-
className: `status-msg mb-4 ${connState !== "loading" ? "hidden" : "block"}`,
|
|
758
|
-
children: [
|
|
759
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "loader inline-block align-middle mr-2" }),
|
|
760
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { id: "loader-text", className: "text-sm", children: onboardingInProgress ? "Configuring connection to PayPal…" : "Checking connection..." })
|
|
761
|
-
]
|
|
762
|
-
}
|
|
763
|
-
),
|
|
764
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${connState === "ready" ? "block" : "hidden"}`, children: [
|
|
765
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
766
|
-
"a",
|
|
767
|
-
{
|
|
768
|
-
ref: (node) => {
|
|
769
|
-
paypalButtonRef.current = node;
|
|
770
|
-
ppBtnMeasureRef.current = node;
|
|
771
|
-
},
|
|
772
|
-
id: "paypal-button",
|
|
773
|
-
"data-paypal-button": "true",
|
|
774
|
-
href: finalUrl || "#",
|
|
775
|
-
"data-paypal-onboard-complete": "onboardingCallback",
|
|
776
|
-
onClick: handleConnectClick,
|
|
777
|
-
className: "btn-paypal",
|
|
778
|
-
style: {
|
|
779
|
-
borderRadius: "50px",
|
|
780
|
-
textDecoration: "none",
|
|
781
|
-
display: "inline-block",
|
|
782
|
-
fontWeight: "bold",
|
|
783
|
-
border: "none",
|
|
784
|
-
cursor: onboardingInProgress ? "not-allowed" : "pointer",
|
|
785
|
-
opacity: onboardingInProgress ? 0.6 : 1,
|
|
786
|
-
pointerEvents: onboardingInProgress ? "none" : "auto"
|
|
787
|
-
},
|
|
788
|
-
children: "Connect to PayPal"
|
|
789
|
-
}
|
|
790
|
-
),
|
|
791
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
792
|
-
"div",
|
|
793
|
-
{
|
|
794
|
-
className: "mt-2",
|
|
795
|
-
style: {
|
|
796
|
-
width: ppBtnWidth ? `${ppBtnWidth}px` : "auto",
|
|
797
|
-
marginTop: "20px",
|
|
798
|
-
marginBottom: "10px"
|
|
799
|
-
},
|
|
800
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] text-ui-fg-muted leading-none", children: "OR" }) })
|
|
801
|
-
}
|
|
802
|
-
),
|
|
803
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
804
|
-
"button",
|
|
805
|
-
{
|
|
806
|
-
type: "button",
|
|
807
|
-
onClick: () => setShowManual(!showManual),
|
|
808
|
-
disabled: onboardingInProgress,
|
|
809
|
-
className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
|
|
810
|
-
children: "Click here to insert credentials manually"
|
|
811
|
-
}
|
|
812
|
-
) })
|
|
813
|
-
] }),
|
|
814
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `${connState === "ready" ? "hidden" : "block"} mt-3`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
815
|
-
"button",
|
|
816
|
-
{
|
|
817
|
-
type: "button",
|
|
818
|
-
onClick: () => setShowManual(!showManual),
|
|
819
|
-
disabled: onboardingInProgress,
|
|
820
|
-
className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
|
|
821
|
-
children: "Click here to insert credentials manually"
|
|
822
|
-
}
|
|
823
|
-
) }),
|
|
824
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
825
|
-
"div",
|
|
826
|
-
{
|
|
827
|
-
ref: errorLogRef,
|
|
828
|
-
id: "error-log",
|
|
829
|
-
className: `mt-4 text-left text-xs bg-red-50 text-red-600 p-3 border border-red-200 rounded ${connState === "error" && error ? "block" : "hidden"}`,
|
|
830
|
-
children: error
|
|
831
|
-
}
|
|
832
|
-
)
|
|
833
|
-
] }) }),
|
|
834
|
-
showManual && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:col-span-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-[260px] max-w-xl mt-4 grid grid-cols-1 gap-3 md:grid-cols-2", children: [
|
|
835
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
836
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Client ID" }),
|
|
837
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
838
|
-
"input",
|
|
839
|
-
{
|
|
840
|
-
type: "text",
|
|
841
|
-
value: clientId,
|
|
842
|
-
onChange: (e) => setClientId(e.target.value),
|
|
843
|
-
disabled: onboardingInProgress,
|
|
844
|
-
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
845
|
-
placeholder: env === "sandbox" ? "Sandbox Client ID" : "Live Client ID"
|
|
846
|
-
}
|
|
847
|
-
)
|
|
848
|
-
] }),
|
|
849
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
850
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Client Secret" }),
|
|
851
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
852
|
-
"input",
|
|
853
|
-
{
|
|
854
|
-
type: "password",
|
|
855
|
-
value: secret,
|
|
856
|
-
onChange: (e) => setSecret(e.target.value),
|
|
857
|
-
disabled: onboardingInProgress,
|
|
858
|
-
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
859
|
-
placeholder: env === "sandbox" ? "Sandbox Secret" : "Live Secret"
|
|
860
|
-
}
|
|
861
|
-
)
|
|
862
|
-
] }),
|
|
863
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 md:col-span-2", children: [
|
|
864
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Merchant ID (optional)" }),
|
|
865
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
866
|
-
"input",
|
|
867
|
-
{
|
|
868
|
-
type: "text",
|
|
869
|
-
value: merchantId,
|
|
870
|
-
onChange: (e) => setMerchantId(e.target.value),
|
|
871
|
-
disabled: onboardingInProgress,
|
|
872
|
-
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
873
|
-
placeholder: "Merchant ID"
|
|
874
|
-
}
|
|
875
|
-
)
|
|
876
|
-
] }),
|
|
877
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:col-span-2 flex items-center gap-2 mt-2", children: [
|
|
878
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
879
|
-
"button",
|
|
880
|
-
{
|
|
881
|
-
type: "button",
|
|
882
|
-
className: "rounded-md border border-ui-border-base px-3 py-2 text-sm font-medium hover:bg-ui-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed",
|
|
883
|
-
onClick: () => setShowManual(false),
|
|
884
|
-
disabled: onboardingInProgress,
|
|
885
|
-
children: "Cancel"
|
|
886
|
-
}
|
|
887
|
-
),
|
|
888
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
889
|
-
"button",
|
|
890
|
-
{
|
|
891
|
-
type: "button",
|
|
892
|
-
className: "rounded-md border border-ui-border-base px-3 py-2 text-sm font-medium bg-ui-bg-base hover:bg-ui-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed",
|
|
893
|
-
disabled: !canSaveManual || onboardingInProgress,
|
|
894
|
-
onClick: handleSaveManual,
|
|
895
|
-
children: "Save credentials"
|
|
896
|
-
}
|
|
897
|
-
)
|
|
898
|
-
] })
|
|
899
|
-
] }) })
|
|
900
|
-
] }) })
|
|
901
|
-
] }),
|
|
902
|
-
/* @__PURE__ */ jsxRuntime.jsx("style", { children: `
|
|
903
|
-
.loader {
|
|
904
|
-
border: 3px solid #f3f3f3;
|
|
905
|
-
border-top: 3px solid #0070ba;
|
|
906
|
-
border-radius: 50%;
|
|
907
|
-
width: 18px;
|
|
908
|
-
height: 18px;
|
|
909
|
-
animation: spin 1s linear infinite;
|
|
910
|
-
display: inline-block;
|
|
911
|
-
vertical-align: middle;
|
|
912
|
-
margin-right: 8px;
|
|
913
|
-
}
|
|
914
|
-
@keyframes spin {
|
|
915
|
-
0% { transform: rotate(0deg); }
|
|
916
|
-
100% { transform: rotate(360deg); }
|
|
917
|
-
}
|
|
918
|
-
` })
|
|
919
|
-
] });
|
|
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
|
+
)
|
|
334
|
+
] })
|
|
335
|
+
}
|
|
336
|
+
)
|
|
337
|
+
] }) });
|
|
338
|
+
}
|
|
339
|
+
function PayPalApplePayPage() {
|
|
340
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
920
341
|
}
|
|
921
|
-
const EMPTY_FILTERS = {
|
|
922
|
-
dispute_id: "",
|
|
923
|
-
status: "",
|
|
924
|
-
order_id: "",
|
|
925
|
-
cart_id: ""
|
|
926
|
-
};
|
|
927
342
|
function formatDate$2(value) {
|
|
928
343
|
if (!value) {
|
|
929
344
|
return "";
|
|
@@ -934,566 +349,962 @@ function formatDate$2(value) {
|
|
|
934
349
|
}
|
|
935
350
|
return parsed.toLocaleString();
|
|
936
351
|
}
|
|
937
|
-
function
|
|
938
|
-
const [
|
|
939
|
-
const [disputes, setDisputes] = react.useState([]);
|
|
352
|
+
function PayPalAuditLogsPage() {
|
|
353
|
+
const [logs, setLogs] = react.useState([]);
|
|
940
354
|
const [loading, setLoading] = react.useState(false);
|
|
941
355
|
const [error, setError] = react.useState(null);
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
356
|
+
const fetchLogs = react.useCallback(async () => {
|
|
357
|
+
try {
|
|
358
|
+
setLoading(true);
|
|
359
|
+
setError(null);
|
|
360
|
+
const response = await fetch("/admin/paypal/audit-logs?limit=50", {
|
|
361
|
+
credentials: "include",
|
|
362
|
+
headers: {
|
|
363
|
+
Accept: "application/json"
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
if (!response.ok) {
|
|
367
|
+
const message = await response.text().catch(() => "");
|
|
368
|
+
throw new Error(message || "Failed to load audit logs.");
|
|
369
|
+
}
|
|
370
|
+
const data = await response.json().catch(() => ({}));
|
|
371
|
+
setLogs((data == null ? void 0 : data.logs) || []);
|
|
372
|
+
} catch (fetchError) {
|
|
373
|
+
setError((fetchError == null ? void 0 : fetchError.message) || "Failed to load audit logs.");
|
|
374
|
+
setLogs([]);
|
|
375
|
+
} finally {
|
|
376
|
+
setLoading(false);
|
|
377
|
+
}
|
|
378
|
+
}, []);
|
|
379
|
+
react.useEffect(() => {
|
|
380
|
+
fetchLogs();
|
|
381
|
+
}, [fetchLogs]);
|
|
382
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
383
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
384
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Audit Logs" }),
|
|
385
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-ui-fg-subtle", children: "Track administrative changes and credential events for PayPal configuration." })
|
|
386
|
+
] }),
|
|
387
|
+
/* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
|
|
388
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
|
|
389
|
+
/* @__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: [
|
|
390
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: "Latest events" }),
|
|
391
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
392
|
+
"button",
|
|
393
|
+
{
|
|
394
|
+
type: "button",
|
|
395
|
+
onClick: fetchLogs,
|
|
396
|
+
className: "rounded-md border border-ui-border-base px-3 py-2 text-sm text-ui-fg-base",
|
|
397
|
+
disabled: loading,
|
|
398
|
+
children: loading ? "Refreshing..." : "Refresh"
|
|
399
|
+
}
|
|
400
|
+
)
|
|
401
|
+
] }) }),
|
|
402
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
|
|
403
|
+
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,
|
|
404
|
+
!error && logs.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-ui-fg-subtle", children: loading ? "Loading audit logs..." : "No audit log entries found yet." }) : null,
|
|
405
|
+
logs.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full text-left text-sm", children: [
|
|
406
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "text-ui-fg-muted", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
407
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 pr-4 font-medium", children: "Timestamp" }),
|
|
408
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 pr-4 font-medium", children: "Event" }),
|
|
409
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 font-medium", children: "Details" })
|
|
410
|
+
] }) }),
|
|
411
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: logs.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-t border-ui-border-base", children: [
|
|
412
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: formatDate$2(entry.created_at) || "—" }),
|
|
413
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: entry.event_type || "—" }),
|
|
414
|
+
/* @__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) }) })
|
|
415
|
+
] }, entry.id)) })
|
|
416
|
+
] }) }) : null
|
|
417
|
+
] })
|
|
418
|
+
] })
|
|
419
|
+
] }) });
|
|
420
|
+
}
|
|
421
|
+
const DEFAULT_FORM = {
|
|
422
|
+
enabled: true,
|
|
423
|
+
title: "Credit or Debit Card",
|
|
424
|
+
disabledCards: [],
|
|
425
|
+
threeDS: "when_required",
|
|
426
|
+
cardSaveEnabled: false
|
|
427
|
+
};
|
|
428
|
+
function mergeWithDefaults(saved) {
|
|
429
|
+
if (!saved) return { ...DEFAULT_FORM };
|
|
430
|
+
const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
|
|
431
|
+
return {
|
|
432
|
+
...DEFAULT_FORM,
|
|
433
|
+
...Object.fromEntries(entries)
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
const CARD_BRANDS = [
|
|
437
|
+
{ value: "visa", label: "Visa" },
|
|
438
|
+
{ value: "mastercard", label: "Mastercard" },
|
|
439
|
+
{ value: "amex", label: "American Express" },
|
|
440
|
+
{ value: "discover", label: "Discover" },
|
|
441
|
+
{ value: "diners", label: "Diners Club" },
|
|
442
|
+
{ value: "jcb", label: "JCB" },
|
|
443
|
+
{ value: "unionpay", label: "UnionPay" }
|
|
444
|
+
];
|
|
445
|
+
const THREE_DS_OPTIONS = [
|
|
446
|
+
{
|
|
447
|
+
value: "when_required",
|
|
448
|
+
label: "3D Secure when required",
|
|
449
|
+
hint: "Triggers 3DS only when the card / issuer requires it."
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
value: "sli",
|
|
453
|
+
label: "3D Secure (SCA) / liability shift (recommended)",
|
|
454
|
+
hint: "Attempts to optimize for liability shift while remaining compliant."
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
value: "always",
|
|
458
|
+
label: "Always request 3D Secure",
|
|
459
|
+
hint: "Forces 3DS challenge whenever possible (may reduce conversion)."
|
|
460
|
+
}
|
|
461
|
+
];
|
|
462
|
+
function cx$1(...parts) {
|
|
463
|
+
return parts.filter(Boolean).join(" ");
|
|
464
|
+
}
|
|
465
|
+
function Pill$1({
|
|
466
|
+
children,
|
|
467
|
+
onRemove
|
|
468
|
+
}) {
|
|
469
|
+
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: [
|
|
470
|
+
children,
|
|
471
|
+
onRemove ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
472
|
+
"button",
|
|
473
|
+
{
|
|
474
|
+
type: "button",
|
|
475
|
+
onClick: onRemove,
|
|
476
|
+
className: "ml-1 rounded px-1 text-ui-fg-subtle hover:text-ui-fg-base",
|
|
477
|
+
"aria-label": "Remove",
|
|
478
|
+
children: "×"
|
|
479
|
+
}
|
|
480
|
+
) : null
|
|
481
|
+
] });
|
|
482
|
+
}
|
|
483
|
+
function SectionCard$1({
|
|
484
|
+
title,
|
|
485
|
+
description,
|
|
486
|
+
right,
|
|
487
|
+
children
|
|
488
|
+
}) {
|
|
489
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
|
|
490
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
|
|
491
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
492
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: title }),
|
|
493
|
+
description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-sm text-ui-fg-subtle", children: description }) : null
|
|
494
|
+
] }),
|
|
495
|
+
right
|
|
496
|
+
] }),
|
|
497
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children })
|
|
498
|
+
] });
|
|
499
|
+
}
|
|
500
|
+
function FieldRow$1({
|
|
501
|
+
label,
|
|
502
|
+
hint,
|
|
503
|
+
children
|
|
504
|
+
}) {
|
|
505
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
|
|
506
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 md:col-span-4", children: [
|
|
507
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
|
|
508
|
+
hint ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: hint }) : null
|
|
509
|
+
] }),
|
|
510
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-12 md:col-span-8", children })
|
|
511
|
+
] });
|
|
512
|
+
}
|
|
513
|
+
function AdvancedCardPaymentsTab() {
|
|
514
|
+
var _a, _b;
|
|
515
|
+
const [form, setForm] = react.useState(() => ({ ...DEFAULT_FORM }));
|
|
516
|
+
const [loading, setLoading] = react.useState(false);
|
|
517
|
+
const [saving, setSaving] = react.useState(false);
|
|
518
|
+
const [toast, setToast] = react.useState(null);
|
|
519
|
+
const didInit = react.useRef(false);
|
|
520
|
+
react.useEffect(() => {
|
|
521
|
+
if (didInit.current) return;
|
|
522
|
+
didInit.current = true;
|
|
523
|
+
(async () => {
|
|
524
|
+
try {
|
|
525
|
+
setLoading(true);
|
|
526
|
+
const r = await fetch("/admin/paypal/settings", {
|
|
527
|
+
credentials: "include",
|
|
528
|
+
headers: { "Accept": "application/json" }
|
|
529
|
+
});
|
|
530
|
+
if (!r.ok) return;
|
|
531
|
+
const json = await r.json();
|
|
532
|
+
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
533
|
+
const saved = payload == null ? void 0 : payload.advanced_card_payments;
|
|
534
|
+
if (saved && typeof saved === "object") {
|
|
535
|
+
setForm(mergeWithDefaults(saved));
|
|
536
|
+
}
|
|
537
|
+
} finally {
|
|
538
|
+
setLoading(false);
|
|
947
539
|
}
|
|
948
|
-
});
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
}, [filters]);
|
|
952
|
-
const fetchDisputes = react.useCallback(async (source) => {
|
|
540
|
+
})();
|
|
541
|
+
}, []);
|
|
542
|
+
async function onSave() {
|
|
953
543
|
try {
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
Object.entries(source).forEach(([key, value]) => {
|
|
958
|
-
if (value.trim()) {
|
|
959
|
-
params.set(key, value.trim());
|
|
960
|
-
}
|
|
961
|
-
});
|
|
962
|
-
const qs = params.toString();
|
|
963
|
-
const resp = await fetch(`/admin/paypal/disputes${qs ? `?${qs}` : ""}`, {
|
|
544
|
+
setSaving(true);
|
|
545
|
+
const r = await fetch("/admin/paypal/settings", {
|
|
546
|
+
method: "POST",
|
|
964
547
|
credentials: "include",
|
|
965
548
|
headers: {
|
|
966
|
-
|
|
967
|
-
|
|
549
|
+
"Content-Type": "application/json",
|
|
550
|
+
"Accept": "application/json"
|
|
551
|
+
},
|
|
552
|
+
body: JSON.stringify({ advanced_card_payments: form })
|
|
968
553
|
});
|
|
969
|
-
if (!
|
|
970
|
-
const
|
|
971
|
-
|
|
554
|
+
if (!r.ok) {
|
|
555
|
+
const t = await r.text();
|
|
556
|
+
setToast({ type: "error", message: "Failed to save settings. " + t });
|
|
557
|
+
window.setTimeout(() => setToast(null), 3500);
|
|
558
|
+
return;
|
|
972
559
|
}
|
|
973
|
-
const json = await
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
560
|
+
const json = await r.json().catch(() => null);
|
|
561
|
+
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
562
|
+
const saved = payload == null ? void 0 : payload.advanced_card_payments;
|
|
563
|
+
if (saved && typeof saved === "object") {
|
|
564
|
+
setForm(mergeWithDefaults(saved));
|
|
565
|
+
}
|
|
566
|
+
setToast({ type: "success", message: "Settings saved" });
|
|
567
|
+
window.setTimeout(() => setToast(null), 2500);
|
|
978
568
|
} finally {
|
|
979
|
-
|
|
569
|
+
setSaving(false);
|
|
980
570
|
}
|
|
981
|
-
}
|
|
982
|
-
react.
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
571
|
+
}
|
|
572
|
+
const disabledSet = react.useMemo(() => new Set(form.disabledCards), [form.disabledCards]);
|
|
573
|
+
function toggleDisabledCard(value) {
|
|
574
|
+
setForm((prev) => {
|
|
575
|
+
const exists = prev.disabledCards.includes(value);
|
|
576
|
+
return {
|
|
577
|
+
...prev,
|
|
578
|
+
disabledCards: exists ? prev.disabledCards.filter((v) => v !== value) : [...prev.disabledCards, value]
|
|
579
|
+
};
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
function removeDisabledCard(value) {
|
|
583
|
+
setForm((prev) => ({
|
|
584
|
+
...prev,
|
|
585
|
+
disabledCards: prev.disabledCards.filter((v) => v !== value)
|
|
586
|
+
}));
|
|
587
|
+
}
|
|
993
588
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
994
|
-
/* @__PURE__ */ jsxRuntime.
|
|
995
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Disputes" }),
|
|
996
|
-
/* @__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." })
|
|
997
|
-
] }),
|
|
589
|
+
/* @__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" }) }) }),
|
|
998
590
|
/* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
|
|
999
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex
|
|
1028
|
-
"Order ID",
|
|
1029
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1030
|
-
"input",
|
|
1031
|
-
{
|
|
1032
|
-
className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
|
|
1033
|
-
value: filters.order_id,
|
|
1034
|
-
onChange: (event) => setFilters((prev) => ({ ...prev, order_id: event.target.value })),
|
|
1035
|
-
placeholder: "order_..."
|
|
1036
|
-
}
|
|
1037
|
-
)
|
|
1038
|
-
] }),
|
|
1039
|
-
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
|
|
1040
|
-
"Cart ID",
|
|
591
|
+
toast ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
592
|
+
"div",
|
|
593
|
+
{
|
|
594
|
+
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",
|
|
595
|
+
role: "status",
|
|
596
|
+
"aria-live": "polite",
|
|
597
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: toast.type === "success" ? "text-ui-fg-base" : "text-ui-fg-error", children: toast.message })
|
|
598
|
+
}
|
|
599
|
+
) : null,
|
|
600
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
601
|
+
SectionCard$1,
|
|
602
|
+
{
|
|
603
|
+
title: "Advanced Card Payments",
|
|
604
|
+
description: "Control card checkout settings, 3D Secure behavior, and card saving.",
|
|
605
|
+
right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
606
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
607
|
+
"button",
|
|
608
|
+
{
|
|
609
|
+
type: "button",
|
|
610
|
+
onClick: onSave,
|
|
611
|
+
disabled: saving || loading,
|
|
612
|
+
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",
|
|
613
|
+
children: saving ? "Saving..." : "Save settings"
|
|
614
|
+
}
|
|
615
|
+
),
|
|
616
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading…" }) : null
|
|
617
|
+
] }),
|
|
618
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
|
|
619
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Enable/Disable", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
1041
620
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1042
621
|
"input",
|
|
1043
622
|
{
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
onChange: (
|
|
1047
|
-
|
|
623
|
+
type: "checkbox",
|
|
624
|
+
checked: form.enabled,
|
|
625
|
+
onChange: (e) => setForm((p) => ({ ...p, enabled: e.target.checked })),
|
|
626
|
+
className: "h-4 w-4 rounded border-ui-border-base"
|
|
1048
627
|
}
|
|
1049
|
-
)
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
628
|
+
),
|
|
629
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable Advanced Credit/Debit Card" })
|
|
630
|
+
] }) }),
|
|
631
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Title", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
632
|
+
"input",
|
|
633
|
+
{
|
|
634
|
+
value: form.title,
|
|
635
|
+
onChange: (e) => setForm((p) => ({ ...p, title: e.target.value })),
|
|
636
|
+
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",
|
|
637
|
+
placeholder: "Credit or Debit Card"
|
|
638
|
+
}
|
|
639
|
+
) }),
|
|
1053
640
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1054
|
-
|
|
641
|
+
FieldRow$1,
|
|
1055
642
|
{
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
643
|
+
label: "Disable specific credit cards",
|
|
644
|
+
hint: "Select card brands to hide from the card form.",
|
|
645
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
646
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: form.disabledCards.length ? form.disabledCards.map((v) => {
|
|
647
|
+
var _a2;
|
|
648
|
+
const label = ((_a2 = CARD_BRANDS.find((b) => b.value === v)) == null ? void 0 : _a2.label) ?? v;
|
|
649
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Pill$1, { onRemove: () => removeDisabledCard(v), children: label }, v);
|
|
650
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "No card brands disabled." }) }),
|
|
651
|
+
/* @__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) => {
|
|
652
|
+
const checked = disabledSet.has(b.value);
|
|
653
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
654
|
+
"label",
|
|
655
|
+
{
|
|
656
|
+
className: cx$1(
|
|
657
|
+
"flex items-center gap-2 rounded-md p-2",
|
|
658
|
+
"hover:bg-ui-bg-subtle"
|
|
659
|
+
),
|
|
660
|
+
children: [
|
|
661
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
662
|
+
"input",
|
|
663
|
+
{
|
|
664
|
+
type: "checkbox",
|
|
665
|
+
checked,
|
|
666
|
+
onChange: () => toggleDisabledCard(b.value),
|
|
667
|
+
className: "h-4 w-4 rounded border-ui-border-base"
|
|
668
|
+
}
|
|
669
|
+
),
|
|
670
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: b.label })
|
|
671
|
+
]
|
|
672
|
+
},
|
|
673
|
+
b.value
|
|
674
|
+
);
|
|
675
|
+
}) }) })
|
|
676
|
+
] })
|
|
1060
677
|
}
|
|
1061
678
|
),
|
|
1062
679
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1063
|
-
|
|
680
|
+
FieldRow$1,
|
|
1064
681
|
{
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
682
|
+
label: "Contingency for 3D Secure",
|
|
683
|
+
hint: "Choose when 3D Secure should be triggered during card payments.",
|
|
684
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
685
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
686
|
+
"select",
|
|
687
|
+
{
|
|
688
|
+
value: form.threeDS,
|
|
689
|
+
onChange: (e) => setForm((p) => ({ ...p, threeDS: e.target.value })),
|
|
690
|
+
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",
|
|
691
|
+
children: THREE_DS_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
|
|
692
|
+
}
|
|
693
|
+
),
|
|
694
|
+
((_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
|
|
695
|
+
] })
|
|
1070
696
|
}
|
|
1071
697
|
),
|
|
1072
|
-
/* @__PURE__ */ jsxRuntime.jsxs("
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
698
|
+
/* @__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: [
|
|
699
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
700
|
+
"input",
|
|
701
|
+
{
|
|
702
|
+
type: "checkbox",
|
|
703
|
+
checked: form.cardSaveEnabled,
|
|
704
|
+
onChange: (e) => setForm((p) => ({ ...p, cardSaveEnabled: e.target.checked })),
|
|
705
|
+
className: "h-4 w-4 rounded border-ui-border-base"
|
|
706
|
+
}
|
|
707
|
+
),
|
|
708
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable card saving at checkout" })
|
|
709
|
+
] }) })
|
|
1079
710
|
] })
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
|
|
1083
|
-
/* @__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" }) }),
|
|
1084
|
-
/* @__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: [
|
|
1085
|
-
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "text-left text-ui-fg-subtle", children: [
|
|
1086
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Dispute" }),
|
|
1087
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Status" }),
|
|
1088
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Reason" }),
|
|
1089
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Stage" }),
|
|
1090
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Amount" }),
|
|
1091
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Order" }),
|
|
1092
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Cart" }),
|
|
1093
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Updated" })
|
|
1094
|
-
] }) }),
|
|
1095
|
-
/* @__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: [
|
|
1096
|
-
/* @__PURE__ */ jsxRuntime.jsxs("td", { className: "px-4 py-3", children: [
|
|
1097
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-ui-fg-base", children: dispute.dispute_id }),
|
|
1098
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-ui-fg-subtle", children: dispute.transaction_id || "No transaction" })
|
|
1099
|
-
] }),
|
|
1100
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.status || "Unknown" }),
|
|
1101
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.reason || "-" }),
|
|
1102
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.stage || "-" }),
|
|
1103
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.amount ? `${dispute.amount} ${dispute.currency_code || ""}` : "-" }),
|
|
1104
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.order_id || "-" }),
|
|
1105
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.cart_id || "-" }),
|
|
1106
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 text-ui-fg-subtle", children: formatDate$2(dispute.updated_at || dispute.created_at) })
|
|
1107
|
-
] }, dispute.id)) })
|
|
1108
|
-
] }) }),
|
|
1109
|
-
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
|
|
1110
|
-
] })
|
|
711
|
+
}
|
|
712
|
+
)
|
|
1111
713
|
] }) });
|
|
1112
714
|
}
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
715
|
+
const config = adminSdk.defineRouteConfig({
|
|
716
|
+
label: "PayPal Connection",
|
|
717
|
+
hide: true
|
|
718
|
+
});
|
|
719
|
+
if (typeof window !== "undefined") {
|
|
720
|
+
const preloadHref = "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js";
|
|
721
|
+
const existingPreload = document.head.querySelector(
|
|
722
|
+
`link[rel="preload"][href="${preloadHref}"]`
|
|
723
|
+
);
|
|
724
|
+
if (!existingPreload) {
|
|
725
|
+
const preloadLink = document.createElement("link");
|
|
726
|
+
preloadLink.rel = "preload";
|
|
727
|
+
preloadLink.href = preloadHref;
|
|
728
|
+
preloadLink.as = "script";
|
|
729
|
+
document.head.appendChild(preloadLink);
|
|
1119
730
|
}
|
|
1120
|
-
const
|
|
1121
|
-
|
|
1122
|
-
|
|
731
|
+
const existingScript = document.getElementById(
|
|
732
|
+
"paypal-partner-js"
|
|
733
|
+
);
|
|
734
|
+
if (!existingScript) {
|
|
735
|
+
const ppScript = document.createElement("script");
|
|
736
|
+
ppScript.id = "paypal-partner-js";
|
|
737
|
+
ppScript.src = preloadHref;
|
|
738
|
+
ppScript.async = true;
|
|
739
|
+
document.head.appendChild(ppScript);
|
|
1123
740
|
}
|
|
1124
|
-
return parsed.toLocaleString();
|
|
1125
741
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
if (
|
|
1141
|
-
|
|
1142
|
-
throw new Error(message || "Failed to load audit logs.");
|
|
742
|
+
const SERVICE_URL = "/admin/paypal/onboarding-link";
|
|
743
|
+
const CACHE_KEY = "pp_onboard_cache";
|
|
744
|
+
const RELOAD_KEY = "pp_onboard_reloaded_once";
|
|
745
|
+
const CACHE_EXPIRY = 10 * 60 * 1e3;
|
|
746
|
+
const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
|
|
747
|
+
const STATUS_ENDPOINT = "/admin/paypal/status";
|
|
748
|
+
const SAVE_CREDENTIALS_ENDPOINT = "/admin/paypal/save-credentials";
|
|
749
|
+
const DISCONNECT_ENDPOINT = "/admin/paypal/disconnect";
|
|
750
|
+
let cachedUrl = null;
|
|
751
|
+
if (typeof window !== "undefined") {
|
|
752
|
+
try {
|
|
753
|
+
const cached = localStorage.getItem(CACHE_KEY);
|
|
754
|
+
if (cached) {
|
|
755
|
+
const data = JSON.parse(cached);
|
|
756
|
+
if ((/* @__PURE__ */ new Date()).getTime() - data.ts < CACHE_EXPIRY) {
|
|
757
|
+
cachedUrl = data.url;
|
|
1143
758
|
}
|
|
1144
|
-
const data = await response.json().catch(() => ({}));
|
|
1145
|
-
setLogs((data == null ? void 0 : data.logs) || []);
|
|
1146
|
-
} catch (fetchError) {
|
|
1147
|
-
setError((fetchError == null ? void 0 : fetchError.message) || "Failed to load audit logs.");
|
|
1148
|
-
setLogs([]);
|
|
1149
|
-
} finally {
|
|
1150
|
-
setLoading(false);
|
|
1151
759
|
}
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
}, [fetchLogs]);
|
|
1156
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
1157
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1158
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Audit Logs" }),
|
|
1159
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-ui-fg-subtle", children: "Track administrative changes and credential events for PayPal configuration." })
|
|
1160
|
-
] }),
|
|
1161
|
-
/* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
|
|
1162
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
|
|
1163
|
-
/* @__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: [
|
|
1164
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: "Latest events" }),
|
|
1165
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1166
|
-
"button",
|
|
1167
|
-
{
|
|
1168
|
-
type: "button",
|
|
1169
|
-
onClick: fetchLogs,
|
|
1170
|
-
className: "rounded-md border border-ui-border-base px-3 py-2 text-sm text-ui-fg-base",
|
|
1171
|
-
disabled: loading,
|
|
1172
|
-
children: loading ? "Refreshing..." : "Refresh"
|
|
1173
|
-
}
|
|
1174
|
-
)
|
|
1175
|
-
] }) }),
|
|
1176
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
|
|
1177
|
-
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,
|
|
1178
|
-
!error && logs.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-ui-fg-subtle", children: loading ? "Loading audit logs..." : "No audit log entries found yet." }) : null,
|
|
1179
|
-
logs.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full text-left text-sm", children: [
|
|
1180
|
-
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "text-ui-fg-muted", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
1181
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 pr-4 font-medium", children: "Timestamp" }),
|
|
1182
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 pr-4 font-medium", children: "Event" }),
|
|
1183
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "pb-2 font-medium", children: "Details" })
|
|
1184
|
-
] }) }),
|
|
1185
|
-
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: logs.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-t border-ui-border-base", children: [
|
|
1186
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: formatDate$1(entry.created_at) || "—" }),
|
|
1187
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "py-3 pr-4 text-ui-fg-base", children: entry.event_type || "—" }),
|
|
1188
|
-
/* @__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) }) })
|
|
1189
|
-
] }, entry.id)) })
|
|
1190
|
-
] }) }) : null
|
|
1191
|
-
] })
|
|
1192
|
-
] })
|
|
1193
|
-
] }) });
|
|
1194
|
-
}
|
|
1195
|
-
function PayPalGooglePayPage() {
|
|
1196
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
1197
|
-
}
|
|
1198
|
-
const DEFAULT_FORM = {
|
|
1199
|
-
paymentAction: "capture",
|
|
1200
|
-
brandName: "PayPal",
|
|
1201
|
-
landingPage: "no_preference",
|
|
1202
|
-
requireInstantPayment: false,
|
|
1203
|
-
useShippingAsBilling: true,
|
|
1204
|
-
sendItemDetails: true,
|
|
1205
|
-
skipOrderReviewPage: true,
|
|
1206
|
-
invoicePrefix: "WC-",
|
|
1207
|
-
creditCardStatementName: "PayPal",
|
|
1208
|
-
enableLogging: true,
|
|
1209
|
-
logPath: "/uploads/wc-logs/"
|
|
1210
|
-
};
|
|
1211
|
-
function mergeWithDefaults(saved) {
|
|
1212
|
-
if (!saved) return { ...DEFAULT_FORM };
|
|
1213
|
-
const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
|
|
1214
|
-
return {
|
|
1215
|
-
...DEFAULT_FORM,
|
|
1216
|
-
...Object.fromEntries(entries)
|
|
1217
|
-
};
|
|
1218
|
-
}
|
|
1219
|
-
function SectionCard$1({
|
|
1220
|
-
title,
|
|
1221
|
-
description,
|
|
1222
|
-
right,
|
|
1223
|
-
children
|
|
1224
|
-
}) {
|
|
1225
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
|
|
1226
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
|
|
1227
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1228
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: title }),
|
|
1229
|
-
description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-sm text-ui-fg-subtle", children: description }) : null
|
|
1230
|
-
] }),
|
|
1231
|
-
right
|
|
1232
|
-
] }),
|
|
1233
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children })
|
|
1234
|
-
] });
|
|
1235
|
-
}
|
|
1236
|
-
function FieldRow$1({
|
|
1237
|
-
label,
|
|
1238
|
-
hint,
|
|
1239
|
-
children
|
|
1240
|
-
}) {
|
|
1241
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
|
|
1242
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 md:col-span-4", children: [
|
|
1243
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
|
|
1244
|
-
hint ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: hint }) : null
|
|
1245
|
-
] }),
|
|
1246
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-12 md:col-span-8", children })
|
|
1247
|
-
] });
|
|
760
|
+
} catch (e) {
|
|
761
|
+
console.error("Cache read error:", e);
|
|
762
|
+
}
|
|
1248
763
|
}
|
|
1249
|
-
function
|
|
1250
|
-
const [
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
764
|
+
function PayPalConnectionPage() {
|
|
765
|
+
const [env, setEnv] = react.useState("sandbox");
|
|
766
|
+
react.useEffect(() => {
|
|
767
|
+
fetch("/admin/paypal/environment", { method: "GET" }).then((r) => r.json()).then((d) => {
|
|
768
|
+
const v = (d == null ? void 0 : d.environment) === "live" ? "live" : "sandbox";
|
|
769
|
+
setEnv(v);
|
|
770
|
+
}).catch(() => {
|
|
771
|
+
});
|
|
772
|
+
}, []);
|
|
773
|
+
const [connState, setConnState] = react.useState("loading");
|
|
774
|
+
const [error, setError] = react.useState(null);
|
|
775
|
+
const [finalUrl, setFinalUrl] = react.useState("");
|
|
776
|
+
const [showManual, setShowManual] = react.useState(false);
|
|
777
|
+
const [clientId, setClientId] = react.useState("");
|
|
778
|
+
const [secret, setSecret] = react.useState("");
|
|
779
|
+
const [merchantId, setMerchantId] = react.useState("");
|
|
780
|
+
const [statusInfo, setStatusInfo] = react.useState(null);
|
|
781
|
+
const [onboardingInProgress, setOnboardingInProgress] = react.useState(false);
|
|
782
|
+
const initLoaderRef = react.useRef(null);
|
|
783
|
+
const paypalButtonRef = react.useRef(null);
|
|
784
|
+
const errorLogRef = react.useRef(null);
|
|
785
|
+
const runIdRef = react.useRef(0);
|
|
786
|
+
const currentRunId = react.useRef(0);
|
|
787
|
+
const ppBtnMeasureRef = react.useRef(null);
|
|
788
|
+
const [ppBtnWidth, setPpBtnWidth] = react.useState(null);
|
|
789
|
+
const canSaveManual = react.useMemo(() => {
|
|
790
|
+
return clientId.trim().length > 0 && secret.trim().length > 0;
|
|
791
|
+
}, [clientId, secret]);
|
|
792
|
+
const maskValue = react.useCallback((value, visibleChars = 4) => {
|
|
793
|
+
if (!value) return "";
|
|
794
|
+
if (value.length <= visibleChars) {
|
|
795
|
+
return "•".repeat(value.length);
|
|
796
|
+
}
|
|
797
|
+
return `${"•".repeat(Math.max(0, value.length - visibleChars))}${value.slice(
|
|
798
|
+
-visibleChars
|
|
799
|
+
)}`;
|
|
800
|
+
}, []);
|
|
801
|
+
const fetchFreshLink = react.useCallback(
|
|
802
|
+
(runId) => {
|
|
803
|
+
if (initLoaderRef.current) {
|
|
804
|
+
const loaderText = initLoaderRef.current.querySelector("#loader-text");
|
|
805
|
+
if (loaderText)
|
|
806
|
+
loaderText.textContent = "Generating onboarding session...";
|
|
807
|
+
}
|
|
808
|
+
fetch(SERVICE_URL, {
|
|
809
|
+
method: "POST",
|
|
810
|
+
headers: { "content-type": "application/json" },
|
|
811
|
+
body: JSON.stringify({
|
|
812
|
+
products: ["PPCP"]
|
|
813
|
+
})
|
|
814
|
+
}).then((r) => r.json()).then((data) => {
|
|
815
|
+
if (runId !== currentRunId.current) return;
|
|
816
|
+
const href = data == null ? void 0 : data.onboarding_url;
|
|
817
|
+
if (!href) {
|
|
818
|
+
showError("Onboarding URL not returned.");
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
const finalUrl2 = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
|
|
822
|
+
localStorage.setItem(
|
|
823
|
+
CACHE_KEY,
|
|
824
|
+
JSON.stringify({
|
|
825
|
+
url: finalUrl2,
|
|
826
|
+
ts: Date.now()
|
|
827
|
+
})
|
|
828
|
+
);
|
|
829
|
+
if (!localStorage.getItem(RELOAD_KEY)) {
|
|
830
|
+
localStorage.setItem(RELOAD_KEY, "1");
|
|
831
|
+
window.location.reload();
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
activatePayPal(finalUrl2, runId);
|
|
835
|
+
}).catch(() => {
|
|
836
|
+
if (runId !== currentRunId.current) return;
|
|
837
|
+
showError("Unable to connect to service.");
|
|
838
|
+
});
|
|
839
|
+
},
|
|
840
|
+
[env]
|
|
841
|
+
);
|
|
842
|
+
const showUI = react.useCallback(() => {
|
|
843
|
+
var _a, _b, _c, _d;
|
|
844
|
+
const btn = document.querySelector('[data-paypal-button="true"]');
|
|
845
|
+
if (btn && ((_d = (_c = (_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) == null ? void 0 : _c.miniBrowser) == null ? void 0 : _d.init)) {
|
|
846
|
+
window.PAYPAL.apps.Signup.miniBrowser.init();
|
|
847
|
+
}
|
|
848
|
+
setConnState("ready");
|
|
849
|
+
}, []);
|
|
850
|
+
const showError = react.useCallback((msg) => {
|
|
851
|
+
setConnState("error");
|
|
852
|
+
setError(msg);
|
|
853
|
+
}, []);
|
|
854
|
+
const activatePayPal = react.useCallback(
|
|
855
|
+
(url, runId) => {
|
|
856
|
+
if (paypalButtonRef.current) {
|
|
857
|
+
paypalButtonRef.current.href = url;
|
|
858
|
+
}
|
|
859
|
+
setFinalUrl(url);
|
|
860
|
+
const tryInit = () => {
|
|
861
|
+
var _a, _b;
|
|
862
|
+
if (runId !== currentRunId.current) return;
|
|
863
|
+
if ((_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) {
|
|
864
|
+
showUI();
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
setTimeout(tryInit, 50);
|
|
868
|
+
};
|
|
869
|
+
tryInit();
|
|
870
|
+
},
|
|
871
|
+
[showUI]
|
|
872
|
+
);
|
|
1254
873
|
react.useEffect(() => {
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
874
|
+
currentRunId.current = ++runIdRef.current;
|
|
875
|
+
const runId = currentRunId.current;
|
|
876
|
+
let cancelled = false;
|
|
877
|
+
const run = async () => {
|
|
878
|
+
setConnState("loading");
|
|
879
|
+
setError(null);
|
|
880
|
+
setFinalUrl("");
|
|
1258
881
|
try {
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
credentials: "include",
|
|
1262
|
-
headers: { "Accept": "application/json" }
|
|
882
|
+
const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
883
|
+
method: "GET"
|
|
1263
884
|
});
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
const
|
|
1268
|
-
if (
|
|
1269
|
-
|
|
885
|
+
const st = await r.json().catch(() => ({}));
|
|
886
|
+
if (cancelled || runId !== currentRunId.current) return;
|
|
887
|
+
setStatusInfo(st);
|
|
888
|
+
const isConnected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
|
|
889
|
+
if (isConnected) {
|
|
890
|
+
setConnState("connected");
|
|
891
|
+
setShowManual(false);
|
|
892
|
+
return;
|
|
1270
893
|
}
|
|
1271
|
-
}
|
|
1272
|
-
|
|
894
|
+
} catch (e) {
|
|
895
|
+
console.error(e);
|
|
1273
896
|
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
897
|
+
if (cachedUrl) {
|
|
898
|
+
console.log("Using prioritized cache...");
|
|
899
|
+
activatePayPal(cachedUrl, runId);
|
|
900
|
+
} else {
|
|
901
|
+
fetchFreshLink(runId);
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
run();
|
|
905
|
+
return () => {
|
|
906
|
+
cancelled = true;
|
|
907
|
+
currentRunId.current = 0;
|
|
908
|
+
};
|
|
909
|
+
}, [env, fetchFreshLink, activatePayPal]);
|
|
910
|
+
react.useLayoutEffect(() => {
|
|
911
|
+
window.onboardingCallback = async function(authCode, sharedId) {
|
|
912
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
913
|
+
try {
|
|
914
|
+
;
|
|
915
|
+
window.onbeforeunload = "";
|
|
916
|
+
} catch {
|
|
917
|
+
}
|
|
918
|
+
setOnboardingInProgress(true);
|
|
919
|
+
setConnState("loading");
|
|
920
|
+
setError(null);
|
|
921
|
+
const payload = {
|
|
922
|
+
authCode,
|
|
923
|
+
sharedId,
|
|
924
|
+
env: env === "sandbox" ? "sandbox" : "live"
|
|
925
|
+
};
|
|
926
|
+
try {
|
|
927
|
+
const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
|
|
928
|
+
method: "POST",
|
|
929
|
+
headers: { "content-type": "application/json" },
|
|
930
|
+
body: JSON.stringify(payload)
|
|
931
|
+
});
|
|
932
|
+
if (!res.ok) {
|
|
933
|
+
const txt = await res.text().catch(() => "");
|
|
934
|
+
throw new Error(txt || `Onboarding exchange failed (${res.status})`);
|
|
935
|
+
}
|
|
936
|
+
try {
|
|
937
|
+
const close1 = (_d = (_c = (_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) == null ? void 0 : _c.MiniBrowser) == null ? void 0 : _d.closeFlow;
|
|
938
|
+
if (typeof close1 === "function") close1();
|
|
939
|
+
} catch {
|
|
940
|
+
}
|
|
941
|
+
try {
|
|
942
|
+
const close2 = ((_g = (_f = (_e = window.PAYPAL) == null ? void 0 : _e.apps) == null ? void 0 : _f.Signup) == null ? void 0 : _g.miniBrowser) && window.PAYPAL.apps.Signup.miniBrowser.closeFlow;
|
|
943
|
+
if (typeof close2 === "function") close2();
|
|
944
|
+
} catch {
|
|
945
|
+
}
|
|
946
|
+
try {
|
|
947
|
+
localStorage.removeItem(CACHE_KEY);
|
|
948
|
+
localStorage.removeItem(RELOAD_KEY);
|
|
949
|
+
} catch {
|
|
950
|
+
}
|
|
951
|
+
window.location.href = window.location.href;
|
|
952
|
+
} catch (e) {
|
|
953
|
+
console.error(e);
|
|
954
|
+
setConnState("error");
|
|
955
|
+
setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
|
|
956
|
+
setOnboardingInProgress(false);
|
|
957
|
+
}
|
|
958
|
+
};
|
|
959
|
+
return () => {
|
|
960
|
+
window.onboardingCallback = void 0;
|
|
961
|
+
};
|
|
962
|
+
}, [env]);
|
|
963
|
+
react.useLayoutEffect(() => {
|
|
964
|
+
const el = ppBtnMeasureRef.current;
|
|
965
|
+
if (!el) return;
|
|
966
|
+
const update = () => {
|
|
967
|
+
const w = Math.round(el.getBoundingClientRect().width || 0);
|
|
968
|
+
if (w > 0) setPpBtnWidth(w);
|
|
969
|
+
};
|
|
970
|
+
update();
|
|
971
|
+
let ro = null;
|
|
972
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
973
|
+
ro = new ResizeObserver(() => update());
|
|
974
|
+
ro.observe(el);
|
|
975
|
+
} else {
|
|
976
|
+
window.addEventListener("resize", update);
|
|
977
|
+
}
|
|
978
|
+
return () => {
|
|
979
|
+
if (ro) ro.disconnect();
|
|
980
|
+
else window.removeEventListener("resize", update);
|
|
981
|
+
};
|
|
982
|
+
}, [connState, env, finalUrl]);
|
|
983
|
+
const handleConnectClick = (e) => {
|
|
984
|
+
if (connState !== "ready" || !finalUrl || onboardingInProgress) {
|
|
985
|
+
e.preventDefault();
|
|
986
|
+
}
|
|
987
|
+
};
|
|
988
|
+
const handleSaveManual = async () => {
|
|
989
|
+
if (!canSaveManual || onboardingInProgress) return;
|
|
990
|
+
setOnboardingInProgress(true);
|
|
991
|
+
setConnState("loading");
|
|
992
|
+
setError(null);
|
|
1278
993
|
try {
|
|
1279
|
-
|
|
1280
|
-
setToast(null);
|
|
1281
|
-
const r = await fetch("/admin/paypal/settings", {
|
|
994
|
+
const res = await fetch(SAVE_CREDENTIALS_ENDPOINT, {
|
|
1282
995
|
method: "POST",
|
|
1283
|
-
|
|
1284
|
-
headers: {
|
|
1285
|
-
"Content-Type": "application/json",
|
|
1286
|
-
"Accept": "application/json"
|
|
1287
|
-
},
|
|
996
|
+
headers: { "content-type": "application/json" },
|
|
1288
997
|
body: JSON.stringify({
|
|
1289
|
-
|
|
998
|
+
clientId: clientId.trim(),
|
|
999
|
+
clientSecret: secret.trim()
|
|
1290
1000
|
})
|
|
1291
1001
|
});
|
|
1292
|
-
if (!
|
|
1293
|
-
const
|
|
1294
|
-
throw new Error(
|
|
1002
|
+
if (!res.ok) {
|
|
1003
|
+
const txt = await res.text().catch(() => "");
|
|
1004
|
+
throw new Error(txt || `Save credentials failed (${res.status})`);
|
|
1295
1005
|
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1006
|
+
setConnState("connected");
|
|
1007
|
+
setStatusInfo({
|
|
1008
|
+
seller_client_id_masked: maskValue(clientId.trim()),
|
|
1009
|
+
seller_client_secret_masked: "••••••••"
|
|
1010
|
+
});
|
|
1011
|
+
setShowManual(false);
|
|
1012
|
+
try {
|
|
1013
|
+
localStorage.removeItem(CACHE_KEY);
|
|
1014
|
+
localStorage.removeItem(RELOAD_KEY);
|
|
1015
|
+
} catch {
|
|
1016
|
+
}
|
|
1017
|
+
} catch (e) {
|
|
1018
|
+
console.error(e);
|
|
1019
|
+
setConnState("error");
|
|
1020
|
+
setError((e == null ? void 0 : e.message) || "Failed to save credentials.");
|
|
1021
|
+
} finally {
|
|
1022
|
+
setOnboardingInProgress(false);
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
const handleDisconnect = async () => {
|
|
1026
|
+
if (onboardingInProgress) return;
|
|
1027
|
+
if (!window.confirm("Disconnect PayPal for this environment?")) return;
|
|
1028
|
+
setOnboardingInProgress(true);
|
|
1029
|
+
setConnState("loading");
|
|
1030
|
+
setError(null);
|
|
1031
|
+
setFinalUrl("");
|
|
1032
|
+
setShowManual(false);
|
|
1033
|
+
try {
|
|
1034
|
+
const res = await fetch(DISCONNECT_ENDPOINT, {
|
|
1035
|
+
method: "POST",
|
|
1036
|
+
headers: { "content-type": "application/json" },
|
|
1037
|
+
body: JSON.stringify({ environment: env })
|
|
1038
|
+
});
|
|
1039
|
+
if (!res.ok) {
|
|
1040
|
+
const t = await res.text().catch(() => "");
|
|
1041
|
+
throw new Error(t || `Disconnect failed (${res.status})`);
|
|
1301
1042
|
}
|
|
1302
|
-
|
|
1303
|
-
|
|
1043
|
+
try {
|
|
1044
|
+
localStorage.removeItem(CACHE_KEY);
|
|
1045
|
+
localStorage.removeItem(RELOAD_KEY);
|
|
1046
|
+
} catch {
|
|
1047
|
+
}
|
|
1048
|
+
currentRunId.current = ++runIdRef.current;
|
|
1049
|
+
const runId = currentRunId.current;
|
|
1050
|
+
fetchFreshLink(runId);
|
|
1304
1051
|
} catch (e) {
|
|
1305
|
-
|
|
1306
|
-
|
|
1052
|
+
console.error(e);
|
|
1053
|
+
setConnState("error");
|
|
1054
|
+
setError((e == null ? void 0 : e.message) || "Failed to disconnect.");
|
|
1307
1055
|
} finally {
|
|
1308
|
-
|
|
1056
|
+
setOnboardingInProgress(false);
|
|
1309
1057
|
}
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
{
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1058
|
+
};
|
|
1059
|
+
const handleEnvChange = async (e) => {
|
|
1060
|
+
const next = e.target.value;
|
|
1061
|
+
setEnv(next);
|
|
1062
|
+
cachedUrl = null;
|
|
1063
|
+
try {
|
|
1064
|
+
await fetch("/admin/paypal/environment", {
|
|
1065
|
+
method: "POST",
|
|
1066
|
+
headers: { "content-type": "application/json" },
|
|
1067
|
+
body: JSON.stringify({ environment: next })
|
|
1068
|
+
});
|
|
1069
|
+
} catch {
|
|
1070
|
+
}
|
|
1071
|
+
try {
|
|
1072
|
+
localStorage.removeItem(CACHE_KEY);
|
|
1073
|
+
localStorage.removeItem(RELOAD_KEY);
|
|
1074
|
+
} catch {
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6", children: [
|
|
1078
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
1079
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold", children: "PayPal Gateway By Easy Payment" }),
|
|
1080
|
+
/* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
|
|
1081
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-ui-border-base p-4 shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-y-6 md:grid-cols-[260px_1fr] md:items-start", children: [
|
|
1082
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium pt-2", children: "Environment" }),
|
|
1083
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xl", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1084
|
+
"select",
|
|
1085
|
+
{
|
|
1086
|
+
value: env,
|
|
1087
|
+
onChange: handleEnvChange,
|
|
1088
|
+
disabled: onboardingInProgress,
|
|
1089
|
+
className: "w-full rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm",
|
|
1090
|
+
children: [
|
|
1091
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "sandbox", children: "Sandbox (Test Mode)" }),
|
|
1092
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "live", children: "Live (Production)" })
|
|
1093
|
+
]
|
|
1094
|
+
}
|
|
1095
|
+
) }),
|
|
1096
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium pt-2", children: env === "sandbox" ? "Connect to PayPal Sandbox" : "Connect to PayPal Live" }),
|
|
1097
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xl", children: connState === "connected" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1098
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: [
|
|
1099
|
+
"✅ Successfully connected to PayPal!",
|
|
1100
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1101
|
+
"a",
|
|
1102
|
+
{
|
|
1103
|
+
"data-paypal-button": "true",
|
|
1104
|
+
"data-paypal-onboard-complete": "onboardingCallback",
|
|
1105
|
+
href: "#",
|
|
1106
|
+
style: { display: "none" },
|
|
1107
|
+
children: "PayPal"
|
|
1108
|
+
}
|
|
1109
|
+
)
|
|
1110
|
+
] }),
|
|
1111
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 rounded-md border border-ui-border-base bg-ui-bg-subtle p-3 text-xs text-ui-fg-subtle", children: [
|
|
1112
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-ui-fg-base", children: "Connected PayPal account" }),
|
|
1113
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1", children: [
|
|
1114
|
+
"Email:",
|
|
1115
|
+
" ",
|
|
1116
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-ui-fg-base", children: (statusInfo == null ? void 0 : statusInfo.seller_email) || "Unavailable" })
|
|
1117
|
+
] })
|
|
1118
|
+
] }),
|
|
1119
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1330
1120
|
"button",
|
|
1331
1121
|
{
|
|
1332
1122
|
type: "button",
|
|
1333
|
-
onClick:
|
|
1334
|
-
disabled:
|
|
1335
|
-
className: "rounded-md
|
|
1336
|
-
children:
|
|
1337
|
-
}
|
|
1338
|
-
),
|
|
1339
|
-
loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading…" }) : null
|
|
1340
|
-
] }),
|
|
1341
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
|
|
1342
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Payment action", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1343
|
-
"select",
|
|
1344
|
-
{
|
|
1345
|
-
value: form.paymentAction,
|
|
1346
|
-
onChange: (e) => setForm((p) => ({ ...p, paymentAction: e.target.value })),
|
|
1347
|
-
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",
|
|
1348
|
-
children: [
|
|
1349
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "capture", children: "Capture" }),
|
|
1350
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "authorize", children: "Authorize" })
|
|
1351
|
-
]
|
|
1352
|
-
}
|
|
1353
|
-
) }),
|
|
1354
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Brand Name", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1355
|
-
"input",
|
|
1356
|
-
{
|
|
1357
|
-
value: form.brandName,
|
|
1358
|
-
onChange: (e) => setForm((p) => ({ ...p, brandName: e.target.value })),
|
|
1359
|
-
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",
|
|
1360
|
-
placeholder: "PayPal"
|
|
1123
|
+
onClick: handleDisconnect,
|
|
1124
|
+
disabled: onboardingInProgress,
|
|
1125
|
+
className: "rounded-md border border-ui-border-base px-3 py-2 text-sm font-medium hover:bg-ui-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1126
|
+
children: "Disconnect"
|
|
1361
1127
|
}
|
|
1362
|
-
) })
|
|
1363
|
-
|
|
1364
|
-
|
|
1128
|
+
) })
|
|
1129
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1130
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1131
|
+
"div",
|
|
1365
1132
|
{
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
className:
|
|
1133
|
+
ref: initLoaderRef,
|
|
1134
|
+
id: "init-loader",
|
|
1135
|
+
className: `status-msg mb-4 ${connState !== "loading" ? "hidden" : "block"}`,
|
|
1369
1136
|
children: [
|
|
1370
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
1371
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
1372
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "billing", children: "Billing" })
|
|
1137
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "loader inline-block align-middle mr-2" }),
|
|
1138
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { id: "loader-text", className: "text-sm", children: onboardingInProgress ? "Configuring connection to PayPal…" : "Checking connection..." })
|
|
1373
1139
|
]
|
|
1374
1140
|
}
|
|
1375
|
-
)
|
|
1376
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1141
|
+
),
|
|
1142
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${connState === "ready" ? "block" : "hidden"}`, children: [
|
|
1377
1143
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1378
|
-
"
|
|
1144
|
+
"a",
|
|
1379
1145
|
{
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1146
|
+
ref: (node) => {
|
|
1147
|
+
paypalButtonRef.current = node;
|
|
1148
|
+
ppBtnMeasureRef.current = node;
|
|
1149
|
+
},
|
|
1150
|
+
id: "paypal-button",
|
|
1151
|
+
"data-paypal-button": "true",
|
|
1152
|
+
href: finalUrl || "#",
|
|
1153
|
+
"data-paypal-onboard-complete": "onboardingCallback",
|
|
1154
|
+
onClick: handleConnectClick,
|
|
1155
|
+
className: "btn-paypal",
|
|
1156
|
+
style: {
|
|
1157
|
+
borderRadius: "50px",
|
|
1158
|
+
textDecoration: "none",
|
|
1159
|
+
display: "inline-block",
|
|
1160
|
+
fontWeight: "bold",
|
|
1161
|
+
border: "none",
|
|
1162
|
+
cursor: onboardingInProgress ? "not-allowed" : "pointer",
|
|
1163
|
+
opacity: onboardingInProgress ? 0.6 : 1,
|
|
1164
|
+
pointerEvents: onboardingInProgress ? "none" : "auto"
|
|
1165
|
+
},
|
|
1166
|
+
children: "Connect to PayPal"
|
|
1384
1167
|
}
|
|
1385
1168
|
),
|
|
1386
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
),
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
hint: "Include all line item details in the payment request to PayPal so that they can be seen from the PayPal transaction details page.",
|
|
1412
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
1413
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1414
|
-
"input",
|
|
1415
|
-
{
|
|
1416
|
-
type: "checkbox",
|
|
1417
|
-
checked: form.sendItemDetails,
|
|
1418
|
-
onChange: (e) => setForm((p) => ({ ...p, sendItemDetails: e.target.checked })),
|
|
1419
|
-
className: "h-4 w-4 rounded border-ui-border-base"
|
|
1420
|
-
}
|
|
1421
|
-
),
|
|
1422
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Send line item details to PayPal" })
|
|
1423
|
-
] })
|
|
1424
|
-
}
|
|
1425
|
-
),
|
|
1426
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1427
|
-
FieldRow$1,
|
|
1428
|
-
{
|
|
1429
|
-
label: "Order Review Page",
|
|
1430
|
-
hint: "Payments from the Product or Cart page skip the review step and go straight to the Thank You page.",
|
|
1431
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
1432
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1433
|
-
"input",
|
|
1434
|
-
{
|
|
1435
|
-
type: "checkbox",
|
|
1436
|
-
checked: form.skipOrderReviewPage,
|
|
1437
|
-
onChange: (e) => setForm((p) => ({ ...p, skipOrderReviewPage: e.target.checked })),
|
|
1438
|
-
className: "h-4 w-4 rounded border-ui-border-base"
|
|
1439
|
-
}
|
|
1440
|
-
),
|
|
1441
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Skip Order Review Page" })
|
|
1442
|
-
] })
|
|
1443
|
-
}
|
|
1444
|
-
),
|
|
1445
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Invoice prefix", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1446
|
-
"input",
|
|
1447
|
-
{
|
|
1448
|
-
value: form.invoicePrefix,
|
|
1449
|
-
onChange: (e) => setForm((p) => ({ ...p, invoicePrefix: e.target.value })),
|
|
1450
|
-
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",
|
|
1451
|
-
placeholder: "WC-"
|
|
1452
|
-
}
|
|
1453
|
-
) }),
|
|
1454
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow$1, { label: "Credit Card Statement Name", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1455
|
-
"input",
|
|
1169
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1170
|
+
"div",
|
|
1171
|
+
{
|
|
1172
|
+
className: "mt-2",
|
|
1173
|
+
style: {
|
|
1174
|
+
width: ppBtnWidth ? `${ppBtnWidth}px` : "auto",
|
|
1175
|
+
marginTop: "20px",
|
|
1176
|
+
marginBottom: "10px"
|
|
1177
|
+
},
|
|
1178
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] text-ui-fg-muted leading-none", children: "OR" }) })
|
|
1179
|
+
}
|
|
1180
|
+
),
|
|
1181
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1182
|
+
"button",
|
|
1183
|
+
{
|
|
1184
|
+
type: "button",
|
|
1185
|
+
onClick: () => setShowManual(!showManual),
|
|
1186
|
+
disabled: onboardingInProgress,
|
|
1187
|
+
className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1188
|
+
children: "Click here to insert credentials manually"
|
|
1189
|
+
}
|
|
1190
|
+
) })
|
|
1191
|
+
] }),
|
|
1192
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `${connState === "ready" ? "hidden" : "block"} mt-3`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1193
|
+
"button",
|
|
1456
1194
|
{
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1195
|
+
type: "button",
|
|
1196
|
+
onClick: () => setShowManual(!showManual),
|
|
1197
|
+
disabled: onboardingInProgress,
|
|
1198
|
+
className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1199
|
+
children: "Click here to insert credentials manually"
|
|
1461
1200
|
}
|
|
1462
1201
|
) }),
|
|
1463
1202
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1464
|
-
|
|
1203
|
+
"div",
|
|
1465
1204
|
{
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
form.logPath ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1471
|
-
"Log location: ",
|
|
1472
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: form.logPath })
|
|
1473
|
-
] }) : null
|
|
1474
|
-
] }),
|
|
1475
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
1476
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1477
|
-
"input",
|
|
1478
|
-
{
|
|
1479
|
-
type: "checkbox",
|
|
1480
|
-
checked: form.enableLogging,
|
|
1481
|
-
onChange: (e) => setForm((p) => ({ ...p, enableLogging: e.target.checked })),
|
|
1482
|
-
className: "h-4 w-4 rounded border-ui-border-base"
|
|
1483
|
-
}
|
|
1484
|
-
),
|
|
1485
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable logging" })
|
|
1486
|
-
] })
|
|
1205
|
+
ref: errorLogRef,
|
|
1206
|
+
id: "error-log",
|
|
1207
|
+
className: `mt-4 text-left text-xs bg-red-50 text-red-600 p-3 border border-red-200 rounded ${connState === "error" && error ? "block" : "hidden"}`,
|
|
1208
|
+
children: error
|
|
1487
1209
|
}
|
|
1488
1210
|
)
|
|
1489
|
-
] })
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1211
|
+
] }) }),
|
|
1212
|
+
showManual && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:col-span-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-[260px] max-w-xl mt-4 grid grid-cols-1 gap-3 md:grid-cols-2", children: [
|
|
1213
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
1214
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Client ID" }),
|
|
1215
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1216
|
+
"input",
|
|
1217
|
+
{
|
|
1218
|
+
type: "text",
|
|
1219
|
+
value: clientId,
|
|
1220
|
+
onChange: (e) => setClientId(e.target.value),
|
|
1221
|
+
disabled: onboardingInProgress,
|
|
1222
|
+
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
1223
|
+
placeholder: env === "sandbox" ? "Sandbox Client ID" : "Live Client ID"
|
|
1224
|
+
}
|
|
1225
|
+
)
|
|
1226
|
+
] }),
|
|
1227
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
1228
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Client Secret" }),
|
|
1229
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1230
|
+
"input",
|
|
1231
|
+
{
|
|
1232
|
+
type: "password",
|
|
1233
|
+
value: secret,
|
|
1234
|
+
onChange: (e) => setSecret(e.target.value),
|
|
1235
|
+
disabled: onboardingInProgress,
|
|
1236
|
+
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
1237
|
+
placeholder: env === "sandbox" ? "Sandbox Secret" : "Live Secret"
|
|
1238
|
+
}
|
|
1239
|
+
)
|
|
1240
|
+
] }),
|
|
1241
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 md:col-span-2", children: [
|
|
1242
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Merchant ID (optional)" }),
|
|
1243
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1244
|
+
"input",
|
|
1245
|
+
{
|
|
1246
|
+
type: "text",
|
|
1247
|
+
value: merchantId,
|
|
1248
|
+
onChange: (e) => setMerchantId(e.target.value),
|
|
1249
|
+
disabled: onboardingInProgress,
|
|
1250
|
+
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
1251
|
+
placeholder: "Merchant ID"
|
|
1252
|
+
}
|
|
1253
|
+
)
|
|
1254
|
+
] }),
|
|
1255
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:col-span-2 flex items-center gap-2 mt-2", children: [
|
|
1256
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1257
|
+
"button",
|
|
1258
|
+
{
|
|
1259
|
+
type: "button",
|
|
1260
|
+
className: "rounded-md border border-ui-border-base px-3 py-2 text-sm font-medium hover:bg-ui-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1261
|
+
onClick: () => setShowManual(false),
|
|
1262
|
+
disabled: onboardingInProgress,
|
|
1263
|
+
children: "Cancel"
|
|
1264
|
+
}
|
|
1265
|
+
),
|
|
1266
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1267
|
+
"button",
|
|
1268
|
+
{
|
|
1269
|
+
type: "button",
|
|
1270
|
+
className: "rounded-md border border-ui-border-base px-3 py-2 text-sm font-medium bg-ui-bg-base hover:bg-ui-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1271
|
+
disabled: !canSaveManual || onboardingInProgress,
|
|
1272
|
+
onClick: handleSaveManual,
|
|
1273
|
+
children: "Save credentials"
|
|
1274
|
+
}
|
|
1275
|
+
)
|
|
1276
|
+
] })
|
|
1277
|
+
] }) })
|
|
1278
|
+
] }) })
|
|
1279
|
+
] }),
|
|
1280
|
+
/* @__PURE__ */ jsxRuntime.jsx("style", { children: `
|
|
1281
|
+
.loader {
|
|
1282
|
+
border: 3px solid #f3f3f3;
|
|
1283
|
+
border-top: 3px solid #0070ba;
|
|
1284
|
+
border-radius: 50%;
|
|
1285
|
+
width: 18px;
|
|
1286
|
+
height: 18px;
|
|
1287
|
+
animation: spin 1s linear infinite;
|
|
1288
|
+
display: inline-block;
|
|
1289
|
+
vertical-align: middle;
|
|
1290
|
+
margin-right: 8px;
|
|
1291
|
+
}
|
|
1292
|
+
@keyframes spin {
|
|
1293
|
+
0% { transform: rotate(0deg); }
|
|
1294
|
+
100% { transform: rotate(360deg); }
|
|
1295
|
+
}
|
|
1296
|
+
` })
|
|
1297
|
+
] });
|
|
1493
1298
|
}
|
|
1494
|
-
|
|
1299
|
+
const EMPTY_FILTERS = {
|
|
1300
|
+
dispute_id: "",
|
|
1301
|
+
status: "",
|
|
1302
|
+
order_id: "",
|
|
1303
|
+
cart_id: ""
|
|
1304
|
+
};
|
|
1305
|
+
function formatDate$1(value) {
|
|
1495
1306
|
if (!value) {
|
|
1496
|
-
return "
|
|
1307
|
+
return "";
|
|
1497
1308
|
}
|
|
1498
1309
|
const parsed = new Date(value);
|
|
1499
1310
|
if (Number.isNaN(parsed.getTime())) {
|
|
@@ -1501,106 +1312,185 @@ function formatDate(value) {
|
|
|
1501
1312
|
}
|
|
1502
1313
|
return parsed.toLocaleString();
|
|
1503
1314
|
}
|
|
1504
|
-
function
|
|
1505
|
-
const [
|
|
1315
|
+
function PayPalDisputesPage() {
|
|
1316
|
+
const [filters, setFilters] = react.useState({ ...EMPTY_FILTERS });
|
|
1317
|
+
const [disputes, setDisputes] = react.useState([]);
|
|
1506
1318
|
const [loading, setLoading] = react.useState(false);
|
|
1507
1319
|
const [error, setError] = react.useState(null);
|
|
1508
|
-
const
|
|
1320
|
+
const queryString = react.useMemo(() => {
|
|
1321
|
+
const params = new URLSearchParams();
|
|
1322
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
1323
|
+
if (value.trim()) {
|
|
1324
|
+
params.set(key, value.trim());
|
|
1325
|
+
}
|
|
1326
|
+
});
|
|
1327
|
+
const qs = params.toString();
|
|
1328
|
+
return qs ? `?${qs}` : "";
|
|
1329
|
+
}, [filters]);
|
|
1330
|
+
const fetchDisputes = react.useCallback(async (source) => {
|
|
1509
1331
|
try {
|
|
1510
1332
|
setLoading(true);
|
|
1511
1333
|
setError(null);
|
|
1512
|
-
const
|
|
1334
|
+
const params = new URLSearchParams();
|
|
1335
|
+
Object.entries(source).forEach(([key, value]) => {
|
|
1336
|
+
if (value.trim()) {
|
|
1337
|
+
params.set(key, value.trim());
|
|
1338
|
+
}
|
|
1339
|
+
});
|
|
1340
|
+
const qs = params.toString();
|
|
1341
|
+
const resp = await fetch(`/admin/paypal/disputes${qs ? `?${qs}` : ""}`, {
|
|
1513
1342
|
credentials: "include",
|
|
1514
1343
|
headers: {
|
|
1515
1344
|
Accept: "application/json"
|
|
1516
1345
|
}
|
|
1517
1346
|
});
|
|
1518
|
-
if (!
|
|
1519
|
-
const message = await
|
|
1520
|
-
throw new Error(message || "Failed to load
|
|
1347
|
+
if (!resp.ok) {
|
|
1348
|
+
const message = await resp.text().catch(() => "");
|
|
1349
|
+
throw new Error(message || "Failed to load disputes");
|
|
1521
1350
|
}
|
|
1522
|
-
const
|
|
1523
|
-
|
|
1351
|
+
const json = await resp.json().catch(() => ({}));
|
|
1352
|
+
setDisputes((json == null ? void 0 : json.disputes) || []);
|
|
1524
1353
|
} catch (fetchError) {
|
|
1525
|
-
setError((fetchError == null ? void 0 : fetchError.message) || "Failed to load
|
|
1526
|
-
|
|
1354
|
+
setError((fetchError == null ? void 0 : fetchError.message) || "Failed to load disputes");
|
|
1355
|
+
setDisputes([]);
|
|
1527
1356
|
} finally {
|
|
1528
1357
|
setLoading(false);
|
|
1529
1358
|
}
|
|
1530
1359
|
}, []);
|
|
1531
1360
|
react.useEffect(() => {
|
|
1532
|
-
|
|
1533
|
-
}, [
|
|
1361
|
+
fetchDisputes(EMPTY_FILTERS);
|
|
1362
|
+
}, [fetchDisputes]);
|
|
1363
|
+
const onSubmit = (event) => {
|
|
1364
|
+
event.preventDefault();
|
|
1365
|
+
fetchDisputes(filters);
|
|
1366
|
+
};
|
|
1367
|
+
const onReset = () => {
|
|
1368
|
+
setFilters({ ...EMPTY_FILTERS });
|
|
1369
|
+
fetchDisputes(EMPTY_FILTERS);
|
|
1370
|
+
};
|
|
1534
1371
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
1535
1372
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1536
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal
|
|
1537
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-ui-fg-subtle", children: "
|
|
1373
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Disputes" }),
|
|
1374
|
+
/* @__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." })
|
|
1538
1375
|
] }),
|
|
1539
1376
|
/* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
|
|
1540
1377
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
|
|
1541
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-ui-border-base p-4", children: /* @__PURE__ */ jsxRuntime.
|
|
1542
|
-
|
|
1543
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1544
|
-
"
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
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,
|
|
1556
|
-
!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,
|
|
1557
|
-
Object.keys(status).length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 text-sm text-ui-fg-base md:grid-cols-2", children: [
|
|
1558
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
|
|
1559
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last run" }),
|
|
1560
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_run_at) })
|
|
1561
|
-
] }),
|
|
1562
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
|
|
1563
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last run status" }),
|
|
1564
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium capitalize", children: status.last_run_status || "—" })
|
|
1565
|
-
] }),
|
|
1566
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
|
|
1567
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last success" }),
|
|
1568
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_success_at) })
|
|
1569
|
-
] }),
|
|
1570
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
|
|
1571
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Last failure" }),
|
|
1572
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: formatDate(status.last_failure_at) })
|
|
1573
|
-
] }),
|
|
1574
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
|
|
1575
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Sessions checked" }),
|
|
1576
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.sessions_checked ?? 0 })
|
|
1577
|
-
] }),
|
|
1578
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
|
|
1579
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Sessions updated" }),
|
|
1580
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.sessions_updated ?? 0 })
|
|
1581
|
-
] }),
|
|
1582
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3", children: [
|
|
1583
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "Drift detections" }),
|
|
1584
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 font-medium", children: status.drift_count ?? 0 })
|
|
1378
|
+
/* @__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" }) }),
|
|
1379
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit, className: "flex flex-col gap-4", children: [
|
|
1380
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-4", children: [
|
|
1381
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
|
|
1382
|
+
"Dispute ID",
|
|
1383
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1384
|
+
"input",
|
|
1385
|
+
{
|
|
1386
|
+
className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
|
|
1387
|
+
value: filters.dispute_id,
|
|
1388
|
+
onChange: (event) => setFilters((prev) => ({ ...prev, dispute_id: event.target.value })),
|
|
1389
|
+
placeholder: "PP-D-123"
|
|
1390
|
+
}
|
|
1391
|
+
)
|
|
1585
1392
|
] }),
|
|
1586
|
-
/* @__PURE__ */ jsxRuntime.jsxs("
|
|
1587
|
-
|
|
1588
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1589
|
-
|
|
1393
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
|
|
1394
|
+
"Status",
|
|
1395
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1396
|
+
"input",
|
|
1397
|
+
{
|
|
1398
|
+
className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
|
|
1399
|
+
value: filters.status,
|
|
1400
|
+
onChange: (event) => setFilters((prev) => ({ ...prev, status: event.target.value })),
|
|
1401
|
+
placeholder: "OPEN"
|
|
1402
|
+
}
|
|
1403
|
+
)
|
|
1590
1404
|
] }),
|
|
1591
|
-
/* @__PURE__ */ jsxRuntime.jsxs("
|
|
1592
|
-
|
|
1593
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1405
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
|
|
1406
|
+
"Order ID",
|
|
1407
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1408
|
+
"input",
|
|
1409
|
+
{
|
|
1410
|
+
className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
|
|
1411
|
+
value: filters.order_id,
|
|
1412
|
+
onChange: (event) => setFilters((prev) => ({ ...prev, order_id: event.target.value })),
|
|
1413
|
+
placeholder: "order_..."
|
|
1414
|
+
}
|
|
1415
|
+
)
|
|
1594
1416
|
] }),
|
|
1595
|
-
/* @__PURE__ */ jsxRuntime.jsxs("
|
|
1596
|
-
|
|
1597
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1417
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1 text-sm text-ui-fg-subtle", children: [
|
|
1418
|
+
"Cart ID",
|
|
1419
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1420
|
+
"input",
|
|
1421
|
+
{
|
|
1422
|
+
className: "rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base",
|
|
1423
|
+
value: filters.cart_id,
|
|
1424
|
+
onChange: (event) => setFilters((prev) => ({ ...prev, cart_id: event.target.value })),
|
|
1425
|
+
placeholder: "cart_..."
|
|
1426
|
+
}
|
|
1427
|
+
)
|
|
1598
1428
|
] })
|
|
1599
|
-
] })
|
|
1600
|
-
|
|
1429
|
+
] }),
|
|
1430
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-3", children: [
|
|
1431
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1432
|
+
"button",
|
|
1433
|
+
{
|
|
1434
|
+
type: "submit",
|
|
1435
|
+
className: "rounded-md bg-ui-fg-base px-4 py-2 text-sm font-medium text-ui-bg-base",
|
|
1436
|
+
disabled: loading,
|
|
1437
|
+
children: loading ? "Loading..." : "Apply filters"
|
|
1438
|
+
}
|
|
1439
|
+
),
|
|
1440
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1441
|
+
"button",
|
|
1442
|
+
{
|
|
1443
|
+
type: "button",
|
|
1444
|
+
className: "rounded-md border border-ui-border-base px-4 py-2 text-sm text-ui-fg-base",
|
|
1445
|
+
onClick: onReset,
|
|
1446
|
+
disabled: loading,
|
|
1447
|
+
children: "Reset"
|
|
1448
|
+
}
|
|
1449
|
+
),
|
|
1450
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-ui-fg-subtle", children: [
|
|
1451
|
+
"Showing ",
|
|
1452
|
+
disputes.length,
|
|
1453
|
+
" dispute",
|
|
1454
|
+
disputes.length === 1 ? "" : "s",
|
|
1455
|
+
queryString ? " (filtered)" : ""
|
|
1456
|
+
] })
|
|
1457
|
+
] })
|
|
1458
|
+
] }) })
|
|
1459
|
+
] }),
|
|
1460
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
|
|
1461
|
+
/* @__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" }) }),
|
|
1462
|
+
/* @__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: [
|
|
1463
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "text-left text-ui-fg-subtle", children: [
|
|
1464
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Dispute" }),
|
|
1465
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Status" }),
|
|
1466
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Reason" }),
|
|
1467
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Stage" }),
|
|
1468
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Amount" }),
|
|
1469
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Order" }),
|
|
1470
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Cart" }),
|
|
1471
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-4 py-3 font-medium", children: "Updated" })
|
|
1472
|
+
] }) }),
|
|
1473
|
+
/* @__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: [
|
|
1474
|
+
/* @__PURE__ */ jsxRuntime.jsxs("td", { className: "px-4 py-3", children: [
|
|
1475
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-ui-fg-base", children: dispute.dispute_id }),
|
|
1476
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-ui-fg-subtle", children: dispute.transaction_id || "No transaction" })
|
|
1477
|
+
] }),
|
|
1478
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.status || "Unknown" }),
|
|
1479
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.reason || "-" }),
|
|
1480
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.stage || "-" }),
|
|
1481
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.amount ? `${dispute.amount} ${dispute.currency_code || ""}` : "-" }),
|
|
1482
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.order_id || "-" }),
|
|
1483
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3", children: dispute.cart_id || "-" }),
|
|
1484
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 text-ui-fg-subtle", children: formatDate$1(dispute.updated_at || dispute.created_at) })
|
|
1485
|
+
] }, dispute.id)) })
|
|
1486
|
+
] }) }),
|
|
1487
|
+
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
|
|
1601
1488
|
] })
|
|
1602
1489
|
] }) });
|
|
1603
1490
|
}
|
|
1491
|
+
function PayPalGooglePayPage() {
|
|
1492
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
1493
|
+
}
|
|
1604
1494
|
function PayPalPayLaterMessagingPage() {
|
|
1605
1495
|
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
1606
1496
|
}
|
|
@@ -2041,6 +1931,116 @@ function PayPalSettingsTab() {
|
|
|
2041
1931
|
)
|
|
2042
1932
|
] }) });
|
|
2043
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.");
|
|
1961
|
+
}
|
|
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
|
|
2040
|
+
] })
|
|
2041
|
+
] })
|
|
2042
|
+
] }) });
|
|
2043
|
+
}
|
|
2044
2044
|
const widgetModule = { widgets: [] };
|
|
2045
2045
|
const routeModule = {
|
|
2046
2046
|
routes: [
|
|
@@ -2049,16 +2049,8 @@ const routeModule = {
|
|
|
2049
2049
|
path: "/settings/paypal"
|
|
2050
2050
|
},
|
|
2051
2051
|
{
|
|
2052
|
-
Component:
|
|
2053
|
-
path: "/settings/paypal/
|
|
2054
|
-
},
|
|
2055
|
-
{
|
|
2056
|
-
Component: PayPalConnectionPage,
|
|
2057
|
-
path: "/settings/paypal/connection"
|
|
2058
|
-
},
|
|
2059
|
-
{
|
|
2060
|
-
Component: PayPalDisputesPage,
|
|
2061
|
-
path: "/settings/paypal/disputes"
|
|
2052
|
+
Component: AdditionalSettingsTab,
|
|
2053
|
+
path: "/settings/paypal/additional-settings"
|
|
2062
2054
|
},
|
|
2063
2055
|
{
|
|
2064
2056
|
Component: PayPalApplePayPage,
|
|
@@ -2069,16 +2061,20 @@ const routeModule = {
|
|
|
2069
2061
|
path: "/settings/paypal/audit-logs"
|
|
2070
2062
|
},
|
|
2071
2063
|
{
|
|
2072
|
-
Component:
|
|
2073
|
-
path: "/settings/paypal/
|
|
2064
|
+
Component: AdvancedCardPaymentsTab,
|
|
2065
|
+
path: "/settings/paypal/advanced-card-payments"
|
|
2074
2066
|
},
|
|
2075
2067
|
{
|
|
2076
|
-
Component:
|
|
2077
|
-
path: "/settings/paypal/
|
|
2068
|
+
Component: PayPalConnectionPage,
|
|
2069
|
+
path: "/settings/paypal/connection"
|
|
2078
2070
|
},
|
|
2079
2071
|
{
|
|
2080
|
-
Component:
|
|
2081
|
-
path: "/settings/paypal/
|
|
2072
|
+
Component: PayPalDisputesPage,
|
|
2073
|
+
path: "/settings/paypal/disputes"
|
|
2074
|
+
},
|
|
2075
|
+
{
|
|
2076
|
+
Component: PayPalGooglePayPage,
|
|
2077
|
+
path: "/settings/paypal/google-pay"
|
|
2082
2078
|
},
|
|
2083
2079
|
{
|
|
2084
2080
|
Component: PayPalPayLaterMessagingPage,
|
|
@@ -2087,6 +2083,10 @@ const routeModule = {
|
|
|
2087
2083
|
{
|
|
2088
2084
|
Component: PayPalSettingsTab,
|
|
2089
2085
|
path: "/settings/paypal/paypal-settings"
|
|
2086
|
+
},
|
|
2087
|
+
{
|
|
2088
|
+
Component: PayPalReconciliationStatusPage,
|
|
2089
|
+
path: "/settings/paypal/reconciliation-status"
|
|
2090
2090
|
}
|
|
2091
2091
|
]
|
|
2092
2092
|
};
|