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