@easypayment/medusa-payment-paypal 0.9.21 → 0.9.24
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 +258 -214
- package/.medusa/server/src/admin/index.mjs +258 -214
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.d.ts.map +1 -1
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js +210 -223
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js.map +1 -1
- package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.js +6 -8
- package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/environment/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/paypal/environment/route.js +11 -3
- package/.medusa/server/src/api/admin/paypal/environment/route.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/onboarding-status/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/paypal/onboarding-status/route.js +4 -1
- package/.medusa/server/src/api/admin/paypal/onboarding-status/route.js.map +1 -1
- package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -1
- package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js +6 -8
- package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js.map +1 -1
- package/.medusa/server/src/api/store/paypal/capture-order/route.d.ts.map +1 -1
- package/.medusa/server/src/api/store/paypal/capture-order/route.js +11 -0
- package/.medusa/server/src/api/store/paypal/capture-order/route.js.map +1 -1
- package/.medusa/server/src/api/store/paypal-complete/route.d.ts.map +1 -1
- package/.medusa/server/src/api/store/paypal-complete/route.js +2 -4
- package/.medusa/server/src/api/store/paypal-complete/route.js.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/card-service.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/card-service.js +55 -34
- package/.medusa/server/src/modules/paypal/payment-provider/card-service.js.map +1 -1
- package/.medusa/server/src/modules/paypal/utils/core-workflow.d.ts +32 -0
- package/.medusa/server/src/modules/paypal/utils/core-workflow.d.ts.map +1 -0
- package/.medusa/server/src/modules/paypal/utils/core-workflow.js +40 -0
- package/.medusa/server/src/modules/paypal/utils/core-workflow.js.map +1 -0
- package/package.json +1 -1
- package/src/admin/routes/settings/paypal/connection/page.tsx +273 -293
- package/src/api/admin/payment-collections/[id]/payment-sessions/route.ts +6 -8
- package/src/api/admin/paypal/environment/route.ts +10 -3
- package/src/api/admin/paypal/onboarding-status/route.ts +4 -1
- package/src/api/store/payment-collections/[id]/payment-sessions/route.ts +6 -8
- package/src/api/store/paypal/capture-order/route.ts +15 -0
- package/src/api/store/paypal-complete/route.ts +6 -4
- package/src/modules/paypal/payment-provider/card-service.ts +72 -38
- package/src/modules/paypal/utils/core-workflow.ts +46 -0
|
@@ -134,22 +134,20 @@ async function adminFetch(path, opts = {}) {
|
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
const DEFAULT_FORM$1 = {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
paymentAction: "capture",
|
|
138
|
+
brandName: "PayPal",
|
|
139
|
+
landingPage: "no_preference",
|
|
140
|
+
requireInstantPayment: false,
|
|
141
|
+
sendItemDetails: true,
|
|
142
|
+
invoicePrefix: "PP-",
|
|
143
|
+
creditCardStatementName: "PayPal"
|
|
140
144
|
};
|
|
141
145
|
function mergeWithDefaults$1(saved) {
|
|
142
146
|
if (!saved) return { ...DEFAULT_FORM$1 };
|
|
143
147
|
const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
|
|
144
148
|
return { ...DEFAULT_FORM$1, ...Object.fromEntries(entries) };
|
|
145
149
|
}
|
|
146
|
-
|
|
147
|
-
{ value: "when_required", label: "3D Secure when required", hint: "Triggers 3DS only when the card / issuer requires it." },
|
|
148
|
-
{ value: "sli", label: "3D Secure (SCA) / liability shift (recommended)", hint: "Attempts to optimize for liability shift while remaining compliant." },
|
|
149
|
-
{ value: "always", label: "Always request 3D Secure", hint: "Forces 3DS challenge whenever possible (may reduce conversion)." }
|
|
150
|
-
];
|
|
151
|
-
function AdvancedCardPaymentsTab() {
|
|
152
|
-
var _a, _b;
|
|
150
|
+
function AdditionalSettingsTab() {
|
|
153
151
|
const [form, setForm] = react.useState(() => ({ ...DEFAULT_FORM$1 }));
|
|
154
152
|
const [loading, setLoading] = react.useState(false);
|
|
155
153
|
const [saving, setSaving] = react.useState(false);
|
|
@@ -164,7 +162,7 @@ function AdvancedCardPaymentsTab() {
|
|
|
164
162
|
setLoading(true);
|
|
165
163
|
const json = await adminFetch("/admin/paypal/settings");
|
|
166
164
|
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
167
|
-
const saved = payload == null ? void 0 : payload.
|
|
165
|
+
const saved = payload == null ? void 0 : payload.additional_settings;
|
|
168
166
|
if (saved && typeof saved === "object") setForm(mergeWithDefaults$1(saved));
|
|
169
167
|
} catch {
|
|
170
168
|
} finally {
|
|
@@ -175,16 +173,14 @@ function AdvancedCardPaymentsTab() {
|
|
|
175
173
|
async function onSave() {
|
|
176
174
|
try {
|
|
177
175
|
setSaving(true);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
body: { advanced_card_payments: form }
|
|
181
|
-
});
|
|
176
|
+
setToast(null);
|
|
177
|
+
const json = await adminFetch("/admin/paypal/settings", { method: "POST", body: { additional_settings: form } });
|
|
182
178
|
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
183
|
-
const saved = payload == null ? void 0 : payload.
|
|
179
|
+
const saved = payload == null ? void 0 : payload.additional_settings;
|
|
184
180
|
if (saved && typeof saved === "object") setForm(mergeWithDefaults$1(saved));
|
|
185
181
|
setToast({ kind: "success", message: "Settings saved" });
|
|
186
182
|
} catch (e) {
|
|
187
|
-
setToast({ kind: "error", message:
|
|
183
|
+
setToast({ kind: "error", message: e instanceof Error ? e.message : "Failed to save settings" });
|
|
188
184
|
} finally {
|
|
189
185
|
setSaving(false);
|
|
190
186
|
}
|
|
@@ -196,42 +192,58 @@ function AdvancedCardPaymentsTab() {
|
|
|
196
192
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
197
193
|
SectionCard,
|
|
198
194
|
{
|
|
199
|
-
title: "
|
|
200
|
-
description: "
|
|
195
|
+
title: "Additional Settings",
|
|
196
|
+
description: "These settings control checkout behavior and PayPal experience.",
|
|
201
197
|
right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
202
198
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onSave, disabled: saving || loading, className: "transition-fg relative inline-flex w-fit items-center justify-center overflow-hidden rounded-md outline-none shadow-buttons-neutral text-ui-fg-base bg-ui-button-neutral after:transition-fg after:absolute after:inset-0 after:content-[''] after:button-neutral-gradient hover:bg-ui-button-neutral-hover hover:after:button-neutral-hover-gradient active:bg-ui-button-neutral-pressed active:after:button-neutral-pressed-gradient focus-visible:shadow-buttons-neutral-focus disabled:bg-ui-bg-disabled disabled:border-ui-border-base disabled:text-ui-fg-disabled disabled:shadow-buttons-neutral disabled:after:hidden txt-compact-small-plus px-3 py-1.5", children: saving ? "Saving..." : "Save settings" }),
|
|
203
199
|
loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading…" }) : null
|
|
204
200
|
] }),
|
|
205
201
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
|
|
206
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
207
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
208
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
202
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Payment action", htmlFor: "as-payment-action", children: /* @__PURE__ */ jsxRuntime.jsxs("select", { id: "as-payment-action", value: form.paymentAction, onChange: (e) => setForm((p) => ({ ...p, paymentAction: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", children: [
|
|
203
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "capture", children: "Capture" }),
|
|
204
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "authorize", children: "Authorize" })
|
|
209
205
|
] }) }),
|
|
210
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
211
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
212
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
213
|
-
|
|
214
|
-
|
|
206
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Brand Name", htmlFor: "as-brand-name", children: /* @__PURE__ */ jsxRuntime.jsx("input", { id: "as-brand-name", value: form.brandName, onChange: (e) => setForm((p) => ({ ...p, brandName: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", placeholder: "PayPal" }) }),
|
|
207
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Landing Page", htmlFor: "as-landing-page", children: /* @__PURE__ */ jsxRuntime.jsxs("select", { id: "as-landing-page", value: form.landingPage, onChange: (e) => setForm((p) => ({ ...p, landingPage: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", children: [
|
|
208
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "no_preference", children: "No Preference" }),
|
|
209
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "login", children: "Login" }),
|
|
210
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "billing", children: "Billing" })
|
|
211
|
+
] }) }),
|
|
212
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Instant Payments", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
213
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: form.requireInstantPayment, onChange: (e) => setForm((p) => ({ ...p, requireInstantPayment: e.target.checked })), className: "h-4 w-4 rounded border-ui-border-base" }),
|
|
214
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Require Instant Payment" })
|
|
215
|
+
] }) }),
|
|
216
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Send Item Details", hint: "Include all line item details in the payment request to PayPal so that they can be seen from the PayPal transaction details page.", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
217
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: form.sendItemDetails, onChange: (e) => setForm((p) => ({ ...p, sendItemDetails: e.target.checked })), className: "h-4 w-4 rounded border-ui-border-base" }),
|
|
218
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Send line item details to PayPal" })
|
|
219
|
+
] }) }),
|
|
220
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Invoice prefix", htmlFor: "as-invoice-prefix", children: /* @__PURE__ */ jsxRuntime.jsx("input", { id: "as-invoice-prefix", value: form.invoicePrefix, onChange: (e) => setForm((p) => ({ ...p, invoicePrefix: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", placeholder: "PP-" }) }),
|
|
221
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Credit Card Statement Name", htmlFor: "as-cc-statement", children: /* @__PURE__ */ jsxRuntime.jsx("input", { id: "as-cc-statement", value: form.creditCardStatementName, onChange: (e) => setForm((p) => ({ ...p, creditCardStatementName: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", placeholder: "PayPal" }) })
|
|
215
222
|
] })
|
|
216
223
|
}
|
|
217
224
|
)
|
|
218
225
|
] }) });
|
|
219
226
|
}
|
|
227
|
+
function PayPalApplePayPage() {
|
|
228
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
229
|
+
}
|
|
220
230
|
const DEFAULT_FORM = {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
requireInstantPayment: false,
|
|
225
|
-
sendItemDetails: true,
|
|
226
|
-
invoicePrefix: "PP-",
|
|
227
|
-
creditCardStatementName: "PayPal"
|
|
231
|
+
enabled: true,
|
|
232
|
+
title: "Credit or Debit Card",
|
|
233
|
+
threeDS: "when_required"
|
|
228
234
|
};
|
|
229
235
|
function mergeWithDefaults(saved) {
|
|
230
236
|
if (!saved) return { ...DEFAULT_FORM };
|
|
231
237
|
const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
|
|
232
238
|
return { ...DEFAULT_FORM, ...Object.fromEntries(entries) };
|
|
233
239
|
}
|
|
234
|
-
|
|
240
|
+
const THREE_DS_OPTIONS = [
|
|
241
|
+
{ value: "when_required", label: "3D Secure when required", hint: "Triggers 3DS only when the card / issuer requires it." },
|
|
242
|
+
{ value: "sli", label: "3D Secure (SCA) / liability shift (recommended)", hint: "Attempts to optimize for liability shift while remaining compliant." },
|
|
243
|
+
{ value: "always", label: "Always request 3D Secure", hint: "Forces 3DS challenge whenever possible (may reduce conversion)." }
|
|
244
|
+
];
|
|
245
|
+
function AdvancedCardPaymentsTab() {
|
|
246
|
+
var _a, _b;
|
|
235
247
|
const [form, setForm] = react.useState(() => ({ ...DEFAULT_FORM }));
|
|
236
248
|
const [loading, setLoading] = react.useState(false);
|
|
237
249
|
const [saving, setSaving] = react.useState(false);
|
|
@@ -246,7 +258,7 @@ function AdditionalSettingsTab() {
|
|
|
246
258
|
setLoading(true);
|
|
247
259
|
const json = await adminFetch("/admin/paypal/settings");
|
|
248
260
|
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
249
|
-
const saved = payload == null ? void 0 : payload.
|
|
261
|
+
const saved = payload == null ? void 0 : payload.advanced_card_payments;
|
|
250
262
|
if (saved && typeof saved === "object") setForm(mergeWithDefaults(saved));
|
|
251
263
|
} catch {
|
|
252
264
|
} finally {
|
|
@@ -257,14 +269,16 @@ function AdditionalSettingsTab() {
|
|
|
257
269
|
async function onSave() {
|
|
258
270
|
try {
|
|
259
271
|
setSaving(true);
|
|
260
|
-
|
|
261
|
-
|
|
272
|
+
const json = await adminFetch("/admin/paypal/settings", {
|
|
273
|
+
method: "POST",
|
|
274
|
+
body: { advanced_card_payments: form }
|
|
275
|
+
});
|
|
262
276
|
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
263
|
-
const saved = payload == null ? void 0 : payload.
|
|
277
|
+
const saved = payload == null ? void 0 : payload.advanced_card_payments;
|
|
264
278
|
if (saved && typeof saved === "object") setForm(mergeWithDefaults(saved));
|
|
265
279
|
setToast({ kind: "success", message: "Settings saved" });
|
|
266
280
|
} catch (e) {
|
|
267
|
-
setToast({ kind: "error", message: e instanceof Error ? e.message : "Failed to save settings" });
|
|
281
|
+
setToast({ kind: "error", message: (e instanceof Error ? e.message : "") || "Failed to save settings." });
|
|
268
282
|
} finally {
|
|
269
283
|
setSaving(false);
|
|
270
284
|
}
|
|
@@ -276,44 +290,27 @@ function AdditionalSettingsTab() {
|
|
|
276
290
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
277
291
|
SectionCard,
|
|
278
292
|
{
|
|
279
|
-
title: "
|
|
280
|
-
description: "
|
|
293
|
+
title: "Advanced Card Payments",
|
|
294
|
+
description: "Control card checkout settings and 3D Secure behavior.",
|
|
281
295
|
right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
282
296
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onSave, disabled: saving || loading, className: "transition-fg relative inline-flex w-fit items-center justify-center overflow-hidden rounded-md outline-none shadow-buttons-neutral text-ui-fg-base bg-ui-button-neutral after:transition-fg after:absolute after:inset-0 after:content-[''] after:button-neutral-gradient hover:bg-ui-button-neutral-hover hover:after:button-neutral-hover-gradient active:bg-ui-button-neutral-pressed active:after:button-neutral-pressed-gradient focus-visible:shadow-buttons-neutral-focus disabled:bg-ui-bg-disabled disabled:border-ui-border-base disabled:text-ui-fg-disabled disabled:shadow-buttons-neutral disabled:after:hidden txt-compact-small-plus px-3 py-1.5", children: saving ? "Saving..." : "Save settings" }),
|
|
283
297
|
loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading…" }) : null
|
|
284
298
|
] }),
|
|
285
299
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
|
|
286
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
287
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
288
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
289
|
-
] }) }),
|
|
290
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Brand Name", htmlFor: "as-brand-name", children: /* @__PURE__ */ jsxRuntime.jsx("input", { id: "as-brand-name", value: form.brandName, onChange: (e) => setForm((p) => ({ ...p, brandName: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", placeholder: "PayPal" }) }),
|
|
291
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Landing Page", htmlFor: "as-landing-page", children: /* @__PURE__ */ jsxRuntime.jsxs("select", { id: "as-landing-page", value: form.landingPage, onChange: (e) => setForm((p) => ({ ...p, landingPage: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", children: [
|
|
292
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "no_preference", children: "No Preference" }),
|
|
293
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "login", children: "Login" }),
|
|
294
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "billing", children: "Billing" })
|
|
295
|
-
] }) }),
|
|
296
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Instant Payments", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
297
|
-
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: form.requireInstantPayment, onChange: (e) => setForm((p) => ({ ...p, requireInstantPayment: e.target.checked })), className: "h-4 w-4 rounded border-ui-border-base" }),
|
|
298
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Require Instant Payment" })
|
|
299
|
-
] }) }),
|
|
300
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Send Item Details", hint: "Include all line item details in the payment request to PayPal so that they can be seen from the PayPal transaction details page.", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
301
|
-
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: form.sendItemDetails, onChange: (e) => setForm((p) => ({ ...p, sendItemDetails: e.target.checked })), className: "h-4 w-4 rounded border-ui-border-base" }),
|
|
302
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Send line item details to PayPal" })
|
|
300
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Enable/Disable", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
301
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: form.enabled, onChange: (e) => setForm((p) => ({ ...p, enabled: e.target.checked })), className: "h-4 w-4 rounded border-ui-border-base" }),
|
|
302
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable Advanced Credit/Debit Card" })
|
|
303
303
|
] }) }),
|
|
304
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
305
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
304
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Title", htmlFor: "acp-title", children: /* @__PURE__ */ jsxRuntime.jsx("input", { id: "acp-title", value: form.title, onChange: (e) => setForm((p) => ({ ...p, title: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", placeholder: "Credit or Debit Card" }) }),
|
|
305
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "Contingency for 3D Secure", hint: "Choose when 3D Secure should be triggered during card payments.", htmlFor: "acp-threeds", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
306
|
+
/* @__PURE__ */ jsxRuntime.jsx("select", { id: "acp-threeds", value: form.threeDS, onChange: (e) => setForm((p) => ({ ...p, threeDS: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", children: THREE_DS_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value)) }),
|
|
307
|
+
((_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
|
|
308
|
+
] }) })
|
|
306
309
|
] })
|
|
307
310
|
}
|
|
308
311
|
)
|
|
309
312
|
] }) });
|
|
310
313
|
}
|
|
311
|
-
function PayPalApplePayPage() {
|
|
312
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
313
|
-
}
|
|
314
|
-
function PayPalGooglePayPage() {
|
|
315
|
-
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
316
|
-
}
|
|
317
314
|
const config = adminSdk.defineRouteConfig({
|
|
318
315
|
label: "PayPal Connection"
|
|
319
316
|
});
|
|
@@ -324,7 +321,7 @@ const PARTNER_JS_URLS = {
|
|
|
324
321
|
const SERVICE_URL = "/admin/paypal/onboarding-link";
|
|
325
322
|
const POPUP_NAME = "PPFrame";
|
|
326
323
|
const CACHE_PREFIX = "pp_onboard_cache";
|
|
327
|
-
const CACHE_EXPIRY =
|
|
324
|
+
const CACHE_EXPIRY = 6 * 60 * 60 * 1e3;
|
|
328
325
|
const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
|
|
329
326
|
const STATUS_ENDPOINT = "/admin/paypal/status";
|
|
330
327
|
const SAVE_CREDENTIALS_ENDPOINT = "/admin/paypal/save-credentials";
|
|
@@ -347,7 +344,9 @@ function readCachedUrl(env) {
|
|
|
347
344
|
function writeCachedUrl(env, url) {
|
|
348
345
|
try {
|
|
349
346
|
localStorage.setItem(cacheKeyFor(env), JSON.stringify({ url, ts: Date.now() }));
|
|
347
|
+
return readCachedUrl(env) === url;
|
|
350
348
|
} catch {
|
|
349
|
+
return false;
|
|
351
350
|
}
|
|
352
351
|
}
|
|
353
352
|
function clearCachedUrl(env) {
|
|
@@ -373,23 +372,27 @@ function extractAuth(data) {
|
|
|
373
372
|
if (!data) return {};
|
|
374
373
|
if (typeof data === "object") {
|
|
375
374
|
const obj = data;
|
|
376
|
-
const authCode = obj.authCode ?? obj.auth_code ?? obj.authcode;
|
|
375
|
+
const authCode = obj.authCode ?? obj.auth_code ?? obj.authcode ?? obj.code;
|
|
377
376
|
const sharedId = obj.sharedId ?? obj.shared_id ?? obj.sharedid;
|
|
378
377
|
if (authCode && sharedId) {
|
|
379
378
|
return { authCode: String(authCode), sharedId: String(sharedId) };
|
|
380
379
|
}
|
|
381
|
-
for (const key of ["data", "payload", "message", "detail", "body"]) {
|
|
380
|
+
for (const key of ["data", "payload", "message", "detail", "body", "params"]) {
|
|
382
381
|
if (obj[key] && typeof obj[key] === "object") {
|
|
383
382
|
const inner = extractAuth(obj[key]);
|
|
384
383
|
if (inner.authCode && inner.sharedId) return inner;
|
|
385
384
|
}
|
|
385
|
+
if (typeof obj[key] === "string") {
|
|
386
|
+
const inner = extractAuth(obj[key]);
|
|
387
|
+
if (inner.authCode && inner.sharedId) return inner;
|
|
388
|
+
}
|
|
386
389
|
}
|
|
387
390
|
return {};
|
|
388
391
|
}
|
|
389
392
|
if (typeof data === "string") {
|
|
390
393
|
const s = data.trim();
|
|
391
394
|
if (!s) return {};
|
|
392
|
-
if (s.startsWith("{")) {
|
|
395
|
+
if (s.startsWith("{") || s.startsWith("[")) {
|
|
393
396
|
try {
|
|
394
397
|
return extractAuth(JSON.parse(s));
|
|
395
398
|
} catch {
|
|
@@ -424,16 +427,16 @@ function PayPalConnectionPage() {
|
|
|
424
427
|
const errorLogRef = react.useRef(null);
|
|
425
428
|
const runIdRef = react.useRef(0);
|
|
426
429
|
const currentRunId = react.useRef(0);
|
|
430
|
+
const envRef = react.useRef(env);
|
|
431
|
+
envRef.current = env;
|
|
427
432
|
const finalUrlRef = react.useRef(finalUrl);
|
|
428
433
|
finalUrlRef.current = finalUrl;
|
|
429
434
|
const connStateRef = react.useRef(connState);
|
|
430
435
|
connStateRef.current = connState;
|
|
431
436
|
const inProgressRef = react.useRef(onboardingInProgress);
|
|
432
437
|
inProgressRef.current = onboardingInProgress;
|
|
433
|
-
const envRef = react.useRef(env);
|
|
434
|
-
envRef.current = env;
|
|
435
438
|
const popupRef = react.useRef(null);
|
|
436
|
-
const
|
|
439
|
+
const pollRef = react.useRef(null);
|
|
437
440
|
const completedRef = react.useRef(false);
|
|
438
441
|
const ppBtnMeasureRef = react.useRef(null);
|
|
439
442
|
const [ppBtnWidth, setPpBtnWidth] = react.useState(null);
|
|
@@ -444,52 +447,44 @@ function PayPalConnectionPage() {
|
|
|
444
447
|
setConnState("error");
|
|
445
448
|
setError(msg);
|
|
446
449
|
}, []);
|
|
447
|
-
const
|
|
448
|
-
if (
|
|
449
|
-
clearInterval(
|
|
450
|
-
|
|
450
|
+
const stopPoll = react.useCallback(() => {
|
|
451
|
+
if (pollRef.current) {
|
|
452
|
+
clearInterval(pollRef.current);
|
|
453
|
+
pollRef.current = null;
|
|
451
454
|
}
|
|
452
455
|
}, []);
|
|
453
|
-
const openOnboardingPopup = react.useCallback(
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
456
|
+
const openOnboardingPopup = react.useCallback((url) => {
|
|
457
|
+
const w = 450;
|
|
458
|
+
const h = 600;
|
|
459
|
+
const baseLeft = typeof window.screenX === "number" ? window.screenX : window.screenLeft || 0;
|
|
460
|
+
const baseTop = typeof window.screenY === "number" ? window.screenY : window.screenTop || 0;
|
|
461
|
+
const outerW = window.outerWidth || document.documentElement.clientWidth || 1024;
|
|
462
|
+
const outerH = window.outerHeight || document.documentElement.clientHeight || 768;
|
|
463
|
+
const left = Math.round(baseLeft + Math.max(0, (outerW - w) / 2));
|
|
464
|
+
const top = Math.round(baseTop + Math.max(0, (outerH - h) / 2));
|
|
465
|
+
const features = `popup=yes,width=${w},height=${h},left=${left},top=${top},scrollbars=yes,resizable=yes`;
|
|
466
|
+
let popup = null;
|
|
467
|
+
try {
|
|
468
|
+
popup = window.open(url, POPUP_NAME, features);
|
|
469
|
+
} catch {
|
|
470
|
+
popup = null;
|
|
471
|
+
}
|
|
472
|
+
if (popup) {
|
|
473
|
+
popupRef.current = popup;
|
|
465
474
|
try {
|
|
466
|
-
popup
|
|
475
|
+
popup.focus();
|
|
467
476
|
} catch {
|
|
468
|
-
popup = null;
|
|
469
|
-
}
|
|
470
|
-
if (popup) {
|
|
471
|
-
popupRef.current = popup;
|
|
472
|
-
try {
|
|
473
|
-
popup.focus();
|
|
474
|
-
} catch {
|
|
475
|
-
}
|
|
476
|
-
stopPopupPoll();
|
|
477
|
-
popupPollRef.current = setInterval(() => {
|
|
478
|
-
if (!popupRef.current || popupRef.current.closed) {
|
|
479
|
-
stopPopupPoll();
|
|
480
|
-
}
|
|
481
|
-
}, 1e3);
|
|
482
477
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
);
|
|
478
|
+
}
|
|
479
|
+
return popup;
|
|
480
|
+
}, []);
|
|
487
481
|
const completeOnboarding = react.useCallback(
|
|
488
482
|
async (authCode, sharedId) => {
|
|
489
483
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
490
484
|
if (!authCode || !sharedId) return;
|
|
491
485
|
if (completedRef.current) return;
|
|
492
486
|
completedRef.current = true;
|
|
487
|
+
stopPoll();
|
|
493
488
|
try {
|
|
494
489
|
window.onbeforeunload = null;
|
|
495
490
|
} catch {
|
|
@@ -514,7 +509,6 @@ function PayPalConnectionPage() {
|
|
|
514
509
|
(_a = popupRef.current) == null ? void 0 : _a.close();
|
|
515
510
|
} catch {
|
|
516
511
|
}
|
|
517
|
-
stopPopupPoll();
|
|
518
512
|
try {
|
|
519
513
|
const close1 = (_e = (_d = (_c = (_b = window.PAYPAL) == null ? void 0 : _b.apps) == null ? void 0 : _c.Signup) == null ? void 0 : _d.MiniBrowser) == null ? void 0 : _e.closeFlow;
|
|
520
514
|
if (typeof close1 === "function") close1();
|
|
@@ -527,10 +521,10 @@ function PayPalConnectionPage() {
|
|
|
527
521
|
}
|
|
528
522
|
clearCachedUrl(activeEnv);
|
|
529
523
|
try {
|
|
530
|
-
const statusRes = await fetch(
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
);
|
|
524
|
+
const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${activeEnv}`, {
|
|
525
|
+
method: "GET",
|
|
526
|
+
credentials: "include"
|
|
527
|
+
});
|
|
534
528
|
const refreshedStatus = await statusRes.json().catch(() => ({}));
|
|
535
529
|
setStatusInfo(refreshedStatus || null);
|
|
536
530
|
} catch {
|
|
@@ -546,29 +540,56 @@ function PayPalConnectionPage() {
|
|
|
546
540
|
setOnboardingInProgress(false);
|
|
547
541
|
}
|
|
548
542
|
},
|
|
549
|
-
[
|
|
543
|
+
[stopPoll]
|
|
550
544
|
);
|
|
551
|
-
const
|
|
552
|
-
(
|
|
545
|
+
const startStatusPoll = react.useCallback(() => {
|
|
546
|
+
stopPoll();
|
|
547
|
+
let ticks = 0;
|
|
548
|
+
pollRef.current = setInterval(async () => {
|
|
549
|
+
var _a;
|
|
550
|
+
ticks += 1;
|
|
551
|
+
if (completedRef.current || ticks > 150) {
|
|
552
|
+
stopPoll();
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
try {
|
|
556
|
+
const r = await fetch(`${STATUS_ENDPOINT}?environment=${envRef.current}`, {
|
|
557
|
+
method: "GET",
|
|
558
|
+
credentials: "include"
|
|
559
|
+
});
|
|
560
|
+
const st = await r.json().catch(() => ({}));
|
|
561
|
+
if ((st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true) {
|
|
562
|
+
completedRef.current = true;
|
|
563
|
+
stopPoll();
|
|
564
|
+
try {
|
|
565
|
+
(_a = popupRef.current) == null ? void 0 : _a.close();
|
|
566
|
+
} catch {
|
|
567
|
+
}
|
|
568
|
+
clearCachedUrl(envRef.current);
|
|
569
|
+
setStatusInfo(st);
|
|
570
|
+
setConnState("connected");
|
|
571
|
+
setShowManual(false);
|
|
572
|
+
setOnboardingInProgress(false);
|
|
573
|
+
}
|
|
574
|
+
} catch {
|
|
575
|
+
}
|
|
576
|
+
}, 2e3);
|
|
577
|
+
}, [stopPoll]);
|
|
578
|
+
const generateLinkAndReload = react.useCallback(
|
|
579
|
+
async (targetEnv, runId) => {
|
|
553
580
|
if (initLoaderRef.current) {
|
|
554
581
|
const loaderText = initLoaderRef.current.querySelector("#loader-text");
|
|
555
|
-
if (loaderText)
|
|
556
|
-
loaderText.textContent = "Generating onboarding session...";
|
|
582
|
+
if (loaderText) loaderText.textContent = "Generating onboarding session...";
|
|
557
583
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
products: ["PPCP"],
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
})
|
|
568
|
-
}).then((r) => {
|
|
569
|
-
if (!r.ok) throw new Error(`Service returned ${r.status}`);
|
|
570
|
-
return r.json();
|
|
571
|
-
}).then((data) => {
|
|
584
|
+
try {
|
|
585
|
+
const res = await fetch(SERVICE_URL, {
|
|
586
|
+
method: "POST",
|
|
587
|
+
headers: { "content-type": "application/json" },
|
|
588
|
+
credentials: "include",
|
|
589
|
+
body: JSON.stringify({ products: ["PPCP"], environment: targetEnv })
|
|
590
|
+
});
|
|
591
|
+
if (!res.ok) throw new Error(`Service returned ${res.status}`);
|
|
592
|
+
const data = await res.json();
|
|
572
593
|
if (runId !== currentRunId.current) return;
|
|
573
594
|
const href = data == null ? void 0 : data.onboarding_url;
|
|
574
595
|
if (!href) {
|
|
@@ -576,13 +597,17 @@ function PayPalConnectionPage() {
|
|
|
576
597
|
return;
|
|
577
598
|
}
|
|
578
599
|
const url = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
|
|
579
|
-
writeCachedUrl(targetEnv, url);
|
|
600
|
+
const persisted = writeCachedUrl(targetEnv, url);
|
|
601
|
+
if (persisted) {
|
|
602
|
+
window.location.reload();
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
580
605
|
setFinalUrl(url);
|
|
581
606
|
setConnState("ready");
|
|
582
|
-
}
|
|
607
|
+
} catch {
|
|
583
608
|
if (runId !== currentRunId.current) return;
|
|
584
609
|
showError("Unable to connect to service.");
|
|
585
|
-
}
|
|
610
|
+
}
|
|
586
611
|
},
|
|
587
612
|
[showError]
|
|
588
613
|
);
|
|
@@ -599,6 +624,48 @@ function PayPalConnectionPage() {
|
|
|
599
624
|
alive = false;
|
|
600
625
|
};
|
|
601
626
|
}, []);
|
|
627
|
+
react.useEffect(() => {
|
|
628
|
+
if (!envReady) return;
|
|
629
|
+
currentRunId.current = ++runIdRef.current;
|
|
630
|
+
const runId = currentRunId.current;
|
|
631
|
+
let cancelled = false;
|
|
632
|
+
completedRef.current = false;
|
|
633
|
+
const run = async () => {
|
|
634
|
+
setConnState("loading");
|
|
635
|
+
setError(null);
|
|
636
|
+
setPopupBlocked(false);
|
|
637
|
+
setFinalUrl("");
|
|
638
|
+
try {
|
|
639
|
+
const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
640
|
+
method: "GET",
|
|
641
|
+
credentials: "include"
|
|
642
|
+
});
|
|
643
|
+
const st = await r.json().catch(() => ({}));
|
|
644
|
+
if (cancelled || runId !== currentRunId.current) return;
|
|
645
|
+
setStatusInfo(st);
|
|
646
|
+
const isConnected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
|
|
647
|
+
if (isConnected) {
|
|
648
|
+
setConnState("connected");
|
|
649
|
+
setShowManual(false);
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
} catch (e) {
|
|
653
|
+
console.error(e);
|
|
654
|
+
}
|
|
655
|
+
if (cancelled || runId !== currentRunId.current) return;
|
|
656
|
+
const cached = readCachedUrl(env);
|
|
657
|
+
if (cached) {
|
|
658
|
+
setFinalUrl(cached);
|
|
659
|
+
setConnState("ready");
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
await generateLinkAndReload(env, runId);
|
|
663
|
+
};
|
|
664
|
+
run();
|
|
665
|
+
return () => {
|
|
666
|
+
cancelled = true;
|
|
667
|
+
};
|
|
668
|
+
}, [env, envReady, generateLinkAndReload]);
|
|
602
669
|
react.useEffect(() => {
|
|
603
670
|
var _a, _b, _c;
|
|
604
671
|
if (connState !== "ready" || !finalUrl) return;
|
|
@@ -653,16 +720,27 @@ function PayPalConnectionPage() {
|
|
|
653
720
|
document.body.appendChild(ppScript);
|
|
654
721
|
return () => {
|
|
655
722
|
cancelled = true;
|
|
656
|
-
if (pollTimer)
|
|
657
|
-
|
|
658
|
-
}
|
|
659
|
-
if (ppScript.parentNode) {
|
|
660
|
-
ppScript.parentNode.removeChild(ppScript);
|
|
661
|
-
}
|
|
723
|
+
if (pollTimer) clearTimeout(pollTimer);
|
|
724
|
+
if (ppScript.parentNode) ppScript.parentNode.removeChild(ppScript);
|
|
662
725
|
};
|
|
663
726
|
}, [connState, finalUrl, env]);
|
|
664
727
|
react.useEffect(() => {
|
|
665
728
|
const onMessage = (ev) => {
|
|
729
|
+
let serialized = "";
|
|
730
|
+
try {
|
|
731
|
+
serialized = typeof ev.data === "string" ? ev.data : JSON.stringify(ev.data);
|
|
732
|
+
} catch {
|
|
733
|
+
serialized = String(ev.data);
|
|
734
|
+
}
|
|
735
|
+
const looksRelevant = isPayPalOrigin(ev.origin) || /auth_?code|shared_?id|onboard|merchantId/i.test(serialized || "");
|
|
736
|
+
if (looksRelevant) {
|
|
737
|
+
console.info(
|
|
738
|
+
"[PayPal onboarding] message from",
|
|
739
|
+
ev.origin,
|
|
740
|
+
"·",
|
|
741
|
+
(serialized || "").slice(0, 500)
|
|
742
|
+
);
|
|
743
|
+
}
|
|
666
744
|
if (!isPayPalOrigin(ev.origin)) return;
|
|
667
745
|
const { authCode, sharedId } = extractAuth(ev.data);
|
|
668
746
|
if (authCode && sharedId) {
|
|
@@ -672,48 +750,6 @@ function PayPalConnectionPage() {
|
|
|
672
750
|
window.addEventListener("message", onMessage);
|
|
673
751
|
return () => window.removeEventListener("message", onMessage);
|
|
674
752
|
}, [completeOnboarding]);
|
|
675
|
-
react.useEffect(() => {
|
|
676
|
-
if (!envReady) return;
|
|
677
|
-
currentRunId.current = ++runIdRef.current;
|
|
678
|
-
const runId = currentRunId.current;
|
|
679
|
-
let cancelled = false;
|
|
680
|
-
completedRef.current = false;
|
|
681
|
-
const run = async () => {
|
|
682
|
-
setConnState("loading");
|
|
683
|
-
setError(null);
|
|
684
|
-
setPopupBlocked(false);
|
|
685
|
-
setFinalUrl("");
|
|
686
|
-
try {
|
|
687
|
-
const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
688
|
-
method: "GET",
|
|
689
|
-
credentials: "include"
|
|
690
|
-
});
|
|
691
|
-
const st = await r.json().catch(() => ({}));
|
|
692
|
-
if (cancelled || runId !== currentRunId.current) return;
|
|
693
|
-
setStatusInfo(st);
|
|
694
|
-
const isConnected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
|
|
695
|
-
if (isConnected) {
|
|
696
|
-
setConnState("connected");
|
|
697
|
-
setShowManual(false);
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
} catch (e) {
|
|
701
|
-
console.error(e);
|
|
702
|
-
}
|
|
703
|
-
if (cancelled || runId !== currentRunId.current) return;
|
|
704
|
-
const cached = readCachedUrl(env);
|
|
705
|
-
if (cached) {
|
|
706
|
-
setFinalUrl(cached);
|
|
707
|
-
setConnState("ready");
|
|
708
|
-
} else {
|
|
709
|
-
fetchFreshLink(runId, env);
|
|
710
|
-
}
|
|
711
|
-
};
|
|
712
|
-
run();
|
|
713
|
-
return () => {
|
|
714
|
-
cancelled = true;
|
|
715
|
-
};
|
|
716
|
-
}, [env, envReady, fetchFreshLink]);
|
|
717
753
|
react.useLayoutEffect(() => {
|
|
718
754
|
window.onboardingCallback = (authCode, sharedId) => {
|
|
719
755
|
completeOnboarding(authCode, sharedId);
|
|
@@ -723,10 +759,31 @@ function PayPalConnectionPage() {
|
|
|
723
759
|
};
|
|
724
760
|
}, [completeOnboarding]);
|
|
725
761
|
react.useEffect(() => {
|
|
726
|
-
|
|
727
|
-
|
|
762
|
+
const onCaptureClick = (e) => {
|
|
763
|
+
const btn = paypalButtonRef.current;
|
|
764
|
+
if (!btn) return;
|
|
765
|
+
const target = e.target;
|
|
766
|
+
if (!target || !btn.contains(target)) return;
|
|
767
|
+
e.preventDefault();
|
|
768
|
+
e.stopImmediatePropagation();
|
|
769
|
+
if (connStateRef.current !== "ready" || !finalUrlRef.current || inProgressRef.current) {
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
completedRef.current = false;
|
|
773
|
+
const popup = openOnboardingPopup(finalUrlRef.current);
|
|
774
|
+
if (!popup) {
|
|
775
|
+
setPopupBlocked(true);
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
setPopupBlocked(false);
|
|
779
|
+
startStatusPoll();
|
|
728
780
|
};
|
|
729
|
-
|
|
781
|
+
document.addEventListener("click", onCaptureClick, true);
|
|
782
|
+
return () => document.removeEventListener("click", onCaptureClick, true);
|
|
783
|
+
}, [openOnboardingPopup, startStatusPoll]);
|
|
784
|
+
react.useEffect(() => {
|
|
785
|
+
return () => stopPoll();
|
|
786
|
+
}, [stopPoll]);
|
|
730
787
|
react.useLayoutEffect(() => {
|
|
731
788
|
const el = ppBtnMeasureRef.current;
|
|
732
789
|
if (!el) return;
|
|
@@ -747,23 +804,6 @@ function PayPalConnectionPage() {
|
|
|
747
804
|
else window.removeEventListener("resize", update);
|
|
748
805
|
};
|
|
749
806
|
}, [connState, env, finalUrl]);
|
|
750
|
-
react.useEffect(() => {
|
|
751
|
-
const onCaptureClick = (e) => {
|
|
752
|
-
const btn = paypalButtonRef.current;
|
|
753
|
-
if (!btn) return;
|
|
754
|
-
const target = e.target;
|
|
755
|
-
if (!target || !btn.contains(target)) return;
|
|
756
|
-
e.preventDefault();
|
|
757
|
-
if (connStateRef.current !== "ready" || !finalUrlRef.current || inProgressRef.current) {
|
|
758
|
-
return;
|
|
759
|
-
}
|
|
760
|
-
completedRef.current = false;
|
|
761
|
-
const popup = openOnboardingPopup(finalUrlRef.current);
|
|
762
|
-
setPopupBlocked(!popup);
|
|
763
|
-
};
|
|
764
|
-
document.addEventListener("click", onCaptureClick, true);
|
|
765
|
-
return () => document.removeEventListener("click", onCaptureClick, true);
|
|
766
|
-
}, [openOnboardingPopup]);
|
|
767
807
|
const handleConnectClick = (e) => {
|
|
768
808
|
e.preventDefault();
|
|
769
809
|
};
|
|
@@ -827,8 +867,7 @@ function PayPalConnectionPage() {
|
|
|
827
867
|
clearCachedUrl(env);
|
|
828
868
|
completedRef.current = false;
|
|
829
869
|
currentRunId.current = ++runIdRef.current;
|
|
830
|
-
|
|
831
|
-
fetchFreshLink(runId, env);
|
|
870
|
+
await generateLinkAndReload(env, currentRunId.current);
|
|
832
871
|
} catch (e) {
|
|
833
872
|
console.error(e);
|
|
834
873
|
setConnState("error");
|
|
@@ -839,10 +878,11 @@ function PayPalConnectionPage() {
|
|
|
839
878
|
};
|
|
840
879
|
const handleEnvChange = async (e) => {
|
|
841
880
|
const next = e.target.value;
|
|
881
|
+
if (next === env || onboardingInProgress) return;
|
|
842
882
|
completedRef.current = false;
|
|
843
|
-
setPopupBlocked(false);
|
|
844
883
|
clearCachedUrl();
|
|
845
|
-
|
|
884
|
+
setPopupBlocked(false);
|
|
885
|
+
setConnState("loading");
|
|
846
886
|
try {
|
|
847
887
|
await fetch(ENVIRONMENT_ENDPOINT, {
|
|
848
888
|
method: "POST",
|
|
@@ -852,6 +892,7 @@ function PayPalConnectionPage() {
|
|
|
852
892
|
});
|
|
853
893
|
} catch {
|
|
854
894
|
}
|
|
895
|
+
setEnv(next);
|
|
855
896
|
};
|
|
856
897
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6", children: [
|
|
857
898
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
@@ -1085,6 +1126,9 @@ function PayPalConnectionPage() {
|
|
|
1085
1126
|
` })
|
|
1086
1127
|
] });
|
|
1087
1128
|
}
|
|
1129
|
+
function PayPalGooglePayPage() {
|
|
1130
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
1131
|
+
}
|
|
1088
1132
|
function PayPalPayLaterMessagingPage() {
|
|
1089
1133
|
return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
1090
1134
|
}
|
|
@@ -1302,10 +1346,6 @@ const routeModule = {
|
|
|
1302
1346
|
Component: PayPalSettingsIndexRoute,
|
|
1303
1347
|
path: "/settings/paypal"
|
|
1304
1348
|
},
|
|
1305
|
-
{
|
|
1306
|
-
Component: AdvancedCardPaymentsTab,
|
|
1307
|
-
path: "/settings/paypal/advanced-card-payments"
|
|
1308
|
-
},
|
|
1309
1349
|
{
|
|
1310
1350
|
Component: AdditionalSettingsTab,
|
|
1311
1351
|
path: "/settings/paypal/additional-settings"
|
|
@@ -1315,13 +1355,17 @@ const routeModule = {
|
|
|
1315
1355
|
path: "/settings/paypal/apple-pay"
|
|
1316
1356
|
},
|
|
1317
1357
|
{
|
|
1318
|
-
Component:
|
|
1319
|
-
path: "/settings/paypal/
|
|
1358
|
+
Component: AdvancedCardPaymentsTab,
|
|
1359
|
+
path: "/settings/paypal/advanced-card-payments"
|
|
1320
1360
|
},
|
|
1321
1361
|
{
|
|
1322
1362
|
Component: PayPalConnectionPage,
|
|
1323
1363
|
path: "/settings/paypal/connection"
|
|
1324
1364
|
},
|
|
1365
|
+
{
|
|
1366
|
+
Component: PayPalGooglePayPage,
|
|
1367
|
+
path: "/settings/paypal/google-pay"
|
|
1368
|
+
},
|
|
1325
1369
|
{
|
|
1326
1370
|
Component: PayPalPayLaterMessagingPage,
|
|
1327
1371
|
path: "/settings/paypal/pay-later-messaging"
|