@djangocfg/ext-payments 1.0.4 → 1.0.7

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 (42) hide show
  1. package/dist/config.cjs +3 -2
  2. package/dist/config.js +3 -2
  3. package/dist/hooks.cjs +559 -543
  4. package/dist/hooks.js +558 -543
  5. package/dist/index.cjs +559 -543
  6. package/dist/index.js +558 -543
  7. package/package.json +9 -8
  8. package/src/api/generated/ext_payments/CLAUDE.md +76 -0
  9. package/src/api/generated/ext_payments/_utils/fetchers/ext_payments__payments.ts +1 -0
  10. package/src/api/generated/ext_payments/_utils/fetchers/index.ts +1 -0
  11. package/src/api/generated/ext_payments/_utils/hooks/ext_payments__payments.ts +1 -0
  12. package/src/api/generated/ext_payments/_utils/hooks/index.ts +1 -0
  13. package/src/api/generated/ext_payments/_utils/schemas/index.ts +1 -0
  14. package/src/api/generated/ext_payments/api-instance.ts +1 -0
  15. package/src/api/generated/ext_payments/enums.ts +1 -0
  16. package/src/api/generated/ext_payments/errors.ts +1 -0
  17. package/src/api/generated/ext_payments/ext_payments__payments/index.ts +1 -0
  18. package/src/api/generated/ext_payments/ext_payments__payments/models.ts +1 -0
  19. package/src/api/generated/ext_payments/http.ts +1 -0
  20. package/src/api/generated/ext_payments/index.ts +1 -0
  21. package/src/api/generated/ext_payments/logger.ts +1 -0
  22. package/src/api/generated/ext_payments/retry.ts +1 -0
  23. package/src/api/generated/ext_payments/storage.ts +1 -0
  24. package/src/api/generated/ext_payments/validation-events.ts +1 -0
  25. package/src/api/index.ts +2 -1
  26. package/src/config.ts +1 -0
  27. package/src/contexts/BalancesContext.tsx +2 -1
  28. package/src/contexts/CurrenciesContext.tsx +2 -1
  29. package/src/contexts/OverviewContext.tsx +5 -5
  30. package/src/contexts/PaymentsContext.tsx +6 -5
  31. package/src/contexts/PaymentsExtensionProvider.tsx +3 -2
  32. package/src/contexts/RootPaymentsContext.tsx +2 -1
  33. package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +5 -7
  34. package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +10 -27
  35. package/src/layouts/PaymentsLayout/components/PaymentDetailsDialog.tsx +15 -18
  36. package/src/layouts/PaymentsLayout/views/overview/components/BalanceCard.tsx +6 -13
  37. package/src/layouts/PaymentsLayout/views/overview/components/RecentPayments.tsx +8 -11
  38. package/src/layouts/PaymentsLayout/views/overview/index.tsx +1 -0
  39. package/src/layouts/PaymentsLayout/views/payments/components/PaymentsList.tsx +43 -42
  40. package/src/layouts/PaymentsLayout/views/payments/index.tsx +1 -0
  41. package/src/layouts/PaymentsLayout/views/transactions/components/TransactionsList.tsx +71 -84
  42. package/src/layouts/PaymentsLayout/views/transactions/index.tsx +1 -0
package/dist/hooks.cjs CHANGED
@@ -4,19 +4,21 @@ var consola = require('consola');
4
4
  var pRetry = require('p-retry');
5
5
  var zod = require('zod');
6
6
  var api = require('@djangocfg/ext-base/api');
7
+ var lucideReact = require('lucide-react');
8
+ var uiNextjs = require('@djangocfg/ui-nextjs');
7
9
  var react = require('react');
8
10
  var useSWR = require('swr');
9
11
  var jsxRuntime = require('react/jsx-runtime');
10
- var uiNextjs = require('@djangocfg/ui-nextjs');
11
- var lucideReact = require('lucide-react');
12
12
  var reactHookForm = require('react-hook-form');
13
13
  var zod$1 = require('@hookform/resolvers/zod');
14
+ var moment = require('moment');
14
15
  var extBase = require('@djangocfg/ext-base');
15
16
 
16
17
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
17
18
 
18
19
  var pRetry__default = /*#__PURE__*/_interopDefault(pRetry);
19
20
  var useSWR__default = /*#__PURE__*/_interopDefault(useSWR);
21
+ var moment__default = /*#__PURE__*/_interopDefault(moment);
20
22
 
21
23
  var __defProp = Object.defineProperty;
22
24
  var __export = (target, all) => {
@@ -1646,6 +1648,11 @@ function useRootPaymentsContext() {
1646
1648
  }
1647
1649
  return context;
1648
1650
  }
1651
+ var isDevelopment = process.env.NODE_ENV === "development";
1652
+ var logger = consola.createConsola({
1653
+ level: isDevelopment ? 4 : 1
1654
+ }).withTag("ext-payments");
1655
+ var paymentsLogger = logger;
1649
1656
 
1650
1657
  // src/layouts/PaymentsLayout/events.ts
