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