@djangocfg/ext-payments 1.0.6 → 1.0.8

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