1651
1658
  var PAYMENT_EVENTS = {
@@ -1666,156 +1673,526 @@ var openPaymentDetailsDialog = (id) => {
1666
1673
  var closePaymentsDialog = () => {
1667
1674
  window.dispatchEvent(new Event(PAYMENT_EVENTS.CLOSE_DIALOG));
1668
1675
  };
1669
- var BalanceCard = () => {
1670
- const {
1671
- balance,
1672
- isLoadingBalance,
1673
- refreshBalance
1674
- } = useOverviewContext();
1675
- const formatCurrency = (amount) => {
1676
- if (amount === null || amount === void 0) return "$0.00";
1677
- return new Intl.NumberFormat("en-US", {
1678
- style: "currency",
1679
- currency: "USD",
1680
- minimumFractionDigits: 2
1681
- }).format(amount);
1676
+ var PaymentCreateSchema = zod.z.object({
1677
+ amount_usd: zod.z.number().min(0.01, "Amount must be at least $0.01"),
1678
+ currency_code: zod.z.string().min(1, "Please select a currency")
1679
+ });
1680
+ var CreatePaymentDialog = () => {
1681
+ const [open, setOpen] = react.useState(false);
1682
+ const [isSubmitting, setIsSubmitting] = react.useState(false);
1683
+ const { createPayment } = usePaymentsContext();
1684
+ const { currencies, isLoadingCurrencies } = useRootPaymentsContext();
1685
+ const form = reactHookForm.useForm({
1686
+ resolver: zod$1.zodResolver(PaymentCreateSchema),
1687
+ defaultValues: {
1688
+ amount_usd: 10,
1689
+ currency_code: "USDT"
1690
+ }
1691
+ });
1692
+ const currenciesList = react.useMemo(() => {
1693
+ const data = currencies?.currencies || currencies?.results || currencies || [];
1694
+ return Array.isArray(data) ? data : [];
1695
+ }, [currencies]);
1696
+ const currencyOptions = react.useMemo(() => {
1697
+ return currenciesList.filter((curr) => curr.is_enabled !== false).map((curr) => ({
1698
+ code: curr.code || curr.currency_code || curr.symbol,
1699
+ name: curr.name || curr.code || curr.currency_code,
1700
+ usd_rate: curr.usd_rate || curr.rate || 1,
1701
+ network: curr.network || null
1702
+ }));
1703
+ }, [currenciesList]);
1704
+ const calculateCryptoAmount = react.useMemo(() => {
1705
+ const amountUsd = form.watch("amount_usd");
1706
+ const currencyCode = form.watch("currency_code");
1707
+ const currency = currencyOptions.find((c) => c.code === currencyCode);
1708
+ if (!currency || !currency.usd_rate || !amountUsd) {
1709
+ return null;
1710
+ }
1711
+ const cryptoAmount = amountUsd / currency.usd_rate;
1712
+ return {
1713
+ amount: cryptoAmount,
1714
+ currency: currency.code,
1715
+ rate: currency.usd_rate,
1716
+ network: currency.network
1717
+ };
1718
+ }, [form.watch("amount_usd"), form.watch("currency_code"), currencyOptions]);
1719
+ react.useEffect(() => {
1720
+ const handleOpen = () => setOpen(true);
1721
+ const handleClose2 = () => setOpen(false);
1722
+ window.addEventListener(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG, handleOpen);
1723
+ window.addEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
1724
+ return () => {
1725
+ window.removeEventListener(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG, handleOpen);
1726
+ window.removeEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
1727
+ };
1728
+ }, []);
1729
+ const handleClose = () => {
1730
+ setOpen(false);
1731
+ form.reset();
1682
1732
  };
1683
- const formatDate = (dateStr) => {
1684
- if (!dateStr) return "No transactions yet";
1733
+ react.useEffect(() => {
1734
+ if (currencyOptions.length > 0 && !form.getValues("currency_code")) {
1735
+ form.setValue("currency_code", currencyOptions[0].code);
1736
+ }
1737
+ }, [currencyOptions, form]);
1738
+ const handleSubmit = async (data) => {
1685
1739
  try {
1686
- return new Date(dateStr).toLocaleDateString("en-US", {
1687
- year: "numeric",
1688
- month: "short",
1689
- day: "numeric"
1690
- });
1691
- } catch {
1692
- return "Invalid date";
1740
+ setIsSubmitting(true);
1741
+ const result = await createPayment();
1742
+ handleClose();
1743
+ closePaymentsDialog();
1744
+ const paymentData = result;
1745
+ const paymentId = paymentData?.payment?.id || paymentData?.id;
1746
+ if (paymentId) {
1747
+ openPaymentDetailsDialog(String(paymentId));
1748
+ }
1749
+ } catch (error) {
1750
+ paymentsLogger.error("Failed to create payment:", error);
1751
+ } finally {
1752
+ setIsSubmitting(false);
1693
1753
  }
1694
1754
  };
1695
- if (isLoadingBalance) {
1696
- return /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.Card, { children: [
1697
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.CardTitle, { className: "flex items-center justify-between", children: [
1698
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1699
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { className: "h-5 w-5" }),
1700
- "Account Balance"
1755
+ return /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogContent, { className: "sm:max-w-md", children: [
1756
+ /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogHeader, { children: [
1757
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogTitle, { children: "Create Payment" }),
1758
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogDescription, { children: "Create a new payment to add funds to your account." })
1759
+ ] }),
1760
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Form, { ...form, children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: form.handleSubmit(handleSubmit), className: "space-y-4", children: [
1761
+ /* @__PURE__ */ jsxRuntime.jsx(
1762
+ uiNextjs.FormField,
1763
+ {
1764
+ control: form.control,
1765
+ name: "amount_usd",
1766
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.FormItem, { children: [
1767
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormLabel, { children: "Amount (USD)" }),
1768
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormControl, { children: /* @__PURE__ */ jsxRuntime.jsx(
1769
+ uiNextjs.Input,
1770
+ {
1771
+ type: "number",
1772
+ step: "0.01",
1773
+ min: "0.01",
1774
+ placeholder: "10.00",
1775
+ ...field,
1776
+ onChange: (e) => field.onChange(parseFloat(e.target.value) || 0)
1777
+ }
1778
+ ) }),
1779
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormDescription, { children: "The amount you want to pay in USD." }),
1780
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormMessage, {})
1781
+ ] })
1782
+ }
1783
+ ),
1784
+ /* @__PURE__ */ jsxRuntime.jsx(
1785
+ uiNextjs.FormField,
1786
+ {
1787
+ control: form.control,
1788
+ name: "currency_code",
1789
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.FormItem, { children: [
1790
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormLabel, { children: "Currency" }),
1791
+ /* @__PURE__ */ jsxRuntime.jsxs(
1792
+ uiNextjs.Select,
1793
+ {
1794
+ onValueChange: field.onChange,
1795
+ defaultValue: field.value,
1796
+ disabled: isLoadingCurrencies,
1797
+ children: [
1798
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormControl, { children: /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.SelectTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.SelectValue, { placeholder: "Select currency..." }) }) }),
1799
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.SelectContent, { children: currencyOptions.map((curr) => /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.SelectItem, { value: curr.code, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1800
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TokenIcon, { symbol: curr.code, size: 16 }),
1801
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: curr.code }),
1802
+ curr.network && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
1803
+ "(",
1804
+ curr.network,
1805
+ ")"
1806
+ ] })
1807
+ ] }) }, curr.code)) })
1808
+ ]
1809
+ }
1810
+ ),
1811
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormDescription, { children: "The cryptocurrency to use for payment." }),
1812
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormMessage, {})
1813
+ ] })
1814
+ }
1815
+ ),
1816
+ calculateCryptoAmount && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-sm bg-muted p-4 space-y-3", children: [
1817
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
1818
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "You will send" }),
1819
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1820
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TokenIcon, { symbol: calculateCryptoAmount.currency, size: 16 }),
1821
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono font-semibold", children: [
1822
+ calculateCryptoAmount.amount.toFixed(8),
1823
+ " ",
1824
+ calculateCryptoAmount.currency
1825
+ ] })
1826
+ ] })
1701
1827
  ] }),
1702
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Skeleton, { className: "h-8 w-20" })
1703
- ] }) }),
1704
- /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.CardContent, { className: "space-y-4", children: [
1705
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Skeleton, { className: "h-10 w-32" }),
1706
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Skeleton, { className: "h-4 w-48" })
1707
- ] })
1708
- ] });
1709
- }
1710
- const balanceData = balance?.balance || balance;
1711
- const amountUsd = balanceData?.amount_usd ?? 0;
1712
- const totalDeposited = balanceData?.total_deposited ?? 0;
1713
- const totalWithdrawn = balanceData?.total_withdrawn ?? 0;
1714
- const lastTransactionAt = balanceData?.last_transaction_at;
1715
- const isEmpty = amountUsd === 0 && totalDeposited === 0;
1716
- return /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.Card, { children: [
1717
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.CardTitle, { className: "flex items-center justify-between", children: [
1718
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1719
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { className: "h-5 w-5" }),
1720
- "Account Balance"
1721
- ] }),
1722
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1723
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Button, { variant: "ghost", size: "sm", onClick: refreshBalance, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "h-4 w-4" }) }),
1724
- /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.Button, { size: "sm", onClick: () => openCreatePaymentDialog(), children: [
1725
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4 mr-2" }),
1726
- "Add Funds"
1727
- ] })
1728
- ] })
1729
- ] }) }),
1730
- /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.CardContent, { className: "space-y-4", children: [
1731
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1732
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-4xl font-bold", children: formatCurrency(amountUsd) }),
1733
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground mt-1", children: [
1734
- "Available balance \u2022 Last updated ",
1735
- formatDate(lastTransactionAt)
1736
- ] })
1737
- ] }),
1738
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4 pt-4 border-t", children: [
1739
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1740
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Total Deposited" }),
1741
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg font-semibold text-green-600", children: formatCurrency(totalDeposited) })
1828
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
1829
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "You will receive" }),
1830
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-lg font-bold", children: [
1831
+ "$",
1832
+ form.watch("amount_usd")?.toFixed(2),
1833
+ " USD"
1834
+ ] })
1742
1835
  ] }),
