@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.js CHANGED
@@ -1,31 +1,31 @@
1
- import * as React3 from 'react';
2
- import { createContext, useMemo, useState, useEffect, useCallback, useRef, useContext } from 'react';
3
- import { QueryClient, useQueryClient, useQuery, useMutation, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query';
4
- import { useWallet, ConnectionProvider, WalletProvider, useConnection } from '@solana/wallet-adapter-react';
5
- import { WalletModalProvider, WalletMultiButton } from '@solana/wallet-adapter-react-ui';
1
+ import * as React17 from 'react';
2
+ import React17__default, { createContext, useMemo, useState, useEffect, useCallback, useRef, useContext } from 'react';
3
+ import { useQueryClient, useQuery, useMutation, QueryClient, QueryClientProvider, useInfiniteQuery } from '@tanstack/react-query';
4
+ import { ConnectionProvider, WalletProvider, useWallet, useConnection } from '@solana/wallet-adapter-react';
5
+ import { WalletModalProvider } from '@solana/wallet-adapter-react-ui';
6
6
  import '@solana/wallet-adapter-react-ui/styles.css';
7
- import { Connection, VersionedTransaction, Transaction, clusterApiUrl, PublicKey, LAMPORTS_PER_SOL } from '@solana/web3.js';
7
+ import { WalletAdapterNetwork } from '@solana/wallet-adapter-base';
8
+ import { clusterApiUrl, PublicKey } from '@solana/web3.js';
8
9
  import { PhantomWalletAdapter } from '@solana/wallet-adapter-phantom';
9
10
  import { SolflareWalletAdapter } from '@solana/wallet-adapter-solflare';
10
11
  import { TrustWalletAdapter } from '@solana/wallet-adapter-trust';
11
12
  import { CoinbaseWalletAdapter } from '@solana/wallet-adapter-coinbase';
12
13
  import * as DialogPrimitive from '@radix-ui/react-dialog';
13
- import { X, ChevronDown, ChevronUp, Check, User, MapPin, Loader2, CreditCard, WalletCards, Trash2, ArrowLeft, CheckCircle, AlertCircle, Wallet, Ban, TriangleAlert, Star, Copy, ExternalLink, Shield, UserRound, Calendar, KeyRound, Sparkles, XCircle, RotateCcw, RefreshCw } from 'lucide-react';
14
+ import { X, ChevronDown, ChevronUp, Check, User, MapPin, Loader2, CreditCard, WalletCards, Trash2, ArrowLeft, CheckCircle, AlertCircle, Wallet, Ban, TriangleAlert, Shield, UserRound, Calendar, KeyRound, Sparkles, XCircle, RotateCcw, RefreshCw } from 'lucide-react';
14
15
  import { clsx } from 'clsx';
15
16
  import { twMerge } from 'tailwind-merge';
16
17
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
17
18
  import countryList from 'country-list';
19
+ import { Slot } from '@radix-ui/react-slot';
18
20
  import { cva } from 'class-variance-authority';
19
21
  import * as LabelPrimitive from '@radix-ui/react-label';
20
22
  import * as SelectPrimitive from '@radix-ui/react-select';
21
23
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
22
24
  import * as TabsPrimitive from '@radix-ui/react-tabs';
23
- import { Buffer } from 'buffer';
24
- import { getAssociatedTokenAddress, getAccount, TOKEN_PROGRAM_ID } from '@solana/spl-token';
25
25
  import QRCode from 'qrcode';
26
26
  import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
27
- import bs58 from 'bs58';
28
27
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
28
+ import { getAssociatedTokenAddress, getAccount } from '@solana/spl-token';
29
29
 
30
30
  // src/context/PaymentContext.tsx
31
31
 
@@ -57,531 +57,297 @@ var loadCollectJs = (tokenizationKey) => {
57
57
  document.head.appendChild(script);
58
58
  };
59
59
 
60
- // src/services/apiClient.ts
61
- var buildUrl = (baseUrl, path, { params, query }) => {
62
- let resolved = `${baseUrl}${path}`;
63
- if (params) {
64
- Object.entries(params).forEach(([key, value]) => {
65
- resolved = resolved.replace(`:${key}`, encodeURIComponent(String(value)));
66
- });
60
+ // src/lib/client.ts
61
+ var ClientApiError = class extends Error {
62
+ constructor(message, status, body, request) {
63
+ super(message);
64
+ this.name = "ClientApiError";
65
+ this.status = status;
66
+ this.body = body;
67
+ this.request = request;
67
68
  }
68
- if (query) {
69
- const queryString = new URLSearchParams();
70
- Object.entries(query).forEach(([key, value]) => {
71
- if (value === void 0 || value === null) return;
72
- queryString.append(key, String(value));
73
- });
74
- if ([...queryString.keys()].length > 0) {
75
- resolved = `${resolved}?${queryString.toString()}`;
76
- }
69
+ };
70
+ var ensureFetch = (fetchImpl) => {
71
+ if (fetchImpl) return fetchImpl;
72
+ if (typeof globalThis.fetch === "function") {
73
+ return globalThis.fetch.bind(globalThis);
77
74
  }
78
- return resolved;
75
+ throw new Error("payments-ui: global fetch is not available");
79
76
  };
80
- var createApiClient = (paymentConfig, baseUrl, fetcher, resolveAuthToken) => {
77
+ var createClient = (config) => {
78
+ const fetchImpl = ensureFetch(config.fetch);
79
+ const normalizeBase = (value) => value.replace(/\/$/, "");
80
+ const normalizePath = (value, fallback = "/v1") => {
81
+ if (!value) return fallback;
82
+ return value.startsWith("/") ? value : `/${value}`;
83
+ };
84
+ const billingBaseUrl = normalizeBase(config.billingBaseUrl);
85
+ const accountBaseUrl = normalizeBase(
86
+ config.accountBaseUrl ?? config.billingBaseUrl
87
+ );
88
+ const billingBasePath = normalizePath(config.billingBasePath ?? "/v1");
89
+ const accountBasePath = normalizePath(
90
+ config.accountBasePath ?? config.billingBasePath ?? "/v1"
91
+ );
92
+ const defaultHeaders = config.defaultHeaders ?? {};
93
+ const resolveAuthToken = async () => {
94
+ if (!config.getAuthToken) return null;
95
+ try {
96
+ const result = config.getAuthToken();
97
+ return result instanceof Promise ? await result : result;
98
+ } catch (error) {
99
+ console.warn("payments-ui: failed to resolve auth token", error);
100
+ return null;
101
+ }
102
+ };
103
+ const buildUrl = (path, query, target) => {
104
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
105
+ const basePath = target === "account" ? accountBasePath : billingBasePath;
106
+ const baseUrl = target === "account" ? accountBaseUrl : billingBaseUrl;
107
+ const needsBasePrefix = !normalizedPath.startsWith(basePath);
108
+ const finalPath = needsBasePrefix ? `${basePath}${normalizedPath}` : normalizedPath;
109
+ const url = new URL(`${baseUrl}${finalPath}`);
110
+ if (query) {
111
+ Object.entries(query).forEach(([key, value]) => {
112
+ if (value === void 0 || value === null) return;
113
+ url.searchParams.append(key, String(value));
114
+ });
115
+ }
116
+ return url.toString();
117
+ };
81
118
  const request = async (method, path, options) => {
82
- const url = buildUrl(baseUrl, path, options ?? {});
119
+ const target = options?.target ?? "billing";
120
+ const url = buildUrl(path, options?.query, target);
83
121
  const headers = {
84
122
  "Content-Type": "application/json",
85
- ...paymentConfig.defaultHeaders ?? {},
123
+ ...defaultHeaders,
86
124
  ...options?.headers ?? {}
87
125
  };
88
126
  const token = await resolveAuthToken();
89
127
  if (token) {
90
128
  headers.Authorization = `Bearer ${token}`;
91
129
  }
92
- try {
93
- const response = await fetcher(url, {
94
- method,
95
- headers,
96
- body: options?.body ? JSON.stringify(options.body) : void 0
97
- });
98
- if (!response.ok) {
99
- const message = await response.text();
100
- console.error("payments-ui: API request failed", {
101
- url,
102
- method,
103
- status: response.status,
104
- message
105
- });
106
- throw new Error(message || `Request failed with status ${response.status}`);
107
- }
108
- if (response.status === 204) {
109
- return void 0;
110
- }
111
- const data = await response.json();
112
- return data;
113
- } catch (error) {
114
- console.error("payments-ui: API request error", { url, method, error });
115
- throw error;
116
- }
117
- };
118
- return {
119
- request,
120
- get: (path, options) => request("GET", path, options),
121
- post: (path, options) => request("POST", path, options),
122
- put: (path, options) => request("PUT", path, options),
123
- patch: (path, options) => request("PATCH", path, options),
124
- delete: (path, options) => request("DELETE", path, options)
125
- };
126
- };
127
-
128
- // src/services/CardPaymentService.ts
129
- var CardPaymentService = class {
130
- constructor(config) {
131
- this.config = config;
132
- this.collectLoaded = false;
133
- }
134
- async ensureCollectLoaded() {
135
- if (this.collectLoaded) return;
136
- if (!this.config.collectJsKey) {
137
- throw new Error("payments-ui: collect.js key missing");
138
- }
139
- loadCollectJs(this.config.collectJsKey);
140
- this.collectLoaded = true;
141
- }
142
- buildCreatePayload(result) {
143
- return {
144
- payment_token: result.token,
145
- first_name: result.billing.firstName,
146
- last_name: result.billing.lastName,
147
- address1: result.billing.address1,
148
- address2: result.billing.address2,
149
- city: result.billing.city,
150
- state: result.billing.stateRegion,
151
- zip: result.billing.postalCode,
152
- country: result.billing.country,
153
- email: result.billing.email,
154
- provider: result.billing.provider
155
- };
156
- }
157
- };
158
-
159
- // src/services/PaymentMethodService.ts
160
- var PaymentMethodService = class {
161
- constructor(api) {
162
- this.api = api;
163
- }
164
- async list(params) {
165
- return this.api.get("/payment-methods", {
166
- query: {
167
- page: params?.page ?? 1,
168
- page_size: params?.pageSize ?? 50
169
- }
170
- });
171
- }
172
- async create(payload) {
173
- return this.api.post("/payment-methods", {
174
- body: { ...payload }
175
- });
176
- }
177
- async remove(id) {
178
- await this.api.delete(`/payment-methods/${id}`);
179
- }
180
- async activate(id) {
181
- await this.api.put(`/payment-methods/${id}/activate`);
182
- }
183
- };
184
-
185
- // src/services/SolanaPaymentService.ts
186
- var SolanaPaymentService = class {
187
- constructor(api) {
188
- this.api = api;
189
- }
190
- async generatePayment(priceId, token, userWallet) {
191
- return this.api.post("/solana/generate", {
192
- body: { price_id: priceId, token, user_wallet: userWallet }
193
- });
194
- }
195
- async submitPayment(signedTransaction, priceId, intentId, memo) {
196
- return this.api.post("/solana/submit", {
197
- body: {
198
- signed_transaction: signedTransaction,
199
- price_id: priceId,
200
- intent_id: intentId,
201
- ...memo ? { memo } : {}
202
- }
203
- });
204
- }
205
- async fetchSupportedTokens() {
206
- const response = await this.api.get(
207
- "/solana/tokens"
208
- );
209
- return response.tokens;
210
- }
211
- async getSupportedTokens() {
212
- return this.fetchSupportedTokens();
213
- }
214
- async generateQrCode(priceId, token, userWallet) {
215
- return this.api.post("/solana/qr", {
216
- body: {
217
- price_id: priceId,
218
- token,
219
- ...userWallet ? { user_wallet: userWallet } : {}
220
- }
130
+ const response = await fetchImpl(url, {
131
+ method,
132
+ headers,
133
+ body: options?.body ? JSON.stringify(options.body) : void 0
221
134
  });
222
- }
223
- async generateQRCode(priceId, token, userWallet) {
224
- return this.generateQrCode(priceId, token, userWallet);
225
- }
226
- async checkPaymentStatus(reference, memo) {
227
- return this.api.get("/solana/check", {
228
- query: {
229
- reference,
230
- ...memo ? { memo } : {}
231
- }
232
- });
233
- }
234
- };
235
-
236
- // src/services/TokenCatalog.ts
237
- var TokenCatalog = class {
238
- constructor(solanaService, options = {}) {
239
- this.solanaService = solanaService;
240
- this.options = options;
241
- this.cache = [];
242
- this.lastFetched = 0;
243
- }
244
- get ttl() {
245
- return this.options.ttlMs ?? 5 * 60 * 1e3;
246
- }
247
- async getTokens(force = false) {
248
- const isStale = Date.now() - this.lastFetched > this.ttl;
249
- if (!force && this.cache.length > 0 && !isStale) {
250
- return this.cache;
251
- }
252
- const tokens = await this.solanaService.fetchSupportedTokens();
253
- this.cache = tokens;
254
- this.lastFetched = Date.now();
255
- return tokens;
256
- }
257
- getCached() {
258
- return this.cache;
259
- }
260
- };
261
-
262
- // src/services/WalletGateway.ts
263
- var WalletGateway = class {
264
- constructor() {
265
- this.adapter = null;
266
- }
267
- setAdapter(adapter) {
268
- this.adapter = adapter;
269
- }
270
- getPublicKey() {
271
- if (!this.adapter?.publicKey) return null;
272
- try {
273
- return this.adapter.publicKey.toBase58();
274
- } catch {
275
- return null;
276
- }
277
- }
278
- async sign(transaction) {
279
- if (!this.adapter) {
280
- throw new Error("payments-ui: wallet adapter not set");
281
- }
282
- if (typeof this.adapter.signVersionedTransaction === "function") {
283
- return this.adapter.signVersionedTransaction(transaction);
135
+ if (!response.ok) {
136
+ let payload = null;
137
+ try {
138
+ payload = await response.json();
139
+ } catch {
140
+ payload = await response.text();
141
+ }
142
+ throw new ClientApiError(
143
+ payload && typeof payload === "object" && "message" in payload ? String(payload.message) : response.statusText || "Request failed",
144
+ response.status,
145
+ payload,
146
+ { method, url }
147
+ );
284
148
  }
285
- if (typeof this.adapter.signTransaction === "function") {
286
- return this.adapter.signTransaction(transaction);
149
+ if (response.status === 204) {
150
+ return void 0;
287
151
  }
288
- throw new Error("payments-ui: wallet adapter cannot sign transactions");
289
- }
290
- };
291
-
292
- // src/services/SubscriptionService.ts
293
- var SubscriptionService = class {
294
- constructor(api) {
295
- this.api = api;
296
- }
297
- async subscribe(platform, payload) {
298
- const body = this.serializePayload(platform, payload);
299
- return this.api.post(
300
- `/subscriptions/process/${platform}`,
301
- {
302
- body
152
+ return await response.json();
153
+ };
154
+ const normalizeList = (payload) => {
155
+ const data = payload.data ?? [];
156
+ const total = payload.total ?? payload.total_items ?? data.length;
157
+ const limit = payload.limit ?? data.length;
158
+ const offset = payload.offset ?? 0;
159
+ const hasMore = typeof payload.has_more === "boolean" ? payload.has_more : offset + data.length < total;
160
+ return { data, total, limit, offset, hasMore };
161
+ };
162
+ return {
163
+ async listPaymentMethods(params) {
164
+ const result = await request(
165
+ "GET",
166
+ "/me/payment-methods",
167
+ {
168
+ query: {
169
+ limit: params?.limit,
170
+ offset: params?.offset,
171
+ include_inactive: params?.includeInactive
172
+ },
173
+ target: "account"
174
+ }
175
+ );
176
+ return normalizeList(result);
177
+ },
178
+ createPaymentMethod(payload) {
179
+ return request("POST", "/me/payment-methods", {
180
+ body: payload,
181
+ target: "account"
182
+ });
183
+ },
184
+ updatePaymentMethod(id, payload) {
185
+ return request("PUT", `/me/payment-methods/${id}`, {
186
+ body: payload,
187
+ target: "account"
188
+ });
189
+ },
190
+ deletePaymentMethod(id) {
191
+ return request("DELETE", `/me/payment-methods/${id}`, {
192
+ target: "account"
193
+ });
194
+ },
195
+ activatePaymentMethod(id) {
196
+ return request("PUT", `/me/payment-methods/${id}/activate`, {
197
+ target: "account"
198
+ });
199
+ },
200
+ checkout(payload) {
201
+ return request("POST", "/me/checkout", {
202
+ body: payload
203
+ });
204
+ },
205
+ cancelSubscription(feedback) {
206
+ return request("POST", "/me/subscriptions/cancel", {
207
+ body: feedback ? { feedback } : void 0
208
+ });
209
+ },
210
+ async getPaymentHistory(params) {
211
+ const result = await request("GET", "/me/payments", {
212
+ query: {
213
+ limit: params?.limit,
214
+ offset: params?.offset,
215
+ type: params?.type
216
+ }
217
+ });
218
+ return normalizeList(result);
219
+ },
220
+ async getSolanaTokens() {
221
+ const response = await request(
222
+ "GET",
223
+ "/solana/tokens"
224
+ );
225
+ if (Array.isArray(response)) {
226
+ return response;
303
227
  }
304
- );
305
- }
306
- async generateFlexFormUrl(payload) {
307
- return this.api.post(`/subscriptions/ccbill/flexform-url`, {
308
- body: { ...payload }
309
- });
310
- }
311
- async getPaymentHistory(params) {
312
- const limit = params?.limit ?? 10;
313
- const offset = params?.offset ?? 0;
314
- const query = {
315
- limit: String(limit),
316
- offset: String(offset)
317
- };
318
- if (params?.type) {
319
- query.type = params.type;
320
- }
321
- const response = await this.api.get("/subscriptions/purchases", {
322
- query
323
- });
324
- const totalItems = response?.total_items ?? 0;
325
- const pageSize = limit;
326
- const pageNumber = response?.page ?? (pageSize > 0 ? Math.floor(offset / pageSize) + 1 : 1);
327
- const totalPages = response?.total_pages ?? (pageSize > 0 ? Math.ceil(totalItems / pageSize) : void 0);
328
- return {
329
- data: response?.data ?? [],
330
- total_items: totalItems,
331
- limit,
332
- offset,
333
- page: pageNumber,
334
- page_size: pageSize,
335
- total_pages: totalPages
336
- };
337
- }
338
- async cancelSubscription(feedback) {
339
- return this.api.post("/subscriptions/cancel", {
340
- body: feedback ? { feedback } : void 0
341
- });
342
- }
343
- serializePayload(platform, payload) {
344
- if (platform === "nmi") {
345
- const data2 = payload;
346
- if (!data2.priceId) {
347
- throw new Error("payments-ui: priceId is required for NMI subscriptions");
228
+ return response.tokens ?? [];
229
+ },
230
+ async createSolanaPayIntent(payload) {
231
+ const response = await request("POST", "/solana/pay", {
232
+ body: {
233
+ price_id: payload.priceId,
234
+ token: payload.token,
235
+ ...payload.userWallet ? { user_wallet: payload.userWallet } : {}
236
+ }
237
+ });
238
+ return response;
239
+ },
240
+ async getSolanaPayStatus(reference) {
241
+ const response = await request(
242
+ "GET",
243
+ `/solana/pay/${reference}`
244
+ );
245
+ if (response.status === "confirmed") {
246
+ return {
247
+ status: "confirmed",
248
+ payment_id: response.payment_id ?? "",
249
+ transaction: response.signature ?? null,
250
+ intent_id: response.intent_id
251
+ };
348
252
  }
349
- if (!data2.paymentToken && !data2.paymentMethodId) {
350
- throw new Error(
351
- "payments-ui: paymentToken or paymentMethodId is required for NMI subscriptions"
352
- );
253
+ if (response.status === "expired") {
254
+ return {
255
+ status: "failed",
256
+ payment_id: response.payment_id ?? "",
257
+ transaction: response.signature ?? null,
258
+ intent_id: response.intent_id,
259
+ error_message: "Payment intent expired"
260
+ };
353
261
  }
354
- const body = {
355
- price_id: data2.priceId,
356
- processor: data2.processor ?? "nmi",
357
- provider: data2.provider
262
+ return {
263
+ status: "pending",
264
+ payment_id: response.payment_id ?? "",
265
+ transaction: response.signature ?? null,
266
+ intent_id: response.intent_id
358
267
  };
359
- if (data2.email) body.email = data2.email;
360
- if (data2.firstName) body.first_name = data2.firstName;
361
- if (data2.lastName) body.last_name = data2.lastName;
362
- if (data2.address1) body.address1 = data2.address1;
363
- if (data2.city) body.city = data2.city;
364
- if (data2.state) body.state = data2.state;
365
- if (data2.zipCode) body.zip = data2.zipCode;
366
- if (data2.country) body.country = data2.country;
367
- if (data2.paymentToken) body.payment_token = data2.paymentToken;
368
- if (data2.paymentMethodId) body.payment_method_id = data2.paymentMethodId;
369
- return body;
370
- }
371
- const data = payload;
372
- if (!data.priceId) {
373
- throw new Error("payments-ui: priceId is required for CCBill subscriptions");
374
- }
375
- return {
376
- price_id: data.priceId,
377
- processor: data.processor ?? "ccbill",
378
- email: data.email,
379
- first_name: data.firstName,
380
- last_name: data.lastName,
381
- zip: data.zipCode,
382
- country: data.country
383
- };
384
- }
385
- };
386
-
387
- // src/services/SolanaWalletService.ts
388
- var SolanaWalletService = class {
389
- constructor(api) {
390
- this.api = api;
391
- }
392
- async list() {
393
- const response = await this.api.get(
394
- "/wallet/solana"
395
- );
396
- if (Array.isArray(response)) {
397
- return response;
398
- }
399
- if ("wallets" in response && Array.isArray(response.wallets)) {
400
- return response.wallets;
401
- }
402
- if ("wallet" in response) {
403
- return response.wallet ? [response.wallet] : [];
404
- }
405
- if ("address" in response) {
406
- return [response];
407
- }
408
- return [];
409
- }
410
- async requestChallenge(wallet) {
411
- return this.api.post("/wallet/solana/challenge", {
412
- body: { wallet }
413
- });
414
- }
415
- async verify(wallet, signature, nonce) {
416
- const body = { wallet, signature };
417
- if (nonce) {
418
- body.nonce = nonce;
419
- }
420
- return this.api.post("/wallet/solana/verify", { body });
421
- }
422
- async remove(wallet) {
423
- await this.api.delete("/wallet/solana", {
424
- query: { wallet }
425
- });
426
- }
427
- };
428
-
429
- // src/core/PaymentApp.ts
430
- var PaymentApp = class {
431
- constructor(options) {
432
- this.resolveAuthToken = async () => {
433
- if (!this.config.getAuthToken) {
434
- return null;
435
- }
268
+ },
269
+ async getPaymentStatus(id) {
436
270
  try {
437
- const result = this.config.getAuthToken();
438
- if (result instanceof Promise) {
439
- return await result ?? null;
440
- }
441
- return result ?? null;
271
+ return await request("GET", `/payment/status/${id}`);
442
272
  } catch (error) {
443
- console.warn("payments-ui: failed to resolve auth token", error);
444
- return null;
273
+ if (error instanceof ClientApiError && error.status === 404) {
274
+ return null;
275
+ }
276
+ throw error;
445
277
  }
446
- };
447
- this.config = options.config;
448
- this.fetcher = options.fetcher ?? options.config.fetcher ?? globalThis.fetch?.bind(globalThis);
449
- if (!this.fetcher) {
450
- throw new Error("payments-ui: fetch implementation is required");
451
- }
452
- this.services = this.createServices();
453
- }
454
- getConfig() {
455
- return this.config;
456
- }
457
- getFetcher() {
458
- return this.fetcher;
459
- }
460
- getServices() {
461
- return this.services;
462
- }
463
- createServices() {
464
- const billingApi = createApiClient(
465
- this.config,
466
- this.config.endpoints.billingBaseUrl,
467
- this.fetcher,
468
- this.resolveAuthToken
469
- );
470
- const accountBaseUrl = this.config.endpoints.accountBaseUrl ?? this.config.endpoints.billingBaseUrl;
471
- const accountApi = createApiClient(
472
- this.config,
473
- accountBaseUrl,
474
- this.fetcher,
475
- this.resolveAuthToken
476
- );
477
- const solanaPayments = new SolanaPaymentService(billingApi);
478
- const solanaWallets = new SolanaWalletService(billingApi);
479
- const paymentMethods = new PaymentMethodService(accountApi);
480
- const cardPayments = new CardPaymentService(this.config);
481
- const walletGateway = new WalletGateway();
482
- const tokenCatalog = new TokenCatalog(solanaPayments);
483
- const subscriptions = new SubscriptionService(billingApi);
484
- return {
485
- cardPayments,
486
- paymentMethods,
487
- solanaPayments,
488
- solanaWallets,
489
- tokenCatalog,
490
- walletGateway,
491
- subscriptions,
492
- billingApi,
493
- accountApi
494
- };
495
- }
496
- };
497
-
498
- // src/runtime/PaymentsRuntime.ts
499
- var createQueryClient = () => new QueryClient({
500
- defaultOptions: {
501
- queries: {
502
- staleTime: 3e4,
503
- gcTime: 5 * 6e4,
504
- refetchOnWindowFocus: false,
505
- retry: 1
506
- },
507
- mutations: {
508
- retry: 1
509
278
  }
510
- }
511
- });
512
- var PaymentsRuntime = class {
513
- constructor(config) {
514
- this.config = config;
515
- this.app = new PaymentApp({ config });
516
- this.services = this.app.getServices();
517
- this.queryClient = createQueryClient();
518
- }
279
+ };
519
280
  };
520
- var createPaymentsRuntime = (config) => new PaymentsRuntime(config);
521
-
522
- // node_modules/@solana/wallet-adapter-base/lib/esm/types.js
523
- var WalletAdapterNetwork;
524
- (function(WalletAdapterNetwork2) {
525
- WalletAdapterNetwork2["Mainnet"] = "mainnet-beta";
526
- WalletAdapterNetwork2["Testnet"] = "testnet";
527
- WalletAdapterNetwork2["Devnet"] = "devnet";
528
- })(WalletAdapterNetwork || (WalletAdapterNetwork = {}));
529
281
  function cn(...inputs) {
530
282
  return twMerge(clsx(inputs));
531
283
  }
532
284
  var Dialog = DialogPrimitive.Root;
533
- var DialogPortal = ({ className, ...props }) => /* @__PURE__ */ jsx(DialogPrimitive.Portal, { className: cn(className), ...props });
534
- DialogPortal.displayName = DialogPrimitive.Portal.displayName;
535
- var DialogOverlay = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
285
+ var DialogPortal = DialogPrimitive.Portal;
286
+ var DialogOverlay = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
536
287
  DialogPrimitive.Overlay,
537
288
  {
538
289
  ref,
539
290
  className: cn(
540
- "fixed inset-0 z-50 bg-black/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in",
291
+ "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",
541
292
  className
542
293
  ),
543
294
  ...props
544
295
  }
545
296
  ));
546
297
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
547
- var DialogContent = React3.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
298
+ var DialogContent = React17.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(DialogPortal, { children: /* @__PURE__ */ jsxs("div", { className: "payments-ui-portal", children: [
548
299
  /* @__PURE__ */ jsx(DialogOverlay, {}),
549
300
  /* @__PURE__ */ jsxs(
550
301
  DialogPrimitive.Content,
551
302
  {
552
303
  ref,
553
304
  className: cn(
554
- "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background 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%]",
305
+ "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",
555
306
  className
556
307
  ),
557
308
  ...props,
558
309
  children: [
559
310
  children,
560
- /* @__PURE__ */ jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none", children: [
561
- /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }),
311
+ /* @__PURE__ */ jsxs(DialogPrimitive.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: [
312
+ /* @__PURE__ */ jsx(X, { className: "h-3 w-3 text-white" }),
562
313
  /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
563
314
  ] })
564
315
  ]
565
316
  }
566
317
  )
567
- ] }));
318
+ ] }) }));
568
319
  DialogContent.displayName = DialogPrimitive.Content.displayName;
569
- var DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
320
+ var DialogHeader = ({
321
+ className,
322
+ ...props
323
+ }) => /* @__PURE__ */ jsx(
324
+ "div",
325
+ {
326
+ className: cn(
327
+ "flex flex-col space-y-1.5 text-center sm:text-left",
328
+ className
329
+ ),
330
+ ...props
331
+ }
332
+ );
570
333
  DialogHeader.displayName = "DialogHeader";
571
- var DialogTitle = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
334
+ var DialogTitle = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
572
335
  DialogPrimitive.Title,
573
336
  {
574
337
  ref,
575
- className: cn("text-lg font-semibold leading-none tracking-tight", className),
338
+ className: cn(
339
+ "text-lg font-semibold leading-none tracking-tight",
340
+ className
341
+ ),
576
342
  ...props
577
343
  }
578
344
  ));
579
345
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
580
- var DialogDescription = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
346
+ var DialogDescription = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
581
347
  DialogPrimitive.Description,
582
348
  {
583
349
  ref,
584
- className: cn("text-sm text-muted-foreground", className),
350
+ className: cn("text-white/60 text-sm", className),
585
351
  ...props
586
352
  }
587
353
  ));
