@djangocfg/ext-payments 1.0.17 → 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 (46) hide show
  1. package/dist/config.cjs +1 -1
  2. package/dist/config.js +1 -1
  3. package/dist/index.cjs +1175 -290
  4. package/dist/index.d.cts +226 -80
  5. package/dist/index.d.ts +226 -80
  6. package/dist/index.js +1157 -255
  7. package/package.json +9 -9
  8. package/src/WalletPage.tsx +100 -0
  9. package/src/api/generated/ext_payments/CLAUDE.md +6 -4
  10. package/src/api/generated/ext_payments/_utils/fetchers/ext_payments__payments.ts +37 -6
  11. package/src/api/generated/ext_payments/_utils/hooks/ext_payments__payments.ts +34 -3
  12. package/src/api/generated/ext_payments/_utils/schemas/Balance.schema.ts +1 -1
  13. package/src/api/generated/ext_payments/_utils/schemas/PaymentCreateResponse.schema.ts +22 -0
  14. package/src/api/generated/ext_payments/_utils/schemas/PaymentDetail.schema.ts +3 -3
  15. package/src/api/generated/ext_payments/_utils/schemas/PaymentList.schema.ts +2 -2
  16. package/src/api/generated/ext_payments/_utils/schemas/Transaction.schema.ts +1 -1
  17. package/src/api/generated/ext_payments/_utils/schemas/WithdrawalCancelResponse.schema.ts +22 -0
  18. package/src/api/generated/ext_payments/_utils/schemas/WithdrawalCreateResponse.schema.ts +22 -0
  19. package/src/api/generated/ext_payments/_utils/schemas/WithdrawalDetail.schema.ts +5 -5
  20. package/src/api/generated/ext_payments/_utils/schemas/WithdrawalList.schema.ts +2 -2
  21. package/src/api/generated/ext_payments/_utils/schemas/index.ts +3 -0
  22. package/src/api/generated/ext_payments/client.ts +1 -1
  23. package/src/api/generated/ext_payments/ext_payments__payments/client.ts +49 -4
  24. package/src/api/generated/ext_payments/ext_payments__payments/models.ts +33 -14
  25. package/src/api/generated/ext_payments/index.ts +1 -1
  26. package/src/api/generated/ext_payments/schema.json +167 -33
  27. package/src/components/AddFundsSheet.tsx +157 -73
  28. package/src/components/CurrencyCombobox.tsx +49 -0
  29. package/src/components/PaymentSheet.tsx +94 -32
  30. package/src/components/WithdrawSheet.tsx +121 -95
  31. package/src/components/WithdrawalSheet.tsx +332 -0
  32. package/src/components/index.ts +1 -8
  33. package/src/config.ts +1 -0
  34. package/src/contexts/WalletContext.tsx +10 -9
  35. package/src/contexts/index.ts +5 -1
  36. package/src/contexts/types.ts +46 -0
  37. package/src/hooks/index.ts +3 -0
  38. package/src/hooks/useCurrencyOptions.ts +79 -0
  39. package/src/hooks/useEstimate.ts +113 -0
  40. package/src/hooks/useWithdrawalEstimate.ts +117 -0
  41. package/src/index.ts +3 -0
  42. package/src/types/index.ts +78 -0
  43. package/src/utils/errors.ts +36 -0
  44. package/src/utils/format.ts +65 -0
  45. package/src/utils/index.ts +3 -0
  46. package/src/components/ResponsiveSheet.tsx +0 -151
package/dist/index.js CHANGED
@@ -1,15 +1,14 @@
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 { Plus, ArrowUpRight, RefreshCw, AlertCircle, XCircle, CheckCircle2, Loader2, Clock, ArrowDownLeft, History, ChevronRight, ExternalLink } from 'lucide-react';
6
- import { Skeleton, Button, TokenIcon, ResponsiveSheet, ResponsiveSheetContent, ResponsiveSheetHeader, ResponsiveSheetTitle, ResponsiveSheetDescription, Form, FormField, FormItem, FormLabel, FormControl, Input, FormMessage, Combobox, Alert, AlertDescription, CopyButton, useIsMobile, Drawer, Dialog, DrawerContent, DialogContent, DrawerHeader, DialogHeader, DrawerTitle, DialogTitle, DrawerDescription, DialogDescription, DrawerFooter, DialogFooter } from '@djangocfg/ui-core';
7
- import { cn } from '@djangocfg/ui-core/lib';
8
- import * as React2 from 'react';
9
- import { createContext, useState, useMemo, useCallback, useEffect, useContext } from 'react';
10
- import useSWR2 from 'swr';
6
+ import useSWR, { useSWRConfig } from 'swr';
11
7
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
12
- import moment2 from 'moment';
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';
13
12
  import { useForm } from 'react-hook-form';
14
13
  import { zodResolver } from '@hookform/resolvers/zod';
15
14
  import { createExtensionConfig } from '@djangocfg/ext-base';
