@easypayment/medusa-payment-paypal 0.8.3 → 0.8.4
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 +855 -855
- package/.medusa/server/src/admin/index.mjs +856 -856
- package/package.json +1 -1
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { defineRouteConfig } from "@medusajs/admin-sdk";
|
|
3
3
|
import { Navigate, useLocation, Link } from "react-router-dom";
|
|
4
|
-
import { useState,
|
|
4
|
+
import { useState, useRef, useEffect, useMemo, useCallback, useLayoutEffect } from "react";
|
|
5
5
|
const config$1 = defineRouteConfig({
|
|
6
6
|
label: "PayPal"
|
|
7
7
|
});
|
|
8
8
|
const PayPalSettingsIndexRoute = () => {
|
|
9
9
|
return /* @__PURE__ */ jsx(Navigate, { to: "connection", replace: true });
|
|
10
10
|
};
|
|
11
|
-
function PayPalApplePayPage() {
|
|
12
|
-
return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
13
|
-
}
|
|
14
11
|
const BASE = "/settings/paypal";
|
|
15
12
|
const TABS = [
|
|
16
13
|
{ label: "PayPal Connection", to: `${BASE}/connection` },
|
|
@@ -36,888 +33,888 @@ function PayPalTabs() {
|
|
|
36
33
|
);
|
|
37
34
|
}) }) });
|
|
38
35
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
`link[rel="preload"][href="${preloadHref}"]`
|
|
47
|
-
);
|
|
48
|
-
if (!existingPreload) {
|
|
49
|
-
const preloadLink = document.createElement("link");
|
|
50
|
-
preloadLink.rel = "preload";
|
|
51
|
-
preloadLink.href = preloadHref;
|
|
52
|
-
preloadLink.as = "script";
|
|
53
|
-
document.head.appendChild(preloadLink);
|
|
36
|
+
async function adminFetch$2(path, opts = {}) {
|
|
37
|
+
var _a;
|
|
38
|
+
const { method = "GET", body, query } = opts;
|
|
39
|
+
let url = path;
|
|
40
|
+
if (query && Object.keys(query).length > 0) {
|
|
41
|
+
const params = new URLSearchParams(query);
|
|
42
|
+
url = `${path}?${params.toString()}`;
|
|
54
43
|
}
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
ppScript.id = "paypal-partner-js";
|
|
61
|
-
ppScript.src = preloadHref;
|
|
62
|
-
ppScript.async = true;
|
|
63
|
-
document.head.appendChild(ppScript);
|
|
44
|
+
const headers = { Accept: "application/json" };
|
|
45
|
+
if (body !== void 0) headers["Content-Type"] = "application/json";
|
|
46
|
+
if (typeof window !== "undefined") {
|
|
47
|
+
const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
|
|
48
|
+
if (token) headers["Authorization"] = `Bearer ${token}`;
|
|
64
49
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
50
|
+
const res = await fetch(url, {
|
|
51
|
+
method,
|
|
52
|
+
headers,
|
|
53
|
+
credentials: "include",
|
|
54
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
55
|
+
});
|
|
56
|
+
const text = await res.text().catch(() => "");
|
|
57
|
+
if (!res.ok) {
|
|
58
|
+
if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
|
|
59
|
+
if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
|
|
60
|
+
throw new Error(text || `Request failed with status ${res.status}`);
|
|
61
|
+
}
|
|
62
|
+
if (!text) return {};
|
|
76
63
|
try {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if ((/* @__PURE__ */ new Date()).getTime() - data.ts < CACHE_EXPIRY) {
|
|
81
|
-
cachedUrl = data.url;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
} catch (e) {
|
|
85
|
-
console.error("Cache read error:", e);
|
|
64
|
+
return JSON.parse(text);
|
|
65
|
+
} catch {
|
|
66
|
+
return {};
|
|
86
67
|
}
|
|
87
68
|
}
|
|
88
|
-
|
|
89
|
-
|
|
69
|
+
const DEFAULT_FORM$1 = {
|
|
70
|
+
paymentAction: "capture",
|
|
71
|
+
brandName: "PayPal",
|
|
72
|
+
landingPage: "no_preference",
|
|
73
|
+
requireInstantPayment: false,
|
|
74
|
+
sendItemDetails: true,
|
|
75
|
+
invoicePrefix: "WC-",
|
|
76
|
+
creditCardStatementName: "PayPal"
|
|
77
|
+
};
|
|
78
|
+
function mergeWithDefaults$1(saved) {
|
|
79
|
+
if (!saved) return { ...DEFAULT_FORM$1 };
|
|
80
|
+
const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
|
|
81
|
+
return { ...DEFAULT_FORM$1, ...Object.fromEntries(entries) };
|
|
82
|
+
}
|
|
83
|
+
function SectionCard$2({ title, description, right, children }) {
|
|
84
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
|
|
85
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
|
|
86
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
87
|
+
/* @__PURE__ */ jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: title }),
|
|
88
|
+
description ? /* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-ui-fg-subtle", children: description }) : null
|
|
89
|
+
] }),
|
|
90
|
+
right
|
|
91
|
+
] }),
|
|
92
|
+
/* @__PURE__ */ jsx("div", { className: "p-4", children })
|
|
93
|
+
] });
|
|
94
|
+
}
|
|
95
|
+
function FieldRow$2({ label, hint, children }) {
|
|
96
|
+
return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
|
|
97
|
+
/* @__PURE__ */ jsxs("div", { className: "col-span-12 md:col-span-4", children: [
|
|
98
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
|
|
99
|
+
hint ? /* @__PURE__ */ jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: hint }) : null
|
|
100
|
+
] }),
|
|
101
|
+
/* @__PURE__ */ jsx("div", { className: "col-span-12 md:col-span-8", children })
|
|
102
|
+
] });
|
|
103
|
+
}
|
|
104
|
+
function AdditionalSettingsTab() {
|
|
105
|
+
const [form, setForm] = useState(() => ({ ...DEFAULT_FORM$1 }));
|
|
106
|
+
const [loading, setLoading] = useState(false);
|
|
107
|
+
const [saving, setSaving] = useState(false);
|
|
108
|
+
const [toast, setToast] = useState(null);
|
|
109
|
+
const didInit = useRef(false);
|
|
90
110
|
useEffect(() => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const [statusInfo, setStatusInfo] = useState(null);
|
|
104
|
-
const [onboardingInProgress, setOnboardingInProgress] = useState(false);
|
|
105
|
-
const initLoaderRef = useRef(null);
|
|
106
|
-
const paypalButtonRef = useRef(null);
|
|
107
|
-
const errorLogRef = useRef(null);
|
|
108
|
-
const runIdRef = useRef(0);
|
|
109
|
-
const currentRunId = useRef(0);
|
|
110
|
-
const ppBtnMeasureRef = useRef(null);
|
|
111
|
-
const [ppBtnWidth, setPpBtnWidth] = useState(null);
|
|
112
|
-
const canSaveManual = useMemo(() => {
|
|
113
|
-
return clientId.trim().length > 0 && secret.trim().length > 0;
|
|
114
|
-
}, [clientId, secret]);
|
|
115
|
-
const fetchFreshLink = useCallback(
|
|
116
|
-
(runId) => {
|
|
117
|
-
if (initLoaderRef.current) {
|
|
118
|
-
const loaderText = initLoaderRef.current.querySelector("#loader-text");
|
|
119
|
-
if (loaderText)
|
|
120
|
-
loaderText.textContent = "Generating onboarding session...";
|
|
111
|
+
if (didInit.current) return;
|
|
112
|
+
didInit.current = true;
|
|
113
|
+
(async () => {
|
|
114
|
+
try {
|
|
115
|
+
setLoading(true);
|
|
116
|
+
const json = await adminFetch$2("/admin/paypal/settings");
|
|
117
|
+
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
118
|
+
const saved = payload == null ? void 0 : payload.additional_settings;
|
|
119
|
+
if (saved && typeof saved === "object") setForm(mergeWithDefaults$1(saved));
|
|
120
|
+
} catch {
|
|
121
|
+
} finally {
|
|
122
|
+
setLoading(false);
|
|
121
123
|
}
|
|
122
|
-
|
|
123
|
-
method: "POST",
|
|
124
|
-
headers: { "content-type": "application/json" },
|
|
125
|
-
body: JSON.stringify({
|
|
126
|
-
products: ["PPCP"]
|
|
127
|
-
})
|
|
128
|
-
}).then((r) => r.json()).then((data) => {
|
|
129
|
-
if (runId !== currentRunId.current) return;
|
|
130
|
-
const href = data == null ? void 0 : data.onboarding_url;
|
|
131
|
-
if (!href) {
|
|
132
|
-
showError("Onboarding URL not returned.");
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
const finalUrl2 = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
|
|
136
|
-
localStorage.setItem(
|
|
137
|
-
CACHE_KEY,
|
|
138
|
-
JSON.stringify({
|
|
139
|
-
url: finalUrl2,
|
|
140
|
-
ts: Date.now()
|
|
141
|
-
})
|
|
142
|
-
);
|
|
143
|
-
if (!localStorage.getItem(RELOAD_KEY)) {
|
|
144
|
-
localStorage.setItem(RELOAD_KEY, "1");
|
|
145
|
-
window.location.reload();
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
activatePayPal(finalUrl2, runId);
|
|
149
|
-
}).catch(() => {
|
|
150
|
-
if (runId !== currentRunId.current) return;
|
|
151
|
-
showError("Unable to connect to service.");
|
|
152
|
-
});
|
|
153
|
-
},
|
|
154
|
-
[env]
|
|
155
|
-
);
|
|
156
|
-
const showUI = useCallback(() => {
|
|
157
|
-
var _a, _b, _c, _d;
|
|
158
|
-
const btn = document.querySelector('[data-paypal-button="true"]');
|
|
159
|
-
if (btn && ((_d = (_c = (_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) == null ? void 0 : _c.miniBrowser) == null ? void 0 : _d.init)) {
|
|
160
|
-
window.PAYPAL.apps.Signup.miniBrowser.init();
|
|
161
|
-
}
|
|
162
|
-
setConnState("ready");
|
|
163
|
-
}, []);
|
|
164
|
-
const showError = useCallback((msg) => {
|
|
165
|
-
setConnState("error");
|
|
166
|
-
setError(msg);
|
|
124
|
+
})();
|
|
167
125
|
}, []);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
126
|
+
async function onSave() {
|
|
127
|
+
try {
|
|
128
|
+
setSaving(true);
|
|
129
|
+
setToast(null);
|
|
130
|
+
const json = await adminFetch$2("/admin/paypal/settings", { method: "POST", body: { additional_settings: form } });
|
|
131
|
+
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
132
|
+
const saved = payload == null ? void 0 : payload.additional_settings;
|
|
133
|
+
if (saved && typeof saved === "object") setForm(mergeWithDefaults$1(saved));
|
|
134
|
+
setToast({ type: "success", message: "Settings saved" });
|
|
135
|
+
window.setTimeout(() => setToast(null), 2500);
|
|
136
|
+
} catch (e) {
|
|
137
|
+
setToast({ type: "error", message: e instanceof Error ? e.message : "Failed to save settings" });
|
|
138
|
+
window.setTimeout(() => setToast(null), 3500);
|
|
139
|
+
} finally {
|
|
140
|
+
setSaving(false);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return /* @__PURE__ */ jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
144
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-start justify-between gap-4", children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Gateway By Easy Payment" }) }) }),
|
|
145
|
+
/* @__PURE__ */ jsx(PayPalTabs, {}),
|
|
146
|
+
toast ? /* @__PURE__ */ jsx("div", { className: "fixed right-6 top-6 z-50 rounded-md border border-ui-border-base bg-ui-bg-base px-4 py-3 text-sm shadow-lg", role: "status", "aria-live": "polite", children: /* @__PURE__ */ jsx("span", { className: toast.type === "success" ? "text-ui-fg-base" : "text-ui-fg-error", children: toast.message }) }) : null,
|
|
147
|
+
/* @__PURE__ */ jsx(
|
|
148
|
+
SectionCard$2,
|
|
149
|
+
{
|
|
150
|
+
title: "Additional Settings",
|
|
151
|
+
description: "These settings control checkout behavior and PayPal experience.",
|
|
152
|
+
right: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
153
|
+
/* @__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" }),
|
|
154
|
+
loading ? /* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading..." }) : null
|
|
155
|
+
] }),
|
|
156
|
+
children: /* @__PURE__ */ jsxs("div", { className: "divide-y divide-ui-border-base", children: [
|
|
157
|
+
/* @__PURE__ */ jsx(FieldRow$2, { label: "Payment action", children: /* @__PURE__ */ jsxs("select", { value: form.paymentAction, onChange: (e) => setForm((p) => ({ ...p, paymentAction: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", children: [
|
|
158
|
+
/* @__PURE__ */ jsx("option", { value: "capture", children: "Capture" }),
|
|
159
|
+
/* @__PURE__ */ jsx("option", { value: "authorize", children: "Authorize" })
|
|
160
|
+
] }) }),
|
|
161
|
+
/* @__PURE__ */ jsx(FieldRow$2, { label: "Brand Name", children: /* @__PURE__ */ jsx("input", { value: form.brandName, onChange: (e) => setForm((p) => ({ ...p, brandName: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", placeholder: "PayPal" }) }),
|
|
162
|
+
/* @__PURE__ */ jsx(FieldRow$2, { label: "Landing Page", children: /* @__PURE__ */ jsxs("select", { value: form.landingPage, onChange: (e) => setForm((p) => ({ ...p, landingPage: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", children: [
|
|
163
|
+
/* @__PURE__ */ jsx("option", { value: "no_preference", children: "No Preference" }),
|
|
164
|
+
/* @__PURE__ */ jsx("option", { value: "login", children: "Login" }),
|
|
165
|
+
/* @__PURE__ */ jsx("option", { value: "billing", children: "Billing" })
|
|
166
|
+
] }) }),
|
|
167
|
+
/* @__PURE__ */ jsx(FieldRow$2, { label: "Instant Payments", children: /* @__PURE__ */ jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
168
|
+
/* @__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" }),
|
|
169
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-base", children: "Require Instant Payment" })
|
|
170
|
+
] }) }),
|
|
171
|
+
/* @__PURE__ */ jsx(FieldRow$2, { label: "Send Item Details", hint: "Include all line item details in the payment request to PayPal so that they can be seen from the PayPal transaction details page.", children: /* @__PURE__ */ jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
172
|
+
/* @__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" }),
|
|
173
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-base", children: "Send line item details to PayPal" })
|
|
174
|
+
] }) }),
|
|
175
|
+
/* @__PURE__ */ jsx(FieldRow$2, { label: "Invoice prefix", children: /* @__PURE__ */ jsx("input", { value: form.invoicePrefix, onChange: (e) => setForm((p) => ({ ...p, invoicePrefix: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", placeholder: "WC-" }) }),
|
|
176
|
+
/* @__PURE__ */ jsx(FieldRow$2, { label: "Credit Card Statement Name", children: /* @__PURE__ */ jsx("input", { value: form.creditCardStatementName, onChange: (e) => setForm((p) => ({ ...p, creditCardStatementName: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", placeholder: "PayPal" }) })
|
|
177
|
+
] })
|
|
172
178
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
)
|
|
179
|
+
)
|
|
180
|
+
] }) });
|
|
181
|
+
}
|
|
182
|
+
async function adminFetch$1(path, opts = {}) {
|
|
183
|
+
var _a;
|
|
184
|
+
const { method = "GET", body, query } = opts;
|
|
185
|
+
let url = path;
|
|
186
|
+
if (query && Object.keys(query).length > 0) {
|
|
187
|
+
const params = new URLSearchParams(query);
|
|
188
|
+
url = `${path}?${params.toString()}`;
|
|
189
|
+
}
|
|
190
|
+
const headers = { Accept: "application/json" };
|
|
191
|
+
if (body !== void 0) headers["Content-Type"] = "application/json";
|
|
192
|
+
if (typeof window !== "undefined") {
|
|
193
|
+
const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
|
|
194
|
+
if (token) headers["Authorization"] = `Bearer ${token}`;
|
|
195
|
+
}
|
|
196
|
+
const res = await fetch(url, {
|
|
197
|
+
method,
|
|
198
|
+
headers,
|
|
199
|
+
credentials: "include",
|
|
200
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
201
|
+
});
|
|
202
|
+
const text = await res.text().catch(() => "");
|
|
203
|
+
if (!res.ok) {
|
|
204
|
+
if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
|
|
205
|
+
if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
|
|
206
|
+
throw new Error(text || `Request failed with status ${res.status}`);
|
|
207
|
+
}
|
|
208
|
+
if (!text) return {};
|
|
209
|
+
try {
|
|
210
|
+
return JSON.parse(text);
|
|
211
|
+
} catch {
|
|
212
|
+
return {};
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const DEFAULT_FORM = {
|
|
216
|
+
enabled: true,
|
|
217
|
+
title: "Credit or Debit Card",
|
|
218
|
+
threeDS: "when_required"
|
|
219
|
+
};
|
|
220
|
+
function mergeWithDefaults(saved) {
|
|
221
|
+
if (!saved) return { ...DEFAULT_FORM };
|
|
222
|
+
const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
|
|
223
|
+
return { ...DEFAULT_FORM, ...Object.fromEntries(entries) };
|
|
224
|
+
}
|
|
225
|
+
const THREE_DS_OPTIONS = [
|
|
226
|
+
{ value: "when_required", label: "3D Secure when required", hint: "Triggers 3DS only when the card / issuer requires it." },
|
|
227
|
+
{ value: "sli", label: "3D Secure (SCA) / liability shift (recommended)", hint: "Attempts to optimize for liability shift while remaining compliant." },
|
|
228
|
+
{ value: "always", label: "Always request 3D Secure", hint: "Forces 3DS challenge whenever possible (may reduce conversion)." }
|
|
229
|
+
];
|
|
230
|
+
function SectionCard$1({ title, description, right, children }) {
|
|
231
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
|
|
232
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
|
|
233
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
234
|
+
/* @__PURE__ */ jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: title }),
|
|
235
|
+
description ? /* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-ui-fg-subtle", children: description }) : null
|
|
236
|
+
] }),
|
|
237
|
+
right
|
|
238
|
+
] }),
|
|
239
|
+
/* @__PURE__ */ jsx("div", { className: "p-4", children })
|
|
240
|
+
] });
|
|
241
|
+
}
|
|
242
|
+
function FieldRow$1({ label, hint, children }) {
|
|
243
|
+
return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
|
|
244
|
+
/* @__PURE__ */ jsxs("div", { className: "col-span-12 md:col-span-4", children: [
|
|
245
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
|
|
246
|
+
hint ? /* @__PURE__ */ jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: hint }) : null
|
|
247
|
+
] }),
|
|
248
|
+
/* @__PURE__ */ jsx("div", { className: "col-span-12 md:col-span-8", children })
|
|
249
|
+
] });
|
|
250
|
+
}
|
|
251
|
+
function AdvancedCardPaymentsTab() {
|
|
252
|
+
var _a, _b;
|
|
253
|
+
const [form, setForm] = useState(() => ({ ...DEFAULT_FORM }));
|
|
254
|
+
const [loading, setLoading] = useState(false);
|
|
255
|
+
const [saving, setSaving] = useState(false);
|
|
256
|
+
const [toast, setToast] = useState(null);
|
|
257
|
+
const didInit = useRef(false);
|
|
187
258
|
useEffect(() => {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const run = async () => {
|
|
192
|
-
setConnState("loading");
|
|
193
|
-
setError(null);
|
|
194
|
-
setFinalUrl("");
|
|
195
|
-
try {
|
|
196
|
-
const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
197
|
-
method: "GET"
|
|
198
|
-
});
|
|
199
|
-
const st = await r.json().catch(() => ({}));
|
|
200
|
-
if (cancelled || runId !== currentRunId.current) return;
|
|
201
|
-
setStatusInfo(st);
|
|
202
|
-
const isConnected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
|
|
203
|
-
if (isConnected) {
|
|
204
|
-
setConnState("connected");
|
|
205
|
-
setShowManual(false);
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
} catch (e) {
|
|
209
|
-
console.error(e);
|
|
210
|
-
}
|
|
211
|
-
if (cachedUrl) {
|
|
212
|
-
activatePayPal(cachedUrl, runId);
|
|
213
|
-
} else {
|
|
214
|
-
fetchFreshLink(runId);
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
run();
|
|
218
|
-
return () => {
|
|
219
|
-
cancelled = true;
|
|
220
|
-
currentRunId.current = 0;
|
|
221
|
-
};
|
|
222
|
-
}, [env, fetchFreshLink, activatePayPal]);
|
|
223
|
-
useLayoutEffect(() => {
|
|
224
|
-
window.onboardingCallback = async function(authCode, sharedId) {
|
|
225
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
259
|
+
if (didInit.current) return;
|
|
260
|
+
didInit.current = true;
|
|
261
|
+
(async () => {
|
|
226
262
|
try {
|
|
227
|
-
;
|
|
228
|
-
|
|
263
|
+
setLoading(true);
|
|
264
|
+
const json = await adminFetch$1("/admin/paypal/settings");
|
|
265
|
+
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
266
|
+
const saved = payload == null ? void 0 : payload.advanced_card_payments;
|
|
267
|
+
if (saved && typeof saved === "object") setForm(mergeWithDefaults(saved));
|
|
229
268
|
} catch {
|
|
269
|
+
} finally {
|
|
270
|
+
setLoading(false);
|
|
230
271
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
const payload = {
|
|
235
|
-
authCode,
|
|
236
|
-
sharedId,
|
|
237
|
-
env: env === "sandbox" ? "sandbox" : "live"
|
|
238
|
-
};
|
|
239
|
-
try {
|
|
240
|
-
const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
|
|
241
|
-
method: "POST",
|
|
242
|
-
headers: { "content-type": "application/json" },
|
|
243
|
-
body: JSON.stringify(payload)
|
|
244
|
-
});
|
|
245
|
-
if (!res.ok) {
|
|
246
|
-
const txt = await res.text().catch(() => "");
|
|
247
|
-
throw new Error(txt || `Onboarding exchange failed (${res.status})`);
|
|
248
|
-
}
|
|
249
|
-
try {
|
|
250
|
-
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;
|
|
251
|
-
if (typeof close1 === "function") close1();
|
|
252
|
-
} catch {
|
|
253
|
-
}
|
|
254
|
-
try {
|
|
255
|
-
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;
|
|
256
|
-
if (typeof close2 === "function") close2();
|
|
257
|
-
} catch {
|
|
258
|
-
}
|
|
259
|
-
try {
|
|
260
|
-
localStorage.removeItem(CACHE_KEY);
|
|
261
|
-
localStorage.removeItem(RELOAD_KEY);
|
|
262
|
-
} catch {
|
|
263
|
-
}
|
|
264
|
-
window.location.href = window.location.href;
|
|
265
|
-
} catch (e) {
|
|
266
|
-
console.error(e);
|
|
267
|
-
setConnState("error");
|
|
268
|
-
setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
|
|
269
|
-
setOnboardingInProgress(false);
|
|
270
|
-
}
|
|
271
|
-
};
|
|
272
|
-
return () => {
|
|
273
|
-
window.onboardingCallback = void 0;
|
|
274
|
-
};
|
|
275
|
-
}, [env]);
|
|
276
|
-
useLayoutEffect(() => {
|
|
277
|
-
const el = ppBtnMeasureRef.current;
|
|
278
|
-
if (!el) return;
|
|
279
|
-
const update = () => {
|
|
280
|
-
const w = Math.round(el.getBoundingClientRect().width || 0);
|
|
281
|
-
if (w > 0) setPpBtnWidth(w);
|
|
282
|
-
};
|
|
283
|
-
update();
|
|
284
|
-
let ro = null;
|
|
285
|
-
if (typeof ResizeObserver !== "undefined") {
|
|
286
|
-
ro = new ResizeObserver(() => update());
|
|
287
|
-
ro.observe(el);
|
|
288
|
-
} else {
|
|
289
|
-
window.addEventListener("resize", update);
|
|
290
|
-
}
|
|
291
|
-
return () => {
|
|
292
|
-
if (ro) ro.disconnect();
|
|
293
|
-
else window.removeEventListener("resize", update);
|
|
294
|
-
};
|
|
295
|
-
}, [connState, env, finalUrl]);
|
|
296
|
-
const handleConnectClick = (e) => {
|
|
297
|
-
if (connState !== "ready" || !finalUrl || onboardingInProgress) {
|
|
298
|
-
e.preventDefault();
|
|
299
|
-
}
|
|
300
|
-
};
|
|
301
|
-
const handleSaveManual = async () => {
|
|
302
|
-
if (!canSaveManual || onboardingInProgress) return;
|
|
303
|
-
setOnboardingInProgress(true);
|
|
304
|
-
setConnState("loading");
|
|
305
|
-
setError(null);
|
|
272
|
+
})();
|
|
273
|
+
}, []);
|
|
274
|
+
async function onSave() {
|
|
306
275
|
try {
|
|
307
|
-
|
|
276
|
+
setSaving(true);
|
|
277
|
+
const json = await adminFetch$1("/admin/paypal/settings", {
|
|
308
278
|
method: "POST",
|
|
309
|
-
|
|
310
|
-
body: JSON.stringify({
|
|
311
|
-
clientId: clientId.trim(),
|
|
312
|
-
clientSecret: secret.trim(),
|
|
313
|
-
environment: env
|
|
314
|
-
})
|
|
315
|
-
});
|
|
316
|
-
if (!res.ok) {
|
|
317
|
-
const txt = await res.text().catch(() => "");
|
|
318
|
-
throw new Error(txt || `Save credentials failed (${res.status})`);
|
|
319
|
-
}
|
|
320
|
-
const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
321
|
-
method: "GET"
|
|
279
|
+
body: { advanced_card_payments: form }
|
|
322
280
|
});
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
localStorage.removeItem(CACHE_KEY);
|
|
329
|
-
localStorage.removeItem(RELOAD_KEY);
|
|
330
|
-
} catch {
|
|
331
|
-
}
|
|
281
|
+
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
282
|
+
const saved = payload == null ? void 0 : payload.advanced_card_payments;
|
|
283
|
+
if (saved && typeof saved === "object") setForm(mergeWithDefaults(saved));
|
|
284
|
+
setToast({ type: "success", message: "Settings saved" });
|
|
285
|
+
window.setTimeout(() => setToast(null), 2500);
|
|
332
286
|
} catch (e) {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
setError((e == null ? void 0 : e.message) || "Failed to save credentials.");
|
|
287
|
+
setToast({ type: "error", message: (e instanceof Error ? e.message : "") || "Failed to save settings." });
|
|
288
|
+
window.setTimeout(() => setToast(null), 3500);
|
|
336
289
|
} finally {
|
|
337
|
-
|
|
290
|
+
setSaving(false);
|
|
338
291
|
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
292
|
+
}
|
|
293
|
+
return /* @__PURE__ */ jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
294
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-start justify-between gap-4", children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Gateway By Easy Payment" }) }) }),
|
|
295
|
+
/* @__PURE__ */ jsx(PayPalTabs, {}),
|
|
296
|
+
toast ? /* @__PURE__ */ jsx("div", { className: "fixed right-6 top-6 z-50 rounded-md border border-ui-border-base bg-ui-bg-base px-4 py-3 text-sm shadow-lg", role: "status", "aria-live": "polite", children: /* @__PURE__ */ jsx("span", { className: toast.type === "success" ? "text-ui-fg-base" : "text-ui-fg-error", children: toast.message }) }) : null,
|
|
297
|
+
/* @__PURE__ */ jsx(
|
|
298
|
+
SectionCard$1,
|
|
299
|
+
{
|
|
300
|
+
title: "Advanced Card Payments",
|
|
301
|
+
description: "Control card checkout settings and 3D Secure behavior.",
|
|
302
|
+
right: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
303
|
+
/* @__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" }),
|
|
304
|
+
loading ? /* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading..." }) : null
|
|
305
|
+
] }),
|
|
306
|
+
children: /* @__PURE__ */ jsxs("div", { className: "divide-y divide-ui-border-base", children: [
|
|
307
|
+
/* @__PURE__ */ jsx(FieldRow$1, { label: "Enable/Disable", children: /* @__PURE__ */ jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
308
|
+
/* @__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" }),
|
|
309
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable Advanced Credit/Debit Card" })
|
|
310
|
+
] }) }),
|
|
311
|
+
/* @__PURE__ */ jsx(FieldRow$1, { label: "Title", children: /* @__PURE__ */ jsx("input", { value: form.title, onChange: (e) => setForm((p) => ({ ...p, title: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", placeholder: "Credit or Debit Card" }) }),
|
|
312
|
+
/* @__PURE__ */ jsx(FieldRow$1, { label: "Contingency for 3D Secure", hint: "Choose when 3D Secure should be triggered during card payments.", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
313
|
+
/* @__PURE__ */ jsx("select", { value: form.threeDS, onChange: (e) => setForm((p) => ({ ...p, threeDS: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", children: THREE_DS_OPTIONS.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value)) }),
|
|
314
|
+
((_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
|
|
315
|
+
] }) })
|
|
316
|
+
] })
|
|
357
317
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
318
|
+
)
|
|
319
|
+
] }) });
|
|
320
|
+
}
|
|
321
|
+
const config = defineRouteConfig({
|
|
322
|
+
label: "PayPal Connection",
|
|
323
|
+
hide: true
|
|
324
|
+
});
|
|
325
|
+
if (typeof window !== "undefined") {
|
|
326
|
+
const preloadHref = "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js";
|
|
327
|
+
const existingPreload = document.head.querySelector(
|
|
328
|
+
`link[rel="preload"][href="${preloadHref}"]`
|
|
329
|
+
);
|
|
330
|
+
if (!existingPreload) {
|
|
331
|
+
const preloadLink = document.createElement("link");
|
|
332
|
+
preloadLink.rel = "preload";
|
|
333
|
+
preloadLink.href = preloadHref;
|
|
334
|
+
preloadLink.as = "script";
|
|
335
|
+
document.head.appendChild(preloadLink);
|
|
336
|
+
}
|
|
337
|
+
const existingScript = document.getElementById(
|
|
338
|
+
"paypal-partner-js"
|
|
339
|
+
);
|
|
340
|
+
if (!existingScript) {
|
|
341
|
+
const ppScript = document.createElement("script");
|
|
342
|
+
ppScript.id = "paypal-partner-js";
|
|
343
|
+
ppScript.src = preloadHref;
|
|
344
|
+
ppScript.async = true;
|
|
345
|
+
document.head.appendChild(ppScript);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
const SERVICE_URL = "/admin/paypal/onboarding-link";
|
|
349
|
+
const CACHE_KEY = "pp_onboard_cache";
|
|
350
|
+
const RELOAD_KEY = "pp_onboard_reloaded_once";
|
|
351
|
+
const CACHE_EXPIRY = 10 * 60 * 1e3;
|
|
352
|
+
const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
|
|
353
|
+
const STATUS_ENDPOINT = "/admin/paypal/status";
|
|
354
|
+
const SAVE_CREDENTIALS_ENDPOINT = "/admin/paypal/save-credentials";
|
|
355
|
+
const DISCONNECT_ENDPOINT = "/admin/paypal/disconnect";
|
|
356
|
+
let cachedUrl = null;
|
|
357
|
+
if (typeof window !== "undefined") {
|
|
358
|
+
try {
|
|
359
|
+
const cached = localStorage.getItem(CACHE_KEY);
|
|
360
|
+
if (cached) {
|
|
361
|
+
const data = JSON.parse(cached);
|
|
362
|
+
if ((/* @__PURE__ */ new Date()).getTime() - data.ts < CACHE_EXPIRY) {
|
|
363
|
+
cachedUrl = data.url;
|
|
362
364
|
}
|
|
363
|
-
currentRunId.current = ++runIdRef.current;
|
|
364
|
-
const runId = currentRunId.current;
|
|
365
|
-
fetchFreshLink(runId);
|
|
366
|
-
} catch (e) {
|
|
367
|
-
console.error(e);
|
|
368
|
-
setConnState("error");
|
|
369
|
-
setError((e == null ? void 0 : e.message) || "Failed to disconnect.");
|
|
370
|
-
} finally {
|
|
371
|
-
setOnboardingInProgress(false);
|
|
372
365
|
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
366
|
+
} catch (e) {
|
|
367
|
+
console.error("Cache read error:", e);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function PayPalConnectionPage() {
|
|
371
|
+
const [env, setEnv] = useState("live");
|
|
372
|
+
useEffect(() => {
|
|
373
|
+
fetch("/admin/paypal/environment", { method: "GET" }).then((r) => r.json()).then((d) => {
|
|
374
|
+
const v = (d == null ? void 0 : d.environment) === "sandbox" ? "sandbox" : "live";
|
|
375
|
+
setEnv(v);
|
|
376
|
+
}).catch(() => {
|
|
377
|
+
});
|
|
378
|
+
}, []);
|
|
379
|
+
const [connState, setConnState] = useState("loading");
|
|
380
|
+
const [error, setError] = useState(null);
|
|
381
|
+
const [finalUrl, setFinalUrl] = useState("");
|
|
382
|
+
const [showManual, setShowManual] = useState(false);
|
|
383
|
+
const [clientId, setClientId] = useState("");
|
|
384
|
+
const [secret, setSecret] = useState("");
|
|
385
|
+
const [statusInfo, setStatusInfo] = useState(null);
|
|
386
|
+
const [onboardingInProgress, setOnboardingInProgress] = useState(false);
|
|
387
|
+
const initLoaderRef = useRef(null);
|
|
388
|
+
const paypalButtonRef = useRef(null);
|
|
389
|
+
const errorLogRef = useRef(null);
|
|
390
|
+
const runIdRef = useRef(0);
|
|
391
|
+
const currentRunId = useRef(0);
|
|
392
|
+
const ppBtnMeasureRef = useRef(null);
|
|
393
|
+
const [ppBtnWidth, setPpBtnWidth] = useState(null);
|
|
394
|
+
const canSaveManual = useMemo(() => {
|
|
395
|
+
return clientId.trim().length > 0 && secret.trim().length > 0;
|
|
396
|
+
}, [clientId, secret]);
|
|
397
|
+
const fetchFreshLink = useCallback(
|
|
398
|
+
(runId) => {
|
|
399
|
+
if (initLoaderRef.current) {
|
|
400
|
+
const loaderText = initLoaderRef.current.querySelector("#loader-text");
|
|
401
|
+
if (loaderText)
|
|
402
|
+
loaderText.textContent = "Generating onboarding session...";
|
|
403
|
+
}
|
|
404
|
+
fetch(SERVICE_URL, {
|
|
380
405
|
method: "POST",
|
|
381
406
|
headers: { "content-type": "application/json" },
|
|
382
|
-
body: JSON.stringify({
|
|
407
|
+
body: JSON.stringify({
|
|
408
|
+
products: ["PPCP"]
|
|
409
|
+
})
|
|
410
|
+
}).then((r) => r.json()).then((data) => {
|
|
411
|
+
if (runId !== currentRunId.current) return;
|
|
412
|
+
const href = data == null ? void 0 : data.onboarding_url;
|
|
413
|
+
if (!href) {
|
|
414
|
+
showError("Onboarding URL not returned.");
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const finalUrl2 = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
|
|
418
|
+
localStorage.setItem(
|
|
419
|
+
CACHE_KEY,
|
|
420
|
+
JSON.stringify({
|
|
421
|
+
url: finalUrl2,
|
|
422
|
+
ts: Date.now()
|
|
423
|
+
})
|
|
424
|
+
);
|
|
425
|
+
if (!localStorage.getItem(RELOAD_KEY)) {
|
|
426
|
+
localStorage.setItem(RELOAD_KEY, "1");
|
|
427
|
+
window.location.reload();
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
activatePayPal(finalUrl2, runId);
|
|
431
|
+
}).catch(() => {
|
|
432
|
+
if (runId !== currentRunId.current) return;
|
|
433
|
+
showError("Unable to connect to service.");
|
|
383
434
|
});
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
435
|
+
},
|
|
436
|
+
[env]
|
|
437
|
+
);
|
|
438
|
+
const showUI = useCallback(() => {
|
|
439
|
+
var _a, _b, _c, _d;
|
|
440
|
+
const btn = document.querySelector('[data-paypal-button="true"]');
|
|
441
|
+
if (btn && ((_d = (_c = (_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) == null ? void 0 : _c.miniBrowser) == null ? void 0 : _d.init)) {
|
|
442
|
+
window.PAYPAL.apps.Signup.miniBrowser.init();
|
|
390
443
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
}
|
|
410
|
-
) }),
|
|
411
|
-
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium pt-2", children: env === "sandbox" ? "Connect to PayPal (Sandbox)" : "Connect to PayPal" }),
|
|
412
|
-
/* @__PURE__ */ jsx("div", { className: "max-w-xl", children: connState === "connected" ? /* @__PURE__ */ jsxs("div", { children: [
|
|
413
|
-
/* @__PURE__ */ jsxs("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: [
|
|
414
|
-
"✅ Successfully connected to PayPal!",
|
|
415
|
-
/* @__PURE__ */ jsx(
|
|
416
|
-
"a",
|
|
417
|
-
{
|
|
418
|
-
"data-paypal-button": "true",
|
|
419
|
-
"data-paypal-onboard-complete": "onboardingCallback",
|
|
420
|
-
href: "#",
|
|
421
|
-
style: { display: "none" },
|
|
422
|
-
children: "PayPal"
|
|
423
|
-
}
|
|
424
|
-
)
|
|
425
|
-
] }),
|
|
426
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-3 rounded-md border border-ui-border-base bg-ui-bg-subtle p-3 text-xs text-ui-fg-subtle", children: [
|
|
427
|
-
/* @__PURE__ */ jsx("div", { className: "font-medium text-ui-fg-base", children: "Connected PayPal account" }),
|
|
428
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-1", children: [
|
|
429
|
-
"Email:",
|
|
430
|
-
" ",
|
|
431
|
-
/* @__PURE__ */ jsx("span", { className: "font-mono text-ui-fg-base", children: (statusInfo == null ? void 0 : statusInfo.seller_email) || "Unavailable" })
|
|
432
|
-
] })
|
|
433
|
-
] }),
|
|
434
|
-
/* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center gap-2", children: /* @__PURE__ */ jsx(
|
|
435
|
-
"button",
|
|
436
|
-
{
|
|
437
|
-
type: "button",
|
|
438
|
-
onClick: handleDisconnect,
|
|
439
|
-
disabled: onboardingInProgress,
|
|
440
|
-
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",
|
|
441
|
-
children: "Disconnect"
|
|
442
|
-
}
|
|
443
|
-
) })
|
|
444
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
445
|
-
/* @__PURE__ */ jsxs(
|
|
446
|
-
"div",
|
|
447
|
-
{
|
|
448
|
-
ref: initLoaderRef,
|
|
449
|
-
id: "init-loader",
|
|
450
|
-
className: `status-msg mb-4 ${connState !== "loading" ? "hidden" : "block"}`,
|
|
451
|
-
children: [
|
|
452
|
-
/* @__PURE__ */ jsx("div", { className: "loader inline-block align-middle mr-2" }),
|
|
453
|
-
/* @__PURE__ */ jsx("span", { id: "loader-text", className: "text-sm", children: onboardingInProgress ? "Configuring connection to PayPal…" : "Checking connection..." })
|
|
454
|
-
]
|
|
455
|
-
}
|
|
456
|
-
),
|
|
457
|
-
/* @__PURE__ */ jsxs("div", { className: `${connState === "ready" ? "block" : "hidden"}`, children: [
|
|
458
|
-
/* @__PURE__ */ jsx(
|
|
459
|
-
"a",
|
|
460
|
-
{
|
|
461
|
-
ref: (node) => {
|
|
462
|
-
paypalButtonRef.current = node;
|
|
463
|
-
ppBtnMeasureRef.current = node;
|
|
464
|
-
},
|
|
465
|
-
id: "paypal-button",
|
|
466
|
-
"data-paypal-button": "true",
|
|
467
|
-
href: finalUrl || "#",
|
|
468
|
-
"data-paypal-onboard-complete": "onboardingCallback",
|
|
469
|
-
onClick: handleConnectClick,
|
|
470
|
-
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",
|
|
471
|
-
style: {
|
|
472
|
-
cursor: onboardingInProgress ? "not-allowed" : "pointer",
|
|
473
|
-
opacity: onboardingInProgress ? 0.6 : 1,
|
|
474
|
-
pointerEvents: onboardingInProgress ? "none" : "auto"
|
|
475
|
-
},
|
|
476
|
-
children: "Connect to PayPal"
|
|
477
|
-
}
|
|
478
|
-
),
|
|
479
|
-
/* @__PURE__ */ jsx(
|
|
480
|
-
"div",
|
|
481
|
-
{
|
|
482
|
-
className: "mt-2",
|
|
483
|
-
style: {
|
|
484
|
-
width: ppBtnWidth ? `${ppBtnWidth}px` : "auto",
|
|
485
|
-
marginTop: "20px",
|
|
486
|
-
marginBottom: "10px"
|
|
487
|
-
},
|
|
488
|
-
children: /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx("span", { className: "text-[11px] text-ui-fg-muted leading-none", children: "OR" }) })
|
|
489
|
-
}
|
|
490
|
-
),
|
|
491
|
-
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
492
|
-
"button",
|
|
493
|
-
{
|
|
494
|
-
type: "button",
|
|
495
|
-
onClick: () => setShowManual(!showManual),
|
|
496
|
-
disabled: onboardingInProgress,
|
|
497
|
-
className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
|
|
498
|
-
children: "Click here to insert credentials manually"
|
|
499
|
-
}
|
|
500
|
-
) })
|
|
501
|
-
] }),
|
|
502
|
-
/* @__PURE__ */ jsx("div", { className: `${connState === "ready" ? "hidden" : "block"} mt-3`, children: /* @__PURE__ */ jsx(
|
|
503
|
-
"button",
|
|
504
|
-
{
|
|
505
|
-
type: "button",
|
|
506
|
-
onClick: () => setShowManual(!showManual),
|
|
507
|
-
disabled: onboardingInProgress,
|
|
508
|
-
className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
|
|
509
|
-
children: "Click here to insert credentials manually"
|
|
510
|
-
}
|
|
511
|
-
) }),
|
|
512
|
-
/* @__PURE__ */ jsx(
|
|
513
|
-
"div",
|
|
514
|
-
{
|
|
515
|
-
ref: errorLogRef,
|
|
516
|
-
id: "error-log",
|
|
517
|
-
className: `mt-4 text-left text-xs bg-red-50 text-red-600 p-3 border border-red-200 rounded ${connState === "error" && error ? "block" : "hidden"}`,
|
|
518
|
-
children: error
|
|
519
|
-
}
|
|
520
|
-
)
|
|
521
|
-
] }) }),
|
|
522
|
-
showManual && /* @__PURE__ */ jsx("div", { className: "md:col-span-2", children: /* @__PURE__ */ jsxs("div", { className: "ml-[260px] max-w-xl mt-4 grid grid-cols-1 gap-3 md:grid-cols-2", children: [
|
|
523
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
524
|
-
/* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Client ID" }),
|
|
525
|
-
/* @__PURE__ */ jsx(
|
|
526
|
-
"input",
|
|
527
|
-
{
|
|
528
|
-
type: "text",
|
|
529
|
-
value: clientId,
|
|
530
|
-
onChange: (e) => setClientId(e.target.value),
|
|
531
|
-
disabled: onboardingInProgress,
|
|
532
|
-
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
533
|
-
placeholder: env === "sandbox" ? "Sandbox Client ID" : "Live Client ID"
|
|
534
|
-
}
|
|
535
|
-
)
|
|
536
|
-
] }),
|
|
537
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
538
|
-
/* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Secret" }),
|
|
539
|
-
/* @__PURE__ */ jsx(
|
|
540
|
-
"input",
|
|
541
|
-
{
|
|
542
|
-
type: "password",
|
|
543
|
-
value: secret,
|
|
544
|
-
onChange: (e) => setSecret(e.target.value),
|
|
545
|
-
disabled: onboardingInProgress,
|
|
546
|
-
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
547
|
-
placeholder: env === "sandbox" ? "Sandbox Secret" : "Live Secret"
|
|
548
|
-
}
|
|
549
|
-
)
|
|
550
|
-
] }),
|
|
551
|
-
/* @__PURE__ */ jsxs("div", { className: "md:col-span-2 rounded-md border border-ui-border-base bg-ui-bg-subtle p-4 text-sm text-ui-fg-subtle", children: [
|
|
552
|
-
/* @__PURE__ */ jsx("p", { className: "font-medium text-ui-fg-base", children: "Get your Client ID and Secret in 3 steps:" }),
|
|
553
|
-
/* @__PURE__ */ jsxs("ol", { className: "mt-2 list-decimal space-y-2 pl-5", children: [
|
|
554
|
-
/* @__PURE__ */ jsxs("li", { children: [
|
|
555
|
-
"Open",
|
|
556
|
-
" ",
|
|
557
|
-
/* @__PURE__ */ jsx(
|
|
558
|
-
"a",
|
|
559
|
-
{
|
|
560
|
-
href: "https://developer.paypal.com/dashboard/",
|
|
561
|
-
target: "_blank",
|
|
562
|
-
rel: "noreferrer",
|
|
563
|
-
className: "text-ui-fg-interactive underline",
|
|
564
|
-
children: "Log in to Dashboard"
|
|
565
|
-
}
|
|
566
|
-
),
|
|
567
|
-
" ",
|
|
568
|
-
"and sign in or create an account."
|
|
569
|
-
] }),
|
|
570
|
-
/* @__PURE__ */ jsxs("li", { children: [
|
|
571
|
-
"Select ",
|
|
572
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Apps & Credentials" }),
|
|
573
|
-
", then choose ",
|
|
574
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Create App" }),
|
|
575
|
-
" if you need a new project."
|
|
576
|
-
] }),
|
|
577
|
-
/* @__PURE__ */ jsxs("li", { children: [
|
|
578
|
-
"Copy your app's ",
|
|
579
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Client ID" }),
|
|
580
|
-
" and ",
|
|
581
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Secret" }),
|
|
582
|
-
", paste them above, then click ",
|
|
583
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Save credentials" }),
|
|
584
|
-
"."
|
|
585
|
-
] })
|
|
586
|
-
] })
|
|
587
|
-
] }),
|
|
588
|
-
/* @__PURE__ */ jsxs("div", { className: "md:col-span-2 flex items-center gap-2 mt-2", children: [
|
|
589
|
-
/* @__PURE__ */ jsx(
|
|
590
|
-
"button",
|
|
591
|
-
{
|
|
592
|
-
type: "button",
|
|
593
|
-
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",
|
|
594
|
-
onClick: () => setShowManual(false),
|
|
595
|
-
disabled: onboardingInProgress,
|
|
596
|
-
children: "Cancel"
|
|
597
|
-
}
|
|
598
|
-
),
|
|
599
|
-
/* @__PURE__ */ jsx(
|
|
600
|
-
"button",
|
|
601
|
-
{
|
|
602
|
-
type: "button",
|
|
603
|
-
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",
|
|
604
|
-
disabled: !canSaveManual || onboardingInProgress,
|
|
605
|
-
onClick: handleSaveManual,
|
|
606
|
-
children: "Save credentials"
|
|
607
|
-
}
|
|
608
|
-
)
|
|
609
|
-
] })
|
|
610
|
-
] }) })
|
|
611
|
-
] }) })
|
|
612
|
-
] }),
|
|
613
|
-
/* @__PURE__ */ jsx("style", { children: `
|
|
614
|
-
.loader {
|
|
615
|
-
border: 3px solid #f3f3f3;
|
|
616
|
-
border-top: 3px solid #0070ba;
|
|
617
|
-
border-radius: 50%;
|
|
618
|
-
width: 18px;
|
|
619
|
-
height: 18px;
|
|
620
|
-
animation: spin 1s linear infinite;
|
|
621
|
-
display: inline-block;
|
|
622
|
-
vertical-align: middle;
|
|
623
|
-
margin-right: 8px;
|
|
624
|
-
}
|
|
625
|
-
@keyframes spin {
|
|
626
|
-
0% { transform: rotate(0deg); }
|
|
627
|
-
100% { transform: rotate(360deg); }
|
|
444
|
+
setConnState("ready");
|
|
445
|
+
}, []);
|
|
446
|
+
const showError = useCallback((msg) => {
|
|
447
|
+
setConnState("error");
|
|
448
|
+
setError(msg);
|
|
449
|
+
}, []);
|
|
450
|
+
const activatePayPal = useCallback(
|
|
451
|
+
(url, runId) => {
|
|
452
|
+
if (paypalButtonRef.current) {
|
|
453
|
+
paypalButtonRef.current.href = url;
|
|
454
|
+
}
|
|
455
|
+
setFinalUrl(url);
|
|
456
|
+
const tryInit = () => {
|
|
457
|
+
var _a, _b;
|
|
458
|
+
if (runId !== currentRunId.current) return;
|
|
459
|
+
if ((_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) {
|
|
460
|
+
showUI();
|
|
461
|
+
return;
|
|
628
462
|
}
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
let url = path;
|
|
636
|
-
if (query && Object.keys(query).length > 0) {
|
|
637
|
-
const params = new URLSearchParams(query);
|
|
638
|
-
url = `${path}?${params.toString()}`;
|
|
639
|
-
}
|
|
640
|
-
const headers = { Accept: "application/json" };
|
|
641
|
-
if (body !== void 0) headers["Content-Type"] = "application/json";
|
|
642
|
-
if (typeof window !== "undefined") {
|
|
643
|
-
const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
|
|
644
|
-
if (token) headers["Authorization"] = `Bearer ${token}`;
|
|
645
|
-
}
|
|
646
|
-
const res = await fetch(url, {
|
|
647
|
-
method,
|
|
648
|
-
headers,
|
|
649
|
-
credentials: "include",
|
|
650
|
-
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
651
|
-
});
|
|
652
|
-
const text = await res.text().catch(() => "");
|
|
653
|
-
if (!res.ok) {
|
|
654
|
-
if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
|
|
655
|
-
if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
|
|
656
|
-
throw new Error(text || `Request failed with status ${res.status}`);
|
|
657
|
-
}
|
|
658
|
-
if (!text) return {};
|
|
659
|
-
try {
|
|
660
|
-
return JSON.parse(text);
|
|
661
|
-
} catch {
|
|
662
|
-
return {};
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
const DEFAULT_FORM$1 = {
|
|
666
|
-
enabled: true,
|
|
667
|
-
title: "Credit or Debit Card",
|
|
668
|
-
threeDS: "when_required"
|
|
669
|
-
};
|
|
670
|
-
function mergeWithDefaults$1(saved) {
|
|
671
|
-
if (!saved) return { ...DEFAULT_FORM$1 };
|
|
672
|
-
const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
|
|
673
|
-
return { ...DEFAULT_FORM$1, ...Object.fromEntries(entries) };
|
|
674
|
-
}
|
|
675
|
-
const THREE_DS_OPTIONS = [
|
|
676
|
-
{ value: "when_required", label: "3D Secure when required", hint: "Triggers 3DS only when the card / issuer requires it." },
|
|
677
|
-
{ value: "sli", label: "3D Secure (SCA) / liability shift (recommended)", hint: "Attempts to optimize for liability shift while remaining compliant." },
|
|
678
|
-
{ value: "always", label: "Always request 3D Secure", hint: "Forces 3DS challenge whenever possible (may reduce conversion)." }
|
|
679
|
-
];
|
|
680
|
-
function SectionCard$2({ title, description, right, children }) {
|
|
681
|
-
return /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
|
|
682
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
|
|
683
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
684
|
-
/* @__PURE__ */ jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: title }),
|
|
685
|
-
description ? /* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-ui-fg-subtle", children: description }) : null
|
|
686
|
-
] }),
|
|
687
|
-
right
|
|
688
|
-
] }),
|
|
689
|
-
/* @__PURE__ */ jsx("div", { className: "p-4", children })
|
|
690
|
-
] });
|
|
691
|
-
}
|
|
692
|
-
function FieldRow$2({ label, hint, children }) {
|
|
693
|
-
return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
|
|
694
|
-
/* @__PURE__ */ jsxs("div", { className: "col-span-12 md:col-span-4", children: [
|
|
695
|
-
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
|
|
696
|
-
hint ? /* @__PURE__ */ jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: hint }) : null
|
|
697
|
-
] }),
|
|
698
|
-
/* @__PURE__ */ jsx("div", { className: "col-span-12 md:col-span-8", children })
|
|
699
|
-
] });
|
|
700
|
-
}
|
|
701
|
-
function AdvancedCardPaymentsTab() {
|
|
702
|
-
var _a, _b;
|
|
703
|
-
const [form, setForm] = useState(() => ({ ...DEFAULT_FORM$1 }));
|
|
704
|
-
const [loading, setLoading] = useState(false);
|
|
705
|
-
const [saving, setSaving] = useState(false);
|
|
706
|
-
const [toast, setToast] = useState(null);
|
|
707
|
-
const didInit = useRef(false);
|
|
463
|
+
setTimeout(tryInit, 50);
|
|
464
|
+
};
|
|
465
|
+
tryInit();
|
|
466
|
+
},
|
|
467
|
+
[showUI]
|
|
468
|
+
);
|
|
708
469
|
useEffect(() => {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
470
|
+
currentRunId.current = ++runIdRef.current;
|
|
471
|
+
const runId = currentRunId.current;
|
|
472
|
+
let cancelled = false;
|
|
473
|
+
const run = async () => {
|
|
474
|
+
setConnState("loading");
|
|
475
|
+
setError(null);
|
|
476
|
+
setFinalUrl("");
|
|
477
|
+
try {
|
|
478
|
+
const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
479
|
+
method: "GET"
|
|
480
|
+
});
|
|
481
|
+
const st = await r.json().catch(() => ({}));
|
|
482
|
+
if (cancelled || runId !== currentRunId.current) return;
|
|
483
|
+
setStatusInfo(st);
|
|
484
|
+
const isConnected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
|
|
485
|
+
if (isConnected) {
|
|
486
|
+
setConnState("connected");
|
|
487
|
+
setShowManual(false);
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
} catch (e) {
|
|
491
|
+
console.error(e);
|
|
492
|
+
}
|
|
493
|
+
if (cachedUrl) {
|
|
494
|
+
activatePayPal(cachedUrl, runId);
|
|
495
|
+
} else {
|
|
496
|
+
fetchFreshLink(runId);
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
run();
|
|
500
|
+
return () => {
|
|
501
|
+
cancelled = true;
|
|
502
|
+
currentRunId.current = 0;
|
|
503
|
+
};
|
|
504
|
+
}, [env, fetchFreshLink, activatePayPal]);
|
|
505
|
+
useLayoutEffect(() => {
|
|
506
|
+
window.onboardingCallback = async function(authCode, sharedId) {
|
|
507
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
508
|
+
try {
|
|
509
|
+
;
|
|
510
|
+
window.onbeforeunload = "";
|
|
511
|
+
} catch {
|
|
512
|
+
}
|
|
513
|
+
setOnboardingInProgress(true);
|
|
514
|
+
setConnState("loading");
|
|
515
|
+
setError(null);
|
|
516
|
+
const payload = {
|
|
517
|
+
authCode,
|
|
518
|
+
sharedId,
|
|
519
|
+
env: env === "sandbox" ? "sandbox" : "live"
|
|
520
|
+
};
|
|
521
|
+
try {
|
|
522
|
+
const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
|
|
523
|
+
method: "POST",
|
|
524
|
+
headers: { "content-type": "application/json" },
|
|
525
|
+
body: JSON.stringify(payload)
|
|
526
|
+
});
|
|
527
|
+
if (!res.ok) {
|
|
528
|
+
const txt = await res.text().catch(() => "");
|
|
529
|
+
throw new Error(txt || `Onboarding exchange failed (${res.status})`);
|
|
530
|
+
}
|
|
531
|
+
try {
|
|
532
|
+
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;
|
|
533
|
+
if (typeof close1 === "function") close1();
|
|
534
|
+
} catch {
|
|
535
|
+
}
|
|
536
|
+
try {
|
|
537
|
+
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;
|
|
538
|
+
if (typeof close2 === "function") close2();
|
|
539
|
+
} catch {
|
|
540
|
+
}
|
|
541
|
+
try {
|
|
542
|
+
localStorage.removeItem(CACHE_KEY);
|
|
543
|
+
localStorage.removeItem(RELOAD_KEY);
|
|
544
|
+
} catch {
|
|
545
|
+
}
|
|
546
|
+
window.location.href = window.location.href;
|
|
547
|
+
} catch (e) {
|
|
548
|
+
console.error(e);
|
|
549
|
+
setConnState("error");
|
|
550
|
+
setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
|
|
551
|
+
setOnboardingInProgress(false);
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
return () => {
|
|
555
|
+
window.onboardingCallback = void 0;
|
|
556
|
+
};
|
|
557
|
+
}, [env]);
|
|
558
|
+
useLayoutEffect(() => {
|
|
559
|
+
const el = ppBtnMeasureRef.current;
|
|
560
|
+
if (!el) return;
|
|
561
|
+
const update = () => {
|
|
562
|
+
const w = Math.round(el.getBoundingClientRect().width || 0);
|
|
563
|
+
if (w > 0) setPpBtnWidth(w);
|
|
564
|
+
};
|
|
565
|
+
update();
|
|
566
|
+
let ro = null;
|
|
567
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
568
|
+
ro = new ResizeObserver(() => update());
|
|
569
|
+
ro.observe(el);
|
|
570
|
+
} else {
|
|
571
|
+
window.addEventListener("resize", update);
|
|
572
|
+
}
|
|
573
|
+
return () => {
|
|
574
|
+
if (ro) ro.disconnect();
|
|
575
|
+
else window.removeEventListener("resize", update);
|
|
576
|
+
};
|
|
577
|
+
}, [connState, env, finalUrl]);
|
|
578
|
+
const handleConnectClick = (e) => {
|
|
579
|
+
if (connState !== "ready" || !finalUrl || onboardingInProgress) {
|
|
580
|
+
e.preventDefault();
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
const handleSaveManual = async () => {
|
|
584
|
+
if (!canSaveManual || onboardingInProgress) return;
|
|
585
|
+
setOnboardingInProgress(true);
|
|
586
|
+
setConnState("loading");
|
|
587
|
+
setError(null);
|
|
588
|
+
try {
|
|
589
|
+
const res = await fetch(SAVE_CREDENTIALS_ENDPOINT, {
|
|
590
|
+
method: "POST",
|
|
591
|
+
headers: { "content-type": "application/json" },
|
|
592
|
+
body: JSON.stringify({
|
|
593
|
+
clientId: clientId.trim(),
|
|
594
|
+
clientSecret: secret.trim(),
|
|
595
|
+
environment: env
|
|
596
|
+
})
|
|
597
|
+
});
|
|
598
|
+
if (!res.ok) {
|
|
599
|
+
const txt = await res.text().catch(() => "");
|
|
600
|
+
throw new Error(txt || `Save credentials failed (${res.status})`);
|
|
601
|
+
}
|
|
602
|
+
const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
|
|
603
|
+
method: "GET"
|
|
604
|
+
});
|
|
605
|
+
const refreshedStatus = await statusRes.json().catch(() => ({}));
|
|
606
|
+
setConnState("connected");
|
|
607
|
+
setStatusInfo(refreshedStatus || null);
|
|
608
|
+
setShowManual(false);
|
|
712
609
|
try {
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
716
|
-
const saved = payload == null ? void 0 : payload.advanced_card_payments;
|
|
717
|
-
if (saved && typeof saved === "object") setForm(mergeWithDefaults$1(saved));
|
|
610
|
+
localStorage.removeItem(CACHE_KEY);
|
|
611
|
+
localStorage.removeItem(RELOAD_KEY);
|
|
718
612
|
} catch {
|
|
719
|
-
} finally {
|
|
720
|
-
setLoading(false);
|
|
721
613
|
}
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
|
|
614
|
+
} catch (e) {
|
|
615
|
+
console.error(e);
|
|
616
|
+
setConnState("error");
|
|
617
|
+
setError((e == null ? void 0 : e.message) || "Failed to save credentials.");
|
|
618
|
+
} finally {
|
|
619
|
+
setOnboardingInProgress(false);
|
|
620
|
+
}
|
|
621
|
+
};
|
|
622
|
+
const handleDisconnect = async () => {
|
|
623
|
+
if (onboardingInProgress) return;
|
|
624
|
+
if (!window.confirm("Disconnect PayPal for this environment?")) return;
|
|
625
|
+
setOnboardingInProgress(true);
|
|
626
|
+
setConnState("loading");
|
|
627
|
+
setError(null);
|
|
628
|
+
setFinalUrl("");
|
|
629
|
+
setShowManual(false);
|
|
725
630
|
try {
|
|
726
|
-
|
|
727
|
-
const json = await adminFetch$2("/admin/paypal/settings", {
|
|
631
|
+
const res = await fetch(DISCONNECT_ENDPOINT, {
|
|
728
632
|
method: "POST",
|
|
729
|
-
|
|
633
|
+
headers: { "content-type": "application/json" },
|
|
634
|
+
body: JSON.stringify({ environment: env })
|
|
730
635
|
});
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
636
|
+
if (!res.ok) {
|
|
637
|
+
const t = await res.text().catch(() => "");
|
|
638
|
+
throw new Error(t || `Disconnect failed (${res.status})`);
|
|
639
|
+
}
|
|
640
|
+
try {
|
|
641
|
+
localStorage.removeItem(CACHE_KEY);
|
|
642
|
+
localStorage.removeItem(RELOAD_KEY);
|
|
643
|
+
} catch {
|
|
644
|
+
}
|
|
645
|
+
currentRunId.current = ++runIdRef.current;
|
|
646
|
+
const runId = currentRunId.current;
|
|
647
|
+
fetchFreshLink(runId);
|
|
736
648
|
} catch (e) {
|
|
737
|
-
|
|
738
|
-
|
|
649
|
+
console.error(e);
|
|
650
|
+
setConnState("error");
|
|
651
|
+
setError((e == null ? void 0 : e.message) || "Failed to disconnect.");
|
|
739
652
|
} finally {
|
|
740
|
-
|
|
653
|
+
setOnboardingInProgress(false);
|
|
741
654
|
}
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
655
|
+
};
|
|
656
|
+
const handleEnvChange = async (e) => {
|
|
657
|
+
const next = e.target.value;
|
|
658
|
+
setEnv(next);
|
|
659
|
+
cachedUrl = null;
|
|
660
|
+
try {
|
|
661
|
+
await fetch("/admin/paypal/environment", {
|
|
662
|
+
method: "POST",
|
|
663
|
+
headers: { "content-type": "application/json" },
|
|
664
|
+
body: JSON.stringify({ environment: next })
|
|
665
|
+
});
|
|
666
|
+
} catch {
|
|
667
|
+
}
|
|
668
|
+
try {
|
|
669
|
+
localStorage.removeItem(CACHE_KEY);
|
|
670
|
+
localStorage.removeItem(RELOAD_KEY);
|
|
671
|
+
} catch {
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
return /* @__PURE__ */ jsxs("div", { className: "p-6", children: [
|
|
675
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
676
|
+
/* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold", children: "PayPal Gateway By Easy Payment" }),
|
|
677
|
+
/* @__PURE__ */ jsx(PayPalTabs, {}),
|
|
678
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-y-6 p-4 md:grid-cols-[260px_1fr] md:items-start", children: [
|
|
679
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium pt-2", children: "Environment" }),
|
|
680
|
+
/* @__PURE__ */ jsx("div", { className: "max-w-xl", children: /* @__PURE__ */ jsxs(
|
|
681
|
+
"select",
|
|
682
|
+
{
|
|
683
|
+
value: env,
|
|
684
|
+
onChange: handleEnvChange,
|
|
685
|
+
disabled: onboardingInProgress,
|
|
686
|
+
className: "w-full rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm",
|
|
687
|
+
children: [
|
|
688
|
+
/* @__PURE__ */ jsx("option", { value: "sandbox", children: "Sandbox (Test Mode)" }),
|
|
689
|
+
/* @__PURE__ */ jsx("option", { value: "live", children: "Live (Production)" })
|
|
690
|
+
]
|
|
691
|
+
}
|
|
692
|
+
) }),
|
|
693
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium pt-2", children: env === "sandbox" ? "Connect to PayPal (Sandbox)" : "Connect to PayPal" }),
|
|
694
|
+
/* @__PURE__ */ jsx("div", { className: "max-w-xl", children: connState === "connected" ? /* @__PURE__ */ jsxs("div", { children: [
|
|
695
|
+
/* @__PURE__ */ jsxs("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: [
|
|
696
|
+
"✅ Successfully connected to PayPal!",
|
|
697
|
+
/* @__PURE__ */ jsx(
|
|
698
|
+
"a",
|
|
699
|
+
{
|
|
700
|
+
"data-paypal-button": "true",
|
|
701
|
+
"data-paypal-onboard-complete": "onboardingCallback",
|
|
702
|
+
href: "#",
|
|
703
|
+
style: { display: "none" },
|
|
704
|
+
children: "PayPal"
|
|
705
|
+
}
|
|
706
|
+
)
|
|
707
|
+
] }),
|
|
708
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-3 rounded-md border border-ui-border-base bg-ui-bg-subtle p-3 text-xs text-ui-fg-subtle", children: [
|
|
709
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium text-ui-fg-base", children: "Connected PayPal account" }),
|
|
710
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-1", children: [
|
|
711
|
+
"Email:",
|
|
712
|
+
" ",
|
|
713
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono text-ui-fg-base", children: (statusInfo == null ? void 0 : statusInfo.seller_email) || "Unavailable" })
|
|
714
|
+
] })
|
|
715
|
+
] }),
|
|
716
|
+
/* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center gap-2", children: /* @__PURE__ */ jsx(
|
|
717
|
+
"button",
|
|
718
|
+
{
|
|
719
|
+
type: "button",
|
|
720
|
+
onClick: handleDisconnect,
|
|
721
|
+
disabled: onboardingInProgress,
|
|
722
|
+
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",
|
|
723
|
+
children: "Disconnect"
|
|
724
|
+
}
|
|
725
|
+
) })
|
|
726
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
727
|
+
/* @__PURE__ */ jsxs(
|
|
728
|
+
"div",
|
|
729
|
+
{
|
|
730
|
+
ref: initLoaderRef,
|
|
731
|
+
id: "init-loader",
|
|
732
|
+
className: `status-msg mb-4 ${connState !== "loading" ? "hidden" : "block"}`,
|
|
733
|
+
children: [
|
|
734
|
+
/* @__PURE__ */ jsx("div", { className: "loader inline-block align-middle mr-2" }),
|
|
735
|
+
/* @__PURE__ */ jsx("span", { id: "loader-text", className: "text-sm", children: onboardingInProgress ? "Configuring connection to PayPal…" : "Checking connection..." })
|
|
736
|
+
]
|
|
737
|
+
}
|
|
738
|
+
),
|
|
739
|
+
/* @__PURE__ */ jsxs("div", { className: `${connState === "ready" ? "block" : "hidden"}`, children: [
|
|
740
|
+
/* @__PURE__ */ jsx(
|
|
741
|
+
"a",
|
|
742
|
+
{
|
|
743
|
+
ref: (node) => {
|
|
744
|
+
paypalButtonRef.current = node;
|
|
745
|
+
ppBtnMeasureRef.current = node;
|
|
746
|
+
},
|
|
747
|
+
id: "paypal-button",
|
|
748
|
+
"data-paypal-button": "true",
|
|
749
|
+
href: finalUrl || "#",
|
|
750
|
+
"data-paypal-onboard-complete": "onboardingCallback",
|
|
751
|
+
onClick: handleConnectClick,
|
|
752
|
+
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",
|
|
753
|
+
style: {
|
|
754
|
+
cursor: onboardingInProgress ? "not-allowed" : "pointer",
|
|
755
|
+
opacity: onboardingInProgress ? 0.6 : 1,
|
|
756
|
+
pointerEvents: onboardingInProgress ? "none" : "auto"
|
|
757
|
+
},
|
|
758
|
+
children: "Connect to PayPal"
|
|
759
|
+
}
|
|
760
|
+
),
|
|
761
|
+
/* @__PURE__ */ jsx(
|
|
762
|
+
"div",
|
|
763
|
+
{
|
|
764
|
+
className: "mt-2",
|
|
765
|
+
style: {
|
|
766
|
+
width: ppBtnWidth ? `${ppBtnWidth}px` : "auto",
|
|
767
|
+
marginTop: "20px",
|
|
768
|
+
marginBottom: "10px"
|
|
769
|
+
},
|
|
770
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx("span", { className: "text-[11px] text-ui-fg-muted leading-none", children: "OR" }) })
|
|
771
|
+
}
|
|
772
|
+
),
|
|
773
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsx(
|
|
774
|
+
"button",
|
|
775
|
+
{
|
|
776
|
+
type: "button",
|
|
777
|
+
onClick: () => setShowManual(!showManual),
|
|
778
|
+
disabled: onboardingInProgress,
|
|
779
|
+
className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
|
|
780
|
+
children: "Click here to insert credentials manually"
|
|
781
|
+
}
|
|
782
|
+
) })
|
|
783
|
+
] }),
|
|
784
|
+
/* @__PURE__ */ jsx("div", { className: `${connState === "ready" ? "hidden" : "block"} mt-3`, children: /* @__PURE__ */ jsx(
|
|
785
|
+
"button",
|
|
786
|
+
{
|
|
787
|
+
type: "button",
|
|
788
|
+
onClick: () => setShowManual(!showManual),
|
|
789
|
+
disabled: onboardingInProgress,
|
|
790
|
+
className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
|
|
791
|
+
children: "Click here to insert credentials manually"
|
|
792
|
+
}
|
|
793
|
+
) }),
|
|
794
|
+
/* @__PURE__ */ jsx(
|
|
795
|
+
"div",
|
|
796
|
+
{
|
|
797
|
+
ref: errorLogRef,
|
|
798
|
+
id: "error-log",
|
|
799
|
+
className: `mt-4 text-left text-xs bg-red-50 text-red-600 p-3 border border-red-200 rounded ${connState === "error" && error ? "block" : "hidden"}`,
|
|
800
|
+
children: error
|
|
801
|
+
}
|
|
802
|
+
)
|
|
803
|
+
] }) }),
|
|
804
|
+
showManual && /* @__PURE__ */ jsx("div", { className: "md:col-span-2", children: /* @__PURE__ */ jsxs("div", { className: "ml-[260px] max-w-xl mt-4 grid grid-cols-1 gap-3 md:grid-cols-2", children: [
|
|
805
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
806
|
+
/* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Client ID" }),
|
|
807
|
+
/* @__PURE__ */ jsx(
|
|
808
|
+
"input",
|
|
809
|
+
{
|
|
810
|
+
type: "text",
|
|
811
|
+
value: clientId,
|
|
812
|
+
onChange: (e) => setClientId(e.target.value),
|
|
813
|
+
disabled: onboardingInProgress,
|
|
814
|
+
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
815
|
+
placeholder: env === "sandbox" ? "Sandbox Client ID" : "Live Client ID"
|
|
816
|
+
}
|
|
817
|
+
)
|
|
818
|
+
] }),
|
|
819
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
820
|
+
/* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Secret" }),
|
|
821
|
+
/* @__PURE__ */ jsx(
|
|
822
|
+
"input",
|
|
823
|
+
{
|
|
824
|
+
type: "password",
|
|
825
|
+
value: secret,
|
|
826
|
+
onChange: (e) => setSecret(e.target.value),
|
|
827
|
+
disabled: onboardingInProgress,
|
|
828
|
+
className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
|
|
829
|
+
placeholder: env === "sandbox" ? "Sandbox Secret" : "Live Secret"
|
|
830
|
+
}
|
|
831
|
+
)
|
|
832
|
+
] }),
|
|
833
|
+
/* @__PURE__ */ jsxs("div", { className: "md:col-span-2 rounded-md border border-ui-border-base bg-ui-bg-subtle p-4 text-sm text-ui-fg-subtle", children: [
|
|
834
|
+
/* @__PURE__ */ jsx("p", { className: "font-medium text-ui-fg-base", children: "Get your Client ID and Secret in 3 steps:" }),
|
|
835
|
+
/* @__PURE__ */ jsxs("ol", { className: "mt-2 list-decimal space-y-2 pl-5", children: [
|
|
836
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
837
|
+
"Open",
|
|
838
|
+
" ",
|
|
839
|
+
/* @__PURE__ */ jsx(
|
|
840
|
+
"a",
|
|
841
|
+
{
|
|
842
|
+
href: "https://developer.paypal.com/dashboard/",
|
|
843
|
+
target: "_blank",
|
|
844
|
+
rel: "noreferrer",
|
|
845
|
+
className: "text-ui-fg-interactive underline",
|
|
846
|
+
children: "Log in to Dashboard"
|
|
847
|
+
}
|
|
848
|
+
),
|
|
849
|
+
" ",
|
|
850
|
+
"and sign in or create an account."
|
|
851
|
+
] }),
|
|
852
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
853
|
+
"Select ",
|
|
854
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Apps & Credentials" }),
|
|
855
|
+
", then choose ",
|
|
856
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Create App" }),
|
|
857
|
+
" if you need a new project."
|
|
858
|
+
] }),
|
|
859
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
860
|
+
"Copy your app's ",
|
|
861
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Client ID" }),
|
|
862
|
+
" and ",
|
|
863
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Secret" }),
|
|
864
|
+
", paste them above, then click ",
|
|
865
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: "Save credentials" }),
|
|
866
|
+
"."
|
|
867
|
+
] })
|
|
868
|
+
] })
|
|
869
|
+
] }),
|
|
870
|
+
/* @__PURE__ */ jsxs("div", { className: "md:col-span-2 flex items-center gap-2 mt-2", children: [
|
|
871
|
+
/* @__PURE__ */ jsx(
|
|
872
|
+
"button",
|
|
873
|
+
{
|
|
874
|
+
type: "button",
|
|
875
|
+
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",
|
|
876
|
+
onClick: () => setShowManual(false),
|
|
877
|
+
disabled: onboardingInProgress,
|
|
878
|
+
children: "Cancel"
|
|
879
|
+
}
|
|
880
|
+
),
|
|
881
|
+
/* @__PURE__ */ jsx(
|
|
882
|
+
"button",
|
|
883
|
+
{
|
|
884
|
+
type: "button",
|
|
885
|
+
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",
|
|
886
|
+
disabled: !canSaveManual || onboardingInProgress,
|
|
887
|
+
onClick: handleSaveManual,
|
|
888
|
+
children: "Save credentials"
|
|
889
|
+
}
|
|
890
|
+
)
|
|
891
|
+
] })
|
|
892
|
+
] }) })
|
|
893
|
+
] }) })
|
|
835
894
|
] }),
|
|
836
|
-
/* @__PURE__ */ jsx("
|
|
895
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
896
|
+
.loader {
|
|
897
|
+
border: 3px solid #f3f3f3;
|
|
898
|
+
border-top: 3px solid #0070ba;
|
|
899
|
+
border-radius: 50%;
|
|
900
|
+
width: 18px;
|
|
901
|
+
height: 18px;
|
|
902
|
+
animation: spin 1s linear infinite;
|
|
903
|
+
display: inline-block;
|
|
904
|
+
vertical-align: middle;
|
|
905
|
+
margin-right: 8px;
|
|
906
|
+
}
|
|
907
|
+
@keyframes spin {
|
|
908
|
+
0% { transform: rotate(0deg); }
|
|
909
|
+
100% { transform: rotate(360deg); }
|
|
910
|
+
}
|
|
911
|
+
` })
|
|
837
912
|
] });
|
|
838
913
|
}
|
|
839
|
-
function
|
|
840
|
-
const [form, setForm] = useState(() => ({ ...DEFAULT_FORM }));
|
|
841
|
-
const [loading, setLoading] = useState(false);
|
|
842
|
-
const [saving, setSaving] = useState(false);
|
|
843
|
-
const [toast, setToast] = useState(null);
|
|
844
|
-
const didInit = useRef(false);
|
|
845
|
-
useEffect(() => {
|
|
846
|
-
if (didInit.current) return;
|
|
847
|
-
didInit.current = true;
|
|
848
|
-
(async () => {
|
|
849
|
-
try {
|
|
850
|
-
setLoading(true);
|
|
851
|
-
const json = await adminFetch$1("/admin/paypal/settings");
|
|
852
|
-
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
853
|
-
const saved = payload == null ? void 0 : payload.additional_settings;
|
|
854
|
-
if (saved && typeof saved === "object") setForm(mergeWithDefaults(saved));
|
|
855
|
-
} catch {
|
|
856
|
-
} finally {
|
|
857
|
-
setLoading(false);
|
|
858
|
-
}
|
|
859
|
-
})();
|
|
860
|
-
}, []);
|
|
861
|
-
async function onSave() {
|
|
862
|
-
try {
|
|
863
|
-
setSaving(true);
|
|
864
|
-
setToast(null);
|
|
865
|
-
const json = await adminFetch$1("/admin/paypal/settings", { method: "POST", body: { additional_settings: form } });
|
|
866
|
-
const payload = (json == null ? void 0 : json.data) ?? json;
|
|
867
|
-
const saved = payload == null ? void 0 : payload.additional_settings;
|
|
868
|
-
if (saved && typeof saved === "object") setForm(mergeWithDefaults(saved));
|
|
869
|
-
setToast({ type: "success", message: "Settings saved" });
|
|
870
|
-
window.setTimeout(() => setToast(null), 2500);
|
|
871
|
-
} catch (e) {
|
|
872
|
-
setToast({ type: "error", message: e instanceof Error ? e.message : "Failed to save settings" });
|
|
873
|
-
window.setTimeout(() => setToast(null), 3500);
|
|
874
|
-
} finally {
|
|
875
|
-
setSaving(false);
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
return /* @__PURE__ */ jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
879
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-start justify-between gap-4", children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-ui-fg-base", children: "PayPal Gateway By Easy Payment" }) }) }),
|
|
880
|
-
/* @__PURE__ */ jsx(PayPalTabs, {}),
|
|
881
|
-
toast ? /* @__PURE__ */ jsx("div", { className: "fixed right-6 top-6 z-50 rounded-md border border-ui-border-base bg-ui-bg-base px-4 py-3 text-sm shadow-lg", role: "status", "aria-live": "polite", children: /* @__PURE__ */ jsx("span", { className: toast.type === "success" ? "text-ui-fg-base" : "text-ui-fg-error", children: toast.message }) }) : null,
|
|
882
|
-
/* @__PURE__ */ jsx(
|
|
883
|
-
SectionCard$1,
|
|
884
|
-
{
|
|
885
|
-
title: "Additional Settings",
|
|
886
|
-
description: "These settings control checkout behavior and PayPal experience.",
|
|
887
|
-
right: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
888
|
-
/* @__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" }),
|
|
889
|
-
loading ? /* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading..." }) : null
|
|
890
|
-
] }),
|
|
891
|
-
children: /* @__PURE__ */ jsxs("div", { className: "divide-y divide-ui-border-base", children: [
|
|
892
|
-
/* @__PURE__ */ jsx(FieldRow$1, { label: "Payment action", children: /* @__PURE__ */ jsxs("select", { value: form.paymentAction, onChange: (e) => setForm((p) => ({ ...p, paymentAction: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", children: [
|
|
893
|
-
/* @__PURE__ */ jsx("option", { value: "capture", children: "Capture" }),
|
|
894
|
-
/* @__PURE__ */ jsx("option", { value: "authorize", children: "Authorize" })
|
|
895
|
-
] }) }),
|
|
896
|
-
/* @__PURE__ */ jsx(FieldRow$1, { label: "Brand Name", children: /* @__PURE__ */ jsx("input", { value: form.brandName, onChange: (e) => setForm((p) => ({ ...p, brandName: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", placeholder: "PayPal" }) }),
|
|
897
|
-
/* @__PURE__ */ jsx(FieldRow$1, { label: "Landing Page", children: /* @__PURE__ */ jsxs("select", { value: form.landingPage, onChange: (e) => setForm((p) => ({ ...p, landingPage: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", children: [
|
|
898
|
-
/* @__PURE__ */ jsx("option", { value: "no_preference", children: "No Preference" }),
|
|
899
|
-
/* @__PURE__ */ jsx("option", { value: "login", children: "Login" }),
|
|
900
|
-
/* @__PURE__ */ jsx("option", { value: "billing", children: "Billing" })
|
|
901
|
-
] }) }),
|
|
902
|
-
/* @__PURE__ */ jsx(FieldRow$1, { label: "Instant Payments", children: /* @__PURE__ */ jsxs("label", { className: "inline-flex items-center gap-2", children: [
|
|
903
|
-
/* @__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" }),
|
|
904
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-base", children: "Require Instant Payment" })
|
|
905
|
-
] }) }),
|
|
906
|
-
/* @__PURE__ */ jsx(FieldRow$1, { 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: [
|
|
907
|
-
/* @__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" }),
|
|
908
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm text-ui-fg-base", children: "Send line item details to PayPal" })
|
|
909
|
-
] }) }),
|
|
910
|
-
/* @__PURE__ */ jsx(FieldRow$1, { label: "Invoice prefix", children: /* @__PURE__ */ jsx("input", { value: form.invoicePrefix, onChange: (e) => setForm((p) => ({ ...p, invoicePrefix: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", placeholder: "WC-" }) }),
|
|
911
|
-
/* @__PURE__ */ jsx(FieldRow$1, { label: "Credit Card Statement Name", children: /* @__PURE__ */ jsx("input", { value: form.creditCardStatementName, onChange: (e) => setForm((p) => ({ ...p, creditCardStatementName: e.target.value })), className: "w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive", placeholder: "PayPal" }) })
|
|
912
|
-
] })
|
|
913
|
-
}
|
|
914
|
-
)
|
|
915
|
-
] }) });
|
|
916
|
-
}
|
|
917
|
-
function PayPalGooglePayPage() {
|
|
914
|
+
function PayPalApplePayPage() {
|
|
918
915
|
return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
919
916
|
}
|
|
920
|
-
function
|
|
917
|
+
function PayPalGooglePayPage() {
|
|
921
918
|
return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
922
919
|
}
|
|
923
920
|
async function adminFetch(path, opts = {}) {
|
|
@@ -1193,6 +1190,9 @@ function PayPalSettingsTab() {
|
|
|
1193
1190
|
)
|
|
1194
1191
|
] }) });
|
|
1195
1192
|
}
|
|
1193
|
+
function PayPalPayLaterMessagingPage() {
|
|
1194
|
+
return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
|
|
1195
|
+
}
|
|
1196
1196
|
const widgetModule = { widgets: [] };
|
|
1197
1197
|
const routeModule = {
|
|
1198
1198
|
routes: [
|
|
@@ -1201,32 +1201,32 @@ const routeModule = {
|
|
|
1201
1201
|
path: "/settings/paypal"
|
|
1202
1202
|
},
|
|
1203
1203
|
{
|
|
1204
|
-
Component:
|
|
1205
|
-
path: "/settings/paypal/
|
|
1206
|
-
},
|
|
1207
|
-
{
|
|
1208
|
-
Component: PayPalConnectionPage,
|
|
1209
|
-
path: "/settings/paypal/connection"
|
|
1204
|
+
Component: AdditionalSettingsTab,
|
|
1205
|
+
path: "/settings/paypal/additional-settings"
|
|
1210
1206
|
},
|
|
1211
1207
|
{
|
|
1212
1208
|
Component: AdvancedCardPaymentsTab,
|
|
1213
1209
|
path: "/settings/paypal/advanced-card-payments"
|
|
1214
1210
|
},
|
|
1215
1211
|
{
|
|
1216
|
-
Component:
|
|
1217
|
-
path: "/settings/paypal/
|
|
1212
|
+
Component: PayPalConnectionPage,
|
|
1213
|
+
path: "/settings/paypal/connection"
|
|
1218
1214
|
},
|
|
1219
1215
|
{
|
|
1220
|
-
Component:
|
|
1221
|
-
path: "/settings/paypal/
|
|
1216
|
+
Component: PayPalApplePayPage,
|
|
1217
|
+
path: "/settings/paypal/apple-pay"
|
|
1222
1218
|
},
|
|
1223
1219
|
{
|
|
1224
|
-
Component:
|
|
1225
|
-
path: "/settings/paypal/pay
|
|
1220
|
+
Component: PayPalGooglePayPage,
|
|
1221
|
+
path: "/settings/paypal/google-pay"
|
|
1226
1222
|
},
|
|
1227
1223
|
{
|
|
1228
1224
|
Component: PayPalSettingsTab,
|
|
1229
1225
|
path: "/settings/paypal/paypal-settings"
|
|
1226
|
+
},
|
|
1227
|
+
{
|
|
1228
|
+
Component: PayPalPayLaterMessagingPage,
|
|
1229
|
+
path: "/settings/paypal/pay-later-messaging"
|
|
1230
1230
|
}
|
|
1231
1231
|
]
|
|
1232
1232
|
};
|