@doujins/payments-ui 0.0.15 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1008 -2320
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +248 -346
- package/dist/index.d.ts +248 -346
- package/dist/index.js +872 -2166
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2 -1
- package/package.json +9 -4
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React17 = require('react');
|
|
4
4
|
var reactQuery = require('@tanstack/react-query');
|
|
5
5
|
var walletAdapterReact = require('@solana/wallet-adapter-react');
|
|
6
6
|
var walletAdapterReactUi = require('@solana/wallet-adapter-react-ui');
|
|
7
7
|
require('@solana/wallet-adapter-react-ui/styles.css');
|
|
8
|
+
var walletAdapterBase = require('@solana/wallet-adapter-base');
|
|
8
9
|
var web3_js = require('@solana/web3.js');
|
|
9
10
|
var walletAdapterPhantom = require('@solana/wallet-adapter-phantom');
|
|
10
11
|
var walletAdapterSolflare = require('@solana/wallet-adapter-solflare');
|
|
@@ -16,17 +17,16 @@ var clsx = require('clsx');
|
|
|
16
17
|
var tailwindMerge = require('tailwind-merge');
|
|
17
18
|
var jsxRuntime = require('react/jsx-runtime');
|
|
18
19
|
var countryList = require('country-list');
|
|
20
|
+
var reactSlot = require('@radix-ui/react-slot');
|
|
19
21
|
var classVarianceAuthority = require('class-variance-authority');
|
|
20
22
|
var LabelPrimitive = require('@radix-ui/react-label');
|
|
21
23
|
var SelectPrimitive = require('@radix-ui/react-select');
|
|
22
24
|
var ScrollAreaPrimitive = require('@radix-ui/react-scroll-area');
|
|
23
25
|
var TabsPrimitive = require('@radix-ui/react-tabs');
|
|
24
|
-
var buffer = require('buffer');
|
|
25
|
-
var splToken = require('@solana/spl-token');
|
|
26
26
|
var QRCode = require('qrcode');
|
|
27
27
|
var AlertDialogPrimitive = require('@radix-ui/react-alert-dialog');
|
|
28
|
-
var bs58 = require('bs58');
|
|
29
28
|
var CheckboxPrimitive = require('@radix-ui/react-checkbox');
|
|
29
|
+
var splToken = require('@solana/spl-token');
|
|
30
30
|
|
|
31
31
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
32
32
|
|
|
@@ -48,7 +48,7 @@ function _interopNamespace(e) {
|
|
|
48
48
|
return Object.freeze(n);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
var
|
|
51
|
+
var React17__namespace = /*#__PURE__*/_interopNamespace(React17);
|
|
52
52
|
var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
|
|
53
53
|
var countryList__default = /*#__PURE__*/_interopDefault(countryList);
|
|
54
54
|
var LabelPrimitive__namespace = /*#__PURE__*/_interopNamespace(LabelPrimitive);
|
|
@@ -57,7 +57,6 @@ var ScrollAreaPrimitive__namespace = /*#__PURE__*/_interopNamespace(ScrollAreaPr
|
|
|
57
57
|
var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
|
|
58
58
|
var QRCode__default = /*#__PURE__*/_interopDefault(QRCode);
|
|
59
59
|
var AlertDialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(AlertDialogPrimitive);
|
|
60
|
-
var bs58__default = /*#__PURE__*/_interopDefault(bs58);
|
|
61
60
|
var CheckboxPrimitive__namespace = /*#__PURE__*/_interopNamespace(CheckboxPrimitive);
|
|
62
61
|
|
|
63
62
|
// src/context/PaymentContext.tsx
|
|
@@ -90,531 +89,297 @@ var loadCollectJs = (tokenizationKey) => {
|
|
|
90
89
|
document.head.appendChild(script);
|
|
91
90
|
};
|
|
92
91
|
|
|
93
|
-
// src/
|
|
94
|
-
var
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
92
|
+
// src/lib/client.ts
|
|
93
|
+
var ClientApiError = class extends Error {
|
|
94
|
+
constructor(message, status, body, request) {
|
|
95
|
+
super(message);
|
|
96
|
+
this.name = "ClientApiError";
|
|
97
|
+
this.status = status;
|
|
98
|
+
this.body = body;
|
|
99
|
+
this.request = request;
|
|
100
100
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
});
|
|
107
|
-
if ([...queryString.keys()].length > 0) {
|
|
108
|
-
resolved = `${resolved}?${queryString.toString()}`;
|
|
109
|
-
}
|
|
101
|
+
};
|
|
102
|
+
var ensureFetch = (fetchImpl) => {
|
|
103
|
+
if (fetchImpl) return fetchImpl;
|
|
104
|
+
if (typeof globalThis.fetch === "function") {
|
|
105
|
+
return globalThis.fetch.bind(globalThis);
|
|
110
106
|
}
|
|
111
|
-
|
|
107
|
+
throw new Error("payments-ui: global fetch is not available");
|
|
112
108
|
};
|
|
113
|
-
var
|
|
109
|
+
var createClient = (config) => {
|
|
110
|
+
const fetchImpl = ensureFetch(config.fetch);
|
|
111
|
+
const normalizeBase = (value) => value.replace(/\/$/, "");
|
|
112
|
+
const normalizePath = (value, fallback = "/v1") => {
|
|
113
|
+
if (!value) return fallback;
|
|
114
|
+
return value.startsWith("/") ? value : `/${value}`;
|
|
115
|
+
};
|
|
116
|
+
const billingBaseUrl = normalizeBase(config.billingBaseUrl);
|
|
117
|
+
const accountBaseUrl = normalizeBase(
|
|
118
|
+
config.accountBaseUrl ?? config.billingBaseUrl
|
|
119
|
+
);
|
|
120
|
+
const billingBasePath = normalizePath(config.billingBasePath ?? "/v1");
|
|
121
|
+
const accountBasePath = normalizePath(
|
|
122
|
+
config.accountBasePath ?? config.billingBasePath ?? "/v1"
|
|
123
|
+
);
|
|
124
|
+
const defaultHeaders = config.defaultHeaders ?? {};
|
|
125
|
+
const resolveAuthToken = async () => {
|
|
126
|
+
if (!config.getAuthToken) return null;
|
|
127
|
+
try {
|
|
128
|
+
const result = config.getAuthToken();
|
|
129
|
+
return result instanceof Promise ? await result : result;
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.warn("payments-ui: failed to resolve auth token", error);
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const buildUrl = (path, query, target) => {
|
|
136
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
137
|
+
const basePath = target === "account" ? accountBasePath : billingBasePath;
|
|
138
|
+
const baseUrl = target === "account" ? accountBaseUrl : billingBaseUrl;
|
|
139
|
+
const needsBasePrefix = !normalizedPath.startsWith(basePath);
|
|
140
|
+
const finalPath = needsBasePrefix ? `${basePath}${normalizedPath}` : normalizedPath;
|
|
141
|
+
const url = new URL(`${baseUrl}${finalPath}`);
|
|
142
|
+
if (query) {
|
|
143
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
144
|
+
if (value === void 0 || value === null) return;
|
|
145
|
+
url.searchParams.append(key, String(value));
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return url.toString();
|
|
149
|
+
};
|
|
114
150
|
const request = async (method, path, options) => {
|
|
115
|
-
const
|
|
151
|
+
const target = options?.target ?? "billing";
|
|
152
|
+
const url = buildUrl(path, options?.query, target);
|
|
116
153
|
const headers = {
|
|
117
154
|
"Content-Type": "application/json",
|
|
118
|
-
...
|
|
155
|
+
...defaultHeaders,
|
|
119
156
|
...options?.headers ?? {}
|
|
120
157
|
};
|
|
121
158
|
const token = await resolveAuthToken();
|
|
122
159
|
if (token) {
|
|
123
160
|
headers.Authorization = `Bearer ${token}`;
|
|
124
161
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
130
|
-
});
|
|
131
|
-
if (!response.ok) {
|
|
132
|
-
const message = await response.text();
|
|
133
|
-
console.error("payments-ui: API request failed", {
|
|
134
|
-
url,
|
|
135
|
-
method,
|
|
136
|
-
status: response.status,
|
|
137
|
-
message
|
|
138
|
-
});
|
|
139
|
-
throw new Error(message || `Request failed with status ${response.status}`);
|
|
140
|
-
}
|
|
141
|
-
if (response.status === 204) {
|
|
142
|
-
return void 0;
|
|
143
|
-
}
|
|
144
|
-
const data = await response.json();
|
|
145
|
-
return data;
|
|
146
|
-
} catch (error) {
|
|
147
|
-
console.error("payments-ui: API request error", { url, method, error });
|
|
148
|
-
throw error;
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
return {
|
|
152
|
-
request,
|
|
153
|
-
get: (path, options) => request("GET", path, options),
|
|
154
|
-
post: (path, options) => request("POST", path, options),
|
|
155
|
-
put: (path, options) => request("PUT", path, options),
|
|
156
|
-
patch: (path, options) => request("PATCH", path, options),
|
|
157
|
-
delete: (path, options) => request("DELETE", path, options)
|
|
158
|
-
};
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
// src/services/CardPaymentService.ts
|
|
162
|
-
var CardPaymentService = class {
|
|
163
|
-
constructor(config) {
|
|
164
|
-
this.config = config;
|
|
165
|
-
this.collectLoaded = false;
|
|
166
|
-
}
|
|
167
|
-
async ensureCollectLoaded() {
|
|
168
|
-
if (this.collectLoaded) return;
|
|
169
|
-
if (!this.config.collectJsKey) {
|
|
170
|
-
throw new Error("payments-ui: collect.js key missing");
|
|
171
|
-
}
|
|
172
|
-
loadCollectJs(this.config.collectJsKey);
|
|
173
|
-
this.collectLoaded = true;
|
|
174
|
-
}
|
|
175
|
-
buildCreatePayload(result) {
|
|
176
|
-
return {
|
|
177
|
-
payment_token: result.token,
|
|
178
|
-
first_name: result.billing.firstName,
|
|
179
|
-
last_name: result.billing.lastName,
|
|
180
|
-
address1: result.billing.address1,
|
|
181
|
-
address2: result.billing.address2,
|
|
182
|
-
city: result.billing.city,
|
|
183
|
-
state: result.billing.stateRegion,
|
|
184
|
-
zip: result.billing.postalCode,
|
|
185
|
-
country: result.billing.country,
|
|
186
|
-
email: result.billing.email,
|
|
187
|
-
provider: result.billing.provider
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
// src/services/PaymentMethodService.ts
|
|
193
|
-
var PaymentMethodService = class {
|
|
194
|
-
constructor(api) {
|
|
195
|
-
this.api = api;
|
|
196
|
-
}
|
|
197
|
-
async list(params) {
|
|
198
|
-
return this.api.get("/payment-methods", {
|
|
199
|
-
query: {
|
|
200
|
-
page: params?.page ?? 1,
|
|
201
|
-
page_size: params?.pageSize ?? 50
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
async create(payload) {
|
|
206
|
-
return this.api.post("/payment-methods", {
|
|
207
|
-
body: { ...payload }
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
async remove(id) {
|
|
211
|
-
await this.api.delete(`/payment-methods/${id}`);
|
|
212
|
-
}
|
|
213
|
-
async activate(id) {
|
|
214
|
-
await this.api.put(`/payment-methods/${id}/activate`);
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
// src/services/SolanaPaymentService.ts
|
|
219
|
-
var SolanaPaymentService = class {
|
|
220
|
-
constructor(api) {
|
|
221
|
-
this.api = api;
|
|
222
|
-
}
|
|
223
|
-
async generatePayment(priceId, token, userWallet) {
|
|
224
|
-
return this.api.post("/solana/generate", {
|
|
225
|
-
body: { price_id: priceId, token, user_wallet: userWallet }
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
async submitPayment(signedTransaction, priceId, intentId, memo) {
|
|
229
|
-
return this.api.post("/solana/submit", {
|
|
230
|
-
body: {
|
|
231
|
-
signed_transaction: signedTransaction,
|
|
232
|
-
price_id: priceId,
|
|
233
|
-
intent_id: intentId,
|
|
234
|
-
...memo ? { memo } : {}
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
async fetchSupportedTokens() {
|
|
239
|
-
const response = await this.api.get(
|
|
240
|
-
"/solana/tokens"
|
|
241
|
-
);
|
|
242
|
-
return response.tokens;
|
|
243
|
-
}
|
|
244
|
-
async getSupportedTokens() {
|
|
245
|
-
return this.fetchSupportedTokens();
|
|
246
|
-
}
|
|
247
|
-
async generateQrCode(priceId, token, userWallet) {
|
|
248
|
-
return this.api.post("/solana/qr", {
|
|
249
|
-
body: {
|
|
250
|
-
price_id: priceId,
|
|
251
|
-
token,
|
|
252
|
-
...userWallet ? { user_wallet: userWallet } : {}
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
async generateQRCode(priceId, token, userWallet) {
|
|
257
|
-
return this.generateQrCode(priceId, token, userWallet);
|
|
258
|
-
}
|
|
259
|
-
async checkPaymentStatus(reference, memo) {
|
|
260
|
-
return this.api.get("/solana/check", {
|
|
261
|
-
query: {
|
|
262
|
-
reference,
|
|
263
|
-
...memo ? { memo } : {}
|
|
264
|
-
}
|
|
162
|
+
const response = await fetchImpl(url, {
|
|
163
|
+
method,
|
|
164
|
+
headers,
|
|
165
|
+
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
265
166
|
});
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
async getTokens(force = false) {
|
|
281
|
-
const isStale = Date.now() - this.lastFetched > this.ttl;
|
|
282
|
-
if (!force && this.cache.length > 0 && !isStale) {
|
|
283
|
-
return this.cache;
|
|
284
|
-
}
|
|
285
|
-
const tokens = await this.solanaService.fetchSupportedTokens();
|
|
286
|
-
this.cache = tokens;
|
|
287
|
-
this.lastFetched = Date.now();
|
|
288
|
-
return tokens;
|
|
289
|
-
}
|
|
290
|
-
getCached() {
|
|
291
|
-
return this.cache;
|
|
292
|
-
}
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
// src/services/WalletGateway.ts
|
|
296
|
-
var WalletGateway = class {
|
|
297
|
-
constructor() {
|
|
298
|
-
this.adapter = null;
|
|
299
|
-
}
|
|
300
|
-
setAdapter(adapter) {
|
|
301
|
-
this.adapter = adapter;
|
|
302
|
-
}
|
|
303
|
-
getPublicKey() {
|
|
304
|
-
if (!this.adapter?.publicKey) return null;
|
|
305
|
-
try {
|
|
306
|
-
return this.adapter.publicKey.toBase58();
|
|
307
|
-
} catch {
|
|
308
|
-
return null;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
async sign(transaction) {
|
|
312
|
-
if (!this.adapter) {
|
|
313
|
-
throw new Error("payments-ui: wallet adapter not set");
|
|
314
|
-
}
|
|
315
|
-
if (typeof this.adapter.signVersionedTransaction === "function") {
|
|
316
|
-
return this.adapter.signVersionedTransaction(transaction);
|
|
167
|
+
if (!response.ok) {
|
|
168
|
+
let payload = null;
|
|
169
|
+
try {
|
|
170
|
+
payload = await response.json();
|
|
171
|
+
} catch {
|
|
172
|
+
payload = await response.text();
|
|
173
|
+
}
|
|
174
|
+
throw new ClientApiError(
|
|
175
|
+
payload && typeof payload === "object" && "message" in payload ? String(payload.message) : response.statusText || "Request failed",
|
|
176
|
+
response.status,
|
|
177
|
+
payload,
|
|
178
|
+
{ method, url }
|
|
179
|
+
);
|
|
317
180
|
}
|
|
318
|
-
if (
|
|
319
|
-
return
|
|
181
|
+
if (response.status === 204) {
|
|
182
|
+
return void 0;
|
|
320
183
|
}
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
184
|
+
return await response.json();
|
|
185
|
+
};
|
|
186
|
+
const normalizeList = (payload) => {
|
|
187
|
+
const data = payload.data ?? [];
|
|
188
|
+
const total = payload.total ?? payload.total_items ?? data.length;
|
|
189
|
+
const limit = payload.limit ?? data.length;
|
|
190
|
+
const offset = payload.offset ?? 0;
|
|
191
|
+
const hasMore = typeof payload.has_more === "boolean" ? payload.has_more : offset + data.length < total;
|
|
192
|
+
return { data, total, limit, offset, hasMore };
|
|
193
|
+
};
|
|
194
|
+
return {
|
|
195
|
+
async listPaymentMethods(params) {
|
|
196
|
+
const result = await request(
|
|
197
|
+
"GET",
|
|
198
|
+
"/me/payment-methods",
|
|
199
|
+
{
|
|
200
|
+
query: {
|
|
201
|
+
limit: params?.limit,
|
|
202
|
+
offset: params?.offset,
|
|
203
|
+
include_inactive: params?.includeInactive
|
|
204
|
+
},
|
|
205
|
+
target: "account"
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
return normalizeList(result);
|
|
209
|
+
},
|
|
210
|
+
createPaymentMethod(payload) {
|
|
211
|
+
return request("POST", "/me/payment-methods", {
|
|
212
|
+
body: payload,
|
|
213
|
+
target: "account"
|
|
214
|
+
});
|
|
215
|
+
},
|
|
216
|
+
updatePaymentMethod(id, payload) {
|
|
217
|
+
return request("PUT", `/me/payment-methods/${id}`, {
|
|
218
|
+
body: payload,
|
|
219
|
+
target: "account"
|
|
220
|
+
});
|
|
221
|
+
},
|
|
222
|
+
deletePaymentMethod(id) {
|
|
223
|
+
return request("DELETE", `/me/payment-methods/${id}`, {
|
|
224
|
+
target: "account"
|
|
225
|
+
});
|
|
226
|
+
},
|
|
227
|
+
activatePaymentMethod(id) {
|
|
228
|
+
return request("PUT", `/me/payment-methods/${id}/activate`, {
|
|
229
|
+
target: "account"
|
|
230
|
+
});
|
|
231
|
+
},
|
|
232
|
+
checkout(payload) {
|
|
233
|
+
return request("POST", "/me/checkout", {
|
|
234
|
+
body: payload
|
|
235
|
+
});
|
|
236
|
+
},
|
|
237
|
+
cancelSubscription(feedback) {
|
|
238
|
+
return request("POST", "/me/subscriptions/cancel", {
|
|
239
|
+
body: feedback ? { feedback } : void 0
|
|
240
|
+
});
|
|
241
|
+
},
|
|
242
|
+
async getPaymentHistory(params) {
|
|
243
|
+
const result = await request("GET", "/me/payments", {
|
|
244
|
+
query: {
|
|
245
|
+
limit: params?.limit,
|
|
246
|
+
offset: params?.offset,
|
|
247
|
+
type: params?.type
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
return normalizeList(result);
|
|
251
|
+
},
|
|
252
|
+
async getSolanaTokens() {
|
|
253
|
+
const response = await request(
|
|
254
|
+
"GET",
|
|
255
|
+
"/solana/tokens"
|
|
256
|
+
);
|
|
257
|
+
if (Array.isArray(response)) {
|
|
258
|
+
return response;
|
|
336
259
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
return {
|
|
362
|
-
data: response?.data ?? [],
|
|
363
|
-
total_items: totalItems,
|
|
364
|
-
limit,
|
|
365
|
-
offset,
|
|
366
|
-
page: pageNumber,
|
|
367
|
-
page_size: pageSize,
|
|
368
|
-
total_pages: totalPages
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
async cancelSubscription(feedback) {
|
|
372
|
-
return this.api.post("/subscriptions/cancel", {
|
|
373
|
-
body: feedback ? { feedback } : void 0
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
serializePayload(platform, payload) {
|
|
377
|
-
if (platform === "nmi") {
|
|
378
|
-
const data2 = payload;
|
|
379
|
-
if (!data2.priceId) {
|
|
380
|
-
throw new Error("payments-ui: priceId is required for NMI subscriptions");
|
|
260
|
+
return response.tokens ?? [];
|
|
261
|
+
},
|
|
262
|
+
async createSolanaPayIntent(payload) {
|
|
263
|
+
const response = await request("POST", "/solana/pay", {
|
|
264
|
+
body: {
|
|
265
|
+
price_id: payload.priceId,
|
|
266
|
+
token: payload.token,
|
|
267
|
+
...payload.userWallet ? { user_wallet: payload.userWallet } : {}
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
return response;
|
|
271
|
+
},
|
|
272
|
+
async getSolanaPayStatus(reference) {
|
|
273
|
+
const response = await request(
|
|
274
|
+
"GET",
|
|
275
|
+
`/solana/pay/${reference}`
|
|
276
|
+
);
|
|
277
|
+
if (response.status === "confirmed") {
|
|
278
|
+
return {
|
|
279
|
+
status: "confirmed",
|
|
280
|
+
payment_id: response.payment_id ?? "",
|
|
281
|
+
transaction: response.signature ?? null,
|
|
282
|
+
intent_id: response.intent_id
|
|
283
|
+
};
|
|
381
284
|
}
|
|
382
|
-
if (
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
285
|
+
if (response.status === "expired") {
|
|
286
|
+
return {
|
|
287
|
+
status: "failed",
|
|
288
|
+
payment_id: response.payment_id ?? "",
|
|
289
|
+
transaction: response.signature ?? null,
|
|
290
|
+
intent_id: response.intent_id,
|
|
291
|
+
error_message: "Payment intent expired"
|
|
292
|
+
};
|
|
386
293
|
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
294
|
+
return {
|
|
295
|
+
status: "pending",
|
|
296
|
+
payment_id: response.payment_id ?? "",
|
|
297
|
+
transaction: response.signature ?? null,
|
|
298
|
+
intent_id: response.intent_id
|
|
391
299
|
};
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
if (data2.lastName) body.last_name = data2.lastName;
|
|
395
|
-
if (data2.address1) body.address1 = data2.address1;
|
|
396
|
-
if (data2.city) body.city = data2.city;
|
|
397
|
-
if (data2.state) body.state = data2.state;
|
|
398
|
-
if (data2.zipCode) body.zip = data2.zipCode;
|
|
399
|
-
if (data2.country) body.country = data2.country;
|
|
400
|
-
if (data2.paymentToken) body.payment_token = data2.paymentToken;
|
|
401
|
-
if (data2.paymentMethodId) body.payment_method_id = data2.paymentMethodId;
|
|
402
|
-
return body;
|
|
403
|
-
}
|
|
404
|
-
const data = payload;
|
|
405
|
-
if (!data.priceId) {
|
|
406
|
-
throw new Error("payments-ui: priceId is required for CCBill subscriptions");
|
|
407
|
-
}
|
|
408
|
-
return {
|
|
409
|
-
price_id: data.priceId,
|
|
410
|
-
processor: data.processor ?? "ccbill",
|
|
411
|
-
email: data.email,
|
|
412
|
-
first_name: data.firstName,
|
|
413
|
-
last_name: data.lastName,
|
|
414
|
-
zip: data.zipCode,
|
|
415
|
-
country: data.country
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
};
|
|
419
|
-
|
|
420
|
-
// src/services/SolanaWalletService.ts
|
|
421
|
-
var SolanaWalletService = class {
|
|
422
|
-
constructor(api) {
|
|
423
|
-
this.api = api;
|
|
424
|
-
}
|
|
425
|
-
async list() {
|
|
426
|
-
const response = await this.api.get(
|
|
427
|
-
"/wallet/solana"
|
|
428
|
-
);
|
|
429
|
-
if (Array.isArray(response)) {
|
|
430
|
-
return response;
|
|
431
|
-
}
|
|
432
|
-
if ("wallets" in response && Array.isArray(response.wallets)) {
|
|
433
|
-
return response.wallets;
|
|
434
|
-
}
|
|
435
|
-
if ("wallet" in response) {
|
|
436
|
-
return response.wallet ? [response.wallet] : [];
|
|
437
|
-
}
|
|
438
|
-
if ("address" in response) {
|
|
439
|
-
return [response];
|
|
440
|
-
}
|
|
441
|
-
return [];
|
|
442
|
-
}
|
|
443
|
-
async requestChallenge(wallet) {
|
|
444
|
-
return this.api.post("/wallet/solana/challenge", {
|
|
445
|
-
body: { wallet }
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
async verify(wallet, signature, nonce) {
|
|
449
|
-
const body = { wallet, signature };
|
|
450
|
-
if (nonce) {
|
|
451
|
-
body.nonce = nonce;
|
|
452
|
-
}
|
|
453
|
-
return this.api.post("/wallet/solana/verify", { body });
|
|
454
|
-
}
|
|
455
|
-
async remove(wallet) {
|
|
456
|
-
await this.api.delete("/wallet/solana", {
|
|
457
|
-
query: { wallet }
|
|
458
|
-
});
|
|
459
|
-
}
|
|
460
|
-
};
|
|
461
|
-
|
|
462
|
-
// src/core/PaymentApp.ts
|
|
463
|
-
var PaymentApp = class {
|
|
464
|
-
constructor(options) {
|
|
465
|
-
this.resolveAuthToken = async () => {
|
|
466
|
-
if (!this.config.getAuthToken) {
|
|
467
|
-
return null;
|
|
468
|
-
}
|
|
300
|
+
},
|
|
301
|
+
async getPaymentStatus(id) {
|
|
469
302
|
try {
|
|
470
|
-
|
|
471
|
-
if (result instanceof Promise) {
|
|
472
|
-
return await result ?? null;
|
|
473
|
-
}
|
|
474
|
-
return result ?? null;
|
|
303
|
+
return await request("GET", `/payment/status/${id}`);
|
|
475
304
|
} catch (error) {
|
|
476
|
-
|
|
477
|
-
|
|
305
|
+
if (error instanceof ClientApiError && error.status === 404) {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
throw error;
|
|
478
309
|
}
|
|
479
|
-
};
|
|
480
|
-
this.config = options.config;
|
|
481
|
-
this.fetcher = options.fetcher ?? options.config.fetcher ?? globalThis.fetch?.bind(globalThis);
|
|
482
|
-
if (!this.fetcher) {
|
|
483
|
-
throw new Error("payments-ui: fetch implementation is required");
|
|
484
|
-
}
|
|
485
|
-
this.services = this.createServices();
|
|
486
|
-
}
|
|
487
|
-
getConfig() {
|
|
488
|
-
return this.config;
|
|
489
|
-
}
|
|
490
|
-
getFetcher() {
|
|
491
|
-
return this.fetcher;
|
|
492
|
-
}
|
|
493
|
-
getServices() {
|
|
494
|
-
return this.services;
|
|
495
|
-
}
|
|
496
|
-
createServices() {
|
|
497
|
-
const billingApi = createApiClient(
|
|
498
|
-
this.config,
|
|
499
|
-
this.config.endpoints.billingBaseUrl,
|
|
500
|
-
this.fetcher,
|
|
501
|
-
this.resolveAuthToken
|
|
502
|
-
);
|
|
503
|
-
const accountBaseUrl = this.config.endpoints.accountBaseUrl ?? this.config.endpoints.billingBaseUrl;
|
|
504
|
-
const accountApi = createApiClient(
|
|
505
|
-
this.config,
|
|
506
|
-
accountBaseUrl,
|
|
507
|
-
this.fetcher,
|
|
508
|
-
this.resolveAuthToken
|
|
509
|
-
);
|
|
510
|
-
const solanaPayments = new SolanaPaymentService(billingApi);
|
|
511
|
-
const solanaWallets = new SolanaWalletService(billingApi);
|
|
512
|
-
const paymentMethods = new PaymentMethodService(accountApi);
|
|
513
|
-
const cardPayments = new CardPaymentService(this.config);
|
|
514
|
-
const walletGateway = new WalletGateway();
|
|
515
|
-
const tokenCatalog = new TokenCatalog(solanaPayments);
|
|
516
|
-
const subscriptions = new SubscriptionService(billingApi);
|
|
517
|
-
return {
|
|
518
|
-
cardPayments,
|
|
519
|
-
paymentMethods,
|
|
520
|
-
solanaPayments,
|
|
521
|
-
solanaWallets,
|
|
522
|
-
tokenCatalog,
|
|
523
|
-
walletGateway,
|
|
524
|
-
subscriptions,
|
|
525
|
-
billingApi,
|
|
526
|
-
accountApi
|
|
527
|
-
};
|
|
528
|
-
}
|
|
529
|
-
};
|
|
530
|
-
|
|
531
|
-
// src/runtime/PaymentsRuntime.ts
|
|
532
|
-
var createQueryClient = () => new reactQuery.QueryClient({
|
|
533
|
-
defaultOptions: {
|
|
534
|
-
queries: {
|
|
535
|
-
staleTime: 3e4,
|
|
536
|
-
gcTime: 5 * 6e4,
|
|
537
|
-
refetchOnWindowFocus: false,
|
|
538
|
-
retry: 1
|
|
539
|
-
},
|
|
540
|
-
mutations: {
|
|
541
|
-
retry: 1
|
|
542
310
|
}
|
|
543
|
-
}
|
|
544
|
-
});
|
|
545
|
-
var PaymentsRuntime = class {
|
|
546
|
-
constructor(config) {
|
|
547
|
-
this.config = config;
|
|
548
|
-
this.app = new PaymentApp({ config });
|
|
549
|
-
this.services = this.app.getServices();
|
|
550
|
-
this.queryClient = createQueryClient();
|
|
551
|
-
}
|
|
311
|
+
};
|
|
552
312
|
};
|
|
553
|
-
var createPaymentsRuntime = (config) => new PaymentsRuntime(config);
|
|
554
|
-
|
|
555
|
-
// node_modules/@solana/wallet-adapter-base/lib/esm/types.js
|
|
556
|
-
var WalletAdapterNetwork;
|
|
557
|
-
(function(WalletAdapterNetwork2) {
|
|
558
|
-
WalletAdapterNetwork2["Mainnet"] = "mainnet-beta";
|
|
559
|
-
WalletAdapterNetwork2["Testnet"] = "testnet";
|
|
560
|
-
WalletAdapterNetwork2["Devnet"] = "devnet";
|
|
561
|
-
})(WalletAdapterNetwork || (WalletAdapterNetwork = {}));
|
|
562
313
|
function cn(...inputs) {
|
|
563
314
|
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
564
315
|
}
|
|
565
316
|
var Dialog = DialogPrimitive__namespace.Root;
|
|
566
|
-
var DialogPortal =
|
|
567
|
-
|
|
568
|
-
var DialogOverlay = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
317
|
+
var DialogPortal = DialogPrimitive__namespace.Portal;
|
|
318
|
+
var DialogOverlay = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
569
319
|
DialogPrimitive__namespace.Overlay,
|
|
570
320
|
{
|
|
571
321
|
ref,
|
|
572
322
|
className: cn(
|
|
573
|
-
"fixed inset-0 z-50 bg-black/80
|
|
323
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
574
324
|
className
|
|
575
325
|
),
|
|
576
326
|
...props
|
|
577
327
|
}
|
|
578
328
|
));
|
|
579
329
|
DialogOverlay.displayName = DialogPrimitive__namespace.Overlay.displayName;
|
|
580
|
-
var DialogContent =
|
|
330
|
+
var DialogContent = React17__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(DialogPortal, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payments-ui-portal", children: [
|
|
581
331
|
/* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
|
|
582
332
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
583
333
|
DialogPrimitive__namespace.Content,
|
|
584
334
|
{
|
|
585
335
|
ref,
|
|
586
336
|
className: cn(
|
|
587
|
-
"fixed left-[50%] top-[50%] z-50 grid w-
|
|
337
|
+
"fixed left-[50%] top-[50%] z-50 grid w-[calc(100vw-40px)] sm:w-[calc(100vw-60px)] max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-white/10 bg-[#161b22] text-white p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-lg",
|
|
588
338
|
className
|
|
589
339
|
),
|
|
590
340
|
...props,
|
|
591
341
|
children: [
|
|
592
342
|
children,
|
|
593
|
-
/* @__PURE__ */ jsxRuntime.jsxs(DialogPrimitive__namespace.Close, { className: "absolute right-4 top-
|
|
594
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-
|
|
343
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogPrimitive__namespace.Close, { className: "absolute right-4 top-5 rounded-full bg-white/10 p-1 opacity-70 transition-opacity hover:opacity-100 hover:bg-white/20 focus:outline-none disabled:pointer-events-none", children: [
|
|
344
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3 text-white" }),
|
|
595
345
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
|
|
596
346
|
] })
|
|
597
347
|
]
|
|
598
348
|
}
|
|
599
349
|
)
|
|
600
|
-
] }));
|
|
350
|
+
] }) }));
|
|
601
351
|
DialogContent.displayName = DialogPrimitive__namespace.Content.displayName;
|
|
602
|
-
var DialogHeader = ({
|
|
352
|
+
var DialogHeader = ({
|
|
353
|
+
className,
|
|
354
|
+
...props
|
|
355
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
356
|
+
"div",
|
|
357
|
+
{
|
|
358
|
+
className: cn(
|
|
359
|
+
"flex flex-col space-y-1.5 text-center sm:text-left",
|
|
360
|
+
className
|
|
361
|
+
),
|
|
362
|
+
...props
|
|
363
|
+
}
|
|
364
|
+
);
|
|
603
365
|
DialogHeader.displayName = "DialogHeader";
|
|
604
|
-
var DialogTitle =
|
|
366
|
+
var DialogTitle = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
605
367
|
DialogPrimitive__namespace.Title,
|
|
606
368
|
{
|
|
607
369
|
ref,
|
|
608
|
-
className: cn(
|
|
370
|
+
className: cn(
|
|
371
|
+
"text-lg font-semibold leading-none tracking-tight",
|
|
372
|
+
className
|
|
373
|
+
),
|
|
609
374
|
...props
|
|
610
375
|
}
|
|
611
376
|
));
|
|
612
377
|
DialogTitle.displayName = DialogPrimitive__namespace.Title.displayName;
|
|
613
|
-
var DialogDescription =
|
|
378
|
+
var DialogDescription = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
614
379
|
DialogPrimitive__namespace.Description,
|
|
615
380
|
{
|
|
616
381
|
ref,
|
|
617
|
-
className: cn("text-
|
|
382
|
+
className: cn("text-white/60 text-sm", className),
|
|
618
383
|
...props
|
|
619
384
|
}
|
|
620
385
|
));
|
|
@@ -634,131 +399,17 @@ var customCountries = [
|
|
|
634
399
|
];
|
|
635
400
|
countryList__default.default.overwrite(customCountries);
|
|
636
401
|
var countries = countryList__default.default.getData().sort((a, b) => a.name.localeCompare(b.name));
|
|
637
|
-
function setRef(ref, value) {
|
|
638
|
-
if (typeof ref === "function") {
|
|
639
|
-
return ref(value);
|
|
640
|
-
} else if (ref !== null && ref !== void 0) {
|
|
641
|
-
ref.current = value;
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
function composeRefs(...refs) {
|
|
645
|
-
return (node) => {
|
|
646
|
-
let hasCleanup = false;
|
|
647
|
-
const cleanups = refs.map((ref) => {
|
|
648
|
-
const cleanup = setRef(ref, node);
|
|
649
|
-
if (!hasCleanup && typeof cleanup == "function") {
|
|
650
|
-
hasCleanup = true;
|
|
651
|
-
}
|
|
652
|
-
return cleanup;
|
|
653
|
-
});
|
|
654
|
-
if (hasCleanup) {
|
|
655
|
-
return () => {
|
|
656
|
-
for (let i = 0; i < cleanups.length; i++) {
|
|
657
|
-
const cleanup = cleanups[i];
|
|
658
|
-
if (typeof cleanup == "function") {
|
|
659
|
-
cleanup();
|
|
660
|
-
} else {
|
|
661
|
-
setRef(refs[i], null);
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
};
|
|
665
|
-
}
|
|
666
|
-
};
|
|
667
|
-
}
|
|
668
|
-
// @__NO_SIDE_EFFECTS__
|
|
669
|
-
function createSlot(ownerName) {
|
|
670
|
-
const SlotClone = /* @__PURE__ */ createSlotClone(ownerName);
|
|
671
|
-
const Slot2 = React3__namespace.forwardRef((props, forwardedRef) => {
|
|
672
|
-
const { children, ...slotProps } = props;
|
|
673
|
-
const childrenArray = React3__namespace.Children.toArray(children);
|
|
674
|
-
const slottable = childrenArray.find(isSlottable);
|
|
675
|
-
if (slottable) {
|
|
676
|
-
const newElement = slottable.props.children;
|
|
677
|
-
const newChildren = childrenArray.map((child) => {
|
|
678
|
-
if (child === slottable) {
|
|
679
|
-
if (React3__namespace.Children.count(newElement) > 1) return React3__namespace.Children.only(null);
|
|
680
|
-
return React3__namespace.isValidElement(newElement) ? newElement.props.children : null;
|
|
681
|
-
} else {
|
|
682
|
-
return child;
|
|
683
|
-
}
|
|
684
|
-
});
|
|
685
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SlotClone, { ...slotProps, ref: forwardedRef, children: React3__namespace.isValidElement(newElement) ? React3__namespace.cloneElement(newElement, void 0, newChildren) : null });
|
|
686
|
-
}
|
|
687
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SlotClone, { ...slotProps, ref: forwardedRef, children });
|
|
688
|
-
});
|
|
689
|
-
Slot2.displayName = `${ownerName}.Slot`;
|
|
690
|
-
return Slot2;
|
|
691
|
-
}
|
|
692
|
-
var Slot = /* @__PURE__ */ createSlot("Slot");
|
|
693
|
-
// @__NO_SIDE_EFFECTS__
|
|
694
|
-
function createSlotClone(ownerName) {
|
|
695
|
-
const SlotClone = React3__namespace.forwardRef((props, forwardedRef) => {
|
|
696
|
-
const { children, ...slotProps } = props;
|
|
697
|
-
if (React3__namespace.isValidElement(children)) {
|
|
698
|
-
const childrenRef = getElementRef(children);
|
|
699
|
-
const props2 = mergeProps(slotProps, children.props);
|
|
700
|
-
if (children.type !== React3__namespace.Fragment) {
|
|
701
|
-
props2.ref = forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef;
|
|
702
|
-
}
|
|
703
|
-
return React3__namespace.cloneElement(children, props2);
|
|
704
|
-
}
|
|
705
|
-
return React3__namespace.Children.count(children) > 1 ? React3__namespace.Children.only(null) : null;
|
|
706
|
-
});
|
|
707
|
-
SlotClone.displayName = `${ownerName}.SlotClone`;
|
|
708
|
-
return SlotClone;
|
|
709
|
-
}
|
|
710
|
-
var SLOTTABLE_IDENTIFIER = Symbol("radix.slottable");
|
|
711
|
-
function isSlottable(child) {
|
|
712
|
-
return React3__namespace.isValidElement(child) && typeof child.type === "function" && "__radixId" in child.type && child.type.__radixId === SLOTTABLE_IDENTIFIER;
|
|
713
|
-
}
|
|
714
|
-
function mergeProps(slotProps, childProps) {
|
|
715
|
-
const overrideProps = { ...childProps };
|
|
716
|
-
for (const propName in childProps) {
|
|
717
|
-
const slotPropValue = slotProps[propName];
|
|
718
|
-
const childPropValue = childProps[propName];
|
|
719
|
-
const isHandler = /^on[A-Z]/.test(propName);
|
|
720
|
-
if (isHandler) {
|
|
721
|
-
if (slotPropValue && childPropValue) {
|
|
722
|
-
overrideProps[propName] = (...args) => {
|
|
723
|
-
const result = childPropValue(...args);
|
|
724
|
-
slotPropValue(...args);
|
|
725
|
-
return result;
|
|
726
|
-
};
|
|
727
|
-
} else if (slotPropValue) {
|
|
728
|
-
overrideProps[propName] = slotPropValue;
|
|
729
|
-
}
|
|
730
|
-
} else if (propName === "style") {
|
|
731
|
-
overrideProps[propName] = { ...slotPropValue, ...childPropValue };
|
|
732
|
-
} else if (propName === "className") {
|
|
733
|
-
overrideProps[propName] = [slotPropValue, childPropValue].filter(Boolean).join(" ");
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
return { ...slotProps, ...overrideProps };
|
|
737
|
-
}
|
|
738
|
-
function getElementRef(element) {
|
|
739
|
-
let getter = Object.getOwnPropertyDescriptor(element.props, "ref")?.get;
|
|
740
|
-
let mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
|
|
741
|
-
if (mayWarn) {
|
|
742
|
-
return element.ref;
|
|
743
|
-
}
|
|
744
|
-
getter = Object.getOwnPropertyDescriptor(element, "ref")?.get;
|
|
745
|
-
mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
|
|
746
|
-
if (mayWarn) {
|
|
747
|
-
return element.props.ref;
|
|
748
|
-
}
|
|
749
|
-
return element.props.ref || element.ref;
|
|
750
|
-
}
|
|
751
402
|
var buttonVariants = classVarianceAuthority.cva(
|
|
752
|
-
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-
|
|
403
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/20 disabled:pointer-events-none disabled:opacity-50",
|
|
753
404
|
{
|
|
754
405
|
variants: {
|
|
755
406
|
variant: {
|
|
756
|
-
default: "bg-
|
|
757
|
-
secondary: "bg-
|
|
758
|
-
outline: "border border-
|
|
759
|
-
ghost: "hover:bg-
|
|
760
|
-
destructive: "bg-
|
|
761
|
-
link: "text-
|
|
407
|
+
default: "bg-[#28a745] text-white shadow hover:bg-[#16a34a]",
|
|
408
|
+
secondary: "bg-white/10 text-white hover:bg-white/20",
|
|
409
|
+
outline: "border border-white/10 bg-transparent text-white hover:bg-white/10",
|
|
410
|
+
ghost: "text-white/80 hover:bg-white/10 hover:text-white",
|
|
411
|
+
destructive: "bg-red-600 text-white hover:bg-red-700",
|
|
412
|
+
link: "text-blue-400 underline-offset-4 hover:underline"
|
|
762
413
|
},
|
|
763
414
|
size: {
|
|
764
415
|
default: "h-10 px-4 py-2",
|
|
@@ -773,9 +424,9 @@ var buttonVariants = classVarianceAuthority.cva(
|
|
|
773
424
|
}
|
|
774
425
|
}
|
|
775
426
|
);
|
|
776
|
-
var Button =
|
|
427
|
+
var Button = React17__namespace.forwardRef(
|
|
777
428
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
778
|
-
const Comp = asChild ? Slot : "button";
|
|
429
|
+
const Comp = asChild ? reactSlot.Slot : "button";
|
|
779
430
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
780
431
|
Comp,
|
|
781
432
|
{
|
|
@@ -787,14 +438,14 @@ var Button = React3__namespace.forwardRef(
|
|
|
787
438
|
}
|
|
788
439
|
);
|
|
789
440
|
Button.displayName = "Button";
|
|
790
|
-
var Input =
|
|
441
|
+
var Input = React17__namespace.forwardRef(
|
|
791
442
|
({ className, type, ...props }, ref) => {
|
|
792
443
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
793
444
|
"input",
|
|
794
445
|
{
|
|
795
446
|
type,
|
|
796
447
|
className: cn(
|
|
797
|
-
"flex h-10 w-full rounded-md border border-
|
|
448
|
+
"flex h-10 w-full rounded-md border border-white/10 bg-white/5 px-3 py-2 text-sm text-white placeholder:text-white/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/20 focus-visible:border-white/20 disabled:cursor-not-allowed disabled:opacity-50",
|
|
798
449
|
className
|
|
799
450
|
),
|
|
800
451
|
ref,
|
|
@@ -804,12 +455,12 @@ var Input = React3__namespace.forwardRef(
|
|
|
804
455
|
}
|
|
805
456
|
);
|
|
806
457
|
Input.displayName = "Input";
|
|
807
|
-
var Label =
|
|
458
|
+
var Label = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
808
459
|
LabelPrimitive__namespace.Root,
|
|
809
460
|
{
|
|
810
461
|
ref,
|
|
811
462
|
className: cn(
|
|
812
|
-
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
|
463
|
+
"text-sm font-medium leading-none text-white peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
|
813
464
|
className
|
|
814
465
|
),
|
|
815
466
|
...props
|
|
@@ -818,12 +469,12 @@ var Label = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @_
|
|
|
818
469
|
Label.displayName = LabelPrimitive__namespace.Root.displayName;
|
|
819
470
|
var Select = SelectPrimitive__namespace.Root;
|
|
820
471
|
var SelectValue = SelectPrimitive__namespace.Value;
|
|
821
|
-
var SelectTrigger =
|
|
472
|
+
var SelectTrigger = React17__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
822
473
|
SelectPrimitive__namespace.Trigger,
|
|
823
474
|
{
|
|
824
475
|
ref,
|
|
825
476
|
className: cn(
|
|
826
|
-
"flex h-10 w-full items-center justify-between rounded-md border border-
|
|
477
|
+
"flex h-10 w-full items-center justify-between rounded-md border border-white/10 bg-white/5 px-3 py-2 text-sm text-white placeholder:text-white/40 focus:outline-none focus:ring-2 focus:ring-white/20 disabled:cursor-not-allowed disabled:opacity-50",
|
|
827
478
|
className
|
|
828
479
|
),
|
|
829
480
|
...props,
|
|
@@ -834,39 +485,39 @@ var SelectTrigger = React3__namespace.forwardRef(({ className, children, ...prop
|
|
|
834
485
|
}
|
|
835
486
|
));
|
|
836
487
|
SelectTrigger.displayName = SelectPrimitive__namespace.Trigger.displayName;
|
|
837
|
-
var SelectContent =
|
|
488
|
+
var SelectContent = React17__namespace.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payments-ui-portal", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
838
489
|
SelectPrimitive__namespace.Content,
|
|
839
490
|
{
|
|
840
491
|
ref,
|
|
841
492
|
className: cn(
|
|
842
|
-
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-
|
|
493
|
+
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border border-white/10 bg-[#1a1f26] text-white shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
843
494
|
className
|
|
844
495
|
),
|
|
845
496
|
position,
|
|
846
497
|
...props,
|
|
847
498
|
children: [
|
|
848
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ScrollUpButton, { className: "flex cursor-default items-center justify-center py-1", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "h-4 w-4" }) }),
|
|
499
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ScrollUpButton, { className: "flex cursor-default items-center justify-center py-1 text-white/60", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "h-4 w-4" }) }),
|
|
849
500
|
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Viewport, { className: "p-1", children }),
|
|
850
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ScrollDownButton, { className: "flex cursor-default items-center justify-center py-1", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4" }) })
|
|
501
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ScrollDownButton, { className: "flex cursor-default items-center justify-center py-1 text-white/60", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4" }) })
|
|
851
502
|
]
|
|
852
503
|
}
|
|
853
|
-
) }));
|
|
504
|
+
) }) }));
|
|
854
505
|
SelectContent.displayName = SelectPrimitive__namespace.Content.displayName;
|
|
855
|
-
var SelectLabel =
|
|
506
|
+
var SelectLabel = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
856
507
|
SelectPrimitive__namespace.Label,
|
|
857
508
|
{
|
|
858
509
|
ref,
|
|
859
|
-
className: cn("px-2 py-1.5 text-sm font-semibold text-
|
|
510
|
+
className: cn("px-2 py-1.5 text-sm font-semibold text-white/60", className),
|
|
860
511
|
...props
|
|
861
512
|
}
|
|
862
513
|
));
|
|
863
514
|
SelectLabel.displayName = SelectPrimitive__namespace.Label.displayName;
|
|
864
|
-
var SelectItem =
|
|
515
|
+
var SelectItem = React17__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
865
516
|
SelectPrimitive__namespace.Item,
|
|
866
517
|
{
|
|
867
518
|
ref,
|
|
868
519
|
className: cn(
|
|
869
|
-
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-
|
|
520
|
+
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm text-white outline-none focus:bg-white/10 focus:text-white data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
870
521
|
className
|
|
871
522
|
),
|
|
872
523
|
...props,
|
|
@@ -877,16 +528,18 @@ var SelectItem = React3__namespace.forwardRef(({ className, children, ...props }
|
|
|
877
528
|
}
|
|
878
529
|
));
|
|
879
530
|
SelectItem.displayName = SelectPrimitive__namespace.Item.displayName;
|
|
880
|
-
var SelectSeparator =
|
|
531
|
+
var SelectSeparator = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
881
532
|
SelectPrimitive__namespace.Separator,
|
|
882
533
|
{
|
|
883
534
|
ref,
|
|
884
|
-
className: cn("mx-1 my-1 h-px bg-
|
|
535
|
+
className: cn("mx-1 my-1 h-px bg-white/10", className),
|
|
885
536
|
...props
|
|
886
537
|
}
|
|
887
538
|
));
|
|
888
539
|
SelectSeparator.displayName = SelectPrimitive__namespace.Separator.displayName;
|
|
889
|
-
|
|
540
|
+
|
|
541
|
+
// src/constants/billing.ts
|
|
542
|
+
var defaultBillingDetails = {
|
|
890
543
|
firstName: "",
|
|
891
544
|
lastName: "",
|
|
892
545
|
address1: "",
|
|
@@ -911,32 +564,32 @@ var CardDetailsForm = ({
|
|
|
911
564
|
submitDisabled = false
|
|
912
565
|
}) => {
|
|
913
566
|
const { config } = usePaymentContext();
|
|
914
|
-
const defaultValuesKey =
|
|
915
|
-
const mergedDefaults =
|
|
567
|
+
const defaultValuesKey = React17.useMemo(() => JSON.stringify(defaultValues ?? {}), [defaultValues]);
|
|
568
|
+
const mergedDefaults = React17.useMemo(
|
|
916
569
|
() => ({
|
|
917
|
-
...
|
|
570
|
+
...defaultBillingDetails,
|
|
918
571
|
...defaultValues,
|
|
919
|
-
email: defaultValues?.email ?? config.defaultUser?.email ??
|
|
572
|
+
email: defaultValues?.email ?? config.defaultUser?.email ?? defaultBillingDetails.email
|
|
920
573
|
}),
|
|
921
574
|
[defaultValuesKey, config.defaultUser?.email]
|
|
922
575
|
);
|
|
923
|
-
const [firstName, setFirstName] =
|
|
924
|
-
const [lastName, setLastName] =
|
|
925
|
-
const [address1, setAddress1] =
|
|
926
|
-
const [city, setCity] =
|
|
927
|
-
const [stateRegion, setStateRegion] =
|
|
928
|
-
const [postalCode, setPostalCode] =
|
|
929
|
-
const [country, setCountry] =
|
|
930
|
-
const [email, setEmail] =
|
|
931
|
-
const [localError, setLocalError] =
|
|
932
|
-
const [isTokenizing, setIsTokenizing] =
|
|
933
|
-
|
|
576
|
+
const [firstName, setFirstName] = React17.useState(mergedDefaults.firstName);
|
|
577
|
+
const [lastName, setLastName] = React17.useState(mergedDefaults.lastName);
|
|
578
|
+
const [address1, setAddress1] = React17.useState(mergedDefaults.address1);
|
|
579
|
+
const [city, setCity] = React17.useState(mergedDefaults.city);
|
|
580
|
+
const [stateRegion, setStateRegion] = React17.useState(mergedDefaults.stateRegion ?? "");
|
|
581
|
+
const [postalCode, setPostalCode] = React17.useState(mergedDefaults.postalCode);
|
|
582
|
+
const [country, setCountry] = React17.useState(mergedDefaults.country);
|
|
583
|
+
const [email, setEmail] = React17.useState(mergedDefaults.email ?? "");
|
|
584
|
+
const [localError, setLocalError] = React17.useState(null);
|
|
585
|
+
const [isTokenizing, setIsTokenizing] = React17.useState(false);
|
|
586
|
+
React17.useEffect(() => {
|
|
934
587
|
if (!visible) {
|
|
935
588
|
setLocalError(null);
|
|
936
589
|
setIsTokenizing(false);
|
|
937
590
|
}
|
|
938
591
|
}, [visible]);
|
|
939
|
-
|
|
592
|
+
React17.useEffect(() => {
|
|
940
593
|
if (!visible) return;
|
|
941
594
|
setFirstName(mergedDefaults.firstName);
|
|
942
595
|
setLastName(mergedDefaults.lastName);
|
|
@@ -947,7 +600,7 @@ var CardDetailsForm = ({
|
|
|
947
600
|
setCountry(mergedDefaults.country);
|
|
948
601
|
setEmail(mergedDefaults.email ?? "");
|
|
949
602
|
}, [defaultValuesKey, mergedDefaults, visible]);
|
|
950
|
-
|
|
603
|
+
React17.useEffect(() => {
|
|
951
604
|
if (!onBillingChange) return;
|
|
952
605
|
onBillingChange({
|
|
953
606
|
firstName,
|
|
@@ -972,7 +625,7 @@ var CardDetailsForm = ({
|
|
|
972
625
|
mergedDefaults.provider,
|
|
973
626
|
onBillingChange
|
|
974
627
|
]);
|
|
975
|
-
|
|
628
|
+
React17.useEffect(() => {
|
|
976
629
|
if (typeof window === "undefined" || !window.CollectJS || !visible) {
|
|
977
630
|
return;
|
|
978
631
|
}
|
|
@@ -1045,7 +698,7 @@ var CardDetailsForm = ({
|
|
|
1045
698
|
window.CollectJS.startPaymentRequest();
|
|
1046
699
|
};
|
|
1047
700
|
const errorMessage = localError ?? externalError;
|
|
1048
|
-
const collectFieldClass = "flex h-11 w-full items-center rounded-md border border-
|
|
701
|
+
const collectFieldClass = "flex h-11 w-full items-center rounded-md border border-white/10 bg-white/5 px-3 text-sm text-white";
|
|
1049
702
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1050
703
|
"form",
|
|
1051
704
|
{
|
|
@@ -1053,10 +706,10 @@ var CardDetailsForm = ({
|
|
|
1053
706
|
onSubmit: handleSubmit,
|
|
1054
707
|
noValidate: true,
|
|
1055
708
|
children: [
|
|
1056
|
-
errorMessage && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-
|
|
709
|
+
errorMessage && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-red-500/40 bg-red-500/10 px-4 py-2 text-sm text-red-400", children: errorMessage }),
|
|
1057
710
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-5 md:grid-cols-2", children: [
|
|
1058
711
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1059
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: "payments-first", className: "flex items-center gap-2 text-
|
|
712
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: "payments-first", className: "flex items-center gap-2 text-white/70", children: [
|
|
1060
713
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "h-4 w-4" }),
|
|
1061
714
|
" First name"
|
|
1062
715
|
] }),
|
|
@@ -1071,7 +724,7 @@ var CardDetailsForm = ({
|
|
|
1071
724
|
)
|
|
1072
725
|
] }),
|
|
1073
726
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1074
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: "payments-last", className: "flex items-center gap-2 text-
|
|
727
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: "payments-last", className: "flex items-center gap-2 text-white/70", children: [
|
|
1075
728
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "h-4 w-4" }),
|
|
1076
729
|
" Last name"
|
|
1077
730
|
] }),
|
|
@@ -1138,7 +791,7 @@ var CardDetailsForm = ({
|
|
|
1138
791
|
] }),
|
|
1139
792
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-5 md:grid-cols-2", children: [
|
|
1140
793
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1141
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: "payments-postal", className: "flex items-center gap-2 text-
|
|
794
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: "payments-postal", className: "flex items-center gap-2 text-white/70", children: [
|
|
1142
795
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { className: "h-4 w-4" }),
|
|
1143
796
|
" Postal code"
|
|
1144
797
|
] }),
|
|
@@ -1190,7 +843,7 @@ var CardDetailsForm = ({
|
|
|
1190
843
|
] })
|
|
1191
844
|
}
|
|
1192
845
|
),
|
|
1193
|
-
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 text-xs text-
|
|
846
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 text-xs text-white/50", children: [
|
|
1194
847
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-4 w-4" }),
|
|
1195
848
|
" Your payment information is encrypted and processed securely."
|
|
1196
849
|
] })
|
|
@@ -1198,19 +851,24 @@ var CardDetailsForm = ({
|
|
|
1198
851
|
}
|
|
1199
852
|
);
|
|
1200
853
|
};
|
|
1201
|
-
var usePaymentMethodService = () => {
|
|
1202
|
-
const { services } = usePaymentContext();
|
|
1203
|
-
return React3.useMemo(() => services.paymentMethods, [services]);
|
|
1204
|
-
};
|
|
1205
|
-
|
|
1206
|
-
// src/hooks/usePaymentMethods.ts
|
|
1207
854
|
var PAYMENT_METHODS_KEY = ["payments-ui", "payment-methods"];
|
|
1208
855
|
var usePaymentMethods = () => {
|
|
1209
|
-
const
|
|
856
|
+
const { client } = usePaymentContext();
|
|
1210
857
|
const queryClient = reactQuery.useQueryClient();
|
|
1211
858
|
const listQuery = reactQuery.useQuery({
|
|
1212
859
|
queryKey: PAYMENT_METHODS_KEY,
|
|
1213
|
-
queryFn: () =>
|
|
860
|
+
queryFn: async () => {
|
|
861
|
+
const response = await client.listPaymentMethods({ limit: 50 });
|
|
862
|
+
return {
|
|
863
|
+
data: response.data,
|
|
864
|
+
total_items: response.total,
|
|
865
|
+
limit: response.limit,
|
|
866
|
+
offset: response.offset,
|
|
867
|
+
page: response.limit > 0 ? Math.floor(response.offset / response.limit) + 1 : 1,
|
|
868
|
+
page_size: response.limit,
|
|
869
|
+
total_pages: response.limit > 0 ? Math.ceil(response.total / response.limit) : void 0
|
|
870
|
+
};
|
|
871
|
+
}
|
|
1214
872
|
});
|
|
1215
873
|
const createMutation = reactQuery.useMutation({
|
|
1216
874
|
mutationFn: ({ token, billing }) => {
|
|
@@ -1227,14 +885,14 @@ var usePaymentMethods = () => {
|
|
|
1227
885
|
email: billing.email,
|
|
1228
886
|
provider: billing.provider
|
|
1229
887
|
};
|
|
1230
|
-
return
|
|
888
|
+
return client.createPaymentMethod(payload);
|
|
1231
889
|
},
|
|
1232
890
|
onSuccess: () => {
|
|
1233
891
|
void queryClient.invalidateQueries({ queryKey: PAYMENT_METHODS_KEY });
|
|
1234
892
|
}
|
|
1235
893
|
});
|
|
1236
894
|
const deleteMutation = reactQuery.useMutation({
|
|
1237
|
-
mutationFn: ({ id }) =>
|
|
895
|
+
mutationFn: ({ id }) => client.deletePaymentMethod(id),
|
|
1238
896
|
onSuccess: () => {
|
|
1239
897
|
void queryClient.invalidateQueries({ queryKey: PAYMENT_METHODS_KEY });
|
|
1240
898
|
}
|
|
@@ -1250,10 +908,10 @@ var badgeVariants = classVarianceAuthority.cva(
|
|
|
1250
908
|
{
|
|
1251
909
|
variants: {
|
|
1252
910
|
variant: {
|
|
1253
|
-
default: "border-transparent bg-
|
|
1254
|
-
secondary: "border-transparent bg-
|
|
1255
|
-
outline: "text-
|
|
1256
|
-
destructive: "border-transparent bg-
|
|
911
|
+
default: "border-transparent bg-emerald-500/20 text-emerald-400",
|
|
912
|
+
secondary: "border-transparent bg-white/10 text-white/70",
|
|
913
|
+
outline: "border-white/20 text-white/80",
|
|
914
|
+
destructive: "border-transparent bg-red-500/20 text-red-400"
|
|
1257
915
|
}
|
|
1258
916
|
},
|
|
1259
917
|
defaultVariants: {
|
|
@@ -1264,7 +922,7 @@ var badgeVariants = classVarianceAuthority.cva(
|
|
|
1264
922
|
function Badge({ className, variant, ...props }) {
|
|
1265
923
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
1266
924
|
}
|
|
1267
|
-
var ScrollArea =
|
|
925
|
+
var ScrollArea = React17__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1268
926
|
ScrollAreaPrimitive__namespace.Root,
|
|
1269
927
|
{
|
|
1270
928
|
ref,
|
|
@@ -1278,7 +936,7 @@ var ScrollArea = React3__namespace.forwardRef(({ className, children, ...props }
|
|
|
1278
936
|
}
|
|
1279
937
|
));
|
|
1280
938
|
ScrollArea.displayName = ScrollAreaPrimitive__namespace.Root.displayName;
|
|
1281
|
-
var ScrollBar =
|
|
939
|
+
var ScrollBar = React17__namespace.forwardRef(({ className, orientation = "vertical", ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1282
940
|
ScrollAreaPrimitive__namespace.ScrollAreaScrollbar,
|
|
1283
941
|
{
|
|
1284
942
|
ref,
|
|
@@ -1307,9 +965,9 @@ var StoredPaymentMethods = ({
|
|
|
1307
965
|
description = "Manage your saved cards"
|
|
1308
966
|
}) => {
|
|
1309
967
|
const { listQuery, createMutation, deleteMutation } = usePaymentMethods();
|
|
1310
|
-
const [isModalOpen, setIsModalOpen] =
|
|
1311
|
-
const [deletingId, setDeletingId] =
|
|
1312
|
-
const payments =
|
|
968
|
+
const [isModalOpen, setIsModalOpen] = React17.useState(false);
|
|
969
|
+
const [deletingId, setDeletingId] = React17.useState(null);
|
|
970
|
+
const payments = React17.useMemo(() => listQuery.data?.data ?? [], [listQuery.data]);
|
|
1313
971
|
const handleCardTokenize = (token, billing) => {
|
|
1314
972
|
createMutation.mutate({ token, billing });
|
|
1315
973
|
};
|
|
@@ -1416,36 +1074,36 @@ var StoredPaymentMethods = ({
|
|
|
1416
1074
|
] });
|
|
1417
1075
|
};
|
|
1418
1076
|
var Tabs = TabsPrimitive__namespace.Root;
|
|
1419
|
-
var TabsList =
|
|
1077
|
+
var TabsList = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1420
1078
|
TabsPrimitive__namespace.List,
|
|
1421
1079
|
{
|
|
1422
1080
|
ref,
|
|
1423
1081
|
className: cn(
|
|
1424
|
-
"inline-flex h-10 items-center justify-center rounded-md bg-
|
|
1082
|
+
"inline-flex h-10 items-center justify-center rounded-md bg-white/5 border border-white/10 p-1 text-white/60",
|
|
1425
1083
|
className
|
|
1426
1084
|
),
|
|
1427
1085
|
...props
|
|
1428
1086
|
}
|
|
1429
1087
|
));
|
|
1430
1088
|
TabsList.displayName = TabsPrimitive__namespace.List.displayName;
|
|
1431
|
-
var TabsTrigger =
|
|
1089
|
+
var TabsTrigger = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1432
1090
|
TabsPrimitive__namespace.Trigger,
|
|
1433
1091
|
{
|
|
1434
1092
|
ref,
|
|
1435
1093
|
className: cn(
|
|
1436
|
-
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium
|
|
1094
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/20 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white/10 data-[state=active]:text-white data-[state=active]:shadow",
|
|
1437
1095
|
className
|
|
1438
1096
|
),
|
|
1439
1097
|
...props
|
|
1440
1098
|
}
|
|
1441
1099
|
));
|
|
1442
1100
|
TabsTrigger.displayName = TabsPrimitive__namespace.Trigger.displayName;
|
|
1443
|
-
var TabsContent =
|
|
1101
|
+
var TabsContent = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1444
1102
|
TabsPrimitive__namespace.Content,
|
|
1445
1103
|
{
|
|
1446
1104
|
ref,
|
|
1447
1105
|
className: cn(
|
|
1448
|
-
"mt-2
|
|
1106
|
+
"mt-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/20",
|
|
1449
1107
|
className
|
|
1450
1108
|
),
|
|
1451
1109
|
...props
|
|
@@ -1454,19 +1112,19 @@ var TabsContent = React3__namespace.forwardRef(({ className, ...props }, ref) =>
|
|
|
1454
1112
|
TabsContent.displayName = TabsPrimitive__namespace.Content.displayName;
|
|
1455
1113
|
var usePaymentNotifications = () => {
|
|
1456
1114
|
const { config } = usePaymentContext();
|
|
1457
|
-
const notifyStatus =
|
|
1115
|
+
const notifyStatus = React17.useCallback(
|
|
1458
1116
|
(status, context) => {
|
|
1459
1117
|
config.callbacks?.onStatusChange?.({ status, context });
|
|
1460
1118
|
},
|
|
1461
1119
|
[config.callbacks]
|
|
1462
1120
|
);
|
|
1463
|
-
const notifySuccess =
|
|
1121
|
+
const notifySuccess = React17.useCallback(
|
|
1464
1122
|
(payload) => {
|
|
1465
1123
|
config.callbacks?.onSuccess?.(payload ?? {});
|
|
1466
1124
|
},
|
|
1467
1125
|
[config.callbacks]
|
|
1468
1126
|
);
|
|
1469
|
-
const notifyError =
|
|
1127
|
+
const notifyError = React17.useCallback(
|
|
1470
1128
|
(error) => {
|
|
1471
1129
|
config.callbacks?.onError?.(
|
|
1472
1130
|
typeof error === "string" ? new Error(error) : error
|
|
@@ -1480,384 +1138,21 @@ var usePaymentNotifications = () => {
|
|
|
1480
1138
|
notifyError
|
|
1481
1139
|
};
|
|
1482
1140
|
};
|
|
1483
|
-
var useSolanaService = () => {
|
|
1484
|
-
const { services } = usePaymentContext();
|
|
1485
|
-
return React3.useMemo(() => services.solanaPayments, [services]);
|
|
1486
|
-
};
|
|
1487
|
-
var getSolBalance = async (connection, publicKey) => {
|
|
1488
|
-
try {
|
|
1489
|
-
const lamports = await connection.getBalance(publicKey);
|
|
1490
|
-
return lamports / web3_js.LAMPORTS_PER_SOL;
|
|
1491
|
-
} catch (error) {
|
|
1492
|
-
console.error("Failed to fetch SOL balance:", error);
|
|
1493
|
-
return 0;
|
|
1494
|
-
}
|
|
1495
|
-
};
|
|
1496
|
-
var fetchAllTokenBalances = async (connection, publicKey) => {
|
|
1497
|
-
const balances = /* @__PURE__ */ new Map();
|
|
1498
|
-
try {
|
|
1499
|
-
const tokenAccounts = await connection.getParsedProgramAccounts(
|
|
1500
|
-
splToken.TOKEN_PROGRAM_ID,
|
|
1501
|
-
{
|
|
1502
|
-
filters: [
|
|
1503
|
-
{
|
|
1504
|
-
dataSize: 165
|
|
1505
|
-
// Size of token account
|
|
1506
|
-
},
|
|
1507
|
-
{
|
|
1508
|
-
memcmp: {
|
|
1509
|
-
offset: 32,
|
|
1510
|
-
// Owner field offset
|
|
1511
|
-
bytes: publicKey.toString()
|
|
1512
|
-
}
|
|
1513
|
-
}
|
|
1514
|
-
]
|
|
1515
|
-
}
|
|
1516
|
-
);
|
|
1517
|
-
for (const account of tokenAccounts) {
|
|
1518
|
-
const data = account.account.data;
|
|
1519
|
-
const parsed = data.parsed;
|
|
1520
|
-
const info = parsed?.info;
|
|
1521
|
-
if (info && info.tokenAmount) {
|
|
1522
|
-
const mintAddress = info.mint;
|
|
1523
|
-
const uiAmount = info.tokenAmount.uiAmount || 0;
|
|
1524
|
-
if (uiAmount > 0) {
|
|
1525
|
-
balances.set(mintAddress, uiAmount);
|
|
1526
|
-
}
|
|
1527
|
-
}
|
|
1528
|
-
}
|
|
1529
|
-
} catch (error) {
|
|
1530
|
-
console.error("Failed to fetch token balances:", error);
|
|
1531
|
-
}
|
|
1532
|
-
return balances;
|
|
1533
|
-
};
|
|
1534
|
-
var fetchSupportedTokenBalances = async (connection, publicKey, supportedTokens) => {
|
|
1535
|
-
const results = [];
|
|
1536
|
-
const solBalance = await getSolBalance(connection, publicKey);
|
|
1537
|
-
const solTokenMeta = supportedTokens.find((token) => token.is_native || token.symbol === "SOL") || {
|
|
1538
|
-
symbol: "SOL",
|
|
1539
|
-
name: "Solana",
|
|
1540
|
-
mint: "So11111111111111111111111111111111111111112",
|
|
1541
|
-
decimals: 9};
|
|
1542
|
-
results.push({
|
|
1543
|
-
mint: solTokenMeta.mint,
|
|
1544
|
-
symbol: solTokenMeta.symbol,
|
|
1545
|
-
name: solTokenMeta.name,
|
|
1546
|
-
balance: solBalance,
|
|
1547
|
-
uiBalance: solBalance.toFixed(solTokenMeta.decimals <= 4 ? solTokenMeta.decimals : 4),
|
|
1548
|
-
decimals: solTokenMeta.decimals,
|
|
1549
|
-
isNative: true
|
|
1550
|
-
});
|
|
1551
|
-
const tokenBalances = await fetchAllTokenBalances(connection, publicKey);
|
|
1552
|
-
const tokenMetaByMint = new Map(
|
|
1553
|
-
supportedTokens.filter((token) => !(token.is_native || token.symbol === "SOL")).map((token) => [token.mint, token])
|
|
1554
|
-
);
|
|
1555
|
-
for (const [mint, tokenMeta] of tokenMetaByMint.entries()) {
|
|
1556
|
-
const balance = tokenBalances.get(mint) || 0;
|
|
1557
|
-
results.push({
|
|
1558
|
-
mint,
|
|
1559
|
-
symbol: tokenMeta.symbol,
|
|
1560
|
-
name: tokenMeta.name,
|
|
1561
|
-
balance,
|
|
1562
|
-
uiBalance: balance.toFixed(tokenMeta.decimals <= 6 ? tokenMeta.decimals : 6),
|
|
1563
|
-
decimals: tokenMeta.decimals,
|
|
1564
|
-
isNative: false
|
|
1565
|
-
});
|
|
1566
|
-
}
|
|
1567
|
-
return results;
|
|
1568
|
-
};
|
|
1569
|
-
var hasSufficientBalance = (balance, requiredAmount, buffer = 0.05) => {
|
|
1570
|
-
const requiredWithBuffer = requiredAmount * (1 + buffer);
|
|
1571
|
-
return balance >= requiredWithBuffer;
|
|
1572
|
-
};
|
|
1573
|
-
|
|
1574
|
-
// src/hooks/useSolanaDirectPayment.ts
|
|
1575
|
-
var useSolanaDirectPayment = (options) => {
|
|
1576
|
-
const { priceId, tokenAmount, selectedToken, supportedTokens, onStart, onConfirming, onSuccess, onError } = options;
|
|
1577
|
-
const { connected, publicKey, wallet, signTransaction } = walletAdapterReact.useWallet();
|
|
1578
|
-
const { config } = usePaymentContext();
|
|
1579
|
-
const solanaService = useSolanaService();
|
|
1580
|
-
const [tokenBalance, setTokenBalance] = React3.useState(null);
|
|
1581
|
-
const [isBalanceLoading, setIsBalanceLoading] = React3.useState(false);
|
|
1582
|
-
const [isProcessing, setIsProcessing] = React3.useState(false);
|
|
1583
|
-
const connection = React3.useMemo(() => {
|
|
1584
|
-
const rpc = config.solanaRpcUrl ?? "https://api.mainnet-beta.solana.com";
|
|
1585
|
-
return new web3_js.Connection(rpc);
|
|
1586
|
-
}, [config.solanaRpcUrl]);
|
|
1587
|
-
const fetchTokenBalance = React3.useCallback(async () => {
|
|
1588
|
-
if (!connected || !publicKey || !selectedToken) {
|
|
1589
|
-
setTokenBalance({ balance: 0, hasBalance: false });
|
|
1590
|
-
return;
|
|
1591
|
-
}
|
|
1592
|
-
try {
|
|
1593
|
-
setIsBalanceLoading(true);
|
|
1594
|
-
const balances = await fetchSupportedTokenBalances(
|
|
1595
|
-
connection,
|
|
1596
|
-
publicKey,
|
|
1597
|
-
supportedTokens
|
|
1598
|
-
);
|
|
1599
|
-
const balanceInfo = balances.find(
|
|
1600
|
-
(tb) => tb.symbol === selectedToken.symbol || tb.mint === selectedToken.mint
|
|
1601
|
-
);
|
|
1602
|
-
const balance = balanceInfo?.balance || 0;
|
|
1603
|
-
const hasBalanceFlag = hasSufficientBalance(balance, tokenAmount);
|
|
1604
|
-
setTokenBalance({ balance, hasBalance: hasBalanceFlag });
|
|
1605
|
-
console.log("payments-ui: Solana wallet balance", {
|
|
1606
|
-
token: selectedToken.symbol,
|
|
1607
|
-
balance,
|
|
1608
|
-
required: tokenAmount
|
|
1609
|
-
});
|
|
1610
|
-
} catch (error) {
|
|
1611
|
-
console.error("Failed to fetch token balance:", {
|
|
1612
|
-
token: selectedToken?.symbol,
|
|
1613
|
-
error
|
|
1614
|
-
});
|
|
1615
|
-
setTokenBalance({ balance: 0, hasBalance: false });
|
|
1616
|
-
} finally {
|
|
1617
|
-
setIsBalanceLoading(false);
|
|
1618
|
-
}
|
|
1619
|
-
}, [connected, publicKey, connection, selectedToken, tokenAmount, supportedTokens]);
|
|
1620
|
-
React3.useEffect(() => {
|
|
1621
|
-
if (connected && publicKey && selectedToken) {
|
|
1622
|
-
void fetchTokenBalance();
|
|
1623
|
-
}
|
|
1624
|
-
}, [connected, publicKey, selectedToken, tokenAmount, fetchTokenBalance]);
|
|
1625
|
-
const decodeTransaction = React3.useCallback((serialized) => {
|
|
1626
|
-
const buffer$1 = buffer.Buffer.from(serialized, "base64");
|
|
1627
|
-
try {
|
|
1628
|
-
return web3_js.VersionedTransaction.deserialize(buffer$1);
|
|
1629
|
-
} catch (err) {
|
|
1630
|
-
try {
|
|
1631
|
-
return web3_js.Transaction.from(buffer$1);
|
|
1632
|
-
} catch (legacyErr) {
|
|
1633
|
-
console.error("Failed to deserialize transaction", legacyErr);
|
|
1634
|
-
throw new Error("Invalid transaction payload received from server");
|
|
1635
|
-
}
|
|
1636
|
-
}
|
|
1637
|
-
}, []);
|
|
1638
|
-
const isVersionedTransaction = (tx) => {
|
|
1639
|
-
return !!tx && typeof tx === "object" && "version" in tx;
|
|
1640
|
-
};
|
|
1641
|
-
const signWithWallet = React3.useCallback(
|
|
1642
|
-
async (tx) => {
|
|
1643
|
-
if (!wallet) {
|
|
1644
|
-
throw new Error("Wallet adapter is not available");
|
|
1645
|
-
}
|
|
1646
|
-
const adapter = wallet.adapter;
|
|
1647
|
-
if (isVersionedTransaction(tx)) {
|
|
1648
|
-
if (adapter.supportedTransactionVersions) {
|
|
1649
|
-
const supported = adapter.supportedTransactionVersions;
|
|
1650
|
-
if (!supported.has(tx.version)) {
|
|
1651
|
-
throw new Error("Connected wallet does not support this transaction version");
|
|
1652
|
-
}
|
|
1653
|
-
}
|
|
1654
|
-
if (adapter.signVersionedTransaction) {
|
|
1655
|
-
return adapter.signVersionedTransaction(tx);
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
1658
|
-
if (adapter.signTransaction) {
|
|
1659
|
-
return adapter.signTransaction(tx);
|
|
1660
|
-
}
|
|
1661
|
-
if (signTransaction) {
|
|
1662
|
-
return signTransaction(tx);
|
|
1663
|
-
}
|
|
1664
|
-
throw new Error("Connected wallet cannot sign transactions");
|
|
1665
|
-
},
|
|
1666
|
-
[wallet, signTransaction]
|
|
1667
|
-
);
|
|
1668
|
-
const pay = React3.useCallback(async () => {
|
|
1669
|
-
if (!connected || !publicKey) {
|
|
1670
|
-
onError("Wallet not connected");
|
|
1671
|
-
return;
|
|
1672
|
-
}
|
|
1673
|
-
if (!selectedToken) {
|
|
1674
|
-
onError("No payment token selected");
|
|
1675
|
-
return;
|
|
1676
|
-
}
|
|
1677
|
-
if (!tokenBalance?.hasBalance) {
|
|
1678
|
-
console.warn("payments-ui: insufficient balance for Solana direct payment", {
|
|
1679
|
-
token: selectedToken.symbol
|
|
1680
|
-
});
|
|
1681
|
-
onError("Insufficient balance for this token");
|
|
1682
|
-
return;
|
|
1683
|
-
}
|
|
1684
|
-
try {
|
|
1685
|
-
setIsProcessing(true);
|
|
1686
|
-
onStart();
|
|
1687
|
-
console.log("payments-ui: initiating Solana direct payment", {
|
|
1688
|
-
priceId,
|
|
1689
|
-
token: selectedToken.symbol
|
|
1690
|
-
});
|
|
1691
|
-
const paymentData = await solanaService.generatePayment(
|
|
1692
|
-
priceId,
|
|
1693
|
-
selectedToken.symbol,
|
|
1694
|
-
publicKey.toBase58()
|
|
1695
|
-
);
|
|
1696
|
-
console.log("payments-ui: Solana payment intent created", {
|
|
1697
|
-
intentId: paymentData.intent_id
|
|
1698
|
-
});
|
|
1699
|
-
const transactionToSign = decodeTransaction(paymentData.transaction);
|
|
1700
|
-
console.log("payments-ui: requesting Solana wallet signature");
|
|
1701
|
-
const signedTx = await signWithWallet(transactionToSign);
|
|
1702
|
-
const signedSerialized = buffer.Buffer.from(signedTx.serialize()).toString("base64");
|
|
1703
|
-
onConfirming();
|
|
1704
|
-
console.log("payments-ui: submitting signed Solana transaction");
|
|
1705
|
-
const result = await solanaService.submitPayment(
|
|
1706
|
-
signedSerialized,
|
|
1707
|
-
priceId,
|
|
1708
|
-
paymentData.intent_id,
|
|
1709
|
-
`Payment for subscription - ${selectedToken.symbol}`
|
|
1710
|
-
);
|
|
1711
|
-
console.log("payments-ui: Solana direct payment confirmed", {
|
|
1712
|
-
transactionId: result.transaction_id
|
|
1713
|
-
});
|
|
1714
|
-
onSuccess(result, result.transaction_id);
|
|
1715
|
-
} catch (err) {
|
|
1716
|
-
console.error("Solana direct payment failed:", {
|
|
1717
|
-
priceId,
|
|
1718
|
-
token: selectedToken.symbol,
|
|
1719
|
-
error: err
|
|
1720
|
-
});
|
|
1721
|
-
let errorMessage = "Payment failed. Please try again.";
|
|
1722
|
-
const message = err instanceof Error ? err.message : typeof err === "string" ? err : "";
|
|
1723
|
-
if (message.includes("User rejected")) {
|
|
1724
|
-
errorMessage = "Payment cancelled by user";
|
|
1725
|
-
} else if (/insufficient\s+funds/i.test(message)) {
|
|
1726
|
-
errorMessage = "Insufficient balance for this token";
|
|
1727
|
-
} else if (message) {
|
|
1728
|
-
errorMessage = message;
|
|
1729
|
-
}
|
|
1730
|
-
onError(errorMessage);
|
|
1731
|
-
} finally {
|
|
1732
|
-
setIsProcessing(false);
|
|
1733
|
-
}
|
|
1734
|
-
}, [
|
|
1735
|
-
connected,
|
|
1736
|
-
publicKey,
|
|
1737
|
-
selectedToken,
|
|
1738
|
-
tokenBalance?.hasBalance,
|
|
1739
|
-
onError,
|
|
1740
|
-
onStart,
|
|
1741
|
-
solanaService,
|
|
1742
|
-
priceId,
|
|
1743
|
-
decodeTransaction,
|
|
1744
|
-
signWithWallet,
|
|
1745
|
-
onConfirming,
|
|
1746
|
-
onSuccess
|
|
1747
|
-
]);
|
|
1748
|
-
const balanceLabel = tokenBalance ? `${tokenBalance.balance.toFixed(4)} ${selectedToken?.symbol ?? ""}` : "--";
|
|
1749
|
-
return {
|
|
1750
|
-
isBalanceLoading,
|
|
1751
|
-
isProcessing,
|
|
1752
|
-
balanceLabel,
|
|
1753
|
-
canPay: Boolean(
|
|
1754
|
-
connected && tokenBalance?.hasBalance && !isProcessing
|
|
1755
|
-
),
|
|
1756
|
-
pay
|
|
1757
|
-
};
|
|
1758
|
-
};
|
|
1759
|
-
var Card = React3__namespace.forwardRef(
|
|
1760
|
-
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1761
|
-
"div",
|
|
1762
|
-
{
|
|
1763
|
-
ref,
|
|
1764
|
-
className: cn("rounded-xl border bg-card text-card-foreground shadow", className),
|
|
1765
|
-
...props
|
|
1766
|
-
}
|
|
1767
|
-
)
|
|
1768
|
-
);
|
|
1769
|
-
Card.displayName = "Card";
|
|
1770
|
-
var CardHeader = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1771
|
-
"div",
|
|
1772
|
-
{
|
|
1773
|
-
ref,
|
|
1774
|
-
className: cn("flex flex-col space-y-1.5 p-6", className),
|
|
1775
|
-
...props
|
|
1776
|
-
}
|
|
1777
|
-
));
|
|
1778
|
-
CardHeader.displayName = "CardHeader";
|
|
1779
|
-
var CardTitle = React3__namespace.forwardRef(
|
|
1780
|
-
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("h3", { ref, className: cn("text-2xl font-semibold leading-none tracking-tight", className), ...props })
|
|
1781
|
-
);
|
|
1782
|
-
CardTitle.displayName = "CardTitle";
|
|
1783
|
-
var CardDescription = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
|
|
1784
|
-
CardDescription.displayName = "CardDescription";
|
|
1785
|
-
var CardContent = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
|
|
1786
|
-
CardContent.displayName = "CardContent";
|
|
1787
|
-
var CardFooter = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1788
|
-
"div",
|
|
1789
|
-
{
|
|
1790
|
-
ref,
|
|
1791
|
-
className: cn("flex items-center p-6 pt-0", className),
|
|
1792
|
-
...props
|
|
1793
|
-
}
|
|
1794
|
-
));
|
|
1795
|
-
CardFooter.displayName = "CardFooter";
|
|
1796
|
-
var DirectPayment = ({
|
|
1797
|
-
priceId,
|
|
1798
|
-
tokenAmount,
|
|
1799
|
-
selectedToken,
|
|
1800
|
-
supportedTokens,
|
|
1801
|
-
onPaymentStart,
|
|
1802
|
-
onPaymentConfirming,
|
|
1803
|
-
onPaymentSuccess,
|
|
1804
|
-
onPaymentError
|
|
1805
|
-
}) => {
|
|
1806
|
-
const { isBalanceLoading, balanceLabel, canPay, isProcessing, pay } = useSolanaDirectPayment({
|
|
1807
|
-
priceId,
|
|
1808
|
-
tokenAmount,
|
|
1809
|
-
selectedToken,
|
|
1810
|
-
supportedTokens,
|
|
1811
|
-
onStart: onPaymentStart,
|
|
1812
|
-
onConfirming: onPaymentConfirming,
|
|
1813
|
-
onSuccess: onPaymentSuccess,
|
|
1814
|
-
onError: onPaymentError
|
|
1815
|
-
});
|
|
1816
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "space-y-4 rounded-md border border-border/60 bg-background/80 shadow-none p-6", children: [
|
|
1817
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
1818
|
-
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 text-sm font-semibold uppercase tracking-wide text-muted-foreground", children: [
|
|
1819
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { className: "h-4 w-4" }),
|
|
1820
|
-
" Pay with connected wallet"
|
|
1821
|
-
] }),
|
|
1822
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Sign the transaction directly in your Solana wallet." })
|
|
1823
|
-
] }),
|
|
1824
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between rounded-lg border border-border/50 bg-muted/10 px-4 py-3 text-sm", children: [
|
|
1825
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Available balance" }),
|
|
1826
|
-
isBalanceLoading ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }) : /* @__PURE__ */ jsxRuntime.jsx("strong", { className: "text-foreground", children: balanceLabel })
|
|
1827
|
-
] }),
|
|
1828
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1829
|
-
Button,
|
|
1830
|
-
{
|
|
1831
|
-
type: "button",
|
|
1832
|
-
className: "w-full",
|
|
1833
|
-
disabled: !canPay,
|
|
1834
|
-
onClick: pay,
|
|
1835
|
-
children: isProcessing ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1836
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
1837
|
-
" Processing\u2026"
|
|
1838
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1839
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { className: "mr-2 h-4 w-4" }),
|
|
1840
|
-
" Pay with wallet"
|
|
1841
|
-
] })
|
|
1842
|
-
}
|
|
1843
|
-
)
|
|
1844
|
-
] });
|
|
1845
|
-
};
|
|
1846
1141
|
var useSolanaQrPayment = (options) => {
|
|
1847
1142
|
const { priceId, selectedToken, onSuccess, onError } = options;
|
|
1848
|
-
const
|
|
1143
|
+
const { client } = usePaymentContext();
|
|
1849
1144
|
const tokenSymbol = selectedToken?.symbol ?? null;
|
|
1850
|
-
const onSuccessRef =
|
|
1851
|
-
const onErrorRef =
|
|
1852
|
-
const [intent, setIntent] =
|
|
1853
|
-
const [qrDataUri, setQrDataUri] =
|
|
1854
|
-
const [isLoading, setIsLoading] =
|
|
1855
|
-
const [error, setError] =
|
|
1856
|
-
const [timeRemaining, setTimeRemaining] =
|
|
1857
|
-
const [refreshNonce, setRefreshNonce] =
|
|
1858
|
-
const pollRef =
|
|
1859
|
-
const countdownRef =
|
|
1860
|
-
const clearTimers =
|
|
1145
|
+
const onSuccessRef = React17.useRef(onSuccess);
|
|
1146
|
+
const onErrorRef = React17.useRef(onError);
|
|
1147
|
+
const [intent, setIntent] = React17.useState(null);
|
|
1148
|
+
const [qrDataUri, setQrDataUri] = React17.useState(null);
|
|
1149
|
+
const [isLoading, setIsLoading] = React17.useState(false);
|
|
1150
|
+
const [error, setError] = React17.useState(null);
|
|
1151
|
+
const [timeRemaining, setTimeRemaining] = React17.useState(0);
|
|
1152
|
+
const [refreshNonce, setRefreshNonce] = React17.useState(0);
|
|
1153
|
+
const pollRef = React17.useRef(null);
|
|
1154
|
+
const countdownRef = React17.useRef(null);
|
|
1155
|
+
const clearTimers = React17.useCallback(() => {
|
|
1861
1156
|
if (pollRef.current) {
|
|
1862
1157
|
clearInterval(pollRef.current);
|
|
1863
1158
|
pollRef.current = null;
|
|
@@ -1867,12 +1162,12 @@ var useSolanaQrPayment = (options) => {
|
|
|
1867
1162
|
countdownRef.current = null;
|
|
1868
1163
|
}
|
|
1869
1164
|
}, []);
|
|
1870
|
-
|
|
1165
|
+
React17.useEffect(() => {
|
|
1871
1166
|
return () => {
|
|
1872
1167
|
clearTimers();
|
|
1873
1168
|
};
|
|
1874
1169
|
}, [clearTimers]);
|
|
1875
|
-
const resetState =
|
|
1170
|
+
const resetState = React17.useCallback(
|
|
1876
1171
|
(message) => {
|
|
1877
1172
|
clearTimers();
|
|
1878
1173
|
setIntent(null);
|
|
@@ -1882,13 +1177,13 @@ var useSolanaQrPayment = (options) => {
|
|
|
1882
1177
|
},
|
|
1883
1178
|
[clearTimers]
|
|
1884
1179
|
);
|
|
1885
|
-
|
|
1180
|
+
React17.useEffect(() => {
|
|
1886
1181
|
onSuccessRef.current = onSuccess;
|
|
1887
1182
|
}, [onSuccess]);
|
|
1888
|
-
|
|
1183
|
+
React17.useEffect(() => {
|
|
1889
1184
|
onErrorRef.current = onError;
|
|
1890
1185
|
}, [onError]);
|
|
1891
|
-
const handleError =
|
|
1186
|
+
const handleError = React17.useCallback(
|
|
1892
1187
|
(message, notifyParent = false) => {
|
|
1893
1188
|
console.error("[payments-ui] Solana Pay QR error:", message);
|
|
1894
1189
|
clearTimers();
|
|
@@ -1899,7 +1194,7 @@ var useSolanaQrPayment = (options) => {
|
|
|
1899
1194
|
},
|
|
1900
1195
|
[clearTimers, resetState]
|
|
1901
1196
|
);
|
|
1902
|
-
const handleSuccess =
|
|
1197
|
+
const handleSuccess = React17.useCallback(
|
|
1903
1198
|
(status) => {
|
|
1904
1199
|
clearTimers();
|
|
1905
1200
|
resetState(null);
|
|
@@ -1907,14 +1202,16 @@ var useSolanaQrPayment = (options) => {
|
|
|
1907
1202
|
paymentId: status.payment_id,
|
|
1908
1203
|
intentId: status.intent_id
|
|
1909
1204
|
});
|
|
1910
|
-
|
|
1205
|
+
const paymentId = status.payment_id ?? void 0;
|
|
1206
|
+
const txId = status.transaction ?? void 0;
|
|
1207
|
+
onSuccessRef.current?.(paymentId, txId);
|
|
1911
1208
|
},
|
|
1912
1209
|
[clearTimers, resetState]
|
|
1913
1210
|
);
|
|
1914
|
-
const pollStatus =
|
|
1211
|
+
const pollStatus = React17.useCallback(
|
|
1915
1212
|
async (reference) => {
|
|
1916
1213
|
try {
|
|
1917
|
-
const status = await
|
|
1214
|
+
const status = await client.getSolanaPayStatus(reference);
|
|
1918
1215
|
if (status.status === "confirmed") {
|
|
1919
1216
|
handleSuccess(status);
|
|
1920
1217
|
}
|
|
@@ -1928,9 +1225,9 @@ var useSolanaQrPayment = (options) => {
|
|
|
1928
1225
|
console.error("Failed to poll Solana Pay status:", err);
|
|
1929
1226
|
}
|
|
1930
1227
|
},
|
|
1931
|
-
[handleError, handleSuccess,
|
|
1228
|
+
[handleError, handleSuccess, client]
|
|
1932
1229
|
);
|
|
1933
|
-
const startCountdown =
|
|
1230
|
+
const startCountdown = React17.useCallback(
|
|
1934
1231
|
(expiresAt, reference) => {
|
|
1935
1232
|
const updateTime = () => {
|
|
1936
1233
|
const remaining = Math.max(0, Math.floor(expiresAt - Date.now() / 1e3));
|
|
@@ -1945,7 +1242,7 @@ var useSolanaQrPayment = (options) => {
|
|
|
1945
1242
|
},
|
|
1946
1243
|
[handleError, pollStatus]
|
|
1947
1244
|
);
|
|
1948
|
-
const renderQr =
|
|
1245
|
+
const renderQr = React17.useCallback(async (qrIntent) => {
|
|
1949
1246
|
try {
|
|
1950
1247
|
const dataUri = await QRCode__default.default.toDataURL(qrIntent.url, {
|
|
1951
1248
|
width: 320,
|
|
@@ -1961,7 +1258,7 @@ var useSolanaQrPayment = (options) => {
|
|
|
1961
1258
|
handleError("Unable to render QR code");
|
|
1962
1259
|
}
|
|
1963
1260
|
}, [handleError]);
|
|
1964
|
-
|
|
1261
|
+
React17.useEffect(() => {
|
|
1965
1262
|
let cancelled = false;
|
|
1966
1263
|
const generateIntent = async () => {
|
|
1967
1264
|
clearTimers();
|
|
@@ -1977,10 +1274,10 @@ var useSolanaQrPayment = (options) => {
|
|
|
1977
1274
|
priceId,
|
|
1978
1275
|
token: tokenSymbol
|
|
1979
1276
|
});
|
|
1980
|
-
const nextIntent = await
|
|
1277
|
+
const nextIntent = await client.createSolanaPayIntent({
|
|
1981
1278
|
priceId,
|
|
1982
|
-
tokenSymbol
|
|
1983
|
-
);
|
|
1279
|
+
token: tokenSymbol
|
|
1280
|
+
});
|
|
1984
1281
|
if (cancelled) return;
|
|
1985
1282
|
setIntent(nextIntent);
|
|
1986
1283
|
setTimeRemaining(
|
|
@@ -1990,8 +1287,13 @@ var useSolanaQrPayment = (options) => {
|
|
|
1990
1287
|
console.log("[payments-ui] Solana Pay QR ready", {
|
|
1991
1288
|
reference: nextIntent.reference
|
|
1992
1289
|
});
|
|
1993
|
-
|
|
1994
|
-
|
|
1290
|
+
const reference = nextIntent.reference;
|
|
1291
|
+
if (typeof reference === "string" && reference.length > 0) {
|
|
1292
|
+
startCountdown(nextIntent.expires_at, reference);
|
|
1293
|
+
pollStatus(reference);
|
|
1294
|
+
} else {
|
|
1295
|
+
handleError("Payment reference missing from intent", true);
|
|
1296
|
+
}
|
|
1995
1297
|
} catch (err) {
|
|
1996
1298
|
if (cancelled) return;
|
|
1997
1299
|
console.error("Failed to generate Solana Pay QR intent:", err);
|
|
@@ -2015,12 +1317,12 @@ var useSolanaQrPayment = (options) => {
|
|
|
2015
1317
|
priceId,
|
|
2016
1318
|
renderQr,
|
|
2017
1319
|
resetState,
|
|
2018
|
-
|
|
1320
|
+
client,
|
|
2019
1321
|
startCountdown,
|
|
2020
1322
|
tokenSymbol,
|
|
2021
1323
|
refreshNonce
|
|
2022
1324
|
]);
|
|
2023
|
-
const refresh =
|
|
1325
|
+
const refresh = React17.useCallback(() => {
|
|
2024
1326
|
setRefreshNonce((value) => value + 1);
|
|
2025
1327
|
}, []);
|
|
2026
1328
|
return {
|
|
@@ -2032,17 +1334,65 @@ var useSolanaQrPayment = (options) => {
|
|
|
2032
1334
|
refresh
|
|
2033
1335
|
};
|
|
2034
1336
|
};
|
|
1337
|
+
var Card = React17__namespace.forwardRef(
|
|
1338
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1339
|
+
"div",
|
|
1340
|
+
{
|
|
1341
|
+
ref,
|
|
1342
|
+
className: cn("rounded-xl border border-white/10 bg-[#161b22] text-white shadow", className),
|
|
1343
|
+
...props
|
|
1344
|
+
}
|
|
1345
|
+
)
|
|
1346
|
+
);
|
|
1347
|
+
Card.displayName = "Card";
|
|
1348
|
+
var CardHeader = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1349
|
+
"div",
|
|
1350
|
+
{
|
|
1351
|
+
ref,
|
|
1352
|
+
className: cn("flex flex-col space-y-1.5 p-6", className),
|
|
1353
|
+
...props
|
|
1354
|
+
}
|
|
1355
|
+
));
|
|
1356
|
+
CardHeader.displayName = "CardHeader";
|
|
1357
|
+
var CardTitle = React17__namespace.forwardRef(
|
|
1358
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("h3", { ref, className: cn("text-xl font-semibold leading-none tracking-tight text-white", className), ...props })
|
|
1359
|
+
);
|
|
1360
|
+
CardTitle.displayName = "CardTitle";
|
|
1361
|
+
var CardDescription = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn("text-sm text-white/60", className), ...props }));
|
|
1362
|
+
CardDescription.displayName = "CardDescription";
|
|
1363
|
+
var CardContent = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
|
|
1364
|
+
CardContent.displayName = "CardContent";
|
|
1365
|
+
var CardFooter = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1366
|
+
"div",
|
|
1367
|
+
{
|
|
1368
|
+
ref,
|
|
1369
|
+
className: cn("flex items-center p-6 pt-0", className),
|
|
1370
|
+
...props
|
|
1371
|
+
}
|
|
1372
|
+
));
|
|
1373
|
+
CardFooter.displayName = "CardFooter";
|
|
2035
1374
|
var QRCodePayment = ({
|
|
2036
1375
|
priceId,
|
|
2037
1376
|
selectedToken,
|
|
2038
1377
|
onPaymentError,
|
|
2039
1378
|
onPaymentSuccess
|
|
2040
1379
|
}) => {
|
|
1380
|
+
const handleQrSuccess = React17__namespace.default.useCallback(
|
|
1381
|
+
(paymentId, txId) => {
|
|
1382
|
+
if (!paymentId && !txId) {
|
|
1383
|
+
onPaymentError("Missing payment confirmation details");
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
const resolvedResult = paymentId ?? txId ?? "";
|
|
1387
|
+
onPaymentSuccess(resolvedResult, txId);
|
|
1388
|
+
},
|
|
1389
|
+
[onPaymentError, onPaymentSuccess]
|
|
1390
|
+
);
|
|
2041
1391
|
const { intent, qrDataUri, isLoading, error, timeRemaining, refresh } = useSolanaQrPayment({
|
|
2042
1392
|
priceId,
|
|
2043
1393
|
selectedToken,
|
|
2044
1394
|
onError: onPaymentError,
|
|
2045
|
-
onSuccess:
|
|
1395
|
+
onSuccess: handleQrSuccess
|
|
2046
1396
|
});
|
|
2047
1397
|
if (!selectedToken) {
|
|
2048
1398
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-dashed border-border/60 bg-muted/10 px-4 py-6 text-center text-sm text-muted-foreground", children: "Select a token to continue." });
|
|
@@ -2135,17 +1485,17 @@ var PaymentStatus = ({
|
|
|
2135
1485
|
return null;
|
|
2136
1486
|
};
|
|
2137
1487
|
var useSupportedTokens = () => {
|
|
2138
|
-
const
|
|
2139
|
-
const [tokens, setTokens] =
|
|
2140
|
-
const [isLoading, setIsLoading] =
|
|
2141
|
-
const [error, setError] =
|
|
2142
|
-
const [lastFetched, setLastFetched] =
|
|
1488
|
+
const { client } = usePaymentContext();
|
|
1489
|
+
const [tokens, setTokens] = React17.useState([]);
|
|
1490
|
+
const [isLoading, setIsLoading] = React17.useState(false);
|
|
1491
|
+
const [error, setError] = React17.useState(null);
|
|
1492
|
+
const [lastFetched, setLastFetched] = React17.useState(null);
|
|
2143
1493
|
const CACHE_DURATION = 5 * 60 * 1e3;
|
|
2144
|
-
const tokensRef =
|
|
2145
|
-
const lastFetchedRef =
|
|
1494
|
+
const tokensRef = React17.useRef(tokens);
|
|
1495
|
+
const lastFetchedRef = React17.useRef(lastFetched);
|
|
2146
1496
|
tokensRef.current = tokens;
|
|
2147
1497
|
lastFetchedRef.current = lastFetched;
|
|
2148
|
-
const fetchSupportedTokens =
|
|
1498
|
+
const fetchSupportedTokens = React17.useCallback(async () => {
|
|
2149
1499
|
if (tokensRef.current.length > 0 && lastFetchedRef.current && Date.now() - lastFetchedRef.current < CACHE_DURATION) {
|
|
2150
1500
|
return tokensRef.current;
|
|
2151
1501
|
}
|
|
@@ -2153,7 +1503,7 @@ var useSupportedTokens = () => {
|
|
|
2153
1503
|
setError(null);
|
|
2154
1504
|
try {
|
|
2155
1505
|
console.log("payments-ui: fetching supported Solana tokens");
|
|
2156
|
-
const tokens2 = await
|
|
1506
|
+
const tokens2 = await client.getSolanaTokens();
|
|
2157
1507
|
const sortedTokens = [...tokens2].sort(
|
|
2158
1508
|
(a, b) => a.symbol.localeCompare(b.symbol)
|
|
2159
1509
|
);
|
|
@@ -2171,51 +1521,51 @@ var useSupportedTokens = () => {
|
|
|
2171
1521
|
} finally {
|
|
2172
1522
|
setIsLoading(false);
|
|
2173
1523
|
}
|
|
2174
|
-
}, [
|
|
2175
|
-
|
|
1524
|
+
}, [client]);
|
|
1525
|
+
React17.useEffect(() => {
|
|
2176
1526
|
if (tokens.length === 0) {
|
|
2177
1527
|
fetchSupportedTokens();
|
|
2178
1528
|
}
|
|
2179
1529
|
}, [tokens.length, fetchSupportedTokens]);
|
|
2180
|
-
const getTokenBySymbol =
|
|
1530
|
+
const getTokenBySymbol = React17.useCallback(
|
|
2181
1531
|
(symbol) => {
|
|
2182
1532
|
return tokens.find((token) => token.symbol === symbol);
|
|
2183
1533
|
},
|
|
2184
1534
|
[tokens]
|
|
2185
1535
|
);
|
|
2186
|
-
const getTokenByMint =
|
|
1536
|
+
const getTokenByMint = React17.useCallback(
|
|
2187
1537
|
(mintAddress) => {
|
|
2188
1538
|
return tokens.find((token) => token.mint === mintAddress);
|
|
2189
1539
|
},
|
|
2190
1540
|
[tokens]
|
|
2191
1541
|
);
|
|
2192
|
-
const isTokenSupported =
|
|
1542
|
+
const isTokenSupported = React17.useCallback(
|
|
2193
1543
|
(symbol) => {
|
|
2194
1544
|
return tokens.some((token) => token.symbol === symbol);
|
|
2195
1545
|
},
|
|
2196
1546
|
[tokens]
|
|
2197
1547
|
);
|
|
2198
|
-
const getUSDCToken =
|
|
1548
|
+
const getUSDCToken = React17.useCallback(() => {
|
|
2199
1549
|
return getTokenBySymbol("USDC");
|
|
2200
1550
|
}, [getTokenBySymbol]);
|
|
2201
|
-
const getPYUSDToken =
|
|
1551
|
+
const getPYUSDToken = React17.useCallback(() => {
|
|
2202
1552
|
return getTokenBySymbol("PYUSD");
|
|
2203
1553
|
}, [getTokenBySymbol]);
|
|
2204
|
-
const getSOLToken =
|
|
1554
|
+
const getSOLToken = React17.useCallback(() => {
|
|
2205
1555
|
return getTokenBySymbol("SOL");
|
|
2206
1556
|
}, [getTokenBySymbol]);
|
|
2207
|
-
const getStablecoins =
|
|
1557
|
+
const getStablecoins = React17.useCallback(() => {
|
|
2208
1558
|
return tokens.filter((token) => ["USDC", "PYUSD"].includes(token.symbol));
|
|
2209
1559
|
}, [tokens]);
|
|
2210
|
-
const refreshTokens =
|
|
1560
|
+
const refreshTokens = React17.useCallback(async () => {
|
|
2211
1561
|
setLastFetched(null);
|
|
2212
1562
|
return await fetchSupportedTokens();
|
|
2213
1563
|
}, [fetchSupportedTokens]);
|
|
2214
|
-
const isCacheStale =
|
|
1564
|
+
const isCacheStale = React17.useCallback(() => {
|
|
2215
1565
|
if (!lastFetched) return true;
|
|
2216
1566
|
return Date.now() - lastFetched > CACHE_DURATION;
|
|
2217
1567
|
}, [lastFetched]);
|
|
2218
|
-
const getTokenDisplayInfo =
|
|
1568
|
+
const getTokenDisplayInfo = React17.useCallback((token) => {
|
|
2219
1569
|
return {
|
|
2220
1570
|
...token,
|
|
2221
1571
|
displayName: `${token.name} (${token.symbol})`,
|
|
@@ -2223,7 +1573,7 @@ var useSupportedTokens = () => {
|
|
|
2223
1573
|
decimalPlaces: token.decimals
|
|
2224
1574
|
};
|
|
2225
1575
|
}, []);
|
|
2226
|
-
const getTokenPrice =
|
|
1576
|
+
const getTokenPrice = React17.useCallback(
|
|
2227
1577
|
(symbol) => {
|
|
2228
1578
|
const token = getTokenBySymbol(symbol);
|
|
2229
1579
|
if (!token) return 0;
|
|
@@ -2232,7 +1582,7 @@ var useSupportedTokens = () => {
|
|
|
2232
1582
|
},
|
|
2233
1583
|
[getTokenBySymbol]
|
|
2234
1584
|
);
|
|
2235
|
-
const calculateTokenAmount =
|
|
1585
|
+
const calculateTokenAmount = React17.useCallback(
|
|
2236
1586
|
(usdAmount, tokenSymbol) => {
|
|
2237
1587
|
const token = getTokenBySymbol(tokenSymbol);
|
|
2238
1588
|
const price = getTokenPrice(tokenSymbol);
|
|
@@ -2243,7 +1593,7 @@ var useSupportedTokens = () => {
|
|
|
2243
1593
|
},
|
|
2244
1594
|
[getTokenBySymbol, getTokenPrice]
|
|
2245
1595
|
);
|
|
2246
|
-
const formatTokenAmount =
|
|
1596
|
+
const formatTokenAmount = React17.useCallback(
|
|
2247
1597
|
(amount, tokenSymbol) => {
|
|
2248
1598
|
const token = getTokenBySymbol(tokenSymbol);
|
|
2249
1599
|
if (!token) return "0";
|
|
@@ -2283,39 +1633,29 @@ var SolanaPaymentView = ({
|
|
|
2283
1633
|
onError,
|
|
2284
1634
|
onClose
|
|
2285
1635
|
}) => {
|
|
2286
|
-
const { connected } = walletAdapterReact.useWallet();
|
|
2287
1636
|
const { notifyStatus, notifyError, notifySuccess } = usePaymentNotifications();
|
|
2288
|
-
const [
|
|
2289
|
-
const [
|
|
2290
|
-
const [
|
|
2291
|
-
const [
|
|
2292
|
-
const [
|
|
2293
|
-
const [selectedTokenSymbol, setSelectedTokenSymbol] = React3.useState(null);
|
|
1637
|
+
const [paymentState, setPaymentState] = React17.useState("selecting");
|
|
1638
|
+
const [errorMessage, setErrorMessage] = React17.useState(null);
|
|
1639
|
+
const [transactionId, setTransactionId] = React17.useState(null);
|
|
1640
|
+
const [tokenAmount, setTokenAmount] = React17.useState(0);
|
|
1641
|
+
const [selectedTokenSymbol, setSelectedTokenSymbol] = React17.useState(null);
|
|
2294
1642
|
const {
|
|
2295
1643
|
tokens,
|
|
2296
1644
|
isLoading: tokensLoading,
|
|
2297
1645
|
error: tokensError
|
|
2298
1646
|
} = useSupportedTokens();
|
|
2299
|
-
const selectedToken =
|
|
1647
|
+
const selectedToken = React17.useMemo(() => {
|
|
2300
1648
|
if (!tokens.length) return null;
|
|
2301
1649
|
const explicit = tokens.find((token) => token.symbol === selectedTokenSymbol);
|
|
2302
1650
|
return explicit || tokens[0];
|
|
2303
1651
|
}, [tokens, selectedTokenSymbol]);
|
|
2304
|
-
|
|
1652
|
+
React17.useEffect(() => {
|
|
2305
1653
|
if (!selectedTokenSymbol && tokens.length) {
|
|
2306
1654
|
const defaultToken = tokens.find((token) => token.symbol === "SOL") || tokens[0];
|
|
2307
1655
|
setSelectedTokenSymbol(defaultToken.symbol);
|
|
2308
1656
|
}
|
|
2309
1657
|
}, [tokens, selectedTokenSymbol]);
|
|
2310
|
-
const
|
|
2311
|
-
setPaymentState("processing");
|
|
2312
|
-
setErrorMessage(null);
|
|
2313
|
-
notifyStatus("processing", { source: "solana" });
|
|
2314
|
-
}, [notifyStatus]);
|
|
2315
|
-
const handlePaymentConfirming = React3.useCallback(() => {
|
|
2316
|
-
setPaymentState("confirming");
|
|
2317
|
-
}, []);
|
|
2318
|
-
const handlePaymentSuccess = React3.useCallback(
|
|
1658
|
+
const handlePaymentSuccess = React17.useCallback(
|
|
2319
1659
|
(result, txId) => {
|
|
2320
1660
|
const resolvedTx = txId || (typeof result === "string" ? result : result.transaction_id);
|
|
2321
1661
|
setTransactionId(resolvedTx);
|
|
@@ -2343,7 +1683,7 @@ var SolanaPaymentView = ({
|
|
|
2343
1683
|
},
|
|
2344
1684
|
[notifyStatus, notifySuccess, onSuccess]
|
|
2345
1685
|
);
|
|
2346
|
-
const handlePaymentError =
|
|
1686
|
+
const handlePaymentError = React17.useCallback(
|
|
2347
1687
|
(error) => {
|
|
2348
1688
|
setPaymentState("error");
|
|
2349
1689
|
setErrorMessage(error);
|
|
@@ -2353,22 +1693,22 @@ var SolanaPaymentView = ({
|
|
|
2353
1693
|
},
|
|
2354
1694
|
[notifyError, notifyStatus, onError]
|
|
2355
1695
|
);
|
|
2356
|
-
const resetState =
|
|
1696
|
+
const resetState = React17.useCallback(() => {
|
|
2357
1697
|
setPaymentState("selecting");
|
|
2358
1698
|
setErrorMessage(null);
|
|
2359
1699
|
setTransactionId(null);
|
|
2360
1700
|
}, []);
|
|
2361
|
-
const handleRetry =
|
|
1701
|
+
const handleRetry = React17.useCallback(() => {
|
|
2362
1702
|
resetState();
|
|
2363
1703
|
}, [resetState]);
|
|
2364
|
-
const handleClose =
|
|
1704
|
+
const handleClose = React17.useCallback(() => {
|
|
2365
1705
|
if (paymentState === "processing" || paymentState === "confirming") {
|
|
2366
1706
|
return;
|
|
2367
1707
|
}
|
|
2368
1708
|
resetState();
|
|
2369
1709
|
onClose?.();
|
|
2370
1710
|
}, [paymentState, onClose, resetState]);
|
|
2371
|
-
|
|
1711
|
+
React17.useEffect(() => {
|
|
2372
1712
|
if (!selectedToken || usdAmount === 0) {
|
|
2373
1713
|
setTokenAmount(0);
|
|
2374
1714
|
return;
|
|
@@ -2380,19 +1720,9 @@ var SolanaPaymentView = ({
|
|
|
2380
1720
|
}
|
|
2381
1721
|
setTokenAmount(usdAmount / price);
|
|
2382
1722
|
}, [usdAmount, selectedToken]);
|
|
2383
|
-
const handleTokenChange =
|
|
1723
|
+
const handleTokenChange = React17.useCallback((value) => {
|
|
2384
1724
|
setSelectedTokenSymbol(value);
|
|
2385
1725
|
}, []);
|
|
2386
|
-
const wasConnectedRef = React3.useRef(connected);
|
|
2387
|
-
React3.useEffect(() => {
|
|
2388
|
-
if (connected && !wasConnectedRef.current) {
|
|
2389
|
-
setActiveTab("wallet");
|
|
2390
|
-
}
|
|
2391
|
-
if (!connected && wasConnectedRef.current) {
|
|
2392
|
-
setActiveTab("qr");
|
|
2393
|
-
}
|
|
2394
|
-
wasConnectedRef.current = connected;
|
|
2395
|
-
}, [connected]);
|
|
2396
1726
|
const renderBody = () => {
|
|
2397
1727
|
if (paymentState !== "selecting") {
|
|
2398
1728
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2447,51 +1777,15 @@ var SolanaPaymentView = ({
|
|
|
2447
1777
|
] }, token.symbol)) })
|
|
2448
1778
|
] })
|
|
2449
1779
|
] }),
|
|
2450
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2451
|
-
|
|
1780
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1781
|
+
QRCodePayment,
|
|
2452
1782
|
{
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TabsList, { className: "grid w-full grid-cols-2 bg-muted/10", children: [
|
|
2458
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TabsTrigger, { value: "wallet", disabled: !connected, children: [
|
|
2459
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { className: "mr-2 h-4 w-4" }),
|
|
2460
|
-
" Wallet"
|
|
2461
|
-
] }),
|
|
2462
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TabsTrigger, { value: "qr", children: [
|
|
2463
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "mr-2 h-4 w-4" }),
|
|
2464
|
-
" QR Code"
|
|
2465
|
-
] })
|
|
2466
|
-
] }),
|
|
2467
|
-
/* @__PURE__ */ jsxRuntime.jsxs(TabsContent, { value: "wallet", className: "space-y-4", children: [
|
|
2468
|
-
activeTab === "wallet" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2469
|
-
DirectPayment,
|
|
2470
|
-
{
|
|
2471
|
-
priceId,
|
|
2472
|
-
tokenAmount,
|
|
2473
|
-
selectedToken,
|
|
2474
|
-
supportedTokens: tokens,
|
|
2475
|
-
onPaymentStart: handlePaymentStart,
|
|
2476
|
-
onPaymentConfirming: handlePaymentConfirming,
|
|
2477
|
-
onPaymentSuccess: handlePaymentSuccess,
|
|
2478
|
-
onPaymentError: handlePaymentError
|
|
2479
|
-
}
|
|
2480
|
-
),
|
|
2481
|
-
!connected && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-amber-100", children: "Connect your Solana wallet to continue or switch to QR mode." })
|
|
2482
|
-
] }),
|
|
2483
|
-
/* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "qr", children: activeTab === "qr" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2484
|
-
QRCodePayment,
|
|
2485
|
-
{
|
|
2486
|
-
priceId,
|
|
2487
|
-
selectedToken,
|
|
2488
|
-
onPaymentError: handlePaymentError,
|
|
2489
|
-
onPaymentSuccess: handlePaymentSuccess
|
|
2490
|
-
}
|
|
2491
|
-
) })
|
|
2492
|
-
]
|
|
1783
|
+
priceId,
|
|
1784
|
+
selectedToken,
|
|
1785
|
+
onPaymentError: handlePaymentError,
|
|
1786
|
+
onPaymentSuccess: handlePaymentSuccess
|
|
2493
1787
|
}
|
|
2494
|
-
)
|
|
1788
|
+
)
|
|
2495
1789
|
] });
|
|
2496
1790
|
};
|
|
2497
1791
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
|
|
@@ -2499,7 +1793,7 @@ var SolanaPaymentView = ({
|
|
|
2499
1793
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
2500
1794
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs uppercase tracking-wide text-muted-foreground", children: "Solana Pay checkout" }),
|
|
2501
1795
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-2xl font-semibold text-foreground", children: "Pay with Solana" }),
|
|
2502
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Choose a supported token and send the payment
|
|
1796
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Choose a supported token and send the payment via Solana Pay QR code." })
|
|
2503
1797
|
] }),
|
|
2504
1798
|
onClose && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2505
1799
|
Button,
|
|
@@ -2520,143 +1814,6 @@ var SolanaPaymentView = ({
|
|
|
2520
1814
|
renderBody()
|
|
2521
1815
|
] });
|
|
2522
1816
|
};
|
|
2523
|
-
var useSubscriptionActions = () => {
|
|
2524
|
-
const { services } = usePaymentContext();
|
|
2525
|
-
const ensurePrice = (priceId) => {
|
|
2526
|
-
if (!priceId) {
|
|
2527
|
-
throw new Error("payments-ui: priceId is required for subscription actions");
|
|
2528
|
-
}
|
|
2529
|
-
return priceId;
|
|
2530
|
-
};
|
|
2531
|
-
const subscribeWithCard = React3.useCallback(
|
|
2532
|
-
async ({
|
|
2533
|
-
priceId,
|
|
2534
|
-
processor = "nmi",
|
|
2535
|
-
provider,
|
|
2536
|
-
paymentToken,
|
|
2537
|
-
billing
|
|
2538
|
-
}) => {
|
|
2539
|
-
const payload = {
|
|
2540
|
-
priceId: ensurePrice(priceId),
|
|
2541
|
-
paymentToken,
|
|
2542
|
-
processor,
|
|
2543
|
-
provider,
|
|
2544
|
-
email: billing.email,
|
|
2545
|
-
firstName: billing.firstName,
|
|
2546
|
-
lastName: billing.lastName,
|
|
2547
|
-
address1: billing.address1,
|
|
2548
|
-
city: billing.city,
|
|
2549
|
-
state: billing.stateRegion,
|
|
2550
|
-
zipCode: billing.postalCode,
|
|
2551
|
-
country: billing.country
|
|
2552
|
-
};
|
|
2553
|
-
return services.subscriptions.subscribe("nmi", payload);
|
|
2554
|
-
},
|
|
2555
|
-
[services]
|
|
2556
|
-
);
|
|
2557
|
-
const subscribeWithSavedMethod = React3.useCallback(
|
|
2558
|
-
async ({
|
|
2559
|
-
priceId,
|
|
2560
|
-
processor = "nmi",
|
|
2561
|
-
provider,
|
|
2562
|
-
paymentMethodId,
|
|
2563
|
-
email
|
|
2564
|
-
}) => {
|
|
2565
|
-
const payload = {
|
|
2566
|
-
priceId: ensurePrice(priceId),
|
|
2567
|
-
paymentMethodId,
|
|
2568
|
-
processor,
|
|
2569
|
-
provider,
|
|
2570
|
-
email
|
|
2571
|
-
};
|
|
2572
|
-
return services.subscriptions.subscribe("nmi", payload);
|
|
2573
|
-
},
|
|
2574
|
-
[services]
|
|
2575
|
-
);
|
|
2576
|
-
const subscribeWithCCBill = React3.useCallback(
|
|
2577
|
-
async ({
|
|
2578
|
-
priceId,
|
|
2579
|
-
email,
|
|
2580
|
-
firstName,
|
|
2581
|
-
lastName,
|
|
2582
|
-
zipCode,
|
|
2583
|
-
country,
|
|
2584
|
-
processor = "ccbill"
|
|
2585
|
-
}) => {
|
|
2586
|
-
const payload = {
|
|
2587
|
-
priceId: ensurePrice(priceId),
|
|
2588
|
-
email,
|
|
2589
|
-
firstName,
|
|
2590
|
-
lastName,
|
|
2591
|
-
zipCode,
|
|
2592
|
-
country,
|
|
2593
|
-
processor
|
|
2594
|
-
};
|
|
2595
|
-
return services.subscriptions.subscribe("ccbill", payload);
|
|
2596
|
-
},
|
|
2597
|
-
[services]
|
|
2598
|
-
);
|
|
2599
|
-
const generateFlexFormUrl = React3.useCallback(
|
|
2600
|
-
async ({
|
|
2601
|
-
priceId,
|
|
2602
|
-
firstName,
|
|
2603
|
-
lastName,
|
|
2604
|
-
address1,
|
|
2605
|
-
city,
|
|
2606
|
-
state,
|
|
2607
|
-
zipCode,
|
|
2608
|
-
country
|
|
2609
|
-
}) => {
|
|
2610
|
-
const payload = {
|
|
2611
|
-
price_id: ensurePrice(priceId),
|
|
2612
|
-
first_name: firstName,
|
|
2613
|
-
last_name: lastName,
|
|
2614
|
-
address1,
|
|
2615
|
-
city,
|
|
2616
|
-
state,
|
|
2617
|
-
zip_code: zipCode,
|
|
2618
|
-
country
|
|
2619
|
-
};
|
|
2620
|
-
return services.subscriptions.generateFlexFormUrl(payload);
|
|
2621
|
-
},
|
|
2622
|
-
[services]
|
|
2623
|
-
);
|
|
2624
|
-
return {
|
|
2625
|
-
subscribeWithCard,
|
|
2626
|
-
subscribeWithSavedMethod,
|
|
2627
|
-
subscribeWithCCBill,
|
|
2628
|
-
generateFlexFormUrl
|
|
2629
|
-
};
|
|
2630
|
-
};
|
|
2631
|
-
|
|
2632
|
-
// src/hooks/useAlternativePaymentProvider.ts
|
|
2633
|
-
var useAlternativePaymentProvider = () => {
|
|
2634
|
-
const [isLoading, setIsLoading] = React3.useState(false);
|
|
2635
|
-
const [error, setError] = React3.useState(null);
|
|
2636
|
-
const { generateFlexFormUrl } = useSubscriptionActions();
|
|
2637
|
-
const openFlexForm = React3.useCallback(
|
|
2638
|
-
async (payload) => {
|
|
2639
|
-
setIsLoading(true);
|
|
2640
|
-
setError(null);
|
|
2641
|
-
try {
|
|
2642
|
-
const response = await generateFlexFormUrl(payload);
|
|
2643
|
-
if (response?.iframe_url) {
|
|
2644
|
-
window.location.href = response.iframe_url;
|
|
2645
|
-
} else {
|
|
2646
|
-
throw new Error("Unable to launch payment provider.");
|
|
2647
|
-
}
|
|
2648
|
-
} catch (err) {
|
|
2649
|
-
const message = err instanceof Error ? err.message : "Failed to open payment provider.";
|
|
2650
|
-
setError(message);
|
|
2651
|
-
console.error("[payments-ui] failed to open alternative payment provider", err);
|
|
2652
|
-
} finally {
|
|
2653
|
-
setIsLoading(false);
|
|
2654
|
-
}
|
|
2655
|
-
},
|
|
2656
|
-
[generateFlexFormUrl]
|
|
2657
|
-
);
|
|
2658
|
-
return { openFlexForm, isLoading, error };
|
|
2659
|
-
};
|
|
2660
1817
|
var PaymentExperience = ({
|
|
2661
1818
|
priceId,
|
|
2662
1819
|
usdAmount,
|
|
@@ -2665,7 +1822,6 @@ var PaymentExperience = ({
|
|
|
2665
1822
|
enableNewCard = true,
|
|
2666
1823
|
enableStoredMethods = true,
|
|
2667
1824
|
enableSolanaPay = true,
|
|
2668
|
-
enableAlternativePayments = true,
|
|
2669
1825
|
onSolanaSuccess,
|
|
2670
1826
|
onSolanaError,
|
|
2671
1827
|
initialMode = "cards"
|
|
@@ -2673,27 +1829,20 @@ var PaymentExperience = ({
|
|
|
2673
1829
|
const showNewCard = enableNewCard && Boolean(onNewCardPayment);
|
|
2674
1830
|
const showStored = enableStoredMethods && Boolean(onSavedMethodPayment);
|
|
2675
1831
|
const defaultTab = showStored ? "saved" : "new";
|
|
2676
|
-
const [activeTab, setActiveTab] =
|
|
2677
|
-
const [mode, setMode] =
|
|
1832
|
+
const [activeTab, setActiveTab] = React17.useState(defaultTab);
|
|
1833
|
+
const [mode, setMode] = React17.useState(
|
|
2678
1834
|
() => initialMode === "solana" && enableSolanaPay ? "solana" : "cards"
|
|
2679
1835
|
);
|
|
2680
|
-
const [selectedMethodId, setSelectedMethodId] =
|
|
2681
|
-
const [savedStatus, setSavedStatus] =
|
|
2682
|
-
const [savedError, setSavedError] =
|
|
2683
|
-
const [newCardStatus, setNewCardStatus] =
|
|
2684
|
-
const [newCardError, setNewCardError] =
|
|
2685
|
-
const [billingDetails, setBillingDetails] = React3.useState(null);
|
|
2686
|
-
const [alternativePaymentError, setAlternativePaymentError] = React3.useState(null);
|
|
1836
|
+
const [selectedMethodId, setSelectedMethodId] = React17.useState(null);
|
|
1837
|
+
const [savedStatus, setSavedStatus] = React17.useState("idle");
|
|
1838
|
+
const [savedError, setSavedError] = React17.useState(null);
|
|
1839
|
+
const [newCardStatus, setNewCardStatus] = React17.useState("idle");
|
|
1840
|
+
const [newCardError, setNewCardError] = React17.useState(null);
|
|
2687
1841
|
const { notifyStatus, notifySuccess, notifyError } = usePaymentNotifications();
|
|
2688
|
-
|
|
2689
|
-
openFlexForm,
|
|
2690
|
-
isLoading: flexFormLoading,
|
|
2691
|
-
error: flexFormError
|
|
2692
|
-
} = useAlternativePaymentProvider();
|
|
2693
|
-
React3.useEffect(() => {
|
|
1842
|
+
React17.useEffect(() => {
|
|
2694
1843
|
setActiveTab(showStored ? "saved" : "new");
|
|
2695
1844
|
}, [showStored]);
|
|
2696
|
-
|
|
1845
|
+
React17.useEffect(() => {
|
|
2697
1846
|
if (!enableSolanaPay) {
|
|
2698
1847
|
setMode("cards");
|
|
2699
1848
|
return;
|
|
@@ -2704,12 +1853,12 @@ var PaymentExperience = ({
|
|
|
2704
1853
|
setMode("cards");
|
|
2705
1854
|
}
|
|
2706
1855
|
}, [enableSolanaPay, initialMode]);
|
|
2707
|
-
const handleMethodSelect =
|
|
1856
|
+
const handleMethodSelect = React17.useCallback((method) => {
|
|
2708
1857
|
setSelectedMethodId(method.id);
|
|
2709
1858
|
setSavedStatus("idle");
|
|
2710
1859
|
setSavedError(null);
|
|
2711
1860
|
}, []);
|
|
2712
|
-
const handleSavedPayment =
|
|
1861
|
+
const handleSavedPayment = React17.useCallback(async () => {
|
|
2713
1862
|
if (!onSavedMethodPayment || !selectedMethodId) return;
|
|
2714
1863
|
try {
|
|
2715
1864
|
setSavedStatus("processing");
|
|
@@ -2729,7 +1878,7 @@ var PaymentExperience = ({
|
|
|
2729
1878
|
notifyError(message);
|
|
2730
1879
|
}
|
|
2731
1880
|
}, [notifyError, notifyStatus, onSavedMethodPayment, selectedMethodId, usdAmount]);
|
|
2732
|
-
const handleNewCardTokenize =
|
|
1881
|
+
const handleNewCardTokenize = React17.useCallback(
|
|
2733
1882
|
async (token, billing) => {
|
|
2734
1883
|
if (!onNewCardPayment) return;
|
|
2735
1884
|
try {
|
|
@@ -2749,68 +1898,26 @@ var PaymentExperience = ({
|
|
|
2749
1898
|
},
|
|
2750
1899
|
[notifyError, notifyStatus, onNewCardPayment]
|
|
2751
1900
|
);
|
|
2752
|
-
const showSolanaView =
|
|
1901
|
+
const showSolanaView = React17.useCallback(() => {
|
|
2753
1902
|
if (!enableSolanaPay) return;
|
|
2754
1903
|
setMode("solana");
|
|
2755
1904
|
}, [enableSolanaPay]);
|
|
2756
|
-
const exitSolanaView =
|
|
1905
|
+
const exitSolanaView = React17.useCallback(() => {
|
|
2757
1906
|
setMode("cards");
|
|
2758
1907
|
}, []);
|
|
2759
|
-
const handleSolanaSuccess =
|
|
1908
|
+
const handleSolanaSuccess = React17.useCallback(
|
|
2760
1909
|
(result) => {
|
|
2761
1910
|
onSolanaSuccess?.(result);
|
|
2762
1911
|
exitSolanaView();
|
|
2763
1912
|
},
|
|
2764
1913
|
[exitSolanaView, onSolanaSuccess]
|
|
2765
1914
|
);
|
|
2766
|
-
const handleSolanaError =
|
|
1915
|
+
const handleSolanaError = React17.useCallback(
|
|
2767
1916
|
(error) => {
|
|
2768
1917
|
onSolanaError?.(error);
|
|
2769
1918
|
},
|
|
2770
1919
|
[onSolanaError]
|
|
2771
1920
|
);
|
|
2772
|
-
const handleAlternativePayment = React3.useCallback(() => {
|
|
2773
|
-
if (!enableAlternativePayments || !priceId) {
|
|
2774
|
-
return;
|
|
2775
|
-
}
|
|
2776
|
-
if (!billingDetails) {
|
|
2777
|
-
setAlternativePaymentError("Enter your billing details first.");
|
|
2778
|
-
return;
|
|
2779
|
-
}
|
|
2780
|
-
const requiredFields = [
|
|
2781
|
-
"firstName",
|
|
2782
|
-
"lastName",
|
|
2783
|
-
"address1",
|
|
2784
|
-
"city",
|
|
2785
|
-
"stateRegion",
|
|
2786
|
-
"postalCode",
|
|
2787
|
-
"country"
|
|
2788
|
-
];
|
|
2789
|
-
const missingField = requiredFields.find((field) => {
|
|
2790
|
-
const value = billingDetails[field];
|
|
2791
|
-
return typeof value !== "string" || value.trim().length === 0;
|
|
2792
|
-
});
|
|
2793
|
-
if (missingField) {
|
|
2794
|
-
setAlternativePaymentError("Please complete your billing address before continuing.");
|
|
2795
|
-
return;
|
|
2796
|
-
}
|
|
2797
|
-
setAlternativePaymentError(null);
|
|
2798
|
-
openFlexForm({
|
|
2799
|
-
priceId,
|
|
2800
|
-
firstName: billingDetails.firstName,
|
|
2801
|
-
lastName: billingDetails.lastName,
|
|
2802
|
-
address1: billingDetails.address1,
|
|
2803
|
-
city: billingDetails.city,
|
|
2804
|
-
state: billingDetails.stateRegion ?? "",
|
|
2805
|
-
zipCode: billingDetails.postalCode,
|
|
2806
|
-
country: billingDetails.country
|
|
2807
|
-
});
|
|
2808
|
-
}, [
|
|
2809
|
-
billingDetails,
|
|
2810
|
-
enableAlternativePayments,
|
|
2811
|
-
openFlexForm,
|
|
2812
|
-
priceId
|
|
2813
|
-
]);
|
|
2814
1921
|
const renderSavedTab = () => {
|
|
2815
1922
|
if (!showStored) {
|
|
2816
1923
|
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Saved payment methods are unavailable right now. Add a new card to get started." });
|
|
@@ -2849,8 +1956,7 @@ var PaymentExperience = ({
|
|
|
2849
1956
|
submitLabel: "Pay now",
|
|
2850
1957
|
externalError: newCardError,
|
|
2851
1958
|
onTokenize: handleNewCardTokenize,
|
|
2852
|
-
submitting: newCardStatus === "processing"
|
|
2853
|
-
onBillingChange: setBillingDetails
|
|
1959
|
+
submitting: newCardStatus === "processing"
|
|
2854
1960
|
}
|
|
2855
1961
|
);
|
|
2856
1962
|
};
|
|
@@ -2878,19 +1984,6 @@ var PaymentExperience = ({
|
|
|
2878
1984
|
] });
|
|
2879
1985
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6 pt-4", children: [
|
|
2880
1986
|
mode === "cards" && renderCardExperience(),
|
|
2881
|
-
mode === "cards" && enableAlternativePayments && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 text-center text-sm text-muted-foreground", children: [
|
|
2882
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2883
|
-
"button",
|
|
2884
|
-
{
|
|
2885
|
-
type: "button",
|
|
2886
|
-
className: "text-primary underline-offset-4 hover:underline disabled:opacity-60",
|
|
2887
|
-
onClick: handleAlternativePayment,
|
|
2888
|
-
disabled: flexFormLoading || !priceId,
|
|
2889
|
-
children: flexFormLoading ? "Preparing alternative checkout\u2026" : "Prefer a different processor? Pay with CCBill"
|
|
2890
|
-
}
|
|
2891
|
-
),
|
|
2892
|
-
(alternativePaymentError || flexFormError) && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive", children: alternativePaymentError || flexFormError })
|
|
2893
|
-
] }),
|
|
2894
1987
|
mode === "solana" && enableSolanaPay && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2895
1988
|
SolanaPaymentView,
|
|
2896
1989
|
{
|
|
@@ -2931,6 +2024,88 @@ var SubscriptionSuccessDialog = ({
|
|
|
2931
2024
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-6", children: /* @__PURE__ */ jsxRuntime.jsx(Button, { className: "w-full", onClick: onClose, children: "Continue exploring" }) })
|
|
2932
2025
|
] }) });
|
|
2933
2026
|
};
|
|
2027
|
+
var useSubscriptionActions = () => {
|
|
2028
|
+
const { client } = usePaymentContext();
|
|
2029
|
+
const ensurePrice = (priceId) => {
|
|
2030
|
+
if (!priceId) {
|
|
2031
|
+
throw new Error("payments-ui: priceId is required for subscription actions");
|
|
2032
|
+
}
|
|
2033
|
+
return priceId;
|
|
2034
|
+
};
|
|
2035
|
+
const subscribeWithCard = React17.useCallback(
|
|
2036
|
+
async ({
|
|
2037
|
+
priceId,
|
|
2038
|
+
processor = "nmi",
|
|
2039
|
+
provider,
|
|
2040
|
+
paymentToken,
|
|
2041
|
+
billing
|
|
2042
|
+
}) => {
|
|
2043
|
+
const payload = {
|
|
2044
|
+
price_id: ensurePrice(priceId),
|
|
2045
|
+
processor,
|
|
2046
|
+
provider,
|
|
2047
|
+
payment_token: paymentToken,
|
|
2048
|
+
email: billing.email,
|
|
2049
|
+
first_name: billing.firstName,
|
|
2050
|
+
last_name: billing.lastName,
|
|
2051
|
+
address1: billing.address1,
|
|
2052
|
+
city: billing.city,
|
|
2053
|
+
state: billing.stateRegion,
|
|
2054
|
+
zip: billing.postalCode,
|
|
2055
|
+
country: billing.country
|
|
2056
|
+
};
|
|
2057
|
+
return client.checkout(payload);
|
|
2058
|
+
},
|
|
2059
|
+
[client]
|
|
2060
|
+
);
|
|
2061
|
+
const subscribeWithSavedMethod = React17.useCallback(
|
|
2062
|
+
async ({
|
|
2063
|
+
priceId,
|
|
2064
|
+
processor = "nmi",
|
|
2065
|
+
provider,
|
|
2066
|
+
paymentMethodId,
|
|
2067
|
+
email
|
|
2068
|
+
}) => {
|
|
2069
|
+
const payload = {
|
|
2070
|
+
price_id: ensurePrice(priceId),
|
|
2071
|
+
processor,
|
|
2072
|
+
provider,
|
|
2073
|
+
payment_method_id: paymentMethodId,
|
|
2074
|
+
email
|
|
2075
|
+
};
|
|
2076
|
+
return client.checkout(payload);
|
|
2077
|
+
},
|
|
2078
|
+
[client]
|
|
2079
|
+
);
|
|
2080
|
+
const subscribeWithCCBill = React17.useCallback(
|
|
2081
|
+
async ({
|
|
2082
|
+
priceId,
|
|
2083
|
+
email,
|
|
2084
|
+
firstName,
|
|
2085
|
+
lastName,
|
|
2086
|
+
zipCode,
|
|
2087
|
+
country,
|
|
2088
|
+
processor = "ccbill"
|
|
2089
|
+
}) => {
|
|
2090
|
+
const payload = {
|
|
2091
|
+
price_id: ensurePrice(priceId),
|
|
2092
|
+
processor,
|
|
2093
|
+
email,
|
|
2094
|
+
first_name: firstName,
|
|
2095
|
+
last_name: lastName,
|
|
2096
|
+
zip: zipCode,
|
|
2097
|
+
country
|
|
2098
|
+
};
|
|
2099
|
+
return client.checkout(payload);
|
|
2100
|
+
},
|
|
2101
|
+
[client]
|
|
2102
|
+
);
|
|
2103
|
+
return {
|
|
2104
|
+
subscribeWithCard,
|
|
2105
|
+
subscribeWithSavedMethod,
|
|
2106
|
+
subscribeWithCCBill
|
|
2107
|
+
};
|
|
2108
|
+
};
|
|
2934
2109
|
var SubscriptionCheckoutModal = ({
|
|
2935
2110
|
open,
|
|
2936
2111
|
onOpenChange,
|
|
@@ -2947,9 +2122,9 @@ var SubscriptionCheckoutModal = ({
|
|
|
2947
2122
|
onSolanaError,
|
|
2948
2123
|
initialMode = "cards"
|
|
2949
2124
|
}) => {
|
|
2950
|
-
const [showSuccess, setShowSuccess] =
|
|
2125
|
+
const [showSuccess, setShowSuccess] = React17.useState(false);
|
|
2951
2126
|
const { subscribeWithCard, subscribeWithSavedMethod } = useSubscriptionActions();
|
|
2952
|
-
const handleClose =
|
|
2127
|
+
const handleClose = React17.useCallback(
|
|
2953
2128
|
(nextOpen) => {
|
|
2954
2129
|
onOpenChange(nextOpen);
|
|
2955
2130
|
if (!nextOpen) setShowSuccess(false);
|
|
@@ -2967,22 +2142,32 @@ var SubscriptionCheckoutModal = ({
|
|
|
2967
2142
|
console.debug("[payments-ui] subscription success", result);
|
|
2968
2143
|
}
|
|
2969
2144
|
};
|
|
2145
|
+
const assertCheckoutSuccess = (status, message) => {
|
|
2146
|
+
if (status === "blocked") {
|
|
2147
|
+
throw new Error(message || "This subscription cannot be completed right now.");
|
|
2148
|
+
}
|
|
2149
|
+
if (status === "redirect_required") {
|
|
2150
|
+
throw new Error(message || "Additional action required in an alternate flow.");
|
|
2151
|
+
}
|
|
2152
|
+
};
|
|
2970
2153
|
const handleNewCardPayment = async ({ token, billing }) => {
|
|
2971
|
-
await subscribeWithCard({
|
|
2154
|
+
const response = await subscribeWithCard({
|
|
2972
2155
|
priceId: ensurePrice(),
|
|
2973
2156
|
provider,
|
|
2974
2157
|
paymentToken: token,
|
|
2975
2158
|
billing
|
|
2976
2159
|
});
|
|
2160
|
+
assertCheckoutSuccess(response.status, response.message);
|
|
2977
2161
|
notifySuccess();
|
|
2978
2162
|
};
|
|
2979
2163
|
const handleSavedMethodPayment = async ({ paymentMethodId }) => {
|
|
2980
|
-
await subscribeWithSavedMethod({
|
|
2164
|
+
const response = await subscribeWithSavedMethod({
|
|
2981
2165
|
priceId: ensurePrice(),
|
|
2982
2166
|
provider,
|
|
2983
2167
|
paymentMethodId,
|
|
2984
2168
|
email: userEmail ?? ""
|
|
2985
2169
|
});
|
|
2170
|
+
assertCheckoutSuccess(response.status, response.message);
|
|
2986
2171
|
notifySuccess();
|
|
2987
2172
|
};
|
|
2988
2173
|
const solanaSuccess = (result) => {
|
|
@@ -2994,27 +2179,33 @@ var SubscriptionCheckoutModal = ({
|
|
|
2994
2179
|
onSolanaError?.(error);
|
|
2995
2180
|
};
|
|
2996
2181
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2997
|
-
/* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
"
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
2182
|
+
/* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2183
|
+
DialogContent,
|
|
2184
|
+
{
|
|
2185
|
+
className: "max-w-3xl max-h-[90vh] overflow-y-auto p-0 [&::-webkit-scrollbar]:hidden",
|
|
2186
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6 space-y-6", children: [
|
|
2187
|
+
!priceId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: [
|
|
2188
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-4 w-4" }),
|
|
2189
|
+
" Select a subscription plan to continue."
|
|
2190
|
+
] }),
|
|
2191
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2192
|
+
PaymentExperience,
|
|
2193
|
+
{
|
|
2194
|
+
usdAmount,
|
|
2195
|
+
priceId: priceId ?? "",
|
|
2196
|
+
onSolanaSuccess: solanaSuccess,
|
|
2197
|
+
onSolanaError: solanaError,
|
|
2198
|
+
enableNewCard: Boolean(priceId),
|
|
2199
|
+
enableStoredMethods: Boolean(priceId),
|
|
2200
|
+
enableSolanaPay: enableSolanaPay && Boolean(priceId),
|
|
2201
|
+
onNewCardPayment: priceId ? handleNewCardPayment : void 0,
|
|
2202
|
+
onSavedMethodPayment: priceId ? handleSavedMethodPayment : void 0,
|
|
2203
|
+
initialMode
|
|
2204
|
+
}
|
|
2205
|
+
)
|
|
2206
|
+
] })
|
|
2207
|
+
}
|
|
2208
|
+
) }),
|
|
3018
2209
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3019
2210
|
SubscriptionSuccessDialog,
|
|
3020
2211
|
{
|
|
@@ -3040,7 +2231,7 @@ var wallets = [
|
|
|
3040
2231
|
}
|
|
3041
2232
|
];
|
|
3042
2233
|
var WalletModal = ({ open, onOpenChange }) => {
|
|
3043
|
-
const [expandedWallet, setExpandedWallet] =
|
|
2234
|
+
const [expandedWallet, setExpandedWallet] = React17.useState(null);
|
|
3044
2235
|
return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "w-full max-w-lg max-h-[90vh] overflow-y-auto rounded-md border border-border/70 bg-background/95 p-0 shadow-2xl [&::-webkit-scrollbar]:hidden", children: [
|
|
3045
2236
|
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { className: "border-b border-border/40 bg-gradient-to-r from-primary/10 via-background to-background px-6 py-5 text-left", children: [
|
|
3046
2237
|
/* @__PURE__ */ jsxRuntime.jsxs(DialogTitle, { className: "flex items-center gap-2 text-foreground", children: [
|
|
@@ -3096,17 +2287,17 @@ var createDialogState = () => ({
|
|
|
3096
2287
|
isOpen: false,
|
|
3097
2288
|
props: null
|
|
3098
2289
|
});
|
|
3099
|
-
var PaymentsDialogContext =
|
|
2290
|
+
var PaymentsDialogContext = React17.createContext(void 0);
|
|
3100
2291
|
var PaymentsDialogProvider = ({
|
|
3101
2292
|
children
|
|
3102
2293
|
}) => {
|
|
3103
|
-
const [checkoutState, setCheckoutState] =
|
|
2294
|
+
const [checkoutState, setCheckoutState] = React17.useState(
|
|
3104
2295
|
() => createDialogState()
|
|
3105
2296
|
);
|
|
3106
|
-
const [walletState, setWalletState] =
|
|
2297
|
+
const [walletState, setWalletState] = React17.useState(
|
|
3107
2298
|
() => createDialogState()
|
|
3108
2299
|
);
|
|
3109
|
-
const contextValue =
|
|
2300
|
+
const contextValue = React17.useMemo(() => {
|
|
3110
2301
|
const openCheckout = (options) => setCheckoutState({
|
|
3111
2302
|
isOpen: true,
|
|
3112
2303
|
props: options
|
|
@@ -3160,28 +2351,65 @@ var PaymentsDialogProvider = ({
|
|
|
3160
2351
|
] });
|
|
3161
2352
|
};
|
|
3162
2353
|
var usePaymentDialogs = () => {
|
|
3163
|
-
const context =
|
|
2354
|
+
const context = React17.useContext(PaymentsDialogContext);
|
|
3164
2355
|
if (!context) {
|
|
3165
2356
|
throw new Error("usePaymentDialogs must be used within PaymentProvider");
|
|
3166
2357
|
}
|
|
3167
2358
|
return context;
|
|
3168
2359
|
};
|
|
3169
|
-
var PaymentContext =
|
|
2360
|
+
var PaymentContext = React17.createContext(void 0);
|
|
3170
2361
|
var PaymentProvider = ({
|
|
3171
2362
|
config,
|
|
3172
|
-
runtime: runtimeProp,
|
|
3173
2363
|
children
|
|
3174
2364
|
}) => {
|
|
3175
|
-
const
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
2365
|
+
const queryClient = React17.useMemo(() => {
|
|
2366
|
+
return new reactQuery.QueryClient({
|
|
2367
|
+
defaultOptions: {
|
|
2368
|
+
queries: {
|
|
2369
|
+
staleTime: 3e4,
|
|
2370
|
+
gcTime: 5 * 6e4,
|
|
2371
|
+
refetchOnWindowFocus: false,
|
|
2372
|
+
retry: 1
|
|
2373
|
+
},
|
|
2374
|
+
mutations: {
|
|
2375
|
+
retry: 1
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
});
|
|
2379
|
+
}, []);
|
|
2380
|
+
const client = React17.useMemo(() => {
|
|
2381
|
+
const authProvider = config.getAuthToken ? async () => {
|
|
2382
|
+
try {
|
|
2383
|
+
const result = config.getAuthToken?.();
|
|
2384
|
+
if (result instanceof Promise) {
|
|
2385
|
+
return await result ?? null;
|
|
2386
|
+
}
|
|
2387
|
+
return result ?? null;
|
|
2388
|
+
} catch (error) {
|
|
2389
|
+
console.warn("payments-ui: failed to resolve auth token", error);
|
|
2390
|
+
return null;
|
|
2391
|
+
}
|
|
2392
|
+
} : void 0;
|
|
2393
|
+
const wrappedFetch = config.fetcher ? ((input, init) => {
|
|
2394
|
+
const normalizedInput = input instanceof URL ? input.toString() : input;
|
|
2395
|
+
return config.fetcher(normalizedInput, init);
|
|
2396
|
+
}) : void 0;
|
|
2397
|
+
return createClient({
|
|
2398
|
+
billingBaseUrl: config.endpoints.billingBaseUrl,
|
|
2399
|
+
billingBasePath: config.endpoints.billingBasePath,
|
|
2400
|
+
accountBaseUrl: config.endpoints.accountBaseUrl,
|
|
2401
|
+
accountBasePath: config.endpoints.accountBasePath,
|
|
2402
|
+
getAuthToken: authProvider,
|
|
2403
|
+
defaultHeaders: config.defaultHeaders,
|
|
2404
|
+
fetch: wrappedFetch
|
|
2405
|
+
});
|
|
2406
|
+
}, [config]);
|
|
2407
|
+
const solanaEndpoint = React17.useMemo(() => {
|
|
3180
2408
|
if (config.solana?.endpoint) return config.solana.endpoint;
|
|
3181
|
-
const network = config.solana?.network ?? WalletAdapterNetwork.Mainnet;
|
|
2409
|
+
const network = config.solana?.network ?? walletAdapterBase.WalletAdapterNetwork.Mainnet;
|
|
3182
2410
|
return web3_js.clusterApiUrl(network);
|
|
3183
2411
|
}, [config.solana?.endpoint, config.solana?.network]);
|
|
3184
|
-
const walletAdapters =
|
|
2412
|
+
const walletAdapters = React17.useMemo(() => {
|
|
3185
2413
|
if (config.solana?.wallets?.length) {
|
|
3186
2414
|
return config.solana.wallets;
|
|
3187
2415
|
}
|
|
@@ -3193,29 +2421,60 @@ var PaymentProvider = ({
|
|
|
3193
2421
|
];
|
|
3194
2422
|
}, [config.solana?.wallets]);
|
|
3195
2423
|
const autoConnect = config.solana?.autoConnect ?? true;
|
|
3196
|
-
const value =
|
|
2424
|
+
const value = React17.useMemo(() => {
|
|
3197
2425
|
return {
|
|
3198
|
-
config
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
app: runtime.app,
|
|
3202
|
-
services: runtime.services,
|
|
3203
|
-
queryClient: runtime.queryClient
|
|
2426
|
+
config,
|
|
2427
|
+
client,
|
|
2428
|
+
queryClient
|
|
3204
2429
|
};
|
|
3205
|
-
}, [
|
|
3206
|
-
|
|
2430
|
+
}, [client, config, queryClient]);
|
|
2431
|
+
React17.useEffect(() => {
|
|
3207
2432
|
if (!config.collectJsKey) return;
|
|
3208
2433
|
loadCollectJs(config.collectJsKey);
|
|
3209
2434
|
}, [config.collectJsKey]);
|
|
3210
|
-
return /* @__PURE__ */ jsxRuntime.jsx(PaymentContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client:
|
|
2435
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PaymentContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsxRuntime.jsx(walletAdapterReact.ConnectionProvider, { endpoint: solanaEndpoint, config: { commitment: "confirmed" }, children: /* @__PURE__ */ jsxRuntime.jsx(walletAdapterReact.WalletProvider, { wallets: walletAdapters, autoConnect, children: /* @__PURE__ */ jsxRuntime.jsx(walletAdapterReactUi.WalletModalProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(PaymentsDialogProvider, { children }) }) }) }) }) });
|
|
3211
2436
|
};
|
|
3212
2437
|
var usePaymentContext = () => {
|
|
3213
|
-
const context =
|
|
2438
|
+
const context = React17.useContext(PaymentContext);
|
|
3214
2439
|
if (!context) {
|
|
3215
2440
|
throw new Error("usePaymentContext must be used within a PaymentProvider");
|
|
3216
2441
|
}
|
|
3217
2442
|
return context;
|
|
3218
2443
|
};
|
|
2444
|
+
var PaymentsUIRoot = ({
|
|
2445
|
+
children,
|
|
2446
|
+
className,
|
|
2447
|
+
dark = false
|
|
2448
|
+
}) => {
|
|
2449
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2450
|
+
"div",
|
|
2451
|
+
{
|
|
2452
|
+
className: cn(
|
|
2453
|
+
"payments-ui-root",
|
|
2454
|
+
dark && "dark",
|
|
2455
|
+
className
|
|
2456
|
+
),
|
|
2457
|
+
children
|
|
2458
|
+
}
|
|
2459
|
+
);
|
|
2460
|
+
};
|
|
2461
|
+
var PaymentsUIPortalRoot = ({
|
|
2462
|
+
children,
|
|
2463
|
+
className,
|
|
2464
|
+
dark = false
|
|
2465
|
+
}) => {
|
|
2466
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2467
|
+
"div",
|
|
2468
|
+
{
|
|
2469
|
+
className: cn(
|
|
2470
|
+
"payments-ui-portal",
|
|
2471
|
+
dark && "dark",
|
|
2472
|
+
className
|
|
2473
|
+
),
|
|
2474
|
+
children
|
|
2475
|
+
}
|
|
2476
|
+
);
|
|
2477
|
+
};
|
|
3219
2478
|
var SolanaPaymentSelector = ({
|
|
3220
2479
|
isOpen,
|
|
3221
2480
|
onClose,
|
|
@@ -3223,7 +2482,7 @@ var SolanaPaymentSelector = ({
|
|
|
3223
2482
|
}) => {
|
|
3224
2483
|
return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isOpen, onOpenChange: (value) => value ? void 0 : onClose(), children: /* @__PURE__ */ jsxRuntime.jsx(DialogContent, { className: "w-full max-w-2xl max-h-[90vh] overflow-y-auto rounded-md border border-border/70 bg-background/95 p-0 shadow-2xl [&::-webkit-scrollbar]:hidden", children: /* @__PURE__ */ jsxRuntime.jsx(SolanaPaymentView, { ...props, onClose }) }) });
|
|
3225
2484
|
};
|
|
3226
|
-
var Table =
|
|
2485
|
+
var Table = React17__namespace.forwardRef(
|
|
3227
2486
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3228
2487
|
"table",
|
|
3229
2488
|
{
|
|
@@ -3234,15 +2493,15 @@ var Table = React3__namespace.forwardRef(
|
|
|
3234
2493
|
)
|
|
3235
2494
|
);
|
|
3236
2495
|
Table.displayName = "Table";
|
|
3237
|
-
var TableHeader =
|
|
2496
|
+
var TableHeader = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
|
|
3238
2497
|
TableHeader.displayName = "TableHeader";
|
|
3239
|
-
var TableBody =
|
|
2498
|
+
var TableBody = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { ref, className: cn("[&_tr:last-child]:border-0", className), ...props }));
|
|
3240
2499
|
TableBody.displayName = "TableBody";
|
|
3241
|
-
var TableFooter =
|
|
2500
|
+
var TableFooter = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tfoot", { ref, className: cn("bg-muted/50 font-medium text-muted-foreground", className), ...props }));
|
|
3242
2501
|
TableFooter.displayName = "TableFooter";
|
|
3243
|
-
var TableRow =
|
|
2502
|
+
var TableRow = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tr", { ref, className: cn("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className), ...props }));
|
|
3244
2503
|
TableRow.displayName = "TableRow";
|
|
3245
|
-
var TableHead =
|
|
2504
|
+
var TableHead = React17__namespace.forwardRef(
|
|
3246
2505
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3247
2506
|
"th",
|
|
3248
2507
|
{
|
|
@@ -3256,7 +2515,7 @@ var TableHead = React3__namespace.forwardRef(
|
|
|
3256
2515
|
)
|
|
3257
2516
|
);
|
|
3258
2517
|
TableHead.displayName = "TableHead";
|
|
3259
|
-
var TableCell =
|
|
2518
|
+
var TableCell = React17__namespace.forwardRef(
|
|
3260
2519
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3261
2520
|
"td",
|
|
3262
2521
|
{
|
|
@@ -3267,37 +2526,37 @@ var TableCell = React3__namespace.forwardRef(
|
|
|
3267
2526
|
)
|
|
3268
2527
|
);
|
|
3269
2528
|
TableCell.displayName = "TableCell";
|
|
3270
|
-
var TableCaption =
|
|
2529
|
+
var TableCaption = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props }));
|
|
3271
2530
|
TableCaption.displayName = "TableCaption";
|
|
3272
2531
|
var AlertDialog = AlertDialogPrimitive__namespace.Root;
|
|
3273
2532
|
var AlertDialogTrigger = AlertDialogPrimitive__namespace.Trigger;
|
|
3274
2533
|
var AlertDialogPortal = AlertDialogPrimitive__namespace.Portal;
|
|
3275
|
-
var AlertDialogOverlay =
|
|
2534
|
+
var AlertDialogOverlay = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3276
2535
|
AlertDialogPrimitive__namespace.Overlay,
|
|
3277
2536
|
{
|
|
3278
2537
|
ref,
|
|
3279
2538
|
className: cn(
|
|
3280
|
-
"fixed inset-0 z-50 bg-
|
|
2539
|
+
"fixed inset-0 z-50 bg-black/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0",
|
|
3281
2540
|
className
|
|
3282
2541
|
),
|
|
3283
2542
|
...props
|
|
3284
2543
|
}
|
|
3285
2544
|
));
|
|
3286
2545
|
AlertDialogOverlay.displayName = AlertDialogPrimitive__namespace.Overlay.displayName;
|
|
3287
|
-
var AlertDialogContent =
|
|
2546
|
+
var AlertDialogContent = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(AlertDialogPortal, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payments-ui-portal", children: [
|
|
3288
2547
|
/* @__PURE__ */ jsxRuntime.jsx(AlertDialogOverlay, {}),
|
|
3289
2548
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3290
2549
|
AlertDialogPrimitive__namespace.Content,
|
|
3291
2550
|
{
|
|
3292
2551
|
ref,
|
|
3293
2552
|
className: cn(
|
|
3294
|
-
"fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-
|
|
2553
|
+
"fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-white/10 bg-[#161b22] text-white p-6 shadow-lg rounded-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
3295
2554
|
className
|
|
3296
2555
|
),
|
|
3297
2556
|
...props
|
|
3298
2557
|
}
|
|
3299
2558
|
)
|
|
3300
|
-
] }));
|
|
2559
|
+
] }) }));
|
|
3301
2560
|
AlertDialogContent.displayName = AlertDialogPrimitive__namespace.Content.displayName;
|
|
3302
2561
|
var AlertDialogHeader = ({
|
|
3303
2562
|
className,
|
|
@@ -3315,13 +2574,13 @@ var AlertDialogFooter = ({
|
|
|
3315
2574
|
}
|
|
3316
2575
|
);
|
|
3317
2576
|
AlertDialogFooter.displayName = "AlertDialogFooter";
|
|
3318
|
-
var AlertDialogTitle =
|
|
2577
|
+
var AlertDialogTitle = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(AlertDialogPrimitive__namespace.Title, { ref, className: cn("text-lg font-semibold text-white", className), ...props }));
|
|
3319
2578
|
AlertDialogTitle.displayName = AlertDialogPrimitive__namespace.Title.displayName;
|
|
3320
|
-
var AlertDialogDescription =
|
|
2579
|
+
var AlertDialogDescription = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(AlertDialogPrimitive__namespace.Description, { ref, className: cn("text-sm text-white/60", className), ...props }));
|
|
3321
2580
|
AlertDialogDescription.displayName = AlertDialogPrimitive__namespace.Description.displayName;
|
|
3322
|
-
var AlertDialogAction =
|
|
2581
|
+
var AlertDialogAction = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(AlertDialogPrimitive__namespace.Action, { ref, className: cn(buttonVariants(), className), ...props }));
|
|
3323
2582
|
AlertDialogAction.displayName = AlertDialogPrimitive__namespace.Action.displayName;
|
|
3324
|
-
var AlertDialogCancel =
|
|
2583
|
+
var AlertDialogCancel = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3325
2584
|
AlertDialogPrimitive__namespace.Cancel,
|
|
3326
2585
|
{
|
|
3327
2586
|
ref,
|
|
@@ -3330,7 +2589,7 @@ var AlertDialogCancel = React3__namespace.forwardRef(({ className, ...props }, r
|
|
|
3330
2589
|
}
|
|
3331
2590
|
));
|
|
3332
2591
|
AlertDialogCancel.displayName = AlertDialogPrimitive__namespace.Cancel.displayName;
|
|
3333
|
-
var Textarea =
|
|
2592
|
+
var Textarea = React17__namespace.forwardRef(
|
|
3334
2593
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3335
2594
|
"textarea",
|
|
3336
2595
|
{
|
|
@@ -3348,19 +2607,39 @@ var notifyDefault = (payload) => {
|
|
|
3348
2607
|
const level = payload.status === "destructive" ? "error" : "info";
|
|
3349
2608
|
console[level === "error" ? "error" : "log"]("[payments-ui] cancellation", payload);
|
|
3350
2609
|
};
|
|
2610
|
+
var defaultTranslations = {
|
|
2611
|
+
buttonLabel: "Cancel Membership",
|
|
2612
|
+
title: "Confirm Membership Cancellation",
|
|
2613
|
+
description: "You are about to cancel your membership. Please review the consequences:",
|
|
2614
|
+
consequence1: "You will immediately lose access to premium features upon confirmation.",
|
|
2615
|
+
consequence2: "Your benefits remain active until the end of the billing cycle.",
|
|
2616
|
+
consequence3: "Your account will revert to the free plan afterwards.",
|
|
2617
|
+
reasonLabel: "Please provide a reason for cancellation (required):",
|
|
2618
|
+
reasonPlaceholder: "Your feedback helps us improve...",
|
|
2619
|
+
reasonError: "Reason must be at least {min} characters long.",
|
|
2620
|
+
reasonHint: "Minimum {min} characters required.",
|
|
2621
|
+
keepMembership: "Keep Membership",
|
|
2622
|
+
confirmCancellation: "Confirm Cancellation",
|
|
2623
|
+
cancelling: "Cancelling...",
|
|
2624
|
+
membershipCancelled: "Membership cancelled",
|
|
2625
|
+
cancellationSuccess: "Your subscription has been cancelled successfully.",
|
|
2626
|
+
cancellationFailed: "Cancellation failed"
|
|
2627
|
+
};
|
|
3351
2628
|
var CancelMembershipDialog = ({
|
|
3352
2629
|
minReasonLength = 15,
|
|
3353
2630
|
onCancelled,
|
|
3354
|
-
onNotify
|
|
2631
|
+
onNotify,
|
|
2632
|
+
translations: customTranslations
|
|
3355
2633
|
}) => {
|
|
3356
|
-
const {
|
|
2634
|
+
const { client } = usePaymentContext();
|
|
3357
2635
|
const notify = onNotify ?? notifyDefault;
|
|
3358
|
-
const
|
|
3359
|
-
const [
|
|
3360
|
-
const [
|
|
3361
|
-
const [
|
|
3362
|
-
const [
|
|
3363
|
-
|
|
2636
|
+
const t = { ...defaultTranslations, ...customTranslations };
|
|
2637
|
+
const [cancelReason, setCancelReason] = React17.useState("");
|
|
2638
|
+
const [isOpen, setIsOpen] = React17.useState(false);
|
|
2639
|
+
const [isReasonValid, setIsReasonValid] = React17.useState(false);
|
|
2640
|
+
const [hasInteracted, setHasInteracted] = React17.useState(false);
|
|
2641
|
+
const [isSubmitting, setIsSubmitting] = React17.useState(false);
|
|
2642
|
+
React17.useEffect(() => {
|
|
3364
2643
|
const trimmed = cancelReason.trim();
|
|
3365
2644
|
setIsReasonValid(trimmed.length >= minReasonLength);
|
|
3366
2645
|
}, [cancelReason, minReasonLength]);
|
|
@@ -3386,17 +2665,17 @@ var CancelMembershipDialog = ({
|
|
|
3386
2665
|
}
|
|
3387
2666
|
setIsSubmitting(true);
|
|
3388
2667
|
try {
|
|
3389
|
-
await
|
|
2668
|
+
await client.cancelSubscription(cancelReason.trim());
|
|
3390
2669
|
notify({
|
|
3391
|
-
title:
|
|
3392
|
-
description:
|
|
2670
|
+
title: t.membershipCancelled,
|
|
2671
|
+
description: t.cancellationSuccess,
|
|
3393
2672
|
status: "success"
|
|
3394
2673
|
});
|
|
3395
2674
|
onCancelled?.();
|
|
3396
2675
|
handleOpenChange(false);
|
|
3397
2676
|
} catch (error) {
|
|
3398
2677
|
const message = error instanceof Error ? error.message : "Unable to cancel membership";
|
|
3399
|
-
notify({ title:
|
|
2678
|
+
notify({ title: t.cancellationFailed, description: message, status: "destructive" });
|
|
3400
2679
|
} finally {
|
|
3401
2680
|
setIsSubmitting(false);
|
|
3402
2681
|
}
|
|
@@ -3405,32 +2684,34 @@ var CancelMembershipDialog = ({
|
|
|
3405
2684
|
return /* @__PURE__ */ jsxRuntime.jsxs(AlertDialog, { open: isOpen, onOpenChange: handleOpenChange, children: [
|
|
3406
2685
|
/* @__PURE__ */ jsxRuntime.jsx(AlertDialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "outline", className: "border-destructive/50 text-destructive", children: [
|
|
3407
2686
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ban, { className: "mr-2 h-4 w-4" }),
|
|
3408
|
-
"
|
|
2687
|
+
" ",
|
|
2688
|
+
t.buttonLabel
|
|
3409
2689
|
] }) }),
|
|
3410
2690
|
/* @__PURE__ */ jsxRuntime.jsxs(AlertDialogContent, { className: "max-h-[90vh] overflow-y-auto rounded-md border border-border bg-background", children: [
|
|
3411
2691
|
/* @__PURE__ */ jsxRuntime.jsxs(AlertDialogHeader, { children: [
|
|
3412
2692
|
/* @__PURE__ */ jsxRuntime.jsxs(AlertDialogTitle, { className: "flex items-center gap-2 text-lg font-semibold", children: [
|
|
3413
2693
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.TriangleAlert, { className: "h-5 w-5 text-destructive" }),
|
|
3414
|
-
"
|
|
2694
|
+
" ",
|
|
2695
|
+
t.title
|
|
3415
2696
|
] }),
|
|
3416
2697
|
/* @__PURE__ */ jsxRuntime.jsxs(AlertDialogDescription, { className: "mt-3 space-y-3 text-muted-foreground", children: [
|
|
3417
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { children:
|
|
2698
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: t.description }),
|
|
3418
2699
|
/* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "list-disc space-y-1 pl-5 text-sm", children: [
|
|
3419
|
-
/* @__PURE__ */ jsxRuntime.jsx("li", { children:
|
|
3420
|
-
/* @__PURE__ */ jsxRuntime.jsx("li", { children:
|
|
3421
|
-
/* @__PURE__ */ jsxRuntime.jsx("li", { children:
|
|
2700
|
+
/* @__PURE__ */ jsxRuntime.jsx("li", { children: t.consequence1 }),
|
|
2701
|
+
/* @__PURE__ */ jsxRuntime.jsx("li", { children: t.consequence2 }),
|
|
2702
|
+
/* @__PURE__ */ jsxRuntime.jsx("li", { children: t.consequence3 })
|
|
3422
2703
|
] })
|
|
3423
2704
|
] })
|
|
3424
2705
|
] }),
|
|
3425
2706
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-4 space-y-2 py-2", children: [
|
|
3426
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "cancelReason", className: "text-sm font-medium", children:
|
|
2707
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "cancelReason", className: "text-sm font-medium", children: t.reasonLabel }),
|
|
3427
2708
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3428
2709
|
Textarea,
|
|
3429
2710
|
{
|
|
3430
2711
|
id: "cancelReason",
|
|
3431
2712
|
value: cancelReason,
|
|
3432
2713
|
onChange: handleReasonChange,
|
|
3433
|
-
placeholder:
|
|
2714
|
+
placeholder: t.reasonPlaceholder,
|
|
3434
2715
|
className: cn(
|
|
3435
2716
|
"w-full resize-none border-border bg-background",
|
|
3436
2717
|
showError && "border-destructive"
|
|
@@ -3445,19 +2726,19 @@ var CancelMembershipDialog = ({
|
|
|
3445
2726
|
{
|
|
3446
2727
|
id: "reason-hint",
|
|
3447
2728
|
className: `text-xs ${showError ? "text-destructive" : "text-muted-foreground"}`,
|
|
3448
|
-
children: showError ?
|
|
2729
|
+
children: showError ? t.reasonError.replace("{min}", String(minReasonLength)) : t.reasonHint.replace("{min}", String(minReasonLength))
|
|
3449
2730
|
}
|
|
3450
2731
|
)
|
|
3451
2732
|
] }),
|
|
3452
2733
|
/* @__PURE__ */ jsxRuntime.jsxs(AlertDialogFooter, { className: "mt-6 gap-2", children: [
|
|
3453
|
-
/* @__PURE__ */ jsxRuntime.jsx(AlertDialogCancel, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", className: "border-border text-muted-foreground", children:
|
|
2734
|
+
/* @__PURE__ */ jsxRuntime.jsx(AlertDialogCancel, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", className: "border-border text-muted-foreground", children: t.keepMembership }) }),
|
|
3454
2735
|
/* @__PURE__ */ jsxRuntime.jsx(AlertDialogAction, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3455
2736
|
Button,
|
|
3456
2737
|
{
|
|
3457
2738
|
className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
3458
2739
|
onClick: handleConfirm,
|
|
3459
2740
|
disabled: !isReasonValid || isSubmitting,
|
|
3460
|
-
children: isSubmitting ?
|
|
2741
|
+
children: isSubmitting ? t.cancelling : t.confirmCancellation
|
|
3461
2742
|
}
|
|
3462
2743
|
) })
|
|
3463
2744
|
] })
|
|
@@ -3468,22 +2749,47 @@ var notifyDefault2 = (payload) => {
|
|
|
3468
2749
|
const level = payload.status === "destructive" ? "error" : "info";
|
|
3469
2750
|
console[level === "error" ? "error" : "log"]("[payments-ui] billing", payload);
|
|
3470
2751
|
};
|
|
2752
|
+
var defaultTranslations2 = {
|
|
2753
|
+
title: "Transaction History",
|
|
2754
|
+
description: "Record of billing history",
|
|
2755
|
+
reviewActivity: "Review your account activity below",
|
|
2756
|
+
loading: "Loading...",
|
|
2757
|
+
error: "Error loading billing history.",
|
|
2758
|
+
loadingMore: "Loading more...",
|
|
2759
|
+
reference: "Reference",
|
|
2760
|
+
date: "Date",
|
|
2761
|
+
amount: "Amount",
|
|
2762
|
+
processor: "Processor",
|
|
2763
|
+
status: "Status"
|
|
2764
|
+
};
|
|
3471
2765
|
var BillingHistory = ({
|
|
3472
2766
|
pageSize = 10,
|
|
3473
2767
|
initialPage = 1,
|
|
3474
2768
|
enableCancel = true,
|
|
3475
|
-
onNotify
|
|
2769
|
+
onNotify,
|
|
2770
|
+
translations: customTranslations
|
|
3476
2771
|
}) => {
|
|
3477
|
-
const {
|
|
2772
|
+
const { client } = usePaymentContext();
|
|
3478
2773
|
const notify = onNotify ?? notifyDefault2;
|
|
3479
|
-
const
|
|
3480
|
-
const
|
|
3481
|
-
const
|
|
2774
|
+
const t = { ...defaultTranslations2, ...customTranslations };
|
|
2775
|
+
const [isExpanded, setIsExpanded] = React17.useState(false);
|
|
2776
|
+
const observerRef = React17.useRef(null);
|
|
2777
|
+
const loadMoreRef = React17.useRef(null);
|
|
3482
2778
|
const historyQuery = reactQuery.useInfiniteQuery({
|
|
3483
2779
|
queryKey: ["payments-ui", "billing-history", pageSize],
|
|
3484
2780
|
queryFn: async ({ pageParam = initialPage }) => {
|
|
3485
2781
|
const offset = (pageParam - 1) * pageSize;
|
|
3486
|
-
return
|
|
2782
|
+
return client.getPaymentHistory({ limit: pageSize, offset, type: void 0 }).then(
|
|
2783
|
+
(response) => ({
|
|
2784
|
+
data: response.data,
|
|
2785
|
+
total_items: response.total,
|
|
2786
|
+
limit: response.limit,
|
|
2787
|
+
offset: response.offset,
|
|
2788
|
+
page: response.limit > 0 ? Math.floor(response.offset / response.limit) + 1 : 1,
|
|
2789
|
+
page_size: response.limit,
|
|
2790
|
+
total_pages: response.limit > 0 ? Math.ceil(response.total / response.limit) : void 0
|
|
2791
|
+
})
|
|
2792
|
+
);
|
|
3487
2793
|
},
|
|
3488
2794
|
initialPageParam: initialPage,
|
|
3489
2795
|
getNextPageParam: (lastPage) => {
|
|
@@ -3495,7 +2801,7 @@ var BillingHistory = ({
|
|
|
3495
2801
|
},
|
|
3496
2802
|
staleTime: 5 * 60 * 1e3
|
|
3497
2803
|
});
|
|
3498
|
-
|
|
2804
|
+
React17.useEffect(() => {
|
|
3499
2805
|
if (!loadMoreRef.current || !isExpanded) return;
|
|
3500
2806
|
observerRef.current = new IntersectionObserver((entries) => {
|
|
3501
2807
|
const [entry] = entries;
|
|
@@ -3510,7 +2816,7 @@ var BillingHistory = ({
|
|
|
3510
2816
|
observerRef.current?.disconnect();
|
|
3511
2817
|
};
|
|
3512
2818
|
}, [historyQuery, isExpanded, notify]);
|
|
3513
|
-
const payments =
|
|
2819
|
+
const payments = React17.useMemo(() => {
|
|
3514
2820
|
const data = historyQuery.data;
|
|
3515
2821
|
return data?.pages ?? [];
|
|
3516
2822
|
}, [historyQuery.data]);
|
|
@@ -3532,8 +2838,8 @@ var BillingHistory = ({
|
|
|
3532
2838
|
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "border-0 bg-background/5 shadow-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 sm:p-6", children: [
|
|
3533
2839
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex cursor-pointer items-center justify-between", onClick: () => setIsExpanded((prev) => !prev), children: [
|
|
3534
2840
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3535
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-xl font-semibold", children:
|
|
3536
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children:
|
|
2841
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-xl font-semibold", children: t.title }),
|
|
2842
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: t.description })
|
|
3537
2843
|
] }),
|
|
3538
2844
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: cn("h-5 w-5 text-muted-foreground transition-transform", isExpanded && "rotate-180") })
|
|
3539
2845
|
] }),
|
|
@@ -3546,16 +2852,16 @@ var BillingHistory = ({
|
|
|
3546
2852
|
),
|
|
3547
2853
|
children: /* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "p-0 pt-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
3548
2854
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between", children: [
|
|
3549
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children:
|
|
2855
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: t.reviewActivity }),
|
|
3550
2856
|
enableCancel && /* @__PURE__ */ jsxRuntime.jsx(CancelMembershipDialog, { onNotify: notify })
|
|
3551
2857
|
] }),
|
|
3552
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-[300px] overflow-y-auto rounded-lg border border-border/70", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: historyQuery.isLoading ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-4 text-center text-sm text-muted-foreground", children:
|
|
2858
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-[300px] overflow-y-auto rounded-lg border border-border/70", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: historyQuery.isLoading ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-4 text-center text-sm text-muted-foreground", children: t.loading }) : historyQuery.isError ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-4 text-center text-sm text-destructive", children: t.error }) : /* @__PURE__ */ jsxRuntime.jsxs(Table, { children: [
|
|
3553
2859
|
/* @__PURE__ */ jsxRuntime.jsx(TableHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(TableRow, { className: "border-border/60", children: [
|
|
3554
|
-
/* @__PURE__ */ jsxRuntime.jsx(TableHead, { children:
|
|
3555
|
-
/* @__PURE__ */ jsxRuntime.jsx(TableHead, { children:
|
|
3556
|
-
/* @__PURE__ */ jsxRuntime.jsx(TableHead, { children:
|
|
3557
|
-
/* @__PURE__ */ jsxRuntime.jsx(TableHead, { children:
|
|
3558
|
-
/* @__PURE__ */ jsxRuntime.jsx(TableHead, { children:
|
|
2860
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableHead, { children: t.reference }),
|
|
2861
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableHead, { children: t.date }),
|
|
2862
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableHead, { children: t.amount }),
|
|
2863
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableHead, { children: t.processor }),
|
|
2864
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableHead, { children: t.status })
|
|
3559
2865
|
] }) }),
|
|
3560
2866
|
/* @__PURE__ */ jsxRuntime.jsx(TableBody, { children: payments.map(
|
|
3561
2867
|
(page) => page.data.map((payment) => /* @__PURE__ */ jsxRuntime.jsxs(TableRow, { className: "border-border/40", children: [
|
|
@@ -3567,7 +2873,7 @@ var BillingHistory = ({
|
|
|
3567
2873
|
] }, payment.id))
|
|
3568
2874
|
) })
|
|
3569
2875
|
] }) }) }),
|
|
3570
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: loadMoreRef, className: "h-10 w-full", children: historyQuery.isFetchingNextPage && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-center text-sm text-muted-foreground", children:
|
|
2876
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: loadMoreRef, className: "h-10 w-full", children: historyQuery.isFetchingNextPage && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-center text-sm text-muted-foreground", children: t.loadingMore }) })
|
|
3571
2877
|
] }) })
|
|
3572
2878
|
}
|
|
3573
2879
|
)
|
|
@@ -3582,19 +2888,56 @@ var notifyDefault3 = (payload) => {
|
|
|
3582
2888
|
const level = payload.status === "destructive" ? "error" : "info";
|
|
3583
2889
|
console[level === "error" ? "error" : "log"]("[payments-ui] notification", payload);
|
|
3584
2890
|
};
|
|
2891
|
+
var defaultTranslations3 = {
|
|
2892
|
+
title: "Payment Methods",
|
|
2893
|
+
description: "Manage your saved billing cards",
|
|
2894
|
+
addCard: "Add card",
|
|
2895
|
+
loadingCards: "Loading cards...",
|
|
2896
|
+
noPaymentMethods: "No saved payment methods yet.",
|
|
2897
|
+
addedOn: "Added on",
|
|
2898
|
+
active: "Active",
|
|
2899
|
+
inactive: "Inactive",
|
|
2900
|
+
replaceCard: "Replace card",
|
|
2901
|
+
makeDefault: "Make default",
|
|
2902
|
+
defaultMethod: "Default method",
|
|
2903
|
+
remove: "Remove",
|
|
2904
|
+
addNewCard: "Add a new card",
|
|
2905
|
+
addNewCardDescription: "Your card details are tokenized securely via our payment provider.",
|
|
2906
|
+
saveCard: "Save card",
|
|
2907
|
+
replaceCardTitle: "Replace card",
|
|
2908
|
+
replaceCardDescription: "Update this card with new billing details.",
|
|
2909
|
+
cardAddedSuccess: "Card added successfully",
|
|
2910
|
+
unableToAddCard: "Unable to add card",
|
|
2911
|
+
cardRemoved: "Card removed",
|
|
2912
|
+
unableToRemoveCard: "Unable to remove card",
|
|
2913
|
+
cardUpdated: "Card updated",
|
|
2914
|
+
unableToReplaceCard: "Unable to replace card",
|
|
2915
|
+
defaultPaymentMethodUpdated: "Default payment method updated",
|
|
2916
|
+
unableToSetDefault: "Unable to set default payment method"
|
|
2917
|
+
};
|
|
3585
2918
|
var PaymentMethodsSection = ({
|
|
3586
2919
|
isAuthenticated = true,
|
|
3587
2920
|
userEmail,
|
|
3588
2921
|
provider = "mobius",
|
|
3589
2922
|
defaultCountry = "US",
|
|
3590
2923
|
collectPrefix = "account-card",
|
|
3591
|
-
onNotify
|
|
2924
|
+
onNotify,
|
|
2925
|
+
translations: customTranslations
|
|
3592
2926
|
}) => {
|
|
3593
|
-
const
|
|
2927
|
+
const { client } = usePaymentContext();
|
|
3594
2928
|
const queryClient = reactQuery.useQueryClient();
|
|
3595
|
-
const
|
|
3596
|
-
|
|
2929
|
+
const paymentMethods = {
|
|
2930
|
+
list: (params) => client.listPaymentMethods({ limit: params.pageSize }),
|
|
2931
|
+
create: (payload) => client.createPaymentMethod(payload),
|
|
2932
|
+
update: (id, payload) => client.updatePaymentMethod(id, payload),
|
|
2933
|
+
remove: (id) => client.deletePaymentMethod(id),
|
|
2934
|
+
activate: (id) => client.activatePaymentMethod(id)
|
|
2935
|
+
};
|
|
2936
|
+
const [isModalOpen, setIsModalOpen] = React17.useState(false);
|
|
2937
|
+
const [deletingId, setDeletingId] = React17.useState(null);
|
|
2938
|
+
const [methodBeingReplaced, setMethodBeingReplaced] = React17.useState(null);
|
|
3597
2939
|
const notify = onNotify ?? notifyDefault3;
|
|
2940
|
+
const t = { ...defaultTranslations3, ...customTranslations };
|
|
3598
2941
|
const queryKey = ["payments-ui", "payment-methods"];
|
|
3599
2942
|
const paymentQuery = reactQuery.useQuery({
|
|
3600
2943
|
queryKey,
|
|
@@ -3605,13 +2948,13 @@ var PaymentMethodsSection = ({
|
|
|
3605
2948
|
const createMutation = reactQuery.useMutation({
|
|
3606
2949
|
mutationFn: (payload) => paymentMethods.create(payload),
|
|
3607
2950
|
onSuccess: () => {
|
|
3608
|
-
notify({ title:
|
|
2951
|
+
notify({ title: t.cardAddedSuccess, status: "success" });
|
|
3609
2952
|
setIsModalOpen(false);
|
|
3610
2953
|
void queryClient.invalidateQueries({ queryKey });
|
|
3611
2954
|
},
|
|
3612
2955
|
onError: (error) => {
|
|
3613
2956
|
notify({
|
|
3614
|
-
title:
|
|
2957
|
+
title: t.unableToAddCard,
|
|
3615
2958
|
description: error.message,
|
|
3616
2959
|
status: "destructive"
|
|
3617
2960
|
});
|
|
@@ -3621,68 +2964,104 @@ var PaymentMethodsSection = ({
|
|
|
3621
2964
|
mutationFn: (id) => paymentMethods.remove(id),
|
|
3622
2965
|
onMutate: (id) => setDeletingId(id),
|
|
3623
2966
|
onSuccess: () => {
|
|
3624
|
-
notify({ title:
|
|
2967
|
+
notify({ title: t.cardRemoved, status: "success" });
|
|
3625
2968
|
void queryClient.invalidateQueries({ queryKey });
|
|
3626
2969
|
},
|
|
3627
2970
|
onError: (error) => {
|
|
3628
2971
|
notify({
|
|
3629
|
-
title:
|
|
2972
|
+
title: t.unableToRemoveCard,
|
|
3630
2973
|
description: error.message,
|
|
3631
2974
|
status: "destructive"
|
|
3632
2975
|
});
|
|
3633
2976
|
},
|
|
3634
2977
|
onSettled: () => setDeletingId(null)
|
|
3635
2978
|
});
|
|
3636
|
-
|
|
2979
|
+
const replaceMutation = reactQuery.useMutation({
|
|
2980
|
+
mutationFn: ({ id, payload }) => paymentMethods.update(id, payload),
|
|
2981
|
+
onSuccess: () => {
|
|
2982
|
+
notify({ title: t.cardUpdated, status: "success" });
|
|
2983
|
+
setMethodBeingReplaced(null);
|
|
2984
|
+
void queryClient.invalidateQueries({ queryKey });
|
|
2985
|
+
},
|
|
2986
|
+
onError: (error) => {
|
|
2987
|
+
notify({
|
|
2988
|
+
title: t.unableToReplaceCard,
|
|
2989
|
+
description: error.message,
|
|
2990
|
+
status: "destructive"
|
|
2991
|
+
});
|
|
2992
|
+
}
|
|
2993
|
+
});
|
|
2994
|
+
const activateMutation = reactQuery.useMutation({
|
|
2995
|
+
mutationFn: (id) => paymentMethods.activate(id),
|
|
2996
|
+
onSuccess: () => {
|
|
2997
|
+
notify({ title: t.defaultPaymentMethodUpdated, status: "success" });
|
|
2998
|
+
void queryClient.invalidateQueries({ queryKey });
|
|
2999
|
+
},
|
|
3000
|
+
onError: (error) => {
|
|
3001
|
+
notify({
|
|
3002
|
+
title: t.unableToSetDefault,
|
|
3003
|
+
description: error.message,
|
|
3004
|
+
status: "destructive"
|
|
3005
|
+
});
|
|
3006
|
+
}
|
|
3007
|
+
});
|
|
3008
|
+
React17.useEffect(() => {
|
|
3637
3009
|
if (!isModalOpen) {
|
|
3638
3010
|
createMutation.reset();
|
|
3639
3011
|
}
|
|
3640
3012
|
}, [createMutation, isModalOpen]);
|
|
3641
|
-
const payments =
|
|
3013
|
+
const payments = React17.useMemo(() => paymentQuery.data?.data ?? [], [paymentQuery.data]);
|
|
3642
3014
|
const loading = paymentQuery.isLoading || paymentQuery.isFetching;
|
|
3015
|
+
const buildPayload = (token, billing) => ({
|
|
3016
|
+
payment_token: token,
|
|
3017
|
+
first_name: billing.firstName,
|
|
3018
|
+
last_name: billing.lastName,
|
|
3019
|
+
address1: billing.address1,
|
|
3020
|
+
address2: billing.address2,
|
|
3021
|
+
city: billing.city,
|
|
3022
|
+
state: billing.stateRegion,
|
|
3023
|
+
zip: billing.postalCode,
|
|
3024
|
+
country: billing.country,
|
|
3025
|
+
email: billing.email,
|
|
3026
|
+
provider: billing.provider
|
|
3027
|
+
});
|
|
3643
3028
|
const handleCardTokenize = (token, billing) => {
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
address2: billing.address2,
|
|
3650
|
-
city: billing.city,
|
|
3651
|
-
state: billing.stateRegion,
|
|
3652
|
-
zip: billing.postalCode,
|
|
3653
|
-
country: billing.country,
|
|
3654
|
-
email: billing.email,
|
|
3655
|
-
provider: billing.provider
|
|
3656
|
-
};
|
|
3657
|
-
createMutation.mutate(payload);
|
|
3029
|
+
createMutation.mutate(buildPayload(token, billing));
|
|
3030
|
+
};
|
|
3031
|
+
const handleReplaceTokenize = (token, billing) => {
|
|
3032
|
+
if (!methodBeingReplaced) return;
|
|
3033
|
+
replaceMutation.mutate({ id: methodBeingReplaced.id, payload: buildPayload(token, billing) });
|
|
3658
3034
|
};
|
|
3659
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Card, {
|
|
3035
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { children: [
|
|
3660
3036
|
/* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "flex flex-col gap-4 md:flex-row md:items-center md:justify-between", children: [
|
|
3661
3037
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3662
|
-
/* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "flex items-center gap-2
|
|
3663
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.WalletCards, { className: "h-5 w-5 text-
|
|
3664
|
-
"
|
|
3038
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "flex items-center gap-2", children: [
|
|
3039
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.WalletCards, { className: "h-5 w-5 text-emerald-400" }),
|
|
3040
|
+
" ",
|
|
3041
|
+
t.title
|
|
3665
3042
|
] }),
|
|
3666
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children:
|
|
3043
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: t.description })
|
|
3667
3044
|
] }),
|
|
3668
3045
|
/* @__PURE__ */ jsxRuntime.jsxs(Button, { onClick: () => setIsModalOpen(true), children: [
|
|
3669
3046
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "mr-2 h-4 w-4" }),
|
|
3670
|
-
"
|
|
3047
|
+
" ",
|
|
3048
|
+
t.addCard
|
|
3671
3049
|
] })
|
|
3672
3050
|
] }),
|
|
3673
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "space-y-4", children: loading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center py-10 text-
|
|
3051
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "space-y-4", children: loading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center py-10 text-white/60", children: [
|
|
3674
3052
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-5 w-5 animate-spin" }),
|
|
3675
|
-
"
|
|
3676
|
-
|
|
3053
|
+
" ",
|
|
3054
|
+
t.loadingCards
|
|
3055
|
+
] }) : payments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-dashed border-white/20 bg-white/5 p-6 text-sm text-white/60", children: t.noPaymentMethods }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: payments.map((method) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3677
3056
|
"div",
|
|
3678
3057
|
{
|
|
3679
|
-
className: "rounded-lg border border-
|
|
3058
|
+
className: "rounded-lg border border-white/10 bg-white/5 p-4 shadow-sm",
|
|
3680
3059
|
children: [
|
|
3681
3060
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 md:flex-row md:items-center md:justify-between", children: [
|
|
3682
3061
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3683
|
-
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-base font-medium text-
|
|
3684
|
-
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-
|
|
3685
|
-
|
|
3062
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-base font-medium text-white", children: formatCardLabel2(method) }),
|
|
3063
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-white/60", children: [
|
|
3064
|
+
t.addedOn,
|
|
3686
3065
|
" ",
|
|
3687
3066
|
method.created_at ? new Date(method.created_at).toLocaleDateString() : "unknown date"
|
|
3688
3067
|
] })
|
|
@@ -3692,34 +3071,60 @@ var PaymentMethodsSection = ({
|
|
|
3692
3071
|
Badge,
|
|
3693
3072
|
{
|
|
3694
3073
|
variant: method.is_active ? "default" : "secondary",
|
|
3695
|
-
|
|
3696
|
-
children: method.is_active ? "Active" : "Inactive"
|
|
3074
|
+
children: method.is_active ? t.active : t.inactive
|
|
3697
3075
|
}
|
|
3698
3076
|
),
|
|
3699
3077
|
method.failure_reason && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "destructive", children: method.failure_reason })
|
|
3700
3078
|
] })
|
|
3701
3079
|
] }),
|
|
3702
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3080
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex flex-wrap gap-2", children: [
|
|
3081
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3082
|
+
Button,
|
|
3083
|
+
{
|
|
3084
|
+
variant: "ghost",
|
|
3085
|
+
className: "text-blue-400",
|
|
3086
|
+
disabled: replaceMutation.isPending && methodBeingReplaced?.id === method.id,
|
|
3087
|
+
onClick: () => setMethodBeingReplaced(method),
|
|
3088
|
+
children: [
|
|
3089
|
+
replaceMutation.isPending && methodBeingReplaced?.id === method.id ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "mr-2 h-4 w-4" }),
|
|
3090
|
+
t.replaceCard
|
|
3091
|
+
]
|
|
3092
|
+
}
|
|
3093
|
+
),
|
|
3094
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3095
|
+
Button,
|
|
3096
|
+
{
|
|
3097
|
+
variant: "outline",
|
|
3098
|
+
disabled: method.is_active || activateMutation.isPending,
|
|
3099
|
+
onClick: () => activateMutation.mutate(method.id),
|
|
3100
|
+
children: [
|
|
3101
|
+
activateMutation.isPending ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : null,
|
|
3102
|
+
method.is_active ? t.defaultMethod : t.makeDefault
|
|
3103
|
+
]
|
|
3104
|
+
}
|
|
3105
|
+
),
|
|
3106
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3107
|
+
Button,
|
|
3108
|
+
{
|
|
3109
|
+
variant: "ghost",
|
|
3110
|
+
className: "text-red-400 hover:text-red-300",
|
|
3111
|
+
disabled: deletingId === method.id && deleteMutation.isPending,
|
|
3112
|
+
onClick: () => deleteMutation.mutate(method.id),
|
|
3113
|
+
children: [
|
|
3114
|
+
deletingId === method.id && deleteMutation.isPending ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "mr-2 h-4 w-4" }),
|
|
3115
|
+
t.remove
|
|
3116
|
+
]
|
|
3117
|
+
}
|
|
3118
|
+
)
|
|
3119
|
+
] })
|
|
3715
3120
|
]
|
|
3716
3121
|
},
|
|
3717
3122
|
method.id
|
|
3718
3123
|
)) }) }),
|
|
3719
|
-
/* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isModalOpen, onOpenChange: setIsModalOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "max-h-[95vh] overflow-y-auto
|
|
3124
|
+
/* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isModalOpen, onOpenChange: setIsModalOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "max-h-[95vh] overflow-y-auto", children: [
|
|
3720
3125
|
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
|
|
3721
|
-
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children:
|
|
3722
|
-
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children:
|
|
3126
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: t.addNewCard }),
|
|
3127
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: t.addNewCardDescription })
|
|
3723
3128
|
] }),
|
|
3724
3129
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3725
3130
|
CardDetailsForm,
|
|
@@ -3727,7 +3132,7 @@ var PaymentMethodsSection = ({
|
|
|
3727
3132
|
visible: isModalOpen,
|
|
3728
3133
|
collectPrefix,
|
|
3729
3134
|
submitting: createMutation.isPending,
|
|
3730
|
-
submitLabel:
|
|
3135
|
+
submitLabel: t.saveCard,
|
|
3731
3136
|
defaultValues: {
|
|
3732
3137
|
email: userEmail ?? "",
|
|
3733
3138
|
country: defaultCountry,
|
|
@@ -3735,640 +3140,36 @@ var PaymentMethodsSection = ({
|
|
|
3735
3140
|
},
|
|
3736
3141
|
externalError: createMutation.error?.message ?? null,
|
|
3737
3142
|
onTokenize: handleCardTokenize,
|
|
3738
|
-
className: "rounded-2xl border border-
|
|
3143
|
+
className: "rounded-2xl border border-white/10 bg-white/5 p-6"
|
|
3739
3144
|
}
|
|
3740
3145
|
)
|
|
3741
|
-
] }) })
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
const [state, setState] = React3.useState({
|
|
3747
|
-
wallets: [],
|
|
3748
|
-
isLoading: false,
|
|
3749
|
-
error: null
|
|
3750
|
-
});
|
|
3751
|
-
const fetchWallets = React3.useCallback(async () => {
|
|
3752
|
-
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
3753
|
-
try {
|
|
3754
|
-
const wallets2 = await services.solanaWallets.list();
|
|
3755
|
-
setState({ wallets: wallets2, isLoading: false, error: null });
|
|
3756
|
-
return wallets2;
|
|
3757
|
-
} catch (error) {
|
|
3758
|
-
const message = error instanceof Error ? error.message : "Failed to load wallets";
|
|
3759
|
-
console.error("payments-ui: wallet list fetch failed", error);
|
|
3760
|
-
setState((prev) => ({ ...prev, isLoading: false, error: message }));
|
|
3761
|
-
throw error;
|
|
3762
|
-
}
|
|
3763
|
-
}, [services.solanaWallets]);
|
|
3764
|
-
const deleteWallet = React3.useCallback(
|
|
3765
|
-
async (walletIdOrAddress) => {
|
|
3766
|
-
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
3767
|
-
try {
|
|
3768
|
-
await services.solanaWallets.remove(walletIdOrAddress);
|
|
3769
|
-
setState((prev) => ({
|
|
3770
|
-
...prev,
|
|
3771
|
-
wallets: prev.wallets.filter(
|
|
3772
|
-
(wallet) => wallet.id !== walletIdOrAddress && wallet.address !== walletIdOrAddress
|
|
3773
|
-
),
|
|
3774
|
-
isLoading: false
|
|
3775
|
-
}));
|
|
3776
|
-
} catch (error) {
|
|
3777
|
-
const message = error instanceof Error ? error.message : "Failed to remove wallet";
|
|
3778
|
-
console.error("payments-ui: wallet removal failed", error);
|
|
3779
|
-
setState((prev) => ({ ...prev, isLoading: false, error: message }));
|
|
3780
|
-
throw error;
|
|
3781
|
-
}
|
|
3782
|
-
},
|
|
3783
|
-
[services.solanaWallets]
|
|
3784
|
-
);
|
|
3785
|
-
const addWallet = React3.useCallback((wallet) => {
|
|
3786
|
-
setState((prev) => ({ ...prev, wallets: [...prev.wallets, wallet] }));
|
|
3787
|
-
}, []);
|
|
3788
|
-
const updateWallet = React3.useCallback((walletId, updates) => {
|
|
3789
|
-
setState((prev) => ({
|
|
3790
|
-
...prev,
|
|
3791
|
-
wallets: prev.wallets.map(
|
|
3792
|
-
(wallet) => wallet.id === walletId ? { ...wallet, ...updates } : wallet
|
|
3793
|
-
)
|
|
3794
|
-
}));
|
|
3795
|
-
}, []);
|
|
3796
|
-
const clearError = React3.useCallback(() => {
|
|
3797
|
-
setState((prev) => ({ ...prev, error: null }));
|
|
3798
|
-
}, []);
|
|
3799
|
-
const findWalletByAddress = React3.useCallback(
|
|
3800
|
-
(address) => state.wallets.find((wallet) => wallet.address === address),
|
|
3801
|
-
[state.wallets]
|
|
3802
|
-
);
|
|
3803
|
-
const getVerifiedWallets = React3.useCallback(
|
|
3804
|
-
() => state.wallets.filter((wallet) => wallet.is_verified),
|
|
3805
|
-
[state.wallets]
|
|
3806
|
-
);
|
|
3807
|
-
React3.useEffect(() => {
|
|
3808
|
-
if (options.autoFetch !== false) {
|
|
3809
|
-
fetchWallets().catch(() => {
|
|
3810
|
-
});
|
|
3811
|
-
}
|
|
3812
|
-
}, [fetchWallets, options.autoFetch]);
|
|
3813
|
-
return {
|
|
3814
|
-
wallets: state.wallets,
|
|
3815
|
-
isLoading: state.isLoading,
|
|
3816
|
-
error: state.error,
|
|
3817
|
-
fetchWallets,
|
|
3818
|
-
deleteWallet,
|
|
3819
|
-
addWallet,
|
|
3820
|
-
updateWallet,
|
|
3821
|
-
clearError,
|
|
3822
|
-
findWalletByAddress,
|
|
3823
|
-
getVerifiedWallets,
|
|
3824
|
-
hasVerifiedWallets: state.wallets.some((w) => w.is_verified),
|
|
3825
|
-
totalWallets: state.wallets.length
|
|
3826
|
-
};
|
|
3827
|
-
};
|
|
3828
|
-
var useWalletVerification = () => {
|
|
3829
|
-
const { services } = usePaymentContext();
|
|
3830
|
-
const { publicKey, signMessage } = walletAdapterReact.useWallet();
|
|
3831
|
-
const [state, setState] = React3.useState({
|
|
3832
|
-
isVerifying: false,
|
|
3833
|
-
isVerified: false,
|
|
3834
|
-
error: null
|
|
3835
|
-
});
|
|
3836
|
-
const signAndVerifyWallet = React3.useCallback(
|
|
3837
|
-
async (walletAddress, message, nonce) => {
|
|
3838
|
-
if (!publicKey || !signMessage) {
|
|
3839
|
-
throw new Error("Wallet not connected or signing unavailable");
|
|
3840
|
-
}
|
|
3841
|
-
if (publicKey.toBase58() !== walletAddress) {
|
|
3842
|
-
throw new Error("Connected wallet does not match target wallet");
|
|
3843
|
-
}
|
|
3844
|
-
setState((prev) => ({ ...prev, isVerifying: true, error: null }));
|
|
3845
|
-
try {
|
|
3846
|
-
const encodedMessage = new TextEncoder().encode(message);
|
|
3847
|
-
const signature = await signMessage(encodedMessage);
|
|
3848
|
-
const signatureBase58 = bs58__default.default.encode(signature);
|
|
3849
|
-
const response = await services.solanaWallets.verify(
|
|
3850
|
-
walletAddress,
|
|
3851
|
-
signatureBase58,
|
|
3852
|
-
nonce
|
|
3853
|
-
);
|
|
3854
|
-
setState({ isVerifying: false, isVerified: response.verified, error: null });
|
|
3855
|
-
return response;
|
|
3856
|
-
} catch (error) {
|
|
3857
|
-
const message2 = error instanceof Error ? error.message : "Wallet verification failed";
|
|
3858
|
-
console.error("payments-ui: wallet verification failed", error);
|
|
3859
|
-
setState({ isVerifying: false, isVerified: false, error: message2 });
|
|
3860
|
-
throw error;
|
|
3861
|
-
}
|
|
3862
|
-
},
|
|
3863
|
-
[publicKey, signMessage, services.solanaWallets]
|
|
3864
|
-
);
|
|
3865
|
-
const clearError = React3.useCallback(() => {
|
|
3866
|
-
setState((prev) => ({ ...prev, error: null }));
|
|
3867
|
-
}, []);
|
|
3868
|
-
const resetVerification = React3.useCallback(() => {
|
|
3869
|
-
setState({ isVerifying: false, isVerified: false, error: null });
|
|
3870
|
-
}, []);
|
|
3871
|
-
const autoVerifyWallet = React3.useCallback(
|
|
3872
|
-
async (walletAddress, message, nonce) => {
|
|
3873
|
-
try {
|
|
3874
|
-
return await signAndVerifyWallet(walletAddress, message, nonce);
|
|
3875
|
-
} catch (error) {
|
|
3876
|
-
console.warn("payments-ui: auto-verification skipped", error);
|
|
3877
|
-
return null;
|
|
3878
|
-
}
|
|
3879
|
-
},
|
|
3880
|
-
[signAndVerifyWallet]
|
|
3881
|
-
);
|
|
3882
|
-
return {
|
|
3883
|
-
...state,
|
|
3884
|
-
signAndVerifyWallet,
|
|
3885
|
-
autoVerifyWallet,
|
|
3886
|
-
clearError,
|
|
3887
|
-
resetVerification
|
|
3888
|
-
};
|
|
3889
|
-
};
|
|
3890
|
-
var useWalletConnection = () => {
|
|
3891
|
-
const { services } = usePaymentContext();
|
|
3892
|
-
const { publicKey, connected, connecting, disconnect, wallet } = walletAdapterReact.useWallet();
|
|
3893
|
-
const [state, setState] = React3.useState({
|
|
3894
|
-
isConnected: false,
|
|
3895
|
-
isConnecting: false,
|
|
3896
|
-
publicKey: null,
|
|
3897
|
-
wallets: [],
|
|
3898
|
-
isLoading: false,
|
|
3899
|
-
error: null
|
|
3900
|
-
});
|
|
3901
|
-
React3.useEffect(() => {
|
|
3902
|
-
setState((prev) => ({
|
|
3903
|
-
...prev,
|
|
3904
|
-
isConnected: connected,
|
|
3905
|
-
isConnecting: connecting,
|
|
3906
|
-
publicKey: publicKey?.toBase58() ?? null
|
|
3907
|
-
}));
|
|
3908
|
-
}, [connected, connecting, publicKey]);
|
|
3909
|
-
const connectWalletToBackend = React3.useCallback(
|
|
3910
|
-
async (address) => {
|
|
3911
|
-
if (!address) {
|
|
3912
|
-
throw new Error("Wallet address is required");
|
|
3913
|
-
}
|
|
3914
|
-
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
3915
|
-
try {
|
|
3916
|
-
const challenge = await services.solanaWallets.requestChallenge(address);
|
|
3917
|
-
setState((prev) => ({ ...prev, isLoading: false }));
|
|
3918
|
-
return challenge;
|
|
3919
|
-
} catch (error) {
|
|
3920
|
-
const message = error instanceof Error ? error.message : "Wallet challenge failed";
|
|
3921
|
-
console.error("payments-ui: wallet challenge failed", error);
|
|
3922
|
-
setState((prev) => ({ ...prev, isLoading: false, error: message }));
|
|
3923
|
-
throw error;
|
|
3924
|
-
}
|
|
3925
|
-
},
|
|
3926
|
-
[services.solanaWallets]
|
|
3927
|
-
);
|
|
3928
|
-
const connectWallet = React3.useCallback(async () => {
|
|
3929
|
-
if (!wallet) {
|
|
3930
|
-
throw new Error("No wallet adapter selected");
|
|
3931
|
-
}
|
|
3932
|
-
setState((prev) => ({ ...prev, isConnecting: true, error: null }));
|
|
3933
|
-
try {
|
|
3934
|
-
await wallet.adapter.connect();
|
|
3935
|
-
if (publicKey) {
|
|
3936
|
-
await connectWalletToBackend(publicKey.toBase58());
|
|
3937
|
-
}
|
|
3938
|
-
} catch (error) {
|
|
3939
|
-
const message = error instanceof Error ? error.message : "Failed to connect wallet";
|
|
3940
|
-
console.error("payments-ui: wallet connection failed", error);
|
|
3941
|
-
setState((prev) => ({ ...prev, isConnecting: false, error: message }));
|
|
3942
|
-
throw error;
|
|
3943
|
-
} finally {
|
|
3944
|
-
setState((prev) => ({ ...prev, isConnecting: false }));
|
|
3945
|
-
}
|
|
3946
|
-
}, [wallet, publicKey, connectWalletToBackend]);
|
|
3947
|
-
const disconnectWallet = React3.useCallback(async () => {
|
|
3948
|
-
try {
|
|
3949
|
-
await disconnect();
|
|
3950
|
-
setState((prev) => ({
|
|
3951
|
-
...prev,
|
|
3952
|
-
isConnected: false,
|
|
3953
|
-
publicKey: null,
|
|
3954
|
-
wallets: [],
|
|
3955
|
-
error: null
|
|
3956
|
-
}));
|
|
3957
|
-
} catch (error) {
|
|
3958
|
-
const message = error instanceof Error ? error.message : "Failed to disconnect wallet";
|
|
3959
|
-
console.error("payments-ui: wallet disconnect failed", error);
|
|
3960
|
-
setState((prev) => ({ ...prev, error: message }));
|
|
3961
|
-
throw error;
|
|
3962
|
-
}
|
|
3963
|
-
}, [disconnect]);
|
|
3964
|
-
const clearError = React3.useCallback(() => {
|
|
3965
|
-
setState((prev) => ({ ...prev, error: null }));
|
|
3966
|
-
}, []);
|
|
3967
|
-
return {
|
|
3968
|
-
...state,
|
|
3969
|
-
walletName: wallet?.adapter.name,
|
|
3970
|
-
walletIcon: wallet?.adapter.icon,
|
|
3971
|
-
connectWallet,
|
|
3972
|
-
disconnectWallet,
|
|
3973
|
-
connectWalletToBackend,
|
|
3974
|
-
clearError
|
|
3975
|
-
};
|
|
3976
|
-
};
|
|
3977
|
-
var notifyDefault4 = (payload) => {
|
|
3978
|
-
console.log("[payments-ui] wallet-card", payload);
|
|
3979
|
-
};
|
|
3980
|
-
var WalletCard = ({
|
|
3981
|
-
wallet,
|
|
3982
|
-
isPrimary = false,
|
|
3983
|
-
isConnected = false,
|
|
3984
|
-
balance,
|
|
3985
|
-
onSetPrimary,
|
|
3986
|
-
onVerify,
|
|
3987
|
-
onDelete,
|
|
3988
|
-
isVerifying = false,
|
|
3989
|
-
isDeleting = false,
|
|
3990
|
-
notify = notifyDefault4
|
|
3991
|
-
}) => {
|
|
3992
|
-
const [isCopying, setIsCopying] = React3.useState(false);
|
|
3993
|
-
const formatAddress = (address) => address.length <= 12 ? address : `${address.slice(0, 4)}...${address.slice(-4)}`;
|
|
3994
|
-
const copyToClipboard = async (text) => {
|
|
3995
|
-
setIsCopying(true);
|
|
3996
|
-
try {
|
|
3997
|
-
await navigator.clipboard.writeText(text);
|
|
3998
|
-
notify({ title: "Copied", description: "Wallet address copied to clipboard" });
|
|
3999
|
-
} catch (error) {
|
|
4000
|
-
notify({ title: "Failed to copy", description: error.message, status: "destructive" });
|
|
4001
|
-
} finally {
|
|
4002
|
-
setTimeout(() => setIsCopying(false), 500);
|
|
4003
|
-
}
|
|
4004
|
-
};
|
|
4005
|
-
const openExplorer = () => {
|
|
4006
|
-
window.open(`https://solscan.io/account/${wallet.address}`, "_blank", "noopener,noreferrer");
|
|
4007
|
-
};
|
|
4008
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4009
|
-
"div",
|
|
4010
|
-
{
|
|
4011
|
-
className: cn(
|
|
4012
|
-
"rounded-lg border bg-background/40 p-4 transition-shadow",
|
|
4013
|
-
isPrimary && "border-primary/50 shadow-lg",
|
|
4014
|
-
isConnected && "ring-1 ring-primary"
|
|
4015
|
-
),
|
|
4016
|
-
children: [
|
|
4017
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between", children: [
|
|
4018
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
4019
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-primary/20", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-5 w-5 rounded-full bg-gradient-to-br from-primary to-primary/60" }) }),
|
|
4020
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
|
|
4021
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
4022
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-sm font-medium", children: formatAddress(wallet.address) }),
|
|
4023
|
-
isPrimary && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 rounded-full bg-yellow-500/20 px-2 py-0.5 text-xs text-yellow-500", children: [
|
|
4024
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Star, { className: "h-3 w-3 fill-yellow-500 text-yellow-500" }),
|
|
4025
|
-
" Primary"
|
|
4026
|
-
] }),
|
|
4027
|
-
wallet.is_verified ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 text-xs text-emerald-400", children: [
|
|
4028
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle, { className: "h-3.5 w-3.5" }),
|
|
4029
|
-
" Verified"
|
|
4030
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 text-xs text-amber-400", children: [
|
|
4031
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-3.5 w-3.5" }),
|
|
4032
|
-
" Unverified"
|
|
4033
|
-
] }),
|
|
4034
|
-
isConnected && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-blue-500/20 px-2 py-0.5 text-xs text-blue-400", children: "Connected" })
|
|
4035
|
-
] }),
|
|
4036
|
-
balance !== null && typeof balance !== "undefined" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 text-sm text-muted-foreground", children: [
|
|
4037
|
-
"Balance: ",
|
|
4038
|
-
balance.toFixed(4),
|
|
4039
|
-
" SOL"
|
|
4040
|
-
] }),
|
|
4041
|
-
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-0.5 text-xs text-muted-foreground", children: [
|
|
4042
|
-
"Added ",
|
|
4043
|
-
new Date(wallet.created_at).toLocaleDateString()
|
|
4044
|
-
] })
|
|
4045
|
-
] })
|
|
4046
|
-
] }) }),
|
|
4047
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
4048
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4049
|
-
Button,
|
|
4050
|
-
{
|
|
4051
|
-
variant: "ghost",
|
|
4052
|
-
size: "icon",
|
|
4053
|
-
className: "h-8 w-8",
|
|
4054
|
-
onClick: () => copyToClipboard(wallet.address),
|
|
4055
|
-
disabled: isCopying,
|
|
4056
|
-
children: isCopying ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-4 w-4" })
|
|
4057
|
-
}
|
|
4058
|
-
),
|
|
4059
|
-
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "icon", className: "h-8 w-8", onClick: openExplorer, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-4 w-4" }) })
|
|
4060
|
-
] })
|
|
4061
|
-
] }),
|
|
4062
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [
|
|
4063
|
-
!isPrimary && onSetPrimary && wallet.is_verified && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4064
|
-
Button,
|
|
4065
|
-
{
|
|
4066
|
-
variant: "outline",
|
|
4067
|
-
size: "sm",
|
|
4068
|
-
className: "border-primary/40 text-primary",
|
|
4069
|
-
onClick: () => onSetPrimary(wallet.id),
|
|
4070
|
-
children: [
|
|
4071
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Star, { className: "mr-1 h-3 w-3" }),
|
|
4072
|
-
" Set Primary"
|
|
4073
|
-
]
|
|
4074
|
-
}
|
|
4075
|
-
),
|
|
4076
|
-
!wallet.is_verified && onVerify && isConnected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4077
|
-
Button,
|
|
4078
|
-
{
|
|
4079
|
-
variant: "outline",
|
|
4080
|
-
size: "sm",
|
|
4081
|
-
className: "border-emerald-500/40 text-emerald-400",
|
|
4082
|
-
onClick: () => onVerify(wallet),
|
|
4083
|
-
disabled: isVerifying,
|
|
4084
|
-
children: isVerifying ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4085
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-1 h-3 w-3 animate-spin" }),
|
|
4086
|
-
" Verifying..."
|
|
4087
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4088
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Shield, { className: "mr-1 h-3 w-3" }),
|
|
4089
|
-
" Verify"
|
|
4090
|
-
] })
|
|
4091
|
-
}
|
|
4092
|
-
),
|
|
4093
|
-
onDelete && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4094
|
-
Button,
|
|
4095
|
-
{
|
|
4096
|
-
variant: "outline",
|
|
4097
|
-
size: "sm",
|
|
4098
|
-
className: "ml-auto border-destructive/40 text-destructive",
|
|
4099
|
-
onClick: () => onDelete(wallet.id),
|
|
4100
|
-
disabled: isDeleting,
|
|
4101
|
-
children: isDeleting ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3 w-3 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3 w-3" })
|
|
4102
|
-
}
|
|
4103
|
-
)
|
|
4104
|
-
] })
|
|
4105
|
-
]
|
|
4106
|
-
}
|
|
4107
|
-
);
|
|
4108
|
-
};
|
|
4109
|
-
var EmptyWalletState = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [
|
|
4110
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { className: "mb-4 h-12 w-12 text-muted-foreground" }),
|
|
4111
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-2 text-lg font-medium", children: "No wallets connected" }),
|
|
4112
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-6 text-sm text-muted-foreground", children: "Connect your Solana wallet to get started" }),
|
|
4113
|
-
/* @__PURE__ */ jsxRuntime.jsx(walletAdapterReactUi.WalletMultiButton, { className: "!bg-primary text-primary-foreground hover:!bg-primary/90" })
|
|
4114
|
-
] });
|
|
4115
|
-
var notifyDefault5 = (payload) => {
|
|
4116
|
-
console.log("[payments-ui] solana-wallets", payload);
|
|
4117
|
-
};
|
|
4118
|
-
var SolanaWalletSection = ({
|
|
4119
|
-
onNotify,
|
|
4120
|
-
rpcUrl
|
|
4121
|
-
}) => {
|
|
4122
|
-
const notify = onNotify ?? notifyDefault5;
|
|
4123
|
-
const { config } = usePaymentContext();
|
|
4124
|
-
const { connected, publicKey, disconnect } = walletAdapterReact.useWallet();
|
|
4125
|
-
const { wallets: wallets2, isLoading, deleteWallet, fetchWallets } = useWalletList();
|
|
4126
|
-
const { signAndVerifyWallet } = useWalletVerification();
|
|
4127
|
-
const walletConnection = useWalletConnection();
|
|
4128
|
-
const [primaryWalletId, setPrimaryWalletId] = React3.useState(null);
|
|
4129
|
-
const [showOtherWallets, setShowOtherWallets] = React3.useState(false);
|
|
4130
|
-
const [balances, setBalances] = React3.useState({});
|
|
4131
|
-
const [verifyingWalletId, setVerifyingWalletId] = React3.useState(null);
|
|
4132
|
-
const [deletingWalletId, setDeletingWalletId] = React3.useState(null);
|
|
4133
|
-
const [walletToDelete, setWalletToDelete] = React3.useState(null);
|
|
4134
|
-
const [isRegistering, setIsRegistering] = React3.useState(false);
|
|
4135
|
-
const rpcEndpoint = rpcUrl || config.solanaRpcUrl || "https://api.mainnet-beta.solana.com";
|
|
4136
|
-
const connection = React3.useMemo(() => new web3_js.Connection(rpcEndpoint), [rpcEndpoint]);
|
|
4137
|
-
const primaryWallet = wallets2.find((w) => w.id === primaryWalletId) ?? wallets2.find((w) => w.is_verified) ?? null;
|
|
4138
|
-
const otherWallets = wallets2.filter((w) => w.id !== primaryWallet?.id);
|
|
4139
|
-
const fetchBalance = React3.useCallback(
|
|
4140
|
-
async (address) => {
|
|
4141
|
-
try {
|
|
4142
|
-
const pubkey = new web3_js.PublicKey(address);
|
|
4143
|
-
const balance = await connection.getBalance(pubkey);
|
|
4144
|
-
return balance / web3_js.LAMPORTS_PER_SOL;
|
|
4145
|
-
} catch (error) {
|
|
4146
|
-
console.error("payments-ui: failed to fetch balance", error);
|
|
4147
|
-
return null;
|
|
4148
|
-
}
|
|
4149
|
-
},
|
|
4150
|
-
[connection]
|
|
4151
|
-
);
|
|
4152
|
-
const fetchAllBalances = React3.useCallback(async () => {
|
|
4153
|
-
const results = await Promise.all(
|
|
4154
|
-
wallets2.map(async (wallet) => ({ address: wallet.address, balance: await fetchBalance(wallet.address) }))
|
|
4155
|
-
);
|
|
4156
|
-
const next = {};
|
|
4157
|
-
results.forEach(({ address, balance }) => {
|
|
4158
|
-
if (balance !== null && typeof balance !== "undefined") {
|
|
4159
|
-
next[address] = balance;
|
|
4160
|
-
}
|
|
4161
|
-
});
|
|
4162
|
-
setBalances(next);
|
|
4163
|
-
}, [wallets2, fetchBalance]);
|
|
4164
|
-
React3.useEffect(() => {
|
|
4165
|
-
if (wallets2.length > 0) {
|
|
4166
|
-
fetchAllBalances().catch(() => void 0);
|
|
4167
|
-
}
|
|
4168
|
-
}, [wallets2, fetchAllBalances]);
|
|
4169
|
-
React3.useEffect(() => {
|
|
4170
|
-
const verifiedWallet = wallets2.find((w) => w.is_verified);
|
|
4171
|
-
if (verifiedWallet && !primaryWalletId) {
|
|
4172
|
-
setPrimaryWalletId(verifiedWallet.id);
|
|
4173
|
-
}
|
|
4174
|
-
}, [wallets2, primaryWalletId]);
|
|
4175
|
-
const registerWallet = React3.useCallback(async () => {
|
|
4176
|
-
if (!connected || !publicKey || isRegistering) return;
|
|
4177
|
-
setIsRegistering(true);
|
|
4178
|
-
try {
|
|
4179
|
-
const challenge = await walletConnection.connectWalletToBackend(publicKey.toBase58());
|
|
4180
|
-
if (!challenge?.message) {
|
|
4181
|
-
throw new Error("Failed to retrieve wallet verification challenge");
|
|
4182
|
-
}
|
|
4183
|
-
await signAndVerifyWallet(challenge.wallet, challenge.message, challenge.nonce);
|
|
4184
|
-
await fetchWallets();
|
|
4185
|
-
notify({
|
|
4186
|
-
title: "Wallet verified",
|
|
4187
|
-
description: "Your wallet has been linked successfully.",
|
|
4188
|
-
status: "success"
|
|
4189
|
-
});
|
|
4190
|
-
} catch (error) {
|
|
4191
|
-
notify({
|
|
4192
|
-
title: "Wallet verification failed",
|
|
4193
|
-
description: error instanceof Error ? error.message : "Failed to verify wallet",
|
|
4194
|
-
status: "destructive"
|
|
4195
|
-
});
|
|
4196
|
-
} finally {
|
|
4197
|
-
setIsRegistering(false);
|
|
4198
|
-
}
|
|
4199
|
-
}, [connected, publicKey, isRegistering, walletConnection, signAndVerifyWallet, fetchWallets, notify]);
|
|
4200
|
-
React3.useEffect(() => {
|
|
4201
|
-
if (connected && publicKey && !walletConnection.isConnecting && wallets2.length === 0) {
|
|
4202
|
-
registerWallet().catch(() => void 0);
|
|
4203
|
-
}
|
|
4204
|
-
}, [connected, publicKey, walletConnection.isConnecting, wallets2.length, registerWallet]);
|
|
4205
|
-
const handleVerifyWallet = React3.useCallback(
|
|
4206
|
-
async (wallet) => {
|
|
4207
|
-
if (!connected || publicKey?.toBase58() !== wallet.address) {
|
|
4208
|
-
notify({
|
|
4209
|
-
title: "Connect wallet first",
|
|
4210
|
-
description: "Please connect the wallet you want to verify.",
|
|
4211
|
-
status: "destructive"
|
|
4212
|
-
});
|
|
4213
|
-
return;
|
|
4214
|
-
}
|
|
4215
|
-
setVerifyingWalletId(wallet.id);
|
|
4216
|
-
try {
|
|
4217
|
-
const challenge = await walletConnection.connectWalletToBackend(wallet.address);
|
|
4218
|
-
if (!challenge?.message) {
|
|
4219
|
-
throw new Error("Failed to retrieve verification challenge");
|
|
4220
|
-
}
|
|
4221
|
-
await signAndVerifyWallet(challenge.wallet, challenge.message, challenge.nonce);
|
|
4222
|
-
await fetchWallets();
|
|
4223
|
-
notify({ title: "Wallet verified", status: "success" });
|
|
4224
|
-
} catch (error) {
|
|
4225
|
-
notify({
|
|
4226
|
-
title: "Verification failed",
|
|
4227
|
-
description: error instanceof Error ? error.message : "Failed to verify wallet",
|
|
4228
|
-
status: "destructive"
|
|
4229
|
-
});
|
|
4230
|
-
} finally {
|
|
4231
|
-
setVerifyingWalletId(null);
|
|
4232
|
-
}
|
|
4233
|
-
},
|
|
4234
|
-
[connected, publicKey, walletConnection, signAndVerifyWallet, fetchWallets, notify]
|
|
4235
|
-
);
|
|
4236
|
-
const handleDeleteWallet = React3.useCallback(
|
|
4237
|
-
async (walletId) => {
|
|
4238
|
-
setDeletingWalletId(walletId);
|
|
4239
|
-
try {
|
|
4240
|
-
await deleteWallet(walletId);
|
|
4241
|
-
if (primaryWalletId === walletId) {
|
|
4242
|
-
setPrimaryWalletId(null);
|
|
4243
|
-
}
|
|
4244
|
-
if (connected && publicKey) {
|
|
4245
|
-
const deletedWallet = wallets2.find((w) => w.id === walletId);
|
|
4246
|
-
if (deletedWallet?.address === publicKey.toBase58()) {
|
|
4247
|
-
await disconnect();
|
|
4248
|
-
}
|
|
4249
|
-
}
|
|
4250
|
-
notify({ title: "Wallet removed", status: "success" });
|
|
4251
|
-
} catch (error) {
|
|
4252
|
-
notify({
|
|
4253
|
-
title: "Failed to remove wallet",
|
|
4254
|
-
description: error instanceof Error ? error.message : "Please try again",
|
|
4255
|
-
status: "destructive"
|
|
4256
|
-
});
|
|
4257
|
-
} finally {
|
|
4258
|
-
setDeletingWalletId(null);
|
|
4259
|
-
setWalletToDelete(null);
|
|
4260
|
-
}
|
|
4261
|
-
},
|
|
4262
|
-
[deleteWallet, primaryWalletId, connected, publicKey, wallets2, disconnect, notify]
|
|
4263
|
-
);
|
|
4264
|
-
const handleSetPrimary = (walletId) => {
|
|
4265
|
-
setPrimaryWalletId(walletId);
|
|
4266
|
-
notify({ title: "Primary wallet updated", status: "success" });
|
|
4267
|
-
};
|
|
4268
|
-
const isWalletRegistered = connected && publicKey && wallets2.some((w) => w.address === publicKey.toBase58());
|
|
4269
|
-
if (isLoading && wallets2.length === 0) {
|
|
4270
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-0 bg-background/5", children: [
|
|
4271
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-xl", children: "Solana Wallets" }) }),
|
|
4272
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardContent, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center py-8", children: [
|
|
4273
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-6 w-6 animate-spin text-muted-foreground" }),
|
|
4274
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Loading wallets..." })
|
|
4275
|
-
] }) })
|
|
4276
|
-
] });
|
|
4277
|
-
}
|
|
4278
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4279
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-0 bg-background/5", children: [
|
|
4280
|
-
/* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { children: [
|
|
4281
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-xl", children: "Solana Wallets" }),
|
|
4282
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: "Connect and manage your Solana wallets for payments" })
|
|
4283
|
-
] }),
|
|
4284
|
-
/* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "space-y-4", children: wallets2.length === 0 && !connected ? /* @__PURE__ */ jsxRuntime.jsx(EmptyWalletState, {}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4285
|
-
primaryWallet && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4286
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-3 text-sm font-medium uppercase tracking-wide text-muted-foreground", children: "Primary Wallet" }),
|
|
4287
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4288
|
-
WalletCard,
|
|
4289
|
-
{
|
|
4290
|
-
wallet: primaryWallet,
|
|
4291
|
-
isPrimary: true,
|
|
4292
|
-
isConnected: connected && publicKey?.toBase58() === primaryWallet.address,
|
|
4293
|
-
balance: balances[primaryWallet.address],
|
|
4294
|
-
onVerify: handleVerifyWallet,
|
|
4295
|
-
onDelete: (id) => {
|
|
4296
|
-
const target = wallets2.find((w) => w.id === id);
|
|
4297
|
-
if (target) setWalletToDelete(target);
|
|
4298
|
-
},
|
|
4299
|
-
isVerifying: verifyingWalletId === primaryWallet.id,
|
|
4300
|
-
isDeleting: deletingWalletId === primaryWallet.id,
|
|
4301
|
-
notify
|
|
4302
|
-
}
|
|
4303
|
-
)
|
|
4304
|
-
] }),
|
|
4305
|
-
otherWallets.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4306
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4307
|
-
"button",
|
|
4308
|
-
{
|
|
4309
|
-
className: "mb-3 flex w-full items-center justify-between text-left",
|
|
4310
|
-
onClick: () => setShowOtherWallets((prev) => !prev),
|
|
4311
|
-
children: [
|
|
4312
|
-
/* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "text-sm font-medium uppercase tracking-wide text-muted-foreground", children: [
|
|
4313
|
-
"Other Wallets (",
|
|
4314
|
-
otherWallets.length,
|
|
4315
|
-
")"
|
|
4316
|
-
] }),
|
|
4317
|
-
showOtherWallets ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "h-4 w-4 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4 text-muted-foreground" })
|
|
4318
|
-
]
|
|
4319
|
-
}
|
|
4320
|
-
),
|
|
4321
|
-
showOtherWallets && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: otherWallets.map((wallet) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4322
|
-
WalletCard,
|
|
4323
|
-
{
|
|
4324
|
-
wallet,
|
|
4325
|
-
isConnected: connected && publicKey?.toBase58() === wallet.address,
|
|
4326
|
-
balance: balances[wallet.address],
|
|
4327
|
-
onSetPrimary: handleSetPrimary,
|
|
4328
|
-
onVerify: handleVerifyWallet,
|
|
4329
|
-
onDelete: (id) => {
|
|
4330
|
-
const target = wallets2.find((w) => w.id === id);
|
|
4331
|
-
if (target) setWalletToDelete(target);
|
|
4332
|
-
},
|
|
4333
|
-
isVerifying: verifyingWalletId === wallet.id,
|
|
4334
|
-
isDeleting: deletingWalletId === wallet.id,
|
|
4335
|
-
notify
|
|
4336
|
-
},
|
|
4337
|
-
wallet.id
|
|
4338
|
-
)) })
|
|
4339
|
-
] }),
|
|
4340
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-4", children: connected && publicKey ? isWalletRegistered ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
4341
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-emerald-500/40 bg-emerald-500/10 p-3 text-sm text-emerald-200", children: [
|
|
4342
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle, { className: "h-4 w-4" }),
|
|
4343
|
-
" Connected wallet is verified and linked to your account."
|
|
4344
|
-
] }),
|
|
4345
|
-
/* @__PURE__ */ jsxRuntime.jsx(walletAdapterReactUi.WalletMultiButton, { className: "w-full !bg-primary text-primary-foreground" })
|
|
4346
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
|
|
4347
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-amber-500/40 bg-amber-500/10 p-3 text-sm text-amber-200", children: "Your connected wallet is not registered with your account." }),
|
|
4348
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
|
|
4349
|
-
/* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: registerWallet, disabled: isRegistering || walletConnection.isConnecting, className: "flex-1 bg-primary text-primary-foreground", children: isRegistering ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4350
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
4351
|
-
" Registering..."
|
|
4352
|
-
] }) : "Register This Wallet" }),
|
|
4353
|
-
/* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: () => disconnect(), variant: "outline", className: "border-border", children: "Disconnect" })
|
|
4354
|
-
] })
|
|
4355
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx(walletAdapterReactUi.WalletMultiButton, { className: "w-full !bg-primary text-primary-foreground" }) })
|
|
4356
|
-
] }) })
|
|
4357
|
-
] }),
|
|
4358
|
-
/* @__PURE__ */ jsxRuntime.jsx(AlertDialog, { open: !!walletToDelete, onOpenChange: () => setWalletToDelete(null), children: /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogContent, { children: [
|
|
4359
|
-
/* @__PURE__ */ jsxRuntime.jsxs(AlertDialogHeader, { children: [
|
|
4360
|
-
/* @__PURE__ */ jsxRuntime.jsx(AlertDialogTitle, { children: "Remove Wallet" }),
|
|
4361
|
-
/* @__PURE__ */ jsxRuntime.jsx(AlertDialogDescription, { children: "Are you sure you want to remove this wallet from your account? This action cannot be undone." })
|
|
3146
|
+
] }) }),
|
|
3147
|
+
/* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: Boolean(methodBeingReplaced), onOpenChange: (open) => !open && setMethodBeingReplaced(null), children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "max-h-[95vh] overflow-y-auto", children: [
|
|
3148
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
|
|
3149
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: t.replaceCardTitle }),
|
|
3150
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: t.replaceCardDescription })
|
|
4362
3151
|
] }),
|
|
4363
|
-
/* @__PURE__ */ jsxRuntime.
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
3152
|
+
methodBeingReplaced && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3153
|
+
CardDetailsForm,
|
|
3154
|
+
{
|
|
3155
|
+
visible: true,
|
|
3156
|
+
collectPrefix: `${collectPrefix}-replace-${methodBeingReplaced.id}`,
|
|
3157
|
+
submitting: replaceMutation.isPending,
|
|
3158
|
+
submitLabel: t.replaceCard,
|
|
3159
|
+
defaultValues: {
|
|
3160
|
+
email: userEmail ?? "",
|
|
3161
|
+
country: defaultCountry,
|
|
3162
|
+
provider
|
|
3163
|
+
},
|
|
3164
|
+
externalError: replaceMutation.error?.message ?? null,
|
|
3165
|
+
onTokenize: handleReplaceTokenize,
|
|
3166
|
+
className: "rounded-2xl border border-white/10 bg-white/5 p-6"
|
|
3167
|
+
}
|
|
3168
|
+
)
|
|
4367
3169
|
] }) })
|
|
4368
3170
|
] });
|
|
4369
3171
|
};
|
|
4370
|
-
var
|
|
4371
|
-
var Checkbox = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3172
|
+
var Checkbox = React17__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4372
3173
|
CheckboxPrimitive__namespace.Root,
|
|
4373
3174
|
{
|
|
4374
3175
|
ref,
|
|
@@ -4395,9 +3196,9 @@ var initialState = {
|
|
|
4395
3196
|
termsAccepted: false
|
|
4396
3197
|
};
|
|
4397
3198
|
var WalletDialog = ({ open, onOpenChange }) => {
|
|
4398
|
-
const [form, setForm] =
|
|
4399
|
-
const [errors, setErrors] =
|
|
4400
|
-
const validators =
|
|
3199
|
+
const [form, setForm] = React17.useState(initialState);
|
|
3200
|
+
const [errors, setErrors] = React17.useState({});
|
|
3201
|
+
const validators = React17.useMemo(
|
|
4401
3202
|
() => ({
|
|
4402
3203
|
nameOnCard: (value) => !value ? "Name is required" : void 0,
|
|
4403
3204
|
cardNumber: (value) => /^\d{16}$/.test(value) ? void 0 : "Card number must be 16 digits",
|
|
@@ -4490,10 +3291,10 @@ var WalletDialog = ({ open, onOpenChange }) => {
|
|
|
4490
3291
|
var useTokenBalance = (tokens) => {
|
|
4491
3292
|
const { publicKey } = walletAdapterReact.useWallet();
|
|
4492
3293
|
const { connection } = walletAdapterReact.useConnection();
|
|
4493
|
-
const [balances, setBalances] =
|
|
4494
|
-
const [isLoading, setIsLoading] =
|
|
4495
|
-
const [error, setError] =
|
|
4496
|
-
const fetchTokenBalance =
|
|
3294
|
+
const [balances, setBalances] = React17.useState([]);
|
|
3295
|
+
const [isLoading, setIsLoading] = React17.useState(false);
|
|
3296
|
+
const [error, setError] = React17.useState(null);
|
|
3297
|
+
const fetchTokenBalance = React17.useCallback(
|
|
4497
3298
|
async (token, walletAddress) => {
|
|
4498
3299
|
try {
|
|
4499
3300
|
const mintPublicKey = new web3_js.PublicKey(token.mint);
|
|
@@ -4534,8 +3335,8 @@ var useTokenBalance = (tokens) => {
|
|
|
4534
3335
|
},
|
|
4535
3336
|
[connection]
|
|
4536
3337
|
);
|
|
4537
|
-
const tokensKey =
|
|
4538
|
-
|
|
3338
|
+
const tokensKey = React17.useMemo(() => tokens.map((t) => t.mint).join(","), [tokens]);
|
|
3339
|
+
React17.useEffect(() => {
|
|
4539
3340
|
if (!publicKey || tokens.length === 0) {
|
|
4540
3341
|
setBalances([]);
|
|
4541
3342
|
return;
|
|
@@ -4559,20 +3360,20 @@ var useTokenBalance = (tokens) => {
|
|
|
4559
3360
|
};
|
|
4560
3361
|
fetchAllBalances();
|
|
4561
3362
|
}, [publicKey, tokensKey, fetchTokenBalance]);
|
|
4562
|
-
const getTokenBalance =
|
|
3363
|
+
const getTokenBalance = React17.useCallback(
|
|
4563
3364
|
(tokenSymbol) => {
|
|
4564
3365
|
return balances.find((balance) => balance.token.symbol === tokenSymbol);
|
|
4565
3366
|
},
|
|
4566
3367
|
[balances]
|
|
4567
3368
|
);
|
|
4568
|
-
const
|
|
3369
|
+
const hasSufficientBalance = React17.useCallback(
|
|
4569
3370
|
(tokenSymbol, requiredAmount) => {
|
|
4570
3371
|
const balance = getTokenBalance(tokenSymbol);
|
|
4571
3372
|
return balance ? balance.uiAmount >= requiredAmount : false;
|
|
4572
3373
|
},
|
|
4573
3374
|
[getTokenBalance]
|
|
4574
3375
|
);
|
|
4575
|
-
const getFormattedBalance =
|
|
3376
|
+
const getFormattedBalance = React17.useCallback(
|
|
4576
3377
|
(tokenSymbol) => {
|
|
4577
3378
|
const balance = getTokenBalance(tokenSymbol);
|
|
4578
3379
|
if (!balance) return "0.00";
|
|
@@ -4586,7 +3387,7 @@ var useTokenBalance = (tokens) => {
|
|
|
4586
3387
|
},
|
|
4587
3388
|
[getTokenBalance]
|
|
4588
3389
|
);
|
|
4589
|
-
const refreshBalances =
|
|
3390
|
+
const refreshBalances = React17.useCallback(async () => {
|
|
4590
3391
|
if (!publicKey || tokens.length === 0) {
|
|
4591
3392
|
setBalances([]);
|
|
4592
3393
|
return;
|
|
@@ -4607,7 +3408,7 @@ var useTokenBalance = (tokens) => {
|
|
|
4607
3408
|
setIsLoading(false);
|
|
4608
3409
|
}
|
|
4609
3410
|
}, [publicKey, tokens, fetchTokenBalance]);
|
|
4610
|
-
const getTotalValue =
|
|
3411
|
+
const getTotalValue = React17.useCallback(
|
|
4611
3412
|
(priceData) => {
|
|
4612
3413
|
if (!priceData) return 0;
|
|
4613
3414
|
return balances.reduce((total, balance) => {
|
|
@@ -4626,106 +3427,16 @@ var useTokenBalance = (tokens) => {
|
|
|
4626
3427
|
error,
|
|
4627
3428
|
refreshBalances,
|
|
4628
3429
|
getTokenBalance,
|
|
4629
|
-
hasSufficientBalance
|
|
3430
|
+
hasSufficientBalance,
|
|
4630
3431
|
getFormattedBalance,
|
|
4631
3432
|
getTotalValue,
|
|
4632
3433
|
hasAnyBalance: positiveBalances.length > 0,
|
|
4633
3434
|
isConnected: !!publicKey
|
|
4634
3435
|
};
|
|
4635
3436
|
};
|
|
4636
|
-
var useDirectWalletPayment = () => {
|
|
4637
|
-
const { publicKey, signTransaction, connected } = walletAdapterReact.useWallet();
|
|
4638
|
-
const solanaService = useSolanaService();
|
|
4639
|
-
const [paymentState, setPaymentState] = React3.useState({
|
|
4640
|
-
loading: false,
|
|
4641
|
-
error: null,
|
|
4642
|
-
success: false,
|
|
4643
|
-
transactionId: null
|
|
4644
|
-
});
|
|
4645
|
-
const resetPayment = React3.useCallback(() => {
|
|
4646
|
-
setPaymentState({
|
|
4647
|
-
loading: false,
|
|
4648
|
-
error: null,
|
|
4649
|
-
success: false,
|
|
4650
|
-
transactionId: null
|
|
4651
|
-
});
|
|
4652
|
-
}, []);
|
|
4653
|
-
const payWithWallet = React3.useCallback(
|
|
4654
|
-
async (token, priceId) => {
|
|
4655
|
-
if (!connected || !publicKey || !signTransaction) {
|
|
4656
|
-
setPaymentState((prev) => ({
|
|
4657
|
-
...prev,
|
|
4658
|
-
error: "Wallet not connected. Please connect your wallet first."
|
|
4659
|
-
}));
|
|
4660
|
-
return;
|
|
4661
|
-
}
|
|
4662
|
-
setPaymentState({
|
|
4663
|
-
loading: true,
|
|
4664
|
-
error: null,
|
|
4665
|
-
success: false,
|
|
4666
|
-
transactionId: null
|
|
4667
|
-
});
|
|
4668
|
-
try {
|
|
4669
|
-
console.log("Generating payment transaction...", {
|
|
4670
|
-
token: token.symbol,
|
|
4671
|
-
priceId
|
|
4672
|
-
});
|
|
4673
|
-
const paymentData = await solanaService.generatePayment(
|
|
4674
|
-
priceId,
|
|
4675
|
-
token.symbol,
|
|
4676
|
-
publicKey.toBase58()
|
|
4677
|
-
);
|
|
4678
|
-
const transactionBuffer = buffer.Buffer.from(paymentData.transaction, "base64");
|
|
4679
|
-
const transaction = web3_js.Transaction.from(transactionBuffer);
|
|
4680
|
-
console.log("Requesting wallet signature...");
|
|
4681
|
-
const signedTransaction = await signTransaction(transaction);
|
|
4682
|
-
const signedTransactionBase64 = signedTransaction.serialize().toString("base64");
|
|
4683
|
-
console.log("Submitting signed transaction...");
|
|
4684
|
-
const submitResult = await solanaService.submitPayment(
|
|
4685
|
-
signedTransactionBase64,
|
|
4686
|
-
priceId,
|
|
4687
|
-
paymentData.intent_id
|
|
4688
|
-
);
|
|
4689
|
-
setPaymentState({
|
|
4690
|
-
loading: false,
|
|
4691
|
-
error: null,
|
|
4692
|
-
success: true,
|
|
4693
|
-
transactionId: submitResult.transaction_id
|
|
4694
|
-
});
|
|
4695
|
-
console.log("Payment successful!", submitResult);
|
|
4696
|
-
} catch (err) {
|
|
4697
|
-
console.error("Payment failed:", err);
|
|
4698
|
-
let errorMessage = "Payment failed. Please try again.";
|
|
4699
|
-
const message = err instanceof Error ? err.message : typeof err === "string" ? err : "";
|
|
4700
|
-
if (message.includes("User rejected")) {
|
|
4701
|
-
errorMessage = "Payment cancelled by user.";
|
|
4702
|
-
} else if (/insufficient\s+funds/i.test(message)) {
|
|
4703
|
-
errorMessage = `Insufficient ${token.symbol} balance.`;
|
|
4704
|
-
} else if (/network/i.test(message)) {
|
|
4705
|
-
errorMessage = "Network error. Please check your connection.";
|
|
4706
|
-
} else if (message) {
|
|
4707
|
-
errorMessage = message;
|
|
4708
|
-
}
|
|
4709
|
-
setPaymentState({
|
|
4710
|
-
loading: false,
|
|
4711
|
-
error: errorMessage,
|
|
4712
|
-
success: false,
|
|
4713
|
-
transactionId: null
|
|
4714
|
-
});
|
|
4715
|
-
}
|
|
4716
|
-
},
|
|
4717
|
-
[connected, publicKey, signTransaction, solanaService]
|
|
4718
|
-
);
|
|
4719
|
-
return {
|
|
4720
|
-
paymentState,
|
|
4721
|
-
payWithWallet,
|
|
4722
|
-
resetPayment
|
|
4723
|
-
};
|
|
4724
|
-
};
|
|
4725
3437
|
var usePaymentStatus = (options = {}) => {
|
|
4726
3438
|
const { connection } = walletAdapterReact.useConnection();
|
|
4727
|
-
const {
|
|
4728
|
-
const billingApi = services.billingApi;
|
|
3439
|
+
const { client } = usePaymentContext();
|
|
4729
3440
|
const {
|
|
4730
3441
|
transactionId,
|
|
4731
3442
|
purchaseId,
|
|
@@ -4736,21 +3447,21 @@ var usePaymentStatus = (options = {}) => {
|
|
|
4736
3447
|
retryInterval = 1e4
|
|
4737
3448
|
// 10 seconds
|
|
4738
3449
|
} = options;
|
|
4739
|
-
const [status, setStatus] =
|
|
4740
|
-
const [paymentStatus, setPaymentStatus] =
|
|
4741
|
-
const [isLoading, setIsLoading] =
|
|
4742
|
-
const [error, setError] =
|
|
4743
|
-
const [retryCount, setRetryCount] =
|
|
4744
|
-
const intervalRef =
|
|
4745
|
-
const isMonitoringRef =
|
|
4746
|
-
|
|
3450
|
+
const [status, setStatus] = React17.useState(null);
|
|
3451
|
+
const [paymentStatus, setPaymentStatus] = React17.useState(null);
|
|
3452
|
+
const [isLoading, setIsLoading] = React17.useState(false);
|
|
3453
|
+
const [error, setError] = React17.useState(null);
|
|
3454
|
+
const [retryCount, setRetryCount] = React17.useState(0);
|
|
3455
|
+
const intervalRef = React17.useRef(null);
|
|
3456
|
+
const isMonitoringRef = React17.useRef(false);
|
|
3457
|
+
React17.useEffect(() => {
|
|
4747
3458
|
return () => {
|
|
4748
3459
|
if (intervalRef.current) {
|
|
4749
3460
|
clearInterval(intervalRef.current);
|
|
4750
3461
|
}
|
|
4751
3462
|
};
|
|
4752
3463
|
}, []);
|
|
4753
|
-
const checkTransactionStatus =
|
|
3464
|
+
const checkTransactionStatus = React17.useCallback(
|
|
4754
3465
|
async (signature) => {
|
|
4755
3466
|
try {
|
|
4756
3467
|
const statusResponse = await connection.getSignatureStatus(signature, {
|
|
@@ -4795,17 +3506,11 @@ var usePaymentStatus = (options = {}) => {
|
|
|
4795
3506
|
},
|
|
4796
3507
|
[connection]
|
|
4797
3508
|
);
|
|
4798
|
-
const checkPaymentStatus =
|
|
3509
|
+
const checkPaymentStatus = React17.useCallback(
|
|
4799
3510
|
async (id) => {
|
|
4800
3511
|
try {
|
|
4801
|
-
|
|
4802
|
-
`/payment/status/${id}`
|
|
4803
|
-
);
|
|
4804
|
-
return data;
|
|
3512
|
+
return await client.getPaymentStatus(id);
|
|
4805
3513
|
} catch (error2) {
|
|
4806
|
-
if (error2?.status === 404) {
|
|
4807
|
-
return null;
|
|
4808
|
-
}
|
|
4809
3514
|
console.error("Failed to check payment status:", {
|
|
4810
3515
|
purchaseId: id,
|
|
4811
3516
|
error: error2
|
|
@@ -4813,9 +3518,9 @@ var usePaymentStatus = (options = {}) => {
|
|
|
4813
3518
|
return null;
|
|
4814
3519
|
}
|
|
4815
3520
|
},
|
|
4816
|
-
[
|
|
3521
|
+
[client]
|
|
4817
3522
|
);
|
|
4818
|
-
const startMonitoring =
|
|
3523
|
+
const startMonitoring = React17.useCallback(async () => {
|
|
4819
3524
|
if (isMonitoringRef.current || !transactionId && !purchaseId) {
|
|
4820
3525
|
return;
|
|
4821
3526
|
}
|
|
@@ -4903,14 +3608,14 @@ var usePaymentStatus = (options = {}) => {
|
|
|
4903
3608
|
retryInterval,
|
|
4904
3609
|
retryCount
|
|
4905
3610
|
]);
|
|
4906
|
-
const stopMonitoring =
|
|
3611
|
+
const stopMonitoring = React17.useCallback(() => {
|
|
4907
3612
|
if (intervalRef.current) {
|
|
4908
3613
|
clearInterval(intervalRef.current);
|
|
4909
3614
|
}
|
|
4910
3615
|
isMonitoringRef.current = false;
|
|
4911
3616
|
setIsLoading(false);
|
|
4912
3617
|
}, []);
|
|
4913
|
-
const checkStatus =
|
|
3618
|
+
const checkStatus = React17.useCallback(async () => {
|
|
4914
3619
|
if (!transactionId && !purchaseId) return;
|
|
4915
3620
|
setIsLoading(true);
|
|
4916
3621
|
setError(null);
|
|
@@ -4935,7 +3640,7 @@ var usePaymentStatus = (options = {}) => {
|
|
|
4935
3640
|
setIsLoading(false);
|
|
4936
3641
|
}
|
|
4937
3642
|
}, [transactionId, purchaseId, checkTransactionStatus, checkPaymentStatus]);
|
|
4938
|
-
|
|
3643
|
+
React17.useEffect(() => {
|
|
4939
3644
|
if ((transactionId || purchaseId) && !isMonitoringRef.current) {
|
|
4940
3645
|
startMonitoring();
|
|
4941
3646
|
}
|
|
@@ -4943,7 +3648,7 @@ var usePaymentStatus = (options = {}) => {
|
|
|
4943
3648
|
stopMonitoring();
|
|
4944
3649
|
};
|
|
4945
3650
|
}, [transactionId, purchaseId, startMonitoring, stopMonitoring]);
|
|
4946
|
-
const getConfirmationStatus =
|
|
3651
|
+
const getConfirmationStatus = React17.useCallback(() => {
|
|
4947
3652
|
if (paymentStatus?.status === "confirmed") return "confirmed";
|
|
4948
3653
|
if (paymentStatus?.status === "failed") return "failed";
|
|
4949
3654
|
if (status?.confirmationStatus === "finalized") return "confirmed";
|
|
@@ -4952,7 +3657,7 @@ var usePaymentStatus = (options = {}) => {
|
|
|
4952
3657
|
return "failed";
|
|
4953
3658
|
return "pending";
|
|
4954
3659
|
}, [status, paymentStatus]);
|
|
4955
|
-
const getSolscanUrl =
|
|
3660
|
+
const getSolscanUrl = React17.useCallback(
|
|
4956
3661
|
(signature) => {
|
|
4957
3662
|
const txId = signature || transactionId;
|
|
4958
3663
|
if (!txId) return null;
|
|
@@ -4982,47 +3687,30 @@ var usePaymentStatus = (options = {}) => {
|
|
|
4982
3687
|
exports.BillingHistory = BillingHistory;
|
|
4983
3688
|
exports.CancelMembershipDialog = CancelMembershipDialog;
|
|
4984
3689
|
exports.CardDetailsForm = CardDetailsForm;
|
|
4985
|
-
exports.
|
|
4986
|
-
exports.
|
|
4987
|
-
exports.PaymentApp = PaymentApp;
|
|
3690
|
+
exports.ClientApiError = ClientApiError;
|
|
3691
|
+
exports.PaymentContext = PaymentContext;
|
|
4988
3692
|
exports.PaymentExperience = PaymentExperience;
|
|
4989
|
-
exports.PaymentMethodService = PaymentMethodService;
|
|
4990
3693
|
exports.PaymentMethodsSection = PaymentMethodsSection;
|
|
4991
3694
|
exports.PaymentProvider = PaymentProvider;
|
|
4992
3695
|
exports.PaymentsDialogProvider = PaymentsDialogProvider;
|
|
4993
|
-
exports.
|
|
3696
|
+
exports.PaymentsUIPortalRoot = PaymentsUIPortalRoot;
|
|
3697
|
+
exports.PaymentsUIRoot = PaymentsUIRoot;
|
|
4994
3698
|
exports.SolanaPaymentSelector = SolanaPaymentSelector;
|
|
4995
|
-
exports.SolanaPaymentService = SolanaPaymentService;
|
|
4996
3699
|
exports.SolanaPaymentView = SolanaPaymentView;
|
|
4997
|
-
exports.SolanaWalletSection = SolanaWalletSection;
|
|
4998
|
-
exports.SolanaWalletService = SolanaWalletService;
|
|
4999
3700
|
exports.StoredPaymentMethods = StoredPaymentMethods;
|
|
5000
3701
|
exports.SubscriptionCheckoutModal = SubscriptionCheckoutModal;
|
|
5001
|
-
exports.SubscriptionService = SubscriptionService;
|
|
5002
3702
|
exports.SubscriptionSuccessDialog = SubscriptionSuccessDialog;
|
|
5003
|
-
exports.TokenCatalog = TokenCatalog;
|
|
5004
|
-
exports.WalletCard = WalletCard;
|
|
5005
3703
|
exports.WalletDialog = WalletDialog;
|
|
5006
|
-
exports.WalletGateway = WalletGateway;
|
|
5007
|
-
exports.WalletManagement = WalletManagement;
|
|
5008
3704
|
exports.WalletModal = WalletModal;
|
|
5009
|
-
exports.
|
|
5010
|
-
exports.useAlternativePaymentProvider = useAlternativePaymentProvider;
|
|
5011
|
-
exports.useDirectWalletPayment = useDirectWalletPayment;
|
|
3705
|
+
exports.createClient = createClient;
|
|
5012
3706
|
exports.usePaymentContext = usePaymentContext;
|
|
5013
3707
|
exports.usePaymentDialogs = usePaymentDialogs;
|
|
5014
|
-
exports.usePaymentMethodService = usePaymentMethodService;
|
|
5015
3708
|
exports.usePaymentMethods = usePaymentMethods;
|
|
5016
3709
|
exports.usePaymentNotifications = usePaymentNotifications;
|
|
5017
3710
|
exports.usePaymentStatus = usePaymentStatus;
|
|
5018
|
-
exports.useSolanaDirectPayment = useSolanaDirectPayment;
|
|
5019
3711
|
exports.useSolanaQrPayment = useSolanaQrPayment;
|
|
5020
|
-
exports.useSolanaService = useSolanaService;
|
|
5021
3712
|
exports.useSubscriptionActions = useSubscriptionActions;
|
|
5022
3713
|
exports.useSupportedTokens = useSupportedTokens;
|
|
5023
3714
|
exports.useTokenBalance = useTokenBalance;
|
|
5024
|
-
exports.useWalletConnection = useWalletConnection;
|
|
5025
|
-
exports.useWalletList = useWalletList;
|
|
5026
|
-
exports.useWalletVerification = useWalletVerification;
|
|
5027
3715
|
//# sourceMappingURL=index.cjs.map
|
|
5028
3716
|
//# sourceMappingURL=index.cjs.map
|