@djangocfg/ext-payments 1.0.14 → 1.0.19

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 (76) hide show
  1. package/dist/config.cjs +5 -8
  2. package/dist/config.js +5 -8
  3. package/dist/index.cjs +1906 -1043
  4. package/dist/index.d.cts +644 -59
  5. package/dist/index.d.ts +644 -59
  6. package/dist/index.js +1886 -1040
  7. package/package.json +13 -16
  8. package/src/WalletPage.tsx +100 -0
  9. package/src/api/generated/ext_payments/CLAUDE.md +10 -4
  10. package/src/api/generated/ext_payments/_utils/fetchers/ext_payments__payments.ts +268 -5
  11. package/src/api/generated/ext_payments/_utils/hooks/ext_payments__payments.ts +102 -3
  12. package/src/api/generated/ext_payments/_utils/schemas/Balance.schema.ts +1 -1
  13. package/src/api/generated/ext_payments/_utils/schemas/PaginatedWithdrawalListList.schema.ts +24 -0
  14. package/src/api/generated/ext_payments/_utils/schemas/PaymentCreateRequest.schema.ts +21 -0
  15. package/src/api/generated/ext_payments/_utils/schemas/PaymentCreateResponse.schema.ts +22 -0
  16. package/src/api/generated/ext_payments/_utils/schemas/PaymentDetail.schema.ts +3 -3
  17. package/src/api/generated/ext_payments/_utils/schemas/PaymentList.schema.ts +2 -2
  18. package/src/api/generated/ext_payments/_utils/schemas/Transaction.schema.ts +1 -1
  19. package/src/api/generated/ext_payments/_utils/schemas/WithdrawalCancelResponse.schema.ts +22 -0
  20. package/src/api/generated/ext_payments/_utils/schemas/WithdrawalCreateRequest.schema.ts +21 -0
  21. package/src/api/generated/ext_payments/_utils/schemas/WithdrawalCreateResponse.schema.ts +22 -0
  22. package/src/api/generated/ext_payments/_utils/schemas/WithdrawalDetail.schema.ts +42 -0
  23. package/src/api/generated/ext_payments/_utils/schemas/WithdrawalList.schema.ts +29 -0
  24. package/src/api/generated/ext_payments/_utils/schemas/index.ts +8 -0
  25. package/src/api/generated/ext_payments/client.ts +1 -1
  26. package/src/api/generated/ext_payments/enums.ts +36 -0
  27. package/src/api/generated/ext_payments/ext_payments__payments/client.ts +104 -6
  28. package/src/api/generated/ext_payments/ext_payments__payments/models.ts +168 -8
  29. package/src/api/generated/ext_payments/index.ts +1 -1
  30. package/src/api/generated/ext_payments/schema.json +752 -42
  31. package/src/components/ActivityItem.tsx +118 -0
  32. package/src/components/ActivityList.tsx +93 -0
  33. package/src/components/AddFundsSheet.tsx +342 -0
  34. package/src/components/BalanceHero.tsx +102 -0
  35. package/src/components/CurrencyCombobox.tsx +49 -0
  36. package/src/components/PaymentSheet.tsx +352 -0
  37. package/src/components/WithdrawSheet.tsx +355 -0
  38. package/src/components/WithdrawalSheet.tsx +332 -0
  39. package/src/components/index.ts +11 -0
  40. package/src/config.ts +1 -0
  41. package/src/contexts/WalletContext.tsx +356 -0
  42. package/src/contexts/index.ts +13 -42
  43. package/src/contexts/types.ts +43 -37
  44. package/src/hooks/index.ts +3 -20
  45. package/src/hooks/useCurrencyOptions.ts +79 -0
  46. package/src/hooks/useEstimate.ts +113 -0
  47. package/src/hooks/useWithdrawalEstimate.ts +117 -0
  48. package/src/index.ts +9 -18
  49. package/src/types/index.ts +78 -0
  50. package/src/utils/errors.ts +36 -0
  51. package/src/utils/format.ts +65 -0
  52. package/src/utils/index.ts +3 -0
  53. package/src/contexts/BalancesContext.tsx +0 -63
  54. package/src/contexts/CurrenciesContext.tsx +0 -64
  55. package/src/contexts/OverviewContext.tsx +0 -173
  56. package/src/contexts/PaymentsContext.tsx +0 -122
  57. package/src/contexts/PaymentsExtensionProvider.tsx +0 -56
  58. package/src/contexts/README.md +0 -201
  59. package/src/contexts/RootPaymentsContext.tsx +0 -66
  60. package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +0 -90
  61. package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +0 -274
  62. package/src/layouts/PaymentsLayout/components/PaymentDetailsDialog.tsx +0 -287
  63. package/src/layouts/PaymentsLayout/components/index.ts +0 -2
  64. package/src/layouts/PaymentsLayout/events.ts +0 -47
  65. package/src/layouts/PaymentsLayout/index.ts +0 -16
  66. package/src/layouts/PaymentsLayout/types.ts +0 -6
  67. package/src/layouts/PaymentsLayout/views/overview/components/BalanceCard.tsx +0 -121
  68. package/src/layouts/PaymentsLayout/views/overview/components/RecentPayments.tsx +0 -139
  69. package/src/layouts/PaymentsLayout/views/overview/components/index.ts +0 -2
  70. package/src/layouts/PaymentsLayout/views/overview/index.tsx +0 -21
  71. package/src/layouts/PaymentsLayout/views/payments/components/PaymentsList.tsx +0 -279
  72. package/src/layouts/PaymentsLayout/views/payments/components/index.ts +0 -1
  73. package/src/layouts/PaymentsLayout/views/payments/index.tsx +0 -18
  74. package/src/layouts/PaymentsLayout/views/transactions/components/TransactionsList.tsx +0 -260
  75. package/src/layouts/PaymentsLayout/views/transactions/components/index.ts +0 -1
  76. package/src/layouts/PaymentsLayout/views/transactions/index.tsx +0 -18
package/dist/index.js CHANGED
@@ -1,16 +1,16 @@
1
+ import { createContext, useState, useMemo, useCallback, useEffect, useContext, useRef } from 'react';
2
+ import { initializeExtensionAPI, createExtensionAPI } from '@djangocfg/ext-base/api';
1
3
  import { createConsola, consola } from 'consola';
2
4
  import pRetry, { AbortError } from 'p-retry';
3
5
  import { z } from 'zod';
4
- import { initializeExtensionAPI, createExtensionAPI } from '@djangocfg/ext-base/api';
5
- import { Wallet, CreditCard, History, RefreshCw, Plus, XCircle, ExternalLink, Search, Filter, Clock, AlertCircle, CheckCircle2, ArrowDownLeft, ArrowUpRight } from 'lucide-react';
6
- 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, Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '@djangocfg/ui-core';
7
- import { createContext, useState, useMemo, useEffect, useContext } from 'react';
8
- import useSWR, { SWRConfig, useSWRConfig } from 'swr';
9
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
+ import useSWR, { useSWRConfig } from 'swr';
7
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
8
+ import { Plus, ArrowUpRight, RefreshCw, AlertCircle, XCircle, CheckCircle2, Loader2, Clock, ArrowDownLeft, History, ChevronRight, Ban, ExternalLink } from 'lucide-react';
9
+ import { Skeleton, Button, TokenIcon, useLocalStorage, ResponsiveSheet, ResponsiveSheetContent, ResponsiveSheetHeader, ResponsiveSheetTitle, ResponsiveSheetDescription, Form, FormField, FormItem, FormLabel, FormControl, Input, FormMessage, Alert, AlertDescription, CopyButton, Combobox } from '@djangocfg/ui-core';
10
+ import { cn } from '@djangocfg/ui-core/lib';
11
+ import moment3 from 'moment';
10
12
  import { useForm } from 'react-hook-form';
11
13
  import { zodResolver } from '@hookform/resolvers/zod';
12
- import moment from 'moment';
13
- import { useDRFPagination, StaticPagination } from '@djangocfg/ui-nextjs/components';
14
14
  import { createExtensionConfig } from '@djangocfg/ext-base';
15
15
 
16
16
  var __defProp = Object.defineProperty;