@@ -601,131 +367,17 @@ var customCountries = [
601
367
  ];
602
368
  countryList.overwrite(customCountries);
603
369
  var countries = countryList.getData().sort((a, b) => a.name.localeCompare(b.name));
604
- function setRef(ref, value) {
605
- if (typeof ref === "function") {
606
- return ref(value);
607
- } else if (ref !== null && ref !== void 0) {
608
- ref.current = value;
609
- }
610
- }
611
- function composeRefs(...refs) {
612
- return (node) => {
613
- let hasCleanup = false;
614
- const cleanups = refs.map((ref) => {
615
- const cleanup = setRef(ref, node);
616
- if (!hasCleanup && typeof cleanup == "function") {
617
- hasCleanup = true;
618
- }
619
- return cleanup;
620
- });
621
- if (hasCleanup) {
622
- return () => {
623
- for (let i = 0; i < cleanups.length; i++) {
624
- const cleanup = cleanups[i];
625
- if (typeof cleanup == "function") {
626
- cleanup();
627
- } else {
628
- setRef(refs[i], null);
629
- }
630
- }
631
- };
632
- }
633
- };
634
- }
635
- // @__NO_SIDE_EFFECTS__
636
- function createSlot(ownerName) {
637
- const SlotClone = /* @__PURE__ */ createSlotClone(ownerName);
638
- const Slot2 = React3.forwardRef((props, forwardedRef) => {
639
- const { children, ...slotProps } = props;
640
- const childrenArray = React3.Children.toArray(children);
641
- const slottable = childrenArray.find(isSlottable);
642
- if (slottable) {
643
- const newElement = slottable.props.children;
644
- const newChildren = childrenArray.map((child) => {
645
- if (child === slottable) {
646
- if (React3.Children.count(newElement) > 1) return React3.Children.only(null);
647
- return React3.isValidElement(newElement) ? newElement.props.children : null;
648
- } else {
649
- return child;
650
- }
651
- });
652
- return /* @__PURE__ */ jsx(SlotClone, { ...slotProps, ref: forwardedRef, children: React3.isValidElement(newElement) ? React3.cloneElement(newElement, void 0, newChildren) : null });
653
- }
654
- return /* @__PURE__ */ jsx(SlotClone, { ...slotProps, ref: forwardedRef, children });
655
- });
656
- Slot2.displayName = `${ownerName}.Slot`;
657
- return Slot2;
658
- }
659
- var Slot = /* @__PURE__ */ createSlot("Slot");
660
- // @__NO_SIDE_EFFECTS__
661
- function createSlotClone(ownerName) {
662
- const SlotClone = React3.forwardRef((props, forwardedRef) => {
663
- const { children, ...slotProps } = props;
664
- if (React3.isValidElement(children)) {
665
- const childrenRef = getElementRef(children);
666
- const props2 = mergeProps(slotProps, children.props);
667
- if (children.type !== React3.Fragment) {
668
- props2.ref = forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef;
669
- }
670
- return React3.cloneElement(children, props2);
671
- }
672
- return React3.Children.count(children) > 1 ? React3.Children.only(null) : null;
673
- });
674
- SlotClone.displayName = `${ownerName}.SlotClone`;
675
- return SlotClone;
676
- }
677
- var SLOTTABLE_IDENTIFIER = Symbol("radix.slottable");
678
- function isSlottable(child) {
679
- return React3.isValidElement(child) && typeof child.type === "function" && "__radixId" in child.type && child.type.__radixId === SLOTTABLE_IDENTIFIER;
680
- }
681
- function mergeProps(slotProps, childProps) {
682
- const overrideProps = { ...childProps };
683
- for (const propName in childProps) {
684
- const slotPropValue = slotProps[propName];
685
- const childPropValue = childProps[propName];
686
- const isHandler = /^on[A-Z]/.test(propName);
687
- if (isHandler) {
688
- if (slotPropValue && childPropValue) {
689
- overrideProps[propName] = (...args) => {
690
- const result = childPropValue(...args);
691
- slotPropValue(...args);
692
- return result;
693
- };
694
- } else if (slotPropValue) {
695
- overrideProps[propName] = slotPropValue;
696
- }
697
- } else if (propName === "style") {
698
- overrideProps[propName] = { ...slotPropValue, ...childPropValue };
699
- } else if (propName === "className") {
700
- overrideProps[propName] = [slotPropValue, childPropValue].filter(Boolean).join(" ");
701
- }
702
- }
703
- return { ...slotProps, ...overrideProps };
704
- }
705
- function getElementRef(element) {
706
- let getter = Object.getOwnPropertyDescriptor(element.props, "ref")?.get;
707
- let mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
708
- if (mayWarn) {
709
- return element.ref;
710
- }
711
- getter = Object.getOwnPropertyDescriptor(element, "ref")?.get;
712
- mayWarn = getter && "isReactWarning" in getter && getter.isReactWarning;
713
- if (mayWarn) {
714
- return element.props.ref;
715
- }
716
- return element.props.ref || element.ref;
717
- }
718
370
  var buttonVariants = cva(
719
- "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-ring disabled:pointer-events-none disabled:opacity-50",
371
+ "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",
720
372
  {
721
373
  variants: {
722
374
  variant: {
723
- default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
724
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
725
- outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
726
- ghost: "hover:bg-accent hover:text-accent-foreground",
727
- destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
728
- link: "text-primary underline-offset-4 hover:underline"
375
+ default: "bg-[#28a745] text-white shadow hover:bg-[#16a34a]",
376
+ secondary: "bg-white/10 text-white hover:bg-white/20",
377
+ outline: "border border-white/10 bg-transparent text-white hover:bg-white/10",
378
+ ghost: "text-white/80 hover:bg-white/10 hover:text-white",
379
+ destructive: "bg-red-600 text-white hover:bg-red-700",
380
+ link: "text-blue-400 underline-offset-4 hover:underline"
729
381
  },
730
382
  size: {
731
383
  default: "h-10 px-4 py-2",
@@ -740,7 +392,7 @@ var buttonVariants = cva(
740
392
  }
741
393
  }
742
394
  );
743
- var Button = React3.forwardRef(
395
+ var Button = React17.forwardRef(
744
396
  ({ className, variant, size, asChild = false, ...props }, ref) => {
745
397
  const Comp = asChild ? Slot : "button";
746
398
  return /* @__PURE__ */ jsx(
@@ -754,14 +406,14 @@ var Button = React3.forwardRef(
754
406
  }
755
407
  );
756
408
  Button.displayName = "Button";
757
- var Input = React3.forwardRef(
409
+ var Input = React17.forwardRef(
758
410
  ({ className, type, ...props }, ref) => {
759
411
  return /* @__PURE__ */ jsx(
760
412
  "input",
761
413
  {
762
414
  type,
763
415
  className: cn(
764
- "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
416
+ "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",
765
417
  className
766
418
  ),
767
419
  ref,
@@ -771,12 +423,12 @@ var Input = React3.forwardRef(
771
423
  }
772
424
  );
773
425
  Input.displayName = "Input";
774
- var Label = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
426
+ var Label = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
775
427
  LabelPrimitive.Root,
776
428
  {
777
429
  ref,
778
430
  className: cn(
779
- "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
431
+ "text-sm font-medium leading-none text-white peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
780
432
  className
781
433
  ),
782
434
  ...props
@@ -785,12 +437,12 @@ var Label = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
785
437
  Label.displayName = LabelPrimitive.Root.displayName;
786
438
  var Select = SelectPrimitive.Root;
787
439
  var SelectValue = SelectPrimitive.Value;
788
- var SelectTrigger = React3.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
440
+ var SelectTrigger = React17.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
789
441
  SelectPrimitive.Trigger,
790
442
  {
791
443
  ref,
792
444
  className: cn(
793
- "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
445
+ "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",
794
446
  className
795
447
  ),
796
448
  ...props,
@@ -801,39 +453,39 @@ var SelectTrigger = React3.forwardRef(({ className, children, ...props }, ref) =
801
453
  }
802
454
  ));
803
455
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
804
- var SelectContent = React3.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
456
+ var SelectContent = React17.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsx("div", { className: "payments-ui-portal", children: /* @__PURE__ */ jsxs(
805
457
  SelectPrimitive.Content,
806
458
  {
807
459
  ref,
808
460
  className: cn(
809
- "relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground 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",
461
+ "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",
810
462
  className
811
463
  ),
812
464
  position,
813
465
  ...props,
814
466
  children: [
815
- /* @__PURE__ */ jsx(SelectPrimitive.ScrollUpButton, { className: "flex cursor-default items-center justify-center py-1", children: /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4" }) }),
467
+ /* @__PURE__ */ jsx(SelectPrimitive.ScrollUpButton, { className: "flex cursor-default items-center justify-center py-1 text-white/60", children: /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4" }) }),
816
468
  /* @__PURE__ */ jsx(SelectPrimitive.Viewport, { className: "p-1", children }),
817
- /* @__PURE__ */ jsx(SelectPrimitive.ScrollDownButton, { className: "flex cursor-default items-center justify-center py-1", children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" }) })
469
+ /* @__PURE__ */ jsx(SelectPrimitive.ScrollDownButton, { className: "flex cursor-default items-center justify-center py-1 text-white/60", children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" }) })
818
470
  ]
819
471
  }
820
- ) }));
472
+ ) }) }));
821
473
  SelectContent.displayName = SelectPrimitive.Content.displayName;
822
- var SelectLabel = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
474
+ var SelectLabel = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
823
475
  SelectPrimitive.Label,
824
476
  {
825
477
  ref,
826
- className: cn("px-2 py-1.5 text-sm font-semibold text-muted-foreground", className),
478
+ className: cn("px-2 py-1.5 text-sm font-semibold text-white/60", className),
827
479
  ...props
828
480
  }
829
481
  ));
830
482
  SelectLabel.displayName = SelectPrimitive.Label.displayName;
831
- var SelectItem = React3.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
483
+ var SelectItem = React17.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
832
484
  SelectPrimitive.Item,
833
485
  {
834
486
  ref,
835
487
  className: cn(
836
- "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-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
488
+ "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",
837
489
  className
838
490
  ),
839
491
  ...props,
@@ -844,16 +496,18 @@ var SelectItem = React3.forwardRef(({ className, children, ...props }, ref) => /
844
496
  }
845
497
  ));
846
498
  SelectItem.displayName = SelectPrimitive.Item.displayName;
847
- var SelectSeparator = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
499
+ var SelectSeparator = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
848
500
  SelectPrimitive.Separator,
849
501
  {
850
502
  ref,
851
- className: cn("mx-1 my-1 h-px bg-muted", className),
503
+ className: cn("mx-1 my-1 h-px bg-white/10", className),
852
504
  ...props
853
505
  }
854
506
  ));
855
507
  SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
856
- var defaultBilling = {
508
+
509
+ // src/constants/billing.ts
510
+ var defaultBillingDetails = {
857
511
  firstName: "",
858
512
  lastName: "",
859
513
  address1: "",
@@ -881,9 +535,9 @@ var CardDetailsForm = ({
881
535
  const defaultValuesKey = useMemo(() => JSON.stringify(defaultValues ?? {}), [defaultValues]);
882
536
  const mergedDefaults = useMemo(
883
537
  () => ({
884
- ...defaultBilling,
538
+ ...defaultBillingDetails,
885
539
  ...defaultValues,
886
- email: defaultValues?.email ?? config.defaultUser?.email ?? defaultBilling.email
540
+ email: defaultValues?.email ?? config.defaultUser?.email ?? defaultBillingDetails.email
887
541
  }),
888
542
  [defaultValuesKey, config.defaultUser?.email]
889
543
  );
@@ -1012,7 +666,7 @@ var CardDetailsForm = ({
1012
666
  window.CollectJS.startPaymentRequest();
1013
667
  };
1014
668
  const errorMessage = localError ?? externalError;
1015
- const collectFieldClass = "flex h-11 w-full items-center rounded-md border border-border/60 bg-background px-3 text-sm text-muted-foreground";
669
+ const collectFieldClass = "flex h-11 w-full items-center rounded-md border border-white/10 bg-white/5 px-3 text-sm text-white";
1016
670
  return /* @__PURE__ */ jsxs(
1017
671
  "form",
1018
672
  {
@@ -1020,10 +674,10 @@ var CardDetailsForm = ({
1020
674
  onSubmit: handleSubmit,
1021
675
  noValidate: true,
1022
676
  children: [
1023
- errorMessage && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 px-4 py-2 text-sm text-destructive", children: errorMessage }),
677
+ errorMessage && /* @__PURE__ */ 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 }),
1024
678
  /* @__PURE__ */ jsxs("div", { className: "grid gap-5 md:grid-cols-2", children: [
1025
679
  /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1026
- /* @__PURE__ */ jsxs(Label, { htmlFor: "payments-first", className: "flex items-center gap-2 text-muted-foreground", children: [
680
+ /* @__PURE__ */ jsxs(Label, { htmlFor: "payments-first", className: "flex items-center gap-2 text-white/70", children: [
1027
681
  /* @__PURE__ */ jsx(User, { className: "h-4 w-4" }),
1028
682
  " First name"
1029
683
  ] }),
@@ -1038,7 +692,7 @@ var CardDetailsForm = ({
1038
692
  )
1039
693
  ] }),
1040
694
  /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1041
- /* @__PURE__ */ jsxs(Label, { htmlFor: "payments-last", className: "flex items-center gap-2 text-muted-foreground", children: [
695
+ /* @__PURE__ */ jsxs(Label, { htmlFor: "payments-last", className: "flex items-center gap-2 text-white/70", children: [
1042
696
  /* @__PURE__ */ jsx(User, { className: "h-4 w-4" }),
1043
697
  " Last name"
1044
698
  ] }),
@@ -1105,7 +759,7 @@ var CardDetailsForm = ({
1105
759
  ] }),
1106
760
  /* @__PURE__ */ jsxs("div", { className: "grid gap-5 md:grid-cols-2", children: [
1107
761
  /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1108
- /* @__PURE__ */ jsxs(Label, { htmlFor: "payments-postal", className: "flex items-center gap-2 text-muted-foreground", children: [
762
+ /* @__PURE__ */ jsxs(Label, { htmlFor: "payments-postal", className: "flex items-center gap-2 text-white/70", children: [
1109
763
  /* @__PURE__ */ jsx(MapPin, { className: "h-4 w-4" }),
1110
764
  " Postal code"
1111
765
  ] }),
@@ -1157,7 +811,7 @@ var CardDetailsForm = ({
1157
811
  ] })
1158
812
  }
1159
813
  ),
1160
- /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
814
+ /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-2 text-xs text-white/50", children: [
1161
815
  /* @__PURE__ */ jsx(CreditCard, { className: "h-4 w-4" }),
1162
816
  " Your payment information is encrypted and processed securely."
1163
817
  ] })
@@ -1165,19 +819,24 @@ var CardDetailsForm = ({
1165
819
  }
1166
820
  );
1167
821
  };
1168
- var usePaymentMethodService = () => {
1169
- const { services } = usePaymentContext();
1170
- return useMemo(() => services.paymentMethods, [services]);
1171
- };
1172
-
1173
- // src/hooks/usePaymentMethods.ts
1174
822
  var PAYMENT_METHODS_KEY = ["payments-ui", "payment-methods"];
1175
823
  var usePaymentMethods = () => {
1176
- const service = usePaymentMethodService();
824
+ const { client } = usePaymentContext();
1177
825
  const queryClient = useQueryClient();
1178
826
  const listQuery = useQuery({
1179
827
  queryKey: PAYMENT_METHODS_KEY,
1180
- queryFn: () => service.list({ pageSize: 50 })
828
+ queryFn: async () => {
829
+ const response = await client.listPaymentMethods({ limit: 50 });
830
+ return {
831
+ data: response.data,
832
+ total_items: response.total,
833
+ limit: response.limit,
834
+ offset: response.offset,
835
+ page: response.limit > 0 ? Math.floor(response.offset / response.limit) + 1 : 1,
836
+ page_size: response.limit,
837
+ total_pages: response.limit > 0 ? Math.ceil(response.total / response.limit) : void 0
838
+ };
839
+ }
1181
840
  });
1182
841
  const createMutation = useMutation({
1183
842
  mutationFn: ({ token, billing }) => {
@@ -1194,14 +853,14 @@ var usePaymentMethods = () => {
1194
853
  email: billing.email,
1195
854
  provider: billing.provider
1196
855
  };
1197
- return service.create(payload);
856
+ return client.createPaymentMethod(payload);
1198
857
  },
1199
858
  onSuccess: () => {
1200
859
  void queryClient.invalidateQueries({ queryKey: PAYMENT_METHODS_KEY });
1201
860
  }
1202
861
  });
1203
862
  const deleteMutation = useMutation({
1204
- mutationFn: ({ id }) => service.remove(id),
863
+ mutationFn: ({ id }) => client.deletePaymentMethod(id),
1205
864
  onSuccess: () => {
1206
865
  void queryClient.invalidateQueries({ queryKey: PAYMENT_METHODS_KEY });
1207
866
  }
@@ -1217,10 +876,10 @@ var badgeVariants = cva(
1217
876
  {
1218
877
  variants: {
1219
878
  variant: {
1220
- default: "border-transparent bg-primary text-primary-foreground",
1221
- secondary: "border-transparent bg-secondary text-secondary-foreground",
1222
- outline: "text-foreground",
1223
- destructive: "border-transparent bg-destructive text-destructive-foreground"
879
+ default: "border-transparent bg-emerald-500/20 text-emerald-400",
880
+ secondary: "border-transparent bg-white/10 text-white/70",
881
+ outline: "border-white/20 text-white/80",
882
+ destructive: "border-transparent bg-red-500/20 text-red-400"
1224
883
  }
1225
884
  },
1226
885
  defaultVariants: {
@@ -1231,7 +890,7 @@ var badgeVariants = cva(
1231
890
  function Badge({ className, variant, ...props }) {
1232
891
  return /* @__PURE__ */ jsx("div", { className: cn(badgeVariants({ variant }), className), ...props });
1233
892
  }
1234
- var ScrollArea = React3.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
893
+ var ScrollArea = React17.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1235
894
  ScrollAreaPrimitive.Root,
1236
895
  {
1237
896
  ref,
@@ -1245,7 +904,7 @@ var ScrollArea = React3.forwardRef(({ className, children, ...props }, ref) => /
1245
904
  }
1246
905
  ));
1247
906
  ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
1248
- var ScrollBar = React3.forwardRef(({ className, orientation = "vertical", ...props }, ref) => /* @__PURE__ */ jsx(
907
+ var ScrollBar = React17.forwardRef(({ className, orientation = "vertical", ...props }, ref) => /* @__PURE__ */ jsx(
1249
908
  ScrollAreaPrimitive.ScrollAreaScrollbar,
1250
909
  {
1251
910
  ref,
@@ -1383,36 +1042,36 @@ var StoredPaymentMethods = ({
1383
1042
  ] });
1384
1043
  };
1385
1044
  var Tabs = TabsPrimitive.Root;
1386
- var TabsList = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1045
+ var TabsList = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1387
1046
  TabsPrimitive.List,
1388
1047
  {
1389
1048
  ref,
1390
1049
  className: cn(
1391
- "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
1050
+ "inline-flex h-10 items-center justify-center rounded-md bg-white/5 border border-white/10 p-1 text-white/60",
1392
1051
  className
1393
1052
  ),
1394
1053
  ...props
1395
1054
  }
1396
1055
  ));
1397
1056
  TabsList.displayName = TabsPrimitive.List.displayName;
1398
- var TabsTrigger = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1057
+ var TabsTrigger = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1399
1058
  TabsPrimitive.Trigger,
1400
1059
  {
1401
1060
  ref,
1402
1061
  className: cn(
1403
- "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
1062
+ "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",
1404
1063
  className
1405
1064
  ),
1406
1065
  ...props
1407
1066
  }
1408
1067
  ));
1409
1068
  TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
1410
- var TabsContent = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1069
+ var TabsContent = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1411
1070
  TabsPrimitive.Content,
1412
1071
  {
1413
1072
  ref,
1414
1073
  className: cn(
1415
- "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
1074
+ "mt-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/20",
1416
1075
  className
1417
1076
  ),
1418
1077
  ...props
@@ -1447,372 +1106,9 @@ var usePaymentNotifications = () => {
1447
1106
  notifyError
1448
1107
  };
1449
1108
  };
1450
- var useSolanaService = () => {
1451
- const { services } = usePaymentContext();
1452
- return useMemo(() => services.solanaPayments, [services]);
1453
- };
1454
- var getSolBalance = async (connection, publicKey) => {
1455
- try {
1456
- const lamports = await connection.getBalance(publicKey);
1457
- return lamports / LAMPORTS_PER_SOL;
1458
- } catch (error) {
1459
- console.error("Failed to fetch SOL balance:", error);
1460
- return 0;
1461
- }
1462
- };
1463
- var fetchAllTokenBalances = async (connection, publicKey) => {
1464
- const balances = /* @__PURE__ */ new Map();
1465
- try {
1466
- const tokenAccounts = await connection.getParsedProgramAccounts(
1467
- TOKEN_PROGRAM_ID,
1468
- {
1469
- filters: [
1470
- {
1471
- dataSize: 165
1472
- // Size of token account
1473
- },
1474
- {
1475
- memcmp: {
1476
- offset: 32,
1477
- // Owner field offset
1478
- bytes: publicKey.toString()
1479
- }
1480
- }
1481
- ]
1482
- }
1483
- );
1484
- for (const account of tokenAccounts) {
1485
- const data = account.account.data;
1486
- const parsed = data.parsed;
1487
- const info = parsed?.info;
1488
- if (info && info.tokenAmount) {
1489
- const mintAddress = info.mint;
1490
- const uiAmount = info.tokenAmount.uiAmount || 0;
1491
- if (uiAmount > 0) {
1492
- balances.set(mintAddress, uiAmount);
1493
- }
1494
- }
1495
- }
1496
- } catch (error) {
1497
- console.error("Failed to fetch token balances:", error);
1498
- }
1499
- return balances;
1500
- };
1501
- var fetchSupportedTokenBalances = async (connection, publicKey, supportedTokens) => {
1502
- const results = [];
1503
- const solBalance = await getSolBalance(connection, publicKey);
1504
- const solTokenMeta = supportedTokens.find((token) => token.is_native || token.symbol === "SOL") || {
1505
- symbol: "SOL",
1506
- name: "Solana",
1507
- mint: "So11111111111111111111111111111111111111112",
1508
- decimals: 9};
1509
- results.push({
1510
- mint: solTokenMeta.mint,
1511
- symbol: solTokenMeta.symbol,
1512
- name: solTokenMeta.name,
1513
- balance: solBalance,
1514
- uiBalance: solBalance.toFixed(solTokenMeta.decimals <= 4 ? solTokenMeta.decimals : 4),
1515
- decimals: solTokenMeta.decimals,
1516
- isNative: true
1517
- });
1518
- const tokenBalances = await fetchAllTokenBalances(connection, publicKey);
1519
- const tokenMetaByMint = new Map(
1520
- supportedTokens.filter((token) => !(token.is_native || token.symbol === "SOL")).map((token) => [token.mint, token])
1521
- );
1522
- for (const [mint, tokenMeta] of tokenMetaByMint.entries()) {
1523
- const balance = tokenBalances.get(mint) || 0;
1524
- results.push({
1525
- mint,
1526
- symbol: tokenMeta.symbol,
1527
- name: tokenMeta.name,
1528
- balance,
1529
- uiBalance: balance.toFixed(tokenMeta.decimals <= 6 ? tokenMeta.decimals : 6),
1530
- decimals: tokenMeta.decimals,
1531
- isNative: false
1532
- });
1533
- }
1534
- return results;
1535
- };
1536
- var hasSufficientBalance = (balance, requiredAmount, buffer = 0.05) => {
1537
- const requiredWithBuffer = requiredAmount * (1 + buffer);
1538
- return balance >= requiredWithBuffer;
1539
- };
1540
-
1541
- // src/hooks/useSolanaDirectPayment.ts
1542
- var useSolanaDirectPayment = (options) => {
1543
- const { priceId, tokenAmount, selectedToken, supportedTokens, onStart, onConfirming, onSuccess, onError } = options;
1544
- const { connected, publicKey, wallet, signTransaction } = useWallet();
1545
- const { config } = usePaymentContext();
1546
- const solanaService = useSolanaService();
1547
- const [tokenBalance, setTokenBalance] = useState(null);
1548
- const [isBalanceLoading, setIsBalanceLoading] = useState(false);
1549
- const [isProcessing, setIsProcessing] = useState(false);
1550
- const connection = useMemo(() => {
1551
- const rpc = config.solanaRpcUrl ?? "https://api.mainnet-beta.solana.com";
1552
- return new Connection(rpc);
1553
- }, [config.solanaRpcUrl]);
1554
- const fetchTokenBalance = useCallback(async () => {
1555
- if (!connected || !publicKey || !selectedToken) {
1556
- setTokenBalance({ balance: 0, hasBalance: false });
1557
- return;
1558
- }
1559
- try {
1560
- setIsBalanceLoading(true);
1561
- const balances = await fetchSupportedTokenBalances(
1562
- connection,
1563
- publicKey,
1564
- supportedTokens
1565
- );
1566
- const balanceInfo = balances.find(
1567
- (tb) => tb.symbol === selectedToken.symbol || tb.mint === selectedToken.mint
1568
- );
1569
- const balance = balanceInfo?.balance || 0;
1570
- const hasBalanceFlag = hasSufficientBalance(balance, tokenAmount);
1571
- setTokenBalance({ balance, hasBalance: hasBalanceFlag });
1572
- console.log("payments-ui: Solana wallet balance", {
1573
- token: selectedToken.symbol,
1574
- balance,
1575
- required: tokenAmount
1576
- });
1577
- } catch (error) {
1578
- console.error("Failed to fetch token balance:", {
1579
- token: selectedToken?.symbol,
1580
- error
1581
- });
1582
- setTokenBalance({ balance: 0, hasBalance: false });
1583
- } finally {
1584
- setIsBalanceLoading(false);
1585
- }
1586
- }, [connected, publicKey, connection, selectedToken, tokenAmount, supportedTokens]);
1587
- useEffect(() => {
1588
- if (connected && publicKey && selectedToken) {
1589
- void fetchTokenBalance();
1590
- }
1591
- }, [connected, publicKey, selectedToken, tokenAmount, fetchTokenBalance]);
1592
- const decodeTransaction = useCallback((serialized) => {
1593
- const buffer = Buffer.from(serialized, "base64");
1594
- try {
1595
- return VersionedTransaction.deserialize(buffer);
1596
- } catch (err) {
1597
- try {
1598
- return Transaction.from(buffer);
1599
- } catch (legacyErr) {
1600
- console.error("Failed to deserialize transaction", legacyErr);
1601
- throw new Error("Invalid transaction payload received from server");
1602
- }
1603
- }
1604
- }, []);
1605
- const isVersionedTransaction = (tx) => {
1606
- return !!tx && typeof tx === "object" && "version" in tx;
1607
- };
1608
- const signWithWallet = useCallback(
1609
- async (tx) => {
1610
- if (!wallet) {
1611
- throw new Error("Wallet adapter is not available");
1612
- }
1613
- const adapter = wallet.adapter;
1614
- if (isVersionedTransaction(tx)) {
1615
- if (adapter.supportedTransactionVersions) {
1616
- const supported = adapter.supportedTransactionVersions;
1617
- if (!supported.has(tx.version)) {
1618
- throw new Error("Connected wallet does not support this transaction version");
1619
- }
1620
- }
1621
- if (adapter.signVersionedTransaction) {
1622
- return adapter.signVersionedTransaction(tx);
1623
- }
1624
- }
1625
- if (adapter.signTransaction) {
1626
- return adapter.signTransaction(tx);
1627
- }
1628
- if (signTransaction) {
1629
- return signTransaction(tx);
1630
- }
1631
- throw new Error("Connected wallet cannot sign transactions");
1632
- },
1633
- [wallet, signTransaction]
1634
- );
1635
- const pay = useCallback(async () => {
1636
- if (!connected || !publicKey) {
1637
- onError("Wallet not connected");
1638
- return;
1639
- }
1640
- if (!selectedToken) {
1641
- onError("No payment token selected");
1642
- return;
1643
- }
1644
- if (!tokenBalance?.hasBalance) {
1645
- console.warn("payments-ui: insufficient balance for Solana direct payment", {
1646
- token: selectedToken.symbol
1647
- });
1648
- onError("Insufficient balance for this token");
1649
- return;
1650
- }
1651
- try {
1652
- setIsProcessing(true);
1653
- onStart();
1654
- console.log("payments-ui: initiating Solana direct payment", {
1655
- priceId,
1656
- token: selectedToken.symbol
1657
- });
1658
- const paymentData = await solanaService.generatePayment(
1659
- priceId,
1660
- selectedToken.symbol,
1661
- publicKey.toBase58()
1662
- );
1663
- console.log("payments-ui: Solana payment intent created", {
1664
- intentId: paymentData.intent_id
1665
- });
1666
- const transactionToSign = decodeTransaction(paymentData.transaction);
1667
- console.log("payments-ui: requesting Solana wallet signature");
1668
- const signedTx = await signWithWallet(transactionToSign);
1669
- const signedSerialized = Buffer.from(signedTx.serialize()).toString("base64");
1670
- onConfirming();
1671
- console.log("payments-ui: submitting signed Solana transaction");
1672
- const result = await solanaService.submitPayment(
1673
- signedSerialized,
1674
- priceId,
1675
- paymentData.intent_id,
1676
- `Payment for subscription - ${selectedToken.symbol}`
1677
- );
1678
- console.log("payments-ui: Solana direct payment confirmed", {
1679
- transactionId: result.transaction_id
1680
- });
1681
- onSuccess(result, result.transaction_id);
1682
- } catch (err) {
1683
- console.error("Solana direct payment failed:", {
1684
- priceId,
1685
- token: selectedToken.symbol,
1686
- error: err
1687
- });
1688
- let errorMessage = "Payment failed. Please try again.";
1689
- const message = err instanceof Error ? err.message : typeof err === "string" ? err : "";
1690
- if (message.includes("User rejected")) {
1691
- errorMessage = "Payment cancelled by user";
1692
- } else if (/insufficient\s+funds/i.test(message)) {
1693
- errorMessage = "Insufficient balance for this token";
1694
- } else if (message) {
1695
- errorMessage = message;
1696
- }
1697
- onError(errorMessage);
1698
- } finally {
1699
- setIsProcessing(false);
1700
- }
1701
- }, [
1702
- connected,
1703
- publicKey,
1704
- selectedToken,
1705
- tokenBalance?.hasBalance,
1706
- onError,
1707
- onStart,
1708
- solanaService,
1709
- priceId,
1710
- decodeTransaction,
1711
- signWithWallet,
1712
- onConfirming,
1713
- onSuccess
1714
- ]);
1715
- const balanceLabel = tokenBalance ? `${tokenBalance.balance.toFixed(4)} ${selectedToken?.symbol ?? ""}` : "--";
1716
- return {
1717
- isBalanceLoading,
1718
- isProcessing,
1719
- balanceLabel,
1720
- canPay: Boolean(
1721
- connected && tokenBalance?.hasBalance && !isProcessing
1722
- ),
1723
- pay
1724
- };
1725
- };
1726
- var Card = React3.forwardRef(
1727
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1728
- "div",
1729
- {
1730
- ref,
1731
- className: cn("rounded-xl border bg-card text-card-foreground shadow", className),
1732
- ...props
1733
- }
1734
- )
1735
- );
1736
- Card.displayName = "Card";
1737
- var CardHeader = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1738
- "div",
1739
- {
1740
- ref,
1741
- className: cn("flex flex-col space-y-1.5 p-6", className),
1742
- ...props
1743
- }
1744
- ));
1745
- CardHeader.displayName = "CardHeader";
1746
- var CardTitle = React3.forwardRef(
1747
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx("h3", { ref, className: cn("text-2xl font-semibold leading-none tracking-tight", className), ...props })
1748
- );
1749
- CardTitle.displayName = "CardTitle";
1750
- var CardDescription = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
1751
- CardDescription.displayName = "CardDescription";
1752
- var CardContent = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
1753
- CardContent.displayName = "CardContent";
1754
- var CardFooter = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1755
- "div",
1756
- {
1757
- ref,
1758
- className: cn("flex items-center p-6 pt-0", className),
1759
- ...props
1760
- }
1761
- ));
1762
- CardFooter.displayName = "CardFooter";
1763
- var DirectPayment = ({
1764
- priceId,
1765
- tokenAmount,
1766
- selectedToken,
1767
- supportedTokens,
1768
- onPaymentStart,
1769
- onPaymentConfirming,
1770
- onPaymentSuccess,
1771
- onPaymentError
1772
- }) => {
1773
- const { isBalanceLoading, balanceLabel, canPay, isProcessing, pay } = useSolanaDirectPayment({
1774
- priceId,
1775
- tokenAmount,
1776
- selectedToken,
1777
- supportedTokens,
1778
- onStart: onPaymentStart,
1779
- onConfirming: onPaymentConfirming,
1780
- onSuccess: onPaymentSuccess,
1781
- onError: onPaymentError
1782
- });
1783
- return /* @__PURE__ */ jsxs(Card, { className: "space-y-4 rounded-md border border-border/60 bg-background/80 shadow-none p-6", children: [
1784
- /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1785
- /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-2 text-sm font-semibold uppercase tracking-wide text-muted-foreground", children: [
1786
- /* @__PURE__ */ jsx(Wallet, { className: "h-4 w-4" }),
1787
- " Pay with connected wallet"
1788
- ] }),
1789
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Sign the transaction directly in your Solana wallet." })
1790
- ] }),
1791
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between rounded-lg border border-border/50 bg-muted/10 px-4 py-3 text-sm", children: [
1792
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Available balance" }),
1793
- isBalanceLoading ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }) : /* @__PURE__ */ jsx("strong", { className: "text-foreground", children: balanceLabel })
1794
- ] }),
1795
- /* @__PURE__ */ jsx(
1796
- Button,
1797
- {
1798
- type: "button",
1799
- className: "w-full",
1800
- disabled: !canPay,
1801
- onClick: pay,
1802
- children: isProcessing ? /* @__PURE__ */ jsxs(Fragment, { children: [
1803
- /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
1804
- " Processing\u2026"
1805
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1806
- /* @__PURE__ */ jsx(Wallet, { className: "mr-2 h-4 w-4" }),
1807
- " Pay with wallet"
1808
- ] })
1809
- }
1810
- )
1811
- ] });
1812
- };
1813
1109
  var useSolanaQrPayment = (options) => {
1814
1110
  const { priceId, selectedToken, onSuccess, onError } = options;
1815
- const solanaService = useSolanaService();
1111
+ const { client } = usePaymentContext();
1816
1112
  const tokenSymbol = selectedToken?.symbol ?? null;
1817
1113
  const onSuccessRef = useRef(onSuccess);
1818
1114
  const onErrorRef = useRef(onError);
@@ -1874,14 +1170,16 @@ var useSolanaQrPayment = (options) => {
1874
1170
  paymentId: status.payment_id,
1875
1171
  intentId: status.intent_id
1876
1172
  });
1877
- onSuccessRef.current?.(status.payment_id, status.transaction || "");
1173
+ const paymentId = status.payment_id ?? void 0;
1174
+ const txId = status.transaction ?? void 0;
1175
+ onSuccessRef.current?.(paymentId, txId);
1878
1176
  },
1879
1177
  [clearTimers, resetState]
1880
1178
  );
1881
1179
  const pollStatus = useCallback(
1882
1180
  async (reference) => {
1883
1181
  try {
1884
- const status = await solanaService.checkPaymentStatus(reference);
1182
+ const status = await client.getSolanaPayStatus(reference);
1885
1183
  if (status.status === "confirmed") {
1886
1184
  handleSuccess(status);
1887
1185
  }
@@ -1895,7 +1193,7 @@ var useSolanaQrPayment = (options) => {
1895
1193
  console.error("Failed to poll Solana Pay status:", err);
1896
1194
  }
1897
1195
  },
1898
- [handleError, handleSuccess, solanaService]
1196
+ [handleError, handleSuccess, client]
1899
1197
  );
1900
1198
  const startCountdown = useCallback(
1901
1199
  (expiresAt, reference) => {
@@ -1944,10 +1242,10 @@ var useSolanaQrPayment = (options) => {
1944
1242
  priceId,
1945
1243
  token: tokenSymbol
1946
1244
  });
1947
- const nextIntent = await solanaService.generateQRCode(
1245
+ const nextIntent = await client.createSolanaPayIntent({
1948
1246
  priceId,
1949
- tokenSymbol
1950
- );
1247
+ token: tokenSymbol
1248
+ });
1951
1249
  if (cancelled) return;
1952
1250
  setIntent(nextIntent);
1953
1251
  setTimeRemaining(
@@ -1957,8 +1255,13 @@ var useSolanaQrPayment = (options) => {
1957
1255
  console.log("[payments-ui] Solana Pay QR ready", {
1958
1256
  reference: nextIntent.reference
1959
1257
  });
1960
- startCountdown(nextIntent.expires_at, nextIntent.reference);
1961
- pollStatus(nextIntent.reference);
1258
+ const reference = nextIntent.reference;
1259
+ if (typeof reference === "string" && reference.length > 0) {
1260
+ startCountdown(nextIntent.expires_at, reference);
1261
+ pollStatus(reference);
1262
+ } else {
1263
+ handleError("Payment reference missing from intent", true);
1264
+ }
1962
1265
  } catch (err) {
1963
1266
  if (cancelled) return;
1964
1267
  console.error("Failed to generate Solana Pay QR intent:", err);
@@ -1982,7 +1285,7 @@ var useSolanaQrPayment = (options) => {
1982
1285
  priceId,
1983
1286
  renderQr,
1984
1287
  resetState,
1985
- solanaService,
1288
+ client,
1986
1289
  startCountdown,
1987
1290
  tokenSymbol,
1988
1291
  refreshNonce
@@ -1999,17 +1302,65 @@ var useSolanaQrPayment = (options) => {
1999
1302
  refresh
2000
1303
  };
2001
1304
  };
1305
+ var Card = React17.forwardRef(
1306
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1307
+ "div",
1308
+ {
1309
+ ref,
1310
+ className: cn("rounded-xl border border-white/10 bg-[#161b22] text-white shadow", className),
1311
+ ...props
1312
+ }
1313
+ )
1314
+ );
1315
+ Card.displayName = "Card";
1316
+ var CardHeader = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1317
+ "div",
1318
+ {
1319
+ ref,
1320
+ className: cn("flex flex-col space-y-1.5 p-6", className),
1321
+ ...props
1322
+ }
1323
+ ));
1324
+ CardHeader.displayName = "CardHeader";
1325
+ var CardTitle = React17.forwardRef(
1326
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("h3", { ref, className: cn("text-xl font-semibold leading-none tracking-tight text-white", className), ...props })
1327
+ );
1328
+ CardTitle.displayName = "CardTitle";
1329
+ var CardDescription = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("p", { ref, className: cn("text-sm text-white/60", className), ...props }));
1330
+ CardDescription.displayName = "CardDescription";
1331
+ var CardContent = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
1332
+ CardContent.displayName = "CardContent";
1333
+ var CardFooter = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1334
+ "div",
1335
+ {
1336
+ ref,
1337
+ className: cn("flex items-center p-6 pt-0", className),
1338
+ ...props
1339
+ }
1340
+ ));
1341
+ CardFooter.displayName = "CardFooter";
2002
1342
  var QRCodePayment = ({
2003
1343
  priceId,
2004
1344
  selectedToken,
2005
1345
  onPaymentError,
2006
1346
  onPaymentSuccess
2007
1347
  }) => {
1348
+ const handleQrSuccess = React17__default.useCallback(
1349
+ (paymentId, txId) => {
1350
+ if (!paymentId && !txId) {
1351
+ onPaymentError("Missing payment confirmation details");
1352
+ return;
1353
+ }
1354
+ const resolvedResult = paymentId ?? txId ?? "";
1355
+ onPaymentSuccess(resolvedResult, txId);
1356
+ },
1357
+ [onPaymentError, onPaymentSuccess]
1358
+ );
2008
1359
  const { intent, qrDataUri, isLoading, error, timeRemaining, refresh } = useSolanaQrPayment({
2009
1360
  priceId,
2010
1361
  selectedToken,
2011
1362
  onError: onPaymentError,
2012
- onSuccess: onPaymentSuccess
1363
+ onSuccess: handleQrSuccess
2013
1364
  });
2014
1365
  if (!selectedToken) {
2015
1366
  return /* @__PURE__ */ 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." });
@@ -2102,7 +1453,7 @@ var PaymentStatus = ({
2102
1453
  return null;
2103
1454
  };
2104
1455
  var useSupportedTokens = () => {
2105
- const solanaService = useSolanaService();
1456
+ const { client } = usePaymentContext();
2106
1457
  const [tokens, setTokens] = useState([]);
2107
1458
  const [isLoading, setIsLoading] = useState(false);
2108
1459
  const [error, setError] = useState(null);
@@ -2120,7 +1471,7 @@ var useSupportedTokens = () => {
2120
1471
  setError(null);
2121
1472
  try {
2122
1473
  console.log("payments-ui: fetching supported Solana tokens");
2123
- const tokens2 = await solanaService.getSupportedTokens();
1474
+ const tokens2 = await client.getSolanaTokens();
2124
1475
  const sortedTokens = [...tokens2].sort(
2125
1476
  (a, b) => a.symbol.localeCompare(b.symbol)
2126
1477
  );
@@ -2138,7 +1489,7 @@ var useSupportedTokens = () => {
2138
1489
  } finally {
2139
1490
  setIsLoading(false);
2140
1491
  }
2141
- }, [solanaService]);
1492
+ }, [client]);
2142
1493
  useEffect(() => {
2143
1494
  if (tokens.length === 0) {
2144
1495
  fetchSupportedTokens();
@@ -2250,9 +1601,7 @@ var SolanaPaymentView = ({
2250
1601
  onError,
2251
1602
  onClose
2252
1603
  }) => {
2253
- const { connected } = useWallet();
2254
1604
  const { notifyStatus, notifyError, notifySuccess } = usePaymentNotifications();
2255
- const [activeTab, setActiveTab] = useState("wallet");
2256
1605
  const [paymentState, setPaymentState] = useState("selecting");
2257
1606
  const [errorMessage, setErrorMessage] = useState(null);
2258
1607
  const [transactionId, setTransactionId] = useState(null);
@@ -2274,14 +1623,6 @@ var SolanaPaymentView = ({
2274
1623
  setSelectedTokenSymbol(defaultToken.symbol);
2275
1624
  }
2276
1625
  }, [tokens, selectedTokenSymbol]);
2277
- const handlePaymentStart = useCallback(() => {
2278
- setPaymentState("processing");
2279
- setErrorMessage(null);
2280
- notifyStatus("processing", { source: "solana" });
2281
- }, [notifyStatus]);
2282
- const handlePaymentConfirming = useCallback(() => {
2283
- setPaymentState("confirming");
2284
- }, []);
2285
1626
  const handlePaymentSuccess = useCallback(
2286
1627
  (result, txId) => {
2287
1628
  const resolvedTx = txId || (typeof result === "string" ? result : result.transaction_id);
@@ -2350,16 +1691,6 @@ var SolanaPaymentView = ({
2350
1691
  const handleTokenChange = useCallback((value) => {
2351
1692
  setSelectedTokenSymbol(value);
2352
1693
  }, []);
2353
- const wasConnectedRef = useRef(connected);
2354
- useEffect(() => {
2355
- if (connected && !wasConnectedRef.current) {
2356
- setActiveTab("wallet");
2357
- }
2358
- if (!connected && wasConnectedRef.current) {
2359
- setActiveTab("qr");
2360
- }
2361
- wasConnectedRef.current = connected;
2362
- }, [connected]);
2363
1694
  const renderBody = () => {
2364
1695
  if (paymentState !== "selecting") {
2365
1696
  return /* @__PURE__ */ jsx(
@@ -2414,51 +1745,15 @@ var SolanaPaymentView = ({
2414
1745
  ] }, token.symbol)) })
2415
1746
  ] })
2416
1747
  ] }),
2417
- /* @__PURE__ */ jsx("div", { className: "space-y-3", children: /* @__PURE__ */ jsxs(
2418
- Tabs,
1748
+ /* @__PURE__ */ jsx(
1749
+ QRCodePayment,
2419
1750
  {
2420
- value: activeTab,
2421
- onValueChange: (value) => setActiveTab(value),
2422
- className: "w-full space-y-3",
2423
- children: [
2424
- /* @__PURE__ */ jsxs(TabsList, { className: "grid w-full grid-cols-2 bg-muted/10", children: [
2425
- /* @__PURE__ */ jsxs(TabsTrigger, { value: "wallet", disabled: !connected, children: [
2426
- /* @__PURE__ */ jsx(Wallet, { className: "mr-2 h-4 w-4" }),
2427
- " Wallet"
2428
- ] }),
2429
- /* @__PURE__ */ jsxs(TabsTrigger, { value: "qr", children: [
2430
- /* @__PURE__ */ jsx(CreditCard, { className: "mr-2 h-4 w-4" }),
2431
- " QR Code"
2432
- ] })
2433
- ] }),
2434
- /* @__PURE__ */ jsxs(TabsContent, { value: "wallet", className: "space-y-4", children: [
2435
- activeTab === "wallet" && /* @__PURE__ */ jsx(
2436
- DirectPayment,
2437
- {
2438
- priceId,
2439
- tokenAmount,
2440
- selectedToken,
2441
- supportedTokens: tokens,
2442
- onPaymentStart: handlePaymentStart,
2443
- onPaymentConfirming: handlePaymentConfirming,
2444
- onPaymentSuccess: handlePaymentSuccess,
2445
- onPaymentError: handlePaymentError
2446
- }
2447
- ),
2448
- !connected && /* @__PURE__ */ jsx("div", { className: "text-sm text-amber-100", children: "Connect your Solana wallet to continue or switch to QR mode." })
2449
- ] }),
2450
- /* @__PURE__ */ jsx(TabsContent, { value: "qr", children: activeTab === "qr" && /* @__PURE__ */ jsx(
2451
- QRCodePayment,
2452
- {
2453
- priceId,
2454
- selectedToken,
2455
- onPaymentError: handlePaymentError,
2456
- onPaymentSuccess: handlePaymentSuccess
2457
- }
2458
- ) })
2459
- ]
1751
+ priceId,
1752
+ selectedToken,
1753
+ onPaymentError: handlePaymentError,
1754
+ onPaymentSuccess: handlePaymentSuccess
2460
1755
  }
2461
- ) })
1756
+ )
2462
1757
  ] });
2463
1758
  };
2464
1759
  return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
@@ -2466,7 +1761,7 @@ var SolanaPaymentView = ({
2466
1761
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2467
1762
  /* @__PURE__ */ jsx("p", { className: "text-xs uppercase tracking-wide text-muted-foreground", children: "Solana Pay checkout" }),
2468
1763
  /* @__PURE__ */ jsx("p", { className: "text-2xl font-semibold text-foreground", children: "Pay with Solana" }),
2469
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Choose a supported token and send the payment with your wallet or a QR code." })
1764
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Choose a supported token and send the payment via Solana Pay QR code." })
2470
1765
  ] }),