1743
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1744
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Total Withdrawn" }),
1745
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg font-semibold text-red-600", children: formatCurrency(totalWithdrawn) })
1746
- ] })
1836
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-xs", children: [
1837
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Rate" }),
1838
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
1839
+ "1 ",
1840
+ calculateCryptoAmount.currency,
1841
+ " = $",
1842
+ calculateCryptoAmount.rate?.toFixed(2)
1843
+ ] })
1844
+ ] }),
1845
+ calculateCryptoAmount.network && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t pt-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
1846
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Network" }),
1847
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: calculateCryptoAmount.network })
1848
+ ] }) })
1747
1849
  ] }),
1748
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1749
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Badge, { variant: !isEmpty ? "default" : "secondary", children: !isEmpty ? "Active" : "New Account" }),
1750
- isEmpty && /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Badge, { variant: "outline", children: "Empty Balance" })
1850
+ /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogFooter, { children: [
1851
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Button, { type: "button", variant: "outline", onClick: handleClose, disabled: isSubmitting, children: "Cancel" }),
1852
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Button, { type: "submit", disabled: isSubmitting || currencyOptions.length === 0, children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1853
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "h-4 w-4 mr-2 animate-spin" }),
1854
+ "Creating..."
1855
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1856
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4 mr-2" }),
1857
+ "Create Payment"
1858
+ ] }) })
1859
+ ] })
1860
+ ] }) })
1861
+ ] }) });
1862
+ };
1863
+ var PaymentDetailsDialog = () => {
1864
+ const [open, setOpen] = react.useState(false);
1865
+ const [paymentId, setPaymentId] = react.useState(null);
1866
+ const [timeLeft, setTimeLeft] = react.useState("");
1867
+ const shouldFetch = open && !!paymentId;
1868
+ const { data: payment, isLoading, error, mutate } = usePaymentsPaymentsRetrieve(
1869
+ shouldFetch ? paymentId : "",
1870
+ apiPayments
1871
+ );
1872
+ react.useEffect(() => {
1873
+ const handleOpen = (event) => {
1874
+ const customEvent = event;
1875
+ setPaymentId(customEvent.detail.id);
1876
+ setOpen(true);
1877
+ };
1878
+ const handleClose2 = () => {
1879
+ setOpen(false);
1880
+ setPaymentId(null);
1881
+ };
1882
+ window.addEventListener(PAYMENT_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG, handleOpen);
1883
+ window.addEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
1884
+ return () => {
1885
+ window.removeEventListener(PAYMENT_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG, handleOpen);
1886
+ window.removeEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
1887
+ };
1888
+ }, []);
1889
+ const handleClose = () => {
1890
+ setOpen(false);
1891
+ setPaymentId(null);
1892
+ };
1893
+ react.useEffect(() => {
1894
+ if (!payment?.expires_at) return;
1895
+ const updateTimeLeft = () => {
1896
+ const now = moment__default.default();
1897
+ const expires = moment__default.default.utc(payment.expires_at);
1898
+ const diff = expires.diff(now);
1899
+ if (diff <= 0) {
1900
+ setTimeLeft("Expired");
1901
+ return;
1902
+ }
1903
+ const duration = moment__default.default.duration(diff);
1904
+ const hours = Math.floor(duration.asHours());
1905
+ const minutes = duration.minutes();
1906
+ const seconds = duration.seconds();
1907
+ setTimeLeft(`${hours}h ${minutes}m ${seconds}s`);
1908
+ };
1909
+ updateTimeLeft();
1910
+ const interval = setInterval(updateTimeLeft, 1e3);
1911
+ return () => clearInterval(interval);
1912
+ }, [payment?.expires_at]);
1913
+ const getStatusInfo = () => {
1914
+ switch (payment?.status?.toLowerCase()) {
1915
+ case "pending":
1916
+ return { icon: lucideReact.Clock, color: "text-yellow-500", bg: "bg-yellow-500/10" };
1917
+ case "completed":
1918
+ case "success":
1919
+ return { icon: lucideReact.CheckCircle2, color: "text-green-500", bg: "bg-green-500/10" };
1920
+ case "failed":
1921
+ case "error":
1922
+ return { icon: lucideReact.XCircle, color: "text-red-500", bg: "bg-red-500/10" };
1923
+ case "expired":
1924
+ return { icon: lucideReact.AlertCircle, color: "text-gray-500", bg: "bg-gray-500/10" };
1925
+ case "confirming":
1926
+ return { icon: lucideReact.RefreshCw, color: "text-blue-500", bg: "bg-blue-500/10" };
1927
+ default:
1928
+ return { icon: lucideReact.Clock, color: "text-gray-500", bg: "bg-gray-500/10" };
1929
+ }
1930
+ };
1931
+ if (!open) return null;
1932
+ if (isLoading) {
1933
+ return /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogContent, { className: "sm:max-w-lg", children: [
1934
+ /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogHeader, { children: [
1935
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogTitle, { children: "Payment Details" }),
1936
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogDescription, { children: "Loading payment information..." })
1937
+ ] }),
1938
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "h-8 w-8 animate-spin text-muted-foreground" }) })
1939
+ ] }) });
1940
+ }
1941
+ if (shouldFetch && !isLoading && (error || !payment)) {
1942
+ return /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogContent, { className: "sm:max-w-lg", children: [
1943
+ /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogHeader, { children: [
1944
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogTitle, { children: "Payment Details" }),
1945
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogDescription, { children: "Failed to load payment information" })
1946
+ ] }),
1947
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12 space-y-4", children: [
1948
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { className: "h-12 w-12 text-destructive" }),
1949
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: error ? `Error: ${error}` : "Payment not found" }),
1950
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Button, { onClick: () => mutate(), children: "Try Again" })
1951
+ ] })
1952
+ ] }) });
1953
+ }
1954
+ const statusInfo = getStatusInfo();
1955
+ const StatusIcon = statusInfo.icon;
1956
+ const qrCodeUrl = payment.pay_address ? `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(payment.pay_address)}` : null;
1957
+ return /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogContent, { className: "sm:max-w-lg", children: [
1958
+ /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogHeader, { children: [
1959
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogTitle, { children: "Payment Details" }),
1960
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogDescription, { children: "Send cryptocurrency to complete your payment" })
1961
+ ] }),
1962
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
1963
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-3 p-4 rounded-sm ${statusInfo.bg}`, children: [
1964
+ /* @__PURE__ */ jsxRuntime.jsx(StatusIcon, { className: `h-5 w-5 ${statusInfo.color}` }),
1965
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
1966
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold capitalize", children: payment.status }),
1967
+ payment.status === "pending" && timeLeft && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-muted-foreground", children: [
1968
+ "Expires in ",
1969
+ timeLeft
1970
+ ] })
1971
+ ] })
1972
+ ] }),
1973
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
1974
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-4 bg-muted rounded-sm", children: [
1975
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Amount to send" }),
1976
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1977
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TokenIcon, { symbol: String(payment.currency_code || "BTC"), size: 20 }),
1978
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono font-bold text-lg", children: [
1979
+ payment.pay_amount || "0.00000000",
1980
+ " ",
1981
+ payment.currency_code
1982
+ ] })
1983
+ ] })
1984
+ ] }),
1985
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4", children: [
1986
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Equivalent to" }),
1987
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold text-lg", children: [
1988
+ "$",
1989
+ parseFloat(payment.amount_usd || "0").toFixed(2),
1990
+ " USD"
1991
+ ] })
1992
+ ] }),
1993
+ payment.internal_payment_id && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4", children: [
1994
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Payment Order #" }),
1995
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-medium", children: payment.internal_payment_id })
1996
+ ] }),
1997
+ payment.currency_network && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4", children: [
1998
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Network" }),
1999
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: payment.currency_network })
2000
+ ] })
2001
+ ] }),
2002
+ qrCodeUrl && payment.status === "pending" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center p-6 bg-white rounded-sm", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: qrCodeUrl, alt: "Payment QR Code", className: "w-48 h-48" }) }),
2003
+ payment.pay_address && payment.status === "pending" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
2004
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Payment Address" }),
2005
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2006
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 p-3 bg-muted rounded-sm font-mono text-sm break-all", children: payment.pay_address }),
2007
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.CopyButton, { value: payment.pay_address, variant: "outline" })
2008
+ ] })
2009
+ ] }),
2010
+ payment.transaction_hash && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
2011
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Transaction Hash" }),
2012
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 bg-muted rounded-sm font-mono text-sm break-all", children: payment.transaction_hash })
2013
+ ] }),
2014
+ payment.payment_url && payment.status === "pending" && /* @__PURE__ */ jsxRuntime.jsxs(
2015
+ uiNextjs.Button,
2016
+ {
2017
+ variant: "outline",
2018
+ className: "w-full",
2019
+ onClick: () => window.open(payment.payment_url, "_blank"),
2020
+ children: [
2021
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-4 w-4 mr-2" }),
2022
+ "Open in Payment Provider"
2023
+ ]
2024
+ }
2025
+ ),
2026
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pt-4 border-t space-y-2 text-xs text-muted-foreground", children: [
2027
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
2028
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Payment ID" }),
2029
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: payment.id })
2030
+ ] }),
2031
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
2032
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Created" }),
2033
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: moment__default.default.utc(payment.created_at).local().format("MMM D, YYYY HH:mm") })
2034
+ ] }),
2035
+ payment.confirmations_count !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
2036
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Confirmations" }),
2037
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: payment.confirmations_count })
2038
+ ] })
2039
+ ] })
2040
+ ] }),
2041
+ /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogFooter, { children: [
2042
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Button, { variant: "outline", onClick: handleClose, children: "Close" }),
2043
+ /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.Button, { onClick: () => mutate(), variant: "ghost", size: "sm", children: [
2044
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "h-4 w-4 mr-2" }),
2045
+ "Refresh"
1751
2046
  ] })
1752
2047
  ] })
1753
- ] });
2048
+ ] }) });
1754
2049
  };
1755
- var RecentPayments = () => {
1756
- const { payments, isLoadingPayments } = useOverviewContext();
2050
+ var BalanceCard = () => {
2051
+ const {
2052
+ balance,
2053
+ isLoadingBalance,
2054
+ refreshBalance
2055
+ } = useOverviewContext();
1757
2056
  const formatCurrency = (amount) => {
1758
2057
  if (amount === null || amount === void 0) return "$0.00";
1759
- const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
1760
2058
  return new Intl.NumberFormat("en-US", {
1761
2059
  style: "currency",
1762
2060
  currency: "USD",
1763
2061
  minimumFractionDigits: 2
1764
- }).format(numAmount);
1765
- };
1766
- const getRelativeTime = (date) => {
1767
- if (!date) return "N/A";
1768
- const now = /* @__PURE__ */ new Date();
1769
- const target = new Date(date);
1770
- const diffInSeconds = Math.floor((now.getTime() - target.getTime()) / 1e3);
1771
- if (diffInSeconds < 60) return "Just now";
1772
- if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
1773
- if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
1774
- return `${Math.floor(diffInSeconds / 86400)}d ago`;
2062
+ }).format(amount);
1775
2063
  };
1776
- const getStatusVariant = (status) => {
1777
- switch (status?.toLowerCase()) {
1778
- case "completed":
1779
- case "success":
1780
- return "default";
1781
- case "pending":
1782
- case "confirming":
1783
- return "secondary";
1784
- case "failed":
1785
- case "error":
1786
- case "expired":
1787
- return "destructive";
1788
- default:
1789
- return "outline";
2064
+ const formatDate = (dateStr) => {
2065
+ if (!dateStr) return "No transactions yet";
2066
+ try {
2067
+ return moment__default.default.utc(dateStr).local().format("MMM D, YYYY");
2068
+ } catch {
2069
+ return "Invalid date";
1790
2070
  }
1791
2071
  };
1792
- if (isLoadingPayments) {
2072
+ if (isLoadingBalance) {
1793
2073
  return /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.Card, { children: [
1794
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.CardTitle, { className: "flex items-center gap-2", children: [
1795
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { className: "h-5 w-5" }),
1796
- "Recent Payments"
1797
- ] }) }),
1798
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.CardContent, { className: "space-y-3", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-3 border rounded-sm", children: [
1799
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1800
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Skeleton, { className: "h-4 w-32" }),
1801
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Skeleton, { className: "h-3 w-24" })
2074
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.CardTitle, { className: "flex items-center justify-between", children: [
2075
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2076
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { className: "h-5 w-5" }),
2077
+ "Account Balance"
1802
2078
  ] }),
1803
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Skeleton, { className: "h-6 w-16" })
1804
- ] }, i)) })
2079
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Skeleton, { className: "h-8 w-20" })
2080
+ ] }) }),
2081
+ /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.CardContent, { className: "space-y-4", children: [
2082
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Skeleton, { className: "h-10 w-32" }),
2083
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Skeleton, { className: "h-4 w-48" })
2084
+ ] })
1805
2085
  ] });
1806
2086
  }
1807
- const recentPaymentsList = payments?.results?.slice(0, 5) || [];
2087
+ const balanceData = balance?.balance || balance;
2088
+ const amountUsd = balanceData?.amount_usd ?? 0;
2089
+ const totalDeposited = balanceData?.total_deposited ?? 0;
2090
+ const totalWithdrawn = balanceData?.total_withdrawn ?? 0;
2091
+ const lastTransactionAt = balanceData?.last_transaction_at;
2092
+ const isEmpty = amountUsd === 0 && totalDeposited === 0;
1808
2093
  return /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.Card, { children: [
1809
2094
  /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.CardTitle, { className: "flex items-center justify-between", children: [
1810
2095
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1811
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { className: "h-5 w-5" }),
1812
- "Recent Payments"
2096
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { className: "h-5 w-5" }),
2097
+ "Account Balance"
1813
2098
  ] }),
1814
- /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.Button, { variant: "ghost", size: "sm", children: [
1815
- "View All",
1816
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-4 w-4 ml-2" })
1817
- ] })
1818
- ] }) }),
2099
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2100
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Button, { variant: "ghost", size: "sm", onClick: refreshBalance, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "h-4 w-4" }) }),
2101
+ /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.Button, { size: "sm", onClick: () => openCreatePaymentDialog(), children: [
2102
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4 mr-2" }),
2103
+ "Add Funds"
2104
+ ] })
2105
+ ] })
2106
+ ] }) }),
2107
+ /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.CardContent, { className: "space-y-4", children: [
2108
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2109
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-4xl font-bold", children: formatCurrency(amountUsd) }),
2110
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground mt-1", children: [
2111
+ "Available balance \u2022 Last updated ",
2112
+ formatDate(lastTransactionAt)
2113
+ ] })
2114
+ ] }),
2115
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4 pt-4 border-t", children: [
2116
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2117
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Total Deposited" }),
2118
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg font-semibold text-green-600", children: formatCurrency(totalDeposited) })
2119
+ ] }),
2120
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2121
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Total Withdrawn" }),
2122
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg font-semibold text-red-600", children: formatCurrency(totalWithdrawn) })
2123
+ ] })
2124
+ ] }),
2125
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2126
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Badge, { variant: !isEmpty ? "default" : "secondary", children: !isEmpty ? "Active" : "New Account" }),
2127
+ isEmpty && /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Badge, { variant: "outline", children: "Empty Balance" })
2128
+ ] })
2129
+ ] })
2130
+ ] });
2131
+ };
2132
+ var RecentPayments = () => {
2133
+ const { payments, isLoadingPayments } = useOverviewContext();
2134
+ const formatCurrency = (amount) => {
2135
+ if (amount === null || amount === void 0) return "$0.00";
2136
+ const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
2137
+ return new Intl.NumberFormat("en-US", {
2138
+ style: "currency",
2139
+ currency: "USD",
2140
+ minimumFractionDigits: 2
2141
+ }).format(numAmount);
2142
+ };
2143
+ const getRelativeTime = (date) => {
2144
+ if (!date) return "N/A";
2145
+ const m = moment__default.default.utc(date).local();
2146
+ const now = moment__default.default();
2147
+ const diffInSeconds = now.diff(m, "seconds");
2148
+ if (diffInSeconds < 60) return "Just now";
2149
+ if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
2150
+ if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
2151
+ return `${Math.floor(diffInSeconds / 86400)}d ago`;
2152
+ };
2153
+ const getStatusVariant = (status) => {
2154
+ switch (status?.toLowerCase()) {
2155
+ case "completed":
2156
+ case "success":
2157
+ return "default";
2158
+ case "pending":
2159
+ case "confirming":
2160
+ return "secondary";
2161
+ case "failed":
2162
+ case "error":
2163
+ case "expired":
2164
+ return "destructive";
2165
+ default:
2166
+ return "outline";
2167
+ }
2168
+ };
2169
+ if (isLoadingPayments) {
2170
+ return /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.Card, { children: [
2171
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.CardTitle, { className: "flex items-center gap-2", children: [
2172
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { className: "h-5 w-5" }),
2173
+ "Recent Payments"
2174
+ ] }) }),
2175
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.CardContent, { className: "space-y-3", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-3 border rounded-sm", children: [
2176
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
2177
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Skeleton, { className: "h-4 w-32" }),
2178
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Skeleton, { className: "h-3 w-24" })
2179
+ ] }),
2180
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Skeleton, { className: "h-6 w-16" })
2181
+ ] }, i)) })
2182
+ ] });
2183
+ }
2184
+ const recentPaymentsList = payments?.results?.slice(0, 5) || [];
2185
+ return /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.Card, { children: [
2186
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.CardTitle, { className: "flex items-center justify-between", children: [
2187
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2188
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { className: "h-5 w-5" }),
2189
+ "Recent Payments"
2190
+ ] }),
2191
+ /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.Button, { variant: "ghost", size: "sm", children: [
2192
+ "View All",
2193
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-4 w-4 ml-2" })
2194
+ ] })
2195
+ ] }) }),
1819
2196
  /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.CardContent, { children: recentPaymentsList.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center py-8 text-muted-foreground", children: [
1820
2197
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { className: "h-12 w-12 mx-auto mb-4 opacity-50" }),
1821
2198
  /* @__PURE__ */ jsxRuntime.jsx("p", { children: "No recent payments" }),
@@ -1873,14 +2250,18 @@ var PaymentsList = () => {
1873
2250
  };
1874
2251
  const getRelativeTime = (date) => {
1875
2252
  if (!date) return "N/A";
1876
- const now = /* @__PURE__ */ new Date();
1877
- const target = new Date(date);
1878
- const diffInSeconds = Math.floor((now.getTime() - target.getTime()) / 1e3);
2253
+ const m = moment__default.default.utc(date).local();
2254
+ const now = moment__default.default();
2255
+ const diffInSeconds = now.diff(m, "seconds");
1879
2256
  if (diffInSeconds < 60) return "Just now";
1880
2257
  if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
1881
2258
  if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
1882
2259
  return `${Math.floor(diffInSeconds / 86400)}d ago`;
1883
2260
  };
2261
+ const formatDate = (date) => {
2262
+ if (!date) return "N/A";
2263
+ return moment__default.default.utc(date).local().format("MMM D, YYYY");
2264
+ };
1884
2265
  const getStatusVariant = (status) => {
1885
2266
  switch (status?.toLowerCase()) {
1886
2267
  case "completed":
@@ -1903,11 +2284,21 @@ var PaymentsList = () => {
1903
2284
  const handleStatusFilter = (status) => {
1904
2285
  setStatusFilter(status);
1905
2286
  };
2287
+ const truncateId = (id) => {
2288
+ if (!id) return "N/A";
2289
+ const str = id.toString();
2290
+ return str.length > 8 ? `${str.slice(0, 8)}...` : str;
2291
+ };
1906
2292
  const filteredPayments = paymentsList.filter((payment) => {
1907
2293
  const matchesSearch = searchTerm ? payment.id?.toLowerCase().includes(searchTerm.toLowerCase()) || payment.status?.toLowerCase().includes(searchTerm.toLowerCase()) || payment.currency_code?.toLowerCase().includes(searchTerm.toLowerCase()) : true;
1908
2294
  const matchesStatus = statusFilter !== "all" ? payment.status?.toLowerCase() === statusFilter.toLowerCase() : true;
1909
2295
  return matchesSearch && matchesStatus;
1910
- });
2296
+ }).map((payment) => ({
2297
+ ...payment,
2298
+ formattedDate: formatDate(payment.created_at),
2299
+ relativeTime: getRelativeTime(payment.created_at),
2300
+ truncatedId: truncateId(payment.id)
2301
+ }));
1911
2302
  return /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.Card, { children: [
1912
2303
  /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.CardTitle, { className: "flex items-center justify-between", children: [
1913
2304
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Payment History" }),
@@ -1983,14 +2374,14 @@ var PaymentsList = () => {
1983
2374
  onClick: () => openPaymentDetailsDialog(String(payment.id)),
1984
2375
  children: [
1985
2376
  /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1986
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: payment.created_at ? new Date(payment.created_at).toLocaleDateString() : "N/A" }),
1987
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-muted-foreground", children: getRelativeTime(payment.created_at) })
2377
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: payment.formattedDate }),
2378
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-muted-foreground", children: payment.relativeTime })
1988
2379
  ] }) }),
1989
2380
  /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { className: "font-mono font-semibold", children: formatCurrency(payment.amount_usd) }),
1990
2381
  /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Badge, { variant: "outline", children: payment.currency_code || "USD" }) }),
1991
2382
  /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Badge, { variant: getStatusVariant(payment.status), children: payment.status }) }),
1992
2383
  /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { className: "text-sm text-muted-foreground", children: "NowPayments" }),
1993
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { className: "font-mono text-sm text-muted-foreground", children: payment.id ? `${payment.id.toString().slice(0, 8)}...` : "N/A" }),
2384
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { className: "font-mono text-sm text-muted-foreground", children: payment.truncatedId }),
1994
2385
  /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(
1995
2386
  uiNextjs.Button,
1996
2387
  {
@@ -2043,22 +2434,16 @@ var TransactionsList = () => {
2043
2434
  const formatDate = (date) => {
2044
2435
  if (!date) return "N/A";
2045
2436
  try {
2046
- return new Date(date).toLocaleString("en-US", {
2047
- year: "numeric",
2048
- month: "short",
2049
- day: "numeric",
2050
- hour: "2-digit",
2051
- minute: "2-digit"
2052
- });
2437
+ return moment__default.default.utc(date).local().format("MMM D, YYYY hh:mm A");
2053
2438
  } catch {
2054
2439
  return "Invalid date";
2055
2440
  }
2056
2441
  };
2057
2442
  const getRelativeTime = (date) => {
2058
2443
  if (!date) return "N/A";
2059
- const now = /* @__PURE__ */ new Date();
2060
- const target = new Date(date);
2061
- const diffInSeconds = Math.floor((now.getTime() - target.getTime()) / 1e3);
2444
+ const m = moment__default.default.utc(date).local();
2445
+ const now = moment__default.default();
2446
+ const diffInSeconds = now.diff(m, "seconds");
2062
2447
  if (diffInSeconds < 60) return "Just now";
2063
2448
  if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
2064
2449
  if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
@@ -2088,11 +2473,22 @@ var TransactionsList = () => {
2088
2473
  setTypeFilter(type);
2089
2474
  await refreshTransactions();
2090
2475
  };
2476
+ const truncateId = (id) => {
2477
+ if (!id) return "N/A";
2478
+ const str = id.toString();
2479
+ return str.length > 8 ? `${str.slice(0, 8)}...` : str;
2480
+ };
2091
2481
  const filteredTransactions = transactionsList.filter((transaction) => {
2092
2482
  const matchesSearch = searchTerm ? transaction.id?.toString().toLowerCase().includes(searchTerm.toLowerCase()) || transaction.description?.toLowerCase().includes(searchTerm.toLowerCase()) || transaction.type?.toLowerCase().includes(searchTerm.toLowerCase()) : true;
2093
2483
  const matchesType = typeFilter !== "all" ? transaction.type?.toLowerCase() === typeFilter.toLowerCase() : true;
2094
2484
  return matchesSearch && matchesType;
2095
- });
2485
+ }).map((transaction) => ({
2486
+ ...transaction,
2487
+ isDeposit: transaction.type?.toLowerCase() === "deposit" || transaction.type?.toLowerCase() === "credit",
2488
+ formattedDate: formatDate(transaction.created_at || transaction.timestamp),
2489
+ relativeTime: getRelativeTime(transaction.created_at || transaction.timestamp),
2490
+ truncatedRef: truncateId(transaction.reference || transaction.payment_id)
2491
+ }));
2096
2492
  if (isLoadingTransactions) {
2097
2493
  return /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.Card, { children: [
2098
2494
  /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.CardTitle, { className: "flex items-center gap-2", children: [
@@ -2158,26 +2554,23 @@ var TransactionsList = () => {
2158
2554
  /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableHead, { children: "Description" }),
2159
2555
  /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableHead, { children: "Reference" })
2160
2556
  ] }) }),
2161
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableBody, { children: filteredTransactions.map((transaction, index) => {
2162
- const isDeposit = transaction.type?.toLowerCase() === "deposit" || transaction.type?.toLowerCase() === "credit";
2163
- return /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.TableRow, { children: [
2164
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2165
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: formatDate(transaction.created_at || transaction.timestamp) }),
2166
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-muted-foreground", children: getRelativeTime(transaction.created_at || transaction.timestamp) })
2167
- ] }) }),
2168
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2169
- getTypeIcon(transaction.type),
2170
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Badge, { variant: getTypeVariant(transaction.type), children: transaction.type || "Unknown" })
2171
- ] }) }),
2172
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { className: "font-mono font-semibold", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: isDeposit ? "text-green-600" : "text-red-600", children: [
2173
- isDeposit ? "+" : "-",
2174
- formatCurrency(Math.abs(transaction.amount || transaction.amount_usd || 0))
2175
- ] }) }),
2176
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { className: "font-mono", children: formatCurrency(transaction.balance_after || 0) }),
2177
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { className: "text-sm", children: transaction.description || transaction.note || "No description" }),
2178
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { className: "font-mono text-sm text-muted-foreground", children: transaction.reference || transaction.payment_id ? `${(transaction.reference || transaction.payment_id).toString().slice(0, 8)}...` : "N/A" })
2179
- ] }, transaction.id || index);
2180
- }) })
2557
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableBody, { children: filteredTransactions.map((transaction, index) => /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.TableRow, { children: [
2558
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2559
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: transaction.formattedDate }),
2560
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-muted-foreground", children: transaction.relativeTime })
2561
+ ] }) }),
2562
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2563
+ getTypeIcon(transaction.type),
2564
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Badge, { variant: getTypeVariant(transaction.type), children: transaction.type || "Unknown" })
2565
+ ] }) }),
2566
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { className: "font-mono font-semibold", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: transaction.isDeposit ? "text-green-600" : "text-red-600", children: [
2567
+ transaction.isDeposit ? "+" : "-",
2568
+ formatCurrency(Math.abs(transaction.amount || transaction.amount_usd || 0))
2569
+ ] }) }),
2570
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { className: "font-mono", children: formatCurrency(transaction.balance_after || 0) }),
2571
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { className: "text-sm", children: transaction.description || transaction.note || "No description" }),
2572
+ /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TableCell, { className: "font-mono text-sm text-muted-foreground", children: transaction.truncatedRef })
2573
+ ] }, transaction.id || index)) })
2181
2574
  ] }) })
2182
2575
  ] })
2183
2576
  ] });
@@ -2185,384 +2578,6 @@ var TransactionsList = () => {
2185
2578
  var TransactionsView = () => {
2186
2579
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsxRuntime.jsx(TransactionsList, {}) });
2187
2580
  };
2188
- var isDevelopment = process.env.NODE_ENV === "development";
2189
- var logger = consola.createConsola({
2190
- level: isDevelopment ? 4 : 1
2191
- }).withTag("ext-payments");
2192
- var paymentsLogger = logger;
2193
- var PaymentCreateSchema = zod.z.object({
2194
- amount_usd: zod.z.number().min(0.01, "Amount must be at least $0.01"),
2195
- currency_code: zod.z.string().min(1, "Please select a currency")
2196
- });
2197
- var CreatePaymentDialog = () => {
2198
- const [open, setOpen] = react.useState(false);
2199
- const [isSubmitting, setIsSubmitting] = react.useState(false);
2200
- const { createPayment } = usePaymentsContext();
2201
- const { currencies, isLoadingCurrencies } = useRootPaymentsContext();
2202
- const form = reactHookForm.useForm({
2203
- resolver: zod$1.zodResolver(PaymentCreateSchema),
2204
- defaultValues: {
2205
- amount_usd: 10,
2206
- currency_code: "USDT"
2207
- }
2208
- });
2209
- const currenciesList = react.useMemo(() => {
2210
- const data = currencies?.currencies || currencies?.results || currencies || [];
2211
- return Array.isArray(data) ? data : [];
2212
- }, [currencies]);
2213
- const currencyOptions = react.useMemo(() => {
2214
- return currenciesList.filter((curr) => curr.is_enabled !== false).map((curr) => ({
2215
- code: curr.code || curr.currency_code || curr.symbol,
2216
- name: curr.name || curr.code || curr.currency_code,
2217
- usd_rate: curr.usd_rate || curr.rate || 1,
2218
- network: curr.network || null
2219
- }));
2220
- }, [currenciesList]);
2221
- const calculateCryptoAmount = react.useMemo(() => {
2222
- const amountUsd = form.watch("amount_usd");
2223
- const currencyCode = form.watch("currency_code");
2224
- const currency = currencyOptions.find((c) => c.code === currencyCode);
2225
- if (!currency || !currency.usd_rate || !amountUsd) {
2226
- return null;
2227
- }
2228
- const cryptoAmount = amountUsd / currency.usd_rate;
2229
- return {
2230
- amount: cryptoAmount,
2231
- currency: currency.code,
2232
- rate: currency.usd_rate,
2233
- network: currency.network
2234
- };
2235
- }, [form.watch("amount_usd"), form.watch("currency_code"), currencyOptions]);
2236
- react.useEffect(() => {
2237
- const handleOpen = () => setOpen(true);
2238
- const handleClose2 = () => setOpen(false);
2239
- window.addEventListener(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG, handleOpen);
2240
- window.addEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
2241
- return () => {
2242
- window.removeEventListener(PAYMENT_EVENTS.OPEN_CREATE_PAYMENT_DIALOG, handleOpen);
2243
- window.removeEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
2244
- };
2245
- }, []);
2246
- const handleClose = () => {
2247
- setOpen(false);
2248
- form.reset();
2249
- };
2250
- react.useEffect(() => {
2251
- if (currencyOptions.length > 0 && !form.getValues("currency_code")) {
2252
- form.setValue("currency_code", currencyOptions[0].code);
2253
- }
2254
- }, [currencyOptions, form]);
2255
- const handleSubmit = async (data) => {
2256
- try {
2257
- setIsSubmitting(true);
2258
- const result = await createPayment();
2259
- handleClose();
2260
- closePaymentsDialog();
2261
- const paymentData = result;
2262
- const paymentId = paymentData?.payment?.id || paymentData?.id;
2263
- if (paymentId) {
2264
- openPaymentDetailsDialog(String(paymentId));
2265
- }
2266
- } catch (error) {
2267
- paymentsLogger.error("Failed to create payment:", error);
2268
- } finally {
2269
- setIsSubmitting(false);
2270
- }
2271
- };
2272
- return /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogContent, { className: "sm:max-w-md", children: [
2273
- /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogHeader, { children: [
2274
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogTitle, { children: "Create Payment" }),
2275
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogDescription, { children: "Create a new payment to add funds to your account." })
2276
- ] }),
2277
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Form, { ...form, children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: form.handleSubmit(handleSubmit), className: "space-y-4", children: [
2278
- /* @__PURE__ */ jsxRuntime.jsx(
2279
- uiNextjs.FormField,
2280
- {
2281
- control: form.control,
2282
- name: "amount_usd",
2283
- render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.FormItem, { children: [
2284
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormLabel, { children: "Amount (USD)" }),
2285
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormControl, { children: /* @__PURE__ */ jsxRuntime.jsx(
2286
- uiNextjs.Input,
2287
- {
2288
- type: "number",
2289
- step: "0.01",
2290
- min: "0.01",
2291
- placeholder: "10.00",
2292
- ...field,
2293
- onChange: (e) => field.onChange(parseFloat(e.target.value) || 0)
2294
- }
2295
- ) }),
2296
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormDescription, { children: "The amount you want to pay in USD." }),
2297
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormMessage, {})
2298
- ] })
2299
- }
2300
- ),
2301
- /* @__PURE__ */ jsxRuntime.jsx(
2302
- uiNextjs.FormField,
2303
- {
2304
- control: form.control,
2305
- name: "currency_code",
2306
- render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.FormItem, { children: [
2307
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormLabel, { children: "Currency" }),
2308
- /* @__PURE__ */ jsxRuntime.jsxs(
2309
- uiNextjs.Select,
2310
- {
2311
- onValueChange: field.onChange,
2312
- defaultValue: field.value,
2313
- disabled: isLoadingCurrencies,
2314
- children: [
2315
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormControl, { children: /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.SelectTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.SelectValue, { placeholder: "Select currency..." }) }) }),
2316
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.SelectContent, { children: currencyOptions.map((curr) => /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.SelectItem, { value: curr.code, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2317
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TokenIcon, { symbol: curr.code, size: 16 }),
2318
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: curr.code }),
2319
- curr.network && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
2320
- "(",
2321
- curr.network,
2322
- ")"
2323
- ] })
2324
- ] }) }, curr.code)) })
2325
- ]
2326
- }
2327
- ),
2328
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormDescription, { children: "The cryptocurrency to use for payment." }),
2329
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.FormMessage, {})
2330
- ] })
2331
- }
2332
- ),
2333
- calculateCryptoAmount && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-sm bg-muted p-4 space-y-3", children: [
2334
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
2335
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "You will send" }),
2336
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2337
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TokenIcon, { symbol: calculateCryptoAmount.currency, size: 16 }),
2338
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono font-semibold", children: [
2339
- calculateCryptoAmount.amount.toFixed(8),
2340
- " ",
2341
- calculateCryptoAmount.currency
2342
- ] })
2343
- ] })
2344
- ] }),
2345
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
2346
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "You will receive" }),
2347
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-lg font-bold", children: [
2348
- "$",
2349
- form.watch("amount_usd")?.toFixed(2),
2350
- " USD"
2351
- ] })
2352
- ] }),
2353
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-xs", children: [
2354
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Rate" }),
2355
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
2356
- "1 ",
2357
- calculateCryptoAmount.currency,
2358
- " = $",
2359
- calculateCryptoAmount.rate?.toFixed(2)
2360
- ] })
2361
- ] }),
2362
- calculateCryptoAmount.network && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t pt-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
2363
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Network" }),
2364
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: calculateCryptoAmount.network })
2365
- ] }) })
2366
- ] }),
2367
- /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogFooter, { children: [
2368
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Button, { type: "button", variant: "outline", onClick: handleClose, disabled: isSubmitting, children: "Cancel" }),
2369
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Button, { type: "submit", disabled: isSubmitting || currencyOptions.length === 0, children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2370
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "h-4 w-4 mr-2 animate-spin" }),
2371
- "Creating..."
2372
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2373
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4 mr-2" }),
2374
- "Create Payment"
2375
- ] }) })
2376
- ] })
2377
- ] }) })
2378
- ] }) });
2379
- };
2380
- var PaymentDetailsDialog = () => {
2381
- const [open, setOpen] = react.useState(false);
2382
- const [paymentId, setPaymentId] = react.useState(null);
2383
- const [timeLeft, setTimeLeft] = react.useState("");
2384
- const shouldFetch = open && !!paymentId;
2385
- const { data: payment, isLoading, error, mutate } = usePaymentsPaymentsRetrieve(
2386
- shouldFetch ? paymentId : "",
2387
- apiPayments
2388
- );
2389
- react.useEffect(() => {
2390
- const handleOpen = (event) => {
2391
- const customEvent = event;
2392
- setPaymentId(customEvent.detail.id);
2393
- setOpen(true);
2394
- };
2395
- const handleClose2 = () => {
2396
- setOpen(false);
2397
- setPaymentId(null);
2398
- };
2399
- window.addEventListener(PAYMENT_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG, handleOpen);
2400
- window.addEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
2401
- return () => {
2402
- window.removeEventListener(PAYMENT_EVENTS.OPEN_PAYMENT_DETAILS_DIALOG, handleOpen);
2403
- window.removeEventListener(PAYMENT_EVENTS.CLOSE_DIALOG, handleClose2);
2404
- };
2405
- }, []);
2406
- const handleClose = () => {
2407
- setOpen(false);
2408
- setPaymentId(null);
2409
- };
2410
- react.useEffect(() => {
2411
- if (!payment?.expires_at) return;
2412
- const updateTimeLeft = () => {
2413
- const now = (/* @__PURE__ */ new Date()).getTime();
2414
- const expires = new Date(payment.expires_at).getTime();
2415
- const diff = expires - now;
2416
- if (diff <= 0) {
2417
- setTimeLeft("Expired");
2418
- return;
2419
- }
2420
- const hours = Math.floor(diff / (1e3 * 60 * 60));
2421
- const minutes = Math.floor(diff % (1e3 * 60 * 60) / (1e3 * 60));
2422
- const seconds = Math.floor(diff % (1e3 * 60) / 1e3);
2423
- setTimeLeft(`${hours}h ${minutes}m ${seconds}s`);
2424
- };
2425
- updateTimeLeft();
2426
- const interval = setInterval(updateTimeLeft, 1e3);
2427
- return () => clearInterval(interval);
2428
- }, [payment?.expires_at]);
2429
- const getStatusInfo = () => {
2430
- switch (payment?.status?.toLowerCase()) {
2431
- case "pending":
2432
- return { icon: lucideReact.Clock, color: "text-yellow-500", bg: "bg-yellow-500/10" };
2433
- case "completed":
2434
- case "success":
2435
- return { icon: lucideReact.CheckCircle2, color: "text-green-500", bg: "bg-green-500/10" };
2436
- case "failed":
2437
- case "error":
2438
- return { icon: lucideReact.XCircle, color: "text-red-500", bg: "bg-red-500/10" };
2439
- case "expired":
2440
- return { icon: lucideReact.AlertCircle, color: "text-gray-500", bg: "bg-gray-500/10" };
2441
- case "confirming":
2442
- return { icon: lucideReact.RefreshCw, color: "text-blue-500", bg: "bg-blue-500/10" };
2443
- default:
2444
- return { icon: lucideReact.Clock, color: "text-gray-500", bg: "bg-gray-500/10" };
2445
- }
2446
- };
2447
- if (!open) return null;
2448
- if (isLoading) {
2449
- return /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogContent, { className: "sm:max-w-lg", children: [
2450
- /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogHeader, { children: [
2451
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogTitle, { children: "Payment Details" }),
2452
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogDescription, { children: "Loading payment information..." })
2453
- ] }),
2454
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "h-8 w-8 animate-spin text-muted-foreground" }) })
2455
- ] }) });
2456
- }
2457
- if (shouldFetch && !isLoading && (error || !payment)) {
2458
- return /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogContent, { className: "sm:max-w-lg", children: [
2459
- /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogHeader, { children: [
2460
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogTitle, { children: "Payment Details" }),
2461
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogDescription, { children: "Failed to load payment information" })
2462
- ] }),
2463
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12 space-y-4", children: [
2464
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { className: "h-12 w-12 text-destructive" }),
2465
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: error ? `Error: ${error}` : "Payment not found" }),
2466
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Button, { onClick: () => mutate(), children: "Try Again" })
2467
- ] })
2468
- ] }) });
2469
- }
2470
- const statusInfo = getStatusInfo();
2471
- const StatusIcon = statusInfo.icon;
2472
- const qrCodeUrl = payment.pay_address ? `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(payment.pay_address)}` : null;
2473
- return /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Dialog, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogContent, { className: "sm:max-w-lg", children: [
2474
- /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogHeader, { children: [
2475
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogTitle, { children: "Payment Details" }),
2476
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.DialogDescription, { children: "Send cryptocurrency to complete your payment" })
2477
- ] }),
2478
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
2479
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-3 p-4 rounded-sm ${statusInfo.bg}`, children: [
2480
- /* @__PURE__ */ jsxRuntime.jsx(StatusIcon, { className: `h-5 w-5 ${statusInfo.color}` }),
2481
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
2482
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold capitalize", children: payment.status }),
2483
- payment.status === "pending" && timeLeft && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-muted-foreground", children: [
2484
- "Expires in ",
2485
- timeLeft
2486
- ] })
2487
- ] })
2488
- ] }),
2489
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
2490
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between p-4 bg-muted rounded-sm", children: [
2491
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Amount to send" }),
2492
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2493
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.TokenIcon, { symbol: String(payment.currency_code || "BTC"), size: 20 }),
2494
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono font-bold text-lg", children: [
2495
- payment.pay_amount || "0.00000000",
2496
- " ",
2497
- payment.currency_code
2498
- ] })
2499
- ] })
2500
- ] }),
2501
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4", children: [
2502
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Equivalent to" }),
2503
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold text-lg", children: [
2504
- "$",
2505
- parseFloat(payment.amount_usd || "0").toFixed(2),
2506
- " USD"
2507
- ] })
2508
- ] }),
2509
- payment.internal_payment_id && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4", children: [
2510
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Payment Order #" }),
2511
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-medium", children: payment.internal_payment_id })
2512
- ] }),
2513
- payment.currency_network && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4", children: [
2514
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Network" }),
2515
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: payment.currency_network })
2516
- ] })
2517
- ] }),
2518
- qrCodeUrl && payment.status === "pending" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center p-6 bg-white rounded-sm", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: qrCodeUrl, alt: "Payment QR Code", className: "w-48 h-48" }) }),
2519
- payment.pay_address && payment.status === "pending" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
2520
- /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Payment Address" }),
2521
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2522
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 p-3 bg-muted rounded-sm font-mono text-sm break-all", children: payment.pay_address }),
2523
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.CopyButton, { value: payment.pay_address, variant: "outline" })
2524
- ] })
2525
- ] }),
2526
- payment.transaction_hash && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
2527
- /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium", children: "Transaction Hash" }),
2528
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 bg-muted rounded-sm font-mono text-sm break-all", children: payment.transaction_hash })
2529
- ] }),
2530
- payment.payment_url && payment.status === "pending" && /* @__PURE__ */ jsxRuntime.jsxs(
2531
- uiNextjs.Button,
2532
- {
2533
- variant: "outline",
2534
- className: "w-full",
2535
- onClick: () => window.open(payment.payment_url, "_blank"),
2536
- children: [
2537
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-4 w-4 mr-2" }),
2538
- "Open in Payment Provider"
2539
- ]
2540
- }
2541
- ),
2542
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pt-4 border-t space-y-2 text-xs text-muted-foreground", children: [
2543
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
2544
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Payment ID" }),
2545
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: payment.id })
2546
- ] }),
2547
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
2548
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Created" }),
2549
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: new Date(payment.created_at).toLocaleString() })
2550
- ] }),
2551
- payment.confirmations_count !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
2552
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Confirmations" }),
2553
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: payment.confirmations_count })
2554
- ] })
2555
- ] })
2556
- ] }),
2557
- /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.DialogFooter, { children: [
2558
- /* @__PURE__ */ jsxRuntime.jsx(uiNextjs.Button, { variant: "outline", onClick: handleClose, children: "Close" }),
2559
- /* @__PURE__ */ jsxRuntime.jsxs(uiNextjs.Button, { onClick: () => mutate(), variant: "ghost", size: "sm", children: [
2560
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "h-4 w-4 mr-2" }),
2561
- "Refresh"
2562
- ] })
2563
- ] })
2564
- ] }) });
2565
- };
2566
2581
  var PaymentsLayout = () => {
2567
2582
  return /* @__PURE__ */ jsxRuntime.jsx(RootPaymentsProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-full p-6 space-y-6", children: [
2568
2583
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
@@ -2601,7 +2616,7 @@ var PaymentsLayout = () => {
2601
2616
  // package.json
2602
2617
  var package_default = {
2603
2618
  name: "@djangocfg/ext-payments",
2604
- version: "1.0.4",
2619
+ version: "1.0.6",
2605
2620
  description: "Payments system extension for DjangoCFG",
2606
2621
  keywords: [
2607
2622
  "django",
@@ -2669,7 +2684,8 @@ var package_default = {
2669
2684
  "p-retry": "^7.0.0",
2670
2685
  react: "^18 || ^19",
2671
2686
  swr: "^2.3.7",
2672
- zod: "^4.1.13"
2687
+ zod: "^4.1.13",
2688
+ moment: "^2.30.1"
2673
2689
  },
2674
2690
  devDependencies: {
2675
2691
  "@djangocfg/api": "workspace:*",