@@ -37,12 +37,47 @@ var ExtPaymentsPayments = class {
37
37
  /**
38
38
  * Get available currencies
39
39
  *
40
- * Returns list of available currencies with token+network info
40
+ * Returns list of available currencies with token+network info, popular
41
+ * first
41
42
  */
42
43
  async currenciesList() {
43
44
  const response = await this.client.request("GET", "/cfg/payments/currencies/");
44
45
  return response;
45
46
  }
47
+ /**
48
+ * Get currency estimate
49
+ *
50
+ * Get estimated crypto amount for a given USD amount, including min amount
51
+ */
52
+ async currenciesEstimateRetrieve(...args) {
53
+ const code = args[0];
54
+ const isParamsObject = args.length === 2 && typeof args[1] === "object" && args[1] !== null && !Array.isArray(args[1]);
55
+ let params;
56
+ if (isParamsObject) {
57
+ params = args[1];
58
+ } else {
59
+ params = { amount: args[1] };
60
+ }
61
+ const response = await this.client.request("GET", `/cfg/payments/currencies/${code}/estimate/`, { params });
62
+ return response;
63
+ }
64
+ /**
65
+ * Get withdrawal estimate
66
+ *
67
+ * Get estimated crypto amount for withdrawal with fee breakdown
68
+ */
69
+ async currenciesWithdrawalEstimateRetrieve(...args) {
70
+ const code = args[0];
71
+ const isParamsObject = args.length === 2 && typeof args[1] === "object" && args[1] !== null && !Array.isArray(args[1]);
72
+ let params;
73
+ if (isParamsObject) {
74
+ params = args[1];
75
+ } else {
76
+ params = { amount: args[1] };
77
+ }
78
+ const response = await this.client.request("GET", `/cfg/payments/currencies/${code}/withdrawal-estimate/`, { params });
79
+ return response;
80
+ }
46
81
  /**
47
82
  * ViewSet for payment operations. Endpoints: - GET /payments/ - List
48
83
  * user's payments - GET /payments/{id}/ - Get payment details - POST
@@ -89,12 +124,12 @@ var ExtPaymentsPayments = class {
89
124
  return response.results || response;
90
125
  }
91
126
  /**
92
- * POST /api/v1/payments/create/ Create new payment. Request body: {
93
- * "amount_usd": "100.00", "currency_code": "USDTTRC20", "description":
94
- * "Optional description" }
127
+ * Create payment
128
+ *
129
+ * Create a new payment with specified amount and currency
95
130
  */
96
- async paymentsCreateCreate() {
97
- const response = await this.client.request("POST", "/cfg/payments/payments/create/");
131
+ async paymentsCreateCreate(data) {
132
+ const response = await this.client.request("POST", "/cfg/payments/payments/create/", { body: data });
98
133
  return response;
99
134
  }
100
135
  /**
@@ -113,6 +148,51 @@ var ExtPaymentsPayments = class {
113
148
  const response = await this.client.request("GET", "/cfg/payments/transactions/", { params });
114
149
  return response;
115
150
  }
151
+ /**
152
+ * ViewSet for withdrawal operations. Endpoints: - GET /withdrawals/ - List
153
+ * user's withdrawal requests - GET /withdrawals/{id}/ - Get withdrawal
154
+ * details - POST /withdrawals/create/ - Create withdrawal request - POST
155
+ * /withdrawals/{id}/cancel/ - Cancel pending withdrawal
156
+ */
157
+ async withdrawalsList(...args) {
158
+ const isParamsObject = args.length === 1 && typeof args[0] === "object" && args[0] !== null && !Array.isArray(args[0]);
159
+ let params;
160
+ if (isParamsObject) {
161
+ params = args[0];
162
+ } else {
163
+ params = { page: args[0], page_size: args[1] };
164
+ }
165
+ const response = await this.client.request("GET", "/cfg/payments/withdrawals/", { params });
166
+ return response;
167
+ }
168
+ /**
169
+ * ViewSet for withdrawal operations. Endpoints: - GET /withdrawals/ - List
170
+ * user's withdrawal requests - GET /withdrawals/{id}/ - Get withdrawal
171
+ * details - POST /withdrawals/create/ - Create withdrawal request - POST
172
+ * /withdrawals/{id}/cancel/ - Cancel pending withdrawal
173
+ */
174
+ async withdrawalsRetrieve(id) {
175
+ const response = await this.client.request("GET", `/cfg/payments/withdrawals/${id}/`);
176
+ return response;
177
+ }
178
+ /**
179
+ * Cancel withdrawal request
180
+ *
181
+ * Cancel a pending withdrawal request
182
+ */
183
+ async withdrawalsCancelCreate(id) {
184
+ const response = await this.client.request("POST", `/cfg/payments/withdrawals/${id}/cancel/`);
185
+ return response;
186
+ }
187
+ /**
188
+ * Create withdrawal request
189
+ *
190
+ * Create a new withdrawal request (requires admin approval)
191
+ */
192
+ async withdrawalsCreateCreate(data) {
193
+ const response = await this.client.request("POST", "/cfg/payments/withdrawals/create/", { body: data });
194
+ return response;
195
+ }
116
196
  };
117
197
 
118
198
  // src/api/generated/ext_payments/ext_payments__payments/models.ts
@@ -791,7 +871,9 @@ var enums_exports = {};
791
871
  __export(enums_exports, {
792
872
  PaymentDetailStatus: () => PaymentDetailStatus,
793
873
  PaymentListStatus: () => PaymentListStatus,
794
- TransactionTransactionType: () => TransactionTransactionType
874
+ TransactionTransactionType: () => TransactionTransactionType,
875
+ WithdrawalDetailStatus: () => WithdrawalDetailStatus,
876
+ WithdrawalListStatus: () => WithdrawalListStatus
795
877
  });
796
878
  var PaymentDetailStatus = /* @__PURE__ */ ((PaymentDetailStatus2) => {
797
879
  PaymentDetailStatus2["PENDING"] = "pending";
@@ -825,6 +907,24 @@ var TransactionTransactionType = /* @__PURE__ */ ((TransactionTransactionType2)
825
907
  TransactionTransactionType2["ADJUSTMENT"] = "adjustment";
826
908
  return TransactionTransactionType2;
827
909
  })(TransactionTransactionType || {});
910
+ var WithdrawalDetailStatus = /* @__PURE__ */ ((WithdrawalDetailStatus2) => {
911
+ WithdrawalDetailStatus2["PENDING"] = "pending";
912
+ WithdrawalDetailStatus2["APPROVED"] = "approved";
913
+ WithdrawalDetailStatus2["PROCESSING"] = "processing";
914
+ WithdrawalDetailStatus2["COMPLETED"] = "completed";
915
+ WithdrawalDetailStatus2["REJECTED"] = "rejected";
916
+ WithdrawalDetailStatus2["CANCELLED"] = "cancelled";
917
+ return WithdrawalDetailStatus2;
918
+ })(WithdrawalDetailStatus || {});
919
+ var WithdrawalListStatus = /* @__PURE__ */ ((WithdrawalListStatus2) => {
920
+ WithdrawalListStatus2["PENDING"] = "pending";
921
+ WithdrawalListStatus2["APPROVED"] = "approved";
922
+ WithdrawalListStatus2["PROCESSING"] = "processing";
923
+ WithdrawalListStatus2["COMPLETED"] = "completed";
924
+ WithdrawalListStatus2["REJECTED"] = "rejected";
925
+ WithdrawalListStatus2["CANCELLED"] = "cancelled";
926
+ return WithdrawalListStatus2;
927
+ })(WithdrawalListStatus || {});
828
928
 
829
929
  // src/api/generated/ext_payments/_utils/schemas/index.ts
830
930
  var schemas_exports = {};
@@ -832,16 +932,24 @@ __export(schemas_exports, {
832
932
  BalanceSchema: () => BalanceSchema,
833
933
  CurrencySchema: () => CurrencySchema,
834
934
  PaginatedPaymentListListSchema: () => PaginatedPaymentListListSchema,
935
+ PaginatedWithdrawalListListSchema: () => PaginatedWithdrawalListListSchema,
936
+ PaymentCreateRequestSchema: () => PaymentCreateRequestSchema,
937
+ PaymentCreateResponseSchema: () => PaymentCreateResponseSchema,
835
938
  PaymentDetailSchema: () => PaymentDetailSchema,
836
939
  PaymentListSchema: () => PaymentListSchema,
837
- TransactionSchema: () => TransactionSchema
940
+ TransactionSchema: () => TransactionSchema,
941
+ WithdrawalCancelResponseSchema: () => WithdrawalCancelResponseSchema,
942
+ WithdrawalCreateRequestSchema: () => WithdrawalCreateRequestSchema,
943
+ WithdrawalCreateResponseSchema: () => WithdrawalCreateResponseSchema,
944
+ WithdrawalDetailSchema: () => WithdrawalDetailSchema,
945
+ WithdrawalListSchema: () => WithdrawalListSchema
838
946
  });
839
947
  var BalanceSchema = z.object({
840
948
  balance_usd: z.string(),
841
949
  balance_display: z.string(),
842
950
  total_deposited: z.string(),
843
951
  total_withdrawn: z.string(),
844
- last_transaction_at: z.iso.datetime().nullable()
952
+ last_transaction_at: z.string().datetime({ offset: true }).nullable()
845
953
  });
846
954
  var CurrencySchema = z.object({
847
955
  code: z.string(),
@@ -863,8 +971,8 @@ var PaymentListSchema = z.object({
863
971
  currency_token: z.string(),
864
972
  status: z.nativeEnum(PaymentListStatus),
865
973
  status_display: z.string(),
866
- created_at: z.iso.datetime(),
867
- completed_at: z.iso.datetime().nullable()
974
+ created_at: z.string().datetime({ offset: true }),
975
+ completed_at: z.string().datetime({ offset: true }).nullable()
868
976
  });
869
977
 
870
978
  // src/api/generated/ext_payments/_utils/schemas/PaginatedPaymentListList.schema.ts
@@ -879,6 +987,36 @@ var PaginatedPaymentListListSchema = z.object({
879
987
  previous_page: z.int().nullable().optional(),
880
988
  results: z.array(PaymentListSchema)
881
989
  });
990
+ var WithdrawalListSchema = z.object({
991
+ 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),
992
+ internal_withdrawal_id: z.string(),
993
+ amount_usd: z.string(),
994
+ final_amount_usd: z.string(),
995
+ currency_code: z.string(),
996
+ currency_token: z.string(),
997
+ status: z.nativeEnum(WithdrawalListStatus),
998
+ status_display: z.string(),
999
+ created_at: z.string().datetime({ offset: true }),
1000
+ completed_at: z.string().datetime({ offset: true }).nullable()
1001
+ });
1002
+
1003
+ // src/api/generated/ext_payments/_utils/schemas/PaginatedWithdrawalListList.schema.ts
1004
+ var PaginatedWithdrawalListListSchema = z.object({
1005
+ count: z.int(),
1006
+ page: z.int(),
1007
+ pages: z.int(),
1008
+ page_size: z.int(),
1009
+ has_next: z.boolean(),
1010
+ has_previous: z.boolean(),
1011
+ next_page: z.int().nullable().optional(),
1012
+ previous_page: z.int().nullable().optional(),
1013
+ results: z.array(WithdrawalListSchema)
1014
+ });
1015
+ var PaymentCreateRequestSchema = z.object({
1016
+ amount_usd: z.string(),
1017
+ currency_code: z.string().min(1).max(20),
1018
+ description: z.string().max(500).optional()
1019
+ });
882
1020
  var PaymentDetailSchema = z.object({
883
1021
  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),
884
1022
  internal_payment_id: z.string(),
@@ -898,14 +1036,21 @@ var PaymentDetailSchema = z.object({
898
1036
  transaction_hash: z.string().nullable(),
899
1037
  explorer_link: z.string().nullable(),
900
1038
  confirmations_count: z.int(),
901
- expires_at: z.iso.datetime().nullable(),
902
- completed_at: z.iso.datetime().nullable(),
903
- created_at: z.iso.datetime(),
1039
+ expires_at: z.string().datetime({ offset: true }).nullable(),
1040
+ completed_at: z.string().datetime({ offset: true }).nullable(),
1041
+ created_at: z.string().datetime({ offset: true }),
904
1042
  is_completed: z.boolean(),
905
1043
  is_failed: z.boolean(),
906
1044
  is_expired: z.boolean(),
907
1045
  description: z.string()
908
1046
  });
1047
+
1048
+ // src/api/generated/ext_payments/_utils/schemas/PaymentCreateResponse.schema.ts
1049
+ var PaymentCreateResponseSchema = z.object({
1050
+ success: z.boolean(),
1051
+ payment: PaymentDetailSchema,
1052
+ qr_code_url: z.union([z.url(), z.literal("")]).nullable()
1053
+ });
909
1054
  var TransactionSchema = z.object({
910
1055
  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),
911
1056
  transaction_type: z.nativeEnum(TransactionTransactionType),
@@ -915,7 +1060,49 @@ var TransactionSchema = z.object({
915
1060
  balance_after: z.string(),
916
1061
  payment_id: z.string().nullable(),
917
1062
  description: z.string(),
918
- created_at: z.iso.datetime()
1063
+ created_at: z.string().datetime({ offset: true })
1064
+ });
1065
+ var WithdrawalDetailSchema = z.object({
1066
+ 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),
1067
+ internal_withdrawal_id: z.string(),
1068
+ amount_usd: z.string(),
1069
+ currency_code: z.string(),
1070
+ currency_name: z.string(),
1071
+ currency_token: z.string(),
1072
+ currency_network: z.string(),
1073
+ wallet_address: z.string(),
1074
+ network_fee_usd: z.string(),
1075
+ service_fee_usd: z.string(),
1076
+ total_fee_usd: z.string(),
1077
+ final_amount_usd: z.string(),
1078
+ crypto_amount: z.string().nullable(),
1079
+ status: z.nativeEnum(WithdrawalDetailStatus),
1080
+ status_display: z.string(),
1081
+ transaction_hash: z.string().nullable(),
1082
+ explorer_link: z.string().nullable(),
1083
+ admin_notes: z.string(),
1084
+ created_at: z.string().datetime({ offset: true }),
1085
+ approved_at: z.string().datetime({ offset: true }).nullable(),
1086
+ completed_at: z.string().datetime({ offset: true }).nullable(),
1087
+ rejected_at: z.string().datetime({ offset: true }).nullable(),
1088
+ cancelled_at: z.string().datetime({ offset: true }).nullable()
1089
+ });
1090
+
1091
+ // src/api/generated/ext_payments/_utils/schemas/WithdrawalCancelResponse.schema.ts
1092
+ var WithdrawalCancelResponseSchema = z.object({
1093
+ success: z.boolean(),
1094
+ withdrawal: WithdrawalDetailSchema,
1095
+ message: z.string()
1096
+ });
1097
+ var WithdrawalCreateRequestSchema = z.object({
1098
+ amount_usd: z.string(),
1099
+ currency_code: z.string().min(1).max(20),
1100
+ wallet_address: z.string().min(1).max(255)
1101
+ });
1102
+ var WithdrawalCreateResponseSchema = z.object({
1103
+ success: z.boolean(),
1104
+ withdrawal: WithdrawalDetailSchema,
1105
+ message: z.string()
919
1106
  });
920
1107
 
921
1108
  // src/api/generated/ext_payments/validation-events.ts
@@ -969,12 +1156,18 @@ var fetchers_exports = {};
969
1156
  __export(fetchers_exports, {
970
1157
  createPaymentsPaymentsConfirmCreate: () => createPaymentsPaymentsConfirmCreate,
971
1158
  createPaymentsPaymentsCreateCreate: () => createPaymentsPaymentsCreateCreate,
1159
+ createPaymentsWithdrawalsCancelCreate: () => createPaymentsWithdrawalsCancelCreate,
1160
+ createPaymentsWithdrawalsCreateCreate: () => createPaymentsWithdrawalsCreateCreate,
972
1161
  getPaymentsBalanceRetrieve: () => getPaymentsBalanceRetrieve,
1162
+ getPaymentsCurrenciesEstimateRetrieve: () => getPaymentsCurrenciesEstimateRetrieve,
973
1163
  getPaymentsCurrenciesList: () => getPaymentsCurrenciesList,
1164
+ getPaymentsCurrenciesWithdrawalEstimateRetrieve: () => getPaymentsCurrenciesWithdrawalEstimateRetrieve,
974
1165
  getPaymentsPaymentsList: () => getPaymentsPaymentsList,
975
1166
  getPaymentsPaymentsRetrieve: () => getPaymentsPaymentsRetrieve,
976
1167
  getPaymentsPaymentsStatusRetrieve: () => getPaymentsPaymentsStatusRetrieve,
977
- getPaymentsTransactionsList: () => getPaymentsTransactionsList
1168
+ getPaymentsTransactionsList: () => getPaymentsTransactionsList,
1169
+ getPaymentsWithdrawalsList: () => getPaymentsWithdrawalsList,
1170
+ getPaymentsWithdrawalsRetrieve: () => getPaymentsWithdrawalsRetrieve
978
1171
  });
979
1172
 
980
1173
  // src/api/generated/ext_payments/api-instance.ts
@@ -1079,6 +1272,16 @@ async function getPaymentsCurrenciesList(client) {
1079
1272
  const response = await api.ext_payments_payments.currenciesList();
1080
1273
  return response;
1081
1274
  }
1275
+ async function getPaymentsCurrenciesEstimateRetrieve(code, params, client) {
1276
+ const api = client || getAPIInstance();
1277
+ const response = await api.ext_payments_payments.currenciesEstimateRetrieve(code, params?.amount);
1278
+ return response;
1279
+ }
1280
+ async function getPaymentsCurrenciesWithdrawalEstimateRetrieve(code, params, client) {
1281
+ const api = client || getAPIInstance();
1282
+ const response = await api.ext_payments_payments.currenciesWithdrawalEstimateRetrieve(code, params?.amount);
1283
+ return response;
1284
+ }
1082
1285
  async function getPaymentsPaymentsList(params, client) {
1083
1286
  const api = client || getAPIInstance();
1084
1287
  const response = await api.ext_payments_payments.paymentsList(params?.page, params?.page_size);
@@ -1247,11 +1450,11 @@ Method: GET`);
1247
1450
  throw error;
1248
1451
  }
1249
1452
  }
1250
- async function createPaymentsPaymentsCreateCreate(client) {
1453
+ async function createPaymentsPaymentsCreateCreate(data, client) {
1251
1454
  const api = client || getAPIInstance();
1252
- const response = await api.ext_payments_payments.paymentsCreateCreate();
1455
+ const response = await api.ext_payments_payments.paymentsCreateCreate(data);
1253
1456
  try {
1254
- return PaymentListSchema.parse(response);
1457
+ return PaymentCreateResponseSchema.parse(response);
1255
1458
  } catch (error) {
1256
1459
  consola.error("\u274C Zod Validation Failed");
1257
1460
  consola.box(`createPaymentsPaymentsCreateCreate
@@ -1294,6 +1497,174 @@ async function getPaymentsTransactionsList(params, client) {
1294
1497
  const response = await api.ext_payments_payments.transactionsList(params?.limit, params?.offset, params?.type);
1295
1498
  return response;
1296
1499
  }
1500
+ async function getPaymentsWithdrawalsList(params, client) {
1501
+ const api = client || getAPIInstance();
1502
+ const response = await api.ext_payments_payments.withdrawalsList(params?.page, params?.page_size);
1503
+ try {
1504
+ return PaginatedWithdrawalListListSchema.parse(response);
1505
+ } catch (error) {
1506
+ consola.error("\u274C Zod Validation Failed");
1507
+ consola.box(`getPaymentsWithdrawalsList
1508
+ Path: /cfg/payments/withdrawals/
1509
+ Method: GET`);
1510
+ if (error instanceof Error && "issues" in error && Array.isArray(error.issues)) {
1511
+ consola.error("Validation Issues:");
1512
+ error.issues.forEach((issue, index) => {
1513
+ consola.error(` ${index + 1}. ${issue.path.join(".") || "root"}`);
1514
+ consola.error(` \u251C\u2500 Message: ${issue.message}`);
1515
+ if (issue.expected) consola.error(` \u251C\u2500 Expected: ${issue.expected}`);
1516
+ if (issue.received) consola.error(` \u2514\u2500 Received: ${issue.received}`);
1517
+ });
1518
+ }
1519
+ consola.error("Response data:", response);
1520
+ if (typeof window !== "undefined" && error instanceof Error && "issues" in error) {
1521
+ try {
1522
+ const event = new CustomEvent("zod-validation-error", {
1523
+ detail: {
1524
+ operation: "getPaymentsWithdrawalsList",
1525
+ path: "/cfg/payments/withdrawals/",
1526
+ method: "GET",
1527
+ error,
1528
+ response,
1529
+ timestamp: /* @__PURE__ */ new Date()
1530
+ },
1531
+ bubbles: true,
1532
+ cancelable: false
1533
+ });
1534
+ window.dispatchEvent(event);
1535
+ } catch (eventError) {
1536
+ consola.warn("Failed to dispatch validation error event:", eventError);
1537
+ }
1538
+ }
1539
+ throw error;
1540
+ }
1541
+ }
1542
+ async function getPaymentsWithdrawalsRetrieve(id, client) {
1543
+ const api = client || getAPIInstance();
1544
+ const response = await api.ext_payments_payments.withdrawalsRetrieve(id);
1545
+ try {
1546
+ return WithdrawalDetailSchema.parse(response);
1547
+ } catch (error) {
1548
+ consola.error("\u274C Zod Validation Failed");
1549
+ consola.box(`getPaymentsWithdrawalsRetrieve
1550
+ Path: /cfg/payments/withdrawals/{id}/
1551
+ Method: GET`);
1552
+ if (error instanceof Error && "issues" in error && Array.isArray(error.issues)) {
1553
+ consola.error("Validation Issues:");
1554
+ error.issues.forEach((issue, index) => {
1555
+ consola.error(` ${index + 1}. ${issue.path.join(".") || "root"}`);
1556
+ consola.error(` \u251C\u2500 Message: ${issue.message}`);
1557
+ if (issue.expected) consola.error(` \u251C\u2500 Expected: ${issue.expected}`);
1558
+ if (issue.received) consola.error(` \u2514\u2500 Received: ${issue.received}`);
1559
+ });
1560
+ }
1561
+ consola.error("Response data:", response);
1562
+ if (typeof window !== "undefined" && error instanceof Error && "issues" in error) {
1563
+ try {
1564
+ const event = new CustomEvent("zod-validation-error", {
1565
+ detail: {
1566
+ operation: "getPaymentsWithdrawalsRetrieve",
1567
+ path: "/cfg/payments/withdrawals/{id}/",
1568
+ method: "GET",
1569
+ error,
1570
+ response,
1571
+ timestamp: /* @__PURE__ */ new Date()
1572
+ },
1573
+ bubbles: true,
1574
+ cancelable: false
1575
+ });
1576
+ window.dispatchEvent(event);
1577
+ } catch (eventError) {
1578
+ consola.warn("Failed to dispatch validation error event:", eventError);
1579
+ }
1580
+ }
1581
+ throw error;
1582
+ }
1583
+ }
1584
+ async function createPaymentsWithdrawalsCancelCreate(id, client) {
1585
+ const api = client || getAPIInstance();
1586
+ const response = await api.ext_payments_payments.withdrawalsCancelCreate(id);
1587
+ try {
1588
+ return WithdrawalCancelResponseSchema.parse(response);
1589
+ } catch (error) {
1590
+ consola.error("\u274C Zod Validation Failed");
1591
+ consola.box(`createPaymentsWithdrawalsCancelCreate
1592
+ Path: /cfg/payments/withdrawals/{id}/cancel/
1593
+ Method: POST`);
1594
+ if (error instanceof Error && "issues" in error && Array.isArray(error.issues)) {
1595
+ consola.error("Validation Issues:");
1596
+ error.issues.forEach((issue, index) => {
1597
+ consola.error(` ${index + 1}. ${issue.path.join(".") || "root"}`);
1598
+ consola.error(` \u251C\u2500 Message: ${issue.message}`);
1599
+ if (issue.expected) consola.error(` \u251C\u2500 Expected: ${issue.expected}`);
1600
+ if (issue.received) consola.error(` \u2514\u2500 Received: ${issue.received}`);
1601
+ });
1602
+ }
1603
+ consola.error("Response data:", response);
1604
+ if (typeof window !== "undefined" && error instanceof Error && "issues" in error) {
1605
+ try {
1606
+ const event = new CustomEvent("zod-validation-error", {
1607
+ detail: {
1608
+ operation: "createPaymentsWithdrawalsCancelCreate",
1609
+ path: "/cfg/payments/withdrawals/{id}/cancel/",
1610
+ method: "POST",
1611
+ error,
1612
+ response,
1613
+ timestamp: /* @__PURE__ */ new Date()
1614
+ },
1615
+ bubbles: true,
1616
+ cancelable: false
1617
+ });
1618
+ window.dispatchEvent(event);
1619
+ } catch (eventError) {
1620
+ consola.warn("Failed to dispatch validation error event:", eventError);
1621
+ }
1622
+ }
1623
+ throw error;
1624
+ }
1625
+ }
1626
+ async function createPaymentsWithdrawalsCreateCreate(data, client) {
1627
+ const api = client || getAPIInstance();
1628
+ const response = await api.ext_payments_payments.withdrawalsCreateCreate(data);
1629
+ try {
1630
+ return WithdrawalCreateResponseSchema.parse(response);
1631
+ } catch (error) {
1632
+ consola.error("\u274C Zod Validation Failed");
1633
+ consola.box(`createPaymentsWithdrawalsCreateCreate
1634
+ Path: /cfg/payments/withdrawals/create/
1635
+ Method: POST`);
1636
+ if (error instanceof Error && "issues" in error && Array.isArray(error.issues)) {
1637
+ consola.error("Validation Issues:");
1638
+ error.issues.forEach((issue, index) => {
1639
+ consola.error(` ${index + 1}. ${issue.path.join(".") || "root"}`);
1640
+ consola.error(` \u251C\u2500 Message: ${issue.message}`);
1641
+ if (issue.expected) consola.error(` \u251C\u2500 Expected: ${issue.expected}`);
1642
+ if (issue.received) consola.error(` \u2514\u2500 Received: ${issue.received}`);
1643
+ });
1644
+ }
1645
+ consola.error("Response data:", response);
1646
+ if (typeof window !== "undefined" && error instanceof Error && "issues" in error) {
1647
+ try {
1648
+ const event = new CustomEvent("zod-validation-error", {
1649
+ detail: {
1650
+ operation: "createPaymentsWithdrawalsCreateCreate",
1651
+ path: "/cfg/payments/withdrawals/create/",
1652
+ method: "POST",
1653
+ error,
1654
+ response,
1655
+ timestamp: /* @__PURE__ */ new Date()
1656
+ },
1657
+ bubbles: true,
1658
+ cancelable: false
1659
+ });
1660
+ window.dispatchEvent(event);
1661
+ } catch (eventError) {
1662
+ consola.warn("Failed to dispatch validation error event:", eventError);
1663
+ }
1664
+ }
1665
+ throw error;
1666
+ }
1667
+ }
1297
1668
 
1298
1669
  // src/api/generated/ext_payments/index.ts
1299
1670
  var TOKEN_KEY = "auth_token";
@@ -1420,6 +1791,8 @@ var API = class {
1420
1791
  return "./schema.json";
1421
1792
  }
1422
1793
  };
1794
+
1795
+ // src/api/index.ts
1423
1796
  initializeExtensionAPI(configureAPI);
1424
1797
  var apiPayments = createExtensionAPI(API);
1425
1798
  function usePaymentsBalanceRetrieve(client) {
@@ -1440,24 +1813,10 @@ function usePaymentsPaymentsList(params, client) {
1440
1813
  () => getPaymentsPaymentsList(params, client)
1441
1814
  );
1442
1815
  }
1443
- function usePaymentsPaymentsRetrieve(id, client) {
1444
- return useSWR(
1445
- ["cfg-payments-payment", id],
1446
- () => getPaymentsPaymentsRetrieve(id, client)
1447
- );
1448
- }
1449
- function useCreatePaymentsPaymentsConfirmCreate() {
1450
- const { mutate } = useSWRConfig();
1451
- return async (id, client) => {
1452
- const result = await createPaymentsPaymentsConfirmCreate(id, client);
1453
- mutate("cfg-payments-payments-confirm");
1454
- return result;
1455
- };
1456
- }
1457
1816
  function useCreatePaymentsPaymentsCreateCreate() {
1458
1817
  const { mutate } = useSWRConfig();
1459
- return async (client) => {
1460
- const result = await createPaymentsPaymentsCreateCreate(client);
1818
+ return async (data, client) => {
1819
+ const result = await createPaymentsPaymentsCreateCreate(data, client);
1461
1820
  mutate("cfg-payments-payments");
1462
1821
  return result;
1463
1822
  };
@@ -1468,287 +1827,1001 @@ function usePaymentsTransactionsList(params, client) {
1468
1827
  () => getPaymentsTransactionsList(params, client)
1469
1828
  );
1470
1829
  }
1471
- var PaymentsContext = createContext(void 0);
1472
- function PaymentsProvider({ children }) {
1473
- const {
1474
- data: payments,
1475
- error: paymentsError,
1476
- isLoading: isLoadingPayments,
1477
- mutate: mutatePayments
1478
- } = usePaymentsPaymentsList({ page: 1, page_size: 1 }, apiPayments);
1479
- const refreshPayments = async () => {
1480
- await mutatePayments();
1481
- };
1482
- const createPaymentMutation = useCreatePaymentsPaymentsCreateCreate();
1483
- const confirmPaymentMutation = useCreatePaymentsPaymentsConfirmCreate();
1484
- const getPayment = async (id) => {
1485
- return getPaymentsPaymentsRetrieve(id, apiPayments);
1486
- };
1487
- const createPayment = async () => {
1488
- const result = await createPaymentMutation(apiPayments);
1489
- await refreshPayments();
1830
+ function usePaymentsWithdrawalsList(params, client) {
1831
+ return useSWR(
1832
+ params ? ["cfg-payments-withdrawals", params] : "cfg-payments-withdrawals",
1833
+ () => getPaymentsWithdrawalsList(params, client)
1834
+ );
1835
+ }
1836
+ function useCreatePaymentsWithdrawalsCancelCreate() {
1837
+ const { mutate } = useSWRConfig();
1838
+ return async (id, client) => {
1839
+ const result = await createPaymentsWithdrawalsCancelCreate(id, client);
1840
+ mutate("cfg-payments-withdrawals-cancel");
1490
1841
  return result;
1491
1842
  };
1492
- const confirmPayment = async (id) => {
1493
- const result = await confirmPaymentMutation(id, apiPayments);
1494
- await refreshPayments();
1843
+ }
1844
+ function useCreatePaymentsWithdrawalsCreateCreate() {
1845
+ const { mutate } = useSWRConfig();
1846
+ return async (data, client) => {
1847
+ const result = await createPaymentsWithdrawalsCreateCreate(data, client);
1848
+ mutate("cfg-payments-withdrawals");
1495
1849
  return result;
1496
1850
  };
1497
- const checkPaymentStatus = async (id) => {
1498
- return getPaymentsPaymentsStatusRetrieve(id, apiPayments);
1499
- };
1500
- const value = {
1501
- payments,
1502
- isLoadingPayments,
1503
- paymentsError,
1504
- refreshPayments,
1505
- getPayment,
1506
- createPayment,
1507
- confirmPayment,
1508
- checkPaymentStatus
1509
- };
1510
- return /* @__PURE__ */ jsx(PaymentsContext.Provider, { value, children });
1511
1851
  }
1512
- function usePaymentsContext() {
1513
- const context = useContext(PaymentsContext);
1514
- if (!context) {
1515
- throw new Error("usePaymentsContext must be used within PaymentsProvider");
1516
- }
1517
- return context;
1518
- }
1519
- createContext(void 0);
1520
- createContext(void 0);
1521
- var OverviewContext = createContext(void 0);
1522
- function OverviewProvider({ children }) {
1523
- const swrConfig = {
1524
- revalidateOnFocus: false,
1525
- revalidateOnReconnect: false,
1526
- revalidateIfStale: false
1527
- };
1852
+ var WalletContext = createContext(void 0);
1853
+ function WalletProvider({ children }) {
1528
1854
  const {
1529
1855
  data: balance,
1530
- error: balanceError,
1531
1856
  isLoading: isLoadingBalance,
1532
1857
  mutate: mutateBalance
1533
1858
  } = usePaymentsBalanceRetrieve(apiPayments);
1534
1859
  const {
1535
- data: payments,
1536
- error: paymentsError,
1860
+ data: paymentsData,
1537
1861
  isLoading: isLoadingPayments,
1538
1862
  mutate: mutatePayments
1539
- } = usePaymentsPaymentsList({}, apiPayments);
1863
+ } = usePaymentsPaymentsList({ page: 1, page_size: 20 }, apiPayments);
1540
1864
  const {
1541
- data: transactions,
1542
- error: transactionsError,
1865
+ data: transactionsData,
1543
1866
  isLoading: isLoadingTransactions,
1544
1867
  mutate: mutateTransactions
1545
- } = usePaymentsTransactionsList({}, apiPayments);
1868
+ } = usePaymentsTransactionsList({ limit: 20 }, apiPayments);
1869
+ const {
1870
+ data: currenciesData,
1871
+ isLoading: isLoadingCurrencies,
1872
+ mutate: mutateCurrencies
1873
+ } = usePaymentsCurrenciesList(apiPayments);
1874
+ const {
1875
+ data: withdrawalsData,
1876
+ isLoading: isLoadingWithdrawals,
1877
+ mutate: mutateWithdrawals
1878
+ } = usePaymentsWithdrawalsList({ page: 1, page_size: 20 }, apiPayments);
1546
1879
  const createPaymentMutation = useCreatePaymentsPaymentsCreateCreate();
1547
- const isLoadingOverview = isLoadingBalance || isLoadingPayments || isLoadingTransactions;
1548
- const overviewError = balanceError || paymentsError || transactionsError;
1549
- const refreshBalance = async () => {
1550
- await mutateBalance();
1551
- };
1552
- const refreshPayments = async () => {
1553
- await mutatePayments();
1554
- };
1555
- const refreshTransactions = async () => {
1556
- await mutateTransactions();
1557
- };
1558
- const refreshOverview = async () => {
1880
+ const createWithdrawalMutation = useCreatePaymentsWithdrawalsCreateCreate();
1881
+ const cancelWithdrawalMutation = useCreatePaymentsWithdrawalsCancelCreate();
1882
+ const balanceAmount = useMemo(() => {
1883
+ if (!balance?.balance_usd) return 0;
1884
+ return parseFloat(balance.balance_usd) || 0;
1885
+ }, [balance]);
1886
+ const activity = useMemo(() => {
1887
+ const items = [];
1888
+ const payments = paymentsData?.results || [];
1889
+ for (const payment of payments) {
1890
+ items.push({
1891
+ id: `payment-${payment.id}`,
1892
+ type: "payment",
1893
+ amount: payment.amount_usd,
1894
+ amountDisplay: `+$${parseFloat(payment.amount_usd).toFixed(2)}`,
1895
+ currency: payment.currency_code,
1896
+ status: mapPaymentStatus(payment.status),
1897
+ statusDisplay: payment.status_display,
1898
+ description: `${payment.currency_code} payment`,
1899
+ createdAt: payment.created_at,
1900
+ payment
1901
+ });
1902
+ }
1903
+ const withdrawals = withdrawalsData?.results || [];
1904
+ for (const withdrawal of withdrawals) {
1905
+ items.push({
1906
+ id: `withdrawal-${withdrawal.id}`,
1907
+ type: "withdrawal",
1908
+ amount: withdrawal.amount_usd,
1909
+ amountDisplay: `-$${parseFloat(withdrawal.amount_usd).toFixed(2)}`,
1910
+ currency: withdrawal.currency_code,
1911
+ status: mapWithdrawalStatus(withdrawal.status),
1912
+ statusDisplay: withdrawal.status_display,
1913
+ description: `${withdrawal.currency_code} withdrawal`,
1914
+ createdAt: withdrawal.created_at,
1915
+ withdrawal
1916
+ });
1917
+ }
1918
+ const transactions = transactionsData?.results || transactionsData || [];
1919
+ if (Array.isArray(transactions)) {
1920
+ for (const tx of transactions) {
1921
+ if (tx.payment_id && payments.some((p) => p.id === tx.payment_id)) {
1922
+ continue;
1923
+ }
1924
+ const isDeposit = tx.transaction_type === "deposit";
1925
+ items.push({
1926
+ id: `tx-${tx.id}`,
1927
+ type: isDeposit ? "deposit" : "withdrawal",
1928
+ amount: tx.amount_usd,
1929
+ amountDisplay: `${isDeposit ? "+" : "-"}$${Math.abs(parseFloat(tx.amount_usd)).toFixed(2)}`,
1930
+ status: "completed",
1931
+ statusDisplay: "Completed",
1932
+ description: tx.description || tx.type_display,
1933
+ createdAt: tx.created_at,
1934
+ transaction: tx
1935
+ });
1936
+ }
1937
+ }
1938
+ items.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
1939
+ return items;
1940
+ }, [paymentsData, withdrawalsData, transactionsData]);
1941
+ const currencies = useMemo(() => {
1942
+ const data = currenciesData?.currencies || currenciesData?.results || currenciesData || [];
1943
+ if (!Array.isArray(data)) return [];
1944
+ return data.filter((c) => c.is_enabled !== false).map((c) => ({
1945
+ code: c.code || c.currency_code || c.symbol,
1946
+ name: c.name || c.code,
1947
+ token: c.token || c.code,
1948
+ // Token symbol (e.g., USDT, WBTC) with fallback to code
1949
+ network: c.network || void 0,
1950
+ enabled: c.is_enabled !== false
1951
+ }));
1952
+ }, [currenciesData]);
1953
+ const addFunds = useCallback(async (data) => {
1954
+ const response = await createPaymentMutation(data, apiPayments);
1955
+ await Promise.all([mutateBalance(), mutatePayments(), mutateTransactions()]);
1956
+ return response.payment;
1957
+ }, [createPaymentMutation, mutateBalance, mutatePayments, mutateTransactions]);
1958
+ const withdraw = useCallback(async (data) => {
1959
+ const response = await createWithdrawalMutation(data, apiPayments);
1960
+ await Promise.all([mutateBalance(), mutateWithdrawals(), mutateTransactions()]);
1961
+ return response.withdrawal;
1962
+ }, [createWithdrawalMutation, mutateBalance, mutateWithdrawals, mutateTransactions]);
1963
+ const cancelWithdrawal = useCallback(async (id) => {
1964
+ await cancelWithdrawalMutation(id, apiPayments);
1965
+ await Promise.all([mutateBalance(), mutateWithdrawals(), mutateTransactions()]);
1966
+ }, [cancelWithdrawalMutation, mutateBalance, mutateWithdrawals, mutateTransactions]);
1967
+ const getPaymentDetails = useCallback(async (id) => {
1968
+ return apiPayments.ext_payments_payments.paymentsRetrieve(id);
1969
+ }, []);
1970
+ const getWithdrawalDetails = useCallback(async (id) => {
1971
+ return apiPayments.ext_payments_payments.withdrawalsRetrieve(id);
1972
+ }, []);
1973
+ const refreshWallet = useCallback(async () => {
1559
1974
  await Promise.all([
1560
1975
  mutateBalance(),
1561
1976
  mutatePayments(),
1562
- mutateTransactions()
1977
+ mutateWithdrawals(),
1978
+ mutateTransactions(),
1979
+ mutateCurrencies()
1563
1980
  ]);
1564
- };
1565
- const createPayment = async () => {
1566
- const result = await createPaymentMutation(apiPayments);
1567
- await refreshOverview();
1568
- return result;
1569
- };
1981
+ }, [mutateBalance, mutatePayments, mutateWithdrawals, mutateTransactions, mutateCurrencies]);
1982
+ const isLoading = isLoadingBalance || isLoadingPayments || isLoadingWithdrawals || isLoadingTransactions;
1983
+ const isLoadingActivity = isLoadingPayments || isLoadingWithdrawals || isLoadingTransactions;
1570
1984
  const value = {
1571
1985
  balance,
1986
+ balanceAmount,
1572
1987
  isLoadingBalance,
1573
- balanceError,
1574
- refreshBalance,
1575
- payments,
1576
- isLoadingPayments,
1577
- paymentsError,
1578
- refreshPayments,
1579
- transactions,
1580
- isLoadingTransactions,
1581
- transactionsError,
1582
- refreshTransactions,
1583
- createPayment,
1584
- isLoadingOverview,
1585
- overviewError,
1586
- refreshOverview
1988
+ activity,
1989
+ isLoadingActivity,
1990
+ hasMoreActivity: (paymentsData?.count || 0) > 20 || (withdrawalsData?.count || 0) > 20,
1991
+ currencies,
1992
+ isLoadingCurrencies,
1993
+ addFunds,
1994
+ withdraw,
1995
+ cancelWithdrawal,
1996
+ getPaymentDetails,
1997
+ getWithdrawalDetails,
1998
+ refreshWallet,
1999
+ isLoading
1587
2000
  };
1588
- return /* @__PURE__ */ jsx(SWRConfig, { value: swrConfig, children: /* @__PURE__ */ jsx(OverviewContext.Provider, { value, children }) });
2001
+ return /* @__PURE__ */ jsx(WalletContext.Provider, { value, children });
1589
2002
  }
1590
- function useOverviewContext() {
1591
- const context = useContext(OverviewContext);
2003
+ function useWallet() {
2004
+ const context = useContext(WalletContext);
1592
2005
  if (!context) {
1593
- throw new Error("useOverviewContext must be used within OverviewProvider");
2006
+ throw new Error("useWallet must be used within WalletProvider");
1594
2007
  }
1595
2008
  return context;
1596
2009
  }
1597
- var RootPaymentsContext = createContext(void 0);
1598
- function RootPaymentsProvider({ children }) {
1599
- const {
1600
- data: currencies,
1601
- error: currenciesError,
1602
- isLoading: isLoadingCurrencies,
1603
- mutate: mutateCurrencies
1604
- } = usePaymentsCurrenciesList(apiPayments);
1605
- const refreshCurrencies = async () => {
1606
- await mutateCurrencies();
1607
- };
1608
- const value = {
1609
- currencies,
1610
- isLoadingCurrencies,
1611
- currenciesError,
1612
- refreshCurrencies
1613
- };
1614
- return /* @__PURE__ */ jsx(RootPaymentsContext.Provider, { value, children });
2010
+ function mapPaymentStatus(status) {
2011
+ switch (status?.toLowerCase()) {
2012
+ case "completed":
2013
+ case "success":
2014
+ case "finished":
2015
+ return "completed";
2016
+ case "pending":
2017
+ case "waiting":
2018
+ return "pending";
2019
+ case "confirming":
2020
+ case "partially_paid":
2021
+ return "confirming";
2022
+ case "expired":
2023
+ return "expired";
2024
+ case "failed":
2025
+ case "error":
2026
+ case "cancelled":
2027
+ return "failed";
2028
+ default:
2029
+ return "pending";
2030
+ }
1615
2031
  }
1616
- function useRootPaymentsContext() {
1617
- const context = useContext(RootPaymentsContext);
1618
- if (!context) {
1619
- throw new Error("useRootPaymentsContext must be used within RootPaymentsProvider");
2032
+ function mapWithdrawalStatus(status) {
2033
+ switch (status?.toLowerCase()) {
2034
+ case "completed":
2035
+ return "completed";
2036
+ case "pending":
2037
+ case "approved":
2038
+ return "pending";
2039
+ case "processing":
2040
+ return "confirming";
2041
+ case "rejected":
2042
+ case "cancelled":
2043
+ return "failed";
2044
+ default:
2045
+ return "pending";
1620
2046
  }
1621
- return context;
2047
+ }
2048
+ function BalanceHero({ onAddFunds, onWithdraw, className }) {
2049
+ const { balance, balanceAmount, isLoadingBalance, refreshWallet } = useWallet();
2050
+ const formattedBalance = new Intl.NumberFormat("en-US", {
2051
+ style: "currency",
2052
+ currency: "USD",
2053
+ minimumFractionDigits: 2,
2054
+ maximumFractionDigits: 2
2055
+ }).format(balanceAmount);
2056
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col items-center py-16 px-4", className), children: [
2057
+ /* @__PURE__ */ jsx("div", { className: "text-center mb-6", children: isLoadingBalance ? /* @__PURE__ */ jsxs(Fragment, { children: [
2058
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-48 mx-auto mb-2" }),
2059
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24 mx-auto" })
2060
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2061
+ /* @__PURE__ */ jsx("h1", { className: "text-5xl font-bold tracking-tight tabular-nums", children: formattedBalance }),
2062
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground mt-1", children: "Available Balance" })
2063
+ ] }) }),
2064
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2065
+ /* @__PURE__ */ jsxs(
2066
+ Button,
2067
+ {
2068
+ size: "lg",
2069
+ onClick: onAddFunds,
2070
+ className: "rounded-full px-6",
2071
+ children: [
2072
+ /* @__PURE__ */ jsx(Plus, { className: "h-5 w-5 mr-2" }),
2073
+ "Add Funds"
2074
+ ]
2075
+ }
2076
+ ),
2077
+ /* @__PURE__ */ jsxs(
2078
+ Button,
2079
+ {
2080
+ size: "lg",
2081
+ variant: "outline",
2082
+ onClick: onWithdraw,
2083
+ className: "rounded-full px-6",
2084
+ children: [
2085
+ /* @__PURE__ */ jsx(ArrowUpRight, { className: "h-5 w-5 mr-2" }),
2086
+ "Withdraw"
2087
+ ]
2088
+ }
2089
+ ),
2090
+ /* @__PURE__ */ jsx(
2091
+ Button,
2092
+ {
2093
+ size: "icon",
2094
+ variant: "ghost",
2095
+ onClick: () => refreshWallet(),
2096
+ className: "rounded-full",
2097
+ children: /* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4" })
2098
+ }
2099
+ )
2100
+ ] }),
2101
+ balance && !isLoadingBalance && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-6 mt-6 text-sm text-muted-foreground", children: [
2102
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
2103
+ /* @__PURE__ */ jsxs("span", { className: "block font-medium text-foreground", children: [
2104
+ "$",
2105
+ parseFloat(balance.total_deposited || "0").toFixed(2)
2106
+ ] }),
2107
+ /* @__PURE__ */ jsx("span", { children: "Total Deposited" })
2108
+ ] }),
2109
+ /* @__PURE__ */ jsx("div", { className: "h-8 w-px bg-border" }),
2110
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
2111
+ /* @__PURE__ */ jsxs("span", { className: "block font-medium text-foreground", children: [
2112
+ "$",
2113
+ parseFloat(balance.total_withdrawn || "0").toFixed(2)
2114
+ ] }),
2115
+ /* @__PURE__ */ jsx("span", { children: "Total Withdrawn" })
2116
+ ] })
2117
+ ] })
2118
+ ] });
2119
+ }
2120
+ var statusConfig = {
2121
+ pending: {
2122
+ icon: Clock,
2123
+ color: "text-yellow-500",
2124
+ bg: "bg-yellow-500/10"
2125
+ },
2126
+ confirming: {
2127
+ icon: Loader2,
2128
+ color: "text-blue-500",
2129
+ bg: "bg-blue-500/10",
2130
+ animate: true
2131
+ },
2132
+ completed: {
2133
+ icon: CheckCircle2,
2134
+ color: "text-green-500",
2135
+ bg: "bg-green-500/10"
2136
+ },
2137
+ failed: {
2138
+ icon: XCircle,
2139
+ color: "text-red-500",
2140
+ bg: "bg-red-500/10"
2141
+ },
2142
+ expired: {
2143
+ icon: AlertCircle,
2144
+ color: "text-muted-foreground",
2145
+ bg: "bg-muted"
2146
+ }
2147
+ };
2148
+ function ActivityItem({ item, onClick }) {
2149
+ const config = statusConfig[item.status];
2150
+ const StatusIcon = config.icon;
2151
+ const isPositive = item.type === "payment" || item.type === "deposit";
2152
+ const DirectionIcon = isPositive ? ArrowDownLeft : ArrowUpRight;
2153
+ const relativeTime = moment3(item.createdAt).fromNow();
2154
+ return /* @__PURE__ */ jsxs(
2155
+ "button",
2156
+ {
2157
+ onClick,
2158
+ className: cn(
2159
+ "w-full flex items-center gap-4 p-4 rounded-xl",
2160
+ "cursor-pointer",
2161
+ "hover:bg-accent active:bg-accent/80 transition-colors",
2162
+ "text-left"
2163
+ ),
2164
+ children: [
2165
+ /* @__PURE__ */ jsx("div", { className: cn(
2166
+ "flex items-center justify-center w-10 h-10 rounded-full",
2167
+ isPositive ? "bg-green-500/10" : "bg-red-500/10"
2168
+ ), children: item.currency ? /* @__PURE__ */ jsx(TokenIcon, { symbol: item.currency, size: 24 }) : /* @__PURE__ */ jsx(DirectionIcon, { className: cn(
2169
+ "h-5 w-5",
2170
+ isPositive ? "text-green-500" : "text-red-500"
2171
+ ) }) }),
2172
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
2173
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx("span", { className: "font-medium truncate", children: item.description }) }),
2174
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
2175
+ /* @__PURE__ */ jsx("span", { children: relativeTime }),
2176
+ item.status !== "completed" && /* @__PURE__ */ jsxs(Fragment, { children: [
2177
+ /* @__PURE__ */ jsx("span", { children: "\xB7" }),
2178
+ /* @__PURE__ */ jsxs("span", { className: cn("flex items-center gap-1", config.color), children: [
2179
+ /* @__PURE__ */ jsx(StatusIcon, { className: cn("h-3 w-3", config.animate && "animate-spin") }),
2180
+ item.statusDisplay
2181
+ ] })
2182
+ ] })
2183
+ ] })
2184
+ ] }),
2185
+ /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
2186
+ /* @__PURE__ */ jsx("span", { className: cn(
2187
+ "font-semibold tabular-nums",
2188
+ isPositive ? "text-green-600 dark:text-green-400" : "text-foreground"
2189
+ ), children: item.amountDisplay }),
2190
+ item.status === "completed" && /* @__PURE__ */ jsx(CheckCircle2, { className: "h-4 w-4 text-green-500 ml-2 inline-block" })
2191
+ ] })
2192
+ ]
2193
+ }
2194
+ );
2195
+ }
2196
+ function ActivityList({
2197
+ onItemClick,
2198
+ onViewAll,
2199
+ limit = 10,
2200
+ className
2201
+ }) {
2202
+ const { activity, isLoadingActivity, hasMoreActivity } = useWallet();
2203
+ const displayedActivity = limit ? activity.slice(0, limit) : activity;
2204
+ if (isLoadingActivity) {
2205
+ return /* @__PURE__ */ jsxs("div", { className: cn("space-y-2", className), children: [
2206
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between px-4 py-2", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-32" }) }),
2207
+ [1, 2, 3, 4, 5].map((i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 p-4", children: [
2208
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-10 rounded-full" }),
2209
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-2", children: [
2210
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" }),
2211
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" })
2212
+ ] }),
2213
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-16" })
2214
+ ] }, i))
2215
+ ] });
2216
+ }
2217
+ if (activity.length === 0) {
2218
+ return /* @__PURE__ */ jsxs("div", { className: cn("text-center py-12", className), children: [
2219
+ /* @__PURE__ */ jsx("div", { className: "inline-flex items-center justify-center w-16 h-16 rounded-full bg-muted mb-4", children: /* @__PURE__ */ jsx(History, { className: "h-8 w-8 text-muted-foreground" }) }),
2220
+ /* @__PURE__ */ jsx("h3", { className: "font-semibold mb-1", children: "No Activity Yet" }),
2221
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Your transactions will appear here" })
2222
+ ] });
2223
+ }
2224
+ return /* @__PURE__ */ jsxs("div", { className: cn("pt-6", className), children: [
2225
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-2", children: [
2226
+ /* @__PURE__ */ jsx("h2", { className: "font-semibold text-lg", children: "Recent Activity" }),
2227
+ hasMoreActivity && onViewAll && /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: onViewAll, className: "text-primary", children: [
2228
+ "View All",
2229
+ /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4 ml-1" })
2230
+ ] })
2231
+ ] }),
2232
+ /* @__PURE__ */ jsx("div", { className: "divide-y divide-border/50", children: displayedActivity.map((item) => /* @__PURE__ */ jsx(
2233
+ ActivityItem,
2234
+ {
2235
+ item,
2236
+ onClick: () => onItemClick?.(item)
2237
+ },
2238
+ item.id
2239
+ )) })
2240
+ ] });
2241
+ }
2242
+ function useEstimate({
2243
+ currencyCode,
2244
+ amountUsd,
2245
+ minAmount = 0,
2246
+ debounceMs = 300,
2247
+ skip = false
2248
+ }) {
2249
+ const [estimate, setEstimate] = useState(null);
2250
+ const [isLoading, setIsLoading] = useState(false);
2251
+ const [error, setError] = useState(null);
2252
+ useEffect(() => {
2253
+ if (skip || !currencyCode || amountUsd < minAmount) {
2254
+ setEstimate(null);
2255
+ setError(null);
2256
+ return;
2257
+ }
2258
+ const fetchEstimate = async () => {
2259
+ setIsLoading(true);
2260
+ setError(null);
2261
+ try {
2262
+ const response = await apiPayments.ext_payments_payments.currenciesEstimateRetrieve(
2263
+ currencyCode,
2264
+ { amount: amountUsd }
2265
+ );
2266
+ if (response?.success && response?.estimated_amount) {
2267
+ setEstimate({
2268
+ estimatedAmount: parseFloat(response.estimated_amount),
2269
+ usdRate: parseFloat(response.usd_rate) || 0,
2270
+ minAmountUsd: response.min_amount_usd ? parseFloat(response.min_amount_usd) : null,
2271
+ isStablecoin: response.is_stablecoin || false,
2272
+ // New fee fields
2273
+ amountToReceive: parseFloat(response.amount_to_receive) || amountUsd,
2274
+ serviceFeeUsd: parseFloat(response.service_fee_usd) || 0,
2275
+ serviceFeePercent: parseFloat(response.service_fee_percent) || 0,
2276
+ totalToPayUsd: parseFloat(response.total_to_pay_usd) || amountUsd
2277
+ });
2278
+ } else {
2279
+ setEstimate(null);
2280
+ }
2281
+ } catch (err) {
2282
+ console.error("Failed to fetch estimate:", err);
2283
+ setEstimate(null);
2284
+ setError(err instanceof Error ? err : new Error("Failed to fetch estimate"));
2285
+ } finally {
2286
+ setIsLoading(false);
2287
+ }
2288
+ };
2289
+ const timeoutId = setTimeout(fetchEstimate, debounceMs);
2290
+ return () => clearTimeout(timeoutId);
2291
+ }, [currencyCode, amountUsd, minAmount, debounceMs, skip]);
2292
+ return { estimate, isLoading, error };
2293
+ }
2294
+ function useWithdrawalEstimate({
2295
+ currencyCode,
2296
+ amountUsd,
2297
+ minAmount = 10,
2298
+ debounceMs = 300,
2299
+ skip = false
2300
+ }) {
2301
+ const [estimate, setEstimate] = useState(null);
2302
+ const [isLoading, setIsLoading] = useState(false);
2303
+ const [error, setError] = useState(null);
2304
+ useEffect(() => {
2305
+ if (skip || !currencyCode || amountUsd < minAmount) {
2306
+ setEstimate(null);
2307
+ setError(null);
2308
+ return;
2309
+ }
2310
+ const fetchEstimate = async () => {
2311
+ setIsLoading(true);
2312
+ setError(null);
2313
+ try {
2314
+ const response = await apiPayments.ext_payments_payments.currenciesWithdrawalEstimateRetrieve(
2315
+ currencyCode,
2316
+ { amount: amountUsd }
2317
+ );
2318
+ if (response?.success && response?.estimated_amount) {
2319
+ setEstimate({
2320
+ estimatedAmount: parseFloat(response.estimated_amount),
2321
+ usdRate: parseFloat(response.usd_rate) || 0,
2322
+ minAmountUsd: response.min_amount_usd ? parseFloat(response.min_amount_usd) : null,
2323
+ isStablecoin: response.is_stablecoin || false,
2324
+ // Withdrawal-specific fields
2325
+ amountRequested: parseFloat(response.amount_requested) || amountUsd,
2326
+ serviceFeeUsd: parseFloat(response.service_fee_usd) || 0,
2327
+ serviceFeePercent: parseFloat(response.service_fee_percent) || 0,
2328
+ networkFeeUsd: parseFloat(response.network_fee_usd) || 0,
2329
+ totalFeesUsd: parseFloat(response.total_fees_usd) || 0,
2330
+ amountToReceive: parseFloat(response.amount_to_receive) || 0
2331
+ });
2332
+ } else {
2333
+ setEstimate(null);
2334
+ }
2335
+ } catch (err) {
2336
+ console.error("Failed to fetch withdrawal estimate:", err);
2337
+ setEstimate(null);
2338
+ setError(err instanceof Error ? err : new Error("Failed to fetch withdrawal estimate"));
2339
+ } finally {
2340
+ setIsLoading(false);
2341
+ }
2342
+ };
2343
+ const timeoutId = setTimeout(fetchEstimate, debounceMs);
2344
+ return () => clearTimeout(timeoutId);
2345
+ }, [currencyCode, amountUsd, minAmount, debounceMs, skip]);
2346
+ return { estimate, isLoading, error };
2347
+ }
2348
+ function useCurrencyOptions(currencies) {
2349
+ return useMemo(() => {
2350
+ return currencies.map((c) => ({
2351
+ value: c.code,
2352
+ label: c.name,
2353
+ token: c.token,
2354
+ network: c.network
2355
+ }));
2356
+ }, [currencies]);
2357
+ }
2358
+ function useDefaultCurrency({
2359
+ currencyOptions,
2360
+ savedCurrency,
2361
+ currentValue,
2362
+ setValue
2363
+ }) {
2364
+ useEffect(() => {
2365
+ if (currencyOptions.length > 0 && !currentValue) {
2366
+ const savedOption = savedCurrency && currencyOptions.find((c) => c.value === savedCurrency);
2367
+ if (savedOption) {
2368
+ setValue(savedOption.value);
2369
+ } else {
2370
+ const usdt = currencyOptions.find((c) => c.value.includes("USDT"));
2371
+ setValue(usdt?.value || currencyOptions[0].value);
2372
+ }
2373
+ }
2374
+ }, [currencyOptions, savedCurrency, currentValue, setValue]);
2375
+ }
2376
+ function useAutoSave(value, save, validate) {
2377
+ const saveRef = useRef(save);
2378
+ const validateRef = useRef(validate);
2379
+ useEffect(() => {
2380
+ saveRef.current = save;
2381
+ validateRef.current = validate;
2382
+ });
2383
+ useEffect(() => {
2384
+ const isValid = validateRef.current ? validateRef.current(value) : Boolean(value);
2385
+ if (isValid) {
2386
+ saveRef.current(value);
2387
+ }
2388
+ }, [value]);
2389
+ }
2390
+
2391
+ // src/utils/format.ts
2392
+ function formatUsdRate(rate) {
2393
+ if (rate >= 1) {
2394
+ return rate.toLocaleString(void 0, {
2395
+ minimumFractionDigits: 2,
2396
+ maximumFractionDigits: 2
2397
+ });
2398
+ } else if (rate >= 0.01) {
2399
+ return rate.toLocaleString(void 0, {
2400
+ minimumFractionDigits: 2,
2401
+ maximumFractionDigits: 4
2402
+ });
2403
+ } else if (rate >= 1e-4) {
2404
+ return rate.toLocaleString(void 0, {
2405
+ minimumFractionDigits: 4,
2406
+ maximumFractionDigits: 6
2407
+ });
2408
+ } else {
2409
+ return rate.toLocaleString(void 0, {
2410
+ minimumFractionDigits: 6,
2411
+ maximumFractionDigits: 8
2412
+ });
2413
+ }
2414
+ }
2415
+ function formatCryptoAmount(amount, isStablecoin) {
2416
+ const decimals = isStablecoin ? 2 : 8;
2417
+ return amount.toFixed(decimals);
2418
+ }
2419
+ function formatUsdAmount(amount, alwaysShowCents = false) {
2420
+ if (alwaysShowCents) {
2421
+ return amount.toFixed(2);
2422
+ }
2423
+ const hasCents = amount % 1 !== 0;
2424
+ if (hasCents) {
2425
+ return amount.toFixed(2);
2426
+ }
2427
+ return amount.toFixed(0);
2428
+ }
2429
+
2430
+ // src/utils/errors.ts
2431
+ function extractErrorMessage(err, fallback = "An error occurred") {
2432
+ if (!err) return fallback;
2433
+ const error = err;
2434
+ const responseData = error.response?.data;
2435
+ const response = responseData || error.response;
2436
+ if (response) {
2437
+ if (typeof response.error === "string") return response.error;
2438
+ if (typeof response.message === "string") return response.message;
2439
+ if (typeof response.detail === "string") return response.detail;
2440
+ }
2441
+ if (typeof error.errorMessage === "string") return error.errorMessage;
2442
+ if (typeof error.message === "string") return error.message;
2443
+ return fallback;
1622
2444
  }