@@ -38,12 +37,47 @@ var ExtPaymentsPayments = class {
38
37
  /**
39
38
  * Get available currencies
40
39
  *
41
- * Returns list of available currencies with token+network info
40
+ * Returns list of available currencies with token+network info, popular
41
+ * first
42
42
  */
43
43
  async currenciesList() {
44
44
  const response = await this.client.request("GET", "/cfg/payments/currencies/");
45
45
  return response;
46
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
+ }
47
81
  /**
48
82
  * ViewSet for payment operations. Endpoints: - GET /payments/ - List
49
83
  * user's payments - GET /payments/{id}/ - Get payment details - POST
@@ -721,8 +755,8 @@ var APIClient = class {
721
755
  // src/api/generated/ext_payments/storage.ts
722
756
  var LocalStorageAdapter = class {
723
757
  logger;
724
- constructor(logger) {
725
- this.logger = logger;
758
+ constructor(logger2) {
759
+ this.logger = logger2;
726
760
  }
727
761
  getItem(key) {
728
762
  try {
@@ -764,8 +798,8 @@ var LocalStorageAdapter = class {
764
798
  };
765
799
  var CookieStorageAdapter = class {
766
800
  logger;
767
- constructor(logger) {
768
- this.logger = logger;
801
+ constructor(logger2) {
802
+ this.logger = logger2;
769
803
  }
770
804
  getItem(key) {
771
805
  try {
@@ -814,8 +848,8 @@ var CookieStorageAdapter = class {
814
848
  var MemoryStorageAdapter = class {
815
849
  storage = /* @__PURE__ */ new Map();
816
850
  logger;
817
- constructor(logger) {
818
- this.logger = logger;
851
+ constructor(logger2) {
852
+ this.logger = logger2;
819
853
  }
820
854
  getItem(key) {
821
855
  const value = this.storage.get(key) || null;
@@ -900,10 +934,13 @@ __export(schemas_exports, {
900
934
  PaginatedPaymentListListSchema: () => PaginatedPaymentListListSchema,
901
935
  PaginatedWithdrawalListListSchema: () => PaginatedWithdrawalListListSchema,
902
936
  PaymentCreateRequestSchema: () => PaymentCreateRequestSchema,
937
+ PaymentCreateResponseSchema: () => PaymentCreateResponseSchema,
903
938
  PaymentDetailSchema: () => PaymentDetailSchema,
904
939
  PaymentListSchema: () => PaymentListSchema,
905
940
  TransactionSchema: () => TransactionSchema,
941
+ WithdrawalCancelResponseSchema: () => WithdrawalCancelResponseSchema,
906
942
  WithdrawalCreateRequestSchema: () => WithdrawalCreateRequestSchema,
943
+ WithdrawalCreateResponseSchema: () => WithdrawalCreateResponseSchema,
907
944
  WithdrawalDetailSchema: () => WithdrawalDetailSchema,
908
945
  WithdrawalListSchema: () => WithdrawalListSchema
909
946
  });
@@ -912,7 +949,7 @@ var BalanceSchema = z.object({
912
949
  balance_display: z.string(),
913
950
  total_deposited: z.string(),
914
951
  total_withdrawn: z.string(),
915
- last_transaction_at: z.iso.datetime().nullable()
952
+ last_transaction_at: z.string().datetime({ offset: true }).nullable()
916
953
  });
917
954
  var CurrencySchema = z.object({
918
955
  code: z.string(),
@@ -934,8 +971,8 @@ var PaymentListSchema = z.object({
934
971
  currency_token: z.string(),
935
972
  status: z.nativeEnum(PaymentListStatus),
936
973
  status_display: z.string(),
937
- created_at: z.iso.datetime(),
938
- completed_at: z.iso.datetime().nullable()
974
+ created_at: z.string().datetime({ offset: true }),
975
+ completed_at: z.string().datetime({ offset: true }).nullable()
939
976
  });
940
977
 
941
978
  // src/api/generated/ext_payments/_utils/schemas/PaginatedPaymentListList.schema.ts
@@ -959,8 +996,8 @@ var WithdrawalListSchema = z.object({
959
996
  currency_token: z.string(),
960
997
  status: z.nativeEnum(WithdrawalListStatus),
961
998
  status_display: z.string(),
962
- created_at: z.iso.datetime(),
963
- completed_at: z.iso.datetime().nullable()
999
+ created_at: z.string().datetime({ offset: true }),
1000
+ completed_at: z.string().datetime({ offset: true }).nullable()
964
1001
  });
965
1002
 
966
1003
  // src/api/generated/ext_payments/_utils/schemas/PaginatedWithdrawalListList.schema.ts
@@ -999,14 +1036,21 @@ var PaymentDetailSchema = z.object({
999
1036
  transaction_hash: z.string().nullable(),
1000
1037
  explorer_link: z.string().nullable(),
1001
1038
  confirmations_count: z.int(),
1002
- expires_at: z.iso.datetime().nullable(),
1003
- completed_at: z.iso.datetime().nullable(),
1004
- 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 }),
1005
1042
  is_completed: z.boolean(),
1006
1043
  is_failed: z.boolean(),
1007
1044
  is_expired: z.boolean(),
1008
1045
  description: z.string()
1009
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
+ });
1010
1054
  var TransactionSchema = z.object({
1011
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),
1012
1056
  transaction_type: z.nativeEnum(TransactionTransactionType),
@@ -1016,12 +1060,7 @@ var TransactionSchema = z.object({
1016
1060
  balance_after: z.string(),
1017
1061
  payment_id: z.string().nullable(),
1018
1062
  description: z.string(),
1019
- created_at: z.iso.datetime()
1020
- });
1021
- var WithdrawalCreateRequestSchema = z.object({
1022
- amount_usd: z.string(),
1023
- currency_code: z.string().min(1).max(20),
1024
- wallet_address: z.string().min(1).max(255)
1063
+ created_at: z.string().datetime({ offset: true })
1025
1064
  });
1026
1065
  var WithdrawalDetailSchema = z.object({
1027
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),
@@ -1042,11 +1081,28 @@ var WithdrawalDetailSchema = z.object({
1042
1081
  transaction_hash: z.string().nullable(),
1043
1082
  explorer_link: z.string().nullable(),
1044
1083
  admin_notes: z.string(),
1045
- created_at: z.iso.datetime(),
1046
- approved_at: z.iso.datetime().nullable(),
1047
- completed_at: z.iso.datetime().nullable(),
1048
- rejected_at: z.iso.datetime().nullable(),
1049
- cancelled_at: z.iso.datetime().nullable()
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()
1050
1106
  });
1051
1107
 
1052
1108
  // src/api/generated/ext_payments/validation-events.ts
@@ -1103,7 +1159,9 @@ __export(fetchers_exports, {
1103
1159
  createPaymentsWithdrawalsCancelCreate: () => createPaymentsWithdrawalsCancelCreate,
1104
1160
  createPaymentsWithdrawalsCreateCreate: () => createPaymentsWithdrawalsCreateCreate,
1105
1161
  getPaymentsBalanceRetrieve: () => getPaymentsBalanceRetrieve,
1162
+ getPaymentsCurrenciesEstimateRetrieve: () => getPaymentsCurrenciesEstimateRetrieve,
1106
1163
  getPaymentsCurrenciesList: () => getPaymentsCurrenciesList,
1164
+ getPaymentsCurrenciesWithdrawalEstimateRetrieve: () => getPaymentsCurrenciesWithdrawalEstimateRetrieve,
1107
1165
  getPaymentsPaymentsList: () => getPaymentsPaymentsList,
1108
1166
  getPaymentsPaymentsRetrieve: () => getPaymentsPaymentsRetrieve,
1109
1167
  getPaymentsPaymentsStatusRetrieve: () => getPaymentsPaymentsStatusRetrieve,
@@ -1214,6 +1272,16 @@ async function getPaymentsCurrenciesList(client) {
1214
1272
  const response = await api.ext_payments_payments.currenciesList();
1215
1273
  return response;
1216
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
+ }
1217
1285
  async function getPaymentsPaymentsList(params, client) {
1218
1286
  const api = client || getAPIInstance();
1219
1287
  const response = await api.ext_payments_payments.paymentsList(params?.page, params?.page_size);
@@ -1386,7 +1454,7 @@ async function createPaymentsPaymentsCreateCreate(data, client) {
1386
1454
  const api = client || getAPIInstance();
1387
1455
  const response = await api.ext_payments_payments.paymentsCreateCreate(data);
1388
1456
  try {
1389
- return PaymentDetailSchema.parse(response);
1457
+ return PaymentCreateResponseSchema.parse(response);
1390
1458
  } catch (error) {
1391
1459
  consola.error("\u274C Zod Validation Failed");
1392
1460
  consola.box(`createPaymentsPaymentsCreateCreate
@@ -1517,7 +1585,7 @@ async function createPaymentsWithdrawalsCancelCreate(id, client) {
1517
1585
  const api = client || getAPIInstance();
1518
1586
  const response = await api.ext_payments_payments.withdrawalsCancelCreate(id);
1519
1587
  try {
1520
- return WithdrawalDetailSchema.parse(response);
1588
+ return WithdrawalCancelResponseSchema.parse(response);
1521
1589
  } catch (error) {
1522
1590
  consola.error("\u274C Zod Validation Failed");
1523
1591
  consola.box(`createPaymentsWithdrawalsCancelCreate
@@ -1559,7 +1627,7 @@ async function createPaymentsWithdrawalsCreateCreate(data, client) {
1559
1627
  const api = client || getAPIInstance();
1560
1628
  const response = await api.ext_payments_payments.withdrawalsCreateCreate(data);
1561
1629
  try {
1562
- return WithdrawalDetailSchema.parse(response);
1630
+ return WithdrawalCreateResponseSchema.parse(response);
1563
1631
  } catch (error) {
1564
1632
  consola.error("\u274C Zod Validation Failed");
1565
1633
  consola.box(`createPaymentsWithdrawalsCreateCreate
@@ -1613,8 +1681,8 @@ var API = class {
1613
1681
  constructor(baseUrl, options) {
1614
1682
  this.baseUrl = baseUrl;
1615
1683
  this.options = options;
1616
- const logger = options?.loggerConfig ? new APILogger(options.loggerConfig) : void 0;
1617
- this.storage = options?.storage || new LocalStorageAdapter(logger);
1684
+ const logger2 = options?.loggerConfig ? new APILogger(options.loggerConfig) : void 0;
1685
+ this.storage = options?.storage || new LocalStorageAdapter(logger2);
1618
1686
  this._loadTokensFromStorage();
1619
1687
  this._client = new APIClient(this.baseUrl, {
1620
1688
  retryConfig: this.options?.retryConfig,
@@ -1723,9 +1791,215 @@ var API = class {
1723
1791
  return "./schema.json";
1724
1792
  }
1725
1793
  };
1794
+
1795
+ // src/api/index.ts
1726
1796
  initializeExtensionAPI(configureAPI);
1727
1797
  var apiPayments = createExtensionAPI(API);
1798
+ function usePaymentsBalanceRetrieve(client) {
1799
+ return useSWR(
1800
+ "cfg-payments-balance",
1801
+ () => getPaymentsBalanceRetrieve(client)
1802
+ );
1803
+ }
1804
+ function usePaymentsCurrenciesList(client) {
1805
+ return useSWR(
1806
+ "cfg-payments-currencies",
1807
+ () => getPaymentsCurrenciesList(client)
1808
+ );
1809
+ }
1810
+ function usePaymentsPaymentsList(params, client) {
1811
+ return useSWR(
1812
+ params ? ["cfg-payments-payments", params] : "cfg-payments-payments",
1813
+ () => getPaymentsPaymentsList(params, client)
1814
+ );
1815
+ }
1816
+ function useCreatePaymentsPaymentsCreateCreate() {
1817
+ const { mutate } = useSWRConfig();
1818
+ return async (data, client) => {
1819
+ const result = await createPaymentsPaymentsCreateCreate(data, client);
1820
+ mutate("cfg-payments-payments");
1821
+ return result;
1822
+ };
1823
+ }
1824
+ function usePaymentsTransactionsList(params, client) {
1825
+ return useSWR(
1826
+ params ? ["cfg-payments-transactions", params] : "cfg-payments-transactions",
1827
+ () => getPaymentsTransactionsList(params, client)
1828
+ );
1829
+ }
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");
1841
+ return result;
1842
+ };
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");
1849
+ return result;
1850
+ };
1851
+ }
1728
1852
  var WalletContext = createContext(void 0);
1853
+ function WalletProvider({ children }) {
1854
+ const {
1855
+ data: balance,
1856
+ isLoading: isLoadingBalance,
1857
+ mutate: mutateBalance
1858
+ } = usePaymentsBalanceRetrieve(apiPayments);
1859
+ const {
1860
+ data: paymentsData,
1861
+ isLoading: isLoadingPayments,
1862
+ mutate: mutatePayments
1863
+ } = usePaymentsPaymentsList({ page: 1, page_size: 20 }, apiPayments);
1864
+ const {
1865
+ data: transactionsData,
1866
+ isLoading: isLoadingTransactions,
1867
+ mutate: mutateTransactions
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);
1879
+ const createPaymentMutation = useCreatePaymentsPaymentsCreateCreate();
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 () => {
1974
+ await Promise.all([
1975
+ mutateBalance(),
1976
+ mutatePayments(),
1977
+ mutateWithdrawals(),
1978
+ mutateTransactions(),
1979
+ mutateCurrencies()
1980
+ ]);
1981
+ }, [mutateBalance, mutatePayments, mutateWithdrawals, mutateTransactions, mutateCurrencies]);
1982
+ const isLoading = isLoadingBalance || isLoadingPayments || isLoadingWithdrawals || isLoadingTransactions;
1983
+ const isLoadingActivity = isLoadingPayments || isLoadingWithdrawals || isLoadingTransactions;
1984
+ const value = {
1985
+ balance,
1986
+ balanceAmount,
1987
+ isLoadingBalance,
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
2000
+ };
2001
+ return /* @__PURE__ */ jsx(WalletContext.Provider, { value, children });
2002
+ }
1729
2003
  function useWallet() {
1730
2004
  const context = useContext(WalletContext);
1731
2005
  if (!context) {
@@ -1733,6 +2007,44 @@ function useWallet() {
1733
2007
  }
1734
2008
  return context;
1735
2009
  }
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
+ }
2031
+ }
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";
2046
+ }
2047
+ }
1736
2048
  function BalanceHero({ onAddFunds, onWithdraw, className }) {
1737
2049
  const { balance, balanceAmount, isLoadingBalance, refreshWallet } = useWallet();
1738
2050
  const formattedBalance = new Intl.NumberFormat("en-US", {
@@ -1838,7 +2150,7 @@ function ActivityItem({ item, onClick }) {
1838
2150
  const StatusIcon = config.icon;
1839
2151
  const isPositive = item.type === "payment" || item.type === "deposit";
1840
2152
  const DirectionIcon = isPositive ? ArrowDownLeft : ArrowUpRight;
1841
- const relativeTime = moment2(item.createdAt).fromNow();
2153
+ const relativeTime = moment3(item.createdAt).fromNow();
1842
2154
  return /* @__PURE__ */ jsxs(
1843
2155
  "button",
1844
2156
  {
@@ -1927,41 +2239,299 @@ function ActivityList({
1927
2239
  )) })
1928
2240
  ] });
1929
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;
2444
+ }
2445
+ var isDevelopment = process.env.NODE_ENV === "development";
2446
+ createConsola({
2447
+ level: isDevelopment ? 4 : 1
2448
+ }).withTag("ext-payments");
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
+ }
2475
+ );
2476
+ }
1930
2477
  var AddFundsSchema = z.object({
1931
- amount: z.number().min(1, "Minimum $1.00"),
2478
+ amount: z.number().min(1, "Minimum $1"),
1932
2479
  currency: z.string().min(1, "Select a currency")
1933
2480
  });
2481
+ var STORAGE_KEY = "payments:addFunds";
1934
2482
  function AddFundsSheet({ open, onOpenChange, onSuccess }) {
1935
2483
  const { currencies, isLoadingCurrencies, addFunds } = useWallet();
1936
2484
  const [isSubmitting, setIsSubmitting] = useState(false);
1937
2485
  const [error, setError] = useState(null);
2486
+ const [saved, setSaved] = useLocalStorage(STORAGE_KEY, {
2487
+ currency: "",
2488
+ amount: 100
2489
+ });
1938
2490
  const form = useForm({
1939
2491
  resolver: zodResolver(AddFundsSchema),
1940
2492
  defaultValues: {
1941
- amount: 100,
1942
- currency: ""
2493
+ amount: saved.amount,
2494
+ currency: saved.currency
1943
2495
  }
1944
2496
  });
1945
- const currencyOptions = useMemo(() => {
1946
- return currencies.map((c) => ({
1947
- value: c.code,
1948
- label: c.network ? `${c.code} (${c.network})` : c.code,
1949
- rate: c.rate,
1950
- network: c.network
1951
- }));
1952
- }, [currencies]);
1953
- useMemo(() => {
1954
- if (currencyOptions.length > 0 && !form.getValues("currency")) {
1955
- const usdt = currencyOptions.find((c) => c.value.includes("USDT"));
1956
- form.setValue("currency", usdt?.value || currencyOptions[0].value);
1957
- }
1958
- }, [currencyOptions, form]);
1959
- const selectedCurrency = currencyOptions.find((c) => c.value === form.watch("currency"));
1960
- const cryptoAmount = useMemo(() => {
1961
- const amount = form.watch("amount");
1962
- if (!selectedCurrency?.rate || !amount) return null;
1963
- return amount / selectedCurrency.rate;
1964
- }, [form.watch("amount"), selectedCurrency]);
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;
2521
+ return {
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
2533
+ };
2534
+ }, [selectedCurrency, estimate, watchedAmount]);
1965
2535
  const handleSubmit = useCallback(async (data) => {
1966
2536
  try {
1967
2537
  setIsSubmitting(true);
@@ -1974,19 +2544,22 @@ function AddFundsSheet({ open, onOpenChange, onSuccess }) {
1974
2544
  onOpenChange(false);
1975
2545
  onSuccess?.(result);
1976
2546
  } catch (err) {
1977
- const message = err?.response?.data?.message || err?.response?.data?.detail || err?.message || "Failed to create payment";
1978
- setError(message);
2547
+ setError(extractErrorMessage(err, "Failed to create payment"));
1979
2548
  } finally {
1980
2549
  setIsSubmitting(false);
1981
2550
  }
1982
2551
  }, [addFunds, form, onOpenChange, onSuccess]);
1983
2552
  const handleOpenChange = useCallback((open2) => {
1984
- if (!open2) {
2553
+ if (open2) {
2554
+ form.reset({
2555
+ amount: saved.amount,
2556
+ currency: saved.currency
2557
+ });
2558
+ } else {
1985
2559
  setError(null);
1986
- form.reset();
1987
2560
  }
1988
2561
  onOpenChange(open2);
1989
- }, [form, onOpenChange]);
2562
+ }, [form, onOpenChange, saved]);
1990
2563
  return /* @__PURE__ */ jsx(ResponsiveSheet, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs(ResponsiveSheetContent, { className: "sm:max-w-md", children: [
1991
2564
  /* @__PURE__ */ jsxs(ResponsiveSheetHeader, { children: [
1992
2565
  /* @__PURE__ */ jsx(ResponsiveSheetTitle, { children: "Add Funds" }),
@@ -2008,7 +2581,7 @@ function AddFundsSheet({ open, onOpenChange, onSuccess }) {
2008
2581
  type: "number",
2009
2582
  step: "0.01",
2010
2583
  min: "1",
2011
- placeholder: "100.00",
2584
+ placeholder: "100",
2012
2585
  className: "pl-8 text-2xl h-14 font-semibold",
2013
2586
  ...field,
2014
2587
  onChange: (e) => field.onChange(parseFloat(e.target.value) || 0)
@@ -2027,51 +2600,78 @@ function AddFundsSheet({ open, onOpenChange, onSuccess }) {
2027
2600
  render: ({ field }) => /* @__PURE__ */ jsxs(FormItem, { children: [
2028
2601
  /* @__PURE__ */ jsx(FormLabel, { children: "Pay with" }),
2029
2602
  /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(
2030
- Combobox,
2603
+ CurrencyCombobox,
2031
2604
  {
2032
2605
  options: currencyOptions,
2033
2606
  value: field.value,
2034
- onValueChange: field.onChange,
2035
- placeholder: "Select currency...",
2036
- searchPlaceholder: "Search...",
2037
- disabled: isLoadingCurrencies,
2038
- className: "h-14",
2039
- renderOption: (option) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 flex-1", children: [
2040
- /* @__PURE__ */ jsx(TokenIcon, { symbol: option.value, size: 24 }),
2041
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: option.label })
2042
- ] }),
2043
- renderValue: (option) => option && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2044
- /* @__PURE__ */ jsx(TokenIcon, { symbol: option.value, size: 24 }),
2045
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: option.label })
2046
- ] })
2607
+ onChange: field.onChange,
2608
+ disabled: isLoadingCurrencies
2047
2609
  }
2048
2610
  ) }),
2049
2611
  /* @__PURE__ */ jsx(FormMessage, {})
2050
2612
  ] })
2051
2613
  }
2052
2614
  ),
2053
- cryptoAmount !== null && selectedCurrency && /* @__PURE__ */ jsxs("div", { className: "bg-muted rounded-xl p-4 space-y-2", children: [
2054
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2055
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "You will send" }),
2056
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2057
- /* @__PURE__ */ jsx(TokenIcon, { symbol: selectedCurrency.value, size: 20 }),
2058
- /* @__PURE__ */ jsxs("span", { className: "font-mono font-semibold", children: [
2059
- cryptoAmount.toFixed(8),
2060
- " ",
2061
- selectedCurrency.value
2062
- ] })
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)
2063
2624
  ] })
2064
2625
  ] }),
2065
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm text-muted-foreground", children: [
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: [
2066
2638
  /* @__PURE__ */ jsx("span", { children: "Rate" }),
2067
2639
  /* @__PURE__ */ jsxs("span", { children: [
2068
2640
  "1 ",
2069
- selectedCurrency.value,
2641
+ displayData.token,
2070
2642
  " = $",
2071
- selectedCurrency.rate.toFixed(2)
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
+ ] })
2072
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
2073
2673
  ] })
2074
- ] }),
2674
+ ] }) : /* @__PURE__ */ jsx("div", { className: "text-center text-sm text-muted-foreground py-2", children: "Enter amount to see conversion" }) }),
2075
2675
  error && /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: /* @__PURE__ */ jsx(AlertDescription, { children: error }) }),
2076
2676
  /* @__PURE__ */ jsx(
2077
2677
  Button,
@@ -2079,7 +2679,7 @@ function AddFundsSheet({ open, onOpenChange, onSuccess }) {
2079
2679
  type: "submit",
2080
2680
  size: "lg",
2081
2681
  className: "w-full h-14 text-lg rounded-xl",
2082
- disabled: isSubmitting || currencyOptions.length === 0,
2682
+ disabled: isSubmitting || currencyOptions.length === 0 || isLoadingEstimate || displayData?.belowMinimum,
2083
2683
  children: isSubmitting ? /* @__PURE__ */ jsxs(Fragment, { children: [
2084
2684
  /* @__PURE__ */ jsx(RefreshCw, { className: "h-5 w-5 mr-2 animate-spin" }),
2085
2685
  "Creating..."
@@ -2090,54 +2690,54 @@ function AddFundsSheet({ open, onOpenChange, onSuccess }) {
2090
2690
  ] }) });
2091
2691
  }
2092
2692
  var WithdrawSchema = z.object({
2093
- amount: z.number().min(10, "Minimum $10.00"),
2693
+ amount: z.number().min(10, "Minimum $10"),
2094
2694
  currency: z.string().min(1, "Select a currency"),
2095
2695
  wallet_address: z.string().min(26, "Invalid wallet address")
2096
2696
  });
2097
- var SERVICE_FEE_PERCENT = 0.01;
2098
- var NETWORK_FEE_USD = 1;
2697
+ var STORAGE_KEY2 = "payments:withdraw";
2099
2698
  function WithdrawSheet({ open, onOpenChange, onSuccess }) {
2100
2699
  const { currencies, isLoadingCurrencies, withdraw, balanceAmount } = useWallet();
2101
2700
  const [isSubmitting, setIsSubmitting] = useState(false);
2102
2701
  const [error, setError] = useState(null);
2702
+ const [saved, setSaved] = useLocalStorage(STORAGE_KEY2, {
2703
+ currency: "",
2704
+ wallet: ""
2705
+ });
2103
2706
  const form = useForm({
2104
2707
  resolver: zodResolver(WithdrawSchema),
2105
2708
  defaultValues: {
2106
2709
  amount: 10,
2107
- currency: "",
2108
- wallet_address: ""
2710
+ currency: saved.currency,
2711
+ wallet_address: saved.wallet
2109
2712
  }
2110
2713
  });
2111
- const currencyOptions = useMemo(() => {
2112
- return currencies.map((c) => ({
2113
- value: c.code,
2114
- label: c.network ? `${c.code} (${c.network})` : c.code,
2115
- rate: c.rate,
2116
- network: c.network
2117
- }));
2118
- }, [currencies]);
2119
- useMemo(() => {
2120
- if (currencyOptions.length > 0 && !form.getValues("currency")) {
2121
- const usdt = currencyOptions.find((c) => c.value.includes("USDT"));
2122
- form.setValue("currency", usdt?.value || currencyOptions[0].value);
2123
- }
2124
- }, [currencyOptions, form]);
2125
- const selectedCurrency = currencyOptions.find((c) => c.value === form.watch("currency"));
2126
- const amount = form.watch("amount") || 0;
2127
- const feeBreakdown = useMemo(() => {
2128
- const serviceFee = amount * SERVICE_FEE_PERCENT;
2129
- const networkFee = NETWORK_FEE_USD;
2130
- const totalFee = serviceFee + networkFee;
2131
- const finalAmount = Math.max(0, amount - totalFee);
2132
- const cryptoAmount = selectedCurrency?.rate ? finalAmount / selectedCurrency.rate : null;
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;
2133
2736
  return {
2134
- serviceFee,
2135
- networkFee,
2136
- totalFee,
2137
- finalAmount,
2138
- cryptoAmount
2737
+ token: selectedCurrency.token,
2738
+ cryptoAmount: formatCryptoAmount(estimate.estimatedAmount, estimate.isStablecoin)
2139
2739
  };
2140
- }, [amount, selectedCurrency]);
2740
+ }, [selectedCurrency, estimate]);
2141
2741
  const insufficientBalance = amount > balanceAmount;
2142
2742
  const handleSubmit = useCallback(async (data) => {
2143
2743
  try {
@@ -2152,19 +2752,23 @@ function WithdrawSheet({ open, onOpenChange, onSuccess }) {
2152
2752
  onOpenChange(false);
2153
2753
  onSuccess?.(result);
2154
2754
  } catch (err) {
2155
- const message = err?.response?.data?.error || err?.response?.data?.message || err?.response?.data?.detail || err?.message || "Failed to create withdrawal request";
2156
- setError(message);
2755
+ setError(extractErrorMessage(err, "Failed to create withdrawal request"));
2157
2756
  } finally {
2158
2757
  setIsSubmitting(false);
2159
2758
  }
2160
2759
  }, [withdraw, form, onOpenChange, onSuccess]);
2161
2760
  const handleOpenChange = useCallback((open2) => {
2162
- if (!open2) {
2761
+ if (open2) {
2762
+ form.reset({
2763
+ amount: 10,
2764
+ currency: saved.currency,
2765
+ wallet_address: saved.wallet
2766
+ });
2767
+ } else {
2163
2768
  setError(null);
2164
- form.reset();
2165
2769
  }
2166
2770
  onOpenChange(open2);
2167
- }, [form, onOpenChange]);
2771
+ }, [form, onOpenChange, saved]);
2168
2772
  return /* @__PURE__ */ jsx(ResponsiveSheet, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs(ResponsiveSheetContent, { className: "sm:max-w-md", children: [
2169
2773
  /* @__PURE__ */ jsxs(ResponsiveSheetHeader, { children: [
2170
2774
  /* @__PURE__ */ jsx(ResponsiveSheetTitle, { children: "Withdraw" }),
@@ -2186,7 +2790,7 @@ function WithdrawSheet({ open, onOpenChange, onSuccess }) {
2186
2790
  type: "number",
2187
2791
  step: "0.01",
2188
2792
  min: "10",
2189
- placeholder: "10.00",
2793
+ placeholder: "10",
2190
2794
  className: "pl-8 text-2xl h-14 font-semibold",
2191
2795
  ...field,
2192
2796
  onChange: (e) => field.onChange(parseFloat(e.target.value) || 0)
@@ -2196,7 +2800,7 @@ function WithdrawSheet({ open, onOpenChange, onSuccess }) {
2196
2800
  /* @__PURE__ */ jsx(FormMessage, {}),
2197
2801
  insufficientBalance && /* @__PURE__ */ jsxs("p", { className: "text-sm text-destructive mt-1", children: [
2198
2802
  "Insufficient balance (Available: $",
2199
- balanceAmount.toFixed(2),
2803
+ formatUsdAmount(balanceAmount),
2200
2804
  ")"
2201
2805
  ] })
2202
2806
  ] })
@@ -2210,23 +2814,12 @@ function WithdrawSheet({ open, onOpenChange, onSuccess }) {
2210
2814
  render: ({ field }) => /* @__PURE__ */ jsxs(FormItem, { children: [
2211
2815
  /* @__PURE__ */ jsx(FormLabel, { children: "Withdraw as" }),
2212
2816
  /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(
2213
- Combobox,
2817
+ CurrencyCombobox,
2214
2818
  {
2215
2819
  options: currencyOptions,
2216
2820
  value: field.value,
2217
- onValueChange: field.onChange,
2218
- placeholder: "Select currency...",
2219
- searchPlaceholder: "Search...",
2220
- disabled: isLoadingCurrencies,
2221
- className: "h-14",
2222
- renderOption: (option) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 flex-1", children: [
2223
- /* @__PURE__ */ jsx(TokenIcon, { symbol: option.value, size: 24 }),
2224
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: option.label })
2225
- ] }),
2226
- renderValue: (option) => option && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2227
- /* @__PURE__ */ jsx(TokenIcon, { symbol: option.value, size: 24 }),
2228
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: option.label })
2229
- ] })
2821
+ onChange: field.onChange,
2822
+ disabled: isLoadingCurrencies
2230
2823
  }
2231
2824
  ) }),
2232
2825
  /* @__PURE__ */ jsx(FormMessage, {})
@@ -2257,36 +2850,49 @@ function WithdrawSheet({ open, onOpenChange, onSuccess }) {
2257
2850
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Amount" }),
2258
2851
  /* @__PURE__ */ jsxs("span", { children: [
2259
2852
  "$",
2260
- amount.toFixed(2)
2853
+ formatUsdAmount(amount)
2261
2854
  ] })
2262
2855
  ] }),
2263
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
2264
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Service fee (1%)" }),
2265
- /* @__PURE__ */ jsxs("span", { className: "text-destructive", children: [
2266
- "-$",
2267
- feeBreakdown.serviceFee.toFixed(2)
2268
- ] })
2269
- ] }),
2270
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
2271
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Network fee" }),
2272
- /* @__PURE__ */ jsxs("span", { className: "text-destructive", children: [
2273
- "-$",
2274
- feeBreakdown.networkFee.toFixed(2)
2275
- ] })
2276
- ] }),
2277
- /* @__PURE__ */ jsx("div", { className: "border-t pt-2 mt-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2278
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: "You will receive" }),
2279
- /* @__PURE__ */ jsxs("div", { className: "text-right", children: [
2280
- /* @__PURE__ */ jsxs("div", { className: "font-semibold", children: [
2281
- "$",
2282
- feeBreakdown.finalAmount.toFixed(2)
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
+ "%)"
2283
2865
  ] }),
2284
- feeBreakdown.cryptoAmount !== null && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
2285
- /* @__PURE__ */ jsx(TokenIcon, { symbol: selectedCurrency.value, size: 16 }),
2286
- /* @__PURE__ */ jsx("span", { className: "font-mono", children: feeBreakdown.cryptoAmount.toFixed(8) })
2866
+ /* @__PURE__ */ jsxs("span", { className: "text-destructive", children: [
2867
+ "-$",
2868
+ formatUsdAmount(estimate.serviceFeeUsd)
2287
2869
  ] })
2288
- ] })
2289
- ] }) })
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
2290
2896
  ] }),
2291
2897
  /* @__PURE__ */ jsxs(Alert, { children: [
2292
2898
  /* @__PURE__ */ jsx(AlertCircle, { className: "h-4 w-4" }),
@@ -2299,7 +2905,7 @@ function WithdrawSheet({ open, onOpenChange, onSuccess }) {
2299
2905
  type: "submit",
2300
2906
  size: "lg",
2301
2907
  className: "w-full h-14 text-lg rounded-xl",
2302
- disabled: isSubmitting || currencyOptions.length === 0 || insufficientBalance || feeBreakdown.finalAmount <= 0,
2908
+ disabled: isSubmitting || currencyOptions.length === 0 || insufficientBalance || !estimate || estimate.amountToReceive <= 0 || isLoadingEstimate,
2303
2909
  children: isSubmitting ? /* @__PURE__ */ jsxs(Fragment, { children: [
2304
2910
  /* @__PURE__ */ jsx(RefreshCw, { className: "h-5 w-5 mr-2 animate-spin" }),
2305
2911
  "Submitting..."
@@ -2310,6 +2916,229 @@ function WithdrawSheet({ open, onOpenChange, onSuccess }) {
2310
2916
  ] }) });
2311
2917
  }
2312
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,
3060
+ " ",
3061
+ withdrawal.currency_token
3062
+ ] })
3063
+ ] })
3064
+ ] }),
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" })
3070
+ ] })
3071
+ ] }),
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" })
3077
+ ] })
3078
+ ] }),
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
+ )
3137
+ ] })
3138
+ ] })
3139
+ ] }) });
3140
+ }
3141
+ var statusConfig3 = {
2313
3142
  pending: {
2314
3143
  icon: Clock,
2315
3144
  color: "text-yellow-500",
@@ -2342,10 +3171,10 @@ var statusConfig2 = {
2342
3171
  label: "Expired"
2343
3172
  }
2344
3173
  };
2345
- function PaymentSheet({ paymentId, open, onOpenChange }) {
3174
+ function PaymentSheet({ paymentId, open, onOpenChange, onCreateNew }) {
2346
3175
  const { getPaymentDetails } = useWallet();
2347
3176
  const [timeLeft, setTimeLeft] = useState("");
2348
- const { data: payment, isLoading, error, mutate } = useSWR2(
3177
+ const { data: payment, isLoading, error, mutate } = useSWR(
2349
3178
  open && paymentId ? ["payment-details", paymentId] : null,
2350
3179
  () => getPaymentDetails(paymentId),
2351
3180
  { refreshInterval: 1e4 }
@@ -2353,14 +3182,14 @@ function PaymentSheet({ paymentId, open, onOpenChange }) {
2353
3182
  useEffect(() => {
2354
3183
  if (!payment?.expires_at) return;
2355
3184
  const updateTimeLeft = () => {
2356
- const now = moment2();
2357
- const expires = moment2.utc(payment.expires_at);
3185
+ const now = moment3();
3186
+ const expires = moment3.utc(payment.expires_at);
2358
3187
  const diff = expires.diff(now);
2359
3188
  if (diff <= 0) {
2360
3189
  setTimeLeft("Expired");
2361
3190
  return;
2362
3191
  }
2363
- const duration = moment2.duration(diff);
3192
+ const duration = moment3.duration(diff);
2364
3193
  const hours = Math.floor(duration.asHours());
2365
3194
  const minutes = duration.minutes();
2366
3195
  const seconds = duration.seconds();
@@ -2370,22 +3199,59 @@ function PaymentSheet({ paymentId, open, onOpenChange }) {
2370
3199
  const interval = setInterval(updateTimeLeft, 1e3);
2371
3200
  return () => clearInterval(interval);
2372
3201
  }, [payment?.expires_at]);
2373
- const status = useMemo(() => {
3202
+ const displayData = useMemo(() => {
2374
3203
  const s = payment?.status?.toLowerCase();
2375
- if (s === "completed" || s === "success" || s === "finished") return "completed";
2376
- if (s === "confirming" || s === "partially_paid") return "confirming";
2377
- if (s === "expired") return "expired";
2378
- if (s === "failed" || s === "error" || s === "cancelled") return "failed";
2379
- return "pending";
2380
- }, [payment?.status]);
2381
- const config = statusConfig2[status];
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;
2382
3250
  const StatusIcon = config.icon;
2383
- const qrCodeUrl = payment?.pay_address ? `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(payment.pay_address)}` : null;
2384
- const isPending = status === "pending";
2385
3251
  return /* @__PURE__ */ jsx(ResponsiveSheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs(ResponsiveSheetContent, { className: "sm:max-w-lg", children: [
2386
3252
  /* @__PURE__ */ jsxs(ResponsiveSheetHeader, { children: [
2387
3253
  /* @__PURE__ */ jsx(ResponsiveSheetTitle, { children: "Payment Details" }),
2388
- /* @__PURE__ */ jsx(ResponsiveSheetDescription, { children: isPending ? "Send cryptocurrency to complete payment" : "Payment information" })
3254
+ /* @__PURE__ */ jsx(ResponsiveSheetDescription, { children: description })
2389
3255
  ] }),
2390
3256
  /* @__PURE__ */ jsxs("div", { className: "p-4 sm:p-0 sm:mt-4 overflow-y-auto max-h-[70vh]", children: [
2391
3257
  isLoading && /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
@@ -2399,14 +3265,11 @@ function PaymentSheet({ paymentId, open, onOpenChange }) {
2399
3265
  /* @__PURE__ */ jsx(Button, { onClick: () => mutate(), children: "Try Again" })
2400
3266
  ] }),
2401
3267
  payment && !isLoading && /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
2402
- /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-3 p-4 rounded-xl", config.bg), children: [
2403
- /* @__PURE__ */ jsx(StatusIcon, { className: cn("h-6 w-6", config.color, config.animate && "animate-spin") }),
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") }),
2404
3270
  /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
2405
- /* @__PURE__ */ jsx("div", { className: "font-semibold", children: config.label }),
2406
- isPending && timeLeft && /* @__PURE__ */ jsxs("div", { className: "text-sm text-muted-foreground", children: [
2407
- "Expires in ",
2408
- timeLeft
2409
- ] })
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 })
2410
3273
  ] })
2411
3274
  ] }),
2412
3275
  /* @__PURE__ */ jsxs("div", { className: "bg-muted rounded-xl p-4 space-y-3", children: [
@@ -2423,30 +3286,38 @@ function PaymentSheet({ paymentId, open, onOpenChange }) {
2423
3286
  ] }),
2424
3287
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
2425
3288
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Equivalent" }),
2426
- /* @__PURE__ */ jsxs("span", { className: "font-semibold", children: [
2427
- "$",
2428
- parseFloat(payment.amount_usd).toFixed(2),
2429
- " USD"
2430
- ] })
3289
+ /* @__PURE__ */ jsx("span", { className: "font-semibold", children: amountUsd })
2431
3290
  ] }),
2432
3291
  payment.currency_network && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm pt-2 border-t", children: [
2433
3292
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Network" }),
2434
3293
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: payment.currency_network })
2435
3294
  ] })
2436
3295
  ] }),
2437
- qrCodeUrl && isPending && /* @__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" }) }),
2438
- payment.pay_address && isPending && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
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: [
2439
3298
  /* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Payment Address" }),
2440
3299
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2441
3300
  /* @__PURE__ */ jsx("div", { className: "flex-1 p-3 bg-muted rounded-xl font-mono text-sm break-all", children: payment.pay_address }),
2442
3301
  /* @__PURE__ */ jsx(CopyButton, { value: payment.pay_address, variant: "outline", className: "shrink-0" })
2443
3302
  ] })
2444
3303
  ] }),
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
+ ),
2445
3316
  payment.transaction_hash && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2446
3317
  /* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Transaction Hash" }),
2447
3318
  /* @__PURE__ */ jsx("div", { className: "p-3 bg-muted rounded-xl font-mono text-sm break-all", children: payment.transaction_hash })
2448
3319
  ] }),
2449
- payment.payment_url && isPending && /* @__PURE__ */ jsxs(
3320
+ payment.payment_url && canPay && /* @__PURE__ */ jsxs(
2450
3321
  Button,
2451
3322
  {
2452
3323
  variant: "outline",
@@ -2469,7 +3340,7 @@ function PaymentSheet({ paymentId, open, onOpenChange }) {
2469
3340
  ] }),
2470
3341
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
2471
3342
  /* @__PURE__ */ jsx("span", { children: "Created" }),
2472
- /* @__PURE__ */ jsx("span", { children: moment2.utc(payment.created_at).local().format("MMM D, YYYY HH:mm") })
3343
+ /* @__PURE__ */ jsx("span", { children: createdAt })
2473
3344
  ] })
2474
3345
  ] }),
2475
3346
  /* @__PURE__ */ jsxs(
@@ -2488,54 +3359,85 @@ function PaymentSheet({ paymentId, open, onOpenChange }) {
2488
3359
  ] })
2489
3360
  ] }) });
2490
3361
  }
2491
- var ResponsiveSheetContext = React2.createContext({ isMobile: false });
2492
- function ResponsiveSheet4({ open, onOpenChange, children }) {
2493
- const isMobile = useIsMobile();
2494
- if (isMobile) {
2495
- return /* @__PURE__ */ jsx(ResponsiveSheetContext.Provider, { value: { isMobile: true }, children: /* @__PURE__ */ jsx(Drawer, { open, onOpenChange, children }) });
2496
- }
2497
- return /* @__PURE__ */ jsx(ResponsiveSheetContext.Provider, { value: { isMobile: false }, children: /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children }) });
2498
- }
2499
- function ResponsiveSheetContent4({ children, className }) {
2500
- const { isMobile } = React2.useContext(ResponsiveSheetContext);
2501
- if (isMobile) {
2502
- return /* @__PURE__ */ jsx(DrawerContent, { className, children });
2503
- }
2504
- return /* @__PURE__ */ jsx(DialogContent, { className, children });
2505
- }
2506
- function ResponsiveSheetHeader4({ children, className }) {
2507
- const { isMobile } = React2.useContext(ResponsiveSheetContext);
2508
- if (isMobile) {
2509
- return /* @__PURE__ */ jsx(DrawerHeader, { className, children });
2510
- }
2511
- return /* @__PURE__ */ jsx(DialogHeader, { className, children });
2512
- }
2513
- function ResponsiveSheetTitle4({ children, className }) {
2514
- const { isMobile } = React2.useContext(ResponsiveSheetContext);
2515
- if (isMobile) {
2516
- return /* @__PURE__ */ jsx(DrawerTitle, { className, children });
2517
- }
2518
- return /* @__PURE__ */ jsx(DialogTitle, { className, children });
2519
- }
2520
- function ResponsiveSheetDescription4({ children, className }) {
2521
- const { isMobile } = React2.useContext(ResponsiveSheetContext);
2522
- if (isMobile) {
2523
- return /* @__PURE__ */ jsx(DrawerDescription, { className, children });
2524
- }
2525
- return /* @__PURE__ */ jsx(DialogDescription, { className, children });
2526
- }
2527
- function ResponsiveSheetFooter({ children, className }) {
2528
- const { isMobile } = React2.useContext(ResponsiveSheetContext);
2529
- if (isMobile) {
2530
- return /* @__PURE__ */ jsx(DrawerFooter, { className, children });
2531
- }
2532
- return /* @__PURE__ */ jsx(DialogFooter, { className, children });
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);
3376
+ }
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
+ )
3431
+ ] });
3432
+ };
3433
+ function WalletPage() {
3434
+ return /* @__PURE__ */ jsx(WalletProvider, { children: /* @__PURE__ */ jsx(WalletContent, {}) });
2533
3435
  }
2534
3436
 
2535
3437
  // package.json
2536
3438
  var package_default = {
2537
3439
  name: "@djangocfg/ext-payments",
2538
- version: "1.0.17",
3440
+ version: "1.0.19",
2539
3441
  description: "Payments system extension for DjangoCFG",
2540
3442
  keywords: [
2541
3443
  "django",
@@ -2675,4 +3577,4 @@ export default function CryptoCheckout() {
2675
3577
  ]
2676
3578
  });
2677
3579
 
2678
- 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, PaymentDetailSchema, PaymentListSchema, PaymentSheet, REFRESH_TOKEN_KEY, ResponsiveSheet4 as ResponsiveSheet, ResponsiveSheetContent4 as ResponsiveSheetContent, ResponsiveSheetDescription4 as ResponsiveSheetDescription, ResponsiveSheetFooter, ResponsiveSheetHeader4 as ResponsiveSheetHeader, ResponsiveSheetTitle4 as ResponsiveSheetTitle, schemas_exports as Schemas, TOKEN_KEY, TransactionSchema, WithdrawSheet, WithdrawalCreateRequestSchema, WithdrawalDetailSchema, WithdrawalListSchema, apiPayments, clearAPITokens, configureAPI, createPaymentsPaymentsConfirmCreate, createPaymentsPaymentsCreateCreate, createPaymentsWithdrawalsCancelCreate, createPaymentsWithdrawalsCreateCreate, dispatchValidationError, extensionConfig, formatZodError, getAPIInstance, getPaymentsBalanceRetrieve, getPaymentsCurrenciesList, getPaymentsPaymentsList, getPaymentsPaymentsRetrieve, getPaymentsPaymentsStatusRetrieve, getPaymentsTransactionsList, getPaymentsWithdrawalsList, getPaymentsWithdrawalsRetrieve, isAPIConfigured, onValidationError, 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 };