@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.
@@ -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,888 +34,888 @@ function PayPalTabs() {
37
34
  );
38
35
  }) }) });
39
36
  }
40
- const config = adminSdk.defineRouteConfig({
41
- label: "PayPal Connection",
42
- hide: true
43
- });
44
- if (typeof window !== "undefined") {
45
- const preloadHref = "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js";
46
- const existingPreload = document.head.querySelector(
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 existingScript = document.getElementById(
57
- "paypal-partner-js"
58
- );
59
- if (!existingScript) {
60
- const ppScript = document.createElement("script");
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
- const SERVICE_URL = "/admin/paypal/onboarding-link";
68
- const CACHE_KEY = "pp_onboard_cache";
69
- const RELOAD_KEY = "pp_onboard_reloaded_once";
70
- const CACHE_EXPIRY = 10 * 60 * 1e3;
71
- const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
72
- const STATUS_ENDPOINT = "/admin/paypal/status";
73
- const SAVE_CREDENTIALS_ENDPOINT = "/admin/paypal/save-credentials";
74
- const DISCONNECT_ENDPOINT = "/admin/paypal/disconnect";
75
- let cachedUrl = null;
76
- if (typeof window !== "undefined") {
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
- const cached = localStorage.getItem(CACHE_KEY);
79
- if (cached) {
80
- const data = JSON.parse(cached);
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
- function PayPalConnectionPage() {
90
- const [env, setEnv] = react.useState("live");
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
- fetch("/admin/paypal/environment", { method: "GET" }).then((r) => r.json()).then((d) => {
93
- const v = (d == null ? void 0 : d.environment) === "sandbox" ? "sandbox" : "live";
94
- setEnv(v);
95
- }).catch(() => {
96
- });
97
- }, []);
98
- const [connState, setConnState] = react.useState("loading");
99
- const [error, setError] = react.useState(null);
100
- const [finalUrl, setFinalUrl] = react.useState("");
101
- const [showManual, setShowManual] = react.useState(false);
102
- const [clientId, setClientId] = react.useState("");
103
- const [secret, setSecret] = react.useState("");
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
- fetch(SERVICE_URL, {
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
- const activatePayPal = react.useCallback(
170
- (url, runId) => {
171
- if (paypalButtonRef.current) {
172
- paypalButtonRef.current.href = url;
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
- setFinalUrl(url);
175
- const tryInit = () => {
176
- var _a, _b;
177
- if (runId !== currentRunId.current) return;
178
- if ((_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) {
179
- showUI();
180
- return;
181
- }
182
- setTimeout(tryInit, 50);
183
- };
184
- tryInit();
185
- },
186
- [showUI]
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
- currentRunId.current = ++runIdRef.current;
190
- const runId = currentRunId.current;
191
- let cancelled = false;
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
- window.onbeforeunload = "";
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
- setOnboardingInProgress(true);
233
- setConnState("loading");
234
- setError(null);
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
- const res = await fetch(SAVE_CREDENTIALS_ENDPOINT, {
277
+ setSaving(true);
278
+ const json = await adminFetch$1("/admin/paypal/settings", {
309
279
  method: "POST",
310
- headers: { "content-type": "application/json" },
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 refreshedStatus = await statusRes.json().catch(() => ({}));
325
- setConnState("connected");
326
- setStatusInfo(refreshedStatus || null);
327
- setShowManual(false);
328
- try {
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
- console.error(e);
335
- setConnState("error");
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
- setOnboardingInProgress(false);
291
+ setSaving(false);
339
292
  }
340
- };
341
- const handleDisconnect = async () => {
342
- if (onboardingInProgress) return;
343
- if (!window.confirm("Disconnect PayPal for this environment?")) return;
344
- setOnboardingInProgress(true);
345
- setConnState("loading");
346
- setError(null);
347
- setFinalUrl("");
348
- setShowManual(false);
349
- try {
350
- const res = await fetch(DISCONNECT_ENDPOINT, {
351
- method: "POST",
352
- headers: { "content-type": "application/json" },
353
- body: JSON.stringify({ environment: env })
354
- });
355
- if (!res.ok) {
356
- const t = await res.text().catch(() => "");
357
- throw new Error(t || `Disconnect failed (${res.status})`);
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
- try {
360
- localStorage.removeItem(CACHE_KEY);
361
- localStorage.removeItem(RELOAD_KEY);
362
- } catch {
319
+ )
320
+ ] }) });
321
+ }
322
+ const config = adminSdk.defineRouteConfig({
323
+ label: "PayPal Connection",
324
+ hide: true
325
+ });
326
+ if (typeof window !== "undefined") {
327
+ const preloadHref = "https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js";
328
+ const existingPreload = document.head.querySelector(
329
+ `link[rel="preload"][href="${preloadHref}"]`
330
+ );
331
+ if (!existingPreload) {
332
+ const preloadLink = document.createElement("link");
333
+ preloadLink.rel = "preload";
334
+ preloadLink.href = preloadHref;
335
+ preloadLink.as = "script";
336
+ document.head.appendChild(preloadLink);
337
+ }
338
+ const existingScript = document.getElementById(
339
+ "paypal-partner-js"
340
+ );
341
+ if (!existingScript) {
342
+ const ppScript = document.createElement("script");
343
+ ppScript.id = "paypal-partner-js";
344
+ ppScript.src = preloadHref;
345
+ ppScript.async = true;
346
+ document.head.appendChild(ppScript);
347
+ }
348
+ }
349
+ const SERVICE_URL = "/admin/paypal/onboarding-link";
350
+ const CACHE_KEY = "pp_onboard_cache";
351
+ const RELOAD_KEY = "pp_onboard_reloaded_once";
352
+ const CACHE_EXPIRY = 10 * 60 * 1e3;
353
+ const ONBOARDING_COMPLETE_ENDPOINT = "/admin/paypal/onboard-complete";
354
+ const STATUS_ENDPOINT = "/admin/paypal/status";
355
+ const SAVE_CREDENTIALS_ENDPOINT = "/admin/paypal/save-credentials";
356
+ const DISCONNECT_ENDPOINT = "/admin/paypal/disconnect";
357
+ let cachedUrl = null;
358
+ if (typeof window !== "undefined") {
359
+ try {
360
+ const cached = localStorage.getItem(CACHE_KEY);
361
+ if (cached) {
362
+ const data = JSON.parse(cached);
363
+ if ((/* @__PURE__ */ new Date()).getTime() - data.ts < CACHE_EXPIRY) {
364
+ cachedUrl = data.url;
363
365
  }
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
366
  }
374
- };
375
- const handleEnvChange = async (e) => {
376
- const next = e.target.value;
377
- setEnv(next);
378
- cachedUrl = null;
379
- try {
380
- await fetch("/admin/paypal/environment", {
367
+ } catch (e) {
368
+ console.error("Cache read error:", e);
369
+ }
370
+ }
371
+ function PayPalConnectionPage() {
372
+ const [env, setEnv] = react.useState("live");
373
+ react.useEffect(() => {
374
+ fetch("/admin/paypal/environment", { method: "GET" }).then((r) => r.json()).then((d) => {
375
+ const v = (d == null ? void 0 : d.environment) === "sandbox" ? "sandbox" : "live";
376
+ setEnv(v);
377
+ }).catch(() => {
378
+ });
379
+ }, []);
380
+ const [connState, setConnState] = react.useState("loading");
381
+ const [error, setError] = react.useState(null);
382
+ const [finalUrl, setFinalUrl] = react.useState("");
383
+ const [showManual, setShowManual] = react.useState(false);
384
+ const [clientId, setClientId] = react.useState("");
385
+ const [secret, setSecret] = react.useState("");
386
+ const [statusInfo, setStatusInfo] = react.useState(null);
387
+ const [onboardingInProgress, setOnboardingInProgress] = react.useState(false);
388
+ const initLoaderRef = react.useRef(null);
389
+ const paypalButtonRef = react.useRef(null);
390
+ const errorLogRef = react.useRef(null);
391
+ const runIdRef = react.useRef(0);
392
+ const currentRunId = react.useRef(0);
393
+ const ppBtnMeasureRef = react.useRef(null);
394
+ const [ppBtnWidth, setPpBtnWidth] = react.useState(null);
395
+ const canSaveManual = react.useMemo(() => {
396
+ return clientId.trim().length > 0 && secret.trim().length > 0;
397
+ }, [clientId, secret]);
398
+ const fetchFreshLink = react.useCallback(
399
+ (runId) => {
400
+ if (initLoaderRef.current) {
401
+ const loaderText = initLoaderRef.current.querySelector("#loader-text");
402
+ if (loaderText)
403
+ loaderText.textContent = "Generating onboarding session...";
404
+ }
405
+ fetch(SERVICE_URL, {
381
406
  method: "POST",
382
407
  headers: { "content-type": "application/json" },
383
- body: JSON.stringify({ environment: next })
408
+ body: JSON.stringify({
409
+ products: ["PPCP"]
410
+ })
411
+ }).then((r) => r.json()).then((data) => {
412
+ if (runId !== currentRunId.current) return;
413
+ const href = data == null ? void 0 : data.onboarding_url;
414
+ if (!href) {
415
+ showError("Onboarding URL not returned.");
416
+ return;
417
+ }
418
+ const finalUrl2 = href + (href.includes("?") ? "&" : "?") + "displayMode=minibrowser";
419
+ localStorage.setItem(
420
+ CACHE_KEY,
421
+ JSON.stringify({
422
+ url: finalUrl2,
423
+ ts: Date.now()
424
+ })
425
+ );
426
+ if (!localStorage.getItem(RELOAD_KEY)) {
427
+ localStorage.setItem(RELOAD_KEY, "1");
428
+ window.location.reload();
429
+ return;
430
+ }
431
+ activatePayPal(finalUrl2, runId);
432
+ }).catch(() => {
433
+ if (runId !== currentRunId.current) return;
434
+ showError("Unable to connect to service.");
384
435
  });
385
- } catch {
386
- }
387
- try {
388
- localStorage.removeItem(CACHE_KEY);
389
- localStorage.removeItem(RELOAD_KEY);
390
- } catch {
436
+ },
437
+ [env]
438
+ );
439
+ const showUI = react.useCallback(() => {
440
+ var _a, _b, _c, _d;
441
+ const btn = document.querySelector('[data-paypal-button="true"]');
442
+ 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)) {
443
+ window.PAYPAL.apps.Signup.miniBrowser.init();
391
444
  }
392
- };
393
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6", children: [
394
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
395
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold", children: "PayPal Gateway By Easy Payment" }),
396
- /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
397
- /* @__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: [
398
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium pt-2", children: "Environment" }),
399
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xl", children: /* @__PURE__ */ jsxRuntime.jsxs(
400
- "select",
401
- {
402
- value: env,
403
- onChange: handleEnvChange,
404
- disabled: onboardingInProgress,
405
- className: "w-full rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm",
406
- children: [
407
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "sandbox", children: "Sandbox (Test Mode)" }),
408
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "live", children: "Live (Production)" })
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); }
445
+ setConnState("ready");
446
+ }, []);
447
+ const showError = react.useCallback((msg) => {
448
+ setConnState("error");
449
+ setError(msg);
450
+ }, []);
451
+ const activatePayPal = react.useCallback(
452
+ (url, runId) => {
453
+ if (paypalButtonRef.current) {
454
+ paypalButtonRef.current.href = url;
455
+ }
456
+ setFinalUrl(url);
457
+ const tryInit = () => {
458
+ var _a, _b;
459
+ if (runId !== currentRunId.current) return;
460
+ if ((_b = (_a = window.PAYPAL) == null ? void 0 : _a.apps) == null ? void 0 : _b.Signup) {
461
+ showUI();
462
+ return;
629
463
  }
630
- ` })
631
- ] });
632
- }
633
- async function adminFetch$2(path, opts = {}) {
634
- var _a;
635
- const { method = "GET", body, query } = opts;
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);
464
+ setTimeout(tryInit, 50);
465
+ };
466
+ tryInit();
467
+ },
468
+ [showUI]
469
+ );
709
470
  react.useEffect(() => {
710
- if (didInit.current) return;
711
- didInit.current = true;
712
- (async () => {
471
+ currentRunId.current = ++runIdRef.current;
472
+ const runId = currentRunId.current;
473
+ let cancelled = false;
474
+ const run = async () => {
475
+ setConnState("loading");
476
+ setError(null);
477
+ setFinalUrl("");
478
+ try {
479
+ const r = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
480
+ method: "GET"
481
+ });
482
+ const st = await r.json().catch(() => ({}));
483
+ if (cancelled || runId !== currentRunId.current) return;
484
+ setStatusInfo(st);
485
+ const isConnected = (st == null ? void 0 : st.status) === "connected" && (st == null ? void 0 : st.seller_client_id_present) === true;
486
+ if (isConnected) {
487
+ setConnState("connected");
488
+ setShowManual(false);
489
+ return;
490
+ }
491
+ } catch (e) {
492
+ console.error(e);
493
+ }
494
+ if (cachedUrl) {
495
+ activatePayPal(cachedUrl, runId);
496
+ } else {
497
+ fetchFreshLink(runId);
498
+ }
499
+ };
500
+ run();
501
+ return () => {
502
+ cancelled = true;
503
+ currentRunId.current = 0;
504
+ };
505
+ }, [env, fetchFreshLink, activatePayPal]);
506
+ react.useLayoutEffect(() => {
507
+ window.onboardingCallback = async function(authCode, sharedId) {
508
+ var _a, _b, _c, _d, _e, _f, _g;
509
+ try {
510
+ ;
511
+ window.onbeforeunload = "";
512
+ } catch {
513
+ }
514
+ setOnboardingInProgress(true);
515
+ setConnState("loading");
516
+ setError(null);
517
+ const payload = {
518
+ authCode,
519
+ sharedId,
520
+ env: env === "sandbox" ? "sandbox" : "live"
521
+ };
522
+ try {
523
+ const res = await fetch(ONBOARDING_COMPLETE_ENDPOINT, {
524
+ method: "POST",
525
+ headers: { "content-type": "application/json" },
526
+ body: JSON.stringify(payload)
527
+ });
528
+ if (!res.ok) {
529
+ const txt = await res.text().catch(() => "");
530
+ throw new Error(txt || `Onboarding exchange failed (${res.status})`);
531
+ }
532
+ try {
533
+ 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;
534
+ if (typeof close1 === "function") close1();
535
+ } catch {
536
+ }
537
+ try {
538
+ 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;
539
+ if (typeof close2 === "function") close2();
540
+ } catch {
541
+ }
542
+ try {
543
+ localStorage.removeItem(CACHE_KEY);
544
+ localStorage.removeItem(RELOAD_KEY);
545
+ } catch {
546
+ }
547
+ window.location.href = window.location.href;
548
+ } catch (e) {
549
+ console.error(e);
550
+ setConnState("error");
551
+ setError((e == null ? void 0 : e.message) || "Exchange failed while saving credentials.");
552
+ setOnboardingInProgress(false);
553
+ }
554
+ };
555
+ return () => {
556
+ window.onboardingCallback = void 0;
557
+ };
558
+ }, [env]);
559
+ react.useLayoutEffect(() => {
560
+ const el = ppBtnMeasureRef.current;
561
+ if (!el) return;
562
+ const update = () => {
563
+ const w = Math.round(el.getBoundingClientRect().width || 0);
564
+ if (w > 0) setPpBtnWidth(w);
565
+ };
566
+ update();
567
+ let ro = null;
568
+ if (typeof ResizeObserver !== "undefined") {
569
+ ro = new ResizeObserver(() => update());
570
+ ro.observe(el);
571
+ } else {
572
+ window.addEventListener("resize", update);
573
+ }
574
+ return () => {
575
+ if (ro) ro.disconnect();
576
+ else window.removeEventListener("resize", update);
577
+ };
578
+ }, [connState, env, finalUrl]);
579
+ const handleConnectClick = (e) => {
580
+ if (connState !== "ready" || !finalUrl || onboardingInProgress) {
581
+ e.preventDefault();
582
+ }
583
+ };
584
+ const handleSaveManual = async () => {
585
+ if (!canSaveManual || onboardingInProgress) return;
586
+ setOnboardingInProgress(true);
587
+ setConnState("loading");
588
+ setError(null);
589
+ try {
590
+ const res = await fetch(SAVE_CREDENTIALS_ENDPOINT, {
591
+ method: "POST",
592
+ headers: { "content-type": "application/json" },
593
+ body: JSON.stringify({
594
+ clientId: clientId.trim(),
595
+ clientSecret: secret.trim(),
596
+ environment: env
597
+ })
598
+ });
599
+ if (!res.ok) {
600
+ const txt = await res.text().catch(() => "");
601
+ throw new Error(txt || `Save credentials failed (${res.status})`);
602
+ }
603
+ const statusRes = await fetch(`${STATUS_ENDPOINT}?environment=${env}`, {
604
+ method: "GET"
605
+ });
606
+ const refreshedStatus = await statusRes.json().catch(() => ({}));
607
+ setConnState("connected");
608
+ setStatusInfo(refreshedStatus || null);
609
+ setShowManual(false);
713
610
  try {
714
- setLoading(true);
715
- const json = await adminFetch$2("/admin/paypal/settings");
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));
611
+ localStorage.removeItem(CACHE_KEY);
612
+ localStorage.removeItem(RELOAD_KEY);
719
613
  } catch {
720
- } finally {
721
- setLoading(false);
722
614
  }
723
- })();
724
- }, []);
725
- async function onSave() {
615
+ } catch (e) {
616
+ console.error(e);
617
+ setConnState("error");
618
+ setError((e == null ? void 0 : e.message) || "Failed to save credentials.");
619
+ } finally {
620
+ setOnboardingInProgress(false);
621
+ }
622
+ };
623
+ const handleDisconnect = async () => {
624
+ if (onboardingInProgress) return;
625
+ if (!window.confirm("Disconnect PayPal for this environment?")) return;
626
+ setOnboardingInProgress(true);
627
+ setConnState("loading");
628
+ setError(null);
629
+ setFinalUrl("");
630
+ setShowManual(false);
726
631
  try {
727
- setSaving(true);
728
- const json = await adminFetch$2("/admin/paypal/settings", {
632
+ const res = await fetch(DISCONNECT_ENDPOINT, {
729
633
  method: "POST",
730
- body: { advanced_card_payments: form }
634
+ headers: { "content-type": "application/json" },
635
+ body: JSON.stringify({ environment: env })
731
636
  });
732
- const payload = (json == null ? void 0 : json.data) ?? json;
733
- const saved = payload == null ? void 0 : payload.advanced_card_payments;
734
- if (saved && typeof saved === "object") setForm(mergeWithDefaults$1(saved));
735
- setToast({ type: "success", message: "Settings saved" });
736
- window.setTimeout(() => setToast(null), 2500);
637
+ if (!res.ok) {
638
+ const t = await res.text().catch(() => "");
639
+ throw new Error(t || `Disconnect failed (${res.status})`);
640
+ }
641
+ try {
642
+ localStorage.removeItem(CACHE_KEY);
643
+ localStorage.removeItem(RELOAD_KEY);
644
+ } catch {
645
+ }
646
+ currentRunId.current = ++runIdRef.current;
647
+ const runId = currentRunId.current;
648
+ fetchFreshLink(runId);
737
649
  } catch (e) {
738
- setToast({ type: "error", message: (e instanceof Error ? e.message : "") || "Failed to save settings." });
739
- window.setTimeout(() => setToast(null), 3500);
650
+ console.error(e);
651
+ setConnState("error");
652
+ setError((e == null ? void 0 : e.message) || "Failed to disconnect.");
740
653
  } finally {
741
- setSaving(false);
654
+ setOnboardingInProgress(false);
742
655
  }
743
- }
744
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
745
- /* @__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" }) }) }),
746
- /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
747
- 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,
748
- /* @__PURE__ */ jsxRuntime.jsx(
749
- SectionCard$2,
750
- {
751
- title: "Advanced Card Payments",
752
- description: "Control card checkout settings and 3D Secure behavior.",
753
- right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
754
- /* @__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" }),
755
- loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-subtle", children: "Loading..." }) : null
756
- ] }),
757
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-ui-border-base", children: [
758
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { label: "Enable/Disable", children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "inline-flex items-center gap-2", children: [
759
- /* @__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" }),
760
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-ui-fg-base", children: "Enable Advanced Credit/Debit Card" })
761
- ] }) }),
762
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { 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" }) }),
763
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow$2, { 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: [
764
- /* @__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)) }),
765
- ((_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
766
- ] }) })
767
- ] })
768
- }
769
- )
770
- ] }) });
771
- }
772
- async function adminFetch$1(path, opts = {}) {
773
- var _a;
774
- const { method = "GET", body, query } = opts;
775
- let url = path;
776
- if (query && Object.keys(query).length > 0) {
777
- const params = new URLSearchParams(query);
778
- url = `${path}?${params.toString()}`;
779
- }
780
- const headers = { Accept: "application/json" };
781
- if (body !== void 0) headers["Content-Type"] = "application/json";
782
- if (typeof window !== "undefined") {
783
- const token = (_a = window.__medusa__) == null ? void 0 : _a.token;
784
- if (token) headers["Authorization"] = `Bearer ${token}`;
785
- }
786
- const res = await fetch(url, {
787
- method,
788
- headers,
789
- credentials: "include",
790
- body: body !== void 0 ? JSON.stringify(body) : void 0
791
- });
792
- const text = await res.text().catch(() => "");
793
- if (!res.ok) {
794
- if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.");
795
- if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.");
796
- throw new Error(text || `Request failed with status ${res.status}`);
797
- }
798
- if (!text) return {};
799
- try {
800
- return JSON.parse(text);
801
- } catch {
802
- return {};
803
- }
804
- }
805
- const DEFAULT_FORM = {
806
- paymentAction: "capture",
807
- brandName: "PayPal",
808
- landingPage: "no_preference",
809
- requireInstantPayment: false,
810
- sendItemDetails: true,
811
- invoicePrefix: "WC-",
812
- creditCardStatementName: "PayPal"
813
- };
814
- function mergeWithDefaults(saved) {
815
- if (!saved) return { ...DEFAULT_FORM };
816
- const entries = Object.entries(saved).filter(([, value]) => value !== void 0);
817
- return { ...DEFAULT_FORM, ...Object.fromEntries(entries) };
818
- }
819
- function SectionCard$1({ title, description, right, children }) {
820
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm", children: [
821
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base p-4", children: [
822
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
823
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-ui-fg-base", children: title }),
824
- description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-sm text-ui-fg-subtle", children: description }) : null
825
- ] }),
826
- right
827
- ] }),
828
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children })
829
- ] });
830
- }
831
- function FieldRow$1({ label, hint, children }) {
832
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-12 items-start gap-4 py-3", children: [
833
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-12 md:col-span-4", children: [
834
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-ui-fg-base", children: label }),
835
- hint ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: hint }) : null
656
+ };
657
+ const handleEnvChange = async (e) => {
658
+ const next = e.target.value;
659
+ setEnv(next);
660
+ cachedUrl = null;
661
+ try {
662
+ await fetch("/admin/paypal/environment", {
663
+ method: "POST",
664
+ headers: { "content-type": "application/json" },
665
+ body: JSON.stringify({ environment: next })
666
+ });
667
+ } catch {
668
+ }
669
+ try {
670
+ localStorage.removeItem(CACHE_KEY);
671
+ localStorage.removeItem(RELOAD_KEY);
672
+ } catch {
673
+ }
674
+ };
675
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6", children: [
676
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
677
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold", children: "PayPal Gateway By Easy Payment" }),
678
+ /* @__PURE__ */ jsxRuntime.jsx(PayPalTabs, {}),
679
+ /* @__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: [
680
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium pt-2", children: "Environment" }),
681
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xl", children: /* @__PURE__ */ jsxRuntime.jsxs(
682
+ "select",
683
+ {
684
+ value: env,
685
+ onChange: handleEnvChange,
686
+ disabled: onboardingInProgress,
687
+ className: "w-full rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm",
688
+ children: [
689
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "sandbox", children: "Sandbox (Test Mode)" }),
690
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "live", children: "Live (Production)" })
691
+ ]
692
+ }
693
+ ) }),
694
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium pt-2", children: env === "sandbox" ? "Connect to PayPal (Sandbox)" : "Connect to PayPal" }),
695
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-xl", children: connState === "connected" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
696
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-green-600 bg-green-50 p-3 rounded border border-green-200", children: [
697
+ "✅ Successfully connected to PayPal!",
698
+ /* @__PURE__ */ jsxRuntime.jsx(
699
+ "a",
700
+ {
701
+ "data-paypal-button": "true",
702
+ "data-paypal-onboard-complete": "onboardingCallback",
703
+ href: "#",
704
+ style: { display: "none" },
705
+ children: "PayPal"
706
+ }
707
+ )
708
+ ] }),
709
+ /* @__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: [
710
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-ui-fg-base", children: "Connected PayPal account" }),
711
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1", children: [
712
+ "Email:",
713
+ " ",
714
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-ui-fg-base", children: (statusInfo == null ? void 0 : statusInfo.seller_email) || "Unavailable" })
715
+ ] })
716
+ ] }),
717
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
718
+ "button",
719
+ {
720
+ type: "button",
721
+ onClick: handleDisconnect,
722
+ disabled: onboardingInProgress,
723
+ 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",
724
+ children: "Disconnect"
725
+ }
726
+ ) })
727
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
728
+ /* @__PURE__ */ jsxRuntime.jsxs(
729
+ "div",
730
+ {
731
+ ref: initLoaderRef,
732
+ id: "init-loader",
733
+ className: `status-msg mb-4 ${connState !== "loading" ? "hidden" : "block"}`,
734
+ children: [
735
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "loader inline-block align-middle mr-2" }),
736
+ /* @__PURE__ */ jsxRuntime.jsx("span", { id: "loader-text", className: "text-sm", children: onboardingInProgress ? "Configuring connection to PayPal…" : "Checking connection..." })
737
+ ]
738
+ }
739
+ ),
740
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${connState === "ready" ? "block" : "hidden"}`, children: [
741
+ /* @__PURE__ */ jsxRuntime.jsx(
742
+ "a",
743
+ {
744
+ ref: (node) => {
745
+ paypalButtonRef.current = node;
746
+ ppBtnMeasureRef.current = node;
747
+ },
748
+ id: "paypal-button",
749
+ "data-paypal-button": "true",
750
+ href: finalUrl || "#",
751
+ "data-paypal-onboard-complete": "onboardingCallback",
752
+ onClick: handleConnectClick,
753
+ 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",
754
+ style: {
755
+ cursor: onboardingInProgress ? "not-allowed" : "pointer",
756
+ opacity: onboardingInProgress ? 0.6 : 1,
757
+ pointerEvents: onboardingInProgress ? "none" : "auto"
758
+ },
759
+ children: "Connect to PayPal"
760
+ }
761
+ ),
762
+ /* @__PURE__ */ jsxRuntime.jsx(
763
+ "div",
764
+ {
765
+ className: "mt-2",
766
+ style: {
767
+ width: ppBtnWidth ? `${ppBtnWidth}px` : "auto",
768
+ marginTop: "20px",
769
+ marginBottom: "10px"
770
+ },
771
+ 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" }) })
772
+ }
773
+ ),
774
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsxRuntime.jsx(
775
+ "button",
776
+ {
777
+ type: "button",
778
+ onClick: () => setShowManual(!showManual),
779
+ disabled: onboardingInProgress,
780
+ className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
781
+ children: "Click here to insert credentials manually"
782
+ }
783
+ ) })
784
+ ] }),
785
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${connState === "ready" ? "hidden" : "block"} mt-3`, children: /* @__PURE__ */ jsxRuntime.jsx(
786
+ "button",
787
+ {
788
+ type: "button",
789
+ onClick: () => setShowManual(!showManual),
790
+ disabled: onboardingInProgress,
791
+ className: "text-sm text-ui-fg-interactive underline whitespace-nowrap disabled:opacity-50 disabled:cursor-not-allowed",
792
+ children: "Click here to insert credentials manually"
793
+ }
794
+ ) }),
795
+ /* @__PURE__ */ jsxRuntime.jsx(
796
+ "div",
797
+ {
798
+ ref: errorLogRef,
799
+ id: "error-log",
800
+ 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"}`,
801
+ children: error
802
+ }
803
+ )
804
+ ] }) }),
805
+ 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: [
806
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
807
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Client ID" }),
808
+ /* @__PURE__ */ jsxRuntime.jsx(
809
+ "input",
810
+ {
811
+ type: "text",
812
+ value: clientId,
813
+ onChange: (e) => setClientId(e.target.value),
814
+ disabled: onboardingInProgress,
815
+ className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
816
+ placeholder: env === "sandbox" ? "Sandbox Client ID" : "Live Client ID"
817
+ }
818
+ )
819
+ ] }),
820
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
821
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Secret" }),
822
+ /* @__PURE__ */ jsxRuntime.jsx(
823
+ "input",
824
+ {
825
+ type: "password",
826
+ value: secret,
827
+ onChange: (e) => setSecret(e.target.value),
828
+ disabled: onboardingInProgress,
829
+ className: "rounded-md border border-ui-border-base bg-transparent px-3 py-2 text-sm disabled:opacity-50",
830
+ placeholder: env === "sandbox" ? "Sandbox Secret" : "Live Secret"
831
+ }
832
+ )
833
+ ] }),
834
+ /* @__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: [
835
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium text-ui-fg-base", children: "Get your Client ID and Secret in 3 steps:" }),
836
+ /* @__PURE__ */ jsxRuntime.jsxs("ol", { className: "mt-2 list-decimal space-y-2 pl-5", children: [
837
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
838
+ "Open",
839
+ " ",
840
+ /* @__PURE__ */ jsxRuntime.jsx(
841
+ "a",
842
+ {
843
+ href: "https://developer.paypal.com/dashboard/",
844
+ target: "_blank",
845
+ rel: "noreferrer",
846
+ className: "text-ui-fg-interactive underline",
847
+ children: "Log in to Dashboard"
848
+ }
849
+ ),
850
+ " ",
851
+ "and sign in or create an account."
852
+ ] }),
853
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
854
+ "Select ",
855
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-ui-fg-base", children: "Apps & Credentials" }),
856
+ ", then choose ",
857
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-ui-fg-base", children: "Create App" }),
858
+ " if you need a new project."
859
+ ] }),
860
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
861
+ "Copy your app's ",
862
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-ui-fg-base", children: "Client ID" }),
863
+ " and ",
864
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-ui-fg-base", children: "Secret" }),
865
+ ", paste them above, then click ",
866
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-ui-fg-base", children: "Save credentials" }),
867
+ "."
868
+ ] })
869
+ ] })
870
+ ] }),
871
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:col-span-2 flex items-center gap-2 mt-2", children: [
872
+ /* @__PURE__ */ jsxRuntime.jsx(
873
+ "button",
874
+ {
875
+ type: "button",
876
+ 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",
877
+ onClick: () => setShowManual(false),
878
+ disabled: onboardingInProgress,
879
+ children: "Cancel"
880
+ }
881
+ ),
882
+ /* @__PURE__ */ jsxRuntime.jsx(
883
+ "button",
884
+ {
885
+ type: "button",
886
+ 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",
887
+ disabled: !canSaveManual || onboardingInProgress,
888
+ onClick: handleSaveManual,
889
+ children: "Save credentials"
890
+ }
891
+ )
892
+ ] })
893
+ ] }) })
894
+ ] }) })
836
895
  ] }),