1623
2445
  var isDevelopment = process.env.NODE_ENV === "development";
1624
- var logger = createConsola({
2446
+ createConsola({
1625
2447
  level: isDevelopment ? 4 : 1
1626
2448
  }).withTag("ext-payments");
1627
- var paymentsLogger = logger;
1628
-
1629
- // src/layouts/PaymentsLayout/events.ts
1630
- var PAYMENT_EVENTS = {
1631
- OPEN_CREATE_PAYMENT_DIALOG: "payments:open-create-payment",
1632
- OPEN_PAYMENT_DETAILS_DIALOG: "payments:open-payment-details",
1633
- CLOSE_DIALOG: "payments:close-dialog"
1634
- };
1635
- var openCreatePaymentDialog = () => {
1636
- window.dispatchEvent(new Event(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG));
1637
- };
1638
- var openPaymentDetailsDialog = (id) => {
1639
- window.dispatchEvent(
1640
- new CustomEvent(PAYMENT_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG, {
1641
- detail: { id }
1642
- })
2449
+ function CurrencyCombobox({
2450
+ options,
2451
+ value,
2452
+ onChange,
2453
+ disabled,
2454
+ placeholder = "Select currency..."
2455
+ }) {
2456
+ return /* @__PURE__ */ jsx(
2457
+ Combobox,
2458
+ {
2459
+ options,
2460
+ value,
2461
+ onValueChange: onChange,
2462
+ placeholder,
2463
+ searchPlaceholder: "Search...",
2464
+ disabled,
2465
+ className: "h-14",
2466
+ renderOption: (option) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 flex-1", children: [
2467
+ /* @__PURE__ */ jsx(TokenIcon, { symbol: option.value, size: 24 }),
2468
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: option.label })
2469
+ ] }),
2470
+ renderValue: (option) => option && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2471
+ /* @__PURE__ */ jsx(TokenIcon, { symbol: option.value, size: 24 }),
2472
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: option.label })
2473
+ ] })
2474
+ }
1643
2475
  );