2471
1766
  onClose && /* @__PURE__ */ jsxs(
2472
1767
  Button,
@@ -2487,176 +1782,31 @@ var SolanaPaymentView = ({
2487
1782
  renderBody()
2488
1783
  ] });
2489
1784
  };
2490
- var useSubscriptionActions = () => {
2491
- const { services } = usePaymentContext();
2492
- const ensurePrice = (priceId) => {
2493
- if (!priceId) {
2494
- throw new Error("payments-ui: priceId is required for subscription actions");
2495
- }
2496
- return priceId;
2497
- };
2498
- const subscribeWithCard = useCallback(
2499
- async ({
2500
- priceId,
2501
- processor = "nmi",
2502
- provider,
2503
- paymentToken,
2504
- billing
2505
- }) => {
2506
- const payload = {
2507
- priceId: ensurePrice(priceId),
2508
- paymentToken,
2509
- processor,
2510
- provider,
2511
- email: billing.email,
2512
- firstName: billing.firstName,
2513
- lastName: billing.lastName,
2514
- address1: billing.address1,
2515
- city: billing.city,
2516
- state: billing.stateRegion,
2517
- zipCode: billing.postalCode,
2518
- country: billing.country
2519
- };
2520
- return services.subscriptions.subscribe("nmi", payload);
2521
- },
2522
- [services]
2523
- );
2524
- const subscribeWithSavedMethod = useCallback(
2525
- async ({
2526
- priceId,
2527
- processor = "nmi",
2528
- provider,
2529
- paymentMethodId,
2530
- email
2531
- }) => {
2532
- const payload = {
2533
- priceId: ensurePrice(priceId),
2534
- paymentMethodId,
2535
- processor,
2536
- provider,
2537
- email
2538
- };
2539
- return services.subscriptions.subscribe("nmi", payload);
2540
- },
2541
- [services]
2542
- );
2543
- const subscribeWithCCBill = useCallback(
2544
- async ({
2545
- priceId,
2546
- email,
2547
- firstName,
2548
- lastName,
2549
- zipCode,
2550
- country,
2551
- processor = "ccbill"
2552
- }) => {
2553
- const payload = {
2554
- priceId: ensurePrice(priceId),
2555
- email,
2556
- firstName,
2557
- lastName,
2558
- zipCode,
2559
- country,
2560
- processor
2561
- };
2562
- return services.subscriptions.subscribe("ccbill", payload);
2563
- },
2564
- [services]
2565
- );
2566
- const generateFlexFormUrl = useCallback(
2567
- async ({
2568
- priceId,
2569
- firstName,
2570
- lastName,
2571
- address1,
2572
- city,
2573
- state,
2574
- zipCode,
2575
- country
2576
- }) => {
2577
- const payload = {
2578
- price_id: ensurePrice(priceId),
2579
- first_name: firstName,
2580
- last_name: lastName,
2581
- address1,
2582
- city,
2583
- state,
2584
- zip_code: zipCode,
2585
- country
2586
- };
2587
- return services.subscriptions.generateFlexFormUrl(payload);
2588
- },
2589
- [services]
2590
- );
2591
- return {
2592
- subscribeWithCard,
2593
- subscribeWithSavedMethod,
2594
- subscribeWithCCBill,
2595
- generateFlexFormUrl
2596
- };
2597
- };
2598
-
2599
- // src/hooks/useAlternativePaymentProvider.ts
2600
- var useAlternativePaymentProvider = () => {
2601
- const [isLoading, setIsLoading] = useState(false);
2602
- const [error, setError] = useState(null);
2603
- const { generateFlexFormUrl } = useSubscriptionActions();
2604
- const openFlexForm = useCallback(
2605
- async (payload) => {
2606
- setIsLoading(true);
2607
- setError(null);
2608
- try {
2609
- const response = await generateFlexFormUrl(payload);
2610
- if (response?.iframe_url) {
2611
- window.location.href = response.iframe_url;
2612
- } else {
2613
- throw new Error("Unable to launch payment provider.");
2614
- }
2615
- } catch (err) {
2616
- const message = err instanceof Error ? err.message : "Failed to open payment provider.";
2617
- setError(message);
2618
- console.error("[payments-ui] failed to open alternative payment provider", err);
2619
- } finally {
2620
- setIsLoading(false);
2621
- }
2622
- },
2623
- [generateFlexFormUrl]
2624
- );
2625
- return { openFlexForm, isLoading, error };
2626
- };
2627
- var PaymentExperience = ({
2628
- priceId,
2629
- usdAmount,
2630
- onNewCardPayment,
2631
- onSavedMethodPayment,
2632
- enableNewCard = true,
2633
- enableStoredMethods = true,
2634
- enableSolanaPay = true,
2635
- enableAlternativePayments = true,
2636
- onSolanaSuccess,
2637
- onSolanaError,
2638
- initialMode = "cards"
2639
- }) => {
2640
- const showNewCard = enableNewCard && Boolean(onNewCardPayment);
2641
- const showStored = enableStoredMethods && Boolean(onSavedMethodPayment);
2642
- const defaultTab = showStored ? "saved" : "new";
2643
- const [activeTab, setActiveTab] = useState(defaultTab);
2644
- const [mode, setMode] = useState(
2645
- () => initialMode === "solana" && enableSolanaPay ? "solana" : "cards"
1785
+ var PaymentExperience = ({
1786
+ priceId,
1787
+ usdAmount,
1788
+ onNewCardPayment,
1789
+ onSavedMethodPayment,
1790
+ enableNewCard = true,
1791
+ enableStoredMethods = true,
1792
+ enableSolanaPay = true,
1793
+ onSolanaSuccess,
1794
+ onSolanaError,
1795
+ initialMode = "cards"
1796
+ }) => {
1797
+ const showNewCard = enableNewCard && Boolean(onNewCardPayment);
1798
+ const showStored = enableStoredMethods && Boolean(onSavedMethodPayment);
1799
+ const defaultTab = showStored ? "saved" : "new";
1800
+ const [activeTab, setActiveTab] = useState(defaultTab);
1801
+ const [mode, setMode] = useState(
1802
+ () => initialMode === "solana" && enableSolanaPay ? "solana" : "cards"
2646
1803
  );
2647
1804
  const [selectedMethodId, setSelectedMethodId] = useState(null);
2648
1805
  const [savedStatus, setSavedStatus] = useState("idle");
2649
1806
  const [savedError, setSavedError] = useState(null);
2650
1807
  const [newCardStatus, setNewCardStatus] = useState("idle");
2651
1808
  const [newCardError, setNewCardError] = useState(null);
2652
- const [billingDetails, setBillingDetails] = useState(null);
2653
- const [alternativePaymentError, setAlternativePaymentError] = useState(null);
2654
1809
  const { notifyStatus, notifySuccess, notifyError } = usePaymentNotifications();
2655
- const {
2656
- openFlexForm,
2657
- isLoading: flexFormLoading,
2658
- error: flexFormError
2659
- } = useAlternativePaymentProvider();
2660
1810
  useEffect(() => {
2661
1811
  setActiveTab(showStored ? "saved" : "new");
2662
1812
  }, [showStored]);
@@ -2736,48 +1886,6 @@ var PaymentExperience = ({
2736
1886
  },
2737
1887
  [onSolanaError]
2738
1888
  );
2739
- const handleAlternativePayment = useCallback(() => {
2740
- if (!enableAlternativePayments || !priceId) {
2741
- return;
2742
- }
2743
- if (!billingDetails) {
2744
- setAlternativePaymentError("Enter your billing details first.");
2745
- return;
2746
- }
2747
- const requiredFields = [
2748
- "firstName",
2749
- "lastName",
2750
- "address1",
2751
- "city",
2752
- "stateRegion",
2753
- "postalCode",
2754
- "country"
2755
- ];
2756
- const missingField = requiredFields.find((field) => {
2757
- const value = billingDetails[field];
2758
- return typeof value !== "string" || value.trim().length === 0;
2759
- });
2760
- if (missingField) {
2761
- setAlternativePaymentError("Please complete your billing address before continuing.");
2762
- return;
2763
- }
2764
- setAlternativePaymentError(null);
2765
- openFlexForm({
2766
- priceId,
2767
- firstName: billingDetails.firstName,
2768
- lastName: billingDetails.lastName,
2769
- address1: billingDetails.address1,
2770
- city: billingDetails.city,
2771
- state: billingDetails.stateRegion ?? "",
2772
- zipCode: billingDetails.postalCode,
2773
- country: billingDetails.country
2774
- });
2775
- }, [
2776
- billingDetails,
2777
- enableAlternativePayments,
2778
- openFlexForm,
2779
- priceId
2780
- ]);
2781
1889
  const renderSavedTab = () => {
2782
1890
  if (!showStored) {
2783
1891
  return /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Saved payment methods are unavailable right now. Add a new card to get started." });
@@ -2816,8 +1924,7 @@ var PaymentExperience = ({
2816
1924
  submitLabel: "Pay now",
2817
1925
  externalError: newCardError,
2818
1926
  onTokenize: handleNewCardTokenize,
2819
- submitting: newCardStatus === "processing",
2820
- onBillingChange: setBillingDetails
1927
+ submitting: newCardStatus === "processing"
2821
1928
  }
2822
1929
  );
2823
1930
  };
@@ -2845,19 +1952,6 @@ var PaymentExperience = ({
2845
1952
  ] });
2846
1953
  return /* @__PURE__ */ jsxs("div", { className: "space-y-6 pt-4", children: [
2847
1954
  mode === "cards" && renderCardExperience(),
2848
- mode === "cards" && enableAlternativePayments && /* @__PURE__ */ jsxs("div", { className: "space-y-2 text-center text-sm text-muted-foreground", children: [
2849
- /* @__PURE__ */ jsx(
2850
- "button",
2851
- {
2852
- type: "button",
2853
- className: "text-primary underline-offset-4 hover:underline disabled:opacity-60",
2854
- onClick: handleAlternativePayment,
2855
- disabled: flexFormLoading || !priceId,
2856
- children: flexFormLoading ? "Preparing alternative checkout\u2026" : "Prefer a different processor? Pay with CCBill"
2857
- }
2858
- ),
2859
- (alternativePaymentError || flexFormError) && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: alternativePaymentError || flexFormError })
2860
- ] }),
2861
1955
  mode === "solana" && enableSolanaPay && /* @__PURE__ */ jsx(
2862
1956
  SolanaPaymentView,
2863
1957
  {
@@ -2898,6 +1992,88 @@ var SubscriptionSuccessDialog = ({
2898
1992
  /* @__PURE__ */ jsx("div", { className: "px-6 py-6", children: /* @__PURE__ */ jsx(Button, { className: "w-full", onClick: onClose, children: "Continue exploring" }) })
2899
1993
  ] }) });
2900
1994
  };
1995
+ var useSubscriptionActions = () => {
1996
+ const { client } = usePaymentContext();
1997
+ const ensurePrice = (priceId) => {
1998
+ if (!priceId) {
1999
+ throw new Error("payments-ui: priceId is required for subscription actions");
2000
+ }
2001
+ return priceId;
2002
+ };
2003
+ const subscribeWithCard = useCallback(
2004
+ async ({
2005
+ priceId,
2006
+ processor = "nmi",
2007
+ provider,
2008
+ paymentToken,
2009
+ billing
2010
+ }) => {
2011
+ const payload = {
2012
+ price_id: ensurePrice(priceId),
2013
+ processor,
2014
+ provider,
2015
+ payment_token: paymentToken,
2016
+ email: billing.email,
2017
+ first_name: billing.firstName,
2018
+ last_name: billing.lastName,
2019
+ address1: billing.address1,
2020
+ city: billing.city,
2021
+ state: billing.stateRegion,
2022
+ zip: billing.postalCode,
2023
+ country: billing.country
2024
+ };
2025
+ return client.checkout(payload);
2026
+ },
2027
+ [client]
2028
+ );
2029
+ const subscribeWithSavedMethod = useCallback(
2030
+ async ({
2031
+ priceId,
2032
+ processor = "nmi",
2033
+ provider,
2034
+ paymentMethodId,
2035
+ email
2036
+ }) => {
2037
+ const payload = {
2038
+ price_id: ensurePrice(priceId),
2039
+ processor,
2040
+ provider,
2041
+ payment_method_id: paymentMethodId,
2042
+ email
2043
+ };
2044
+ return client.checkout(payload);
2045
+ },
2046
+ [client]
2047
+ );
2048
+ const subscribeWithCCBill = useCallback(
2049
+ async ({
2050
+ priceId,
2051
+ email,
2052
+ firstName,
2053
+ lastName,
2054
+ zipCode,
2055
+ country,
2056
+ processor = "ccbill"
2057
+ }) => {
2058
+ const payload = {
2059
+ price_id: ensurePrice(priceId),
2060
+ processor,
2061
+ email,
2062
+ first_name: firstName,
2063
+ last_name: lastName,
2064
+ zip: zipCode,
2065
+ country
2066
+ };
2067
+ return client.checkout(payload);
2068
+ },
2069
+ [client]
2070
+ );
2071
+ return {
2072
+ subscribeWithCard,
2073
+ subscribeWithSavedMethod,
2074
+ subscribeWithCCBill
2075
+ };
2076
+ };
2901
2077
  var SubscriptionCheckoutModal = ({
2902
2078
  open,
2903
2079
  onOpenChange,
@@ -2934,22 +2110,32 @@ var SubscriptionCheckoutModal = ({
2934
2110
  console.debug("[payments-ui] subscription success", result);
2935
2111
  }
2936
2112
  };
2113
+ const assertCheckoutSuccess = (status, message) => {
2114
+ if (status === "blocked") {
2115
+ throw new Error(message || "This subscription cannot be completed right now.");
2116
+ }
2117
+ if (status === "redirect_required") {
2118
+ throw new Error(message || "Additional action required in an alternate flow.");
2119
+ }
2120
+ };
2937
2121
  const handleNewCardPayment = async ({ token, billing }) => {
2938
- await subscribeWithCard({
2122
+ const response = await subscribeWithCard({
2939
2123
  priceId: ensurePrice(),
2940
2124
  provider,
2941
2125
  paymentToken: token,
2942
2126
  billing
2943
2127
  });
2128
+ assertCheckoutSuccess(response.status, response.message);
2944
2129
  notifySuccess();
2945
2130
  };
2946
2131
  const handleSavedMethodPayment = async ({ paymentMethodId }) => {
2947
- await subscribeWithSavedMethod({
2132
+ const response = await subscribeWithSavedMethod({
2948
2133
  priceId: ensurePrice(),
2949
2134
  provider,
2950
2135
  paymentMethodId,
2951
2136
  email: userEmail ?? ""
2952
2137
  });
2138
+ assertCheckoutSuccess(response.status, response.message);
2953
2139
  notifySuccess();
2954
2140
  };
2955
2141
  const solanaSuccess = (result) => {
@@ -2961,27 +2147,33 @@ var SubscriptionCheckoutModal = ({
2961
2147
  onSolanaError?.(error);
2962
2148
  };
2963
2149
  return /* @__PURE__ */ jsxs(Fragment, { children: [
2964
- /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsx(DialogContent, { className: "w-full max-w-3xl max-h-[90vh] overflow-y-auto rounded-md border border-border/60 bg-background p-0 [&::-webkit-scrollbar]:hidden", children: /* @__PURE__ */ jsxs("div", { className: "p-6 space-y-6", children: [
2965
- !priceId && /* @__PURE__ */ 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: [
2966
- /* @__PURE__ */ jsx(AlertCircle, { className: "h-4 w-4" }),
2967
- " Select a subscription plan to continue."
2968
- ] }),
2969
- /* @__PURE__ */ jsx(
2970
- PaymentExperience,
2971
- {
2972
- usdAmount,
2973
- priceId: priceId ?? "",
2974
- onSolanaSuccess: solanaSuccess,
2975
- onSolanaError: solanaError,
2976
- enableNewCard: Boolean(priceId),
2977
- enableStoredMethods: Boolean(priceId),
2978
- enableSolanaPay: enableSolanaPay && Boolean(priceId),
2979
- onNewCardPayment: priceId ? handleNewCardPayment : void 0,
2980
- onSavedMethodPayment: priceId ? handleSavedMethodPayment : void 0,
2981
- initialMode
2982
- }
2983
- )
2984
- ] }) }) }),
2150
+ /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsx(
2151
+ DialogContent,
2152
+ {
2153
+ className: "max-w-3xl max-h-[90vh] overflow-y-auto p-0 [&::-webkit-scrollbar]:hidden",
2154
+ children: /* @__PURE__ */ jsxs("div", { className: "p-6 space-y-6", children: [
2155
+ !priceId && /* @__PURE__ */ 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: [
2156
+ /* @__PURE__ */ jsx(AlertCircle, { className: "h-4 w-4" }),
2157
+ " Select a subscription plan to continue."
2158
+ ] }),
2159
+ /* @__PURE__ */ jsx(
2160
+ PaymentExperience,
2161
+ {
2162
+ usdAmount,
2163
+ priceId: priceId ?? "",
2164
+ onSolanaSuccess: solanaSuccess,
2165
+ onSolanaError: solanaError,
2166
+ enableNewCard: Boolean(priceId),
2167
+ enableStoredMethods: Boolean(priceId),
2168
+ enableSolanaPay: enableSolanaPay && Boolean(priceId),
2169
+ onNewCardPayment: priceId ? handleNewCardPayment : void 0,
2170
+ onSavedMethodPayment: priceId ? handleSavedMethodPayment : void 0,
2171
+ initialMode
2172
+ }
2173
+ )
2174
+ ] })
2175
+ }
2176
+ ) }),
2985
2177
  /* @__PURE__ */ jsx(
2986
2178
  SubscriptionSuccessDialog,
2987
2179
  {
@@ -3136,13 +2328,50 @@ var usePaymentDialogs = () => {
3136
2328
  var PaymentContext = createContext(void 0);
3137
2329
  var PaymentProvider = ({
3138
2330
  config,
3139
- runtime: runtimeProp,
3140
2331
  children
3141
2332
  }) => {
3142
- const runtime = useMemo(
3143
- () => runtimeProp ?? createPaymentsRuntime(config),
3144
- [runtimeProp, config]
3145
- );
2333
+ const queryClient = useMemo(() => {
2334
+ return new QueryClient({
2335
+ defaultOptions: {
2336
+ queries: {
2337
+ staleTime: 3e4,
2338
+ gcTime: 5 * 6e4,
2339
+ refetchOnWindowFocus: false,
2340
+ retry: 1
2341
+ },
2342
+ mutations: {
2343
+ retry: 1
2344
+ }
2345
+ }
2346
+ });
2347
+ }, []);
2348
+ const client = useMemo(() => {
2349
+ const authProvider = config.getAuthToken ? async () => {
2350
+ try {
2351
+ const result = config.getAuthToken?.();
2352
+ if (result instanceof Promise) {
2353
+ return await result ?? null;
2354
+ }
2355
+ return result ?? null;
2356
+ } catch (error) {
2357
+ console.warn("payments-ui: failed to resolve auth token", error);
2358
+ return null;
2359
+ }
2360
+ } : void 0;
2361
+ const wrappedFetch = config.fetcher ? ((input, init) => {
2362
+ const normalizedInput = input instanceof URL ? input.toString() : input;
2363
+ return config.fetcher(normalizedInput, init);
2364
+ }) : void 0;
2365
+ return createClient({
2366
+ billingBaseUrl: config.endpoints.billingBaseUrl,
2367
+ billingBasePath: config.endpoints.billingBasePath,
2368
+ accountBaseUrl: config.endpoints.accountBaseUrl,
2369
+ accountBasePath: config.endpoints.accountBasePath,
2370
+ getAuthToken: authProvider,
2371
+ defaultHeaders: config.defaultHeaders,
2372
+ fetch: wrappedFetch
2373
+ });
2374
+ }, [config]);
3146
2375
  const solanaEndpoint = useMemo(() => {
3147
2376
  if (config.solana?.endpoint) return config.solana.endpoint;
3148
2377
  const network = config.solana?.network ?? WalletAdapterNetwork.Mainnet;
@@ -3162,19 +2391,16 @@ var PaymentProvider = ({
3162
2391
  const autoConnect = config.solana?.autoConnect ?? true;
3163
2392
  const value = useMemo(() => {
3164
2393
  return {
3165
- config: runtime.config,
3166
- fetcher: runtime.app.getFetcher(),
3167
- resolveAuthToken: runtime.app.resolveAuthToken,
3168
- app: runtime.app,
3169
- services: runtime.services,
3170
- queryClient: runtime.queryClient
2394
+ config,
2395
+ client,
2396
+ queryClient
3171
2397
  };
3172
- }, [runtime]);
2398
+ }, [client, config, queryClient]);
3173
2399
  useEffect(() => {
3174
2400
  if (!config.collectJsKey) return;
3175
2401
  loadCollectJs(config.collectJsKey);
3176
2402
  }, [config.collectJsKey]);
3177
- return /* @__PURE__ */ jsx(PaymentContext.Provider, { value, children: /* @__PURE__ */ jsx(QueryClientProvider, { client: runtime.queryClient, children: /* @__PURE__ */ jsx(ConnectionProvider, { endpoint: solanaEndpoint, config: { commitment: "confirmed" }, children: /* @__PURE__ */ jsx(WalletProvider, { wallets: walletAdapters, autoConnect, children: /* @__PURE__ */ jsx(WalletModalProvider, { children: /* @__PURE__ */ jsx(PaymentsDialogProvider, { children }) }) }) }) }) });
2403
+ return /* @__PURE__ */ jsx(PaymentContext.Provider, { value, children: /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(ConnectionProvider, { endpoint: solanaEndpoint, config: { commitment: "confirmed" }, children: /* @__PURE__ */ jsx(WalletProvider, { wallets: walletAdapters, autoConnect, children: /* @__PURE__ */ jsx(WalletModalProvider, { children: /* @__PURE__ */ jsx(PaymentsDialogProvider, { children }) }) }) }) }) });
3178
2404
  };
3179
2405
  var usePaymentContext = () => {
3180
2406
  const context = useContext(PaymentContext);
@@ -3183,6 +2409,40 @@ var usePaymentContext = () => {
3183
2409
  }
3184
2410
  return context;
3185
2411
  };
2412
+ var PaymentsUIRoot = ({
2413
+ children,
2414
+ className,
2415
+ dark = false
2416
+ }) => {
2417
+ return /* @__PURE__ */ jsx(
2418
+ "div",
2419
+ {
2420
+ className: cn(
2421
+ "payments-ui-root",
2422
+ dark && "dark",
2423
+ className
2424
+ ),
2425
+ children
2426
+ }
2427
+ );
2428
+ };
2429
+ var PaymentsUIPortalRoot = ({
2430
+ children,
2431
+ className,
2432
+ dark = false
2433
+ }) => {
2434
+ return /* @__PURE__ */ jsx(
2435
+ "div",
2436
+ {
2437
+ className: cn(
2438
+ "payments-ui-portal",
2439
+ dark && "dark",
2440
+ className
2441
+ ),
2442
+ children
2443
+ }
2444
+ );
2445
+ };
3186
2446
  var SolanaPaymentSelector = ({
3187
2447
  isOpen,
3188
2448
  onClose,
@@ -3190,7 +2450,7 @@ var SolanaPaymentSelector = ({
3190
2450
  }) => {
3191
2451
  return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (value) => value ? void 0 : onClose(), children: /* @__PURE__ */ 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__ */ jsx(SolanaPaymentView, { ...props, onClose }) }) });
3192
2452
  };
3193
- var Table = React3.forwardRef(
2453
+ var Table = React17.forwardRef(
3194
2454
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3195
2455
  "table",
3196
2456
  {
@@ -3201,15 +2461,15 @@ var Table = React3.forwardRef(
3201
2461
  )
3202
2462
  );
3203
2463
  Table.displayName = "Table";
3204
- var TableHeader = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
2464
+ var TableHeader = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
3205
2465
  TableHeader.displayName = "TableHeader";
3206
- var TableBody = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("tbody", { ref, className: cn("[&_tr:last-child]:border-0", className), ...props }));
2466
+ var TableBody = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("tbody", { ref, className: cn("[&_tr:last-child]:border-0", className), ...props }));
3207
2467
  TableBody.displayName = "TableBody";
3208
- var TableFooter = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("tfoot", { ref, className: cn("bg-muted/50 font-medium text-muted-foreground", className), ...props }));
2468
+ var TableFooter = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("tfoot", { ref, className: cn("bg-muted/50 font-medium text-muted-foreground", className), ...props }));
3209
2469
  TableFooter.displayName = "TableFooter";
3210
- var TableRow = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("tr", { ref, className: cn("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className), ...props }));
2470
+ var TableRow = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("tr", { ref, className: cn("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className), ...props }));
3211
2471
  TableRow.displayName = "TableRow";
3212
- var TableHead = React3.forwardRef(
2472
+ var TableHead = React17.forwardRef(
3213
2473
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3214
2474
  "th",
3215
2475
  {
@@ -3223,7 +2483,7 @@ var TableHead = React3.forwardRef(
3223
2483
  )
3224
2484
  );
3225
2485
  TableHead.displayName = "TableHead";
3226
- var TableCell = React3.forwardRef(
2486
+ var TableCell = React17.forwardRef(
3227
2487
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3228
2488
  "td",
3229
2489
  {
@@ -3234,37 +2494,37 @@ var TableCell = React3.forwardRef(
3234
2494
  )
3235
2495
  );
3236
2496
  TableCell.displayName = "TableCell";
3237
- var TableCaption = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props }));
2497
+ var TableCaption = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props }));
3238
2498
  TableCaption.displayName = "TableCaption";
3239
2499
  var AlertDialog = AlertDialogPrimitive.Root;
3240
2500
  var AlertDialogTrigger = AlertDialogPrimitive.Trigger;
3241
2501
  var AlertDialogPortal = AlertDialogPrimitive.Portal;
3242
- var AlertDialogOverlay = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2502
+ var AlertDialogOverlay = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3243
2503
  AlertDialogPrimitive.Overlay,
3244
2504
  {
3245
2505
  ref,
3246
2506
  className: cn(
3247
- "fixed inset-0 z-50 bg-background/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",
2507
+ "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",
3248
2508
  className
3249
2509
  ),
3250
2510
  ...props
3251
2511
  }
3252
2512
  ));
3253
2513
  AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
3254
- var AlertDialogContent = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs(AlertDialogPortal, { children: [
2514
+ var AlertDialogContent = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(AlertDialogPortal, { children: /* @__PURE__ */ jsxs("div", { className: "payments-ui-portal", children: [
3255
2515
  /* @__PURE__ */ jsx(AlertDialogOverlay, {}),
3256
2516
  /* @__PURE__ */ jsx(
3257
2517
  AlertDialogPrimitive.Content,
3258
2518
  {
3259
2519
  ref,
3260
2520
  className: cn(
3261
- "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-border bg-popover p-6 text-popover-foreground shadow-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",
2521
+ "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",
3262
2522
  className
3263
2523
  ),
3264
2524
  ...props
3265
2525
  }
3266
2526
  )
3267
- ] }));
2527
+ ] }) }));
3268
2528
  AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
3269
2529
  var AlertDialogHeader = ({
3270
2530
  className,
@@ -3282,13 +2542,13 @@ var AlertDialogFooter = ({
3282
2542
  }
3283
2543
  );
3284
2544
  AlertDialogFooter.displayName = "AlertDialogFooter";
3285
- var AlertDialogTitle = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(AlertDialogPrimitive.Title, { ref, className: cn("text-lg font-semibold", className), ...props }));
2545
+ var AlertDialogTitle = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(AlertDialogPrimitive.Title, { ref, className: cn("text-lg font-semibold text-white", className), ...props }));
3286
2546
  AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
3287
- var AlertDialogDescription = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(AlertDialogPrimitive.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
2547
+ var AlertDialogDescription = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(AlertDialogPrimitive.Description, { ref, className: cn("text-sm text-white/60", className), ...props }));
3288
2548
  AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
3289
- var AlertDialogAction = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(AlertDialogPrimitive.Action, { ref, className: cn(buttonVariants(), className), ...props }));
2549
+ var AlertDialogAction = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(AlertDialogPrimitive.Action, { ref, className: cn(buttonVariants(), className), ...props }));
3290
2550
  AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
3291
- var AlertDialogCancel = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2551
+ var AlertDialogCancel = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3292
2552
  AlertDialogPrimitive.Cancel,
3293
2553
  {
3294
2554
  ref,
@@ -3297,7 +2557,7 @@ var AlertDialogCancel = React3.forwardRef(({ className, ...props }, ref) => /* @
3297
2557
  }
3298
2558
  ));
3299
2559
  AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
3300
- var Textarea = React3.forwardRef(
2560
+ var Textarea = React17.forwardRef(
3301
2561
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3302
2562
  "textarea",
3303
2563
  {
@@ -3315,13 +2575,33 @@ var notifyDefault = (payload) => {
3315
2575
  const level = payload.status === "destructive" ? "error" : "info";
3316
2576
  console[level === "error" ? "error" : "log"]("[payments-ui] cancellation", payload);
3317
2577
  };
2578
+ var defaultTranslations = {
2579
+ buttonLabel: "Cancel Membership",
2580
+ title: "Confirm Membership Cancellation",
2581
+ description: "You are about to cancel your membership. Please review the consequences:",
2582
+ consequence1: "You will immediately lose access to premium features upon confirmation.",
2583
+ consequence2: "Your benefits remain active until the end of the billing cycle.",
2584
+ consequence3: "Your account will revert to the free plan afterwards.",
2585
+ reasonLabel: "Please provide a reason for cancellation (required):",
2586
+ reasonPlaceholder: "Your feedback helps us improve...",
2587
+ reasonError: "Reason must be at least {min} characters long.",
2588
+ reasonHint: "Minimum {min} characters required.",
2589
+ keepMembership: "Keep Membership",
2590
+ confirmCancellation: "Confirm Cancellation",
2591
+ cancelling: "Cancelling...",
2592
+ membershipCancelled: "Membership cancelled",
2593
+ cancellationSuccess: "Your subscription has been cancelled successfully.",
2594
+ cancellationFailed: "Cancellation failed"
2595
+ };
3318
2596
  var CancelMembershipDialog = ({
3319
2597
  minReasonLength = 15,
3320
2598
  onCancelled,
3321
- onNotify
2599
+ onNotify,
2600
+ translations: customTranslations
3322
2601
  }) => {
3323
- const { services } = usePaymentContext();
2602
+ const { client } = usePaymentContext();
3324
2603
  const notify = onNotify ?? notifyDefault;
2604
+ const t = { ...defaultTranslations, ...customTranslations };
3325
2605
  const [cancelReason, setCancelReason] = useState("");
3326
2606
  const [isOpen, setIsOpen] = useState(false);
3327
2607
  const [isReasonValid, setIsReasonValid] = useState(false);
@@ -3353,17 +2633,17 @@ var CancelMembershipDialog = ({
3353
2633
  }
3354
2634
  setIsSubmitting(true);
3355
2635
  try {
3356
- await services.subscriptions.cancelSubscription(cancelReason.trim());
2636
+ await client.cancelSubscription(cancelReason.trim());
3357
2637
  notify({
3358
- title: "Membership cancelled",
3359
- description: "Your subscription has been cancelled successfully.",
2638
+ title: t.membershipCancelled,
2639
+ description: t.cancellationSuccess,
3360
2640
  status: "success"
3361
2641
  });
3362
2642
  onCancelled?.();
3363
2643
  handleOpenChange(false);
3364
2644
  } catch (error) {
3365
2645
  const message = error instanceof Error ? error.message : "Unable to cancel membership";
3366
- notify({ title: "Cancellation failed", description: message, status: "destructive" });
2646
+ notify({ title: t.cancellationFailed, description: message, status: "destructive" });
3367
2647
  } finally {
3368
2648
  setIsSubmitting(false);
3369
2649
  }
@@ -3372,32 +2652,34 @@ var CancelMembershipDialog = ({
3372
2652
  return /* @__PURE__ */ jsxs(AlertDialog, { open: isOpen, onOpenChange: handleOpenChange, children: [
3373
2653
  /* @__PURE__ */ jsx(AlertDialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "outline", className: "border-destructive/50 text-destructive", children: [
3374
2654
  /* @__PURE__ */ jsx(Ban, { className: "mr-2 h-4 w-4" }),
3375
- " Cancel Membership"
2655
+ " ",
2656
+ t.buttonLabel
3376
2657
  ] }) }),
3377
2658
  /* @__PURE__ */ jsxs(AlertDialogContent, { className: "max-h-[90vh] overflow-y-auto rounded-md border border-border bg-background", children: [
3378
2659
  /* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
3379
2660
  /* @__PURE__ */ jsxs(AlertDialogTitle, { className: "flex items-center gap-2 text-lg font-semibold", children: [
3380
2661
  /* @__PURE__ */ jsx(TriangleAlert, { className: "h-5 w-5 text-destructive" }),
3381
- " Confirm Membership Cancellation"
2662
+ " ",
2663
+ t.title
3382
2664
  ] }),
3383
2665
  /* @__PURE__ */ jsxs(AlertDialogDescription, { className: "mt-3 space-y-3 text-muted-foreground", children: [
3384
- /* @__PURE__ */ jsx("p", { children: "You are about to cancel your membership. Please review the consequences:" }),
2666
+ /* @__PURE__ */ jsx("p", { children: t.description }),
3385
2667
  /* @__PURE__ */ jsxs("ul", { className: "list-disc space-y-1 pl-5 text-sm", children: [
3386
- /* @__PURE__ */ jsx("li", { children: "You will immediately lose access to premium features upon confirmation." }),
3387
- /* @__PURE__ */ jsx("li", { children: "Your benefits remain active until the end of the billing cycle." }),
3388
- /* @__PURE__ */ jsx("li", { children: "Your account will revert to the free plan afterwards." })
2668
+ /* @__PURE__ */ jsx("li", { children: t.consequence1 }),
2669
+ /* @__PURE__ */ jsx("li", { children: t.consequence2 }),
2670
+ /* @__PURE__ */ jsx("li", { children: t.consequence3 })
3389
2671
  ] })
3390
2672
  ] })
3391
2673
  ] }),
3392
2674
  /* @__PURE__ */ jsxs("div", { className: "my-4 space-y-2 py-2", children: [
3393
- /* @__PURE__ */ jsx(Label, { htmlFor: "cancelReason", className: "text-sm font-medium", children: "Please provide a reason for cancellation (required):" }),
2675
+ /* @__PURE__ */ jsx(Label, { htmlFor: "cancelReason", className: "text-sm font-medium", children: t.reasonLabel }),
3394
2676
  /* @__PURE__ */ jsx(
3395
2677
  Textarea,
3396
2678
  {
3397
2679
  id: "cancelReason",
3398
2680
  value: cancelReason,
3399
2681
  onChange: handleReasonChange,
3400
- placeholder: "Your feedback helps us improve...",
2682
+ placeholder: t.reasonPlaceholder,
3401
2683
  className: cn(
3402
2684
  "w-full resize-none border-border bg-background",
3403
2685
  showError && "border-destructive"
@@ -3412,19 +2694,19 @@ var CancelMembershipDialog = ({
3412
2694
  {
3413
2695
  id: "reason-hint",
3414
2696
  className: `text-xs ${showError ? "text-destructive" : "text-muted-foreground"}`,
3415
- children: showError ? `Reason must be at least ${minReasonLength} characters long.` : `Minimum ${minReasonLength} characters required.`
2697
+ children: showError ? t.reasonError.replace("{min}", String(minReasonLength)) : t.reasonHint.replace("{min}", String(minReasonLength))
3416
2698
  }
3417
2699
  )
3418
2700
  ] }),
3419
2701
  /* @__PURE__ */ jsxs(AlertDialogFooter, { className: "mt-6 gap-2", children: [
3420
- /* @__PURE__ */ jsx(AlertDialogCancel, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "outline", className: "border-border text-muted-foreground", children: "Keep Membership" }) }),
2702
+ /* @__PURE__ */ jsx(AlertDialogCancel, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "outline", className: "border-border text-muted-foreground", children: t.keepMembership }) }),
3421
2703
  /* @__PURE__ */ jsx(AlertDialogAction, { asChild: true, children: /* @__PURE__ */ jsx(
3422
2704
  Button,
3423
2705
  {
3424
2706
  className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
3425
2707
  onClick: handleConfirm,
3426
2708
  disabled: !isReasonValid || isSubmitting,
3427
- children: isSubmitting ? "Cancelling..." : "Confirm Cancellation"
2709
+ children: isSubmitting ? t.cancelling : t.confirmCancellation
3428
2710
  }
3429
2711
  ) })
3430
2712
  ] })
@@ -3435,14 +2717,29 @@ var notifyDefault2 = (payload) => {
3435
2717
  const level = payload.status === "destructive" ? "error" : "info";
3436
2718
  console[level === "error" ? "error" : "log"]("[payments-ui] billing", payload);
3437
2719
  };
2720
+ var defaultTranslations2 = {
2721
+ title: "Transaction History",
2722
+ description: "Record of billing history",
2723
+ reviewActivity: "Review your account activity below",
2724
+ loading: "Loading...",
2725
+ error: "Error loading billing history.",
2726
+ loadingMore: "Loading more...",
2727
+ reference: "Reference",
2728
+ date: "Date",
2729
+ amount: "Amount",
2730
+ processor: "Processor",
2731
+ status: "Status"
2732
+ };
3438
2733
  var BillingHistory = ({
3439
2734
  pageSize = 10,
3440
2735
  initialPage = 1,
3441
2736
  enableCancel = true,
3442
- onNotify
2737
+ onNotify,
2738
+ translations: customTranslations
3443
2739
  }) => {
3444
- const { services } = usePaymentContext();
2740
+ const { client } = usePaymentContext();
3445
2741
  const notify = onNotify ?? notifyDefault2;
2742
+ const t = { ...defaultTranslations2, ...customTranslations };
3446
2743
  const [isExpanded, setIsExpanded] = useState(false);
3447
2744
  const observerRef = useRef(null);
3448
2745
  const loadMoreRef = useRef(null);
@@ -3450,7 +2747,17 @@ var BillingHistory = ({
3450
2747
  queryKey: ["payments-ui", "billing-history", pageSize],
3451
2748
  queryFn: async ({ pageParam = initialPage }) => {
3452
2749
  const offset = (pageParam - 1) * pageSize;
3453
- return services.subscriptions.getPaymentHistory({ limit: pageSize, offset });
2750
+ return client.getPaymentHistory({ limit: pageSize, offset, type: void 0 }).then(
2751
+ (response) => ({
2752
+ data: response.data,
2753
+ total_items: response.total,
2754
+ limit: response.limit,
2755
+ offset: response.offset,
2756
+ page: response.limit > 0 ? Math.floor(response.offset / response.limit) + 1 : 1,
2757
+ page_size: response.limit,
2758
+ total_pages: response.limit > 0 ? Math.ceil(response.total / response.limit) : void 0
2759
+ })
2760
+ );
3454
2761
  },
3455
2762
  initialPageParam: initialPage,
3456
2763
  getNextPageParam: (lastPage) => {
@@ -3499,8 +2806,8 @@ var BillingHistory = ({
3499
2806
  return /* @__PURE__ */ jsx(Card, { className: "border-0 bg-background/5 shadow-lg", children: /* @__PURE__ */ jsxs("div", { className: "p-4 sm:p-6", children: [
3500
2807
  /* @__PURE__ */ jsxs("div", { className: "flex cursor-pointer items-center justify-between", onClick: () => setIsExpanded((prev) => !prev), children: [
3501
2808
  /* @__PURE__ */ jsxs("div", { children: [
3502
- /* @__PURE__ */ jsx(CardTitle, { className: "text-xl font-semibold", children: "Transaction History" }),
3503
- /* @__PURE__ */ jsx(CardDescription, { children: "Record of billing history" })
2809
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl font-semibold", children: t.title }),
2810
+ /* @__PURE__ */ jsx(CardDescription, { children: t.description })
3504
2811
  ] }),
3505
2812
  /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-5 w-5 text-muted-foreground transition-transform", isExpanded && "rotate-180") })
3506
2813
  ] }),
@@ -3513,16 +2820,16 @@ var BillingHistory = ({
3513
2820
  ),
3514
2821
  children: /* @__PURE__ */ jsx(CardContent, { className: "p-0 pt-4", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
3515
2822
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between", children: [
3516
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Review your account activity below" }),
2823
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t.reviewActivity }),
3517
2824
  enableCancel && /* @__PURE__ */ jsx(CancelMembershipDialog, { onNotify: notify })
3518
2825
  ] }),
3519
- /* @__PURE__ */ jsx("div", { className: "max-h-[300px] overflow-y-auto rounded-lg border border-border/70", children: /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: historyQuery.isLoading ? /* @__PURE__ */ jsx("p", { className: "p-4 text-center text-sm text-muted-foreground", children: "Loading..." }) : historyQuery.isError ? /* @__PURE__ */ jsx("p", { className: "p-4 text-center text-sm text-destructive", children: "Error loading billing history." }) : /* @__PURE__ */ jsxs(Table, { children: [
2826
+ /* @__PURE__ */ jsx("div", { className: "max-h-[300px] overflow-y-auto rounded-lg border border-border/70", children: /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: historyQuery.isLoading ? /* @__PURE__ */ jsx("p", { className: "p-4 text-center text-sm text-muted-foreground", children: t.loading }) : historyQuery.isError ? /* @__PURE__ */ jsx("p", { className: "p-4 text-center text-sm text-destructive", children: t.error }) : /* @__PURE__ */ jsxs(Table, { children: [
3520
2827
  /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { className: "border-border/60", children: [
3521
- /* @__PURE__ */ jsx(TableHead, { children: "Reference" }),
3522
- /* @__PURE__ */ jsx(TableHead, { children: "Date" }),
3523
- /* @__PURE__ */ jsx(TableHead, { children: "Amount" }),
3524
- /* @__PURE__ */ jsx(TableHead, { children: "Processor" }),
3525
- /* @__PURE__ */ jsx(TableHead, { children: "Status" })
2828
+ /* @__PURE__ */ jsx(TableHead, { children: t.reference }),
2829
+ /* @__PURE__ */ jsx(TableHead, { children: t.date }),
2830
+ /* @__PURE__ */ jsx(TableHead, { children: t.amount }),
2831
+ /* @__PURE__ */ jsx(TableHead, { children: t.processor }),
2832
+ /* @__PURE__ */ jsx(TableHead, { children: t.status })
3526
2833
  ] }) }),
3527
2834
  /* @__PURE__ */ jsx(TableBody, { children: payments.map(
3528
2835
  (page) => page.data.map((payment) => /* @__PURE__ */ jsxs(TableRow, { className: "border-border/40", children: [
@@ -3534,7 +2841,7 @@ var BillingHistory = ({
3534
2841
  ] }, payment.id))
3535
2842
  ) })
3536
2843
  ] }) }) }),
3537
- /* @__PURE__ */ jsx("div", { ref: loadMoreRef, className: "h-10 w-full", children: historyQuery.isFetchingNextPage && /* @__PURE__ */ jsx("p", { className: "text-center text-sm text-muted-foreground", children: "Loading more..." }) })
2844
+ /* @__PURE__ */ jsx("div", { ref: loadMoreRef, className: "h-10 w-full", children: historyQuery.isFetchingNextPage && /* @__PURE__ */ jsx("p", { className: "text-center text-sm text-muted-foreground", children: t.loadingMore }) })
3538
2845
  ] }) })
3539
2846
  }
3540
2847
  )
@@ -3549,19 +2856,56 @@ var notifyDefault3 = (payload) => {
3549
2856
  const level = payload.status === "destructive" ? "error" : "info";
3550
2857
  console[level === "error" ? "error" : "log"]("[payments-ui] notification", payload);
3551
2858
  };
2859
+ var defaultTranslations3 = {
2860
+ title: "Payment Methods",
2861
+ description: "Manage your saved billing cards",
2862
+ addCard: "Add card",
2863
+ loadingCards: "Loading cards...",
2864
+ noPaymentMethods: "No saved payment methods yet.",
2865
+ addedOn: "Added on",
2866
+ active: "Active",
2867
+ inactive: "Inactive",
2868
+ replaceCard: "Replace card",
2869
+ makeDefault: "Make default",
2870
+ defaultMethod: "Default method",
2871
+ remove: "Remove",
2872
+ addNewCard: "Add a new card",
2873
+ addNewCardDescription: "Your card details are tokenized securely via our payment provider.",
2874
+ saveCard: "Save card",
2875
+ replaceCardTitle: "Replace card",
2876
+ replaceCardDescription: "Update this card with new billing details.",
2877
+ cardAddedSuccess: "Card added successfully",
2878
+ unableToAddCard: "Unable to add card",
2879
+ cardRemoved: "Card removed",
2880
+ unableToRemoveCard: "Unable to remove card",
2881
+ cardUpdated: "Card updated",
2882
+ unableToReplaceCard: "Unable to replace card",
2883
+ defaultPaymentMethodUpdated: "Default payment method updated",
2884
+ unableToSetDefault: "Unable to set default payment method"
2885
+ };
3552
2886
  var PaymentMethodsSection = ({
3553
2887
  isAuthenticated = true,
3554
2888
  userEmail,
3555
2889
  provider = "mobius",
3556
2890
  defaultCountry = "US",
3557
2891
  collectPrefix = "account-card",
3558
- onNotify
2892
+ onNotify,
2893
+ translations: customTranslations
3559
2894
  }) => {
3560
- const paymentMethods = usePaymentMethodService();
2895
+ const { client } = usePaymentContext();
3561
2896
  const queryClient = useQueryClient();
2897
+ const paymentMethods = {
2898
+ list: (params) => client.listPaymentMethods({ limit: params.pageSize }),
2899
+ create: (payload) => client.createPaymentMethod(payload),
2900
+ update: (id, payload) => client.updatePaymentMethod(id, payload),
2901
+ remove: (id) => client.deletePaymentMethod(id),
2902
+ activate: (id) => client.activatePaymentMethod(id)
2903
+ };
3562
2904
  const [isModalOpen, setIsModalOpen] = useState(false);
3563
2905
  const [deletingId, setDeletingId] = useState(null);
2906
+ const [methodBeingReplaced, setMethodBeingReplaced] = useState(null);
3564
2907
  const notify = onNotify ?? notifyDefault3;
2908
+ const t = { ...defaultTranslations3, ...customTranslations };
3565
2909
  const queryKey = ["payments-ui", "payment-methods"];
3566
2910
  const paymentQuery = useQuery({
3567
2911
  queryKey,
@@ -3572,13 +2916,13 @@ var PaymentMethodsSection = ({
3572
2916
  const createMutation = useMutation({
3573
2917
  mutationFn: (payload) => paymentMethods.create(payload),
3574
2918
  onSuccess: () => {
3575
- notify({ title: "Card added successfully", status: "success" });
2919
+ notify({ title: t.cardAddedSuccess, status: "success" });
3576
2920
  setIsModalOpen(false);
3577
2921
  void queryClient.invalidateQueries({ queryKey });
3578
2922
  },
3579
2923
  onError: (error) => {
3580
2924
  notify({
3581
- title: "Unable to add card",
2925
+ title: t.unableToAddCard,
3582
2926
  description: error.message,
3583
2927
  status: "destructive"
3584
2928
  });
@@ -3588,18 +2932,47 @@ var PaymentMethodsSection = ({
3588
2932
  mutationFn: (id) => paymentMethods.remove(id),
3589
2933
  onMutate: (id) => setDeletingId(id),
3590
2934
  onSuccess: () => {
3591
- notify({ title: "Card removed", status: "success" });
2935
+ notify({ title: t.cardRemoved, status: "success" });
3592
2936
  void queryClient.invalidateQueries({ queryKey });
3593
2937
  },
3594
2938
  onError: (error) => {
3595
2939
  notify({
3596
- title: "Unable to remove card",
2940
+ title: t.unableToRemoveCard,
3597
2941
  description: error.message,
3598
2942
  status: "destructive"
3599
2943
  });
3600
2944
  },
3601
2945
  onSettled: () => setDeletingId(null)
3602
2946
  });
2947
+ const replaceMutation = useMutation({
2948
+ mutationFn: ({ id, payload }) => paymentMethods.update(id, payload),
2949
+ onSuccess: () => {
2950
+ notify({ title: t.cardUpdated, status: "success" });
2951
+ setMethodBeingReplaced(null);
2952
+ void queryClient.invalidateQueries({ queryKey });
2953
+ },
2954
+ onError: (error) => {
2955
+ notify({
2956
+ title: t.unableToReplaceCard,
2957
+ description: error.message,
2958
+ status: "destructive"
2959
+ });
2960
+ }
2961
+ });
2962
+ const activateMutation = useMutation({
2963
+ mutationFn: (id) => paymentMethods.activate(id),
2964
+ onSuccess: () => {
2965
+ notify({ title: t.defaultPaymentMethodUpdated, status: "success" });
2966
+ void queryClient.invalidateQueries({ queryKey });
2967
+ },
2968
+ onError: (error) => {
2969
+ notify({
2970
+ title: t.unableToSetDefault,
2971
+ description: error.message,
2972
+ status: "destructive"
2973
+ });
2974
+ }
2975
+ });
3603
2976
  useEffect(() => {
3604
2977
  if (!isModalOpen) {
3605
2978
  createMutation.reset();
@@ -3607,49 +2980,56 @@ var PaymentMethodsSection = ({
3607
2980
  }, [createMutation, isModalOpen]);
3608
2981
  const payments = useMemo(() => paymentQuery.data?.data ?? [], [paymentQuery.data]);
3609
2982
  const loading = paymentQuery.isLoading || paymentQuery.isFetching;
2983
+ const buildPayload = (token, billing) => ({
2984
+ payment_token: token,
2985
+ first_name: billing.firstName,
2986
+ last_name: billing.lastName,
2987
+ address1: billing.address1,
2988
+ address2: billing.address2,
2989
+ city: billing.city,
2990
+ state: billing.stateRegion,
2991
+ zip: billing.postalCode,
2992
+ country: billing.country,
2993
+ email: billing.email,
2994
+ provider: billing.provider
2995
+ });
3610
2996
  const handleCardTokenize = (token, billing) => {
3611
- const payload = {
3612
- payment_token: token,
3613
- first_name: billing.firstName,
3614
- last_name: billing.lastName,
3615
- address1: billing.address1,
3616
- address2: billing.address2,
3617
- city: billing.city,
3618
- state: billing.stateRegion,
3619
- zip: billing.postalCode,
3620
- country: billing.country,
3621
- email: billing.email,
3622
- provider: billing.provider
3623
- };
3624
- createMutation.mutate(payload);
2997
+ createMutation.mutate(buildPayload(token, billing));
3625
2998
  };
3626
- return /* @__PURE__ */ jsxs(Card, { className: "border-0 bg-background/5 shadow-lg", children: [
2999
+ const handleReplaceTokenize = (token, billing) => {
3000
+ if (!methodBeingReplaced) return;
3001
+ replaceMutation.mutate({ id: methodBeingReplaced.id, payload: buildPayload(token, billing) });
3002
+ };
3003
+ return /* @__PURE__ */ jsxs(Card, { children: [
3627
3004
  /* @__PURE__ */ jsxs(CardHeader, { className: "flex flex-col gap-4 md:flex-row md:items-center md:justify-between", children: [
3628
3005
  /* @__PURE__ */ jsxs("div", { children: [
3629
- /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2 text-xl", children: [
3630
- /* @__PURE__ */ jsx(WalletCards, { className: "h-5 w-5 text-primary" }),
3631
- " Payment Methods"
3006
+ /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2", children: [
3007
+ /* @__PURE__ */ jsx(WalletCards, { className: "h-5 w-5 text-emerald-400" }),
3008
+ " ",
3009
+ t.title
3632
3010
  ] }),
3633
- /* @__PURE__ */ jsx(CardDescription, { children: "Manage your saved billing cards" })
3011
+ /* @__PURE__ */ jsx(CardDescription, { children: t.description })
3634
3012
  ] }),
3635
3013
  /* @__PURE__ */ jsxs(Button, { onClick: () => setIsModalOpen(true), children: [
3636
3014
  /* @__PURE__ */ jsx(CreditCard, { className: "mr-2 h-4 w-4" }),
3637
- " Add card"
3015
+ " ",
3016
+ t.addCard
3638
3017
  ] })
3639
3018
  ] }),
3640
- /* @__PURE__ */ jsx(CardContent, { className: "space-y-4", children: loading ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center py-10 text-muted-foreground", children: [
3019
+ /* @__PURE__ */ jsx(CardContent, { className: "space-y-4", children: loading ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center py-10 text-white/60", children: [
3641
3020
  /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-5 w-5 animate-spin" }),
3642
- " Loading cards..."
3643
- ] }) : payments.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-dashed border-border/60 bg-muted/10 p-6 text-sm text-muted-foreground", children: "No saved payment methods yet." }) : /* @__PURE__ */ jsx("div", { className: "space-y-3", children: payments.map((method) => /* @__PURE__ */ jsxs(
3021
+ " ",
3022
+ t.loadingCards
3023
+ ] }) : payments.length === 0 ? /* @__PURE__ */ 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__ */ jsx("div", { className: "space-y-3", children: payments.map((method) => /* @__PURE__ */ jsxs(
3644
3024
  "div",
3645
3025
  {
3646
- className: "rounded-lg border border-border/80 bg-background/40 p-4 shadow-sm",
3026
+ className: "rounded-lg border border-white/10 bg-white/5 p-4 shadow-sm",
3647
3027
  children: [
3648
3028
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 md:flex-row md:items-center md:justify-between", children: [
3649
3029
  /* @__PURE__ */ jsxs("div", { children: [
3650
- /* @__PURE__ */ jsx("h4", { className: "text-base font-medium text-foreground", children: formatCardLabel2(method) }),
3651
- /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
3652
- "Added on",
3030
+ /* @__PURE__ */ jsx("h4", { className: "text-base font-medium text-white", children: formatCardLabel2(method) }),
3031
+ /* @__PURE__ */ jsxs("p", { className: "text-sm text-white/60", children: [
3032
+ t.addedOn,
3653
3033
  " ",
3654
3034
  method.created_at ? new Date(method.created_at).toLocaleDateString() : "unknown date"
3655
3035
  ] })
@@ -3659,34 +3039,60 @@ var PaymentMethodsSection = ({
3659
3039
  Badge,
3660
3040
  {
3661
3041
  variant: method.is_active ? "default" : "secondary",
3662
- className: method.is_active ? "bg-emerald-500/20 text-emerald-400" : "",
3663
- children: method.is_active ? "Active" : "Inactive"
3042
+ children: method.is_active ? t.active : t.inactive
3664
3043
  }
3665
3044
  ),
3666
3045
  method.failure_reason && /* @__PURE__ */ jsx(Badge, { variant: "destructive", children: method.failure_reason })
3667
3046
  ] })
3668
3047
  ] }),
3669
- /* @__PURE__ */ jsx("div", { className: "mt-3 flex flex-wrap gap-2", children: /* @__PURE__ */ jsxs(
3670
- Button,
3671
- {
3672
- variant: "ghost",
3673
- className: "text-destructive hover:text-destructive",
3674
- disabled: deletingId === method.id && deleteMutation.isPending,
3675
- onClick: () => deleteMutation.mutate(method.id),
3676
- children: [
3677
- deletingId === method.id && deleteMutation.isPending ? /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Trash2, { className: "mr-2 h-4 w-4" }),
3678
- "Remove"
3679
- ]
3680
- }
3681
- ) })
3048
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-wrap gap-2", children: [
3049
+ /* @__PURE__ */ jsxs(
3050
+ Button,
3051
+ {
3052
+ variant: "ghost",
3053
+ className: "text-blue-400",
3054
+ disabled: replaceMutation.isPending && methodBeingReplaced?.id === method.id,
3055
+ onClick: () => setMethodBeingReplaced(method),
3056
+ children: [
3057
+ replaceMutation.isPending && methodBeingReplaced?.id === method.id ? /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(CreditCard, { className: "mr-2 h-4 w-4" }),
3058
+ t.replaceCard
3059
+ ]
3060
+ }
3061
+ ),
3062
+ /* @__PURE__ */ jsxs(
3063
+ Button,
3064
+ {
3065
+ variant: "outline",
3066
+ disabled: method.is_active || activateMutation.isPending,
3067
+ onClick: () => activateMutation.mutate(method.id),
3068
+ children: [
3069
+ activateMutation.isPending ? /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : null,
3070
+ method.is_active ? t.defaultMethod : t.makeDefault
3071
+ ]
3072
+ }
3073
+ ),
3074
+ /* @__PURE__ */ jsxs(
3075
+ Button,
3076
+ {
3077
+ variant: "ghost",
3078
+ className: "text-red-400 hover:text-red-300",
3079
+ disabled: deletingId === method.id && deleteMutation.isPending,
3080
+ onClick: () => deleteMutation.mutate(method.id),
3081
+ children: [
3082
+ deletingId === method.id && deleteMutation.isPending ? /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Trash2, { className: "mr-2 h-4 w-4" }),
3083
+ t.remove
3084
+ ]
3085
+ }
3086
+ )
3087
+ ] })
3682
3088
  ]
3683
3089
  },
3684
3090
  method.id
3685
3091
  )) }) }),
3686
- /* @__PURE__ */ jsx(Dialog, { open: isModalOpen, onOpenChange: setIsModalOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-h-[95vh] overflow-y-auto border border-border bg-background", children: [
3092
+ /* @__PURE__ */ jsx(Dialog, { open: isModalOpen, onOpenChange: setIsModalOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-h-[95vh] overflow-y-auto", children: [
3687
3093
  /* @__PURE__ */ jsxs(DialogHeader, { children: [
3688
- /* @__PURE__ */ jsx(DialogTitle, { children: "Add a new card" }),
3689
- /* @__PURE__ */ jsx(DialogDescription, { children: "Your card details are tokenized securely via our payment provider." })
3094
+ /* @__PURE__ */ jsx(DialogTitle, { children: t.addNewCard }),
3095
+ /* @__PURE__ */ jsx(DialogDescription, { children: t.addNewCardDescription })
3690
3096
  ] }),
3691
3097
  /* @__PURE__ */ jsx(
3692
3098
  CardDetailsForm,
@@ -3694,7 +3100,7 @@ var PaymentMethodsSection = ({
3694
3100
  visible: isModalOpen,
3695
3101
  collectPrefix,
3696
3102
  submitting: createMutation.isPending,
3697
- submitLabel: "Save card",
3103
+ submitLabel: t.saveCard,
3698
3104
  defaultValues: {
3699
3105
  email: userEmail ?? "",
3700
3106
  country: defaultCountry,
@@ -3702,640 +3108,36 @@ var PaymentMethodsSection = ({
3702
3108
  },
3703
3109
  externalError: createMutation.error?.message ?? null,
3704
3110
  onTokenize: handleCardTokenize,
3705
- className: "rounded-2xl border border-border bg-muted/20 p-6"
3111
+ className: "rounded-2xl border border-white/10 bg-white/5 p-6"
3706
3112
  }
3707
3113
  )
3708
- ] }) })
3709
- ] });
3710
- };
3711
- var useWalletList = (options = {}) => {
3712
- const { services } = usePaymentContext();
3713
- const [state, setState] = useState({
3714
- wallets: [],
3715
- isLoading: false,
3716
- error: null
3717
- });
3718
- const fetchWallets = useCallback(async () => {
3719
- setState((prev) => ({ ...prev, isLoading: true, error: null }));
3720
- try {
3721
- const wallets2 = await services.solanaWallets.list();
3722
- setState({ wallets: wallets2, isLoading: false, error: null });
3723
- return wallets2;
3724
- } catch (error) {
3725
- const message = error instanceof Error ? error.message : "Failed to load wallets";
3726
- console.error("payments-ui: wallet list fetch failed", error);
3727
- setState((prev) => ({ ...prev, isLoading: false, error: message }));
3728
- throw error;
3729
- }
3730
- }, [services.solanaWallets]);
3731
- const deleteWallet = useCallback(
3732
- async (walletIdOrAddress) => {
3733
- setState((prev) => ({ ...prev, isLoading: true, error: null }));
3734
- try {
3735
- await services.solanaWallets.remove(walletIdOrAddress);
3736
- setState((prev) => ({
3737
- ...prev,
3738
- wallets: prev.wallets.filter(
3739
- (wallet) => wallet.id !== walletIdOrAddress && wallet.address !== walletIdOrAddress
3740
- ),
3741
- isLoading: false
3742
- }));
3743
- } catch (error) {
3744
- const message = error instanceof Error ? error.message : "Failed to remove wallet";
3745
- console.error("payments-ui: wallet removal failed", error);
3746
- setState((prev) => ({ ...prev, isLoading: false, error: message }));
3747
- throw error;
3748
- }
3749
- },
3750
- [services.solanaWallets]
3751
- );
3752
- const addWallet = useCallback((wallet) => {
3753
- setState((prev) => ({ ...prev, wallets: [...prev.wallets, wallet] }));
3754
- }, []);
3755
- const updateWallet = useCallback((walletId, updates) => {
3756
- setState((prev) => ({
3757
- ...prev,
3758
- wallets: prev.wallets.map(
3759
- (wallet) => wallet.id === walletId ? { ...wallet, ...updates } : wallet
3760
- )
3761
- }));
3762
- }, []);
3763
- const clearError = useCallback(() => {
3764
- setState((prev) => ({ ...prev, error: null }));
3765
- }, []);
3766
- const findWalletByAddress = useCallback(
3767
- (address) => state.wallets.find((wallet) => wallet.address === address),
3768
- [state.wallets]
3769
- );
3770
- const getVerifiedWallets = useCallback(
3771
- () => state.wallets.filter((wallet) => wallet.is_verified),
3772
- [state.wallets]
3773
- );
3774
- useEffect(() => {
3775
- if (options.autoFetch !== false) {
3776
- fetchWallets().catch(() => {
3777
- });
3778
- }
3779
- }, [fetchWallets, options.autoFetch]);
3780
- return {
3781
- wallets: state.wallets,
3782
- isLoading: state.isLoading,
3783
- error: state.error,
3784
- fetchWallets,
3785
- deleteWallet,
3786
- addWallet,
3787
- updateWallet,
3788
- clearError,
3789
- findWalletByAddress,
3790
- getVerifiedWallets,
3791
- hasVerifiedWallets: state.wallets.some((w) => w.is_verified),
3792
- totalWallets: state.wallets.length
3793
- };
3794
- };
3795
- var useWalletVerification = () => {
3796
- const { services } = usePaymentContext();
3797
- const { publicKey, signMessage } = useWallet();
3798
- const [state, setState] = useState({
3799
- isVerifying: false,
3800
- isVerified: false,
3801
- error: null
3802
- });
3803
- const signAndVerifyWallet = useCallback(
3804
- async (walletAddress, message, nonce) => {
3805
- if (!publicKey || !signMessage) {
3806
- throw new Error("Wallet not connected or signing unavailable");
3807
- }
3808
- if (publicKey.toBase58() !== walletAddress) {
3809
- throw new Error("Connected wallet does not match target wallet");
3810
- }
3811
- setState((prev) => ({ ...prev, isVerifying: true, error: null }));
3812
- try {
3813
- const encodedMessage = new TextEncoder().encode(message);
3814
- const signature = await signMessage(encodedMessage);
3815
- const signatureBase58 = bs58.encode(signature);
3816
- const response = await services.solanaWallets.verify(
3817
- walletAddress,
3818
- signatureBase58,
3819
- nonce
3820
- );
3821
- setState({ isVerifying: false, isVerified: response.verified, error: null });
3822
- return response;
3823
- } catch (error) {
3824
- const message2 = error instanceof Error ? error.message : "Wallet verification failed";
3825
- console.error("payments-ui: wallet verification failed", error);
3826
- setState({ isVerifying: false, isVerified: false, error: message2 });
3827
- throw error;
3828
- }
3829
- },
3830
- [publicKey, signMessage, services.solanaWallets]
3831
- );
3832
- const clearError = useCallback(() => {
3833
- setState((prev) => ({ ...prev, error: null }));
3834
- }, []);
3835
- const resetVerification = useCallback(() => {
3836
- setState({ isVerifying: false, isVerified: false, error: null });
3837
- }, []);
3838
- const autoVerifyWallet = useCallback(
3839
- async (walletAddress, message, nonce) => {
3840
- try {
3841
- return await signAndVerifyWallet(walletAddress, message, nonce);
3842
- } catch (error) {
3843
- console.warn("payments-ui: auto-verification skipped", error);
3844
- return null;
3845
- }
3846
- },
3847
- [signAndVerifyWallet]
3848
- );
3849
- return {
3850
- ...state,
3851
- signAndVerifyWallet,
3852
- autoVerifyWallet,
3853
- clearError,
3854
- resetVerification
3855
- };
3856
- };
3857
- var useWalletConnection = () => {
3858
- const { services } = usePaymentContext();
3859
- const { publicKey, connected, connecting, disconnect, wallet } = useWallet();
3860
- const [state, setState] = useState({
3861
- isConnected: false,
3862
- isConnecting: false,
3863
- publicKey: null,
3864
- wallets: [],
3865
- isLoading: false,
3866
- error: null
3867
- });
3868
- useEffect(() => {
3869
- setState((prev) => ({
3870
- ...prev,
3871
- isConnected: connected,
3872
- isConnecting: connecting,
3873
- publicKey: publicKey?.toBase58() ?? null
3874
- }));
3875
- }, [connected, connecting, publicKey]);
3876
- const connectWalletToBackend = useCallback(
3877
- async (address) => {
3878
- if (!address) {
3879
- throw new Error("Wallet address is required");
3880
- }
3881
- setState((prev) => ({ ...prev, isLoading: true, error: null }));
3882
- try {
3883
- const challenge = await services.solanaWallets.requestChallenge(address);
3884
- setState((prev) => ({ ...prev, isLoading: false }));
3885
- return challenge;
3886
- } catch (error) {
3887
- const message = error instanceof Error ? error.message : "Wallet challenge failed";
3888
- console.error("payments-ui: wallet challenge failed", error);
3889
- setState((prev) => ({ ...prev, isLoading: false, error: message }));
3890
- throw error;
3891
- }
3892
- },
3893
- [services.solanaWallets]
3894
- );
3895
- const connectWallet = useCallback(async () => {
3896
- if (!wallet) {
3897
- throw new Error("No wallet adapter selected");
3898
- }
3899
- setState((prev) => ({ ...prev, isConnecting: true, error: null }));
3900
- try {
3901
- await wallet.adapter.connect();
3902
- if (publicKey) {
3903
- await connectWalletToBackend(publicKey.toBase58());
3904
- }
3905
- } catch (error) {
3906
- const message = error instanceof Error ? error.message : "Failed to connect wallet";
3907
- console.error("payments-ui: wallet connection failed", error);
3908
- setState((prev) => ({ ...prev, isConnecting: false, error: message }));
3909
- throw error;
3910
- } finally {
3911
- setState((prev) => ({ ...prev, isConnecting: false }));
3912
- }
3913
- }, [wallet, publicKey, connectWalletToBackend]);
3914
- const disconnectWallet = useCallback(async () => {
3915
- try {
3916
- await disconnect();
3917
- setState((prev) => ({
3918
- ...prev,
3919
- isConnected: false,
3920
- publicKey: null,
3921
- wallets: [],
3922
- error: null
3923
- }));
3924
- } catch (error) {
3925
- const message = error instanceof Error ? error.message : "Failed to disconnect wallet";
3926
- console.error("payments-ui: wallet disconnect failed", error);
3927
- setState((prev) => ({ ...prev, error: message }));
3928
- throw error;
3929
- }
3930
- }, [disconnect]);
3931
- const clearError = useCallback(() => {
3932
- setState((prev) => ({ ...prev, error: null }));
3933
- }, []);
3934
- return {
3935
- ...state,
3936
- walletName: wallet?.adapter.name,
3937
- walletIcon: wallet?.adapter.icon,
3938
- connectWallet,
3939
- disconnectWallet,
3940
- connectWalletToBackend,
3941
- clearError
3942
- };
3943
- };
3944
- var notifyDefault4 = (payload) => {
3945
- console.log("[payments-ui] wallet-card", payload);
3946
- };
3947
- var WalletCard = ({
3948
- wallet,
3949
- isPrimary = false,
3950
- isConnected = false,
3951
- balance,
3952
- onSetPrimary,
3953
- onVerify,
3954
- onDelete,
3955
- isVerifying = false,
3956
- isDeleting = false,
3957
- notify = notifyDefault4
3958
- }) => {
3959
- const [isCopying, setIsCopying] = useState(false);
3960
- const formatAddress = (address) => address.length <= 12 ? address : `${address.slice(0, 4)}...${address.slice(-4)}`;
3961
- const copyToClipboard = async (text) => {
3962
- setIsCopying(true);
3963
- try {
3964
- await navigator.clipboard.writeText(text);
3965
- notify({ title: "Copied", description: "Wallet address copied to clipboard" });
3966
- } catch (error) {
3967
- notify({ title: "Failed to copy", description: error.message, status: "destructive" });
3968
- } finally {
3969
- setTimeout(() => setIsCopying(false), 500);
3970
- }
3971
- };
3972
- const openExplorer = () => {
3973
- window.open(`https://solscan.io/account/${wallet.address}`, "_blank", "noopener,noreferrer");
3974
- };
3975
- return /* @__PURE__ */ jsxs(
3976
- "div",
3977
- {
3978
- className: cn(
3979
- "rounded-lg border bg-background/40 p-4 transition-shadow",
3980
- isPrimary && "border-primary/50 shadow-lg",
3981
- isConnected && "ring-1 ring-primary"
3982
- ),
3983
- children: [
3984
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
3985
- /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
3986
- /* @__PURE__ */ jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-primary/20", children: /* @__PURE__ */ jsx("div", { className: "h-5 w-5 rounded-full bg-gradient-to-br from-primary to-primary/60" }) }),
3987
- /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
3988
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
3989
- /* @__PURE__ */ jsx("span", { className: "font-mono text-sm font-medium", children: formatAddress(wallet.address) }),
3990
- isPrimary && /* @__PURE__ */ 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: [
3991
- /* @__PURE__ */ jsx(Star, { className: "h-3 w-3 fill-yellow-500 text-yellow-500" }),
3992
- " Primary"
3993
- ] }),
3994
- wallet.is_verified ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-emerald-400", children: [
3995
- /* @__PURE__ */ jsx(CheckCircle, { className: "h-3.5 w-3.5" }),
3996
- " Verified"
3997
- ] }) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-amber-400", children: [
3998
- /* @__PURE__ */ jsx(AlertCircle, { className: "h-3.5 w-3.5" }),
3999
- " Unverified"
4000
- ] }),
4001
- isConnected && /* @__PURE__ */ jsx("span", { className: "rounded bg-blue-500/20 px-2 py-0.5 text-xs text-blue-400", children: "Connected" })
4002
- ] }),
4003
- balance !== null && typeof balance !== "undefined" && /* @__PURE__ */ jsxs("p", { className: "mt-1 text-sm text-muted-foreground", children: [
4004
- "Balance: ",
4005
- balance.toFixed(4),
4006
- " SOL"
4007
- ] }),
4008
- /* @__PURE__ */ jsxs("p", { className: "mt-0.5 text-xs text-muted-foreground", children: [
4009
- "Added ",
4010
- new Date(wallet.created_at).toLocaleDateString()
4011
- ] })
4012
- ] })
4013
- ] }) }),
4014
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
4015
- /* @__PURE__ */ jsx(
4016
- Button,
4017
- {
4018
- variant: "ghost",
4019
- size: "icon",
4020
- className: "h-8 w-8",
4021
- onClick: () => copyToClipboard(wallet.address),
4022
- disabled: isCopying,
4023
- children: isCopying ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Copy, { className: "h-4 w-4" })
4024
- }
4025
- ),
4026
- /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", className: "h-8 w-8", onClick: openExplorer, children: /* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4" }) })
4027
- ] })
4028
- ] }),
4029
- /* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [
4030
- !isPrimary && onSetPrimary && wallet.is_verified && /* @__PURE__ */ jsxs(
4031
- Button,
4032
- {
4033
- variant: "outline",
4034
- size: "sm",
4035
- className: "border-primary/40 text-primary",
4036
- onClick: () => onSetPrimary(wallet.id),
4037
- children: [
4038
- /* @__PURE__ */ jsx(Star, { className: "mr-1 h-3 w-3" }),
4039
- " Set Primary"
4040
- ]
4041
- }
4042
- ),
4043
- !wallet.is_verified && onVerify && isConnected && /* @__PURE__ */ jsx(
4044
- Button,
4045
- {
4046
- variant: "outline",
4047
- size: "sm",
4048
- className: "border-emerald-500/40 text-emerald-400",
4049
- onClick: () => onVerify(wallet),
4050
- disabled: isVerifying,
4051
- children: isVerifying ? /* @__PURE__ */ jsxs(Fragment, { children: [
4052
- /* @__PURE__ */ jsx(Loader2, { className: "mr-1 h-3 w-3 animate-spin" }),
4053
- " Verifying..."
4054
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4055
- /* @__PURE__ */ jsx(Shield, { className: "mr-1 h-3 w-3" }),
4056
- " Verify"
4057
- ] })
4058
- }
4059
- ),
4060
- onDelete && /* @__PURE__ */ jsx(
4061
- Button,
4062
- {
4063
- variant: "outline",
4064
- size: "sm",
4065
- className: "ml-auto border-destructive/40 text-destructive",
4066
- onClick: () => onDelete(wallet.id),
4067
- disabled: isDeleting,
4068
- children: isDeleting ? /* @__PURE__ */ jsx(Loader2, { className: "h-3 w-3 animate-spin" }) : /* @__PURE__ */ jsx(Trash2, { className: "h-3 w-3" })
4069
- }
4070
- )
4071
- ] })
4072
- ]
4073
- }
4074
- );
4075
- };
4076
- var EmptyWalletState = () => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [
4077
- /* @__PURE__ */ jsx(Wallet, { className: "mb-4 h-12 w-12 text-muted-foreground" }),
4078
- /* @__PURE__ */ jsx("h3", { className: "mb-2 text-lg font-medium", children: "No wallets connected" }),
4079
- /* @__PURE__ */ jsx("p", { className: "mb-6 text-sm text-muted-foreground", children: "Connect your Solana wallet to get started" }),
4080
- /* @__PURE__ */ jsx(WalletMultiButton, { className: "!bg-primary text-primary-foreground hover:!bg-primary/90" })
4081
- ] });
4082
- var notifyDefault5 = (payload) => {
4083
- console.log("[payments-ui] solana-wallets", payload);
4084
- };
4085
- var SolanaWalletSection = ({
4086
- onNotify,
4087
- rpcUrl
4088
- }) => {
4089
- const notify = onNotify ?? notifyDefault5;
4090
- const { config } = usePaymentContext();
4091
- const { connected, publicKey, disconnect } = useWallet();
4092
- const { wallets: wallets2, isLoading, deleteWallet, fetchWallets } = useWalletList();
4093
- const { signAndVerifyWallet } = useWalletVerification();
4094
- const walletConnection = useWalletConnection();
4095
- const [primaryWalletId, setPrimaryWalletId] = useState(null);
4096
- const [showOtherWallets, setShowOtherWallets] = useState(false);
4097
- const [balances, setBalances] = useState({});
4098
- const [verifyingWalletId, setVerifyingWalletId] = useState(null);
4099
- const [deletingWalletId, setDeletingWalletId] = useState(null);
4100
- const [walletToDelete, setWalletToDelete] = useState(null);
4101
- const [isRegistering, setIsRegistering] = useState(false);
4102
- const rpcEndpoint = rpcUrl || config.solanaRpcUrl || "https://api.mainnet-beta.solana.com";
4103
- const connection = useMemo(() => new Connection(rpcEndpoint), [rpcEndpoint]);
4104
- const primaryWallet = wallets2.find((w) => w.id === primaryWalletId) ?? wallets2.find((w) => w.is_verified) ?? null;
4105
- const otherWallets = wallets2.filter((w) => w.id !== primaryWallet?.id);
4106
- const fetchBalance = useCallback(
4107
- async (address) => {
4108
- try {
4109
- const pubkey = new PublicKey(address);
4110
- const balance = await connection.getBalance(pubkey);
4111
- return balance / LAMPORTS_PER_SOL;
4112
- } catch (error) {
4113
- console.error("payments-ui: failed to fetch balance", error);
4114
- return null;
4115
- }
4116
- },
4117
- [connection]
4118
- );
4119
- const fetchAllBalances = useCallback(async () => {
4120
- const results = await Promise.all(
4121
- wallets2.map(async (wallet) => ({ address: wallet.address, balance: await fetchBalance(wallet.address) }))
4122
- );
4123
- const next = {};
4124
- results.forEach(({ address, balance }) => {
4125
- if (balance !== null && typeof balance !== "undefined") {
4126
- next[address] = balance;
4127
- }
4128
- });
4129
- setBalances(next);
4130
- }, [wallets2, fetchBalance]);
4131
- useEffect(() => {
4132
- if (wallets2.length > 0) {
4133
- fetchAllBalances().catch(() => void 0);
4134
- }
4135
- }, [wallets2, fetchAllBalances]);
4136
- useEffect(() => {
4137
- const verifiedWallet = wallets2.find((w) => w.is_verified);
4138
- if (verifiedWallet && !primaryWalletId) {
4139
- setPrimaryWalletId(verifiedWallet.id);
4140
- }
4141
- }, [wallets2, primaryWalletId]);
4142
- const registerWallet = useCallback(async () => {
4143
- if (!connected || !publicKey || isRegistering) return;
4144
- setIsRegistering(true);
4145
- try {
4146
- const challenge = await walletConnection.connectWalletToBackend(publicKey.toBase58());
4147
- if (!challenge?.message) {
4148
- throw new Error("Failed to retrieve wallet verification challenge");
4149
- }
4150
- await signAndVerifyWallet(challenge.wallet, challenge.message, challenge.nonce);
4151
- await fetchWallets();
4152
- notify({
4153
- title: "Wallet verified",
4154
- description: "Your wallet has been linked successfully.",
4155
- status: "success"
4156
- });
4157
- } catch (error) {
4158
- notify({
4159
- title: "Wallet verification failed",
4160
- description: error instanceof Error ? error.message : "Failed to verify wallet",
4161
- status: "destructive"
4162
- });
4163
- } finally {
4164
- setIsRegistering(false);
4165
- }
4166
- }, [connected, publicKey, isRegistering, walletConnection, signAndVerifyWallet, fetchWallets, notify]);
4167
- useEffect(() => {
4168
- if (connected && publicKey && !walletConnection.isConnecting && wallets2.length === 0) {
4169
- registerWallet().catch(() => void 0);
4170
- }
4171
- }, [connected, publicKey, walletConnection.isConnecting, wallets2.length, registerWallet]);
4172
- const handleVerifyWallet = useCallback(
4173
- async (wallet) => {
4174
- if (!connected || publicKey?.toBase58() !== wallet.address) {
4175
- notify({
4176
- title: "Connect wallet first",
4177
- description: "Please connect the wallet you want to verify.",
4178
- status: "destructive"
4179
- });
4180
- return;
4181
- }
4182
- setVerifyingWalletId(wallet.id);
4183
- try {
4184
- const challenge = await walletConnection.connectWalletToBackend(wallet.address);
4185
- if (!challenge?.message) {
4186
- throw new Error("Failed to retrieve verification challenge");
4187
- }
4188
- await signAndVerifyWallet(challenge.wallet, challenge.message, challenge.nonce);
4189
- await fetchWallets();
4190
- notify({ title: "Wallet verified", status: "success" });
4191
- } catch (error) {
4192
- notify({
4193
- title: "Verification failed",
4194
- description: error instanceof Error ? error.message : "Failed to verify wallet",
4195
- status: "destructive"
4196
- });
4197
- } finally {
4198
- setVerifyingWalletId(null);
4199
- }
4200
- },
4201
- [connected, publicKey, walletConnection, signAndVerifyWallet, fetchWallets, notify]
4202
- );
4203
- const handleDeleteWallet = useCallback(
4204
- async (walletId) => {
4205
- setDeletingWalletId(walletId);
4206
- try {
4207
- await deleteWallet(walletId);
4208
- if (primaryWalletId === walletId) {
4209
- setPrimaryWalletId(null);
4210
- }
4211
- if (connected && publicKey) {
4212
- const deletedWallet = wallets2.find((w) => w.id === walletId);
4213
- if (deletedWallet?.address === publicKey.toBase58()) {
4214
- await disconnect();
4215
- }
4216
- }
4217
- notify({ title: "Wallet removed", status: "success" });
4218
- } catch (error) {
4219
- notify({
4220
- title: "Failed to remove wallet",
4221
- description: error instanceof Error ? error.message : "Please try again",
4222
- status: "destructive"
4223
- });
4224
- } finally {
4225
- setDeletingWalletId(null);
4226
- setWalletToDelete(null);
4227
- }
4228
- },
4229
- [deleteWallet, primaryWalletId, connected, publicKey, wallets2, disconnect, notify]
4230
- );
4231
- const handleSetPrimary = (walletId) => {
4232
- setPrimaryWalletId(walletId);
4233
- notify({ title: "Primary wallet updated", status: "success" });
4234
- };
4235
- const isWalletRegistered = connected && publicKey && wallets2.some((w) => w.address === publicKey.toBase58());
4236
- if (isLoading && wallets2.length === 0) {
4237
- return /* @__PURE__ */ jsxs(Card, { className: "border-0 bg-background/5", children: [
4238
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { className: "text-xl", children: "Solana Wallets" }) }),
4239
- /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center py-8", children: [
4240
- /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-6 w-6 animate-spin text-muted-foreground" }),
4241
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Loading wallets..." })
4242
- ] }) })
4243
- ] });
4244
- }
4245
- return /* @__PURE__ */ jsxs(Fragment, { children: [
4246
- /* @__PURE__ */ jsxs(Card, { className: "border-0 bg-background/5", children: [
4247
- /* @__PURE__ */ jsxs(CardHeader, { children: [
4248
- /* @__PURE__ */ jsx(CardTitle, { className: "text-xl", children: "Solana Wallets" }),
4249
- /* @__PURE__ */ jsx(CardDescription, { children: "Connect and manage your Solana wallets for payments" })
4250
- ] }),
4251
- /* @__PURE__ */ jsx(CardContent, { className: "space-y-4", children: wallets2.length === 0 && !connected ? /* @__PURE__ */ jsx(EmptyWalletState, {}) : /* @__PURE__ */ jsxs(Fragment, { children: [
4252
- primaryWallet && /* @__PURE__ */ jsxs("div", { children: [
4253
- /* @__PURE__ */ jsx("h3", { className: "mb-3 text-sm font-medium uppercase tracking-wide text-muted-foreground", children: "Primary Wallet" }),
4254
- /* @__PURE__ */ jsx(
4255
- WalletCard,
4256
- {
4257
- wallet: primaryWallet,
4258
- isPrimary: true,
4259
- isConnected: connected && publicKey?.toBase58() === primaryWallet.address,
4260
- balance: balances[primaryWallet.address],
4261
- onVerify: handleVerifyWallet,
4262
- onDelete: (id) => {
4263
- const target = wallets2.find((w) => w.id === id);
4264
- if (target) setWalletToDelete(target);
4265
- },
4266
- isVerifying: verifyingWalletId === primaryWallet.id,
4267
- isDeleting: deletingWalletId === primaryWallet.id,
4268
- notify
4269
- }
4270
- )
4271
- ] }),
4272
- otherWallets.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
4273
- /* @__PURE__ */ jsxs(
4274
- "button",
4275
- {
4276
- className: "mb-3 flex w-full items-center justify-between text-left",
4277
- onClick: () => setShowOtherWallets((prev) => !prev),
4278
- children: [
4279
- /* @__PURE__ */ jsxs("h3", { className: "text-sm font-medium uppercase tracking-wide text-muted-foreground", children: [
4280
- "Other Wallets (",
4281
- otherWallets.length,
4282
- ")"
4283
- ] }),
4284
- showOtherWallets ? /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4 text-muted-foreground" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 text-muted-foreground" })
4285
- ]
4286
- }
4287
- ),
4288
- showOtherWallets && /* @__PURE__ */ jsx("div", { className: "space-y-2", children: otherWallets.map((wallet) => /* @__PURE__ */ jsx(
4289
- WalletCard,
4290
- {
4291
- wallet,
4292
- isConnected: connected && publicKey?.toBase58() === wallet.address,
4293
- balance: balances[wallet.address],
4294
- onSetPrimary: handleSetPrimary,
4295
- onVerify: handleVerifyWallet,
4296
- onDelete: (id) => {
4297
- const target = wallets2.find((w) => w.id === id);
4298
- if (target) setWalletToDelete(target);
4299
- },
4300
- isVerifying: verifyingWalletId === wallet.id,
4301
- isDeleting: deletingWalletId === wallet.id,
4302
- notify
4303
- },
4304
- wallet.id
4305
- )) })
4306
- ] }),
4307
- /* @__PURE__ */ jsx("div", { className: "pt-4", children: connected && publicKey ? isWalletRegistered ? /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
4308
- /* @__PURE__ */ 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: [
4309
- /* @__PURE__ */ jsx(CheckCircle, { className: "h-4 w-4" }),
4310
- " Connected wallet is verified and linked to your account."
4311
- ] }),
4312
- /* @__PURE__ */ jsx(WalletMultiButton, { className: "w-full !bg-primary text-primary-foreground" })
4313
- ] }) : /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
4314
- /* @__PURE__ */ 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." }),
4315
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
4316
- /* @__PURE__ */ jsx(Button, { onClick: registerWallet, disabled: isRegistering || walletConnection.isConnecting, className: "flex-1 bg-primary text-primary-foreground", children: isRegistering ? /* @__PURE__ */ jsxs(Fragment, { children: [
4317
- /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
4318
- " Registering..."
4319
- ] }) : "Register This Wallet" }),
4320
- /* @__PURE__ */ jsx(Button, { onClick: () => disconnect(), variant: "outline", className: "border-border", children: "Disconnect" })
4321
- ] })
4322
- ] }) : /* @__PURE__ */ jsx(WalletMultiButton, { className: "w-full !bg-primary text-primary-foreground" }) })
4323
- ] }) })
4324
- ] }),
4325
- /* @__PURE__ */ jsx(AlertDialog, { open: !!walletToDelete, onOpenChange: () => setWalletToDelete(null), children: /* @__PURE__ */ jsxs(AlertDialogContent, { children: [
4326
- /* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
4327
- /* @__PURE__ */ jsx(AlertDialogTitle, { children: "Remove Wallet" }),
4328
- /* @__PURE__ */ jsx(AlertDialogDescription, { children: "Are you sure you want to remove this wallet from your account? This action cannot be undone." })
3114
+ ] }) }),
3115
+ /* @__PURE__ */ jsx(Dialog, { open: Boolean(methodBeingReplaced), onOpenChange: (open) => !open && setMethodBeingReplaced(null), children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-h-[95vh] overflow-y-auto", children: [
3116
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
3117
+ /* @__PURE__ */ jsx(DialogTitle, { children: t.replaceCardTitle }),
3118
+ /* @__PURE__ */ jsx(DialogDescription, { children: t.replaceCardDescription })
4329
3119
  ] }),
