@djangocfg/ext-payments 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +206 -0
  2. package/dist/chunk-5KY6HVXF.js +2593 -0
  3. package/dist/hooks.cjs +2666 -0
  4. package/dist/hooks.d.cts +186 -0
  5. package/dist/hooks.d.ts +186 -0
  6. package/dist/hooks.js +1 -0
  7. package/dist/index.cjs +2590 -0
  8. package/dist/index.d.cts +1287 -0
  9. package/dist/index.d.ts +1287 -0
  10. package/dist/index.js +1 -0
  11. package/package.json +79 -0
  12. package/src/api/generated/ext_payments/_utils/fetchers/ext_payments__payments.ts +408 -0
  13. package/src/api/generated/ext_payments/_utils/fetchers/index.ts +28 -0
  14. package/src/api/generated/ext_payments/_utils/hooks/ext_payments__payments.ts +147 -0
  15. package/src/api/generated/ext_payments/_utils/hooks/index.ts +28 -0
  16. package/src/api/generated/ext_payments/_utils/schemas/Balance.schema.ts +23 -0
  17. package/src/api/generated/ext_payments/_utils/schemas/Currency.schema.ts +28 -0
  18. package/src/api/generated/ext_payments/_utils/schemas/PaginatedPaymentListList.schema.ts +24 -0
  19. package/src/api/generated/ext_payments/_utils/schemas/PaymentDetail.schema.ts +44 -0
  20. package/src/api/generated/ext_payments/_utils/schemas/PaymentList.schema.ts +28 -0
  21. package/src/api/generated/ext_payments/_utils/schemas/Transaction.schema.ts +28 -0
  22. package/src/api/generated/ext_payments/_utils/schemas/index.ts +24 -0
  23. package/src/api/generated/ext_payments/api-instance.ts +131 -0
  24. package/src/api/generated/ext_payments/client.ts +301 -0
  25. package/src/api/generated/ext_payments/enums.ts +64 -0
  26. package/src/api/generated/ext_payments/errors.ts +116 -0
  27. package/src/api/generated/ext_payments/ext_payments__payments/client.ts +118 -0
  28. package/src/api/generated/ext_payments/ext_payments__payments/index.ts +2 -0
  29. package/src/api/generated/ext_payments/ext_payments__payments/models.ts +135 -0
  30. package/src/api/generated/ext_payments/http.ts +103 -0
  31. package/src/api/generated/ext_payments/index.ts +273 -0
  32. package/src/api/generated/ext_payments/logger.ts +259 -0
  33. package/src/api/generated/ext_payments/retry.ts +175 -0
  34. package/src/api/generated/ext_payments/schema.json +850 -0
  35. package/src/api/generated/ext_payments/storage.ts +161 -0
  36. package/src/api/generated/ext_payments/validation-events.ts +133 -0
  37. package/src/api/index.ts +9 -0
  38. package/src/config.ts +20 -0
  39. package/src/contexts/BalancesContext.tsx +62 -0
  40. package/src/contexts/CurrenciesContext.tsx +63 -0
  41. package/src/contexts/OverviewContext.tsx +173 -0
  42. package/src/contexts/PaymentsContext.tsx +121 -0
  43. package/src/contexts/PaymentsExtensionProvider.tsx +55 -0
  44. package/src/contexts/README.md +201 -0
  45. package/src/contexts/RootPaymentsContext.tsx +65 -0
  46. package/src/contexts/index.ts +45 -0
  47. package/src/contexts/types.ts +40 -0
  48. package/src/hooks/index.ts +20 -0
  49. package/src/index.ts +36 -0
  50. package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +92 -0
  51. package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +291 -0
  52. package/src/layouts/PaymentsLayout/components/PaymentDetailsDialog.tsx +290 -0
  53. package/src/layouts/PaymentsLayout/components/index.ts +2 -0
  54. package/src/layouts/PaymentsLayout/events.ts +47 -0
  55. package/src/layouts/PaymentsLayout/index.ts +16 -0
  56. package/src/layouts/PaymentsLayout/types.ts +6 -0
  57. package/src/layouts/PaymentsLayout/views/overview/components/BalanceCard.tsx +128 -0
  58. package/src/layouts/PaymentsLayout/views/overview/components/RecentPayments.tsx +142 -0
  59. package/src/layouts/PaymentsLayout/views/overview/components/index.ts +2 -0
  60. package/src/layouts/PaymentsLayout/views/overview/index.tsx +20 -0
  61. package/src/layouts/PaymentsLayout/views/payments/components/PaymentsList.tsx +277 -0
  62. package/src/layouts/PaymentsLayout/views/payments/components/index.ts +1 -0
  63. package/src/layouts/PaymentsLayout/views/payments/index.tsx +17 -0
  64. package/src/layouts/PaymentsLayout/views/transactions/components/TransactionsList.tsx +273 -0
  65. package/src/layouts/PaymentsLayout/views/transactions/components/index.ts +1 -0
  66. package/src/layouts/PaymentsLayout/views/transactions/index.tsx +17 -0
  67. package/src/utils/logger.ts +9 -0