1644
- };
1645
- var closePaymentsDialog = () => {
1646
- window.dispatchEvent(new Event(PAYMENT_EVENTS.CLOSE_DIALOG));
1647
- };
1648
- var PaymentCreateSchema = z.object({
1649
- amount_usd: z.number().min(0.01, "Amount must be at least $0.01"),
1650
- currency_code: z.string().min(1, "Please select a currency")
2476
+ }
2477
+ var AddFundsSchema = z.object({
2478
+ amount: z.number().min(1, "Minimum $1"),
2479
+ currency: z.string().min(1, "Select a currency")
1651
2480
  });
1652
- var CreatePaymentDialog = () => {
1653
- const [open, setOpen] = useState(false);
2481
+ var STORAGE_KEY = "payments:addFunds";
2482
+ function AddFundsSheet({ open, onOpenChange, onSuccess }) {
2483
+ const { currencies, isLoadingCurrencies, addFunds } = useWallet();
1654
2484
  const [isSubmitting, setIsSubmitting] = useState(false);
1655
- const { createPayment } = usePaymentsContext();
1656
- const { currencies, isLoadingCurrencies } = useRootPaymentsContext();
2485
+ const [error, setError] = useState(null);
2486
+ const [saved, setSaved] = useLocalStorage(STORAGE_KEY, {
2487
+ currency: "",
2488
+ amount: 100
2489
+ });
1657
2490
  const form = useForm({
1658
- resolver: zodResolver(PaymentCreateSchema),
2491
+ resolver: zodResolver(AddFundsSchema),
1659
2492
  defaultValues: {
1660
- amount_usd: 10,
1661
- currency_code: "USDT"
2493
+ amount: saved.amount,
2494
+ currency: saved.currency
1662
2495
  }
1663
2496
  });
1664
- const currenciesList = useMemo(() => {
1665
- const data = currencies?.currencies || currencies?.results || currencies || [];
1666
- return Array.isArray(data) ? data : [];
1667
- }, [currencies]);
1668
- const currencyOptions = useMemo(() => {
1669
- return currenciesList.filter((curr) => curr.is_enabled !== false).map((curr) => ({
1670
- code: curr.code || curr.currency_code || curr.symbol,
1671
- name: curr.name || curr.code || curr.currency_code,
1672
- usd_rate: curr.usd_rate || curr.rate || 1,
1673
- network: curr.network || null
1674
- }));
1675
- }, [currenciesList]);
1676
- const calculateCryptoAmount = useMemo(() => {
1677
- const amountUsd = form.watch("amount_usd");
1678
- const currencyCode = form.watch("currency_code");
1679
- const currency = currencyOptions.find((c) => c.code === currencyCode);
1680
- if (!currency || !currency.usd_rate || !amountUsd) {
1681
- return null;
1682
- }
1683
- const cryptoAmount = amountUsd / currency.usd_rate;
2497
+ const watchedAmount = form.watch("amount");
2498
+ const watchedCurrency = form.watch("currency");
2499
+ useAutoSave(watchedAmount, (v) => setSaved((prev) => ({ ...prev, amount: v })), (v) => v > 0);
2500
+ useAutoSave(watchedCurrency, (v) => setSaved((prev) => ({ ...prev, currency: v })));
2501
+ const currencyOptions = useCurrencyOptions(currencies);
2502
+ useDefaultCurrency({
2503
+ currencyOptions,
2504
+ savedCurrency: saved.currency,
2505
+ currentValue: watchedCurrency,
2506
+ setValue: (v) => form.setValue("currency", v)
2507
+ });
2508
+ const { estimate, isLoading: isLoadingEstimate } = useEstimate({
2509
+ currencyCode: watchedCurrency,
2510
+ amountUsd: watchedAmount,
2511
+ minAmount: 1
2512
+ });
2513
+ const selectedCurrency = currencyOptions.find((c) => c.value === watchedCurrency);
2514
+ const displayData = useMemo(() => {
2515
+ if (!selectedCurrency || !estimate) return null;
2516
+ const token = selectedCurrency.token;
2517
+ const cryptoAmount = formatCryptoAmount(estimate.estimatedAmount, estimate.isStablecoin);
2518
+ const rate = formatUsdRate(estimate.usdRate);
2519
+ const belowMinimum = estimate.minAmountUsd ? watchedAmount < estimate.minAmountUsd : false;
2520
+ const minAmount = estimate.minAmountUsd ? formatUsdAmount(estimate.minAmountUsd) : void 0;
1684
2521
  return {
1685
- amount: cryptoAmount,
1686
- currency: currency.code,
1687
- rate: currency.usd_rate,
1688
- network: currency.network
1689
- };
1690
- }, [form.watch("amount_usd"), form.watch("currency_code"), currencyOptions]);
1691
- useEffect(() => {
1692
- const handleOpen = () => setOpen(true);
1693
- const handleClose2 = () => setOpen(false);
1694
- window.addEventListener(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG, handleOpen);
1695
- window.addEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
1696
- return () => {
1697
- window.removeEventListener(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG, handleOpen);
1698
- window.removeEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
2522
+ token,
2523
+ cryptoAmount,
2524
+ rate,
2525
+ showRate: !estimate.isStablecoin && estimate.usdRate > 0,
2526
+ belowMinimum,
2527
+ minAmount,
2528
+ // Fee breakdown from API
2529
+ amountToReceive: estimate.amountToReceive,
2530
+ serviceFeeUsd: estimate.serviceFeeUsd,
2531
+ serviceFeePercent: estimate.serviceFeePercent,
2532
+ totalToPayUsd: estimate.totalToPayUsd
1699
2533
  };
1700
- }, []);
1701
- const handleClose = () => {
1702
- setOpen(false);
1703
- form.reset();
1704
- };
1705
- useEffect(() => {
1706
- if (currencyOptions.length > 0 && !form.getValues("currency_code")) {
1707
- form.setValue("currency_code", currencyOptions[0].code);
2534
+ }, [selectedCurrency, estimate, watchedAmount]);
2535
+ const handleSubmit = useCallback(async (data) => {
2536
+ try {
2537
+ setIsSubmitting(true);
2538
+ setError(null);
2539
+ const result = await addFunds({
2540
+ amount_usd: String(data.amount),
2541
+ currency_code: data.currency
2542
+ });
2543
+ form.reset();
2544
+ onOpenChange(false);
2545
+ onSuccess?.(result);
2546
+ } catch (err) {
2547
+ setError(extractErrorMessage(err, "Failed to create payment"));
2548
+ } finally {
2549
+ setIsSubmitting(false);
2550
+ }
2551
+ }, [addFunds, form, onOpenChange, onSuccess]);
2552
+ const handleOpenChange = useCallback((open2) => {
2553
+ if (open2) {
2554
+ form.reset({
2555
+ amount: saved.amount,
2556
+ currency: saved.currency
2557
+ });
2558
+ } else {
2559
+ setError(null);
2560
+ }
2561
+ onOpenChange(open2);
2562
+ }, [form, onOpenChange, saved]);
2563
+ return /* @__PURE__ */ jsx(ResponsiveSheet, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs(ResponsiveSheetContent, { className: "sm:max-w-md", children: [
2564
+ /* @__PURE__ */ jsxs(ResponsiveSheetHeader, { children: [
2565
+ /* @__PURE__ */ jsx(ResponsiveSheetTitle, { children: "Add Funds" }),
2566
+ /* @__PURE__ */ jsx(ResponsiveSheetDescription, { children: "Add funds to your wallet using cryptocurrency" })
2567
+ ] }),
2568
+ /* @__PURE__ */ jsx(Form, { ...form, children: /* @__PURE__ */ jsxs("form", { onSubmit: form.handleSubmit(handleSubmit), className: "space-y-6 p-4 sm:p-0 sm:mt-4", children: [
2569
+ /* @__PURE__ */ jsx(
2570
+ FormField,
2571
+ {
2572
+ control: form.control,
2573
+ name: "amount",
2574
+ render: ({ field }) => /* @__PURE__ */ jsxs(FormItem, { children: [
2575
+ /* @__PURE__ */ jsx(FormLabel, { children: "Amount (USD)" }),
2576
+ /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
2577
+ /* @__PURE__ */ jsx("span", { className: "absolute left-4 top-1/2 -translate-y-1/2 text-muted-foreground text-lg", children: "$" }),
2578
+ /* @__PURE__ */ jsx(
2579
+ Input,
2580
+ {
2581
+ type: "number",
2582
+ step: "0.01",
2583
+ min: "1",
2584
+ placeholder: "100",
2585
+ className: "pl-8 text-2xl h-14 font-semibold",
2586
+ ...field,
2587
+ onChange: (e) => field.onChange(parseFloat(e.target.value) || 0)
2588
+ }
2589
+ )
2590
+ ] }) }),
2591
+ /* @__PURE__ */ jsx(FormMessage, {})
2592
+ ] })
2593
+ }
2594
+ ),
2595
+ /* @__PURE__ */ jsx(
2596
+ FormField,
2597
+ {
2598
+ control: form.control,
2599
+ name: "currency",
2600
+ render: ({ field }) => /* @__PURE__ */ jsxs(FormItem, { children: [
2601
+ /* @__PURE__ */ jsx(FormLabel, { children: "Pay with" }),
2602
+ /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(
2603
+ CurrencyCombobox,
2604
+ {
2605
+ options: currencyOptions,
2606
+ value: field.value,
2607
+ onChange: field.onChange,
2608
+ disabled: isLoadingCurrencies
2609
+ }
2610
+ ) }),
2611
+ /* @__PURE__ */ jsx(FormMessage, {})
2612
+ ] })
2613
+ }
2614
+ ),
2615
+ selectedCurrency && watchedAmount >= 1 && /* @__PURE__ */ jsx("div", { className: "bg-muted rounded-xl p-4 space-y-2", children: isLoadingEstimate ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center py-2", children: [
2616
+ /* @__PURE__ */ jsx(Loader2, { className: "h-5 w-5 animate-spin text-muted-foreground" }),
2617
+ /* @__PURE__ */ jsx("span", { className: "ml-2 text-sm text-muted-foreground", children: "Getting rate..." })
2618
+ ] }) : displayData ? /* @__PURE__ */ jsxs(Fragment, { children: [
2619
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
2620
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Amount" }),
2621
+ /* @__PURE__ */ jsxs("span", { children: [
2622
+ "$",
2623
+ formatUsdAmount(displayData.amountToReceive)
2624
+ ] })
2625
+ ] }),
2626
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
2627
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
2628
+ "Service fee (",
2629
+ displayData.serviceFeePercent,
2630
+ "%)"
2631
+ ] }),
2632
+ /* @__PURE__ */ jsxs("span", { children: [
2633
+ "+$",
2634
+ formatUsdAmount(displayData.serviceFeeUsd)
2635
+ ] })
2636
+ ] }),
2637
+ displayData.showRate && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm text-muted-foreground", children: [
2638
+ /* @__PURE__ */ jsx("span", { children: "Rate" }),
2639
+ /* @__PURE__ */ jsxs("span", { children: [
2640
+ "1 ",
2641
+ displayData.token,
2642
+ " = $",
2643
+ displayData.rate
2644
+ ] })
2645
+ ] }),
2646
+ /* @__PURE__ */ jsx("div", { className: "border-t pt-2 mt-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2647
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "You will send" }),
2648
+ /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
2649
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 justify-end", children: [
2650
+ /* @__PURE__ */ jsx(TokenIcon, { symbol: displayData.token, size: 20 }),
2651
+ /* @__PURE__ */ jsxs("span", { className: "font-mono font-semibold text-lg", children: [
2652
+ displayData.cryptoAmount,
2653
+ " ",
2654
+ displayData.token
2655
+ ] })
2656
+ ] }),
2657
+ /* @__PURE__ */ jsxs("div", { className: "text-sm text-muted-foreground", children: [
2658
+ "~$",
2659
+ formatUsdAmount(displayData.totalToPayUsd)
2660
+ ] })
2661
+ ] })
2662
+ ] }) }),
2663
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm pt-2", children: [
2664
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "You will receive" }),
2665
+ /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
2666
+ "$",
2667
+ formatUsdAmount(displayData.amountToReceive)
2668
+ ] })
2669
+ ] }),
2670
+ displayData.belowMinimum && displayData.minAmount && /* @__PURE__ */ jsxs("div", { className: "text-sm text-destructive mt-2 pt-2 border-t border-destructive/20", children: [
2671
+ "Minimum amount: $",
2672
+ displayData.minAmount
2673
+ ] })
2674
+ ] }) : /* @__PURE__ */ jsx("div", { className: "text-center text-sm text-muted-foreground py-2", children: "Enter amount to see conversion" }) }),
2675
+ error && /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: /* @__PURE__ */ jsx(AlertDescription, { children: error }) }),
2676
+ /* @__PURE__ */ jsx(
2677
+ Button,
2678
+ {
2679
+ type: "submit",
2680
+ size: "lg",
2681
+ className: "w-full h-14 text-lg rounded-xl",
2682
+ disabled: isSubmitting || currencyOptions.length === 0 || isLoadingEstimate || displayData?.belowMinimum,
2683
+ children: isSubmitting ? /* @__PURE__ */ jsxs(Fragment, { children: [
2684
+ /* @__PURE__ */ jsx(RefreshCw, { className: "h-5 w-5 mr-2 animate-spin" }),
2685
+ "Creating..."
2686
+ ] }) : "Continue"
2687
+ }
2688
+ )
2689
+ ] }) })
2690
+ ] }) });
2691
+ }
2692
+ var WithdrawSchema = z.object({
2693
+ amount: z.number().min(10, "Minimum $10"),
2694
+ currency: z.string().min(1, "Select a currency"),
2695
+ wallet_address: z.string().min(26, "Invalid wallet address")
2696
+ });
2697
+ var STORAGE_KEY2 = "payments:withdraw";
2698
+ function WithdrawSheet({ open, onOpenChange, onSuccess }) {
2699
+ const { currencies, isLoadingCurrencies, withdraw, balanceAmount } = useWallet();
2700
+ const [isSubmitting, setIsSubmitting] = useState(false);
2701
+ const [error, setError] = useState(null);
2702
+ const [saved, setSaved] = useLocalStorage(STORAGE_KEY2, {
2703
+ currency: "",
2704
+ wallet: ""
2705
+ });
2706
+ const form = useForm({
2707
+ resolver: zodResolver(WithdrawSchema),
2708
+ defaultValues: {
2709
+ amount: 10,
2710
+ currency: saved.currency,
2711
+ wallet_address: saved.wallet
1708
2712
  }
1709
- }, [currencyOptions, form]);
1710
- const handleSubmit = async (data) => {
2713
+ });
2714
+ const watchedAmount = form.watch("amount");
2715
+ const watchedCurrency = form.watch("currency");
2716
+ const watchedWallet = form.watch("wallet_address");
2717
+ useAutoSave(watchedCurrency, (v) => setSaved((prev) => ({ ...prev, currency: v })));
2718
+ useAutoSave(watchedWallet, (v) => setSaved((prev) => ({ ...prev, wallet: v })), (v) => v.length >= 26);
2719
+ const currencyOptions = useCurrencyOptions(currencies);
2720
+ useDefaultCurrency({
2721
+ currencyOptions,
2722
+ savedCurrency: saved.currency,
2723
+ currentValue: watchedCurrency,
2724
+ setValue: (v) => form.setValue("currency", v)
2725
+ });
2726
+ const selectedCurrency = currencyOptions.find((c) => c.value === watchedCurrency);
2727
+ const amount = watchedAmount || 0;
2728
+ const { estimate, isLoading: isLoadingEstimate } = useWithdrawalEstimate({
2729
+ currencyCode: watchedCurrency,
2730
+ amountUsd: amount,
2731
+ minAmount: 10,
2732
+ skip: amount < 10
2733
+ });
2734
+ const cryptoDisplay = useMemo(() => {
2735
+ if (!selectedCurrency || !estimate) return null;
2736
+ return {
2737
+ token: selectedCurrency.token,
2738
+ cryptoAmount: formatCryptoAmount(estimate.estimatedAmount, estimate.isStablecoin)
2739
+ };
2740
+ }, [selectedCurrency, estimate]);
2741
+ const insufficientBalance = amount > balanceAmount;
2742
+ const handleSubmit = useCallback(async (data) => {
1711
2743
  try {
1712
2744
  setIsSubmitting(true);
1713
- const result = await createPayment();
1714
- handleClose();
1715
- closePaymentsDialog();
1716
- const paymentData = result;
1717
- const paymentId = paymentData?.payment?.id || paymentData?.id;
1718
- if (paymentId) {
1719
- openPaymentDetailsDialog(String(paymentId));
1720
- }
1721
- } catch (error) {
1722
- paymentsLogger.error("Failed to create payment:", error);
2745
+ setError(null);
2746
+ const result = await withdraw({
2747
+ amount_usd: String(data.amount),
2748
+ currency_code: data.currency,
2749
+ wallet_address: data.wallet_address
2750
+ });
2751
+ form.reset();
2752
+ onOpenChange(false);
2753
+ onSuccess?.(result);
2754
+ } catch (err) {
2755
+ setError(extractErrorMessage(err, "Failed to create withdrawal request"));
1723
2756
  } finally {
1724
2757
  setIsSubmitting(false);
1725
2758
  }
1726
- };
1727
- return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-md", children: [
1728
- /* @__PURE__ */ jsxs(DialogHeader, { children: [
1729
- /* @__PURE__ */ jsx(DialogTitle, { children: "Create Payment" }),
1730
- /* @__PURE__ */ jsx(DialogDescription, { children: "Create a new payment to add funds to your account." })
2759
+ }, [withdraw, form, onOpenChange, onSuccess]);
2760
+ const handleOpenChange = useCallback((open2) => {
2761
+ if (open2) {
2762
+ form.reset({
2763
+ amount: 10,
2764
+ currency: saved.currency,
2765
+ wallet_address: saved.wallet
2766
+ });
2767
+ } else {
2768
+ setError(null);
2769
+ }
2770
+ onOpenChange(open2);
2771
+ }, [form, onOpenChange, saved]);
2772
+ return /* @__PURE__ */ jsx(ResponsiveSheet, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs(ResponsiveSheetContent, { className: "sm:max-w-md", children: [
2773
+ /* @__PURE__ */ jsxs(ResponsiveSheetHeader, { children: [
2774
+ /* @__PURE__ */ jsx(ResponsiveSheetTitle, { children: "Withdraw" }),
2775
+ /* @__PURE__ */ jsx(ResponsiveSheetDescription, { children: "Withdraw funds to your cryptocurrency wallet" })
1731
2776
  ] }),
1732
- /* @__PURE__ */ jsx(Form, { ...form, children: /* @__PURE__ */ jsxs("form", { onSubmit: form.handleSubmit(handleSubmit), className: "space-y-4", children: [
2777
+ /* @__PURE__ */ jsx(Form, { ...form, children: /* @__PURE__ */ jsxs("form", { onSubmit: form.handleSubmit(handleSubmit), className: "space-y-6 p-4 sm:p-0 sm:mt-4", children: [
1733
2778
  /* @__PURE__ */ jsx(
1734
2779
  FormField,
1735
2780
  {
1736
2781
  control: form.control,
1737
- name: "amount_usd",
2782
+ name: "amount",
1738
2783
  render: ({ field }) => /* @__PURE__ */ jsxs(FormItem, { children: [
1739
2784
  /* @__PURE__ */ jsx(FormLabel, { children: "Amount (USD)" }),
2785
+ /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
2786
+ /* @__PURE__ */ jsx("span", { className: "absolute left-4 top-1/2 -translate-y-1/2 text-muted-foreground text-lg", children: "$" }),
2787
+ /* @__PURE__ */ jsx(
2788
+ Input,
2789
+ {
2790
+ type: "number",
2791
+ step: "0.01",
2792
+ min: "10",
2793
+ placeholder: "10",
2794
+ className: "pl-8 text-2xl h-14 font-semibold",
2795
+ ...field,
2796
+ onChange: (e) => field.onChange(parseFloat(e.target.value) || 0)
2797
+ }
2798
+ )
2799
+ ] }) }),
2800
+ /* @__PURE__ */ jsx(FormMessage, {}),
2801
+ insufficientBalance && /* @__PURE__ */ jsxs("p", { className: "text-sm text-destructive mt-1", children: [
2802
+ "Insufficient balance (Available: $",
2803
+ formatUsdAmount(balanceAmount),
2804
+ ")"
2805
+ ] })
2806
+ ] })
2807
+ }
2808
+ ),
2809
+ /* @__PURE__ */ jsx(
2810
+ FormField,
2811
+ {
2812
+ control: form.control,
2813
+ name: "currency",
2814
+ render: ({ field }) => /* @__PURE__ */ jsxs(FormItem, { children: [
2815
+ /* @__PURE__ */ jsx(FormLabel, { children: "Withdraw as" }),
1740
2816
  /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(
1741
- Input,
2817
+ CurrencyCombobox,
1742
2818
  {
1743
- type: "number",
1744
- step: "0.01",
1745
- min: "0.01",
1746
- placeholder: "10.00",
1747
- ...field,
1748
- onChange: (e) => field.onChange(parseFloat(e.target.value) || 0)
2819
+ options: currencyOptions,
2820
+ value: field.value,
2821
+ onChange: field.onChange,
2822
+ disabled: isLoadingCurrencies
1749
2823
  }
1750
2824
  ) }),
1751
- /* @__PURE__ */ jsx(FormDescription, { children: "The amount you want to pay in USD." }),
1752
2825
  /* @__PURE__ */ jsx(FormMessage, {})
1753
2826
  ] })
1754
2827
  }
@@ -1757,122 +2830,366 @@ var CreatePaymentDialog = () => {
1757
2830
  FormField,
1758
2831
  {
1759
2832
  control: form.control,
1760
- name: "currency_code",
2833
+ name: "wallet_address",
1761
2834
  render: ({ field }) => /* @__PURE__ */ jsxs(FormItem, { children: [
1762
- /* @__PURE__ */ jsx(FormLabel, { children: "Currency" }),
1763
- /* @__PURE__ */ jsxs(
1764
- Select,
2835
+ /* @__PURE__ */ jsx(FormLabel, { children: "Wallet Address" }),
2836
+ /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(
2837
+ Input,
1765
2838
  {
1766
- onValueChange: field.onChange,
1767
- defaultValue: field.value,
1768
- disabled: isLoadingCurrencies,
1769
- children: [
1770
- /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select currency..." }) }) }),
1771
- /* @__PURE__ */ jsx(SelectContent, { children: currencyOptions.map((curr) => /* @__PURE__ */ jsx(SelectItem, { value: curr.code, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1772
- /* @__PURE__ */ jsx(TokenIcon, { symbol: curr.code, size: 16 }),
1773
- /* @__PURE__ */ jsx("span", { children: curr.code }),
1774
- curr.network && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
1775
- "(",
1776
- curr.network,
1777
- ")"
1778
- ] })
1779
- ] }) }, curr.code)) })
1780
- ]
2839
+ placeholder: "Enter your wallet address",
2840
+ className: "font-mono text-sm",
2841
+ ...field
1781
2842
  }
1782
- ),
1783
- /* @__PURE__ */ jsx(FormDescription, { children: "The cryptocurrency to use for payment." }),
2843
+ ) }),
1784
2844
  /* @__PURE__ */ jsx(FormMessage, {})
1785
2845
  ] })
1786
2846
  }
1787
2847
  ),
1788
- calculateCryptoAmount && /* @__PURE__ */ jsxs("div", { className: "rounded-sm bg-muted p-4 space-y-3", children: [
1789
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1790
- /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "You will send" }),
1791
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1792
- /* @__PURE__ */ jsx(TokenIcon, { symbol: calculateCryptoAmount.currency, size: 16 }),
1793
- /* @__PURE__ */ jsxs("span", { className: "font-mono font-semibold", children: [
1794
- calculateCryptoAmount.amount.toFixed(8),
2848
+ amount >= 10 && selectedCurrency && /* @__PURE__ */ jsxs("div", { className: "bg-muted rounded-xl p-4 space-y-2", children: [
2849
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
2850
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Amount" }),
2851
+ /* @__PURE__ */ jsxs("span", { children: [
2852
+ "$",
2853
+ formatUsdAmount(amount)
2854
+ ] })
2855
+ ] }),
2856
+ isLoadingEstimate ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground py-2", children: [
2857
+ /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
2858
+ /* @__PURE__ */ jsx("span", { children: "Calculating fees..." })
2859
+ ] }) : estimate ? /* @__PURE__ */ jsxs(Fragment, { children: [
2860
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
2861
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
2862
+ "Service fee (",
2863
+ estimate.serviceFeePercent,
2864
+ "%)"
2865
+ ] }),
2866
+ /* @__PURE__ */ jsxs("span", { className: "text-destructive", children: [
2867
+ "-$",
2868
+ formatUsdAmount(estimate.serviceFeeUsd)
2869
+ ] })
2870
+ ] }),
2871
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
2872
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Network fee" }),
2873
+ /* @__PURE__ */ jsxs("span", { className: "text-destructive", children: [
2874
+ "-$",
2875
+ formatUsdAmount(estimate.networkFeeUsd)
2876
+ ] })
2877
+ ] }),
2878
+ /* @__PURE__ */ jsx("div", { className: "border-t pt-2 mt-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2879
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "You will receive" }),
2880
+ /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
2881
+ /* @__PURE__ */ jsxs("div", { className: "font-semibold", children: [
2882
+ "$",
2883
+ formatUsdAmount(estimate.amountToReceive)
2884
+ ] }),
2885
+ cryptoDisplay && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
2886
+ /* @__PURE__ */ jsx(TokenIcon, { symbol: cryptoDisplay.token, size: 16 }),
2887
+ /* @__PURE__ */ jsxs("span", { className: "font-mono", children: [
2888
+ cryptoDisplay.cryptoAmount,
2889
+ " ",
2890
+ cryptoDisplay.token
2891
+ ] })
2892
+ ] })
2893
+ ] })
2894
+ ] }) })
2895
+ ] }) : null
2896
+ ] }),
2897
+ /* @__PURE__ */ jsxs(Alert, { children: [
2898
+ /* @__PURE__ */ jsx(AlertCircle, { className: "h-4 w-4" }),
2899
+ /* @__PURE__ */ jsx(AlertDescription, { children: "Withdrawal requests require admin approval. Processing may take 24-48 hours." })
2900
+ ] }),
2901
+ error && /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: /* @__PURE__ */ jsx(AlertDescription, { children: error }) }),
2902
+ /* @__PURE__ */ jsx(
2903
+ Button,
2904
+ {
2905
+ type: "submit",
2906
+ size: "lg",
2907
+ className: "w-full h-14 text-lg rounded-xl",
2908
+ disabled: isSubmitting || currencyOptions.length === 0 || insufficientBalance || !estimate || estimate.amountToReceive <= 0 || isLoadingEstimate,
2909
+ children: isSubmitting ? /* @__PURE__ */ jsxs(Fragment, { children: [
2910
+ /* @__PURE__ */ jsx(RefreshCw, { className: "h-5 w-5 mr-2 animate-spin" }),
2911
+ "Submitting..."
2912
+ ] }) : "Request Withdrawal"
2913
+ }
2914
+ )
2915
+ ] }) })
2916
+ ] }) });
2917
+ }
2918
+ var statusConfig2 = {
2919
+ pending: {
2920
+ icon: Clock,
2921
+ color: "text-yellow-500",
2922
+ bg: "bg-yellow-500/10",
2923
+ label: "Pending Approval"
2924
+ },
2925
+ approved: {
2926
+ icon: CheckCircle2,
2927
+ color: "text-blue-500",
2928
+ bg: "bg-blue-500/10",
2929
+ label: "Approved"
2930
+ },
2931
+ processing: {
2932
+ icon: RefreshCw,
2933
+ color: "text-blue-500",
2934
+ bg: "bg-blue-500/10",
2935
+ label: "Processing",
2936
+ animate: true
2937
+ },
2938
+ completed: {
2939
+ icon: CheckCircle2,
2940
+ color: "text-green-500",
2941
+ bg: "bg-green-500/10",
2942
+ label: "Completed"
2943
+ },
2944
+ rejected: {
2945
+ icon: XCircle,
2946
+ color: "text-red-500",
2947
+ bg: "bg-red-500/10",
2948
+ label: "Rejected"
2949
+ },
2950
+ cancelled: {
2951
+ icon: Ban,
2952
+ color: "text-muted-foreground",
2953
+ bg: "bg-muted",
2954
+ label: "Cancelled"
2955
+ }
2956
+ };
2957
+ function WithdrawalSheet({ withdrawalId, open, onOpenChange }) {
2958
+ const { getWithdrawalDetails, cancelWithdrawal, refreshWallet } = useWallet();
2959
+ const { data: withdrawal, isLoading, error, mutate } = useSWR(
2960
+ open && withdrawalId ? ["withdrawal-details", withdrawalId] : null,
2961
+ () => getWithdrawalDetails(withdrawalId),
2962
+ { refreshInterval: 3e4 }
2963
+ );
2964
+ const displayData = useMemo(() => {
2965
+ const s = withdrawal?.status?.toLowerCase() || "pending";
2966
+ const config2 = statusConfig2[s] || statusConfig2.pending;
2967
+ const isPending = s === "pending";
2968
+ const isCompleted = s === "completed";
2969
+ const isRejected = s === "rejected";
2970
+ const isCancelled = s === "cancelled";
2971
+ const isProcessing = s === "processing" || s === "approved";
2972
+ const canCancel2 = isPending;
2973
+ let description2 = "";
2974
+ if (isPending) description2 = "Waiting for admin approval";
2975
+ else if (isProcessing) description2 = "Your withdrawal is being processed";
2976
+ else if (isCompleted) description2 = "Withdrawal completed successfully";
2977
+ else if (isRejected) description2 = "Withdrawal was rejected";
2978
+ else if (isCancelled) description2 = "Withdrawal was cancelled";
2979
+ const amountUsd2 = withdrawal?.amount_usd ? `$${parseFloat(withdrawal.amount_usd).toFixed(2)}` : "";
2980
+ const finalAmountUsd2 = withdrawal?.final_amount_usd ? `$${parseFloat(withdrawal.final_amount_usd).toFixed(2)}` : "";
2981
+ const totalFeeUsd2 = withdrawal?.total_fee_usd ? `$${parseFloat(withdrawal.total_fee_usd).toFixed(2)}` : "";
2982
+ const createdAt2 = withdrawal?.created_at ? moment3.utc(withdrawal.created_at).local().format("MMM D, YYYY HH:mm") : "";
2983
+ const completedAt2 = withdrawal?.completed_at ? moment3.utc(withdrawal.completed_at).local().format("MMM D, YYYY HH:mm") : null;
2984
+ return {
2985
+ status: s,
2986
+ config: config2,
2987
+ isPending,
2988
+ isCompleted,
2989
+ isRejected,
2990
+ isCancelled,
2991
+ isProcessing,
2992
+ canCancel: canCancel2,
2993
+ description: description2,
2994
+ amountUsd: amountUsd2,
2995
+ finalAmountUsd: finalAmountUsd2,
2996
+ totalFeeUsd: totalFeeUsd2,
2997
+ createdAt: createdAt2,
2998
+ completedAt: completedAt2
2999
+ };
3000
+ }, [withdrawal]);
3001
+ const { config, canCancel, description, amountUsd, finalAmountUsd, totalFeeUsd, createdAt, completedAt } = displayData;
3002
+ const StatusIcon = config.icon;
3003
+ const handleCancel = async () => {
3004
+ if (!withdrawalId) return;
3005
+ try {
3006
+ await cancelWithdrawal(withdrawalId);
3007
+ await mutate();
3008
+ await refreshWallet();
3009
+ } catch (err) {
3010
+ console.error("Failed to cancel withdrawal:", err);
3011
+ }
3012
+ };
3013
+ return /* @__PURE__ */ jsx(ResponsiveSheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs(ResponsiveSheetContent, { className: "sm:max-w-lg", children: [
3014
+ /* @__PURE__ */ jsxs(ResponsiveSheetHeader, { children: [
3015
+ /* @__PURE__ */ jsx(ResponsiveSheetTitle, { children: "Withdrawal Details" }),
3016
+ /* @__PURE__ */ jsx(ResponsiveSheetDescription, { children: description })
3017
+ ] }),
3018
+ /* @__PURE__ */ jsxs("div", { className: "p-4 sm:p-0 sm:mt-4 overflow-y-auto max-h-[70vh]", children: [
3019
+ isLoading && /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
3020
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-16 w-full rounded-xl" }),
3021
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-24 w-full rounded-xl" }),
3022
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-20 w-full rounded-xl" })
3023
+ ] }),
3024
+ error && /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-12", children: [
3025
+ /* @__PURE__ */ jsx(XCircle, { className: "h-12 w-12 text-destructive mb-4" }),
3026
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-4", children: "Failed to load withdrawal" }),
3027
+ /* @__PURE__ */ jsx(Button, { onClick: () => mutate(), children: "Try Again" })
3028
+ ] }),
3029
+ withdrawal && !isLoading && /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
3030
+ /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-3 p-4 rounded-xl", config.bg), children: [
3031
+ /* @__PURE__ */ jsx(StatusIcon, { className: cn("h-6 w-6", config.color, config.animate && "animate-spin") }),
3032
+ /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
3033
+ /* @__PURE__ */ jsx("div", { className: "font-semibold", children: config.label }),
3034
+ withdrawal.admin_notes && /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: withdrawal.admin_notes })
3035
+ ] })
3036
+ ] }),
3037
+ /* @__PURE__ */ jsxs("div", { className: "bg-muted rounded-xl p-4 space-y-3", children: [
3038
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
3039
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Amount" }),
3040
+ /* @__PURE__ */ jsx("span", { className: "font-semibold", children: amountUsd })
3041
+ ] }),
3042
+ totalFeeUsd && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
3043
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Total fees" }),
3044
+ /* @__PURE__ */ jsxs("span", { className: "text-destructive", children: [
3045
+ "-",
3046
+ totalFeeUsd
3047
+ ] })
3048
+ ] }),
3049
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pt-2 border-t", children: [
3050
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "You receive" }),
3051
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3052
+ /* @__PURE__ */ jsx(TokenIcon, { symbol: withdrawal.currency_code, size: 24 }),
3053
+ /* @__PURE__ */ jsx("span", { className: "font-mono font-bold text-lg", children: finalAmountUsd })
3054
+ ] })
3055
+ ] }),
3056
+ withdrawal.crypto_amount && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
3057
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Crypto amount" }),
3058
+ /* @__PURE__ */ jsxs("span", { className: "font-mono", children: [
3059
+ withdrawal.crypto_amount,
1795
3060
  " ",
1796
- calculateCryptoAmount.currency
3061
+ withdrawal.currency_token
1797
3062
  ] })