837
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-12 md:col-span-8", children })
896
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
897
+ .loader {
898
+ border: 3px solid #f3f3f3;
899
+ border-top: 3px solid #0070ba;
900
+ border-radius: 50%;
901
+ width: 18px;
902
+ height: 18px;
903
+ animation: spin 1s linear infinite;
904
+ display: inline-block;
905
+ vertical-align: middle;
906
+ margin-right: 8px;
907
+ }
908
+ @keyframes spin {
909
+ 0% { transform: rotate(0deg); }
910
+ 100% { transform: rotate(360deg); }
911
+ }
912
+ ` })
838
913
  ] });
839
914
  }
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
- function PayPalGooglePayPage() {
915
+ function PayPalApplePayPage() {
919
916
  return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
920
917
  }
921
- function PayPalPayLaterMessagingPage() {
918
+ function PayPalGooglePayPage() {
922
919
  return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
923
920
  }
924
921
  async function adminFetch(path, opts = {}) {
@@ -1194,6 +1191,9 @@ function PayPalSettingsTab() {
1194
1191
  )
1195
1192
  ] }) });
1196
1193
  }
1194
+ function PayPalPayLaterMessagingPage() {
1195
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
1196
+ }
1197
1197
  const widgetModule = { widgets: [] };
1198
1198
  const routeModule = {
1199
1199
  routes: [
@@ -1202,32 +1202,32 @@ const routeModule = {
1202
1202
  path: "/settings/paypal"
1203
1203
  },
1204
1204
  {
1205
- Component: PayPalApplePayPage,
1206
- path: "/settings/paypal/apple-pay"
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: AdditionalSettingsTab,
1218
- path: "/settings/paypal/additional-settings"
1213
+ Component: PayPalConnectionPage,
1214
+ path: "/settings/paypal/connection"
1219
1215
  },
1220
1216
  {
1221
- Component: PayPalGooglePayPage,
1222
- path: "/settings/paypal/google-pay"
1217
+ Component: PayPalApplePayPage,
1218
+ path: "/settings/paypal/apple-pay"
1223
1219
  },
1224
1220
  {
1225
- Component: PayPalPayLaterMessagingPage,
1226
- path: "/settings/paypal/pay-later-messaging"
1221
+ Component: PayPalGooglePayPage,
1222
+ path: "/settings/paypal/google-pay"
1227
1223
  },
1228
1224
  {
1229
1225
  Component: PayPalSettingsTab,
1230
1226
  path: "/settings/paypal/paypal-settings"
1227
+ },
1228
+ {
1229
+ Component: PayPalPayLaterMessagingPage,
1230
+ path: "/settings/paypal/pay-later-messaging"
1231
1231
  }
1232
1232
  ]
1233
1233
  };