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