@djangocfg/ext-payments 1.0.1 → 1.0.3
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/README.md +2 -0
- package/dist/config.cjs +172 -0
- package/dist/config.d.cts +8 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.js +148 -0
- package/dist/hooks.cjs +2811 -0
- package/dist/hooks.d.cts +187 -0
- package/dist/hooks.d.ts +187 -0
- package/dist/hooks.js +2737 -0
- package/dist/index.cjs +2735 -0
- package/dist/index.d.cts +1293 -0
- package/dist/index.d.ts +1293 -0
- package/dist/index.js +2681 -0
- package/package.json +9 -4
- package/src/config.ts +0 -1
package/dist/index.js
ADDED
|
@@ -0,0 +1,2681 @@
|
|
|
1
|
+
import { createConsola, consola } from 'consola';
|
|
2
|
+
import pRetry, { AbortError } from 'p-retry';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { createExtensionAPI } from '@djangocfg/ext-base/api';
|
|
5
|
+
import { createContext, useState, useMemo, useEffect, useContext } from 'react';
|
|
6
|
+
import useSWR, { SWRConfig, useSWRConfig } from 'swr';
|
|
7
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
|
+
import { Tabs, TabsList, TabsTrigger, TabsContent, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Form, FormField, FormItem, FormLabel, FormControl, Input, FormDescription, FormMessage, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, TokenIcon, DialogFooter, Button, CopyButton, Card, CardHeader, CardTitle, Skeleton, CardContent, Badge, useDRFPagination, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, StaticPagination } from '@djangocfg/ui-nextjs';
|
|
9
|
+
import { Wallet, CreditCard, History, RefreshCw, Plus, XCircle, ExternalLink, Search, Filter, Clock, AlertCircle, CheckCircle2, ArrowDownLeft, ArrowUpRight } from 'lucide-react';
|
|
10
|
+
import { useForm } from 'react-hook-form';
|
|
11
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
12
|
+
import { createExtensionConfig } from '@djangocfg/ext-base';
|
|
13
|
+
|
|
14
|
+
var __defProp = Object.defineProperty;
|
|
15
|
+
var __export = (target, all) => {
|
|
16
|
+
for (var name in all)
|
|
17
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// src/api/generated/ext_payments/ext_payments__payments/client.ts
|
|
21
|
+
var ExtPaymentsPayments = class {
|
|
22
|
+
client;
|
|
23
|
+
constructor(client) {
|
|
24
|
+
this.client = client;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get user balance
|
|
28
|
+
*
|
|
29
|
+
* Get current user balance and transaction statistics
|
|
30
|
+
*/
|
|
31
|
+
async balanceRetrieve() {
|
|
32
|
+
const response = await this.client.request("GET", "/cfg/payments/balance/");
|
|
33
|
+
return response;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get available currencies
|
|
37
|
+
*
|
|
38
|
+
* Returns list of available currencies with token+network info
|
|
39
|
+
*/
|
|
40
|
+
async currenciesList() {
|
|
41
|
+
const response = await this.client.request("GET", "/cfg/payments/currencies/");
|
|
42
|
+
return response;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* ViewSet for payment operations. Endpoints: - GET /payments/ - List
|
|
46
|
+
* user's payments - GET /payments/{id}/ - Get payment details - POST
|
|
47
|
+
* /payments/create/ - Create new payment - GET /payments/{id}/status/ -
|
|
48
|
+
* Check payment status - POST /payments/{id}/confirm/ - Confirm payment
|
|
49
|
+
*/
|
|
50
|
+
async paymentsList(...args) {
|
|
51
|
+
const isParamsObject = args.length === 1 && typeof args[0] === "object" && args[0] !== null && !Array.isArray(args[0]);
|
|
52
|
+
let params;
|
|
53
|
+
if (isParamsObject) {
|
|
54
|
+
params = args[0];
|
|
55
|
+
} else {
|
|
56
|
+
params = { page: args[0], page_size: args[1] };
|
|
57
|
+
}
|
|
58
|
+
const response = await this.client.request("GET", "/cfg/payments/payments/", { params });
|
|
59
|
+
return response;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* ViewSet for payment operations. Endpoints: - GET /payments/ - List
|
|
63
|
+
* user's payments - GET /payments/{id}/ - Get payment details - POST
|
|
64
|
+
* /payments/create/ - Create new payment - GET /payments/{id}/status/ -
|
|
65
|
+
* Check payment status - POST /payments/{id}/confirm/ - Confirm payment
|
|
66
|
+
*/
|
|
67
|
+
async paymentsRetrieve(id) {
|
|
68
|
+
const response = await this.client.request("GET", `/cfg/payments/payments/${id}/`);
|
|
69
|
+
return response;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* POST /api/v1/payments/{id}/confirm/ Confirm payment (user clicked "I
|
|
73
|
+
* have paid"). Checks status with provider and creates transaction if
|
|
74
|
+
* completed.
|
|
75
|
+
*/
|
|
76
|
+
async paymentsConfirmCreate(id) {
|
|
77
|
+
const response = await this.client.request("POST", `/cfg/payments/payments/${id}/confirm/`);
|
|
78
|
+
return response;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* GET /api/v1/payments/{id}/status/?refresh=true Check payment status
|
|
82
|
+
* (with optional refresh from provider). Query params: - refresh: boolean
|
|
83
|
+
* (default: false) - Force refresh from provider
|
|
84
|
+
*/
|
|
85
|
+
async paymentsStatusRetrieve(id) {
|
|
86
|
+
const response = await this.client.request("GET", `/cfg/payments/payments/${id}/status/`);
|
|
87
|
+
return response.results || response;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* POST /api/v1/payments/create/ Create new payment. Request body: {
|
|
91
|
+
* "amount_usd": "100.00", "currency_code": "USDTTRC20", "description":
|
|
92
|
+
* "Optional description" }
|
|
93
|
+
*/
|
|
94
|
+
async paymentsCreateCreate() {
|
|
95
|
+
const response = await this.client.request("POST", "/cfg/payments/payments/create/");
|
|
96
|
+
return response;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get user transactions
|
|
100
|
+
*
|
|
101
|
+
* Get user transactions with pagination and filtering
|
|
102
|
+
*/
|
|
103
|
+
async transactionsList(...args) {
|
|
104
|
+
const isParamsObject = args.length === 1 && typeof args[0] === "object" && args[0] !== null && !Array.isArray(args[0]);
|
|
105
|
+
let params;
|
|
106
|
+
if (isParamsObject) {
|
|
107
|
+
params = args[0];
|
|
108
|
+
} else {
|
|
109
|
+
params = { limit: args[0], offset: args[1], type: args[2] };
|
|
110
|
+
}
|
|
111
|
+
const response = await this.client.request("GET", "/cfg/payments/transactions/", { params });
|
|
112
|
+
return response;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// src/api/generated/ext_payments/ext_payments__payments/models.ts
|
|
117
|
+
var models_exports = {};
|
|
118
|
+
|
|
119
|
+
// src/api/generated/ext_payments/http.ts
|
|
120
|
+
var FetchAdapter = class {
|
|
121
|
+
async request(request) {
|
|
122
|
+
const { method, url, headers, body, params, formData } = request;
|
|
123
|
+
let finalUrl = url;
|
|
124
|
+
if (params) {
|
|
125
|
+
const searchParams = new URLSearchParams();
|
|
126
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
127
|
+
if (value !== null && value !== void 0) {
|
|
128
|
+
searchParams.append(key, String(value));
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
const queryString = searchParams.toString();
|
|
132
|
+
if (queryString) {
|
|
133
|
+
finalUrl = url.includes("?") ? `${url}&${queryString}` : `${url}?${queryString}`;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const finalHeaders = { ...headers };
|
|
137
|
+
let requestBody;
|
|
138
|
+
if (formData) {
|
|
139
|
+
requestBody = formData;
|
|
140
|
+
} else if (body) {
|
|
141
|
+
finalHeaders["Content-Type"] = "application/json";
|
|
142
|
+
requestBody = JSON.stringify(body);
|
|
143
|
+
}
|
|
144
|
+
const response = await fetch(finalUrl, {
|
|
145
|
+
method,
|
|
146
|
+
headers: finalHeaders,
|
|
147
|
+
body: requestBody,
|
|
148
|
+
credentials: "include"
|
|
149
|
+
// Include Django session cookies
|
|
150
|
+
});
|
|
151
|
+
let data = null;
|
|
152
|
+
const contentType = response.headers.get("content-type");
|
|
153
|
+
if (response.status !== 204 && contentType?.includes("application/json")) {
|
|
154
|
+
data = await response.json();
|
|
155
|
+
} else if (response.status !== 204) {
|
|
156
|
+
data = await response.text();
|
|
157
|
+
}
|
|
158
|
+
const responseHeaders = {};
|
|
159
|
+
response.headers.forEach((value, key) => {
|
|
160
|
+
responseHeaders[key] = value;
|
|
161
|
+
});
|
|
162
|
+
return {
|
|
163
|
+
data,
|
|
164
|
+
status: response.status,
|
|
165
|
+
statusText: response.statusText,
|
|
166
|
+
headers: responseHeaders
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// src/api/generated/ext_payments/errors.ts
|
|
172
|
+
var APIError = class extends Error {
|
|
173
|
+
constructor(statusCode, statusText, response, url, message) {
|
|
174
|
+
super(message || `HTTP ${statusCode}: ${statusText}`);
|
|
175
|
+
this.statusCode = statusCode;
|
|
176
|
+
this.statusText = statusText;
|
|
177
|
+
this.response = response;
|
|
178
|
+
this.url = url;
|
|
179
|
+
this.name = "APIError";
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get error details from response.
|
|
183
|
+
* DRF typically returns: { "detail": "Error message" } or { "field": ["error1", "error2"] }
|
|
184
|
+
*/
|
|
185
|
+
get details() {
|
|
186
|
+
if (typeof this.response === "object" && this.response !== null) {
|
|
187
|
+
return this.response;
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Get field-specific validation errors from DRF.
|
|
193
|
+
* Returns: { "field_name": ["error1", "error2"], ... }
|
|
194
|
+
*/
|
|
195
|
+
get fieldErrors() {
|
|
196
|
+
const details = this.details;
|
|
197
|
+
if (!details) return null;
|
|
198
|
+
const fieldErrors = {};
|
|
199
|
+
for (const [key, value] of Object.entries(details)) {
|
|
200
|
+
if (Array.isArray(value)) {
|
|
201
|
+
fieldErrors[key] = value;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return Object.keys(fieldErrors).length > 0 ? fieldErrors : null;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Get single error message from DRF.
|
|
208
|
+
* Checks for "detail", "message", or first field error.
|
|
209
|
+
*/
|
|
210
|
+
get errorMessage() {
|
|
211
|
+
const details = this.details;
|
|
212
|
+
if (!details) return this.message;
|
|
213
|
+
if (details.detail) {
|
|
214
|
+
return Array.isArray(details.detail) ? details.detail.join(", ") : String(details.detail);
|
|
215
|
+
}
|
|
216
|
+
if (details.message) {
|
|
217
|
+
return String(details.message);
|
|
218
|
+
}
|
|
219
|
+
const fieldErrors = this.fieldErrors;
|
|
220
|
+
if (fieldErrors) {
|
|
221
|
+
const firstField = Object.keys(fieldErrors)[0];
|
|
222
|
+
if (firstField) {
|
|
223
|
+
return `${firstField}: ${fieldErrors[firstField]?.join(", ")}`;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return this.message;
|
|
227
|
+
}
|
|
228
|
+
// Helper methods for common HTTP status codes
|
|
229
|
+
get isValidationError() {
|
|
230
|
+
return this.statusCode === 400;
|
|
231
|
+
}
|
|
232
|
+
get isAuthError() {
|
|
233
|
+
return this.statusCode === 401;
|
|
234
|
+
}
|
|
235
|
+
get isPermissionError() {
|
|
236
|
+
return this.statusCode === 403;
|
|
237
|
+
}
|
|
238
|
+
get isNotFoundError() {
|
|
239
|
+
return this.statusCode === 404;
|
|
240
|
+
}
|
|
241
|
+
get isServerError() {
|
|
242
|
+
return this.statusCode >= 500 && this.statusCode < 600;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
var NetworkError = class extends Error {
|
|
246
|
+
constructor(message, url, originalError) {
|
|
247
|
+
super(message);
|
|
248
|
+
this.url = url;
|
|
249
|
+
this.originalError = originalError;
|
|
250
|
+
this.name = "NetworkError";
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
var DEFAULT_CONFIG = {
|
|
254
|
+
enabled: process.env.NODE_ENV !== "production",
|
|
255
|
+
logRequests: true,
|
|
256
|
+
logResponses: true,
|
|
257
|
+
logErrors: true,
|
|
258
|
+
logBodies: true,
|
|
259
|
+
logHeaders: false
|
|
260
|
+
};
|
|
261
|
+
var SENSITIVE_HEADERS = [
|
|
262
|
+
"authorization",
|
|
263
|
+
"cookie",
|
|
264
|
+
"set-cookie",
|
|
265
|
+
"x-api-key",
|
|
266
|
+
"x-csrf-token"
|
|
267
|
+
];
|
|
268
|
+
var APILogger = class {
|
|
269
|
+
config;
|
|
270
|
+
consola;
|
|
271
|
+
constructor(config = {}) {
|
|
272
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
273
|
+
this.consola = config.consola || createConsola({
|
|
274
|
+
level: this.config.enabled ? 4 : 0
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Enable logging
|
|
279
|
+
*/
|
|
280
|
+
enable() {
|
|
281
|
+
this.config.enabled = true;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Disable logging
|
|
285
|
+
*/
|
|
286
|
+
disable() {
|
|
287
|
+
this.config.enabled = false;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Update configuration
|
|
291
|
+
*/
|
|
292
|
+
setConfig(config) {
|
|
293
|
+
this.config = { ...this.config, ...config };
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Filter sensitive headers
|
|
297
|
+
*/
|
|
298
|
+
filterHeaders(headers) {
|
|
299
|
+
if (!headers) return {};
|
|
300
|
+
const filtered = {};
|
|
301
|
+
Object.keys(headers).forEach((key) => {
|
|
302
|
+
const lowerKey = key.toLowerCase();
|
|
303
|
+
if (SENSITIVE_HEADERS.includes(lowerKey)) {
|
|
304
|
+
filtered[key] = "***";
|
|
305
|
+
} else {
|
|
306
|
+
filtered[key] = headers[key] || "";
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
return filtered;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Log request
|
|
313
|
+
*/
|
|
314
|
+
logRequest(request) {
|
|
315
|
+
if (!this.config.enabled || !this.config.logRequests) return;
|
|
316
|
+
const { method, url, headers, body } = request;
|
|
317
|
+
this.consola.start(`${method} ${url}`);
|
|
318
|
+
if (this.config.logHeaders && headers) {
|
|
319
|
+
this.consola.debug("Headers:", this.filterHeaders(headers));
|
|
320
|
+
}
|
|
321
|
+
if (this.config.logBodies && body) {
|
|
322
|
+
this.consola.debug("Body:", body);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Log response
|
|
327
|
+
*/
|
|
328
|
+
logResponse(request, response) {
|
|
329
|
+
if (!this.config.enabled || !this.config.logResponses) return;
|
|
330
|
+
const { method, url } = request;
|
|
331
|
+
const { status, statusText, data, duration } = response;
|
|
332
|
+
this.consola.success(
|
|
333
|
+
`${method} ${url} ${status} ${statusText} (${duration}ms)`
|
|
334
|
+
);
|
|
335
|
+
if (this.config.logBodies && data) {
|
|
336
|
+
this.consola.debug("Response:", data);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Log error
|
|
341
|
+
*/
|
|
342
|
+
logError(request, error) {
|
|
343
|
+
if (!this.config.enabled || !this.config.logErrors) return;
|
|
344
|
+
const { method, url } = request;
|
|
345
|
+
const { message, statusCode, fieldErrors, duration } = error;
|
|
346
|
+
this.consola.error(
|
|
347
|
+
`${method} ${url} ${statusCode || "Network"} Error (${duration}ms)`
|
|
348
|
+
);
|
|
349
|
+
this.consola.error("Message:", message);
|
|
350
|
+
if (fieldErrors && Object.keys(fieldErrors).length > 0) {
|
|
351
|
+
this.consola.error("Field Errors:");
|
|
352
|
+
Object.entries(fieldErrors).forEach(([field, errors]) => {
|
|
353
|
+
errors.forEach((err) => {
|
|
354
|
+
this.consola.error(` \u2022 ${field}: ${err}`);
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Log general info
|
|
361
|
+
*/
|
|
362
|
+
info(message, ...args) {
|
|
363
|
+
if (!this.config.enabled) return;
|
|
364
|
+
this.consola.info(message, ...args);
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Log warning
|
|
368
|
+
*/
|
|
369
|
+
warn(message, ...args) {
|
|
370
|
+
if (!this.config.enabled) return;
|
|
371
|
+
this.consola.warn(message, ...args);
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Log error
|
|
375
|
+
*/
|
|
376
|
+
error(message, ...args) {
|
|
377
|
+
if (!this.config.enabled) return;
|
|
378
|
+
this.consola.error(message, ...args);
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Log debug
|
|
382
|
+
*/
|
|
383
|
+
debug(message, ...args) {
|
|
384
|
+
if (!this.config.enabled) return;
|
|
385
|
+
this.consola.debug(message, ...args);
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Log success
|
|
389
|
+
*/
|
|
390
|
+
success(message, ...args) {
|
|
391
|
+
if (!this.config.enabled) return;
|
|
392
|
+
this.consola.success(message, ...args);
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Create a sub-logger with prefix
|
|
396
|
+
*/
|
|
397
|
+
withTag(tag) {
|
|
398
|
+
return this.consola.withTag(tag);
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
new APILogger();
|
|
402
|
+
var DEFAULT_RETRY_CONFIG = {
|
|
403
|
+
retries: 3,
|
|
404
|
+
factor: 2,
|
|
405
|
+
minTimeout: 1e3,
|
|
406
|
+
maxTimeout: 6e4,
|
|
407
|
+
randomize: true,
|
|
408
|
+
onFailedAttempt: () => {
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
function shouldRetry(error) {
|
|
412
|
+
if (error instanceof NetworkError) {
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
if (error instanceof APIError) {
|
|
416
|
+
const status = error.statusCode;
|
|
417
|
+
if (status >= 500 && status < 600) {
|
|
418
|
+
return true;
|
|
419
|
+
}
|
|
420
|
+
if (status === 429) {
|
|
421
|
+
return true;
|
|
422
|
+
}
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
async function withRetry(fn, config) {
|
|
428
|
+
const finalConfig = { ...DEFAULT_RETRY_CONFIG, ...config };
|
|
429
|
+
return pRetry(
|
|
430
|
+
async () => {
|
|
431
|
+
try {
|
|
432
|
+
return await fn();
|
|
433
|
+
} catch (error) {
|
|
434
|
+
if (!shouldRetry(error)) {
|
|
435
|
+
throw new AbortError(error);
|
|
436
|
+
}
|
|
437
|
+
throw error;
|
|
438
|
+
}
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
retries: finalConfig.retries,
|
|
442
|
+
factor: finalConfig.factor,
|
|
443
|
+
minTimeout: finalConfig.minTimeout,
|
|
444
|
+
maxTimeout: finalConfig.maxTimeout,
|
|
445
|
+
randomize: finalConfig.randomize,
|
|
446
|
+
onFailedAttempt: finalConfig.onFailedAttempt ? (error) => {
|
|
447
|
+
const pRetryError = error;
|
|
448
|
+
finalConfig.onFailedAttempt({
|
|
449
|
+
error: pRetryError,
|
|
450
|
+
attemptNumber: pRetryError.attemptNumber,
|
|
451
|
+
retriesLeft: pRetryError.retriesLeft
|
|
452
|
+
});
|
|
453
|
+
} : void 0
|
|
454
|
+
}
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// src/api/generated/ext_payments/client.ts
|
|
459
|
+
var APIClient = class {
|
|
460
|
+
baseUrl;
|
|
461
|
+
httpClient;
|
|
462
|
+
logger = null;
|
|
463
|
+
retryConfig = null;
|
|
464
|
+
// Sub-clients
|
|
465
|
+
ext_payments_payments;
|
|
466
|
+
constructor(baseUrl, options) {
|
|
467
|
+
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
468
|
+
this.httpClient = options?.httpClient || new FetchAdapter();
|
|
469
|
+
if (options?.loggerConfig !== void 0) {
|
|
470
|
+
this.logger = new APILogger(options.loggerConfig);
|
|
471
|
+
}
|
|
472
|
+
if (options?.retryConfig !== void 0) {
|
|
473
|
+
this.retryConfig = options.retryConfig;
|
|
474
|
+
}
|
|
475
|
+
this.ext_payments_payments = new ExtPaymentsPayments(this);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Get CSRF token from cookies (for SessionAuthentication).
|
|
479
|
+
*
|
|
480
|
+
* Returns null if cookie doesn't exist (JWT-only auth).
|
|
481
|
+
*/
|
|
482
|
+
getCsrfToken() {
|
|
483
|
+
const name = "csrftoken";
|
|
484
|
+
const value = `; ${document.cookie}`;
|
|
485
|
+
const parts = value.split(`; ${name}=`);
|
|
486
|
+
if (parts.length === 2) {
|
|
487
|
+
return parts.pop()?.split(";").shift() || null;
|
|
488
|
+
}
|
|
489
|
+
return null;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Make HTTP request with Django CSRF and session handling.
|
|
493
|
+
* Automatically retries on network errors and 5xx server errors.
|
|
494
|
+
*/
|
|
495
|
+
async request(method, path, options) {
|
|
496
|
+
if (this.retryConfig) {
|
|
497
|
+
return withRetry(() => this._makeRequest(method, path, options), {
|
|
498
|
+
...this.retryConfig,
|
|
499
|
+
onFailedAttempt: (info) => {
|
|
500
|
+
if (this.logger) {
|
|
501
|
+
this.logger.warn(
|
|
502
|
+
`Retry attempt ${info.attemptNumber}/${info.retriesLeft + info.attemptNumber} for ${method} ${path}: ${info.error.message}`
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
this.retryConfig?.onFailedAttempt?.(info);
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
return this._makeRequest(method, path, options);
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Internal request method (without retry wrapper).
|
|
513
|
+
* Used by request() method with optional retry logic.
|
|
514
|
+
*/
|
|
515
|
+
async _makeRequest(method, path, options) {
|
|
516
|
+
const url = this.baseUrl ? `${this.baseUrl}${path}` : path;
|
|
517
|
+
const startTime = Date.now();
|
|
518
|
+
const headers = {
|
|
519
|
+
...options?.headers || {}
|
|
520
|
+
};
|
|
521
|
+
if (!options?.formData && !headers["Content-Type"]) {
|
|
522
|
+
headers["Content-Type"] = "application/json";
|
|
523
|
+
}
|
|
524
|
+
if (this.logger) {
|
|
525
|
+
this.logger.logRequest({
|
|
526
|
+
method,
|
|
527
|
+
url,
|
|
528
|
+
headers,
|
|
529
|
+
body: options?.formData || options?.body,
|
|
530
|
+
timestamp: startTime
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
try {
|
|
534
|
+
const response = await this.httpClient.request({
|
|
535
|
+
method,
|
|
536
|
+
url,
|
|
537
|
+
headers,
|
|
538
|
+
params: options?.params,
|
|
539
|
+
body: options?.body,
|
|
540
|
+
formData: options?.formData
|
|
541
|
+
});
|
|
542
|
+
const duration = Date.now() - startTime;
|
|
543
|
+
if (response.status >= 400) {
|
|
544
|
+
const error = new APIError(
|
|
545
|
+
response.status,
|
|
546
|
+
response.statusText,
|
|
547
|
+
response.data,
|
|
548
|
+
url
|
|
549
|
+
);
|
|
550
|
+
if (this.logger) {
|
|
551
|
+
this.logger.logError(
|
|
552
|
+
{
|
|
553
|
+
method,
|
|
554
|
+
url,
|
|
555
|
+
headers,
|
|
556
|
+
body: options?.formData || options?.body,
|
|
557
|
+
timestamp: startTime
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
message: error.message,
|
|
561
|
+
statusCode: response.status,
|
|
562
|
+
duration,
|
|
563
|
+
timestamp: Date.now()
|
|
564
|
+
}
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
throw error;
|
|
568
|
+
}
|
|
569
|
+
if (this.logger) {
|
|
570
|
+
this.logger.logResponse(
|
|
571
|
+
{
|
|
572
|
+
method,
|
|
573
|
+
url,
|
|
574
|
+
headers,
|
|
575
|
+
body: options?.formData || options?.body,
|
|
576
|
+
timestamp: startTime
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
status: response.status,
|
|
580
|
+
statusText: response.statusText,
|
|
581
|
+
data: response.data,
|
|
582
|
+
duration,
|
|
583
|
+
timestamp: Date.now()
|
|
584
|
+
}
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
return response.data;
|
|
588
|
+
} catch (error) {
|
|
589
|
+
const duration = Date.now() - startTime;
|
|
590
|
+
if (error instanceof APIError) {
|
|
591
|
+
throw error;
|
|
592
|
+
}
|
|
593
|
+
const isCORSError = error instanceof TypeError && (error.message.toLowerCase().includes("cors") || error.message.toLowerCase().includes("failed to fetch") || error.message.toLowerCase().includes("network request failed"));
|
|
594
|
+
if (this.logger) {
|
|
595
|
+
if (isCORSError) {
|
|
596
|
+
this.logger.error(`\u{1F6AB} CORS Error: ${method} ${url}`);
|
|
597
|
+
this.logger.error(` \u2192 ${error instanceof Error ? error.message : String(error)}`);
|
|
598
|
+
this.logger.error(` \u2192 Configure security_domains parameter on the server`);
|
|
599
|
+
} else {
|
|
600
|
+
this.logger.error(`\u26A0\uFE0F Network Error: ${method} ${url}`);
|
|
601
|
+
this.logger.error(` \u2192 ${error instanceof Error ? error.message : String(error)}`);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
if (typeof window !== "undefined") {
|
|
605
|
+
try {
|
|
606
|
+
if (isCORSError) {
|
|
607
|
+
window.dispatchEvent(new CustomEvent("cors-error", {
|
|
608
|
+
detail: {
|
|
609
|
+
url,
|
|
610
|
+
method,
|
|
611
|
+
error: error instanceof Error ? error.message : String(error),
|
|
612
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
613
|
+
},
|
|
614
|
+
bubbles: true,
|
|
615
|
+
cancelable: false
|
|
616
|
+
}));
|
|
617
|
+
} else {
|
|
618
|
+
window.dispatchEvent(new CustomEvent("network-error", {
|
|
619
|
+
detail: {
|
|
620
|
+
url,
|
|
621
|
+
method,
|
|
622
|
+
error: error instanceof Error ? error.message : String(error),
|
|
623
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
624
|
+
},
|
|
625
|
+
bubbles: true,
|
|
626
|
+
cancelable: false
|
|
627
|
+
}));
|
|
628
|
+
}
|
|
629
|
+
} catch (eventError) {
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
const networkError = error instanceof Error ? new NetworkError(error.message, url, error) : new NetworkError("Unknown error", url);
|
|
633
|
+
if (this.logger) {
|
|
634
|
+
this.logger.logError(
|
|
635
|
+
{
|
|
636
|
+
method,
|
|
637
|
+
url,
|
|
638
|
+
headers,
|
|
639
|
+
body: options?.formData || options?.body,
|
|
640
|
+
timestamp: startTime
|
|
641
|
+
},
|
|
642
|
+
{
|
|
643
|
+
message: networkError.message,
|
|
644
|
+
duration,
|
|
645
|
+
timestamp: Date.now()
|
|
646
|
+
}
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
throw networkError;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
// src/api/generated/ext_payments/storage.ts
|
|
655
|
+
var LocalStorageAdapter = class {
|
|
656
|
+
logger;
|
|
657
|
+
constructor(logger2) {
|
|
658
|
+
this.logger = logger2;
|
|
659
|
+
}
|
|
660
|
+
getItem(key) {
|
|
661
|
+
try {
|
|
662
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
663
|
+
const value = localStorage.getItem(key);
|
|
664
|
+
this.logger?.debug(`LocalStorage.getItem("${key}"): ${value ? "found" : "not found"}`);
|
|
665
|
+
return value;
|
|
666
|
+
}
|
|
667
|
+
this.logger?.warn("LocalStorage not available: window.localStorage is undefined");
|
|
668
|
+
} catch (error) {
|
|
669
|
+
this.logger?.error("LocalStorage.getItem failed:", error);
|
|
670
|
+
}
|
|
671
|
+
return null;
|
|
672
|
+
}
|
|
673
|
+
setItem(key, value) {
|
|
674
|
+
try {
|
|
675
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
676
|
+
localStorage.setItem(key, value);
|
|
677
|
+
this.logger?.debug(`LocalStorage.setItem("${key}"): success`);
|
|
678
|
+
} else {
|
|
679
|
+
this.logger?.warn("LocalStorage not available: window.localStorage is undefined");
|
|
680
|
+
}
|
|
681
|
+
} catch (error) {
|
|
682
|
+
this.logger?.error("LocalStorage.setItem failed:", error);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
removeItem(key) {
|
|
686
|
+
try {
|
|
687
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
688
|
+
localStorage.removeItem(key);
|
|
689
|
+
this.logger?.debug(`LocalStorage.removeItem("${key}"): success`);
|
|
690
|
+
} else {
|
|
691
|
+
this.logger?.warn("LocalStorage not available: window.localStorage is undefined");
|
|
692
|
+
}
|
|
693
|
+
} catch (error) {
|
|
694
|
+
this.logger?.error("LocalStorage.removeItem failed:", error);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
var CookieStorageAdapter = class {
|
|
699
|
+
logger;
|
|
700
|
+
constructor(logger2) {
|
|
701
|
+
this.logger = logger2;
|
|
702
|
+
}
|
|
703
|
+
getItem(key) {
|
|
704
|
+
try {
|
|
705
|
+
if (typeof document === "undefined") {
|
|
706
|
+
this.logger?.warn("Cookies not available: document is undefined (SSR context?)");
|
|
707
|
+
return null;
|
|
708
|
+
}
|
|
709
|
+
const value = `; ${document.cookie}`;
|
|
710
|
+
const parts = value.split(`; ${key}=`);
|
|
711
|
+
if (parts.length === 2) {
|
|
712
|
+
const result = parts.pop()?.split(";").shift() || null;
|
|
713
|
+
this.logger?.debug(`CookieStorage.getItem("${key}"): ${result ? "found" : "not found"}`);
|
|
714
|
+
return result;
|
|
715
|
+
}
|
|
716
|
+
this.logger?.debug(`CookieStorage.getItem("${key}"): not found`);
|
|
717
|
+
} catch (error) {
|
|
718
|
+
this.logger?.error("CookieStorage.getItem failed:", error);
|
|
719
|
+
}
|
|
720
|
+
return null;
|
|
721
|
+
}
|
|
722
|
+
setItem(key, value) {
|
|
723
|
+
try {
|
|
724
|
+
if (typeof document !== "undefined") {
|
|
725
|
+
document.cookie = `${key}=${value}; path=/; max-age=31536000`;
|
|
726
|
+
this.logger?.debug(`CookieStorage.setItem("${key}"): success`);
|
|
727
|
+
} else {
|
|
728
|
+
this.logger?.warn("Cookies not available: document is undefined (SSR context?)");
|
|
729
|
+
}
|
|
730
|
+
} catch (error) {
|
|
731
|
+
this.logger?.error("CookieStorage.setItem failed:", error);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
removeItem(key) {
|
|
735
|
+
try {
|
|
736
|
+
if (typeof document !== "undefined") {
|
|
737
|
+
document.cookie = `${key}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
|
|
738
|
+
this.logger?.debug(`CookieStorage.removeItem("${key}"): success`);
|
|
739
|
+
} else {
|
|
740
|
+
this.logger?.warn("Cookies not available: document is undefined (SSR context?)");
|
|
741
|
+
}
|
|
742
|
+
} catch (error) {
|
|
743
|
+
this.logger?.error("CookieStorage.removeItem failed:", error);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
var MemoryStorageAdapter = class {
|
|
748
|
+
storage = /* @__PURE__ */ new Map();
|
|
749
|
+
logger;
|
|
750
|
+
constructor(logger2) {
|
|
751
|
+
this.logger = logger2;
|
|
752
|
+
}
|
|
753
|
+
getItem(key) {
|
|
754
|
+
const value = this.storage.get(key) || null;
|
|
755
|
+
this.logger?.debug(`MemoryStorage.getItem("${key}"): ${value ? "found" : "not found"}`);
|
|
756
|
+
return value;
|
|
757
|
+
}
|
|
758
|
+
setItem(key, value) {
|
|
759
|
+
this.storage.set(key, value);
|
|
760
|
+
this.logger?.debug(`MemoryStorage.setItem("${key}"): success`);
|
|
761
|
+
}
|
|
762
|
+
removeItem(key) {
|
|
763
|
+
this.storage.delete(key);
|
|
764
|
+
this.logger?.debug(`MemoryStorage.removeItem("${key}"): success`);
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
|
|
768
|
+
// src/api/generated/ext_payments/enums.ts
|
|
769
|
+
var enums_exports = {};
|
|
770
|
+
__export(enums_exports, {
|
|
771
|
+
PaymentDetailStatus: () => PaymentDetailStatus,
|
|
772
|
+
PaymentListStatus: () => PaymentListStatus,
|
|
773
|
+
TransactionTransactionType: () => TransactionTransactionType
|
|
774
|
+
});
|
|
775
|
+
var PaymentDetailStatus = /* @__PURE__ */ ((PaymentDetailStatus2) => {
|
|
776
|
+
PaymentDetailStatus2["PENDING"] = "pending";
|
|
777
|
+
PaymentDetailStatus2["CONFIRMING"] = "confirming";
|
|
778
|
+
PaymentDetailStatus2["CONFIRMED"] = "confirmed";
|
|
779
|
+
PaymentDetailStatus2["COMPLETED"] = "completed";
|
|
780
|
+
PaymentDetailStatus2["PARTIALLY_PAID"] = "partially_paid";
|
|
781
|
+
PaymentDetailStatus2["FAILED"] = "failed";
|
|
782
|
+
PaymentDetailStatus2["EXPIRED"] = "expired";
|
|
783
|
+
PaymentDetailStatus2["CANCELLED"] = "cancelled";
|
|
784
|
+
return PaymentDetailStatus2;
|
|
785
|
+
})(PaymentDetailStatus || {});
|
|
786
|
+
var PaymentListStatus = /* @__PURE__ */ ((PaymentListStatus2) => {
|
|
787
|
+
PaymentListStatus2["PENDING"] = "pending";
|
|
788
|
+
PaymentListStatus2["CONFIRMING"] = "confirming";
|
|
789
|
+
PaymentListStatus2["CONFIRMED"] = "confirmed";
|
|
790
|
+
PaymentListStatus2["COMPLETED"] = "completed";
|
|
791
|
+
PaymentListStatus2["PARTIALLY_PAID"] = "partially_paid";
|
|
792
|
+
PaymentListStatus2["FAILED"] = "failed";
|
|
793
|
+
PaymentListStatus2["EXPIRED"] = "expired";
|
|
794
|
+
PaymentListStatus2["CANCELLED"] = "cancelled";
|
|
795
|
+
return PaymentListStatus2;
|
|
796
|
+
})(PaymentListStatus || {});
|
|
797
|
+
var TransactionTransactionType = /* @__PURE__ */ ((TransactionTransactionType2) => {
|
|
798
|
+
TransactionTransactionType2["DEPOSIT"] = "deposit";
|
|
799
|
+
TransactionTransactionType2["WITHDRAWAL"] = "withdrawal";
|
|
800
|
+
TransactionTransactionType2["PAYMENT"] = "payment";
|
|
801
|
+
TransactionTransactionType2["REFUND"] = "refund";
|
|
802
|
+
TransactionTransactionType2["FEE"] = "fee";
|
|
803
|
+
TransactionTransactionType2["BONUS"] = "bonus";
|
|
804
|
+
TransactionTransactionType2["ADJUSTMENT"] = "adjustment";
|
|
805
|
+
return TransactionTransactionType2;
|
|
806
|
+
})(TransactionTransactionType || {});
|
|
807
|
+
|
|
808
|
+
// src/api/generated/ext_payments/_utils/schemas/index.ts
|
|
809
|
+
var schemas_exports = {};
|
|
810
|
+
__export(schemas_exports, {
|
|
811
|
+
BalanceSchema: () => BalanceSchema,
|
|
812
|
+
CurrencySchema: () => CurrencySchema,
|
|
813
|
+
PaginatedPaymentListListSchema: () => PaginatedPaymentListListSchema,
|
|
814
|
+
PaymentDetailSchema: () => PaymentDetailSchema,
|
|
815
|
+
PaymentListSchema: () => PaymentListSchema,
|
|
816
|
+
TransactionSchema: () => TransactionSchema
|
|
817
|
+
});
|
|
818
|
+
var BalanceSchema = z.object({
|
|
819
|
+
balance_usd: z.string(),
|
|
820
|
+
balance_display: z.string(),
|
|
821
|
+
total_deposited: z.string(),
|
|
822
|
+
total_withdrawn: z.string(),
|
|
823
|
+
last_transaction_at: z.iso.datetime().nullable()
|
|
824
|
+
});
|
|
825
|
+
var CurrencySchema = z.object({
|
|
826
|
+
code: z.string(),
|
|
827
|
+
name: z.string(),
|
|
828
|
+
token: z.string(),
|
|
829
|
+
network: z.string().nullable(),
|
|
830
|
+
display_name: z.string(),
|
|
831
|
+
symbol: z.string(),
|
|
832
|
+
decimal_places: z.int(),
|
|
833
|
+
is_active: z.boolean(),
|
|
834
|
+
min_amount_usd: z.string(),
|
|
835
|
+
sort_order: z.int()
|
|
836
|
+
});
|
|
837
|
+
var PaymentListSchema = z.object({
|
|
838
|
+
id: z.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i),
|
|
839
|
+
internal_payment_id: z.string(),
|
|
840
|
+
amount_usd: z.string(),
|
|
841
|
+
currency_code: z.string(),
|
|
842
|
+
currency_token: z.string(),
|
|
843
|
+
status: z.nativeEnum(PaymentListStatus),
|
|
844
|
+
status_display: z.string(),
|
|
845
|
+
created_at: z.iso.datetime(),
|
|
846
|
+
completed_at: z.iso.datetime().nullable()
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
// src/api/generated/ext_payments/_utils/schemas/PaginatedPaymentListList.schema.ts
|
|
850
|
+
var PaginatedPaymentListListSchema = z.object({
|
|
851
|
+
count: z.int(),
|
|
852
|
+
page: z.int(),
|
|
853
|
+
pages: z.int(),
|
|
854
|
+
page_size: z.int(),
|
|
855
|
+
has_next: z.boolean(),
|
|
856
|
+
has_previous: z.boolean(),
|
|
857
|
+
next_page: z.int().nullable().optional(),
|
|
858
|
+
previous_page: z.int().nullable().optional(),
|
|
859
|
+
results: z.array(PaymentListSchema)
|
|
860
|
+
});
|
|
861
|
+
var PaymentDetailSchema = z.object({
|
|
862
|
+
id: z.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i),
|
|
863
|
+
internal_payment_id: z.string(),
|
|
864
|
+
amount_usd: z.string(),
|
|
865
|
+
currency_code: z.string(),
|
|
866
|
+
currency_name: z.string(),
|
|
867
|
+
currency_token: z.string(),
|
|
868
|
+
currency_network: z.string(),
|
|
869
|
+
pay_amount: z.string().nullable(),
|
|
870
|
+
actual_amount: z.string().nullable(),
|
|
871
|
+
actual_amount_usd: z.string().nullable(),
|
|
872
|
+
status: z.nativeEnum(PaymentDetailStatus),
|
|
873
|
+
status_display: z.string(),
|
|
874
|
+
pay_address: z.string().nullable(),
|
|
875
|
+
qr_code_url: z.string().nullable(),
|
|
876
|
+
payment_url: z.url().nullable(),
|
|
877
|
+
transaction_hash: z.string().nullable(),
|
|
878
|
+
explorer_link: z.string().nullable(),
|
|
879
|
+
confirmations_count: z.int(),
|
|
880
|
+
expires_at: z.iso.datetime().nullable(),
|
|
881
|
+
completed_at: z.iso.datetime().nullable(),
|
|
882
|
+
created_at: z.iso.datetime(),
|
|
883
|
+
is_completed: z.boolean(),
|
|
884
|
+
is_failed: z.boolean(),
|
|
885
|
+
is_expired: z.boolean(),
|
|
886
|
+
description: z.string()
|
|
887
|
+
});
|
|
888
|
+
var TransactionSchema = z.object({
|
|
889
|
+
id: z.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i),
|
|
890
|
+
transaction_type: z.nativeEnum(TransactionTransactionType),
|
|
891
|
+
type_display: z.string(),
|
|
892
|
+
amount_usd: z.string(),
|
|
893
|
+
amount_display: z.string(),
|
|
894
|
+
balance_after: z.string(),
|
|
895
|
+
payment_id: z.string().nullable(),
|
|
896
|
+
description: z.string(),
|
|
897
|
+
created_at: z.iso.datetime()
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
// src/api/generated/ext_payments/validation-events.ts
|
|
901
|
+
function dispatchValidationError(detail) {
|
|
902
|
+
if (typeof window === "undefined") {
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
try {
|
|
906
|
+
const event = new CustomEvent("zod-validation-error", {
|
|
907
|
+
detail,
|
|
908
|
+
bubbles: true,
|
|
909
|
+
cancelable: false
|
|
910
|
+
});
|
|
911
|
+
window.dispatchEvent(event);
|
|
912
|
+
} catch (error) {
|
|
913
|
+
console.warn("Failed to dispatch validation error event:", error);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
function onValidationError(callback) {
|
|
917
|
+
if (typeof window === "undefined") {
|
|
918
|
+
return () => {
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
const handler = (event) => {
|
|
922
|
+
if (event instanceof CustomEvent) {
|
|
923
|
+
callback(event.detail);
|
|
924
|
+
}
|
|
925
|
+
};
|
|
926
|
+
window.addEventListener("zod-validation-error", handler);
|
|
927
|
+
return () => {
|
|
928
|
+
window.removeEventListener("zod-validation-error", handler);
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
function formatZodError(error) {
|
|
932
|
+
const issues = error.issues.map((issue, index) => {
|
|
933
|
+
const path = issue.path.join(".") || "root";
|
|
934
|
+
const parts = [`${index + 1}. ${path}: ${issue.message}`];
|
|
935
|
+
if ("expected" in issue && issue.expected) {
|
|
936
|
+
parts.push(` Expected: ${issue.expected}`);
|
|
937
|
+
}
|
|
938
|
+
if ("received" in issue && issue.received) {
|
|
939
|
+
parts.push(` Received: ${issue.received}`);
|
|
940
|
+
}
|
|
941
|
+
return parts.join("\n");
|
|
942
|
+
});
|
|
943
|
+
return issues.join("\n");
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// src/api/generated/ext_payments/_utils/fetchers/index.ts
|
|
947
|
+
var fetchers_exports = {};
|
|
948
|
+
__export(fetchers_exports, {
|
|
949
|
+
createPaymentsPaymentsConfirmCreate: () => createPaymentsPaymentsConfirmCreate,
|
|
950
|
+
createPaymentsPaymentsCreateCreate: () => createPaymentsPaymentsCreateCreate,
|
|
951
|
+
getPaymentsBalanceRetrieve: () => getPaymentsBalanceRetrieve,
|
|
952
|
+
getPaymentsCurrenciesList: () => getPaymentsCurrenciesList,
|
|
953
|
+
getPaymentsPaymentsList: () => getPaymentsPaymentsList,
|
|
954
|
+
getPaymentsPaymentsRetrieve: () => getPaymentsPaymentsRetrieve,
|
|
955
|
+
getPaymentsPaymentsStatusRetrieve: () => getPaymentsPaymentsStatusRetrieve,
|
|
956
|
+
getPaymentsTransactionsList: () => getPaymentsTransactionsList
|
|
957
|
+
});
|
|
958
|
+
|
|
959
|
+
// src/api/generated/ext_payments/api-instance.ts
|
|
960
|
+
var globalAPI = null;
|
|
961
|
+
function getAPIInstance() {
|
|
962
|
+
if (!globalAPI) {
|
|
963
|
+
throw new Error(
|
|
964
|
+
'API not configured. Call configureAPI() with your base URL before using fetchers or hooks.\n\nExample:\n import { configureAPI } from "./api-instance"\n configureAPI({ baseUrl: "https://api.example.com" })'
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
return globalAPI;
|
|
968
|
+
}
|
|
969
|
+
function isAPIConfigured() {
|
|
970
|
+
return globalAPI !== null;
|
|
971
|
+
}
|
|
972
|
+
function configureAPI(config) {
|
|
973
|
+
globalAPI = new API(config.baseUrl, config.options);
|
|
974
|
+
if (config.token) {
|
|
975
|
+
globalAPI.setToken(config.token, config.refreshToken);
|
|
976
|
+
}
|
|
977
|
+
return globalAPI;
|
|
978
|
+
}
|
|
979
|
+
function reconfigureAPI(updates) {
|
|
980
|
+
const instance = getAPIInstance();
|
|
981
|
+
if (updates.baseUrl) {
|
|
982
|
+
instance.setBaseUrl(updates.baseUrl);
|
|
983
|
+
}
|
|
984
|
+
if (updates.token) {
|
|
985
|
+
instance.setToken(updates.token, updates.refreshToken);
|
|
986
|
+
}
|
|
987
|
+
return instance;
|
|
988
|
+
}
|
|
989
|
+
function clearAPITokens() {
|
|
990
|
+
const instance = getAPIInstance();
|
|
991
|
+
instance.clearTokens();
|
|
992
|
+
}
|
|
993
|
+
function resetAPI() {
|
|
994
|
+
if (globalAPI) {
|
|
995
|
+
globalAPI.clearTokens();
|
|
996
|
+
}
|
|
997
|
+
globalAPI = null;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
// src/api/generated/ext_payments/_utils/fetchers/ext_payments__payments.ts
|
|
1001
|
+
async function getPaymentsBalanceRetrieve(client) {
|
|
1002
|
+
const api = client || getAPIInstance();
|
|
1003
|
+
const response = await api.ext_payments_payments.balanceRetrieve();
|
|
1004
|
+
try {
|
|
1005
|
+
return BalanceSchema.parse(response);
|
|
1006
|
+
} catch (error) {
|
|
1007
|
+
consola.error("\u274C Zod Validation Failed");
|
|
1008
|
+
consola.box(`getPaymentsBalanceRetrieve
|
|
1009
|
+
Path: /cfg/payments/balance/
|
|
1010
|
+
Method: GET`);
|
|
1011
|
+
if (error instanceof Error && "issues" in error && Array.isArray(error.issues)) {
|
|
1012
|
+
consola.error("Validation Issues:");
|
|
1013
|
+
error.issues.forEach((issue, index) => {
|
|
1014
|
+
consola.error(` ${index + 1}. ${issue.path.join(".") || "root"}`);
|
|
1015
|
+
consola.error(` \u251C\u2500 Message: ${issue.message}`);
|
|
1016
|
+
if (issue.expected) consola.error(` \u251C\u2500 Expected: ${issue.expected}`);
|
|
1017
|
+
if (issue.received) consola.error(` \u2514\u2500 Received: ${issue.received}`);
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
consola.error("Response data:", response);
|
|
1021
|
+
if (typeof window !== "undefined" && error instanceof Error && "issues" in error) {
|
|
1022
|
+
try {
|
|
1023
|
+
const event = new CustomEvent("zod-validation-error", {
|
|
1024
|
+
detail: {
|
|
1025
|
+
operation: "getPaymentsBalanceRetrieve",
|
|
1026
|
+
path: "/cfg/payments/balance/",
|
|
1027
|
+
method: "GET",
|
|
1028
|
+
error,
|
|
1029
|
+
response,
|
|
1030
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1031
|
+
},
|
|
1032
|
+
bubbles: true,
|
|
1033
|
+
cancelable: false
|
|
1034
|
+
});
|
|
1035
|
+
window.dispatchEvent(event);
|
|
1036
|
+
} catch (eventError) {
|
|
1037
|
+
consola.warn("Failed to dispatch validation error event:", eventError);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
throw error;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
async function getPaymentsCurrenciesList(client) {
|
|
1044
|
+
const api = client || getAPIInstance();
|
|
1045
|
+
const response = await api.ext_payments_payments.currenciesList();
|
|
1046
|
+
return response;
|
|
1047
|
+
}
|
|
1048
|
+
async function getPaymentsPaymentsList(params, client) {
|
|
1049
|
+
const api = client || getAPIInstance();
|
|
1050
|
+
const response = await api.ext_payments_payments.paymentsList(params?.page, params?.page_size);
|
|
1051
|
+
try {
|
|
1052
|
+
return PaginatedPaymentListListSchema.parse(response);
|
|
1053
|
+
} catch (error) {
|
|
1054
|
+
consola.error("\u274C Zod Validation Failed");
|
|
1055
|
+
consola.box(`getPaymentsPaymentsList
|
|
1056
|
+
Path: /cfg/payments/payments/
|
|
1057
|
+
Method: GET`);
|
|
1058
|
+
if (error instanceof Error && "issues" in error && Array.isArray(error.issues)) {
|
|
1059
|
+
consola.error("Validation Issues:");
|
|
1060
|
+
error.issues.forEach((issue, index) => {
|
|
1061
|
+
consola.error(` ${index + 1}. ${issue.path.join(".") || "root"}`);
|
|
1062
|
+
consola.error(` \u251C\u2500 Message: ${issue.message}`);
|
|
1063
|
+
if (issue.expected) consola.error(` \u251C\u2500 Expected: ${issue.expected}`);
|
|
1064
|
+
if (issue.received) consola.error(` \u2514\u2500 Received: ${issue.received}`);
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
consola.error("Response data:", response);
|
|
1068
|
+
if (typeof window !== "undefined" && error instanceof Error && "issues" in error) {
|
|
1069
|
+
try {
|
|
1070
|
+
const event = new CustomEvent("zod-validation-error", {
|
|
1071
|
+
detail: {
|
|
1072
|
+
operation: "getPaymentsPaymentsList",
|
|
1073
|
+
path: "/cfg/payments/payments/",
|
|
1074
|
+
method: "GET",
|
|
1075
|
+
error,
|
|
1076
|
+
response,
|
|
1077
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1078
|
+
},
|
|
1079
|
+
bubbles: true,
|
|
1080
|
+
cancelable: false
|
|
1081
|
+
});
|
|
1082
|
+
window.dispatchEvent(event);
|
|
1083
|
+
} catch (eventError) {
|
|
1084
|
+
consola.warn("Failed to dispatch validation error event:", eventError);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
throw error;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
async function getPaymentsPaymentsRetrieve(id, client) {
|
|
1091
|
+
const api = client || getAPIInstance();
|
|
1092
|
+
const response = await api.ext_payments_payments.paymentsRetrieve(id);
|
|
1093
|
+
try {
|
|
1094
|
+
return PaymentDetailSchema.parse(response);
|
|
1095
|
+
} catch (error) {
|
|
1096
|
+
consola.error("\u274C Zod Validation Failed");
|
|
1097
|
+
consola.box(`getPaymentsPaymentsRetrieve
|
|
1098
|
+
Path: /cfg/payments/payments/{id}/
|
|
1099
|
+
Method: GET`);
|
|
1100
|
+
if (error instanceof Error && "issues" in error && Array.isArray(error.issues)) {
|
|
1101
|
+
consola.error("Validation Issues:");
|
|
1102
|
+
error.issues.forEach((issue, index) => {
|
|
1103
|
+
consola.error(` ${index + 1}. ${issue.path.join(".") || "root"}`);
|
|
1104
|
+
consola.error(` \u251C\u2500 Message: ${issue.message}`);
|
|
1105
|
+
if (issue.expected) consola.error(` \u251C\u2500 Expected: ${issue.expected}`);
|
|
1106
|
+
if (issue.received) consola.error(` \u2514\u2500 Received: ${issue.received}`);
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
consola.error("Response data:", response);
|
|
1110
|
+
if (typeof window !== "undefined" && error instanceof Error && "issues" in error) {
|
|
1111
|
+
try {
|
|
1112
|
+
const event = new CustomEvent("zod-validation-error", {
|
|
1113
|
+
detail: {
|
|
1114
|
+
operation: "getPaymentsPaymentsRetrieve",
|
|
1115
|
+
path: "/cfg/payments/payments/{id}/",
|
|
1116
|
+
method: "GET",
|
|
1117
|
+
error,
|
|
1118
|
+
response,
|
|
1119
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1120
|
+
},
|
|
1121
|
+
bubbles: true,
|
|
1122
|
+
cancelable: false
|
|
1123
|
+
});
|
|
1124
|
+
window.dispatchEvent(event);
|
|
1125
|
+
} catch (eventError) {
|
|
1126
|
+
consola.warn("Failed to dispatch validation error event:", eventError);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
throw error;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
async function createPaymentsPaymentsConfirmCreate(id, client) {
|
|
1133
|
+
const api = client || getAPIInstance();
|
|
1134
|
+
const response = await api.ext_payments_payments.paymentsConfirmCreate(id);
|
|
1135
|
+
try {
|
|
1136
|
+
return PaymentListSchema.parse(response);
|
|
1137
|
+
} catch (error) {
|
|
1138
|
+
consola.error("\u274C Zod Validation Failed");
|
|
1139
|
+
consola.box(`createPaymentsPaymentsConfirmCreate
|
|
1140
|
+
Path: /cfg/payments/payments/{id}/confirm/
|
|
1141
|
+
Method: POST`);
|
|
1142
|
+
if (error instanceof Error && "issues" in error && Array.isArray(error.issues)) {
|
|
1143
|
+
consola.error("Validation Issues:");
|
|
1144
|
+
error.issues.forEach((issue, index) => {
|
|
1145
|
+
consola.error(` ${index + 1}. ${issue.path.join(".") || "root"}`);
|
|
1146
|
+
consola.error(` \u251C\u2500 Message: ${issue.message}`);
|
|
1147
|
+
if (issue.expected) consola.error(` \u251C\u2500 Expected: ${issue.expected}`);
|
|
1148
|
+
if (issue.received) consola.error(` \u2514\u2500 Received: ${issue.received}`);
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
consola.error("Response data:", response);
|
|
1152
|
+
if (typeof window !== "undefined" && error instanceof Error && "issues" in error) {
|
|
1153
|
+
try {
|
|
1154
|
+
const event = new CustomEvent("zod-validation-error", {
|
|
1155
|
+
detail: {
|
|
1156
|
+
operation: "createPaymentsPaymentsConfirmCreate",
|
|
1157
|
+
path: "/cfg/payments/payments/{id}/confirm/",
|
|
1158
|
+
method: "POST",
|
|
1159
|
+
error,
|
|
1160
|
+
response,
|
|
1161
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1162
|
+
},
|
|
1163
|
+
bubbles: true,
|
|
1164
|
+
cancelable: false
|
|
1165
|
+
});
|
|
1166
|
+
window.dispatchEvent(event);
|
|
1167
|
+
} catch (eventError) {
|
|
1168
|
+
consola.warn("Failed to dispatch validation error event:", eventError);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
throw error;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
async function getPaymentsPaymentsStatusRetrieve(id, client) {
|
|
1175
|
+
const api = client || getAPIInstance();
|
|
1176
|
+
const response = await api.ext_payments_payments.paymentsStatusRetrieve(id);
|
|
1177
|
+
try {
|
|
1178
|
+
return PaymentListSchema.parse(response);
|
|
1179
|
+
} catch (error) {
|
|
1180
|
+
consola.error("\u274C Zod Validation Failed");
|
|
1181
|
+
consola.box(`getPaymentsPaymentsStatusRetrieve
|
|
1182
|
+
Path: /cfg/payments/payments/{id}/status/
|
|
1183
|
+
Method: GET`);
|
|
1184
|
+
if (error instanceof Error && "issues" in error && Array.isArray(error.issues)) {
|
|
1185
|
+
consola.error("Validation Issues:");
|
|
1186
|
+
error.issues.forEach((issue, index) => {
|
|
1187
|
+
consola.error(` ${index + 1}. ${issue.path.join(".") || "root"}`);
|
|
1188
|
+
consola.error(` \u251C\u2500 Message: ${issue.message}`);
|
|
1189
|
+
if (issue.expected) consola.error(` \u251C\u2500 Expected: ${issue.expected}`);
|
|
1190
|
+
if (issue.received) consola.error(` \u2514\u2500 Received: ${issue.received}`);
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
consola.error("Response data:", response);
|
|
1194
|
+
if (typeof window !== "undefined" && error instanceof Error && "issues" in error) {
|
|
1195
|
+
try {
|
|
1196
|
+
const event = new CustomEvent("zod-validation-error", {
|
|
1197
|
+
detail: {
|
|
1198
|
+
operation: "getPaymentsPaymentsStatusRetrieve",
|
|
1199
|
+
path: "/cfg/payments/payments/{id}/status/",
|
|
1200
|
+
method: "GET",
|
|
1201
|
+
error,
|
|
1202
|
+
response,
|
|
1203
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1204
|
+
},
|
|
1205
|
+
bubbles: true,
|
|
1206
|
+
cancelable: false
|
|
1207
|
+
});
|
|
1208
|
+
window.dispatchEvent(event);
|
|
1209
|
+
} catch (eventError) {
|
|
1210
|
+
consola.warn("Failed to dispatch validation error event:", eventError);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
throw error;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
async function createPaymentsPaymentsCreateCreate(client) {
|
|
1217
|
+
const api = client || getAPIInstance();
|
|
1218
|
+
const response = await api.ext_payments_payments.paymentsCreateCreate();
|
|
1219
|
+
try {
|
|
1220
|
+
return PaymentListSchema.parse(response);
|
|
1221
|
+
} catch (error) {
|
|
1222
|
+
consola.error("\u274C Zod Validation Failed");
|
|
1223
|
+
consola.box(`createPaymentsPaymentsCreateCreate
|
|
1224
|
+
Path: /cfg/payments/payments/create/
|
|
1225
|
+
Method: POST`);
|
|
1226
|
+
if (error instanceof Error && "issues" in error && Array.isArray(error.issues)) {
|
|
1227
|
+
consola.error("Validation Issues:");
|
|
1228
|
+
error.issues.forEach((issue, index) => {
|
|
1229
|
+
consola.error(` ${index + 1}. ${issue.path.join(".") || "root"}`);
|
|
1230
|
+
consola.error(` \u251C\u2500 Message: ${issue.message}`);
|
|
1231
|
+
if (issue.expected) consola.error(` \u251C\u2500 Expected: ${issue.expected}`);
|
|
1232
|
+
if (issue.received) consola.error(` \u2514\u2500 Received: ${issue.received}`);
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
consola.error("Response data:", response);
|
|
1236
|
+
if (typeof window !== "undefined" && error instanceof Error && "issues" in error) {
|
|
1237
|
+
try {
|
|
1238
|
+
const event = new CustomEvent("zod-validation-error", {
|
|
1239
|
+
detail: {
|
|
1240
|
+
operation: "createPaymentsPaymentsCreateCreate",
|
|
1241
|
+
path: "/cfg/payments/payments/create/",
|
|
1242
|
+
method: "POST",
|
|
1243
|
+
error,
|
|
1244
|
+
response,
|
|
1245
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1246
|
+
},
|
|
1247
|
+
bubbles: true,
|
|
1248
|
+
cancelable: false
|
|
1249
|
+
});
|
|
1250
|
+
window.dispatchEvent(event);
|
|
1251
|
+
} catch (eventError) {
|
|
1252
|
+
consola.warn("Failed to dispatch validation error event:", eventError);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
throw error;
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
async function getPaymentsTransactionsList(params, client) {
|
|
1259
|
+
const api = client || getAPIInstance();
|
|
1260
|
+
const response = await api.ext_payments_payments.transactionsList(params?.limit, params?.offset, params?.type);
|
|
1261
|
+
return response;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
// src/api/generated/ext_payments/index.ts
|
|
1265
|
+
var TOKEN_KEY = "auth_token";
|
|
1266
|
+
var REFRESH_TOKEN_KEY = "refresh_token";
|
|
1267
|
+
var API = class {
|
|
1268
|
+
baseUrl;
|
|
1269
|
+
_client;
|
|
1270
|
+
_token = null;
|
|
1271
|
+
_refreshToken = null;
|
|
1272
|
+
storage;
|
|
1273
|
+
options;
|
|
1274
|
+
// Sub-clients
|
|
1275
|
+
ext_payments_payments;
|
|
1276
|
+
constructor(baseUrl, options) {
|
|
1277
|
+
this.baseUrl = baseUrl;
|
|
1278
|
+
this.options = options;
|
|
1279
|
+
const logger2 = options?.loggerConfig ? new APILogger(options.loggerConfig) : void 0;
|
|
1280
|
+
this.storage = options?.storage || new LocalStorageAdapter(logger2);
|
|
1281
|
+
this._loadTokensFromStorage();
|
|
1282
|
+
this._client = new APIClient(this.baseUrl, {
|
|
1283
|
+
retryConfig: this.options?.retryConfig,
|
|
1284
|
+
loggerConfig: this.options?.loggerConfig
|
|
1285
|
+
});
|
|
1286
|
+
this._injectAuthHeader();
|
|
1287
|
+
this.ext_payments_payments = this._client.ext_payments_payments;
|
|
1288
|
+
}
|
|
1289
|
+
_loadTokensFromStorage() {
|
|
1290
|
+
this._token = this.storage.getItem(TOKEN_KEY);
|
|
1291
|
+
this._refreshToken = this.storage.getItem(REFRESH_TOKEN_KEY);
|
|
1292
|
+
}
|
|
1293
|
+
_reinitClients() {
|
|
1294
|
+
this._client = new APIClient(this.baseUrl, {
|
|
1295
|
+
retryConfig: this.options?.retryConfig,
|
|
1296
|
+
loggerConfig: this.options?.loggerConfig
|
|
1297
|
+
});
|
|
1298
|
+
this._injectAuthHeader();
|
|
1299
|
+
this.ext_payments_payments = this._client.ext_payments_payments;
|
|
1300
|
+
}
|
|
1301
|
+
_injectAuthHeader() {
|
|
1302
|
+
const originalRequest = this._client.request.bind(this._client);
|
|
1303
|
+
this._client.request = async (method, path, options) => {
|
|
1304
|
+
const token = this.getToken();
|
|
1305
|
+
const mergedOptions = {
|
|
1306
|
+
...options,
|
|
1307
|
+
headers: {
|
|
1308
|
+
...options?.headers || {},
|
|
1309
|
+
...token ? { "Authorization": `Bearer ${token}` } : {}
|
|
1310
|
+
}
|
|
1311
|
+
};
|
|
1312
|
+
return originalRequest(method, path, mergedOptions);
|
|
1313
|
+
};
|
|
1314
|
+
}
|
|
1315
|
+
/**
|
|
1316
|
+
* Get current JWT token
|
|
1317
|
+
*/
|
|
1318
|
+
getToken() {
|
|
1319
|
+
return this.storage.getItem(TOKEN_KEY);
|
|
1320
|
+
}
|
|
1321
|
+
/**
|
|
1322
|
+
* Get current refresh token
|
|
1323
|
+
*/
|
|
1324
|
+
getRefreshToken() {
|
|
1325
|
+
return this.storage.getItem(REFRESH_TOKEN_KEY);
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* Set JWT token and refresh token
|
|
1329
|
+
* @param token - JWT access token
|
|
1330
|
+
* @param refreshToken - JWT refresh token (optional)
|
|
1331
|
+
*/
|
|
1332
|
+
setToken(token, refreshToken) {
|
|
1333
|
+
this._token = token;
|
|
1334
|
+
this.storage.setItem(TOKEN_KEY, token);
|
|
1335
|
+
if (refreshToken) {
|
|
1336
|
+
this._refreshToken = refreshToken;
|
|
1337
|
+
this.storage.setItem(REFRESH_TOKEN_KEY, refreshToken);
|
|
1338
|
+
}
|
|
1339
|
+
this._reinitClients();
|
|
1340
|
+
}
|
|
1341
|
+
/**
|
|
1342
|
+
* Clear all tokens
|
|
1343
|
+
*/
|
|
1344
|
+
clearTokens() {
|
|
1345
|
+
this._token = null;
|
|
1346
|
+
this._refreshToken = null;
|
|
1347
|
+
this.storage.removeItem(TOKEN_KEY);
|
|
1348
|
+
this.storage.removeItem(REFRESH_TOKEN_KEY);
|
|
1349
|
+
this._reinitClients();
|
|
1350
|
+
}
|
|
1351
|
+
/**
|
|
1352
|
+
* Check if user is authenticated
|
|
1353
|
+
*/
|
|
1354
|
+
isAuthenticated() {
|
|
1355
|
+
return !!this.getToken();
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* Update base URL and reinitialize clients
|
|
1359
|
+
* @param url - New base URL
|
|
1360
|
+
*/
|
|
1361
|
+
setBaseUrl(url) {
|
|
1362
|
+
this.baseUrl = url;
|
|
1363
|
+
this._reinitClients();
|
|
1364
|
+
}
|
|
1365
|
+
/**
|
|
1366
|
+
* Get current base URL
|
|
1367
|
+
*/
|
|
1368
|
+
getBaseUrl() {
|
|
1369
|
+
return this.baseUrl;
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Get OpenAPI schema path
|
|
1373
|
+
* @returns Path to the OpenAPI schema JSON file
|
|
1374
|
+
*
|
|
1375
|
+
* Note: The OpenAPI schema is available in the schema.json file.
|
|
1376
|
+
* You can load it dynamically using:
|
|
1377
|
+
* ```typescript
|
|
1378
|
+
* const schema = await fetch('./schema.json').then(r => r.json());
|
|
1379
|
+
* // or using fs in Node.js:
|
|
1380
|
+
* // const schema = JSON.parse(fs.readFileSync('./schema.json', 'utf-8'));
|
|
1381
|
+
* ```
|
|
1382
|
+
*/
|
|
1383
|
+
getSchemaPath() {
|
|
1384
|
+
return "./schema.json";
|
|
1385
|
+
}
|
|
1386
|
+
};
|
|
1387
|
+
var apiPayments = createExtensionAPI(API);
|
|
1388
|
+
function usePaymentsBalanceRetrieve(client) {
|
|
1389
|
+
return useSWR(
|
|
1390
|
+
"cfg-payments-balance",
|
|
1391
|
+
() => getPaymentsBalanceRetrieve(client)
|
|
1392
|
+
);
|
|
1393
|
+
}
|
|
1394
|
+
function usePaymentsCurrenciesList(client) {
|
|
1395
|
+
return useSWR(
|
|
1396
|
+
"cfg-payments-currencies",
|
|
1397
|
+
() => getPaymentsCurrenciesList(client)
|
|
1398
|
+
);
|
|
1399
|
+
}
|
|
1400
|
+
function usePaymentsPaymentsList(params, client) {
|
|
1401
|
+
return useSWR(
|
|
1402
|
+
params ? ["cfg-payments-payments", params] : "cfg-payments-payments",
|
|
1403
|
+
() => getPaymentsPaymentsList(params, client)
|
|
1404
|
+
);
|
|
1405
|
+
}
|
|
1406
|
+
function usePaymentsPaymentsRetrieve(id, client) {
|
|
1407
|
+
return useSWR(
|
|
1408
|
+
["cfg-payments-payment", id],
|
|
1409
|
+
() => getPaymentsPaymentsRetrieve(id, client)
|
|
1410
|
+
);
|
|
1411
|
+
}
|
|
1412
|
+
function useCreatePaymentsPaymentsConfirmCreate() {
|
|
1413
|
+
const { mutate } = useSWRConfig();
|
|
1414
|
+
return async (id, client) => {
|
|
1415
|
+
const result = await createPaymentsPaymentsConfirmCreate(id, client);
|
|
1416
|
+
mutate("cfg-payments-payments-confirm");
|
|
1417
|
+
return result;
|
|
1418
|
+
};
|
|
1419
|
+
}
|
|
1420
|
+
function useCreatePaymentsPaymentsCreateCreate() {
|
|
1421
|
+
const { mutate } = useSWRConfig();
|
|
1422
|
+
return async (client) => {
|
|
1423
|
+
const result = await createPaymentsPaymentsCreateCreate(client);
|
|
1424
|
+
mutate("cfg-payments-payments");
|
|
1425
|
+
return result;
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
function usePaymentsTransactionsList(params, client) {
|
|
1429
|
+
return useSWR(
|
|
1430
|
+
params ? ["cfg-payments-transactions", params] : "cfg-payments-transactions",
|
|
1431
|
+
() => getPaymentsTransactionsList(params, client)
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
var PaymentsContext = createContext(void 0);
|
|
1435
|
+
function PaymentsProvider({ children }) {
|
|
1436
|
+
const {
|
|
1437
|
+
data: payments,
|
|
1438
|
+
error: paymentsError,
|
|
1439
|
+
isLoading: isLoadingPayments,
|
|
1440
|
+
mutate: mutatePayments
|
|
1441
|
+
} = usePaymentsPaymentsList({ page: 1, page_size: 1 }, apiPayments);
|
|
1442
|
+
const refreshPayments = async () => {
|
|
1443
|
+
await mutatePayments();
|
|
1444
|
+
};
|
|
1445
|
+
const createPaymentMutation = useCreatePaymentsPaymentsCreateCreate();
|
|
1446
|
+
const confirmPaymentMutation = useCreatePaymentsPaymentsConfirmCreate();
|
|
1447
|
+
const getPayment = async (id) => {
|
|
1448
|
+
return getPaymentsPaymentsRetrieve(id, apiPayments);
|
|
1449
|
+
};
|
|
1450
|
+
const createPayment = async () => {
|
|
1451
|
+
const result = await createPaymentMutation(apiPayments);
|
|
1452
|
+
await refreshPayments();
|
|
1453
|
+
return result;
|
|
1454
|
+
};
|
|
1455
|
+
const confirmPayment = async (id) => {
|
|
1456
|
+
const result = await confirmPaymentMutation(id, apiPayments);
|
|
1457
|
+
await refreshPayments();
|
|
1458
|
+
return result;
|
|
1459
|
+
};
|
|
1460
|
+
const checkPaymentStatus = async (id) => {
|
|
1461
|
+
return getPaymentsPaymentsStatusRetrieve(id, apiPayments);
|
|
1462
|
+
};
|
|
1463
|
+
const value = {
|
|
1464
|
+
payments,
|
|
1465
|
+
isLoadingPayments,
|
|
1466
|
+
paymentsError,
|
|
1467
|
+
refreshPayments,
|
|
1468
|
+
getPayment,
|
|
1469
|
+
createPayment,
|
|
1470
|
+
confirmPayment,
|
|
1471
|
+
checkPaymentStatus
|
|
1472
|
+
};
|
|
1473
|
+
return /* @__PURE__ */ jsx(PaymentsContext.Provider, { value, children });
|
|
1474
|
+
}
|
|
1475
|
+
function usePaymentsContext() {
|
|
1476
|
+
const context = useContext(PaymentsContext);
|
|
1477
|
+
if (!context) {
|
|
1478
|
+
throw new Error("usePaymentsContext must be used within PaymentsProvider");
|
|
1479
|
+
}
|
|
1480
|
+
return context;
|
|
1481
|
+
}
|
|
1482
|
+
createContext(void 0);
|
|
1483
|
+
createContext(void 0);
|
|
1484
|
+
var OverviewContext = createContext(void 0);
|
|
1485
|
+
function OverviewProvider({ children }) {
|
|
1486
|
+
const swrConfig = {
|
|
1487
|
+
revalidateOnFocus: false,
|
|
1488
|
+
revalidateOnReconnect: false,
|
|
1489
|
+
revalidateIfStale: false
|
|
1490
|
+
};
|
|
1491
|
+
const {
|
|
1492
|
+
data: balance,
|
|
1493
|
+
error: balanceError,
|
|
1494
|
+
isLoading: isLoadingBalance,
|
|
1495
|
+
mutate: mutateBalance
|
|
1496
|
+
} = usePaymentsBalanceRetrieve(apiPayments);
|
|
1497
|
+
const {
|
|
1498
|
+
data: payments,
|
|
1499
|
+
error: paymentsError,
|
|
1500
|
+
isLoading: isLoadingPayments,
|
|
1501
|
+
mutate: mutatePayments
|
|
1502
|
+
} = usePaymentsPaymentsList({}, apiPayments);
|
|
1503
|
+
const {
|
|
1504
|
+
data: transactions,
|
|
1505
|
+
error: transactionsError,
|
|
1506
|
+
isLoading: isLoadingTransactions,
|
|
1507
|
+
mutate: mutateTransactions
|
|
1508
|
+
} = usePaymentsTransactionsList({}, apiPayments);
|
|
1509
|
+
const createPaymentMutation = useCreatePaymentsPaymentsCreateCreate();
|
|
1510
|
+
const isLoadingOverview = isLoadingBalance || isLoadingPayments || isLoadingTransactions;
|
|
1511
|
+
const overviewError = balanceError || paymentsError || transactionsError;
|
|
1512
|
+
const refreshBalance = async () => {
|
|
1513
|
+
await mutateBalance();
|
|
1514
|
+
};
|
|
1515
|
+
const refreshPayments = async () => {
|
|
1516
|
+
await mutatePayments();
|
|
1517
|
+
};
|
|
1518
|
+
const refreshTransactions = async () => {
|
|
1519
|
+
await mutateTransactions();
|
|
1520
|
+
};
|
|
1521
|
+
const refreshOverview = async () => {
|
|
1522
|
+
await Promise.all([
|
|
1523
|
+
mutateBalance(),
|
|
1524
|
+
mutatePayments(),
|
|
1525
|
+
mutateTransactions()
|
|
1526
|
+
]);
|
|
1527
|
+
};
|
|
1528
|
+
const createPayment = async () => {
|
|
1529
|
+
const result = await createPaymentMutation(apiPayments);
|
|
1530
|
+
await refreshOverview();
|
|
1531
|
+
return result;
|
|
1532
|
+
};
|
|
1533
|
+
const value = {
|
|
1534
|
+
balance,
|
|
1535
|
+
isLoadingBalance,
|
|
1536
|
+
balanceError,
|
|
1537
|
+
refreshBalance,
|
|
1538
|
+
payments,
|
|
1539
|
+
isLoadingPayments,
|
|
1540
|
+
paymentsError,
|
|
1541
|
+
refreshPayments,
|
|
1542
|
+
transactions,
|
|
1543
|
+
isLoadingTransactions,
|
|
1544
|
+
transactionsError,
|
|
1545
|
+
refreshTransactions,
|
|
1546
|
+
createPayment,
|
|
1547
|
+
isLoadingOverview,
|
|
1548
|
+
overviewError,
|
|
1549
|
+
refreshOverview
|
|
1550
|
+
};
|
|
1551
|
+
return /* @__PURE__ */ jsx(SWRConfig, { value: swrConfig, children: /* @__PURE__ */ jsx(OverviewContext.Provider, { value, children }) });
|
|
1552
|
+
}
|
|
1553
|
+
function useOverviewContext() {
|
|
1554
|
+
const context = useContext(OverviewContext);
|
|
1555
|
+
if (!context) {
|
|
1556
|
+
throw new Error("useOverviewContext must be used within OverviewProvider");
|
|
1557
|
+
}
|
|
1558
|
+
return context;
|
|
1559
|
+
}
|
|
1560
|
+
var RootPaymentsContext = createContext(void 0);
|
|
1561
|
+
function RootPaymentsProvider({ children }) {
|
|
1562
|
+
const {
|
|
1563
|
+
data: currencies,
|
|
1564
|
+
error: currenciesError,
|
|
1565
|
+
isLoading: isLoadingCurrencies,
|
|
1566
|
+
mutate: mutateCurrencies
|
|
1567
|
+
} = usePaymentsCurrenciesList(apiPayments);
|
|
1568
|
+
const refreshCurrencies = async () => {
|
|
1569
|
+
await mutateCurrencies();
|
|
1570
|
+
};
|
|
1571
|
+
const value = {
|
|
1572
|
+
currencies,
|
|
1573
|
+
isLoadingCurrencies,
|
|
1574
|
+
currenciesError,
|
|
1575
|
+
refreshCurrencies
|
|
1576
|
+
};
|
|
1577
|
+
return /* @__PURE__ */ jsx(RootPaymentsContext.Provider, { value, children });
|
|
1578
|
+
}
|
|
1579
|
+
function useRootPaymentsContext() {
|
|
1580
|
+
const context = useContext(RootPaymentsContext);
|
|
1581
|
+
if (!context) {
|
|
1582
|
+
throw new Error("useRootPaymentsContext must be used within RootPaymentsProvider");
|
|
1583
|
+
}
|
|
1584
|
+
return context;
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
// src/layouts/PaymentsLayout/events.ts
|
|
1588
|
+
var PAYMENT_EVENTS = {
|
|
1589
|
+
OPEN_CREATE_PAYMENT_DIALOG: "payments:open-create-payment",
|
|
1590
|
+
OPEN_PAYMENT_DETAILS_DIALOG: "payments:open-payment-details",
|
|
1591
|
+
CLOSE_DIALOG: "payments:close-dialog"
|
|
1592
|
+
};
|
|
1593
|
+
var openCreatePaymentDialog = () => {
|
|
1594
|
+
window.dispatchEvent(new Event(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG));
|
|
1595
|
+
};
|
|
1596
|
+
var openPaymentDetailsDialog = (id) => {
|
|
1597
|
+
window.dispatchEvent(
|
|
1598
|
+
new CustomEvent(PAYMENT_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG, {
|
|
1599
|
+
detail: { id }
|
|
1600
|
+
})
|
|
1601
|
+
);
|
|
1602
|
+
};
|
|
1603
|
+
var closePaymentsDialog = () => {
|
|
1604
|
+
window.dispatchEvent(new Event(PAYMENT_EVENTS.CLOSE_DIALOG));
|
|
1605
|
+
};
|
|
1606
|
+
var BalanceCard = () => {
|
|
1607
|
+
const {
|
|
1608
|
+
balance,
|
|
1609
|
+
isLoadingBalance,
|
|
1610
|
+
refreshBalance
|
|
1611
|
+
} = useOverviewContext();
|
|
1612
|
+
const formatCurrency = (amount) => {
|
|
1613
|
+
if (amount === null || amount === void 0) return "$0.00";
|
|
1614
|
+
return new Intl.NumberFormat("en-US", {
|
|
1615
|
+
style: "currency",
|
|
1616
|
+
currency: "USD",
|
|
1617
|
+
minimumFractionDigits: 2
|
|
1618
|
+
}).format(amount);
|
|
1619
|
+
};
|
|
1620
|
+
const formatDate = (dateStr) => {
|
|
1621
|
+
if (!dateStr) return "No transactions yet";
|
|
1622
|
+
try {
|
|
1623
|
+
return new Date(dateStr).toLocaleDateString("en-US", {
|
|
1624
|
+
year: "numeric",
|
|
1625
|
+
month: "short",
|
|
1626
|
+
day: "numeric"
|
|
1627
|
+
});
|
|
1628
|
+
} catch {
|
|
1629
|
+
return "Invalid date";
|
|
1630
|
+
}
|
|
1631
|
+
};
|
|
1632
|
+
if (isLoadingBalance) {
|
|
1633
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
1634
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center justify-between", children: [
|
|
1635
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1636
|
+
/* @__PURE__ */ jsx(Wallet, { className: "h-5 w-5" }),
|
|
1637
|
+
"Account Balance"
|
|
1638
|
+
] }),
|
|
1639
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-20" })
|
|
1640
|
+
] }) }),
|
|
1641
|
+
/* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
|
|
1642
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-32" }),
|
|
1643
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" })
|
|
1644
|
+
] })
|
|
1645
|
+
] });
|
|
1646
|
+
}
|
|
1647
|
+
const balanceData = balance?.balance || balance;
|
|
1648
|
+
const amountUsd = balanceData?.amount_usd ?? 0;
|
|
1649
|
+
const totalDeposited = balanceData?.total_deposited ?? 0;
|
|
1650
|
+
const totalWithdrawn = balanceData?.total_withdrawn ?? 0;
|
|
1651
|
+
const lastTransactionAt = balanceData?.last_transaction_at;
|
|
1652
|
+
const isEmpty = amountUsd === 0 && totalDeposited === 0;
|
|
1653
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
1654
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center justify-between", children: [
|
|
1655
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1656
|
+
/* @__PURE__ */ jsx(Wallet, { className: "h-5 w-5" }),
|
|
1657
|
+
"Account Balance"
|
|
1658
|
+
] }),
|
|
1659
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1660
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: refreshBalance, children: /* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4" }) }),
|
|
1661
|
+
/* @__PURE__ */ jsxs(Button, { size: "sm", onClick: () => openCreatePaymentDialog(), children: [
|
|
1662
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
|
|
1663
|
+
"Add Funds"
|
|
1664
|
+
] })
|
|
1665
|
+
] })
|
|
1666
|
+
] }) }),
|
|
1667
|
+
/* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
|
|
1668
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1669
|
+
/* @__PURE__ */ jsx("div", { className: "text-4xl font-bold", children: formatCurrency(amountUsd) }),
|
|
1670
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground mt-1", children: [
|
|
1671
|
+
"Available balance \u2022 Last updated ",
|
|
1672
|
+
formatDate(lastTransactionAt)
|
|
1673
|
+
] })
|
|
1674
|
+
] }),
|
|
1675
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4 pt-4 border-t", children: [
|
|
1676
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1677
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Total Deposited" }),
|
|
1678
|
+
/* @__PURE__ */ jsx("p", { className: "text-lg font-semibold text-green-600", children: formatCurrency(totalDeposited) })
|
|
1679
|
+
] }),
|
|
1680
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1681
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Total Withdrawn" }),
|
|
1682
|
+
/* @__PURE__ */ jsx("p", { className: "text-lg font-semibold text-red-600", children: formatCurrency(totalWithdrawn) })
|
|
1683
|
+
] })
|
|
1684
|
+
] }),
|
|
1685
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1686
|
+
/* @__PURE__ */ jsx(Badge, { variant: !isEmpty ? "default" : "secondary", children: !isEmpty ? "Active" : "New Account" }),
|
|
1687
|
+
isEmpty && /* @__PURE__ */ jsx(Badge, { variant: "outline", children: "Empty Balance" })
|
|
1688
|
+
] })
|
|
1689
|
+
] })
|
|
1690
|
+
] });
|
|
1691
|
+
};
|
|
1692
|
+
var RecentPayments = () => {
|
|
1693
|
+
const { payments, isLoadingPayments } = useOverviewContext();
|
|
1694
|
+
const formatCurrency = (amount) => {
|
|
1695
|
+
if (amount === null || amount === void 0) return "$0.00";
|
|
1696
|
+
const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
|
|
1697
|
+
return new Intl.NumberFormat("en-US", {
|
|
1698
|
+
style: "currency",
|
|
1699
|
+
currency: "USD",
|
|
1700
|
+
minimumFractionDigits: 2
|
|
1701
|
+
}).format(numAmount);
|
|
1702
|
+
};
|
|
1703
|
+
const getRelativeTime = (date) => {
|
|
1704
|
+
if (!date) return "N/A";
|
|
1705
|
+
const now = /* @__PURE__ */ new Date();
|
|
1706
|
+
const target = new Date(date);
|
|
1707
|
+
const diffInSeconds = Math.floor((now.getTime() - target.getTime()) / 1e3);
|
|
1708
|
+
if (diffInSeconds < 60) return "Just now";
|
|
1709
|
+
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
|
|
1710
|
+
if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
|
|
1711
|
+
return `${Math.floor(diffInSeconds / 86400)}d ago`;
|
|
1712
|
+
};
|
|
1713
|
+
const getStatusVariant = (status) => {
|
|
1714
|
+
switch (status?.toLowerCase()) {
|
|
1715
|
+
case "completed":
|
|
1716
|
+
case "success":
|
|
1717
|
+
return "default";
|
|
1718
|
+
case "pending":
|
|
1719
|
+
case "confirming":
|
|
1720
|
+
return "secondary";
|
|
1721
|
+
case "failed":
|
|
1722
|
+
case "error":
|
|
1723
|
+
case "expired":
|
|
1724
|
+
return "destructive";
|
|
1725
|
+
default:
|
|
1726
|
+
return "outline";
|
|
1727
|
+
}
|
|
1728
|
+
};
|
|
1729
|
+
if (isLoadingPayments) {
|
|
1730
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
1731
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2", children: [
|
|
1732
|
+
/* @__PURE__ */ jsx(History, { className: "h-5 w-5" }),
|
|
1733
|
+
"Recent Payments"
|
|
1734
|
+
] }) }),
|
|
1735
|
+
/* @__PURE__ */ jsx(CardContent, { className: "space-y-3", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-3 border rounded-sm", children: [
|
|
1736
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
1737
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" }),
|
|
1738
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" })
|
|
1739
|
+
] }),
|
|
1740
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-16" })
|
|
1741
|
+
] }, i)) })
|
|
1742
|
+
] });
|
|
1743
|
+
}
|
|
1744
|
+
const recentPaymentsList = payments?.results?.slice(0, 5) || [];
|
|
1745
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
1746
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center justify-between", children: [
|
|
1747
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1748
|
+
/* @__PURE__ */ jsx(History, { className: "h-5 w-5" }),
|
|
1749
|
+
"Recent Payments"
|
|
1750
|
+
] }),
|
|
1751
|
+
/* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", children: [
|
|
1752
|
+
"View All",
|
|
1753
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4 ml-2" })
|
|
1754
|
+
] })
|
|
1755
|
+
] }) }),
|
|
1756
|
+
/* @__PURE__ */ jsx(CardContent, { children: recentPaymentsList.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-8 text-muted-foreground", children: [
|
|
1757
|
+
/* @__PURE__ */ jsx(History, { className: "h-12 w-12 mx-auto mb-4 opacity-50" }),
|
|
1758
|
+
/* @__PURE__ */ jsx("p", { children: "No recent payments" }),
|
|
1759
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm mt-2", children: "Create your first payment to get started" })
|
|
1760
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "space-y-3", children: recentPaymentsList.map((payment) => /* @__PURE__ */ jsxs(
|
|
1761
|
+
"div",
|
|
1762
|
+
{
|
|
1763
|
+
className: "flex items-center justify-between p-3 border rounded-sm hover:bg-accent cursor-pointer transition-colors",
|
|
1764
|
+
onClick: () => openPaymentDetailsDialog(String(payment.id)),
|
|
1765
|
+
children: [
|
|
1766
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
1767
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1768
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: formatCurrency(payment.amount_usd) }),
|
|
1769
|
+
/* @__PURE__ */ jsx(Badge, { variant: getStatusVariant(payment.status), className: "text-xs", children: payment.status })
|
|
1770
|
+
] }),
|
|
1771
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
|
|
1772
|
+
getRelativeTime(payment.created_at),
|
|
1773
|
+
" \u2022 ",
|
|
1774
|
+
payment.currency_code || "USD"
|
|
1775
|
+
] })
|
|
1776
|
+
] }),
|
|
1777
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4 text-muted-foreground" })
|
|
1778
|
+
]
|
|
1779
|
+
},
|
|
1780
|
+
payment.id
|
|
1781
|
+
)) }) })
|
|
1782
|
+
] });
|
|
1783
|
+
};
|
|
1784
|
+
var OverviewView = () => {
|
|
1785
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsxs("div", { className: "grid gap-6 lg:grid-cols-2", children: [
|
|
1786
|
+
/* @__PURE__ */ jsx(BalanceCard, {}),
|
|
1787
|
+
/* @__PURE__ */ jsx(RecentPayments, {})
|
|
1788
|
+
] }) });
|
|
1789
|
+
};
|
|
1790
|
+
var PaymentsList = () => {
|
|
1791
|
+
const pagination = useDRFPagination(1, 20);
|
|
1792
|
+
const {
|
|
1793
|
+
data: payments,
|
|
1794
|
+
error,
|
|
1795
|
+
isLoading: isLoadingPayments,
|
|
1796
|
+
mutate: refreshPayments
|
|
1797
|
+
} = usePaymentsPaymentsList(pagination.params, apiPayments);
|
|
1798
|
+
const paymentsList = payments?.results || [];
|
|
1799
|
+
payments?.count || 0;
|
|
1800
|
+
const [searchTerm, setSearchTerm] = useState("");
|
|
1801
|
+
const [statusFilter, setStatusFilter] = useState("all");
|
|
1802
|
+
const formatCurrency = (amount) => {
|
|
1803
|
+
if (amount === null || amount === void 0) return "$0.00";
|
|
1804
|
+
const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
|
|
1805
|
+
return new Intl.NumberFormat("en-US", {
|
|
1806
|
+
style: "currency",
|
|
1807
|
+
currency: "USD",
|
|
1808
|
+
minimumFractionDigits: 2
|
|
1809
|
+
}).format(numAmount);
|
|
1810
|
+
};
|
|
1811
|
+
const getRelativeTime = (date) => {
|
|
1812
|
+
if (!date) return "N/A";
|
|
1813
|
+
const now = /* @__PURE__ */ new Date();
|
|
1814
|
+
const target = new Date(date);
|
|
1815
|
+
const diffInSeconds = Math.floor((now.getTime() - target.getTime()) / 1e3);
|
|
1816
|
+
if (diffInSeconds < 60) return "Just now";
|
|
1817
|
+
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
|
|
1818
|
+
if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
|
|
1819
|
+
return `${Math.floor(diffInSeconds / 86400)}d ago`;
|
|
1820
|
+
};
|
|
1821
|
+
const getStatusVariant = (status) => {
|
|
1822
|
+
switch (status?.toLowerCase()) {
|
|
1823
|
+
case "completed":
|
|
1824
|
+
case "success":
|
|
1825
|
+
return "default";
|
|
1826
|
+
case "pending":
|
|
1827
|
+
case "confirming":
|
|
1828
|
+
return "secondary";
|
|
1829
|
+
case "failed":
|
|
1830
|
+
case "error":
|
|
1831
|
+
case "expired":
|
|
1832
|
+
return "destructive";
|
|
1833
|
+
default:
|
|
1834
|
+
return "outline";
|
|
1835
|
+
}
|
|
1836
|
+
};
|
|
1837
|
+
const handleSearch = (value) => {
|
|
1838
|
+
setSearchTerm(value);
|
|
1839
|
+
};
|
|
1840
|
+
const handleStatusFilter = (status) => {
|
|
1841
|
+
setStatusFilter(status);
|
|
1842
|
+
};
|
|
1843
|
+
const filteredPayments = paymentsList.filter((payment) => {
|
|
1844
|
+
const matchesSearch = searchTerm ? payment.id?.toLowerCase().includes(searchTerm.toLowerCase()) || payment.status?.toLowerCase().includes(searchTerm.toLowerCase()) || payment.currency_code?.toLowerCase().includes(searchTerm.toLowerCase()) : true;
|
|
1845
|
+
const matchesStatus = statusFilter !== "all" ? payment.status?.toLowerCase() === statusFilter.toLowerCase() : true;
|
|
1846
|
+
return matchesSearch && matchesStatus;
|
|
1847
|
+
});
|
|
1848
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
1849
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center justify-between", children: [
|
|
1850
|
+
/* @__PURE__ */ jsx("span", { children: "Payment History" }),
|
|
1851
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1852
|
+
/* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: () => refreshPayments(), disabled: isLoadingPayments, children: [
|
|
1853
|
+
/* @__PURE__ */ jsx(RefreshCw, { className: `h-4 w-4 mr-2 ${isLoadingPayments ? "animate-spin" : ""}` }),
|
|
1854
|
+
"Refresh"
|
|
1855
|
+
] }),
|
|
1856
|
+
/* @__PURE__ */ jsxs(Button, { size: "sm", onClick: () => openCreatePaymentDialog(), children: [
|
|
1857
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
|
|
1858
|
+
"New Payment"
|
|
1859
|
+
] })
|
|
1860
|
+
] })
|
|
1861
|
+
] }) }),
|
|
1862
|
+
/* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
|
|
1863
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row gap-4", children: [
|
|
1864
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
|
|
1865
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
|
|
1866
|
+
/* @__PURE__ */ jsx(
|
|
1867
|
+
Input,
|
|
1868
|
+
{
|
|
1869
|
+
placeholder: "Search by ID, status, or currency...",
|
|
1870
|
+
value: searchTerm,
|
|
1871
|
+
onChange: (e) => handleSearch(e.target.value),
|
|
1872
|
+
className: "pl-10"
|
|
1873
|
+
}
|
|
1874
|
+
)
|
|
1875
|
+
] }),
|
|
1876
|
+
/* @__PURE__ */ jsxs(Select, { value: statusFilter, onValueChange: handleStatusFilter, children: [
|
|
1877
|
+
/* @__PURE__ */ jsxs(SelectTrigger, { className: "w-full sm:w-48", children: [
|
|
1878
|
+
/* @__PURE__ */ jsx(Filter, { className: "h-4 w-4 mr-2" }),
|
|
1879
|
+
/* @__PURE__ */ jsx(SelectValue, { placeholder: "Filter by status" })
|
|
1880
|
+
] }),
|
|
1881
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
1882
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "all", children: "All Statuses" }),
|
|
1883
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "completed", children: "Completed" }),
|
|
1884
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "pending", children: "Pending" }),
|
|
1885
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "confirming", children: "Confirming" }),
|
|
1886
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "failed", children: "Failed" }),
|
|
1887
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "expired", children: "Expired" })
|
|
1888
|
+
] })
|
|
1889
|
+
] })
|
|
1890
|
+
] }),
|
|
1891
|
+
isLoadingPayments ? /* @__PURE__ */ jsx("div", { className: "space-y-3", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 border rounded-sm", children: [
|
|
1892
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
1893
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" }),
|
|
1894
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" })
|
|
1895
|
+
] }),
|
|
1896
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-16" })
|
|
1897
|
+
] }, i)) }) : filteredPayments.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-12", children: [
|
|
1898
|
+
/* @__PURE__ */ jsx("div", { className: "w-16 h-16 mx-auto mb-4 bg-muted rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsx(Search, { className: "w-8 h-8 text-muted-foreground" }) }),
|
|
1899
|
+
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: "No Payments Found" }),
|
|
1900
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground mb-4", children: searchTerm || statusFilter !== "all" ? "No payments match your current filters" : "You haven't made any payments yet" }),
|
|
1901
|
+
/* @__PURE__ */ jsxs(Button, { onClick: () => openCreatePaymentDialog(), children: [
|
|
1902
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
|
|
1903
|
+
"Create Payment"
|
|
1904
|
+
] })
|
|
1905
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1906
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs(Table, { children: [
|
|
1907
|
+
/* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
|
|
1908
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Date" }),
|
|
1909
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Amount" }),
|
|
1910
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Currency" }),
|
|
1911
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Status" }),
|
|
1912
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Provider" }),
|
|
1913
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Payment ID" }),
|
|
1914
|
+
/* @__PURE__ */ jsx(TableHead, { className: "text-right", children: "Actions" })
|
|
1915
|
+
] }) }),
|
|
1916
|
+
/* @__PURE__ */ jsx(TableBody, { children: filteredPayments.map((payment) => /* @__PURE__ */ jsxs(
|
|
1917
|
+
TableRow,
|
|
1918
|
+
{
|
|
1919
|
+
className: "cursor-pointer hover:bg-accent",
|
|
1920
|
+
onClick: () => openPaymentDetailsDialog(String(payment.id)),
|
|
1921
|
+
children: [
|
|
1922
|
+
/* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsxs("div", { children: [
|
|
1923
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium", children: payment.created_at ? new Date(payment.created_at).toLocaleDateString() : "N/A" }),
|
|
1924
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: getRelativeTime(payment.created_at) })
|
|
1925
|
+
] }) }),
|
|
1926
|
+
/* @__PURE__ */ jsx(TableCell, { className: "font-mono font-semibold", children: formatCurrency(payment.amount_usd) }),
|
|
1927
|
+
/* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Badge, { variant: "outline", children: payment.currency_code || "USD" }) }),
|
|
1928
|
+
/* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Badge, { variant: getStatusVariant(payment.status), children: payment.status }) }),
|
|
1929
|
+
/* @__PURE__ */ jsx(TableCell, { className: "text-sm text-muted-foreground", children: "NowPayments" }),
|
|
1930
|
+
/* @__PURE__ */ jsx(TableCell, { className: "font-mono text-sm text-muted-foreground", children: payment.id ? `${payment.id.toString().slice(0, 8)}...` : "N/A" }),
|
|
1931
|
+
/* @__PURE__ */ jsx(TableCell, { className: "text-right", children: /* @__PURE__ */ jsx(
|
|
1932
|
+
Button,
|
|
1933
|
+
{
|
|
1934
|
+
variant: "ghost",
|
|
1935
|
+
size: "sm",
|
|
1936
|
+
onClick: (e) => {
|
|
1937
|
+
e.stopPropagation();
|
|
1938
|
+
openPaymentDetailsDialog(String(payment.id));
|
|
1939
|
+
},
|
|
1940
|
+
children: /* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4" })
|
|
1941
|
+
}
|
|
1942
|
+
) })
|
|
1943
|
+
]
|
|
1944
|
+
},
|
|
1945
|
+
payment.id
|
|
1946
|
+
)) })
|
|
1947
|
+
] }) }),
|
|
1948
|
+
/* @__PURE__ */ jsx(
|
|
1949
|
+
StaticPagination,
|
|
1950
|
+
{
|
|
1951
|
+
data: payments,
|
|
1952
|
+
onPageChange: pagination.setPage,
|
|
1953
|
+
className: "mt-4"
|
|
1954
|
+
}
|
|
1955
|
+
)
|
|
1956
|
+
] })
|
|
1957
|
+
] })
|
|
1958
|
+
] });
|
|
1959
|
+
};
|
|
1960
|
+
var PaymentsView = () => {
|
|
1961
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsx(PaymentsList, {}) });
|
|
1962
|
+
};
|
|
1963
|
+
var TransactionsList = () => {
|
|
1964
|
+
const {
|
|
1965
|
+
transactions,
|
|
1966
|
+
isLoadingTransactions,
|
|
1967
|
+
refreshTransactions
|
|
1968
|
+
} = useOverviewContext();
|
|
1969
|
+
const [searchTerm, setSearchTerm] = useState("");
|
|
1970
|
+
const [typeFilter, setTypeFilter] = useState("all");
|
|
1971
|
+
const transactionsList = transactions?.results || transactions?.transactions || [];
|
|
1972
|
+
const formatCurrency = (amount) => {
|
|
1973
|
+
if (amount === null || amount === void 0) return "$0.00";
|
|
1974
|
+
return new Intl.NumberFormat("en-US", {
|
|
1975
|
+
style: "currency",
|
|
1976
|
+
currency: "USD",
|
|
1977
|
+
minimumFractionDigits: 2
|
|
1978
|
+
}).format(amount);
|
|
1979
|
+
};
|
|
1980
|
+
const formatDate = (date) => {
|
|
1981
|
+
if (!date) return "N/A";
|
|
1982
|
+
try {
|
|
1983
|
+
return new Date(date).toLocaleString("en-US", {
|
|
1984
|
+
year: "numeric",
|
|
1985
|
+
month: "short",
|
|
1986
|
+
day: "numeric",
|
|
1987
|
+
hour: "2-digit",
|
|
1988
|
+
minute: "2-digit"
|
|
1989
|
+
});
|
|
1990
|
+
} catch {
|
|
1991
|
+
return "Invalid date";
|
|
1992
|
+
}
|
|
1993
|
+
};
|
|
1994
|
+
const getRelativeTime = (date) => {
|
|
1995
|
+
if (!date) return "N/A";
|
|
1996
|
+
const now = /* @__PURE__ */ new Date();
|
|
1997
|
+
const target = new Date(date);
|
|
1998
|
+
const diffInSeconds = Math.floor((now.getTime() - target.getTime()) / 1e3);
|
|
1999
|
+
if (diffInSeconds < 60) return "Just now";
|
|
2000
|
+
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
|
|
2001
|
+
if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
|
|
2002
|
+
return `${Math.floor(diffInSeconds / 86400)}d ago`;
|
|
2003
|
+
};
|
|
2004
|
+
const getTypeVariant = (type) => {
|
|
2005
|
+
switch (type?.toLowerCase()) {
|
|
2006
|
+
case "deposit":
|
|
2007
|
+
case "credit":
|
|
2008
|
+
return "default";
|
|
2009
|
+
case "withdrawal":
|
|
2010
|
+
case "debit":
|
|
2011
|
+
return "destructive";
|
|
2012
|
+
default:
|
|
2013
|
+
return "outline";
|
|
2014
|
+
}
|
|
2015
|
+
};
|
|
2016
|
+
const getTypeIcon = (type) => {
|
|
2017
|
+
const isDeposit = type?.toLowerCase() === "deposit" || type?.toLowerCase() === "credit";
|
|
2018
|
+
return isDeposit ? /* @__PURE__ */ jsx(ArrowDownLeft, { className: "h-4 w-4 text-green-600" }) : /* @__PURE__ */ jsx(ArrowUpRight, { className: "h-4 w-4 text-red-600" });
|
|
2019
|
+
};
|
|
2020
|
+
const handleSearch = async (value) => {
|
|
2021
|
+
setSearchTerm(value);
|
|
2022
|
+
await refreshTransactions();
|
|
2023
|
+
};
|
|
2024
|
+
const handleTypeFilter = async (type) => {
|
|
2025
|
+
setTypeFilter(type);
|
|
2026
|
+
await refreshTransactions();
|
|
2027
|
+
};
|
|
2028
|
+
const filteredTransactions = transactionsList.filter((transaction) => {
|
|
2029
|
+
const matchesSearch = searchTerm ? transaction.id?.toString().toLowerCase().includes(searchTerm.toLowerCase()) || transaction.description?.toLowerCase().includes(searchTerm.toLowerCase()) || transaction.type?.toLowerCase().includes(searchTerm.toLowerCase()) : true;
|
|
2030
|
+
const matchesType = typeFilter !== "all" ? transaction.type?.toLowerCase() === typeFilter.toLowerCase() : true;
|
|
2031
|
+
return matchesSearch && matchesType;
|
|
2032
|
+
});
|
|
2033
|
+
if (isLoadingTransactions) {
|
|
2034
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
2035
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2", children: [
|
|
2036
|
+
/* @__PURE__ */ jsx(History, { className: "h-5 w-5" }),
|
|
2037
|
+
"Transaction History"
|
|
2038
|
+
] }) }),
|
|
2039
|
+
/* @__PURE__ */ jsx(CardContent, { className: "space-y-3", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 border rounded-sm", children: [
|
|
2040
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
2041
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" }),
|
|
2042
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" })
|
|
2043
|
+
] }),
|
|
2044
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-16" })
|
|
2045
|
+
] }, i)) })
|
|
2046
|
+
] });
|
|
2047
|
+
}
|
|
2048
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
2049
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center justify-between", children: [
|
|
2050
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2051
|
+
/* @__PURE__ */ jsx(History, { className: "h-5 w-5" }),
|
|
2052
|
+
"Transaction History"
|
|
2053
|
+
] }),
|
|
2054
|
+
/* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: refreshTransactions, disabled: isLoadingTransactions, children: [
|
|
2055
|
+
/* @__PURE__ */ jsx(RefreshCw, { className: `h-4 w-4 mr-2 ${isLoadingTransactions ? "animate-spin" : ""}` }),
|
|
2056
|
+
"Refresh"
|
|
2057
|
+
] })
|
|
2058
|
+
] }) }),
|
|
2059
|
+
/* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
|
|
2060
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row gap-4", children: [
|
|
2061
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
|
|
2062
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
|
|
2063
|
+
/* @__PURE__ */ jsx(
|
|
2064
|
+
Input,
|
|
2065
|
+
{
|
|
2066
|
+
placeholder: "Search by ID, description, or type...",
|
|
2067
|
+
value: searchTerm,
|
|
2068
|
+
onChange: (e) => handleSearch(e.target.value),
|
|
2069
|
+
className: "pl-10"
|
|
2070
|
+
}
|
|
2071
|
+
)
|
|
2072
|
+
] }),
|
|
2073
|
+
/* @__PURE__ */ jsxs(Select, { value: typeFilter, onValueChange: handleTypeFilter, children: [
|
|
2074
|
+
/* @__PURE__ */ jsxs(SelectTrigger, { className: "w-full sm:w-48", children: [
|
|
2075
|
+
/* @__PURE__ */ jsx(Filter, { className: "h-4 w-4 mr-2" }),
|
|
2076
|
+
/* @__PURE__ */ jsx(SelectValue, { placeholder: "Filter by type" })
|
|
2077
|
+
] }),
|
|
2078
|
+
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
2079
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "all", children: "All Types" }),
|
|
2080
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "deposit", children: "Deposits" }),
|
|
2081
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "withdrawal", children: "Withdrawals" })
|
|
2082
|
+
] })
|
|
2083
|
+
] })
|
|
2084
|
+
] }),
|
|
2085
|
+
filteredTransactions.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-12", children: [
|
|
2086
|
+
/* @__PURE__ */ jsx("div", { className: "w-16 h-16 mx-auto mb-4 bg-muted rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsx(History, { className: "w-8 h-8 text-muted-foreground" }) }),
|
|
2087
|
+
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: "No Transactions Found" }),
|
|
2088
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: searchTerm || typeFilter !== "all" ? "No transactions match your current filters" : "You don't have any transactions yet" })
|
|
2089
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs(Table, { children: [
|
|
2090
|
+
/* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
|
|
2091
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Date & Time" }),
|
|
2092
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Type" }),
|
|
2093
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Amount" }),
|
|
2094
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Balance After" }),
|
|
2095
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Description" }),
|
|
2096
|
+
/* @__PURE__ */ jsx(TableHead, { children: "Reference" })
|
|
2097
|
+
] }) }),
|
|
2098
|
+
/* @__PURE__ */ jsx(TableBody, { children: filteredTransactions.map((transaction, index) => {
|
|
2099
|
+
const isDeposit = transaction.type?.toLowerCase() === "deposit" || transaction.type?.toLowerCase() === "credit";
|
|
2100
|
+
return /* @__PURE__ */ jsxs(TableRow, { children: [
|
|
2101
|
+
/* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsxs("div", { children: [
|
|
2102
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium", children: formatDate(transaction.created_at || transaction.timestamp) }),
|
|
2103
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: getRelativeTime(transaction.created_at || transaction.timestamp) })
|
|
2104
|
+
] }) }),
|
|
2105
|
+
/* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2106
|
+
getTypeIcon(transaction.type),
|
|
2107
|
+
/* @__PURE__ */ jsx(Badge, { variant: getTypeVariant(transaction.type), children: transaction.type || "Unknown" })
|
|
2108
|
+
] }) }),
|
|
2109
|
+
/* @__PURE__ */ jsx(TableCell, { className: "font-mono font-semibold", children: /* @__PURE__ */ jsxs("span", { className: isDeposit ? "text-green-600" : "text-red-600", children: [
|
|
2110
|
+
isDeposit ? "+" : "-",
|
|
2111
|
+
formatCurrency(Math.abs(transaction.amount || transaction.amount_usd || 0))
|
|
2112
|
+
] }) }),
|
|
2113
|
+
/* @__PURE__ */ jsx(TableCell, { className: "font-mono", children: formatCurrency(transaction.balance_after || 0) }),
|
|
2114
|
+
/* @__PURE__ */ jsx(TableCell, { className: "text-sm", children: transaction.description || transaction.note || "No description" }),
|
|
2115
|
+
/* @__PURE__ */ jsx(TableCell, { className: "font-mono text-sm text-muted-foreground", children: transaction.reference || transaction.payment_id ? `${(transaction.reference || transaction.payment_id).toString().slice(0, 8)}...` : "N/A" })
|
|
2116
|
+
] }, transaction.id || index);
|
|
2117
|
+
}) })
|
|
2118
|
+
] }) })
|
|
2119
|
+
] })
|
|
2120
|
+
] });
|
|
2121
|
+
};
|
|
2122
|
+
var TransactionsView = () => {
|
|
2123
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsx(TransactionsList, {}) });
|
|
2124
|
+
};
|
|
2125
|
+
var isDevelopment = process.env.NODE_ENV === "development";
|
|
2126
|
+
var logger = createConsola({
|
|
2127
|
+
level: isDevelopment ? 4 : 1
|
|
2128
|
+
}).withTag("ext-payments");
|
|
2129
|
+
var paymentsLogger = logger;
|
|
2130
|
+
var PaymentCreateSchema = z.object({
|
|
2131
|
+
amount_usd: z.number().min(0.01, "Amount must be at least $0.01"),
|
|
2132
|
+
currency_code: z.string().min(1, "Please select a currency")
|
|
2133
|
+
});
|
|
2134
|
+
var CreatePaymentDialog = () => {
|
|
2135
|
+
const [open, setOpen] = useState(false);
|
|
2136
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
2137
|
+
const { createPayment } = usePaymentsContext();
|
|
2138
|
+
const { currencies, isLoadingCurrencies } = useRootPaymentsContext();
|
|
2139
|
+
const form = useForm({
|
|
2140
|
+
resolver: zodResolver(PaymentCreateSchema),
|
|
2141
|
+
defaultValues: {
|
|
2142
|
+
amount_usd: 10,
|
|
2143
|
+
currency_code: "USDT"
|
|
2144
|
+
}
|
|
2145
|
+
});
|
|
2146
|
+
const currenciesList = useMemo(() => {
|
|
2147
|
+
const data = currencies?.currencies || currencies?.results || currencies || [];
|
|
2148
|
+
return Array.isArray(data) ? data : [];
|
|
2149
|
+
}, [currencies]);
|
|
2150
|
+
const currencyOptions = useMemo(() => {
|
|
2151
|
+
return currenciesList.filter((curr) => curr.is_enabled !== false).map((curr) => ({
|
|
2152
|
+
code: curr.code || curr.currency_code || curr.symbol,
|
|
2153
|
+
name: curr.name || curr.code || curr.currency_code,
|
|
2154
|
+
usd_rate: curr.usd_rate || curr.rate || 1,
|
|
2155
|
+
network: curr.network || null
|
|
2156
|
+
}));
|
|
2157
|
+
}, [currenciesList]);
|
|
2158
|
+
const calculateCryptoAmount = useMemo(() => {
|
|
2159
|
+
const amountUsd = form.watch("amount_usd");
|
|
2160
|
+
const currencyCode = form.watch("currency_code");
|
|
2161
|
+
const currency = currencyOptions.find((c) => c.code === currencyCode);
|
|
2162
|
+
if (!currency || !currency.usd_rate || !amountUsd) {
|
|
2163
|
+
return null;
|
|
2164
|
+
}
|
|
2165
|
+
const cryptoAmount = amountUsd / currency.usd_rate;
|
|
2166
|
+
return {
|
|
2167
|
+
amount: cryptoAmount,
|
|
2168
|
+
currency: currency.code,
|
|
2169
|
+
rate: currency.usd_rate,
|
|
2170
|
+
network: currency.network
|
|
2171
|
+
};
|
|
2172
|
+
}, [form.watch("amount_usd"), form.watch("currency_code"), currencyOptions]);
|
|
2173
|
+
useEffect(() => {
|
|
2174
|
+
const handleOpen = () => setOpen(true);
|
|
2175
|
+
const handleClose2 = () => setOpen(false);
|
|
2176
|
+
window.addEventListener(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG, handleOpen);
|
|
2177
|
+
window.addEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
|
|
2178
|
+
return () => {
|
|
2179
|
+
window.removeEventListener(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG, handleOpen);
|
|
2180
|
+
window.removeEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
|
|
2181
|
+
};
|
|
2182
|
+
}, []);
|
|
2183
|
+
const handleClose = () => {
|
|
2184
|
+
setOpen(false);
|
|
2185
|
+
form.reset();
|
|
2186
|
+
};
|
|
2187
|
+
useEffect(() => {
|
|
2188
|
+
if (currencyOptions.length > 0 && !form.getValues("currency_code")) {
|
|
2189
|
+
form.setValue("currency_code", currencyOptions[0].code);
|
|
2190
|
+
}
|
|
2191
|
+
}, [currencyOptions, form]);
|
|
2192
|
+
const handleSubmit = async (data) => {
|
|
2193
|
+
try {
|
|
2194
|
+
setIsSubmitting(true);
|
|
2195
|
+
const result = await createPayment();
|
|
2196
|
+
handleClose();
|
|
2197
|
+
closePaymentsDialog();
|
|
2198
|
+
const paymentData = result;
|
|
2199
|
+
const paymentId = paymentData?.payment?.id || paymentData?.id;
|
|
2200
|
+
if (paymentId) {
|
|
2201
|
+
openPaymentDetailsDialog(String(paymentId));
|
|
2202
|
+
}
|
|
2203
|
+
} catch (error) {
|
|
2204
|
+
paymentsLogger.error("Failed to create payment:", error);
|
|
2205
|
+
} finally {
|
|
2206
|
+
setIsSubmitting(false);
|
|
2207
|
+
}
|
|
2208
|
+
};
|
|
2209
|
+
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-md", children: [
|
|
2210
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
2211
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: "Create Payment" }),
|
|
2212
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: "Create a new payment to add funds to your account." })
|
|
2213
|
+
] }),
|
|
2214
|
+
/* @__PURE__ */ jsx(Form, { ...form, children: /* @__PURE__ */ jsxs("form", { onSubmit: form.handleSubmit(handleSubmit), className: "space-y-4", children: [
|
|
2215
|
+
/* @__PURE__ */ jsx(
|
|
2216
|
+
FormField,
|
|
2217
|
+
{
|
|
2218
|
+
control: form.control,
|
|
2219
|
+
name: "amount_usd",
|
|
2220
|
+
render: ({ field }) => /* @__PURE__ */ jsxs(FormItem, { children: [
|
|
2221
|
+
/* @__PURE__ */ jsx(FormLabel, { children: "Amount (USD)" }),
|
|
2222
|
+
/* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(
|
|
2223
|
+
Input,
|
|
2224
|
+
{
|
|
2225
|
+
type: "number",
|
|
2226
|
+
step: "0.01",
|
|
2227
|
+
min: "0.01",
|
|
2228
|
+
placeholder: "10.00",
|
|
2229
|
+
...field,
|
|
2230
|
+
onChange: (e) => field.onChange(parseFloat(e.target.value) || 0)
|
|
2231
|
+
}
|
|
2232
|
+
) }),
|
|
2233
|
+
/* @__PURE__ */ jsx(FormDescription, { children: "The amount you want to pay in USD." }),
|
|
2234
|
+
/* @__PURE__ */ jsx(FormMessage, {})
|
|
2235
|
+
] })
|
|
2236
|
+
}
|
|
2237
|
+
),
|
|
2238
|
+
/* @__PURE__ */ jsx(
|
|
2239
|
+
FormField,
|
|
2240
|
+
{
|
|
2241
|
+
control: form.control,
|
|
2242
|
+
name: "currency_code",
|
|
2243
|
+
render: ({ field }) => /* @__PURE__ */ jsxs(FormItem, { children: [
|
|
2244
|
+
/* @__PURE__ */ jsx(FormLabel, { children: "Currency" }),
|
|
2245
|
+
/* @__PURE__ */ jsxs(
|
|
2246
|
+
Select,
|
|
2247
|
+
{
|
|
2248
|
+
onValueChange: field.onChange,
|
|
2249
|
+
defaultValue: field.value,
|
|
2250
|
+
disabled: isLoadingCurrencies,
|
|
2251
|
+
children: [
|
|
2252
|
+
/* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select currency..." }) }) }),
|
|
2253
|
+
/* @__PURE__ */ jsx(SelectContent, { children: currencyOptions.map((curr) => /* @__PURE__ */ jsx(SelectItem, { value: curr.code, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2254
|
+
/* @__PURE__ */ jsx(TokenIcon, { symbol: curr.code, size: 16 }),
|
|
2255
|
+
/* @__PURE__ */ jsx("span", { children: curr.code }),
|
|
2256
|
+
curr.network && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
2257
|
+
"(",
|
|
2258
|
+
curr.network,
|
|
2259
|
+
")"
|
|
2260
|
+
] })
|
|
2261
|
+
] }) }, curr.code)) })
|
|
2262
|
+
]
|
|
2263
|
+
}
|
|
2264
|
+
),
|
|
2265
|
+
/* @__PURE__ */ jsx(FormDescription, { children: "The cryptocurrency to use for payment." }),
|
|
2266
|
+
/* @__PURE__ */ jsx(FormMessage, {})
|
|
2267
|
+
] })
|
|
2268
|
+
}
|
|
2269
|
+
),
|
|
2270
|
+
calculateCryptoAmount && /* @__PURE__ */ jsxs("div", { className: "rounded-sm bg-muted p-4 space-y-3", children: [
|
|
2271
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2272
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "You will send" }),
|
|
2273
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2274
|
+
/* @__PURE__ */ jsx(TokenIcon, { symbol: calculateCryptoAmount.currency, size: 16 }),
|
|
2275
|
+
/* @__PURE__ */ jsxs("span", { className: "font-mono font-semibold", children: [
|
|
2276
|
+
calculateCryptoAmount.amount.toFixed(8),
|
|
2277
|
+
" ",
|
|
2278
|
+
calculateCryptoAmount.currency
|
|
2279
|
+
] })
|
|
2280
|
+
] })
|
|
2281
|
+
] }),
|
|
2282
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2283
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "You will receive" }),
|
|
2284
|
+
/* @__PURE__ */ jsxs("span", { className: "text-lg font-bold", children: [
|
|
2285
|
+
"$",
|
|
2286
|
+
form.watch("amount_usd")?.toFixed(2),
|
|
2287
|
+
" USD"
|
|
2288
|
+
] })
|
|
2289
|
+
] }),
|
|
2290
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
|
|
2291
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Rate" }),
|
|
2292
|
+
/* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
|
|
2293
|
+
"1 ",
|
|
2294
|
+
calculateCryptoAmount.currency,
|
|
2295
|
+
" = $",
|
|
2296
|
+
calculateCryptoAmount.rate?.toFixed(2)
|
|
2297
|
+
] })
|
|
2298
|
+
] }),
|
|
2299
|
+
calculateCryptoAmount.network && /* @__PURE__ */ jsx("div", { className: "border-t pt-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2300
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Network" }),
|
|
2301
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: calculateCryptoAmount.network })
|
|
2302
|
+
] }) })
|
|
2303
|
+
] }),
|
|
2304
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
2305
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: handleClose, disabled: isSubmitting, children: "Cancel" }),
|
|
2306
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", disabled: isSubmitting || currencyOptions.length === 0, children: isSubmitting ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2307
|
+
/* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4 mr-2 animate-spin" }),
|
|
2308
|
+
"Creating..."
|
|
2309
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2310
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
|
|
2311
|
+
"Create Payment"
|
|
2312
|
+
] }) })
|
|
2313
|
+
] })
|
|
2314
|
+
] }) })
|
|
2315
|
+
] }) });
|
|
2316
|
+
};
|
|
2317
|
+
var PaymentDetailsDialog = () => {
|
|
2318
|
+
const [open, setOpen] = useState(false);
|
|
2319
|
+
const [paymentId, setPaymentId] = useState(null);
|
|
2320
|
+
const [timeLeft, setTimeLeft] = useState("");
|
|
2321
|
+
const shouldFetch = open && !!paymentId;
|
|
2322
|
+
const { data: payment, isLoading, error, mutate } = usePaymentsPaymentsRetrieve(
|
|
2323
|
+
shouldFetch ? paymentId : "",
|
|
2324
|
+
apiPayments
|
|
2325
|
+
);
|
|
2326
|
+
useEffect(() => {
|
|
2327
|
+
const handleOpen = (event) => {
|
|
2328
|
+
const customEvent = event;
|
|
2329
|
+
setPaymentId(customEvent.detail.id);
|
|
2330
|
+
setOpen(true);
|
|
2331
|
+
};
|
|
2332
|
+
const handleClose2 = () => {
|
|
2333
|
+
setOpen(false);
|
|
2334
|
+
setPaymentId(null);
|
|
2335
|
+
};
|
|
2336
|
+
window.addEventListener(PAYMENT_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG, handleOpen);
|
|
2337
|
+
window.addEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
|
|
2338
|
+
return () => {
|
|
2339
|
+
window.removeEventListener(PAYMENT_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG, handleOpen);
|
|
2340
|
+
window.removeEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
|
|
2341
|
+
};
|
|
2342
|
+
}, []);
|
|
2343
|
+
const handleClose = () => {
|
|
2344
|
+
setOpen(false);
|
|
2345
|
+
setPaymentId(null);
|
|
2346
|
+
};
|
|
2347
|
+
useEffect(() => {
|
|
2348
|
+
if (!payment?.expires_at) return;
|
|
2349
|
+
const updateTimeLeft = () => {
|
|
2350
|
+
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
2351
|
+
const expires = new Date(payment.expires_at).getTime();
|
|
2352
|
+
const diff = expires - now;
|
|
2353
|
+
if (diff <= 0) {
|
|
2354
|
+
setTimeLeft("Expired");
|
|
2355
|
+
return;
|
|
2356
|
+
}
|
|
2357
|
+
const hours = Math.floor(diff / (1e3 * 60 * 60));
|
|
2358
|
+
const minutes = Math.floor(diff % (1e3 * 60 * 60) / (1e3 * 60));
|
|
2359
|
+
const seconds = Math.floor(diff % (1e3 * 60) / 1e3);
|
|
2360
|
+
setTimeLeft(`${hours}h ${minutes}m ${seconds}s`);
|
|
2361
|
+
};
|
|
2362
|
+
updateTimeLeft();
|
|
2363
|
+
const interval = setInterval(updateTimeLeft, 1e3);
|
|
2364
|
+
return () => clearInterval(interval);
|
|
2365
|
+
}, [payment?.expires_at]);
|
|
2366
|
+
const getStatusInfo = () => {
|
|
2367
|
+
switch (payment?.status?.toLowerCase()) {
|
|
2368
|
+
case "pending":
|
|
2369
|
+
return { icon: Clock, color: "text-yellow-500", bg: "bg-yellow-500/10" };
|
|
2370
|
+
case "completed":
|
|
2371
|
+
case "success":
|
|
2372
|
+
return { icon: CheckCircle2, color: "text-green-500", bg: "bg-green-500/10" };
|
|
2373
|
+
case "failed":
|
|
2374
|
+
case "error":
|
|
2375
|
+
return { icon: XCircle, color: "text-red-500", bg: "bg-red-500/10" };
|
|
2376
|
+
case "expired":
|
|
2377
|
+
return { icon: AlertCircle, color: "text-gray-500", bg: "bg-gray-500/10" };
|
|
2378
|
+
case "confirming":
|
|
2379
|
+
return { icon: RefreshCw, color: "text-blue-500", bg: "bg-blue-500/10" };
|
|
2380
|
+
default:
|
|
2381
|
+
return { icon: Clock, color: "text-gray-500", bg: "bg-gray-500/10" };
|
|
2382
|
+
}
|
|
2383
|
+
};
|
|
2384
|
+
if (!open) return null;
|
|
2385
|
+
if (isLoading) {
|
|
2386
|
+
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-lg", children: [
|
|
2387
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
2388
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: "Payment Details" }),
|
|
2389
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: "Loading payment information..." })
|
|
2390
|
+
] }),
|
|
2391
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx(RefreshCw, { className: "h-8 w-8 animate-spin text-muted-foreground" }) })
|
|
2392
|
+
] }) });
|
|
2393
|
+
}
|
|
2394
|
+
if (shouldFetch && !isLoading && (error || !payment)) {
|
|
2395
|
+
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-lg", children: [
|
|
2396
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
2397
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: "Payment Details" }),
|
|
2398
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: "Failed to load payment information" })
|
|
2399
|
+
] }),
|
|
2400
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-12 space-y-4", children: [
|
|
2401
|
+
/* @__PURE__ */ jsx(XCircle, { className: "h-12 w-12 text-destructive" }),
|
|
2402
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: error ? `Error: ${error}` : "Payment not found" }),
|
|
2403
|
+
/* @__PURE__ */ jsx(Button, { onClick: () => mutate(), children: "Try Again" })
|
|
2404
|
+
] })
|
|
2405
|
+
] }) });
|
|
2406
|
+
}
|
|
2407
|
+
const statusInfo = getStatusInfo();
|
|
2408
|
+
const StatusIcon = statusInfo.icon;
|
|
2409
|
+
const qrCodeUrl = payment.pay_address ? `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(payment.pay_address)}` : null;
|
|
2410
|
+
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-lg", children: [
|
|
2411
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
2412
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: "Payment Details" }),
|
|
2413
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: "Send cryptocurrency to complete your payment" })
|
|
2414
|
+
] }),
|
|
2415
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
2416
|
+
/* @__PURE__ */ jsxs("div", { className: `flex items-center gap-3 p-4 rounded-sm ${statusInfo.bg}`, children: [
|
|
2417
|
+
/* @__PURE__ */ jsx(StatusIcon, { className: `h-5 w-5 ${statusInfo.color}` }),
|
|
2418
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
2419
|
+
/* @__PURE__ */ jsx("div", { className: "font-semibold capitalize", children: payment.status }),
|
|
2420
|
+
payment.status === "pending" && timeLeft && /* @__PURE__ */ jsxs("div", { className: "text-sm text-muted-foreground", children: [
|
|
2421
|
+
"Expires in ",
|
|
2422
|
+
timeLeft
|
|
2423
|
+
] })
|
|
2424
|
+
] })
|
|
2425
|
+
] }),
|
|
2426
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
2427
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 bg-muted rounded-sm", children: [
|
|
2428
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Amount to send" }),
|
|
2429
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2430
|
+
/* @__PURE__ */ jsx(TokenIcon, { symbol: String(payment.currency_code || "BTC"), size: 20 }),
|
|
2431
|
+
/* @__PURE__ */ jsxs("span", { className: "font-mono font-bold text-lg", children: [
|
|
2432
|
+
payment.pay_amount || "0.00000000",
|
|
2433
|
+
" ",
|
|
2434
|
+
payment.currency_code
|
|
2435
|
+
] })
|
|
2436
|
+
] })
|
|
2437
|
+
] }),
|
|
2438
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4", children: [
|
|
2439
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Equivalent to" }),
|
|
2440
|
+
/* @__PURE__ */ jsxs("span", { className: "font-semibold text-lg", children: [
|
|
2441
|
+
"$",
|
|
2442
|
+
parseFloat(payment.amount_usd || "0").toFixed(2),
|
|
2443
|
+
" USD"
|
|
2444
|
+
] })
|
|
2445
|
+
] }),
|
|
2446
|
+
payment.internal_payment_id && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4", children: [
|
|
2447
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Payment Order #" }),
|
|
2448
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: payment.internal_payment_id })
|
|
2449
|
+
] }),
|
|
2450
|
+
payment.currency_network && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4", children: [
|
|
2451
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Network" }),
|
|
2452
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: payment.currency_network })
|
|
2453
|
+
] })
|
|
2454
|
+
] }),
|
|
2455
|
+
qrCodeUrl && payment.status === "pending" && /* @__PURE__ */ jsx("div", { className: "flex justify-center p-6 bg-white rounded-sm", children: /* @__PURE__ */ jsx("img", { src: qrCodeUrl, alt: "Payment QR Code", className: "w-48 h-48" }) }),
|
|
2456
|
+
payment.pay_address && payment.status === "pending" && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
2457
|
+
/* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Payment Address" }),
|
|
2458
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2459
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 p-3 bg-muted rounded-sm font-mono text-sm break-all", children: payment.pay_address }),
|
|
2460
|
+
/* @__PURE__ */ jsx(CopyButton, { value: payment.pay_address, variant: "outline" })
|
|
2461
|
+
] })
|
|
2462
|
+
] }),
|
|
2463
|
+
payment.transaction_hash && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
2464
|
+
/* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Transaction Hash" }),
|
|
2465
|
+
/* @__PURE__ */ jsx("div", { className: "p-3 bg-muted rounded-sm font-mono text-sm break-all", children: payment.transaction_hash })
|
|
2466
|
+
] }),
|
|
2467
|
+
payment.payment_url && payment.status === "pending" && /* @__PURE__ */ jsxs(
|
|
2468
|
+
Button,
|
|
2469
|
+
{
|
|
2470
|
+
variant: "outline",
|
|
2471
|
+
className: "w-full",
|
|
2472
|
+
onClick: () => window.open(payment.payment_url, "_blank"),
|
|
2473
|
+
children: [
|
|
2474
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4 mr-2" }),
|
|
2475
|
+
"Open in Payment Provider"
|
|
2476
|
+
]
|
|
2477
|
+
}
|
|
2478
|
+
),
|
|
2479
|
+
/* @__PURE__ */ jsxs("div", { className: "pt-4 border-t space-y-2 text-xs text-muted-foreground", children: [
|
|
2480
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
|
|
2481
|
+
/* @__PURE__ */ jsx("span", { children: "Payment ID" }),
|
|
2482
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono", children: payment.id })
|
|
2483
|
+
] }),
|
|
2484
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
|
|
2485
|
+
/* @__PURE__ */ jsx("span", { children: "Created" }),
|
|
2486
|
+
/* @__PURE__ */ jsx("span", { children: new Date(payment.created_at).toLocaleString() })
|
|
2487
|
+
] }),
|
|
2488
|
+
payment.confirmations_count !== void 0 && /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
|
|
2489
|
+
/* @__PURE__ */ jsx("span", { children: "Confirmations" }),
|
|
2490
|
+
/* @__PURE__ */ jsx("span", { children: payment.confirmations_count })
|
|
2491
|
+
] })
|
|
2492
|
+
] })
|
|
2493
|
+
] }),
|
|
2494
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
2495
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: handleClose, children: "Close" }),
|
|
2496
|
+
/* @__PURE__ */ jsxs(Button, { onClick: () => mutate(), variant: "ghost", size: "sm", children: [
|
|
2497
|
+
/* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4 mr-2" }),
|
|
2498
|
+
"Refresh"
|
|
2499
|
+
] })
|
|
2500
|
+
] })
|
|
2501
|
+
] }) });
|
|
2502
|
+
};
|
|
2503
|
+
var PaymentsLayout = () => {
|
|
2504
|
+
return /* @__PURE__ */ jsx(RootPaymentsProvider, { children: /* @__PURE__ */ jsxs("div", { className: "h-full p-6 space-y-6", children: [
|
|
2505
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2506
|
+
/* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold tracking-tight", children: "Payments" }),
|
|
2507
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "Manage your payments, balance, and transaction history" })
|
|
2508
|
+
] }),
|
|
2509
|
+
/* @__PURE__ */ jsxs(Tabs, { defaultValue: "overview", className: "space-y-6", children: [
|
|
2510
|
+
/* @__PURE__ */ jsxs(TabsList, { className: "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground", children: [
|
|
2511
|
+
/* @__PURE__ */ jsxs(TabsTrigger, { value: "overview", className: "inline-flex items-center gap-2 px-3 py-1.5", children: [
|
|
2512
|
+
/* @__PURE__ */ jsx(Wallet, { className: "h-4 w-4" }),
|
|
2513
|
+
/* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Overview" })
|
|
2514
|
+
] }),
|
|
2515
|
+
/* @__PURE__ */ jsxs(TabsTrigger, { value: "payments", className: "inline-flex items-center gap-2 px-3 py-1.5", children: [
|
|
2516
|
+
/* @__PURE__ */ jsx(CreditCard, { className: "h-4 w-4" }),
|
|
2517
|
+
/* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Payments" })
|
|
2518
|
+
] }),
|
|
2519
|
+
/* @__PURE__ */ jsxs(TabsTrigger, { value: "transactions", className: "inline-flex items-center gap-2 px-3 py-1.5", children: [
|
|
2520
|
+
/* @__PURE__ */ jsx(History, { className: "h-4 w-4" }),
|
|
2521
|
+
/* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Transactions" })
|
|
2522
|
+
] })
|
|
2523
|
+
] }),
|
|
2524
|
+
/* @__PURE__ */ jsx(TabsContent, { value: "overview", className: "space-y-6", children: /* @__PURE__ */ jsx(OverviewProvider, { children: /* @__PURE__ */ jsxs(PaymentsProvider, { children: [
|
|
2525
|
+
/* @__PURE__ */ jsx(OverviewView, {}),
|
|
2526
|
+
/* @__PURE__ */ jsx(CreatePaymentDialog, {})
|
|
2527
|
+
] }) }) }),
|
|
2528
|
+
/* @__PURE__ */ jsx(TabsContent, { value: "payments", className: "space-y-6", children: /* @__PURE__ */ jsxs(PaymentsProvider, { children: [
|
|
2529
|
+
/* @__PURE__ */ jsx(PaymentsView, {}),
|
|
2530
|
+
/* @__PURE__ */ jsx(CreatePaymentDialog, {})
|
|
2531
|
+
] }) }),
|
|
2532
|
+
/* @__PURE__ */ jsx(TabsContent, { value: "transactions", className: "space-y-6", children: /* @__PURE__ */ jsx(OverviewProvider, { children: /* @__PURE__ */ jsx(TransactionsView, {}) }) })
|
|
2533
|
+
] }),
|
|
2534
|
+
/* @__PURE__ */ jsx(PaymentDetailsDialog, {})
|
|
2535
|
+
] }) });
|
|
2536
|
+
};
|
|
2537
|
+
|
|
2538
|
+
// package.json
|
|
2539
|
+
var package_default = {
|
|
2540
|
+
name: "@djangocfg/ext-payments",
|
|
2541
|
+
version: "1.0.3",
|
|
2542
|
+
description: "Payments system extension for DjangoCFG",
|
|
2543
|
+
keywords: [
|
|
2544
|
+
"django",
|
|
2545
|
+
"djangocfg",
|
|
2546
|
+
"extension",
|
|
2547
|
+
"payments",
|
|
2548
|
+
"stripe",
|
|
2549
|
+
"billing",
|
|
2550
|
+
"subscription",
|
|
2551
|
+
"typescript",
|
|
2552
|
+
"react"
|
|
2553
|
+
],
|
|
2554
|
+
author: {
|
|
2555
|
+
name: "DjangoCFG",
|
|
2556
|
+
url: "https://djangocfg.com"
|
|
2557
|
+
},
|
|
2558
|
+
homepage: "https://hub.djangocfg.com/extensions/djangocfg-ext-payments",
|
|
2559
|
+
repository: {
|
|
2560
|
+
type: "git",
|
|
2561
|
+
url: "https://github.com/markolofsen/django-cfg.git",
|
|
2562
|
+
directory: "extensions/payments"
|
|
2563
|
+
},
|
|
2564
|
+
bugs: {
|
|
2565
|
+
url: "https://github.com/markolofsen/django-cfg/issues"
|
|
2566
|
+
},
|
|
2567
|
+
license: "MIT",
|
|
2568
|
+
type: "module",
|
|
2569
|
+
main: "./dist/index.cjs",
|
|
2570
|
+
module: "./dist/index.js",
|
|
2571
|
+
types: "./dist/index.d.ts",
|
|
2572
|
+
exports: {
|
|
2573
|
+
".": {
|
|
2574
|
+
types: "./dist/index.d.ts",
|
|
2575
|
+
import: "./dist/index.js",
|
|
2576
|
+
require: "./dist/index.cjs"
|
|
2577
|
+
},
|
|
2578
|
+
"./hooks": {
|
|
2579
|
+
types: "./dist/hooks.d.ts",
|
|
2580
|
+
import: "./dist/hooks.js",
|
|
2581
|
+
require: "./dist/hooks.cjs"
|
|
2582
|
+
},
|
|
2583
|
+
"./config": {
|
|
2584
|
+
types: "./dist/config.d.ts",
|
|
2585
|
+
import: "./dist/config.js",
|
|
2586
|
+
require: "./dist/config.cjs"
|
|
2587
|
+
}
|
|
2588
|
+
},
|
|
2589
|
+
files: [
|
|
2590
|
+
"dist",
|
|
2591
|
+
"src",
|
|
2592
|
+
"preview.png"
|
|
2593
|
+
],
|
|
2594
|
+
scripts: {
|
|
2595
|
+
build: "tsup",
|
|
2596
|
+
dev: "tsup --watch",
|
|
2597
|
+
check: "tsc --noEmit"
|
|
2598
|
+
},
|
|
2599
|
+
peerDependencies: {
|
|
2600
|
+
"@djangocfg/api": "workspace:*",
|
|
2601
|
+
"@djangocfg/ext-base": "workspace:*",
|
|
2602
|
+
"@djangocfg/ui-nextjs": "workspace:*",
|
|
2603
|
+
consola: "^3.4.2",
|
|
2604
|
+
"lucide-react": "^0.545.0",
|
|
2605
|
+
next: "^15.5.7",
|
|
2606
|
+
"p-retry": "^7.0.0",
|
|
2607
|
+
react: "^18 || ^19",
|
|
2608
|
+
swr: "^2.3.7",
|
|
2609
|
+
zod: "^4.1.13"
|
|
2610
|
+
},
|
|
2611
|
+
devDependencies: {
|
|
2612
|
+
"@djangocfg/api": "workspace:*",
|
|
2613
|
+
"@djangocfg/ext-base": "workspace:*",
|
|
2614
|
+
"@djangocfg/typescript-config": "workspace:*",
|
|
2615
|
+
"@types/node": "^24.7.2",
|
|
2616
|
+
"@types/react": "^19.0.0",
|
|
2617
|
+
consola: "^3.4.2",
|
|
2618
|
+
"p-retry": "^7.0.0",
|
|
2619
|
+
swr: "^2.3.7",
|
|
2620
|
+
tsup: "^8.5.0",
|
|
2621
|
+
typescript: "^5.9.3"
|
|
2622
|
+
}
|
|
2623
|
+
};
|
|
2624
|
+
|
|
2625
|
+
// src/config.ts
|
|
2626
|
+
var extensionConfig = createExtensionConfig(package_default, {
|
|
2627
|
+
name: "payments",
|
|
2628
|
+
displayName: "Payments & Billing",
|
|
2629
|
+
category: "payments",
|
|
2630
|
+
features: [
|
|
2631
|
+
"Multiple payment providers",
|
|
2632
|
+
"Stripe integration",
|
|
2633
|
+
"Cryptocurrency payments (NowPayments)",
|
|
2634
|
+
"Subscription management",
|
|
2635
|
+
"Payment tracking",
|
|
2636
|
+
"Invoice generation"
|
|
2637
|
+
],
|
|
2638
|
+
minVersion: "2.0.0",
|
|
2639
|
+
examples: [
|
|
2640
|
+
{
|
|
2641
|
+
title: "Stripe Payment Form",
|
|
2642
|
+
description: "Accept payments with Stripe",
|
|
2643
|
+
code: `import { PaymentForm, usePayment } from '@djangocfg/ext-payments';
|
|
2644
|
+
|
|
2645
|
+
export default function CheckoutPage() {
|
|
2646
|
+
const { processPayment, isProcessing } = usePayment();
|
|
2647
|
+
|
|
2648
|
+
return (
|
|
2649
|
+
<PaymentForm
|
|
2650
|
+
amount={9900}
|
|
2651
|
+
currency="usd"
|
|
2652
|
+
onSuccess={(paymentIntent) => {
|
|
2653
|
+
console.log('Payment successful!', paymentIntent);
|
|
2654
|
+
}}
|
|
2655
|
+
/>
|
|
2656
|
+
);
|
|
2657
|
+
}`,
|
|
2658
|
+
language: "tsx"
|
|
2659
|
+
},
|
|
2660
|
+
{
|
|
2661
|
+
title: "Cryptocurrency Payment",
|
|
2662
|
+
description: "Accept crypto payments via NowPayments",
|
|
2663
|
+
code: `import { CryptoPayment } from '@djangocfg/ext-payments';
|
|
2664
|
+
|
|
2665
|
+
export default function CryptoCheckout() {
|
|
2666
|
+
return (
|
|
2667
|
+
<CryptoPayment
|
|
2668
|
+
amount={100}
|
|
2669
|
+
currency="USDT"
|
|
2670
|
+
onPaymentCreated={(payment) => {
|
|
2671
|
+
console.log('Payment created:', payment.paymentUrl);
|
|
2672
|
+
}}
|
|
2673
|
+
/>
|
|
2674
|
+
);
|
|
2675
|
+
}`,
|
|
2676
|
+
language: "tsx"
|
|
2677
|
+
}
|
|
2678
|
+
]
|
|
2679
|
+
});
|
|
2680
|
+
|
|
2681
|
+
export { API, APIClient, APIError, APILogger, BalanceSchema, CookieStorageAdapter, CurrencySchema, DEFAULT_RETRY_CONFIG, enums_exports as Enums, models_exports as ExtPaymentsPaymentsTypes, FetchAdapter, fetchers_exports as Fetchers, LocalStorageAdapter, MemoryStorageAdapter, NetworkError, PAYMENT_EVENTS, PaginatedPaymentListListSchema, PaymentDetailSchema, PaymentListSchema, PaymentsLayout, REFRESH_TOKEN_KEY, schemas_exports as Schemas, TOKEN_KEY, TransactionSchema, apiPayments, clearAPITokens, closePaymentsDialog, configureAPI, createPaymentsPaymentsConfirmCreate, createPaymentsPaymentsCreateCreate, dispatchValidationError, extensionConfig, formatZodError, getAPIInstance, getPaymentsBalanceRetrieve, getPaymentsCurrenciesList, getPaymentsPaymentsList, getPaymentsPaymentsRetrieve, getPaymentsPaymentsStatusRetrieve, getPaymentsTransactionsList, isAPIConfigured, onValidationError, openCreatePaymentDialog, openPaymentDetailsDialog, reconfigureAPI, resetAPI, shouldRetry, withRetry };
|