1798
3063
  ] })
1799
3064
  ] }),
1800
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1801
- /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "You will receive" }),
1802
- /* @__PURE__ */ jsxs("span", { className: "text-lg font-bold", children: [
1803
- "$",
1804
- form.watch("amount_usd")?.toFixed(2),
1805
- " USD"
3065
+ withdrawal.wallet_address && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
3066
+ /* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Destination Wallet" }),
3067
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3068
+ /* @__PURE__ */ jsx("div", { className: "flex-1 p-3 bg-muted rounded-xl font-mono text-sm break-all", children: withdrawal.wallet_address }),
3069
+ /* @__PURE__ */ jsx(CopyButton, { value: withdrawal.wallet_address, variant: "outline", className: "shrink-0" })
1806
3070
  ] })
1807
3071
  ] }),
1808
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
1809
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Rate" }),
1810
- /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
1811
- "1 ",
1812
- calculateCryptoAmount.currency,
1813
- " = $",
1814
- calculateCryptoAmount.rate?.toFixed(2)
3072
+ withdrawal.transaction_hash && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
3073
+ /* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Transaction Hash" }),
3074
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3075
+ /* @__PURE__ */ jsx("div", { className: "flex-1 p-3 bg-muted rounded-xl font-mono text-sm break-all", children: withdrawal.transaction_hash }),
3076
+ /* @__PURE__ */ jsx(CopyButton, { value: withdrawal.transaction_hash, variant: "outline", className: "shrink-0" })
1815
3077
  ] })