@@ -0,0 +1,116 @@
1
+ /**
2
+ * API Error Classes
3
+ *
4
+ * Typed error classes with Django REST Framework support.
5
+ */
6
+
7
+ /**
8
+ * HTTP API Error with DRF field-specific validation errors.
9
+ *
10
+ * Usage:
11
+ * ```typescript
12
+ * try {
13
+ * await api.users.create(userData);
14
+ * } catch (error) {
15
+ * if (error instanceof APIError) {
16
+ * if (error.isValidationError) {
17
+ * console.log('Field errors:', error.fieldErrors);
18
+ * // { "email": ["Email already exists"], "username": ["Required"] }
19
+ * }
20
+ * }
21
+ * }
22
+ * ```
23
+ */
24
+ export class APIError extends Error {
25
+ constructor(
26
+ public statusCode: number,
27
+ public statusText: string,
28
+ public response: any,
29
+ public url: string,
30
+ message?: string
31
+ ) {
32
+ super(message || `HTTP ${statusCode}: ${statusText}`);
33
+ this.name = 'APIError';
34
+ }
35
+
36
+ /**
37
+ * Get error details from response.
38
+ * DRF typically returns: { "detail": "Error message" } or { "field": ["error1", "error2"] }
39
+ */
40
+ get details(): Record<string, any> | null {
41
+ if (typeof this.response === 'object' && this.response !== null) {
42
+ return this.response;
43
+ }
44
+ return null;
45
+ }
46
+
47
+ /**
48
+ * Get field-specific validation errors from DRF.
49
+ * Returns: { "field_name": ["error1", "error2"], ... }
50
+ */
51
+ get fieldErrors(): Record<string, string[]> | null {
52
+ const details = this.details;
53
+ if (!details) return null;
54
+
55
+ // DRF typically returns: { "field": ["error1", "error2"] }
56
+ const fieldErrors: Record<string, string[]> = {};
57
+ for (const [key, value] of Object.entries(details)) {
58
+ if (Array.isArray(value)) {
59
+ fieldErrors[key] = value;
60
+ }
61
+ }
62
+
63
+ return Object.keys(fieldErrors).length > 0 ? fieldErrors : null;
64
+ }
65
+
66
+ /**
67
+ * Get single error message from DRF.
68
+ * Checks for "detail", "message", or first field error.
69
+ */
70
+ get errorMessage(): string {
71
+ const details = this.details;
72
+ if (!details) return this.message;
73
+
74
+ // Check for "detail" field (common in DRF)
75
+ if (details.detail) {
76
+ return Array.isArray(details.detail) ? details.detail.join(', ') : String(details.detail);
77
+ }
78
+
79
+ // Check for "message" field
80
+ if (details.message) {
81
+ return String(details.message);
82
+ }
83
+
84
+ // Return first field error
85
+ const fieldErrors = this.fieldErrors;
86
+ if (fieldErrors) {
87
+ const firstField = Object.keys(fieldErrors)[0];
88
+ if (firstField) {
89
+ return `${firstField}: ${fieldErrors[firstField]?.join(', ')}`;
90
+ }
91
+ }
92
+
93
+ return this.message;
94
+ }
95
+
96
+ // Helper methods for common HTTP status codes
97
+ get isValidationError(): boolean { return this.statusCode === 400; }
98
+ get isAuthError(): boolean { return this.statusCode === 401; }
99
+ get isPermissionError(): boolean { return this.statusCode === 403; }
100
+ get isNotFoundError(): boolean { return this.statusCode === 404; }
101
+ get isServerError(): boolean { return this.statusCode >= 500 && this.statusCode < 600; }
102
+ }
103
+
104
+ /**
105
+ * Network Error (connection failed, timeout, etc.)
106
+ */
107
+ export class NetworkError extends Error {
108
+ constructor(
109
+ message: string,
110
+ public url: string,
111
+ public originalError?: Error
112
+ ) {
113
+ super(message);
114
+ this.name = 'NetworkError';
115
+ }
116
+ }
@@ -0,0 +1,118 @@
1
+ import * as Models from "./models";
2
+
3
+
4
+ /**
5
+ * API endpoints for Payments.
6
+ */
7
+ export class ExtPaymentsPayments {
8
+ private client: any;
9
+
10
+ constructor(client: any) {
11
+ this.client = client;
12
+ }
13
+
14
+ /**
15
+ * Get user balance
16
+ *
17
+ * Get current user balance and transaction statistics
18
+ */
19
+ async balanceRetrieve(): Promise<Models.Balance> {
20
+ const response = await this.client.request('GET', "/cfg/payments/balance/");
21
+ return response;
22
+ }
23
+
24
+ /**
25
+ * Get available currencies
26
+ *
27
+ * Returns list of available currencies with token+network info
28
+ */
29
+ async currenciesList(): Promise<any> {
30
+ const response = await this.client.request('GET', "/cfg/payments/currencies/");
31
+ return response;
32
+ }
33
+
34
+ async paymentsList(page?: number, page_size?: number): Promise<Models.PaginatedPaymentListList>;
35
+ async paymentsList(params?: { page?: number; page_size?: number }): Promise<Models.PaginatedPaymentListList>;
36
+
37
+ /**
38
+ * ViewSet for payment operations. Endpoints: - GET /payments/ - List
39
+ * user's payments - GET /payments/{id}/ - Get payment details - POST
40
+ * /payments/create/ - Create new payment - GET /payments/{id}/status/ -
41
+ * Check payment status - POST /payments/{id}/confirm/ - Confirm payment
42
+ */
43
+ async paymentsList(...args: any[]): Promise<Models.PaginatedPaymentListList> {
44
+ const isParamsObject = args.length === 1 && typeof args[0] === 'object' && args[0] !== null && !Array.isArray(args[0]);
45
+
46
+ let params;
47
+ if (isParamsObject) {
48
+ params = args[0];
49
+ } else {
50
+ params = { page: args[0], page_size: args[1] };
51
+ }
52
+ const response = await this.client.request('GET', "/cfg/payments/payments/", { params });
53
+ return response;
54
+ }
55
+
56
+ /**
57
+ * ViewSet for payment operations. Endpoints: - GET /payments/ - List
58
+ * user's payments - GET /payments/{id}/ - Get payment details - POST
59
+ * /payments/create/ - Create new payment - GET /payments/{id}/status/ -
60
+ * Check payment status - POST /payments/{id}/confirm/ - Confirm payment
61
+ */
62
+ async paymentsRetrieve(id: string): Promise<Models.PaymentDetail> {
63
+ const response = await this.client.request('GET', `/cfg/payments/payments/${id}/`);
64
+ return response;
65
+ }
66
+
67
+ /**
68
+ * POST /api/v1/payments/{id}/confirm/ Confirm payment (user clicked "I
69
+ * have paid"). Checks status with provider and creates transaction if
70
+ * completed.
71
+ */
72
+ async paymentsConfirmCreate(id: string): Promise<Models.PaymentList> {
73
+ const response = await this.client.request('POST', `/cfg/payments/payments/${id}/confirm/`);
74
+ return response;
75
+ }
76
+
77
+ /**
78
+ * GET /api/v1/payments/{id}/status/?refresh=true Check payment status
79
+ * (with optional refresh from provider). Query params: - refresh: boolean
80
+ * (default: false) - Force refresh from provider
81
+ */
82
+ async paymentsStatusRetrieve(id: string): Promise<Models.PaymentList[]> {
83
+ const response = await this.client.request('GET', `/cfg/payments/payments/${id}/status/`);
84
+ return (response as any).results || response;
85
+ }
86
+
87
+ /**
88
+ * POST /api/v1/payments/create/ Create new payment. Request body: {
89
+ * "amount_usd": "100.00", "currency_code": "USDTTRC20", "description":
90
+ * "Optional description" }
91
+ */
92
+ async paymentsCreateCreate(): Promise<Models.PaymentList> {
93
+ const response = await this.client.request('POST', "/cfg/payments/payments/create/");
94
+ return response;
95
+ }
96
+
97
+ async transactionsList(limit?: number, offset?: number, type?: string): Promise<any>;
98
+ async transactionsList(params?: { limit?: number; offset?: number; type?: string }): Promise<any>;
99
+
100
+ /**
101
+ * Get user transactions
102
+ *
103
+ * Get user transactions with pagination and filtering
104
+ */
105
+ async transactionsList(...args: any[]): Promise<any> {
106
+ const isParamsObject = args.length === 1 && typeof args[0] === 'object' && args[0] !== null && !Array.isArray(args[0]);
107
+
108
+ let params;
109
+ if (isParamsObject) {
110
+ params = args[0];
111
+ } else {
112
+ params = { limit: args[0], offset: args[1], type: args[2] };
113
+ }
114
+ const response = await this.client.request('GET', "/cfg/payments/transactions/", { params });
115
+ return response;
116
+ }
117
+
118
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./client";
2
+ export * as Models from "./models";
@@ -0,0 +1,135 @@
1
+ import * as Enums from "../enums";
2
+
3
+ /**
4
+ * User balance serializer.
5
+ *
6
+ * Response model (includes read-only fields).
7
+ */
8
+ export interface Balance {
9
+ /** Current balance in USD */
10
+ balance_usd: string;
11
+ balance_display: string;
12
+ /** Total amount deposited (lifetime) */
13
+ total_deposited: string;
14
+ /** Total amount withdrawn (lifetime) */
15
+ total_withdrawn: string;
16
+ /** When the last transaction occurred */
17
+ last_transaction_at?: string | null;
18
+ }
19
+
20
+ /**
21
+ *
22
+ * Response model (includes read-only fields).
23
+ */
24
+ export interface PaginatedPaymentListList {
25
+ /** Total number of items across all pages */
26
+ count: number;
27
+ /** Current page number (1-based) */
28
+ page: number;
29
+ /** Total number of pages */
30
+ pages: number;
31
+ /** Number of items per page */
32
+ page_size: number;
33
+ /** Whether there is a next page */
34
+ has_next: boolean;
35
+ /** Whether there is a previous page */
36
+ has_previous: boolean;
37
+ /** Next page number (null if no next page) */
38
+ next_page?: number | null;
39
+ /** Previous page number (null if no previous page) */
40
+ previous_page?: number | null;
41
+ /** Array of items for current page */
42
+ results: Array<PaymentList>;
43
+ }
44
+
45
+ /**
46
+ * Detailed payment information.
47
+ *
48
+ * Response model (includes read-only fields).
49
+ */
50
+ export interface PaymentDetail {
51
+ /** Unique identifier for this record */
52
+ id: string;
53
+ /** Internal payment identifier (PAY_YYYYMMDDHHMMSS_UUID) */
54
+ internal_payment_id: string;
55
+ /** Payment amount in USD */
56
+ amount_usd: string;
57
+ currency_code: string;
58
+ currency_name: string;
59
+ currency_token: string;
60
+ currency_network: string;
61
+ /** Amount to pay in cryptocurrency */
62
+ pay_amount?: string | null;
63
+ /** Actual amount received in cryptocurrency */
64
+ actual_amount?: string | null;
65
+ /** Actual amount received in USD */
66
+ actual_amount_usd?: string | null;
67
+ /** Current payment status
68
+
69
+ * `pending` - Pending
70
+ * `confirming` - Confirming
71
+ * `confirmed` - Confirmed
72
+ * `completed` - Completed
73
+ * `partially_paid` - Partially Paid
74
+ * `failed` - Failed
75
+ * `expired` - Expired
76
+ * `cancelled` - Cancelled */
77
+ status: Enums.PaymentDetailStatus;
78
+ status_display: string;
79
+ /** Cryptocurrency payment address */
80
+ pay_address?: string | null;
81
+ /** Get QR code URL. */
82
+ qr_code_url?: string | null;
83
+ /** Payment page URL (if provided by provider) */
84
+ payment_url?: string | null;
85
+ /** Blockchain transaction hash */
86
+ transaction_hash?: string | null;
87
+ /** Get blockchain explorer link. */
88
+ explorer_link?: string | null;
89
+ /** Number of blockchain confirmations */
90
+ confirmations_count: number;
91
+ /** When this payment expires (typically 30 minutes) */
92
+ expires_at?: string | null;
93
+ /** When this payment was completed */
94
+ completed_at?: string | null;
95
+ /** When this record was created */
96
+ created_at: string;
97
+ is_completed: boolean;
98
+ is_failed: boolean;
99
+ is_expired: boolean;
100
+ /** Payment description */
101
+ description: string;
102
+ }
103
+
104
+ /**
105
+ * Payment list item (lighter than detail).
106
+ *
107
+ * Response model (includes read-only fields).
108
+ */
109
+ export interface PaymentList {
110
+ /** Unique identifier for this record */
111
+ id: string;
112
+ /** Internal payment identifier (PAY_YYYYMMDDHHMMSS_UUID) */
113
+ internal_payment_id: string;
114
+ /** Payment amount in USD */
115
+ amount_usd: string;
116
+ currency_code: string;
117
+ currency_token: string;
118
+ /** Current payment status
119
+
120
+ * `pending` - Pending
121
+ * `confirming` - Confirming
122
+ * `confirmed` - Confirmed
123
+ * `completed` - Completed
124
+ * `partially_paid` - Partially Paid
125
+ * `failed` - Failed
126
+ * `expired` - Expired
127
+ * `cancelled` - Cancelled */
128
+ status: Enums.PaymentListStatus;
129
+ status_display: string;
130
+ /** When this record was created */
131
+ created_at: string;
132
+ /** When this payment was completed */
133
+ completed_at?: string | null;
134
+ }
135
+
@@ -0,0 +1,103 @@
1
+ /**
2
+ * HTTP Client Adapter Pattern
3
+ *
4
+ * Allows switching between fetch/axios/httpx without changing generated code.
5
+ * Provides unified interface for making HTTP requests.
6
+ */
7
+
8
+ export interface HttpRequest {
9
+ method: string;
10
+ url: string;
11
+ headers?: Record<string, string>;
12
+ body?: any;
13
+ params?: Record<string, any>;
14
+ /** FormData for file uploads (multipart/form-data) */
15
+ formData?: FormData;
16
+ }
17
+
18
+ export interface HttpResponse<T = any> {
19
+ data: T;
20
+ status: number;
21
+ statusText: string;
22
+ headers: Record<string, string>;
23
+ }
24
+
25
+ /**
26
+ * HTTP Client Adapter Interface.
27
+ * Implement this to use custom HTTP clients (axios, httpx, etc.)
28
+ */
29
+ export interface HttpClientAdapter {
30
+ request<T = any>(request: HttpRequest): Promise<HttpResponse<T>>;
31
+ }
32
+
33
+ /**
34
+ * Default Fetch API adapter.
35
+ * Uses native browser fetch() with proper error handling.
36
+ */
37
+ export class FetchAdapter implements HttpClientAdapter {
38
+ async request<T = any>(request: HttpRequest): Promise<HttpResponse<T>> {
39
+ const { method, url, headers, body, params, formData } = request;
40
+
41
+ // Build URL with query params
42
+ let finalUrl = url;
43
+ if (params) {
44
+ const searchParams = new URLSearchParams();
45
+ Object.entries(params).forEach(([key, value]) => {
46
+ if (value !== null && value !== undefined) {
47
+ searchParams.append(key, String(value));
48
+ }
49
+ });
50
+ const queryString = searchParams.toString();
51
+ if (queryString) {
52
+ finalUrl = url.includes('?') ? `${url}&${queryString}` : `${url}?${queryString}`;
53
+ }
54
+ }
55
+
56
+ // Build headers
57
+ const finalHeaders: Record<string, string> = { ...headers };
58
+
59
+ // Determine body and content-type
60
+ let requestBody: string | FormData | undefined;
61
+
62
+ if (formData) {
63
+ // For multipart/form-data, let browser set Content-Type with boundary
64
+ requestBody = formData;
65
+ // Don't set Content-Type - browser will set it with boundary
66
+ } else if (body) {
67
+ // JSON request
68
+ finalHeaders['Content-Type'] = 'application/json';
69
+ requestBody = JSON.stringify(body);
70
+ }
71
+
72
+ // Make request
73
+ const response = await fetch(finalUrl, {
74
+ method,
75
+ headers: finalHeaders,
76
+ body: requestBody,
77
+ credentials: 'include', // Include Django session cookies
78
+ });
79
+
80
+ // Parse response
81
+ let data: any = null;
82
+ const contentType = response.headers.get('content-type');
83
+
84
+ if (response.status !== 204 && contentType?.includes('application/json')) {
85
+ data = await response.json();
86
+ } else if (response.status !== 204) {
87
+ data = await response.text();
88
+ }
89
+
90
+ // Convert Headers to plain object
91
+ const responseHeaders: Record<string, string> = {};
92
+ response.headers.forEach((value, key) => {
93
+ responseHeaders[key] = value;
94
+ });
95
+
96
+ return {
97
+ data,
98
+ status: response.status,
99
+ statusText: response.statusText,
100
+ headers: responseHeaders,
101
+ };
102
+ }
103
+ }