4330
- /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [
4331
- /* @__PURE__ */ jsx(AlertDialogCancel, { children: "Cancel" }),
4332
- /* @__PURE__ */ jsx(AlertDialogAction, { onClick: () => walletToDelete && handleDeleteWallet(walletToDelete.id), className: "bg-destructive text-destructive-foreground", children: "Remove" })
4333
- ] })
3120
+ methodBeingReplaced && /* @__PURE__ */ jsx(
3121
+ CardDetailsForm,
3122
+ {
3123
+ visible: true,
3124
+ collectPrefix: `${collectPrefix}-replace-${methodBeingReplaced.id}`,
3125
+ submitting: replaceMutation.isPending,
3126
+ submitLabel: t.replaceCard,
3127
+ defaultValues: {
3128
+ email: userEmail ?? "",
3129
+ country: defaultCountry,
3130
+ provider
3131
+ },
3132
+ externalError: replaceMutation.error?.message ?? null,
3133
+ onTokenize: handleReplaceTokenize,
3134
+ className: "rounded-2xl border border-white/10 bg-white/5 p-6"
3135
+ }
3136
+ )
4334
3137
  ] }) })
4335
3138
  ] });
4336
3139
  };
4337
- var WalletManagement = (props) => /* @__PURE__ */ jsx(SolanaWalletSection, { ...props });
4338
- var Checkbox = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3140
+ var Checkbox = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
4339
3141
  CheckboxPrimitive.Root,