1816
3078
  ] }),
1817
- calculateCryptoAmount.network && /* @__PURE__ */ jsx("div", { className: "border-t pt-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1818
- /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Network" }),
1819
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: calculateCryptoAmount.network })
1820
- ] }) })
1821
- ] }),
1822
- /* @__PURE__ */ jsxs(DialogFooter, { children: [
1823
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: handleClose, disabled: isSubmitting, children: "Cancel" }),
1824
- /* @__PURE__ */ jsx(Button, { type: "submit", disabled: isSubmitting || currencyOptions.length === 0, children: isSubmitting ? /* @__PURE__ */ jsxs(Fragment, { children: [
1825
- /* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4 mr-2 animate-spin" }),
1826
- "Creating..."
1827
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1828
- /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
1829
- "Create Payment"
1830
- ] }) })
3079
+ withdrawal.explorer_link && /* @__PURE__ */ jsxs(
3080
+ Button,
3081
+ {
3082
+ variant: "outline",
3083
+ className: "w-full",
3084
+ onClick: () => window.open(withdrawal.explorer_link, "_blank"),
3085
+ children: [
3086
+ /* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4 mr-2" }),
3087
+ "View on Explorer"
3088
+ ]
3089
+ }
3090
+ ),
3091
+ canCancel && /* @__PURE__ */ jsxs(
3092
+ Button,
3093
+ {
3094
+ variant: "destructive",
3095
+ className: "w-full",
3096
+ onClick: handleCancel,
3097
+ children: [
3098
+ /* @__PURE__ */ jsx(Ban, { className: "h-4 w-4 mr-2" }),
3099
+ "Cancel Withdrawal"
3100
+ ]
3101
+ }
3102
+ ),
3103
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 text-xs text-muted-foreground pt-4 border-t", children: [
3104
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
3105
+ /* @__PURE__ */ jsx("span", { children: "Withdrawal ID" }),
3106
+ /* @__PURE__ */ jsx("span", { className: "font-mono", children: withdrawal.id })
3107
+ ] }),
3108
+ withdrawal.internal_withdrawal_id && /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
3109
+ /* @__PURE__ */ jsx("span", { children: "Reference #" }),
3110
+ /* @__PURE__ */ jsx("span", { className: "font-mono", children: withdrawal.internal_withdrawal_id })
3111
+ ] }),
3112
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
3113
+ /* @__PURE__ */ jsx("span", { children: "Created" }),
3114
+ /* @__PURE__ */ jsx("span", { children: createdAt })
3115
+ ] }),
3116
+ completedAt && /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
3117
+ /* @__PURE__ */ jsx("span", { children: "Completed" }),
3118
+ /* @__PURE__ */ jsx("span", { children: completedAt })
3119
+ ] }),
3120
+ withdrawal.currency_network && /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
3121
+ /* @__PURE__ */ jsx("span", { children: "Network" }),
3122
+ /* @__PURE__ */ jsx("span", { children: withdrawal.currency_network })
3123
+ ] })
3124
+ ] }),
3125
+ /* @__PURE__ */ jsxs(
3126
+ Button,
3127
+ {
3128
+ variant: "ghost",
3129
+ className: "w-full",
3130
+ onClick: () => mutate(),
3131
+ children: [
3132
+ /* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4 mr-2" }),
3133
+ "Refresh Status"
3134
+ ]
3135
+ }
3136
+ )
1831
3137
  ] })
1832
- ] }) })
3138
+ ] })
1833
3139
  ] }) });
3140
+ }
3141
+ var statusConfig3 = {
3142
+ pending: {
3143
+ icon: Clock,
3144
+ color: "text-yellow-500",
3145
+ bg: "bg-yellow-500/10",
3146
+ label: "Waiting for payment"
3147
+ },
3148
+ confirming: {
3149
+ icon: RefreshCw,
3150
+ color: "text-blue-500",
3151
+ bg: "bg-blue-500/10",
3152
+ label: "Confirming",
3153
+ animate: true
3154
+ },
3155
+ completed: {
3156
+ icon: CheckCircle2,
3157
+ color: "text-green-500",
3158
+ bg: "bg-green-500/10",
3159
+ label: "Completed"
3160
+ },
3161
+ failed: {
3162
+ icon: XCircle,
3163
+ color: "text-red-500",
3164
+ bg: "bg-red-500/10",
3165
+ label: "Failed"
3166
+ },
3167
+ expired: {
3168
+ icon: AlertCircle,
3169
+ color: "text-muted-foreground",
3170
+ bg: "bg-muted",
3171
+ label: "Expired"
3172
+ }
1834
3173
  };
1835
- var PaymentDetailsDialog = () => {
1836
- const [open, setOpen] = useState(false);
1837
- const [paymentId, setPaymentId] = useState(null);
3174
+ function PaymentSheet({ paymentId, open, onOpenChange, onCreateNew }) {
3175
+ const { getPaymentDetails } = useWallet();
1838
3176
  const [timeLeft, setTimeLeft] = useState("");
1839
- const shouldFetch = open && !!paymentId;
1840
- const { data: payment, isLoading, error, mutate } = usePaymentsPaymentsRetrieve(
1841
- shouldFetch ? paymentId : "",
1842
- apiPayments
3177
+ const { data: payment, isLoading, error, mutate } = useSWR(
3178
+ open && paymentId ? ["payment-details", paymentId] : null,
3179
+ () => getPaymentDetails(paymentId),
3180
+ { refreshInterval: 1e4 }
1843
3181
  );
1844
- useEffect(() => {
1845
- const handleOpen = (event) => {
1846
- const customEvent = event;
1847
- setPaymentId(customEvent.detail.id);
1848
- setOpen(true);
1849
- };
1850
- const handleClose2 = () => {
1851
- setOpen(false);
1852
- setPaymentId(null);
1853
- };
1854
- window.addEventListener(PAYMENT_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG, handleOpen);
1855
- window.addEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
1856
- return () => {
1857
- window.removeEventListener(PAYMENT_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG, handleOpen);
1858
- window.removeEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
1859
- };
1860
- }, []);
1861
- const handleClose = () => {
1862
- setOpen(false);
1863
- setPaymentId(null);
1864
- };
1865
3182
  useEffect(() => {
1866
3183
  if (!payment?.expires_at) return;
1867
3184
  const updateTimeLeft = () => {
1868
- const now = moment();
1869
- const expires = moment.utc(payment.expires_at);
3185
+ const now = moment3();
3186
+ const expires = moment3.utc(payment.expires_at);
1870
3187
  const diff = expires.diff(now);
1871
3188
  if (diff <= 0) {
1872
3189
  setTimeLeft("Expired");
1873
3190
  return;
1874
3191
  }
1875
- const duration = moment.duration(diff);
3192
+ const duration = moment3.duration(diff);
1876
3193
  const hours = Math.floor(duration.asHours());
1877
3194
  const minutes = duration.minutes();
1878
3195
  const seconds = duration.seconds();
@@ -1882,713 +3199,245 @@ var PaymentDetailsDialog = () => {
1882
3199
  const interval = setInterval(updateTimeLeft, 1e3);
1883
3200
  return () => clearInterval(interval);
1884
3201
  }, [payment?.expires_at]);
1885
- const getStatusInfo = () => {
1886
- switch (payment?.status?.toLowerCase()) {
1887
- case "pending":
1888
- return { icon: Clock, color: "text-yellow-500", bg: "bg-yellow-500/10" };
1889
- case "completed":
1890
- case "success":
1891
- return { icon: CheckCircle2, color: "text-green-500", bg: "bg-green-500/10" };
1892
- case "failed":
1893
- case "error":
1894
- return { icon: XCircle, color: "text-red-500", bg: "bg-red-500/10" };
1895
- case "expired":
1896
- return { icon: AlertCircle, color: "text-gray-500", bg: "bg-gray-500/10" };
1897
- case "confirming":
1898
- return { icon: RefreshCw, color: "text-blue-500", bg: "bg-blue-500/10" };
1899
- default:
1900
- return { icon: Clock, color: "text-gray-500", bg: "bg-gray-500/10" };
1901
- }
1902
- };
1903
- if (!open) return null;
1904
- if (isLoading) {
1905
- return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-lg", children: [
1906
- /* @__PURE__ */ jsxs(DialogHeader, { children: [
1907
- /* @__PURE__ */ jsx(DialogTitle, { children: "Payment Details" }),
1908
- /* @__PURE__ */ jsx(DialogDescription, { children: "Loading payment information..." })
1909
- ] }),
1910
- /* @__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" }) })
1911
- ] }) });
1912
- }
1913
- if (shouldFetch && !isLoading && (error || !payment)) {
1914
- return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-lg", children: [
1915
- /* @__PURE__ */ jsxs(DialogHeader, { children: [
1916
- /* @__PURE__ */ jsx(DialogTitle, { children: "Payment Details" }),
1917
- /* @__PURE__ */ jsx(DialogDescription, { children: "Failed to load payment information" })
3202
+ const displayData = useMemo(() => {
3203
+ const s = payment?.status?.toLowerCase();
3204
+ let status;
3205
+ if (s === "completed" || s === "success" || s === "finished") status = "completed";
3206
+ else if (s === "confirming" || s === "partially_paid") status = "confirming";
3207
+ else if (s === "expired") status = "expired";
3208
+ else if (s === "failed" || s === "error" || s === "cancelled") status = "failed";
3209
+ else status = "pending";
3210
+ const config2 = statusConfig3[status];
3211
+ const isPending = status === "pending";
3212
+ const isExpired2 = status === "expired" || timeLeft === "Expired";
3213
+ const isCompleted = status === "completed";
3214
+ const isFailed = status === "failed";
3215
+ const isConfirming = status === "confirming";
3216
+ const canPay2 = isPending && !isExpired2;
3217
+ let description2 = "";
3218
+ if (canPay2) description2 = "Send cryptocurrency to complete payment";
3219
+ else if (isExpired2) description2 = "This payment has expired";
3220
+ else if (isCompleted) description2 = "Payment completed successfully";
3221
+ else if (isFailed) description2 = "Payment failed";
3222
+ else if (isConfirming) description2 = "Confirming your payment";
3223
+ const statusBadge2 = {
3224
+ bg: isExpired2 ? "bg-muted" : config2.bg,
3225
+ iconColor: isExpired2 ? "text-muted-foreground" : config2.color,
3226
+ iconAnimate: config2.animate,
3227
+ label: isExpired2 ? "Payment Expired" : config2.label,
3228
+ subtitle: canPay2 && timeLeft ? `Expires in ${timeLeft}` : isExpired2 ? "Please create a new payment to continue" : null
3229
+ };
3230
+ const qrCodeUrl2 = payment?.pay_address && canPay2 ? `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(payment.pay_address)}` : null;
3231
+ const amountUsd2 = payment?.amount_usd ? `$${parseFloat(payment.amount_usd).toFixed(2)} USD` : "";
3232
+ const createdAt2 = payment?.created_at ? moment3.utc(payment.created_at).local().format("MMM D, YYYY HH:mm") : "";
3233
+ return {
3234
+ status,
3235
+ config: config2,
3236
+ isPending,
3237
+ isExpired: isExpired2,
3238
+ isCompleted,
3239
+ isFailed,
3240
+ isConfirming,
3241
+ canPay: canPay2,
3242
+ description: description2,
3243
+ statusBadge: statusBadge2,
3244
+ qrCodeUrl: qrCodeUrl2,
3245
+ amountUsd: amountUsd2,
3246
+ createdAt: createdAt2
3247
+ };
3248
+ }, [payment, timeLeft]);
3249
+ const { config, canPay, isExpired, description, statusBadge, qrCodeUrl, amountUsd, createdAt } = displayData;
3250
+ const StatusIcon = config.icon;
3251
+ return /* @__PURE__ */ jsx(ResponsiveSheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs(ResponsiveSheetContent, { className: "sm:max-w-lg", children: [
3252
+ /* @__PURE__ */ jsxs(ResponsiveSheetHeader, { children: [
3253
+ /* @__PURE__ */ jsx(ResponsiveSheetTitle, { children: "Payment Details" }),
3254
+ /* @__PURE__ */ jsx(ResponsiveSheetDescription, { children: description })
3255
+ ] }),
3256
+ /* @__PURE__ */ jsxs("div", { className: "p-4 sm:p-0 sm:mt-4 overflow-y-auto max-h-[70vh]", children: [
3257
+ isLoading && /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
3258
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-48 w-48 rounded-xl" }) }),
3259
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-full" }),
3260
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-24 w-full" })
1918
3261
  ] }),
1919
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-12 space-y-4", children: [
1920
- /* @__PURE__ */ jsx(XCircle, { className: "h-12 w-12 text-destructive" }),
1921
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: error ? `Error: ${error}` : "Payment not found" }),
3262
+ error && /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-12", children: [
3263
+ /* @__PURE__ */ jsx(XCircle, { className: "h-12 w-12 text-destructive mb-4" }),
3264
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-4", children: "Failed to load payment" }),
1922
3265
  /* @__PURE__ */ jsx(Button, { onClick: () => mutate(), children: "Try Again" })
1923
- ] })
1924
- ] }) });
1925
- }
1926
- const statusInfo = getStatusInfo();
1927
- const StatusIcon = statusInfo.icon;
1928
- const qrCodeUrl = payment.pay_address ? `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(payment.pay_address)}` : null;
1929
- return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-lg", children: [
1930
- /* @__PURE__ */ jsxs(DialogHeader, { children: [
1931
- /* @__PURE__ */ jsx(DialogTitle, { children: "Payment Details" }),
1932
- /* @__PURE__ */ jsx(DialogDescription, { children: "Send cryptocurrency to complete your payment" })
1933
- ] }),
1934
- /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
1935
- /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-3 p-4 rounded-sm ${statusInfo.bg}`, children: [
1936
- /* @__PURE__ */ jsx(StatusIcon, { className: `h-5 w-5 ${statusInfo.color}` }),
1937
- /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
1938
- /* @__PURE__ */ jsx("div", { className: "font-semibold capitalize", children: payment.status }),
1939
- payment.status === "pending" && timeLeft && /* @__PURE__ */ jsxs("div", { className: "text-sm text-muted-foreground", children: [
1940
- "Expires in ",
1941
- timeLeft
1942
- ] })
1943
- ] })
1944
3266
  ] }),
1945
- /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1946
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 bg-muted rounded-sm", children: [
1947
- /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Amount to send" }),
1948
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1949
- /* @__PURE__ */ jsx(TokenIcon, { symbol: String(payment.currency_code || "BTC"), size: 20 }),
1950
- /* @__PURE__ */ jsxs("span", { className: "font-mono font-bold text-lg", children: [
1951
- payment.pay_amount || "0.00000000",
1952
- " ",
1953
- payment.currency_code
1954
- ] })
1955
- ] })
1956
- ] }),
1957
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4", children: [
1958
- /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Equivalent to" }),
1959
- /* @__PURE__ */ jsxs("span", { className: "font-semibold text-lg", children: [
1960
- "$",
1961
- parseFloat(payment.amount_usd || "0").toFixed(2),
1962
- " USD"
3267
+ payment && !isLoading && /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
3268
+ /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-3 p-4 rounded-xl", statusBadge.bg), children: [
3269
+ /* @__PURE__ */ jsx(StatusIcon, { className: cn("h-6 w-6", statusBadge.iconColor, statusBadge.iconAnimate && "animate-spin") }),
3270
+ /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
3271
+ /* @__PURE__ */ jsx("div", { className: "font-semibold", children: statusBadge.label }),
3272
+ statusBadge.subtitle && /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: statusBadge.subtitle })
1963
3273
  ] })
1964
3274
  ] }),
1965
- payment.internal_payment_id && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4", children: [
1966
- /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Payment Order #" }),
1967
- /* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: payment.internal_payment_id })
1968
- ] }),
1969
- payment.currency_network && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4", children: [
1970
- /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Network" }),
1971
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: payment.currency_network })
1972
- ] })
1973
- ] }),
1974
- 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" }) }),
1975
- payment.pay_address && payment.status === "pending" && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1976
- /* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Payment Address" }),
1977
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1978
- /* @__PURE__ */ jsx("div", { className: "flex-1 p-3 bg-muted rounded-sm font-mono text-sm break-all", children: payment.pay_address }),
1979
- /* @__PURE__ */ jsx(CopyButton, { value: payment.pay_address, variant: "outline" })
1980
- ] })
1981
- ] }),
1982
- payment.transaction_hash && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1983
- /* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Transaction Hash" }),
1984
- /* @__PURE__ */ jsx("div", { className: "p-3 bg-muted rounded-sm font-mono text-sm break-all", children: payment.transaction_hash })
1985
- ] }),
1986
- payment.payment_url && payment.status === "pending" && /* @__PURE__ */ jsxs(
1987
- Button,
1988
- {
1989
- variant: "outline",
1990
- className: "w-full",
1991
- onClick: () => window.open(payment.payment_url, "_blank"),
1992
- children: [
1993
- /* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4 mr-2" }),
1994
- "Open in Payment Provider"
1995
- ]
1996
- }
1997
- ),
1998
- /* @__PURE__ */ jsxs("div", { className: "pt-4 border-t space-y-2 text-xs text-muted-foreground", children: [
1999
- /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
2000
- /* @__PURE__ */ jsx("span", { children: "Payment ID" }),
2001
- /* @__PURE__ */ jsx("span", { className: "font-mono", children: payment.id })
2002
- ] }),
2003
- /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
2004
- /* @__PURE__ */ jsx("span", { children: "Created" }),
2005
- /* @__PURE__ */ jsx("span", { children: moment.utc(payment.created_at).local().format("MMM D, YYYY HH:mm") })
2006
- ] }),
2007
- payment.confirmations_count !== void 0 && /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
2008
- /* @__PURE__ */ jsx("span", { children: "Confirmations" }),
2009
- /* @__PURE__ */ jsx("span", { children: payment.confirmations_count })
2010
- ] })
2011
- ] })
2012
- ] }),
2013
- /* @__PURE__ */ jsxs(DialogFooter, { children: [
2014
- /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: handleClose, children: "Close" }),
2015
- /* @__PURE__ */ jsxs(Button, { onClick: () => mutate(), variant: "ghost", size: "sm", children: [
2016
- /* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4 mr-2" }),
2017
- "Refresh"
2018
- ] })
2019
- ] })
2020
- ] }) });
2021
- };
2022
- var BalanceCard = () => {
2023
- const {
2024
- balance,
2025
- isLoadingBalance,
2026
- refreshBalance
2027
- } = useOverviewContext();
2028
- const formatCurrency = (amount) => {
2029
- if (amount === null || amount === void 0) return "$0.00";
2030
- return new Intl.NumberFormat("en-US", {
2031
- style: "currency",
2032
- currency: "USD",
2033
- minimumFractionDigits: 2
2034
- }).format(amount);
2035
- };
2036
- const formatDate = (dateStr) => {
2037
- if (!dateStr) return "No transactions yet";
2038
- try {
2039
- return moment.utc(dateStr).local().format("MMM D, YYYY");
2040
- } catch {
2041
- return "Invalid date";
2042
- }
2043
- };
2044
- if (isLoadingBalance) {
2045
- return /* @__PURE__ */ jsxs(Card, { children: [
2046
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center justify-between", children: [
2047
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2048
- /* @__PURE__ */ jsx(Wallet, { className: "h-5 w-5" }),
2049
- "Account Balance"
2050
- ] }),
2051
- /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-20" })
2052
- ] }) }),
2053
- /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
2054
- /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-32" }),
2055
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" })
2056
- ] })
2057
- ] });
2058
- }
2059
- const balanceData = balance?.balance || balance;
2060
- const amountUsd = balanceData?.amount_usd ?? 0;
2061
- const totalDeposited = balanceData?.total_deposited ?? 0;
2062
- const totalWithdrawn = balanceData?.total_withdrawn ?? 0;
2063
- const lastTransactionAt = balanceData?.last_transaction_at;
2064
- const isEmpty = amountUsd === 0 && totalDeposited === 0;
2065
- return /* @__PURE__ */ jsxs(Card, { children: [
2066
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center justify-between", children: [
2067
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2068
- /* @__PURE__ */ jsx(Wallet, { className: "h-5 w-5" }),
2069
- "Account Balance"
2070
- ] }),
2071
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2072
- /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: refreshBalance, children: /* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4" }) }),
2073
- /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: () => openCreatePaymentDialog(), children: [
2074
- /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
2075
- "Add Funds"
2076
- ] })
2077
- ] })
2078
- ] }) }),
2079
- /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
2080
- /* @__PURE__ */ jsxs("div", { children: [
2081
- /* @__PURE__ */ jsx("div", { className: "text-4xl font-bold", children: formatCurrency(amountUsd) }),
2082
- /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground mt-1", children: [
2083
- "Available balance \u2022 Last updated ",
2084
- formatDate(lastTransactionAt)
2085
- ] })
2086
- ] }),
2087
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4 pt-4 border-t", children: [
2088
- /* @__PURE__ */ jsxs("div", { children: [
2089
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Total Deposited" }),
2090
- /* @__PURE__ */ jsx("p", { className: "text-lg font-semibold text-green-600", children: formatCurrency(totalDeposited) })
2091
- ] }),
2092
- /* @__PURE__ */ jsxs("div", { children: [
2093
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Total Withdrawn" }),
2094
- /* @__PURE__ */ jsx("p", { className: "text-lg font-semibold text-red-600", children: formatCurrency(totalWithdrawn) })
2095
- ] })
2096
- ] }),
2097
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2098
- /* @__PURE__ */ jsx(Badge, { variant: !isEmpty ? "default" : "secondary", children: !isEmpty ? "Active" : "New Account" }),
2099
- isEmpty && /* @__PURE__ */ jsx(Badge, { variant: "outline", children: "Empty Balance" })
2100
- ] })
2101
- ] })
2102
- ] });
2103
- };
2104
- var RecentPayments = () => {
2105
- const { payments, isLoadingPayments } = useOverviewContext();
2106
- const formatCurrency = (amount) => {
2107
- if (amount === null || amount === void 0) return "$0.00";
2108
- const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
2109
- return new Intl.NumberFormat("en-US", {
2110
- style: "currency",
2111
- currency: "USD",
2112
- minimumFractionDigits: 2
2113
- }).format(numAmount);
2114
- };
2115
- const getRelativeTime = (date) => {
2116
- if (!date) return "N/A";
2117
- const m = moment.utc(date).local();
2118
- const now = moment();
2119
- const diffInSeconds = now.diff(m, "seconds");
2120
- if (diffInSeconds < 60) return "Just now";
2121
- if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
2122
- if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
2123
- return `${Math.floor(diffInSeconds / 86400)}d ago`;
2124
- };
2125
- const getStatusVariant = (status) => {
2126
- switch (status?.toLowerCase()) {
2127
- case "completed":
2128
- case "success":
2129
- return "default";
2130
- case "pending":
2131
- case "confirming":
2132
- return "secondary";
2133
- case "failed":
2134
- case "error":
2135
- case "expired":
2136
- return "destructive";
2137
- default:
2138
- return "outline";
2139
- }
2140
- };
2141
- if (isLoadingPayments) {
2142
- return /* @__PURE__ */ jsxs(Card, { children: [
2143
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2", children: [
2144
- /* @__PURE__ */ jsx(History, { className: "h-5 w-5" }),
2145
- "Recent Payments"
2146
- ] }) }),
2147
- /* @__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: [
2148
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2149
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" }),
2150
- /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" })
2151
- ] }),
2152
- /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-16" })
2153
- ] }, i)) })
2154
- ] });
2155
- }
2156
- const recentPaymentsList = payments?.results?.slice(0, 5) || [];
2157
- return /* @__PURE__ */ jsxs(Card, { children: [
2158
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center justify-between", children: [
2159
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2160
- /* @__PURE__ */ jsx(History, { className: "h-5 w-5" }),
2161
- "Recent Payments"
2162
- ] }),
2163
- /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", children: [
2164
- "View All",
2165
- /* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4 ml-2" })
2166
- ] })
2167
- ] }) }),
2168
- /* @__PURE__ */ jsx(CardContent, { children: recentPaymentsList.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-8 text-muted-foreground", children: [
2169
- /* @__PURE__ */ jsx(History, { className: "h-12 w-12 mx-auto mb-4 opacity-50" }),
2170
- /* @__PURE__ */ jsx("p", { children: "No recent payments" }),
2171
- /* @__PURE__ */ jsx("p", { className: "text-sm mt-2", children: "Create your first payment to get started" })
2172
- ] }) : /* @__PURE__ */ jsx("div", { className: "space-y-3", children: recentPaymentsList.map((payment) => /* @__PURE__ */ jsxs(
2173
- "div",
2174
- {
2175
- className: "flex items-center justify-between p-3 border rounded-sm hover:bg-accent cursor-pointer transition-colors",
2176
- onClick: () => openPaymentDetailsDialog(String(payment.id)),
2177
- children: [
2178
- /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
3275
+ /* @__PURE__ */ jsxs("div", { className: "bg-muted rounded-xl p-4 space-y-3", children: [
3276
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
3277
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Amount to send" }),
2179
3278
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2180
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: formatCurrency(payment.amount_usd) }),
2181
- /* @__PURE__ */ jsx(Badge, { variant: getStatusVariant(payment.status), className: "text-xs", children: payment.status })
2182
- ] }),
2183
- /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
2184
- getRelativeTime(payment.created_at),
2185
- " \u2022 ",
2186
- payment.currency_code || "USD"
3279
+ /* @__PURE__ */ jsx(TokenIcon, { symbol: payment.currency_code, size: 24 }),
3280
+ /* @__PURE__ */ jsxs("span", { className: "font-mono font-bold text-lg", children: [
3281
+ payment.pay_amount,
3282
+ " ",
3283
+ payment.currency_code
3284
+ ] })
2187
3285
  ] })
2188
3286
  ] }),
2189
- /* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4 text-muted-foreground" })
2190
- ]
2191
- },
2192
- payment.id
2193
- )) }) })
2194
- ] });
2195
- };
2196
- var OverviewView = () => {
2197
- return /* @__PURE__ */ jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsxs("div", { className: "grid gap-6 lg:grid-cols-2", children: [
2198
- /* @__PURE__ */ jsx(BalanceCard, {}),
2199
- /* @__PURE__ */ jsx(RecentPayments, {})
2200
- ] }) });
2201
- };
2202
- var PaymentsList = () => {
2203
- const pagination = useDRFPagination(1, 20);
2204
- const {
2205
- data: payments,
2206
- error,
2207
- isLoading: isLoadingPayments,
2208
- mutate: refreshPayments
2209
- } = usePaymentsPaymentsList(pagination.params, apiPayments);
2210
- const paymentsList = payments?.results || [];
2211
- payments?.count || 0;
2212
- const [searchTerm, setSearchTerm] = useState("");
2213
- const [statusFilter, setStatusFilter] = useState("all");
2214
- const formatCurrency = (amount) => {
2215
- if (amount === null || amount === void 0) return "$0.00";
2216
- const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
2217
- return new Intl.NumberFormat("en-US", {
2218
- style: "currency",
2219
- currency: "USD",
2220
- minimumFractionDigits: 2
2221
- }).format(numAmount);
2222
- };
2223
- const getRelativeTime = (date) => {
2224
- if (!date) return "N/A";
2225
- const m = moment.utc(date).local();
2226
- const now = moment();
2227
- const diffInSeconds = now.diff(m, "seconds");
2228
- if (diffInSeconds < 60) return "Just now";
2229
- if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
2230
- if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
2231
- return `${Math.floor(diffInSeconds / 86400)}d ago`;
2232
- };
2233
- const formatDate = (date) => {
2234
- if (!date) return "N/A";
2235
- return moment.utc(date).local().format("MMM D, YYYY");
2236
- };
2237
- const getStatusVariant = (status) => {
2238
- switch (status?.toLowerCase()) {
2239
- case "completed":
2240
- case "success":
2241
- return "default";
2242
- case "pending":
2243
- case "confirming":
2244
- return "secondary";
2245
- case "failed":
2246
- case "error":
2247
- case "expired":
2248
- return "destructive";
2249
- default:
2250
- return "outline";
2251
- }
2252
- };
2253
- const handleSearch = (value) => {
2254
- setSearchTerm(value);
2255
- };
2256
- const handleStatusFilter = (status) => {
2257
- setStatusFilter(status);
2258
- };
2259
- const truncateId = (id) => {
2260
- if (!id) return "N/A";
2261
- const str = id.toString();
2262
- return str.length > 8 ? `${str.slice(0, 8)}...` : str;
2263
- };
2264
- const filteredPayments = paymentsList.filter((payment) => {
2265
- const matchesSearch = searchTerm ? payment.id?.toLowerCase().includes(searchTerm.toLowerCase()) || payment.status?.toLowerCase().includes(searchTerm.toLowerCase()) || payment.currency_code?.toLowerCase().includes(searchTerm.toLowerCase()) : true;
2266
- const matchesStatus = statusFilter !== "all" ? payment.status?.toLowerCase() === statusFilter.toLowerCase() : true;
2267
- return matchesSearch && matchesStatus;
2268
- }).map((payment) => ({
2269
- ...payment,
2270
- formattedDate: formatDate(payment.created_at),
2271
- relativeTime: getRelativeTime(payment.created_at),
2272
- truncatedId: truncateId(payment.id)
2273
- }));
2274
- return /* @__PURE__ */ jsxs(Card, { children: [
2275
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center justify-between", children: [
2276
- /* @__PURE__ */ jsx("span", { children: "Payment History" }),
2277
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2278
- /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: () => refreshPayments(), disabled: isLoadingPayments, children: [
2279
- /* @__PURE__ */ jsx(RefreshCw, { className: `h-4 w-4 mr-2 ${isLoadingPayments ? "animate-spin" : ""}` }),
2280
- "Refresh"
3287
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
3288
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Equivalent" }),
3289
+ /* @__PURE__ */ jsx("span", { className: "font-semibold", children: amountUsd })
3290
+ ] }),
3291
+ payment.currency_network && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm pt-2 border-t", children: [
3292
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Network" }),
3293
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: payment.currency_network })
3294
+ ] })
2281
3295
  ] }),
2282
- /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: () => openCreatePaymentDialog(), children: [
2283
- /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
2284
- "New Payment"
2285
- ] })
2286
- ] })
2287
- ] }) }),
2288
- /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
2289
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row gap-4", children: [
2290
- /* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
2291
- /* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
2292
- /* @__PURE__ */ jsx(
2293
- Input,
2294
- {
2295
- placeholder: "Search by ID, status, or currency...",
2296
- value: searchTerm,
2297
- onChange: (e) => handleSearch(e.target.value),
2298
- className: "pl-10"
2299
- }
2300
- )
3296
+ qrCodeUrl && /* @__PURE__ */ jsx("div", { className: "flex justify-center p-6 bg-white rounded-xl", children: /* @__PURE__ */ jsx("img", { src: qrCodeUrl, alt: "Payment QR Code", className: "w-48 h-48" }) }),
3297
+ payment.pay_address && canPay && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
3298
+ /* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Payment Address" }),
3299
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3300
+ /* @__PURE__ */ jsx("div", { className: "flex-1 p-3 bg-muted rounded-xl font-mono text-sm break-all", children: payment.pay_address }),
3301
+ /* @__PURE__ */ jsx(CopyButton, { value: payment.pay_address, variant: "outline", className: "shrink-0" })
3302
+ ] })
2301
3303
  ] }),
2302
- /* @__PURE__ */ jsxs(Select, { value: statusFilter, onValueChange: handleStatusFilter, children: [
2303
- /* @__PURE__ */ jsxs(SelectTrigger, { className: "w-full sm:w-48", children: [
2304
- /* @__PURE__ */ jsx(Filter, { className: "h-4 w-4 mr-2" }),
2305
- /* @__PURE__ */ jsx(SelectValue, { placeholder: "Filter by status" })
3304
+ isExpired && onCreateNew && /* @__PURE__ */ jsx(
3305
+ Button,
3306
+ {
3307
+ size: "lg",
3308
+ className: "w-full",
3309
+ onClick: () => {
3310
+ onOpenChange(false);
3311
+ onCreateNew();
3312
+ },
3313
+ children: "Create New Payment"
3314
+ }
3315
+ ),
3316
+ payment.transaction_hash && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
3317
+ /* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Transaction Hash" }),
3318
+ /* @__PURE__ */ jsx("div", { className: "p-3 bg-muted rounded-xl font-mono text-sm break-all", children: payment.transaction_hash })
3319
+ ] }),
3320
+ payment.payment_url && canPay && /* @__PURE__ */ jsxs(
3321
+ Button,
3322
+ {
3323
+ variant: "outline",
3324
+ className: "w-full",
3325
+ onClick: () => window.open(payment.payment_url, "_blank"),
3326
+ children: [
3327
+ /* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4 mr-2" }),
3328
+ "Open in Payment Provider"
3329
+ ]
3330
+ }
3331
+ ),
3332
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 text-xs text-muted-foreground pt-4 border-t", children: [
3333
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
3334
+ /* @__PURE__ */ jsx("span", { children: "Payment ID" }),
3335
+ /* @__PURE__ */ jsx("span", { className: "font-mono", children: payment.id })
3336
+ ] }),
3337
+ payment.internal_payment_id && /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
3338
+ /* @__PURE__ */ jsx("span", { children: "Order #" }),
3339
+ /* @__PURE__ */ jsx("span", { className: "font-mono", children: payment.internal_payment_id })
2306
3340
  ] }),
2307
- /* @__PURE__ */ jsxs(SelectContent, { children: [
2308
- /* @__PURE__ */ jsx(SelectItem, { value: "all", children: "All Statuses" }),
2309
- /* @__PURE__ */ jsx(SelectItem, { value: "completed", children: "Completed" }),
2310
- /* @__PURE__ */ jsx(SelectItem, { value: "pending", children: "Pending" }),
2311
- /* @__PURE__ */ jsx(SelectItem, { value: "confirming", children: "Confirming" }),
2312
- /* @__PURE__ */ jsx(SelectItem, { value: "failed", children: "Failed" }),
2313
- /* @__PURE__ */ jsx(SelectItem, { value: "expired", children: "Expired" })
3341
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
3342
+ /* @__PURE__ */ jsx("span", { children: "Created" }),
3343
+ /* @__PURE__ */ jsx("span", { children: createdAt })
2314
3344
  ] })
2315
- ] })
2316
- ] }),
2317
- 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: [
2318
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2319
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" }),
2320
- /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" })
2321
3345
  ] }),
2322
- /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-16" })
2323
- ] }, i)) }) : filteredPayments.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-12", children: [
2324
- /* @__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" }) }),
2325
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: "No Payments Found" }),
2326
- /* @__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" }),
2327
- /* @__PURE__ */ jsxs(Button, { onClick: () => openCreatePaymentDialog(), children: [
2328
- /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 mr-2" }),
2329
- "Create Payment"
2330
- ] })
2331
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2332
- /* @__PURE__ */ jsx("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs(Table, { children: [
2333
- /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
2334
- /* @__PURE__ */ jsx(TableHead, { children: "Date" }),
2335
- /* @__PURE__ */ jsx(TableHead, { children: "Amount" }),
2336
- /* @__PURE__ */ jsx(TableHead, { children: "Currency" }),
2337
- /* @__PURE__ */ jsx(TableHead, { children: "Status" }),
2338
- /* @__PURE__ */ jsx(TableHead, { children: "Provider" }),
2339
- /* @__PURE__ */ jsx(TableHead, { children: "Payment ID" }),
2340
- /* @__PURE__ */ jsx(TableHead, { className: "text-right", children: "Actions" })
2341
- ] }) }),
2342
- /* @__PURE__ */ jsx(TableBody, { children: filteredPayments.map((payment) => /* @__PURE__ */ jsxs(
2343
- TableRow,
2344
- {
2345
- className: "cursor-pointer hover:bg-accent",
2346
- onClick: () => openPaymentDetailsDialog(String(payment.id)),
2347
- children: [
2348
- /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsxs("div", { children: [
2349
- /* @__PURE__ */ jsx("div", { className: "font-medium", children: payment.formattedDate }),
2350
- /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: payment.relativeTime })
2351
- ] }) }),
2352
- /* @__PURE__ */ jsx(TableCell, { className: "font-mono font-semibold", children: formatCurrency(payment.amount_usd) }),
2353
- /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Badge, { variant: "outline", children: payment.currency_code || "USD" }) }),
2354
- /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Badge, { variant: getStatusVariant(payment.status), children: payment.status }) }),
2355
- /* @__PURE__ */ jsx(TableCell, { className: "text-sm text-muted-foreground", children: "NowPayments" }),
2356
- /* @__PURE__ */ jsx(TableCell, { className: "font-mono text-sm text-muted-foreground", children: payment.truncatedId }),
2357
- /* @__PURE__ */ jsx(TableCell, { className: "text-right", children: /* @__PURE__ */ jsx(
2358
- Button,
2359
- {
2360
- variant: "ghost",
2361
- size: "sm",
2362
- onClick: (e) => {
2363
- e.stopPropagation();
2364
- openPaymentDetailsDialog(String(payment.id));
2365
- },
2366
- children: /* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4" })
2367
- }
2368
- ) })
2369
- ]
2370
- },
2371
- payment.id
2372
- )) })
2373
- ] }) }),
2374
- /* @__PURE__ */ jsx(
2375
- StaticPagination,
3346
+ /* @__PURE__ */ jsxs(
3347
+ Button,
2376
3348
  {
2377
- data: payments,
2378
- onPageChange: pagination.setPage,
2379
- className: "mt-4"
3349
+ variant: "ghost",
3350
+ className: "w-full",
3351
+ onClick: () => mutate(),
3352
+ children: [
3353
+ /* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4 mr-2" }),
3354
+ "Refresh Status"
3355
+ ]
2380
3356
  }
2381
3357
  )
2382
3358
  ] })
2383
3359
  ] })
2384
- ] });
2385
- };
2386
- var PaymentsView = () => {
2387
- return /* @__PURE__ */ jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsx(PaymentsList, {}) });
2388
- };
2389
- var TransactionsList = () => {
2390
- const {
2391
- transactions,
2392
- isLoadingTransactions,
2393
- refreshTransactions
2394
- } = useOverviewContext();
2395
- const [searchTerm, setSearchTerm] = useState("");
2396
- const [typeFilter, setTypeFilter] = useState("all");
2397
- const transactionsList = transactions?.results || transactions?.transactions || [];
2398
- const formatCurrency = (amount) => {
2399
- if (amount === null || amount === void 0) return "$0.00";
2400
- return new Intl.NumberFormat("en-US", {
2401
- style: "currency",
2402
- currency: "USD",
2403
- minimumFractionDigits: 2
2404
- }).format(amount);
2405
- };
2406
- const formatDate = (date) => {
2407
- if (!date) return "N/A";
2408
- try {
2409
- return moment.utc(date).local().format("MMM D, YYYY hh:mm A");
2410
- } catch {
2411
- return "Invalid date";
2412
- }
2413
- };
2414
- const getRelativeTime = (date) => {
2415
- if (!date) return "N/A";
2416
- const m = moment.utc(date).local();
2417
- const now = moment();
2418
- const diffInSeconds = now.diff(m, "seconds");
2419
- if (diffInSeconds < 60) return "Just now";
2420
- if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
2421
- if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
2422
- return `${Math.floor(diffInSeconds / 86400)}d ago`;
2423
- };
2424
- const getTypeVariant = (type) => {
2425
- switch (type?.toLowerCase()) {
2426
- case "deposit":
2427
- case "credit":
2428
- return "default";
2429
- case "withdrawal":
2430
- case "debit":
2431
- return "destructive";
2432
- default:
2433
- return "outline";
3360
+ ] }) });
3361
+ }
3362
+ var WalletContent = () => {
3363
+ const [addFundsOpen, setAddFundsOpen] = useState(false);
3364
+ const [withdrawOpen, setWithdrawOpen] = useState(false);
3365
+ const [selectedPaymentId, setSelectedPaymentId] = useState(null);
3366
+ const [paymentSheetOpen, setPaymentSheetOpen] = useState(false);
3367
+ const [selectedWithdrawalId, setSelectedWithdrawalId] = useState(null);
3368
+ const [withdrawalSheetOpen, setWithdrawalSheetOpen] = useState(false);
3369
+ const handleActivityClick = useCallback((item) => {
3370
+ if (item.payment) {
3371
+ setSelectedPaymentId(item.payment.id);
3372
+ setPaymentSheetOpen(true);
3373
+ } else if (item.withdrawal) {
3374
+ setSelectedWithdrawalId(item.withdrawal.id);
3375
+ setWithdrawalSheetOpen(true);
2434
3376
  }
2435
- };
2436
- const getTypeIcon = (type) => {
2437
- const isDeposit = type?.toLowerCase() === "deposit" || type?.toLowerCase() === "credit";
2438
- return isDeposit ? /* @__PURE__ */ jsx(ArrowDownLeft, { className: "h-4 w-4 text-green-600" }) : /* @__PURE__ */ jsx(ArrowUpRight, { className: "h-4 w-4 text-red-600" });
2439
- };
2440
- const handleSearch = async (value) => {
2441
- setSearchTerm(value);
2442
- await refreshTransactions();
2443
- };
2444
- const handleTypeFilter = async (type) => {
2445
- setTypeFilter(type);
2446
- await refreshTransactions();
2447
- };
2448
- const truncateId = (id) => {
2449
- if (!id) return "N/A";
2450
- const str = id.toString();
2451
- return str.length > 8 ? `${str.slice(0, 8)}...` : str;
2452
- };
2453
- const filteredTransactions = transactionsList.filter((transaction) => {
2454
- const matchesSearch = searchTerm ? transaction.id?.toString().toLowerCase().includes(searchTerm.toLowerCase()) || transaction.description?.toLowerCase().includes(searchTerm.toLowerCase()) || transaction.type?.toLowerCase().includes(searchTerm.toLowerCase()) : true;
2455
- const matchesType = typeFilter !== "all" ? transaction.type?.toLowerCase() === typeFilter.toLowerCase() : true;
2456
- return matchesSearch && matchesType;
2457
- }).map((transaction) => ({
2458
- ...transaction,
2459
- isDeposit: transaction.type?.toLowerCase() === "deposit" || transaction.type?.toLowerCase() === "credit",
2460
- formattedDate: formatDate(transaction.created_at || transaction.timestamp),
2461
- relativeTime: getRelativeTime(transaction.created_at || transaction.timestamp),
2462
- truncatedRef: truncateId(transaction.reference || transaction.payment_id)
2463
- }));
2464
- if (isLoadingTransactions) {
2465
- return /* @__PURE__ */ jsxs(Card, { children: [
2466
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2", children: [
2467
- /* @__PURE__ */ jsx(History, { className: "h-5 w-5" }),
2468
- "Transaction History"
2469
- ] }) }),
2470
- /* @__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: [
2471
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2472
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" }),
2473
- /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" })
2474
- ] }),
2475
- /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-16" })
2476
- ] }, i)) })
2477
- ] });
2478
- }
2479
- return /* @__PURE__ */ jsxs(Card, { children: [
2480
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center justify-between", children: [
2481
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2482
- /* @__PURE__ */ jsx(History, { className: "h-5 w-5" }),
2483
- "Transaction History"
2484
- ] }),
2485
- /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: refreshTransactions, disabled: isLoadingTransactions, children: [
2486
- /* @__PURE__ */ jsx(RefreshCw, { className: `h-4 w-4 mr-2 ${isLoadingTransactions ? "animate-spin" : ""}` }),
2487
- "Refresh"
2488
- ] })
2489
- ] }) }),
2490
- /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
2491
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row gap-4", children: [
2492
- /* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
2493
- /* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
2494
- /* @__PURE__ */ jsx(
2495
- Input,
2496
- {
2497
- placeholder: "Search by ID, description, or type...",
2498
- value: searchTerm,
2499
- onChange: (e) => handleSearch(e.target.value),
2500
- className: "pl-10"
2501
- }
2502
- )
2503
- ] }),
2504
- /* @__PURE__ */ jsxs(Select, { value: typeFilter, onValueChange: handleTypeFilter, children: [
2505
- /* @__PURE__ */ jsxs(SelectTrigger, { className: "w-full sm:w-48", children: [
2506
- /* @__PURE__ */ jsx(Filter, { className: "h-4 w-4 mr-2" }),
2507
- /* @__PURE__ */ jsx(SelectValue, { placeholder: "Filter by type" })
2508
- ] }),
2509
- /* @__PURE__ */ jsxs(SelectContent, { children: [
2510
- /* @__PURE__ */ jsx(SelectItem, { value: "all", children: "All Types" }),
2511
- /* @__PURE__ */ jsx(SelectItem, { value: "deposit", children: "Deposits" }),
2512
- /* @__PURE__ */ jsx(SelectItem, { value: "withdrawal", children: "Withdrawals" })
2513
- ] })
2514
- ] })
2515
- ] }),
2516
- filteredTransactions.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "text-center py-12", children: [
2517
- /* @__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" }) }),
2518
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: "No Transactions Found" }),
2519
- /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: searchTerm || typeFilter !== "all" ? "No transactions match your current filters" : "You don't have any transactions yet" })
2520
- ] }) : /* @__PURE__ */ jsx("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs(Table, { children: [
2521
- /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
2522
- /* @__PURE__ */ jsx(TableHead, { children: "Date & Time" }),
2523
- /* @__PURE__ */ jsx(TableHead, { children: "Type" }),
2524
- /* @__PURE__ */ jsx(TableHead, { children: "Amount" }),
2525
- /* @__PURE__ */ jsx(TableHead, { children: "Balance After" }),
2526
- /* @__PURE__ */ jsx(TableHead, { children: "Description" }),
2527
- /* @__PURE__ */ jsx(TableHead, { children: "Reference" })
2528
- ] }) }),
2529
- /* @__PURE__ */ jsx(TableBody, { children: filteredTransactions.map((transaction, index) => /* @__PURE__ */ jsxs(TableRow, { children: [
2530
- /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsxs("div", { children: [
2531
- /* @__PURE__ */ jsx("div", { className: "font-medium", children: transaction.formattedDate }),
2532
- /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: transaction.relativeTime })
2533
- ] }) }),
2534
- /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2535
- getTypeIcon(transaction.type),
2536
- /* @__PURE__ */ jsx(Badge, { variant: getTypeVariant(transaction.type), children: transaction.type || "Unknown" })
2537
- ] }) }),
2538
- /* @__PURE__ */ jsx(TableCell, { className: "font-mono font-semibold", children: /* @__PURE__ */ jsxs("span", { className: transaction.isDeposit ? "text-green-600" : "text-red-600", children: [
2539
- transaction.isDeposit ? "+" : "-",
2540
- formatCurrency(Math.abs(transaction.amount || transaction.amount_usd || 0))
2541
- ] }) }),
2542
- /* @__PURE__ */ jsx(TableCell, { className: "font-mono", children: formatCurrency(transaction.balance_after || 0) }),
2543
- /* @__PURE__ */ jsx(TableCell, { className: "text-sm", children: transaction.description || transaction.note || "No description" }),
2544
- /* @__PURE__ */ jsx(TableCell, { className: "font-mono text-sm text-muted-foreground", children: transaction.truncatedRef })
2545
- ] }, transaction.id || index)) })
2546
- ] }) })
2547
- ] })
3377
+ }, []);
3378
+ const handlePaymentCreated = useCallback((payment) => {
3379
+ setSelectedPaymentId(payment.id);
3380
+ setPaymentSheetOpen(true);
3381
+ }, []);
3382
+ return /* @__PURE__ */ jsxs("div", { className: "min-h-screen", children: [
3383
+ /* @__PURE__ */ jsx(
3384
+ BalanceHero,
3385
+ {
3386
+ onAddFunds: () => setAddFundsOpen(true),
3387
+ onWithdraw: () => setWithdrawOpen(true),
3388
+ className: "bg-muted/30 border-b"
3389
+ }
3390
+ ),
3391
+ /* @__PURE__ */ jsx(
3392
+ ActivityList,
3393
+ {
3394
+ onItemClick: handleActivityClick,
3395
+ limit: 20,
3396
+ className: "max-w-2xl mx-auto pb-12"
3397
+ }
3398
+ ),
3399
+ /* @__PURE__ */ jsx(
3400
+ AddFundsSheet,
3401
+ {
3402
+ open: addFundsOpen,
3403
+ onOpenChange: setAddFundsOpen,
3404
+ onSuccess: handlePaymentCreated
3405
+ }
3406
+ ),
3407
+ /* @__PURE__ */ jsx(
3408
+ WithdrawSheet,
3409
+ {
3410
+ open: withdrawOpen,
3411
+ onOpenChange: setWithdrawOpen
3412
+ }
3413
+ ),
3414
+ /* @__PURE__ */ jsx(
3415
+ PaymentSheet,
3416
+ {
3417
+ paymentId: selectedPaymentId,
3418
+ open: paymentSheetOpen,
3419
+ onOpenChange: setPaymentSheetOpen,
3420
+ onCreateNew: () => setAddFundsOpen(true)
3421
+ }
3422
+ ),
3423
+ /* @__PURE__ */ jsx(
3424
+ WithdrawalSheet,
3425
+ {
3426
+ withdrawalId: selectedWithdrawalId,
3427
+ open: withdrawalSheetOpen,
3428
+ onOpenChange: setWithdrawalSheetOpen
3429
+ }
3430
+ )
2548
3431
  ] });
2549
3432
  };
2550
- var TransactionsView = () => {
2551
- return /* @__PURE__ */ jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsx(TransactionsList, {}) });
2552
- };
2553
- var PaymentsLayout = () => {
2554
- return /* @__PURE__ */ jsx(RootPaymentsProvider, { children: /* @__PURE__ */ jsxs("div", { className: "h-full p-6 space-y-6", children: [
2555
- /* @__PURE__ */ jsxs("div", { children: [
2556
- /* @__PURE__ */ jsx("h1", { className: "text-3xl font-bold tracking-tight", children: "Payments" }),
2557
- /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "Manage your payments, balance, and transaction history" })
2558
- ] }),
2559
- /* @__PURE__ */ jsxs(Tabs, { defaultValue: "overview", className: "space-y-6", children: [
2560
- /* @__PURE__ */ jsxs(TabsList, { className: "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground", children: [
2561
- /* @__PURE__ */ jsxs(TabsTrigger, { value: "overview", className: "inline-flex items-center gap-2 px-3 py-1.5", children: [
2562
- /* @__PURE__ */ jsx(Wallet, { className: "h-4 w-4" }),
2563
- /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Overview" })
2564
- ] }),
2565
- /* @__PURE__ */ jsxs(TabsTrigger, { value: "payments", className: "inline-flex items-center gap-2 px-3 py-1.5", children: [
2566
- /* @__PURE__ */ jsx(CreditCard, { className: "h-4 w-4" }),
2567
- /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Payments" })
2568
- ] }),
2569
- /* @__PURE__ */ jsxs(TabsTrigger, { value: "transactions", className: "inline-flex items-center gap-2 px-3 py-1.5", children: [
2570
- /* @__PURE__ */ jsx(History, { className: "h-4 w-4" }),
2571
- /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Transactions" })
2572
- ] })
2573
- ] }),
2574
- /* @__PURE__ */ jsx(TabsContent, { value: "overview", className: "space-y-6", children: /* @__PURE__ */ jsx(OverviewProvider, { children: /* @__PURE__ */ jsxs(PaymentsProvider, { children: [
2575
- /* @__PURE__ */ jsx(OverviewView, {}),
2576
- /* @__PURE__ */ jsx(CreatePaymentDialog, {})
2577
- ] }) }) }),
2578
- /* @__PURE__ */ jsx(TabsContent, { value: "payments", className: "space-y-6", children: /* @__PURE__ */ jsxs(PaymentsProvider, { children: [
2579
- /* @__PURE__ */ jsx(PaymentsView, {}),
2580
- /* @__PURE__ */ jsx(CreatePaymentDialog, {})
2581
- ] }) }),
2582
- /* @__PURE__ */ jsx(TabsContent, { value: "transactions", className: "space-y-6", children: /* @__PURE__ */ jsx(OverviewProvider, { children: /* @__PURE__ */ jsx(TransactionsView, {}) }) })
2583
- ] }),
2584
- /* @__PURE__ */ jsx(PaymentDetailsDialog, {})
2585
- ] }) });
2586
- };
3433
+ function WalletPage() {
3434
+ return /* @__PURE__ */ jsx(WalletProvider, { children: /* @__PURE__ */ jsx(WalletContent, {}) });
3435
+ }
2587
3436
 
2588
3437
  // package.json
2589
3438
  var package_default = {
2590
3439
  name: "@djangocfg/ext-payments",
2591
- version: "1.0.14",
3440
+ version: "1.0.19",
2592
3441
  description: "Payments system extension for DjangoCFG",
2593
3442
  keywords: [
2594
3443
  "django",
@@ -2625,11 +3474,6 @@ var package_default = {
2625
3474
  import: "./dist/index.js",
2626
3475
  require: "./dist/index.cjs"
2627
3476
  },
2628
- "./hooks": {
2629
- types: "./dist/hooks.d.ts",
2630
- import: "./dist/hooks.js",
2631
- require: "./dist/hooks.cjs"
2632
- },
2633
3477
  "./config": {
2634
3478
  types: "./dist/config.d.ts",
2635
3479
  import: "./dist/config.js",
@@ -2657,8 +3501,10 @@ var package_default = {
2657
3501
  "p-retry": "^7.0.0",
2658
3502
  react: "^19",
2659
3503
  swr: "^2.3.7",
2660
- zod: "^4.1.13",
2661
- moment: "^2.30.1"
3504
+ zod: "^4.3.4",
3505
+ moment: "^2.30.1",
3506
+ "react-hook-form": "^7.69.0",
3507
+ "@hookform/resolvers": "^5.2.2"
2662
3508
  },
2663
3509
  devDependencies: {
2664
3510
  "@djangocfg/api": "workspace:*",
@@ -2731,4 +3577,4 @@ export default function CryptoCheckout() {
2731
3577
  ]
2732
3578
  });
2733
3579
 
2734
- 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 };
3580
+ export { API, APIClient, APIError, APILogger, ActivityItem, ActivityList, AddFundsSheet, BalanceHero, BalanceSchema, CookieStorageAdapter, CurrencySchema, DEFAULT_RETRY_CONFIG, enums_exports as Enums, models_exports as ExtPaymentsPaymentsTypes, FetchAdapter, fetchers_exports as Fetchers, LocalStorageAdapter, MemoryStorageAdapter, NetworkError, PaginatedPaymentListListSchema, PaginatedWithdrawalListListSchema, PaymentCreateRequestSchema, PaymentCreateResponseSchema, PaymentDetailSchema, PaymentListSchema, PaymentSheet, REFRESH_TOKEN_KEY, schemas_exports as Schemas, TOKEN_KEY, TransactionSchema, WalletPage, WithdrawSheet, WithdrawalCancelResponseSchema, WithdrawalCreateRequestSchema, WithdrawalCreateResponseSchema, WithdrawalDetailSchema, WithdrawalListSchema, WithdrawalSheet, apiPayments, clearAPITokens, configureAPI, createPaymentsPaymentsConfirmCreate, createPaymentsPaymentsCreateCreate, createPaymentsWithdrawalsCancelCreate, createPaymentsWithdrawalsCreateCreate, dispatchValidationError, extensionConfig, formatZodError, getAPIInstance, getPaymentsBalanceRetrieve, getPaymentsCurrenciesEstimateRetrieve, getPaymentsCurrenciesList, getPaymentsCurrenciesWithdrawalEstimateRetrieve, getPaymentsPaymentsList, getPaymentsPaymentsRetrieve, getPaymentsPaymentsStatusRetrieve, getPaymentsTransactionsList, getPaymentsWithdrawalsList, getPaymentsWithdrawalsRetrieve, isAPIConfigured, onValidationError, reconfigureAPI, resetAPI, shouldRetry, withRetry };