@easypayment/medusa-payment-paypal 0.9.21 → 0.9.22
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 +200 -326
- package/.medusa/server/src/admin/index.mjs +200 -326
- 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 +208 -379
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js.map +1 -1
- package/package.json +1 -1
- package/src/admin/routes/settings/paypal/connection/page.tsx +234 -423
|
@@ -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,55 @@ 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
|
}
|
|
219
226
|
const DEFAULT_FORM = {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
requireInstantPayment: false,
|
|
224
|
-
sendItemDetails: true,
|
|
225
|
-
invoicePrefix: "PP-",
|
|
226
|
-
creditCardStatementName: "PayPal"
|
|
227
|
+
enabled: true,
|
|
228
|
+
title: "Credit or Debit Card",
|
|
229
|
+
threeDS: "when_required"
|
|
227
230
|
};
|
|
228
231
|
function mergeWithDefaults(saved) {
|
|
229
232
|
if (!saved) return { ...DEFAULT_FORM };
|
|
230
233
|
const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
|
|
231
234
|
return { ...DEFAULT_FORM, ...Object.fromEntries(entries) };
|
|
232
235
|
}
|
|
233
|
-
|
|
236
|
+
const THREE_DS_OPTIONS = [
|
|
237
|
+
{ value: "when_required", label: "3D Secure when required", hint: "Triggers 3DS only when the card / issuer requires it." },
|
|
238
|
+
{ value: "sli", label: "3D Secure (SCA) / liability shift (recommended)", hint: "Attempts to optimize for liability shift while remaining compliant." },
|
|
239
|
+
{ value: "always", label: "Always request 3D Secure", hint: "Forces 3DS challenge whenever possible (may reduce conversion)." }
|
|
240
|
+
];
|
|
241
|
+
function AdvancedCardPaymentsTab() {
|
|
242
|
+
var _a, _b;
|
|
234
243
|
const [form, setForm] = useState(() => ({ ...DEFAULT_FORM }));
|
|
235
244
|
const [loading, setLoading] = useState(false);
|
|
236
245
|
const [saving, setSaving] = useState(false);
|
|
@@ -245,7 +254,7 @@ function AdditionalSettingsTab() {
|
|
|
245
254
|
setLoading(true);
|
|
246
255
|
const json = await adminFetch("/admin/paypal/settings");
|
|
247
256
|
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
248
|
-
const saved = payload == null ? void 0 : payload.
|
|
257
|
+
const saved = payload == null ? void 0 : payload.advanced_card_payments;
|
|
249
258
|
if (saved && typeof saved === "object") setForm(mergeWithDefaults(saved));
|
|
250
259
|
} catch {
|
|
251
260
|
} finally {
|
|
@@ -256,14 +265,16 @@ function AdditionalSettingsTab() {
|
|
|
256
265
|
async function onSave() {
|
|
257
266
|
try {
|
|
258
267
|
setSaving(true);
|
|
259
|
-
|
|
260
|
-
|
|
268
|
+
const json = await adminFetch("/admin/paypal/settings", {
|
|
269
|
+
method: "POST",
|
|
270
|
+
body: { advanced_card_payments: form }
|
|
271
|
+
});
|
|
261
272
|
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
262
|
-
const saved = payload == null ? void 0 : payload.
|
|
273
|
+
const saved = payload == null ? void 0 : payload.advanced_card_payments;
|
|
263
274
|
if (saved && typeof saved === "object") setForm(mergeWithDefaults(saved));
|
|
264
275
|
setToast({ kind: "success", message: "Settings saved" });
|
|
265
276
|
} catch (e) {
|
|
266
|
-
setToast({ kind: "error", message: e instanceof Error ? e.message : "Failed to save settings" });
|
|
277
|
+
setToast({ kind: "error", message: (e instanceof Error ? e.message : "") || "Failed to save settings." });
|
|
267
278
|
} finally {
|
|
268
279
|
setSaving(false);
|
|
269
280
|
}
|
|
@@ -275,33 +286,22 @@ function AdditionalSettingsTab() {
|
|
|
275
286
|
/* @__PURE__ */ jsx(
|
|
276
287
|
SectionCard,
|
|
277
288
|
{
|
|
278
|
-
title: "
|
|
279
|
-
description: "
|
|
289
|
+
title: "Advanced Card Payments",
|
|
290
|
+
description: "Control card checkout settings and 3D Secure behavior.",
|
|
280
291
|
right: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
281
292
|
/* @__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
293
|
loading ? /* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading…" }) : null
|
|
283
294
|
] }),
|
|
284
295
|
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" })
|
|
296
|
+
/* @__PURE__ */ jsx(FieldRow, { label: "Enable/Disable", children: /* @__PURE__ */ jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
297
|
+
/* @__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" }),
|
|
298
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable Advanced Credit/Debit Card" })
|
|
302
299
|
] }) }),
|
|
303
|
-
/* @__PURE__ */ jsx(FieldRow, { label: "
|
|
304
|
-
/* @__PURE__ */ jsx(FieldRow, { label: "
|
|
300
|
+
/* @__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" }) }),
|
|
301
|
+
/* @__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: [
|
|
302
|
+
/* @__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)) }),
|
|
303
|
+
((_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
|
|
304
|
+
] }) })
|
|
305
305
|
] })
|
|
306
306
|
}
|
|
307
307
|
)
|
|
@@ -323,7 +323,7 @@ const PARTNER_JS_URLS = {
|
|
|
323
323
|
const SERVICE_URL = "/admin/paypal/onboarding-link";
|
|
324
324
|
const POPUP_NAME = "PPFrame";
|
|
325
325
|
const CACHE_PREFIX = "pp_onboard_cache";
|
|
326
|
-
const CACHE_EXPIRY =
|
|
326
|
+
const CACHE_EXPIRY = 6 * 60 * 60 * 1e3;
|
|
327
327
|
const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
|
|
328
328
|
const STATUS_ENDPOINT = "/admin/paypal/status";
|
|
329
329
|
const SAVE_CREDENTIALS_ENDPOINT = "/admin/paypal/save-credentials";
|
|
@@ -346,7 +346,9 @@ function readCachedUrl(env) {
|
|
|
346
346
|
function writeCachedUrl(env, url) {
|
|
347
347
|
try {
|
|
348
348
|
localStorage.setItem(cacheKeyFor(env), JSON.stringify({ url, ts: Date.now() }));
|
|
349
|
+
return readCachedUrl(env) === url;
|
|
349
350
|
} catch {
|
|
351
|
+
return false;
|
|
350
352
|
}
|
|
351
353
|
}
|
|
352
354
|
function clearCachedUrl(env) {
|
|
@@ -360,58 +362,12 @@ function clearCachedUrl(env) {
|
|
|
360
362
|
} catch {
|
|
361
363
|
}
|
|
362
364
|
}
|
|
363
|
-
function isPayPalOrigin(origin) {
|
|
364
|
-
try {
|
|
365
|
-
const host = new URL(origin).hostname.toLowerCase();
|
|
366
|
-
return host === "www.paypal.com" || host === "www.sandbox.paypal.com" || host.endsWith(".paypal.com") || host.endsWith(".paypalobjects.com");
|
|
367
|
-
} catch {
|
|
368
|
-
return false;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
function extractAuth(data) {
|
|
372
|
-
if (!data) return {};
|
|
373
|
-
if (typeof data === "object") {
|
|
374
|
-
const obj = data;
|
|
375
|
-
const authCode = obj.authCode ?? obj.auth_code ?? obj.authcode;
|
|
376
|
-
const sharedId = obj.sharedId ?? obj.shared_id ?? obj.sharedid;
|
|
377
|
-
if (authCode && sharedId) {
|
|
378
|
-
return { authCode: String(authCode), sharedId: String(sharedId) };
|
|
379
|
-
}
|
|
380
|
-
for (const key of ["data", "payload", "message", "detail", "body"]) {
|
|
381
|
-
if (obj[key] && typeof obj[key] === "object") {
|
|
382
|
-
const inner = extractAuth(obj[key]);
|
|
383
|
-
if (inner.authCode && inner.sharedId) return inner;
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
return {};
|
|
387
|
-
}
|
|
388
|
-
if (typeof data === "string") {
|
|
389
|
-
const s = data.trim();
|
|
390
|
-
if (!s) return {};
|
|
391
|
-
if (s.startsWith("{")) {
|
|
392
|
-
try {
|
|
393
|
-
return extractAuth(JSON.parse(s));
|
|
394
|
-
} catch {
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
if (/auth_?code/i.test(s) && /shared_?id/i.test(s)) {
|
|
398
|
-
try {
|
|
399
|
-
const sp = new URLSearchParams(s.replace(/^[?#]/, ""));
|
|
400
|
-
const authCode = sp.get("authCode") || sp.get("auth_code") || void 0;
|
|
401
|
-
const sharedId = sp.get("sharedId") || sp.get("shared_id") || void 0;
|
|
402
|
-
if (authCode && sharedId) return { authCode, sharedId };
|
|
403
|
-
} catch {
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
return {};
|
|
408
|
-
}
|
|
409
365
|
function PayPalConnectionPage() {
|
|
410
366
|
const [env, setEnv] = useState("live");
|
|
411
367
|
const [envReady, setEnvReady] = useState(false);
|
|
412
368
|
const [connState, setConnState] = useState("loading");
|
|
369
|
+
const [partnerReady, setPartnerReady] = useState(false);
|
|
413
370
|
const [error, setError] = useState(null);
|
|
414
|
-
const [popupBlocked, setPopupBlocked] = useState(false);
|
|
415
371
|
const [finalUrl, setFinalUrl] = useState("");
|
|
416
372
|
const [showManual, setShowManual] = useState(false);
|
|
417
373
|
const [clientId, setClientId] = useState("");
|
|
@@ -419,20 +375,11 @@ function PayPalConnectionPage() {
|
|
|
419
375
|
const [statusInfo, setStatusInfo] = useState(null);
|
|
420
376
|
const [onboardingInProgress, setOnboardingInProgress] = useState(false);
|
|
421
377
|
const initLoaderRef = useRef(null);
|
|
422
|
-
const paypalButtonRef = useRef(null);
|
|
423
378
|
const errorLogRef = useRef(null);
|
|
424
379
|
const runIdRef = useRef(0);
|
|
425
380
|
const currentRunId = useRef(0);
|
|
426
|
-
const finalUrlRef = useRef(finalUrl);
|
|
427
|
-
finalUrlRef.current = finalUrl;
|
|
428
|
-
const connStateRef = useRef(connState);
|
|
429
|
-
connStateRef.current = connState;
|
|
430
|
-
const inProgressRef = useRef(onboardingInProgress);
|
|
431
|
-
inProgressRef.current = onboardingInProgress;
|
|
432
381
|
const envRef = useRef(env);
|
|
433
382
|
envRef.current = env;
|
|
434
|
-
const popupRef = useRef(null);
|
|
435
|
-
const popupPollRef = useRef(null);
|
|
436
383
|
const completedRef = useRef(false);
|
|
437
384
|
const ppBtnMeasureRef = useRef(null);
|
|
438
385
|
const [ppBtnWidth, setPpBtnWidth] = useState(null);
|
|
@@ -443,131 +390,23 @@ function PayPalConnectionPage() {
|
|
|
443
390
|
setConnState("error");
|
|
444
391
|
setError(msg);
|
|
445
392
|
}, []);
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
const openOnboardingPopup = useCallback(
|
|
453
|
-
(url) => {
|
|
454
|
-
const w = 450;
|
|
455
|
-
const h = 600;
|
|
456
|
-
const baseLeft = typeof window.screenX === "number" ? window.screenX : window.screenLeft || 0;
|
|
457
|
-
const baseTop = typeof window.screenY === "number" ? window.screenY : window.screenTop || 0;
|
|
458
|
-
const outerW = window.outerWidth || document.documentElement.clientWidth || 1024;
|
|
459
|
-
const outerH = window.outerHeight || document.documentElement.clientHeight || 768;
|
|
460
|
-
const left = Math.round(baseLeft + Math.max(0, (outerW - w) / 2));
|
|
461
|
-
const top = Math.round(baseTop + Math.max(0, (outerH - h) / 2));
|
|
462
|
-
const features = `popup=yes,width=${w},height=${h},left=${left},top=${top},scrollbars=yes,resizable=yes`;
|
|
463
|
-
let popup = null;
|
|
464
|
-
try {
|
|
465
|
-
popup = window.open(url, POPUP_NAME, features);
|
|
466
|
-
} catch {
|
|
467
|
-
popup = null;
|
|
468
|
-
}
|
|
469
|
-
if (popup) {
|
|
470
|
-
popupRef.current = popup;
|
|
471
|
-
try {
|
|
472
|
-
popup.focus();
|
|
473
|
-
} catch {
|
|
393
|
+
const generateLinkAndReload = useCallback(
|
|
394
|
+
async (targetEnv, runId) => {
|
|
395
|
+
if (initLoaderRef.current) {
|
|
396
|
+
const loaderText = initLoaderRef.current.querySelector("#loader-text");
|
|
397
|
+
if (loaderText) {
|
|
398
|
+
loaderText.textContent = "Generating onboarding session...";
|
|
474
399
|
}
|
|
475
|
-
stopPopupPoll();
|
|
476
|
-
popupPollRef.current = setInterval(() => {
|
|
477
|
-
if (!popupRef.current || popupRef.current.closed) {
|
|
478
|
-
stopPopupPoll();
|
|
479
|
-
}
|
|
480
|
-
}, 1e3);
|
|
481
400
|
}
|
|
482
|
-
return popup;
|
|
483
|
-
},
|
|
484
|
-
[stopPopupPoll]
|
|
485
|
-
);
|
|
486
|
-
const completeOnboarding = useCallback(
|
|
487
|
-
async (authCode, sharedId) => {
|
|
488
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
489
|
-
if (!authCode || !sharedId) return;
|
|
490
|
-
if (completedRef.current) return;
|
|
491
|
-
completedRef.current = true;
|
|
492
401
|
try {
|
|
493
|
-
|
|
494
|
-
} catch {
|
|
495
|
-
}
|
|
496
|
-
const activeEnv = envRef.current === "sandbox" ? "sandbox" : "live";
|
|
497
|
-
setOnboardingInProgress(true);
|
|
498
|
-
setConnState("loading");
|
|
499
|
-
setError(null);
|
|
500
|
-
setPopupBlocked(false);
|
|
501
|
-
try {
|
|
502
|
-
const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
|
|
402
|
+
const res = await fetch(SERVICE_URL, {
|
|
503
403
|
method: "POST",
|
|
504
404
|
headers: { "content-type": "application/json" },
|
|
505
405
|
credentials: "include",
|
|
506
|
-
body: JSON.stringify({
|
|
406
|
+
body: JSON.stringify({ products: ["PPCP"], environment: targetEnv })
|
|
507
407
|
});
|
|
508
|
-
if (!res.ok) {
|
|
509
|
-
|
|
510
|
-
throw new Error(txt || `Onboarding exchange failed (${res.status})`);
|
|
511
|
-
}
|
|
512
|
-
try {
|
|
513
|
-
(_a = popupRef.current) == null ? void 0 : _a.close();
|
|
514
|
-
} catch {
|
|
515
|
-
}
|
|
516
|
-
stopPopupPoll();
|
|
517
|
-
try {
|
|
518
|
-
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
|
-
if (typeof close1 === "function") close1();
|
|
520
|
-
} catch {
|
|
521
|
-
}
|
|
522
|
-
try {
|
|
523
|
-
const close2 = ((_h = (_g = (_f = window.PAYPAL) == null ? void 0 : _f.apps) == null ? void 0 : _g.Signup) == null ? void 0 : _h.miniBrowser) && window.PAYPAL.apps.Signup.miniBrowser.closeFlow;
|
|
524
|
-
if (typeof close2 === "function") close2();
|
|
525
|
-
} catch {
|
|
526
|
-
}
|
|
527
|
-
clearCachedUrl(activeEnv);
|
|
528
|
-
try {
|
|
529
|
-
const statusRes = await fetch(
|
|
530
|
-
`${STATUS_ENDPOINT}?environment=${activeEnv}`,
|
|
531
|
-
{ method: "GET", credentials: "include" }
|
|
532
|
-
);
|
|
533
|
-
const refreshedStatus = await statusRes.json().catch(() => ({}));
|
|
534
|
-
setStatusInfo(refreshedStatus || null);
|
|
535
|
-
} catch {
|
|
536
|
-
}
|
|
537
|
-
setConnState("connected");
|
|
538
|
-
setShowManual(false);
|
|
539
|
-
} catch (e) {
|
|
540
|
-
completedRef.current = false;
|
|
541
|
-
console.error(e);
|
|
542
|
-
setConnState("error");
|
|
543
|
-
setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
|
|
544
|
-
} finally {
|
|
545
|
-
setOnboardingInProgress(false);
|
|
546
|
-
}
|
|
547
|
-
},
|
|
548
|
-
[stopPopupPoll]
|
|
549
|
-
);
|
|
550
|
-
const fetchFreshLink = useCallback(
|
|
551
|
-
(runId, targetEnv) => {
|
|
552
|
-
if (initLoaderRef.current) {
|
|
553
|
-
const loaderText = initLoaderRef.current.querySelector("#loader-text");
|
|
554
|
-
if (loaderText)
|
|
555
|
-
loaderText.textContent = "Generating onboarding session...";
|
|
556
|
-
}
|
|
557
|
-
fetch(SERVICE_URL, {
|
|
558
|
-
method: "POST",
|
|
559
|
-
headers: { "content-type": "application/json" },
|
|
560
|
-
credentials: "include",
|
|
561
|
-
body: JSON.stringify({
|
|
562
|
-
products: ["PPCP"],
|
|
563
|
-
// Generate the link for the explicitly selected environment so it can
|
|
564
|
-
// never depend on a racing POST /environment having landed yet.
|
|
565
|
-
environment: targetEnv
|
|
566
|
-
})
|
|
567
|
-
}).then((r) => {
|
|
568
|
-
if (!r.ok) throw new Error(`Service returned ${r.status}`);
|
|
569
|
-
return r.json();
|
|
570
|
-
}).then((data) => {
|
|
408
|
+
if (!res.ok) throw new Error(`Service returned ${res.status}`);
|
|
409
|
+
const data = await res.json();
|
|
571
410
|
if (runId !== currentRunId.current) return;
|
|
572
411
|
const href = data == null ? void 0 : data.onboarding_url;
|
|
573
412
|
if (!href) {
|
|
@@ -575,13 +414,17 @@ function PayPalConnectionPage() {
|
|
|
575
414
|
return;
|
|
576
415
|
}
|
|
577
416
|
const url = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
|
|
578
|
-
writeCachedUrl(targetEnv, url);
|
|
417
|
+
const persisted = writeCachedUrl(targetEnv, url);
|
|
418
|
+
if (persisted) {
|
|
419
|
+
window.location.reload();
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
579
422
|
setFinalUrl(url);
|
|
580
423
|
setConnState("ready");
|
|
581
|
-
}
|
|
424
|
+
} catch {
|
|
582
425
|
if (runId !== currentRunId.current) return;
|
|
583
426
|
showError("Unable to connect to service.");
|
|
584
|
-
}
|
|
427
|
+
}
|
|
585
428
|
},
|
|
586
429
|
[showError]
|
|
587
430
|
);
|
|
@@ -598,12 +441,60 @@ function PayPalConnectionPage() {
|
|
|
598
441
|
alive = false;
|
|
599
442
|
};
|
|
600
443
|
}, []);
|
|
444
|
+
useEffect(() => {
|
|
445
|
+
if (!envReady) return;
|
|
446
|
+
currentRunId.current = ++runIdRef.current;
|
|
447
|
+
const runId = currentRunId.current;
|
|
448
|
+
let cancelled = false;
|
|
449
|
+
completedRef.current = false;
|
|
450
|
+
const run = async () => {
|
|
451
|
+
setConnState("loading");
|
|
452
|
+
setError(null);
|
|
453
|
+
setFinalUrl("");
|
|
454
|
+
try {
|
|
455
|
+
const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
456
|
+
method: "GET",
|
|
457
|
+
credentials: "include"
|
|
458
|
+
});
|
|
459
|
+
const st = await r.json().catch(() => ({}));
|
|
460
|
+
if (cancelled || runId !== currentRunId.current) return;
|
|
461
|
+
setStatusInfo(st);
|
|
462
|
+
const isConnected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
|
|
463
|
+
if (isConnected) {
|
|
464
|
+
setConnState("connected");
|
|
465
|
+
setShowManual(false);
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
} catch (e) {
|
|
469
|
+
console.error(e);
|
|
470
|
+
}
|
|
471
|
+
if (cancelled || runId !== currentRunId.current) return;
|
|
472
|
+
const cached = readCachedUrl(env);
|
|
473
|
+
if (cached) {
|
|
474
|
+
setFinalUrl(cached);
|
|
475
|
+
setConnState("ready");
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
await generateLinkAndReload(env, runId);
|
|
479
|
+
};
|
|
480
|
+
run();
|
|
481
|
+
return () => {
|
|
482
|
+
cancelled = true;
|
|
483
|
+
};
|
|
484
|
+
}, [env, envReady, generateLinkAndReload]);
|
|
601
485
|
useEffect(() => {
|
|
602
486
|
var _a, _b, _c;
|
|
603
487
|
if (connState !== "ready" || !finalUrl) return;
|
|
604
488
|
const scriptUrl = PARTNER_JS_URLS[env];
|
|
605
489
|
let cancelled = false;
|
|
606
490
|
let pollTimer;
|
|
491
|
+
setPartnerReady(false);
|
|
492
|
+
const readyFallback = setTimeout(() => {
|
|
493
|
+
if (!cancelled) setPartnerReady(true);
|
|
494
|
+
}, 6e3);
|
|
495
|
+
const markReady = () => {
|
|
496
|
+
if (!cancelled) setPartnerReady(true);
|
|
497
|
+
};
|
|
607
498
|
const initPartner = (attempt = 0) => {
|
|
608
499
|
var _a2, _b2;
|
|
609
500
|
if (cancelled) return;
|
|
@@ -615,6 +506,7 @@ function PayPalConnectionPage() {
|
|
|
615
506
|
} catch (e) {
|
|
616
507
|
console.error("[paypal] partner.js init failed:", e);
|
|
617
508
|
}
|
|
509
|
+
markReady();
|
|
618
510
|
return;
|
|
619
511
|
}
|
|
620
512
|
if (typeof (signup == null ? void 0 : signup.render) === "function") {
|
|
@@ -623,6 +515,7 @@ function PayPalConnectionPage() {
|
|
|
623
515
|
} catch (e) {
|
|
624
516
|
console.error("[paypal] partner.js render failed:", e);
|
|
625
517
|
}
|
|
518
|
+
markReady();
|
|
626
519
|
return;
|
|
627
520
|
}
|
|
628
521
|
if (attempt < 40) {
|
|
@@ -633,6 +526,7 @@ function PayPalConnectionPage() {
|
|
|
633
526
|
document.dispatchEvent(new Event("DOMContentLoaded"));
|
|
634
527
|
} catch {
|
|
635
528
|
}
|
|
529
|
+
markReady();
|
|
636
530
|
};
|
|
637
531
|
const existingScript = document.getElementById("paypal-partner-js");
|
|
638
532
|
if (existingScript) {
|
|
@@ -649,9 +543,11 @@ function PayPalConnectionPage() {
|
|
|
649
543
|
ppScript.src = scriptUrl;
|
|
650
544
|
ppScript.async = true;
|
|
651
545
|
ppScript.onload = () => initPartner();
|
|
546
|
+
ppScript.onerror = () => markReady();
|
|
652
547
|
document.body.appendChild(ppScript);
|
|
653
548
|
return () => {
|
|
654
549
|
cancelled = true;
|
|
550
|
+
clearTimeout(readyFallback);
|
|
655
551
|
if (pollTimer) {
|
|
656
552
|
clearTimeout(pollTimer);
|
|
657
553
|
}
|
|
@@ -660,59 +556,61 @@ function PayPalConnectionPage() {
|
|
|
660
556
|
}
|
|
661
557
|
};
|
|
662
558
|
}, [connState, finalUrl, env]);
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
559
|
+
const completeOnboarding = useCallback(async (authCode, sharedId) => {
|
|
560
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
561
|
+
if (!authCode || !sharedId) return;
|
|
562
|
+
if (completedRef.current) return;
|
|
563
|
+
completedRef.current = true;
|
|
564
|
+
try {
|
|
565
|
+
window.onbeforeunload = null;
|
|
566
|
+
} catch {
|
|
567
|
+
}
|
|
568
|
+
const activeEnv = envRef.current === "sandbox" ? "sandbox" : "live";
|
|
569
|
+
setOnboardingInProgress(true);
|
|
570
|
+
setConnState("loading");
|
|
571
|
+
setError(null);
|
|
572
|
+
try {
|
|
573
|
+
const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
|
|
574
|
+
method: "POST",
|
|
575
|
+
headers: { "content-type": "application/json" },
|
|
576
|
+
credentials: "include",
|
|
577
|
+
body: JSON.stringify({ authCode, sharedId, env: activeEnv })
|
|
578
|
+
});
|
|
579
|
+
if (!res.ok) {
|
|
580
|
+
const txt = await res.text().catch(() => "");
|
|
581
|
+
throw new Error(txt || `Onboarding exchange failed (${res.status})`);
|
|
669
582
|
}
|
|
670
|
-
};
|
|
671
|
-
window.addEventListener("message", onMessage);
|
|
672
|
-
return () => window.removeEventListener("message", onMessage);
|
|
673
|
-
}, [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
583
|
try {
|
|
686
|
-
const
|
|
584
|
+
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;
|
|
585
|
+
if (typeof close1 === "function") close1();
|
|
586
|
+
} catch {
|
|
587
|
+
}
|
|
588
|
+
try {
|
|
589
|
+
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;
|
|
590
|
+
if (typeof close2 === "function") close2();
|
|
591
|
+
} catch {
|
|
592
|
+
}
|
|
593
|
+
clearCachedUrl(activeEnv);
|
|
594
|
+
try {
|
|
595
|
+
const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${activeEnv}`, {
|
|
687
596
|
method: "GET",
|
|
688
597
|
credentials: "include"
|
|
689
598
|
});
|
|
690
|
-
const
|
|
691
|
-
|
|
692
|
-
|
|
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);
|
|
599
|
+
const refreshedStatus = await statusRes.json().catch(() => ({}));
|
|
600
|
+
setStatusInfo(refreshedStatus || null);
|
|
601
|
+
} catch {
|
|
709
602
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
603
|
+
setConnState("connected");
|
|
604
|
+
setShowManual(false);
|
|
605
|
+
} catch (e) {
|
|
606
|
+
completedRef.current = false;
|
|
607
|
+
console.error(e);
|
|
608
|
+
setConnState("error");
|
|
609
|
+
setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
|
|
610
|
+
} finally {
|
|
611
|
+
setOnboardingInProgress(false);
|
|
612
|
+
}
|
|
613
|
+
}, []);
|
|
716
614
|
useLayoutEffect(() => {
|
|
717
615
|
window.onboardingCallback = (authCode, sharedId) => {
|
|
718
616
|
completeOnboarding(authCode, sharedId);
|
|
@@ -721,11 +619,6 @@ function PayPalConnectionPage() {
|
|
|
721
619
|
window.onboardingCallback = void 0;
|
|
722
620
|
};
|
|
723
621
|
}, [completeOnboarding]);
|
|
724
|
-
useEffect(() => {
|
|
725
|
-
return () => {
|
|
726
|
-
stopPopupPoll();
|
|
727
|
-
};
|
|
728
|
-
}, [stopPopupPoll]);
|
|
729
622
|
useLayoutEffect(() => {
|
|
730
623
|
const el = ppBtnMeasureRef.current;
|
|
731
624
|
if (!el) return;
|
|
@@ -746,26 +639,6 @@ function PayPalConnectionPage() {
|
|
|
746
639
|
else window.removeEventListener("resize", update);
|
|
747
640
|
};
|
|
748
641
|
}, [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
|
-
const handleConnectClick = (e) => {
|
|
767
|
-
e.preventDefault();
|
|
768
|
-
};
|
|
769
642
|
const handleSaveManual = async () => {
|
|
770
643
|
if (!canSaveManual || onboardingInProgress) return;
|
|
771
644
|
setOnboardingInProgress(true);
|
|
@@ -826,8 +699,7 @@ function PayPalConnectionPage() {
|
|
|
826
699
|
clearCachedUrl(env);
|
|
827
700
|
completedRef.current = false;
|
|
828
701
|
currentRunId.current = ++runIdRef.current;
|
|
829
|
-
|
|
830
|
-
fetchFreshLink(runId, env);
|
|
702
|
+
await generateLinkAndReload(env, currentRunId.current);
|
|
831
703
|
} catch (e) {
|
|
832
704
|
console.error(e);
|
|
833
705
|
setConnState("error");
|
|
@@ -838,10 +710,10 @@ function PayPalConnectionPage() {
|
|
|
838
710
|
};
|
|
839
711
|
const handleEnvChange = async (e) => {
|
|
840
712
|
const next = e.target.value;
|
|
713
|
+
if (next === env || onboardingInProgress) return;
|
|
841
714
|
completedRef.current = false;
|
|
842
|
-
setPopupBlocked(false);
|
|
843
715
|
clearCachedUrl();
|
|
844
|
-
|
|
716
|
+
setConnState("loading");
|
|
845
717
|
try {
|
|
846
718
|
await fetch(ENVIRONMENT_ENDPOINT, {
|
|
847
719
|
method: "POST",
|
|
@@ -851,6 +723,7 @@ function PayPalConnectionPage() {
|
|
|
851
723
|
});
|
|
852
724
|
} catch {
|
|
853
725
|
}
|
|
726
|
+
setEnv(next);
|
|
854
727
|
};
|
|
855
728
|
return /* @__PURE__ */ jsxs("div", { className: "p-6", children: [
|
|
856
729
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
@@ -910,7 +783,6 @@ function PayPalConnectionPage() {
|
|
|
910
783
|
"a",
|
|
911
784
|
{
|
|
912
785
|
ref: (node) => {
|
|
913
|
-
paypalButtonRef.current = node;
|
|
914
786
|
ppBtnMeasureRef.current = node;
|
|
915
787
|
},
|
|
916
788
|
id: "paypal-button",
|
|
@@ -918,17 +790,19 @@ function PayPalConnectionPage() {
|
|
|
918
790
|
"data-paypal-button": "true",
|
|
919
791
|
href: finalUrl || "#",
|
|
920
792
|
"data-paypal-onboard-complete": "onboardingCallback",
|
|
921
|
-
|
|
793
|
+
"aria-disabled": onboardingInProgress || !partnerReady,
|
|
922
794
|
className: "transition-fg relative inline-flex w-fit items-center justify-center overflow-hidden rounded-md outline-none no-underline 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",
|
|
923
795
|
style: {
|
|
924
|
-
cursor: onboardingInProgress ? "not-allowed" : "pointer",
|
|
925
|
-
opacity: onboardingInProgress ? 0.6 : 1,
|
|
926
|
-
|
|
796
|
+
cursor: onboardingInProgress || !partnerReady ? "not-allowed" : "pointer",
|
|
797
|
+
opacity: onboardingInProgress || !partnerReady ? 0.6 : 1,
|
|
798
|
+
// Keep the anchor mounted (partner.js must find it to bind)
|
|
799
|
+
// but un-clickable until partner.js has taken over the
|
|
800
|
+
// click — so it can never open a tab via the native href.
|
|
801
|
+
pointerEvents: onboardingInProgress || !partnerReady ? "none" : "auto"
|
|
927
802
|
},
|
|
928
|
-
children: "Connect to PayPal"
|
|
803
|
+
children: partnerReady || onboardingInProgress ? "Connect to PayPal" : "Preparing PayPal…"
|
|
929
804
|
}
|
|
930
805
|
),
|
|
931
|
-
popupBlocked && /* @__PURE__ */ jsx("div", { className: "mt-3 text-left text-xs bg-amber-50 text-amber-700 p-3 border border-amber-200 rounded", children: "Your browser blocked the PayPal popup. Please allow popups for this site, then click “Connect to PayPal” again." }),
|
|
932
806
|
/* @__PURE__ */ jsx(
|
|
933
807
|
"div",
|
|
934
808
|
{
|
|
@@ -1301,14 +1175,14 @@ const routeModule = {
|
|
|
1301
1175
|
Component: PayPalSettingsIndexRoute,
|
|
1302
1176
|
path: "/settings/paypal"
|
|
1303
1177
|
},
|
|
1304
|
-
{
|
|
1305
|
-
Component: AdvancedCardPaymentsTab,
|
|
1306
|
-
path: "/settings/paypal/advanced-card-payments"
|
|
1307
|
-
},
|
|
1308
1178
|
{
|
|
1309
1179
|
Component: AdditionalSettingsTab,
|
|
1310
1180
|
path: "/settings/paypal/additional-settings"
|
|
1311
1181
|
},
|
|
1182
|
+
{
|
|
1183
|
+
Component: AdvancedCardPaymentsTab,
|
|
1184
|
+
path: "/settings/paypal/advanced-card-payments"
|
|
1185
|
+
},
|
|
1312
1186
|
{
|
|
1313
1187
|
Component: PayPalApplePayPage,
|
|
1314
1188
|
path: "/settings/paypal/apple-pay"
|