4340
3142
  {
4341
3143
  ref,
@@ -4532,7 +3334,7 @@ var useTokenBalance = (tokens) => {
4532
3334
  },
4533
3335
  [balances]
4534
3336
  );
4535
- const hasSufficientBalance2 = useCallback(
3337
+ const hasSufficientBalance = useCallback(
4536
3338
  (tokenSymbol, requiredAmount) => {
4537
3339
  const balance = getTokenBalance(tokenSymbol);
4538
3340
  return balance ? balance.uiAmount >= requiredAmount : false;
@@ -4593,106 +3395,16 @@ var useTokenBalance = (tokens) => {
4593
3395
  error,
4594
3396
  refreshBalances,
4595
3397
  getTokenBalance,
4596
- hasSufficientBalance: hasSufficientBalance2,
3398
+ hasSufficientBalance,
4597
3399
  getFormattedBalance,
4598
3400
  getTotalValue,
4599
3401
  hasAnyBalance: positiveBalances.length > 0,
4600
3402
  isConnected: !!publicKey
4601
3403
  };
4602
3404
  };
4603
- var useDirectWalletPayment = () => {
4604
- const { publicKey, signTransaction, connected } = useWallet();
4605
- const solanaService = useSolanaService();
4606
- const [paymentState, setPaymentState] = useState({
4607
- loading: false,
4608
- error: null,
4609
- success: false,
4610
- transactionId: null
4611
- });
4612
- const resetPayment = useCallback(() => {
4613
- setPaymentState({
4614
- loading: false,
4615
- error: null,
4616
- success: false,
4617
- transactionId: null
4618
- });
4619
- }, []);
4620
- const payWithWallet = useCallback(
4621
- async (token, priceId) => {
4622
- if (!connected || !publicKey || !signTransaction) {
4623
- setPaymentState((prev) => ({
4624
- ...prev,
4625
- error: "Wallet not connected. Please connect your wallet first."
4626
- }));
4627
- return;
4628
- }
4629
- setPaymentState({
4630
- loading: true,
4631
- error: null,
4632
- success: false,
4633
- transactionId: null
4634
- });
4635
- try {
4636
- console.log("Generating payment transaction...", {
4637
- token: token.symbol,
4638
- priceId
4639
- });
4640
- const paymentData = await solanaService.generatePayment(
4641
- priceId,
4642
- token.symbol,
4643
- publicKey.toBase58()
4644
- );
4645
- const transactionBuffer = Buffer.from(paymentData.transaction, "base64");
4646
- const transaction = Transaction.from(transactionBuffer);
4647
- console.log("Requesting wallet signature...");
4648
- const signedTransaction = await signTransaction(transaction);
4649
- const signedTransactionBase64 = signedTransaction.serialize().toString("base64");
4650
- console.log("Submitting signed transaction...");
4651
- const submitResult = await solanaService.submitPayment(
4652
- signedTransactionBase64,
4653
- priceId,
4654
- paymentData.intent_id
4655
- );
4656
- setPaymentState({
4657
- loading: false,
4658
- error: null,
4659
- success: true,
4660
- transactionId: submitResult.transaction_id
4661
- });
4662
- console.log("Payment successful!", submitResult);
4663
- } catch (err) {
4664
- console.error("Payment failed:", err);
4665
- let errorMessage = "Payment failed. Please try again.";
4666
- const message = err instanceof Error ? err.message : typeof err === "string" ? err : "";
4667
- if (message.includes("User rejected")) {
4668
- errorMessage = "Payment cancelled by user.";
4669
- } else if (/insufficient\s+funds/i.test(message)) {
4670
- errorMessage = `Insufficient ${token.symbol} balance.`;
4671
- } else if (/network/i.test(message)) {
4672
- errorMessage = "Network error. Please check your connection.";
4673
- } else if (message) {
4674
- errorMessage = message;
4675
- }
4676
- setPaymentState({
4677
- loading: false,
4678
- error: errorMessage,
4679
- success: false,
4680
- transactionId: null
4681
- });
4682
- }
4683
- },
4684
- [connected, publicKey, signTransaction, solanaService]
4685
- );
4686
- return {
4687
- paymentState,
4688
- payWithWallet,
4689
- resetPayment
4690
- };
4691
- };
4692
3405
  var usePaymentStatus = (options = {}) => {
4693
3406
  const { connection } = useConnection();
4694
- const { services } = usePaymentContext();
4695
- const billingApi = services.billingApi;
3407
+ const { client } = usePaymentContext();
4696
3408
  const {
4697
3409
  transactionId,
4698
3410
  purchaseId,
@@ -4765,14 +3477,8 @@ var usePaymentStatus = (options = {}) => {
4765
3477
  const checkPaymentStatus = useCallback(
4766
3478
  async (id) => {
4767
3479
  try {
4768
- const data = await billingApi.get(
4769
- `/payment/status/${id}`
4770
- );
4771
- return data;
3480
+ return await client.getPaymentStatus(id);
4772
3481
  } catch (error2) {
4773
- if (error2?.status === 404) {
4774
- return null;
4775
- }
4776
3482
  console.error("Failed to check payment status:", {
4777
3483
  purchaseId: id,
4778
3484
  error: error2
@@ -4780,7 +3486,7 @@ var usePaymentStatus = (options = {}) => {
4780
3486
  return null;
4781
3487
  }
4782
3488
  },
4783
- [billingApi]
3489
+ [client]
4784
3490
  );
4785
3491
  const startMonitoring = useCallback(async () => {
4786
3492
  if (isMonitoringRef.current || !transactionId && !purchaseId) {
@@ -4946,6 +3652,6 @@ var usePaymentStatus = (options = {}) => {
4946
3652
  };
4947
3653
  };
4948
3654
 
4949
- export { BillingHistory, CancelMembershipDialog, CardDetailsForm, CardPaymentService, EmptyWalletState, PaymentApp, PaymentExperience, PaymentMethodService, PaymentMethodsSection, PaymentProvider, PaymentsDialogProvider, PaymentsRuntime, SolanaPaymentSelector, SolanaPaymentService, SolanaPaymentView, SolanaWalletSection, SolanaWalletService, StoredPaymentMethods, SubscriptionCheckoutModal, SubscriptionService, SubscriptionSuccessDialog, TokenCatalog, WalletCard, WalletDialog, WalletGateway, WalletManagement, WalletModal, createPaymentsRuntime, useAlternativePaymentProvider, useDirectWalletPayment, usePaymentContext, usePaymentDialogs, usePaymentMethodService, usePaymentMethods, usePaymentNotifications, usePaymentStatus, useSolanaDirectPayment, useSolanaQrPayment, useSolanaService, useSubscriptionActions, useSupportedTokens, useTokenBalance, useWalletConnection, useWalletList, useWalletVerification };
3655
+ export { BillingHistory, CancelMembershipDialog, CardDetailsForm, ClientApiError, PaymentContext, PaymentExperience, PaymentMethodsSection, PaymentProvider, PaymentsDialogProvider, PaymentsUIPortalRoot, PaymentsUIRoot, SolanaPaymentSelector, SolanaPaymentView, StoredPaymentMethods, SubscriptionCheckoutModal, SubscriptionSuccessDialog, WalletDialog, WalletModal, createClient, usePaymentContext, usePaymentDialogs, usePaymentMethods, usePaymentNotifications, usePaymentStatus, useSolanaQrPayment, useSubscriptionActions, useSupportedTokens, useTokenBalance };
4950
3656
  //# sourceMappingURL=index.js.map
4951
3657
  //# sourceMappingURL=index.js.map