@oasisprotocol/privana-sdk 0.4.3 → 0.5.0

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.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { usePrivanaContext, createHostedAuthPendingStorageKey, clearHostedAuthPendingTransaction, HostedAuthRequiredError, HostedAuthError, createPkceVerifier, createPkceChallenge, createHostedAuthState, persistHostedAuthPendingTransaction, parseHostedAuthCallback, readHostedAuthPendingTransaction, HostedAuthStateMismatchError, buildHostedAuthSession, useSafePrivanaContext, usePrivateReadRequest, formatTokenAmount, useDepositVerification, getTransactionReceipt, waitForTransactionReceipt, cn, Button, stripHostedAuthCallbackParams, AccountingApiError, getChainId2, shortenAddress, formatTimeRemaining, parseTokenAmount, getExplorerAddressUrl } from './chunk-2AHJHISR.js';
3
- export { AccountingApiError, Button, HOSTED_AUTH_CLOCK_SKEW_MS, HostedAuthError, HostedAuthRequiredError, HostedAuthStateMismatchError, HttpClient, NETWORK_CONFIG, NetworkError, PrivanaClient, PrivanaProvider, SUPPORTED_CHAINS, SiweAuthProvider, Skeleton, ValidationError, applyRefreshResponse, buildHostedAuthSession, buttonVariants, clearHostedAuthPendingTransaction, createHostedAuthPendingStorageKey, createHostedAuthState, createHostedAuthStorageKey, createPkceChallenge, createPkceVerifier, getAccountingContract, getApiUrl, getChainById, getChainId, getExplorerAddressUrl, isHostedAuthRefreshActive, isHostedAuthSessionActive, normalizeAddress, normalizeHex, parseHostedAuthCallback, persistHostedAuthPendingTransaction, readHostedAuthPendingTransaction, readStoredHostedAuthSession, stripHostedAuthCallbackParams, syncHostedAuthSessionToClient, useDepositVerification, usePrivanaContext, useSafeAccount, useSafePrivanaContext, useSiweAuth } from './chunk-2AHJHISR.js';
2
+ import { usePrivanaContext, createHostedAuthPendingStorageKey, clearHostedAuthPendingTransaction, HostedAuthRequiredError, HostedAuthError, createPkceVerifier, createPkceChallenge, createHostedAuthState, persistHostedAuthPendingTransaction, parseHostedAuthCallback, readHostedAuthPendingTransaction, HostedAuthStateMismatchError, buildHostedAuthSession, useSafePrivanaContext, usePrivateReadRequest, formatTokenAmount, useDepositVerification, getTransactionReceipt, waitForTransactionReceipt, cn, Button, stripHostedAuthCallbackParams, AccountingApiError, getChainId2, shortenAddress, formatTimeRemaining, parseTokenAmount, getExplorerAddressUrl, getExplorerLabel, Skeleton, FiatOnRampForm } from './chunk-54FC6TO3.js';
3
+ export { AccountingApiError, Button, HOSTED_AUTH_CLOCK_SKEW_MS, HostedAuthError, HostedAuthRequiredError, HostedAuthStateMismatchError, HttpClient, NETWORK_CONFIG, NetworkError, PrivanaClient, PrivanaProvider, SUPPORTED_CHAINS, SiweAuthProvider, Skeleton, ValidationError, applyRefreshResponse, buildHostedAuthSession, buildSiweStatement, buttonVariants, clearHostedAuthPendingTransaction, createHostedAuthPendingStorageKey, createHostedAuthState, createHostedAuthStorageKey, createPkceChallenge, createPkceVerifier, getAccountingContract, getApiUrl, getChainById, getChainId, getExplorerAddressUrl, getExplorerLabel, isHostedAuthRefreshActive, isHostedAuthSessionActive, normalizeAddress, normalizeHex, parseHostedAuthCallback, persistHostedAuthPendingTransaction, readHostedAuthPendingTransaction, readStoredHostedAuthSession, stripHostedAuthCallbackParams, syncHostedAuthSessionToClient, useDepositVerification, usePrivanaContext, useSafeAccount, useSafePrivanaContext, useSiweAuth } from './chunk-54FC6TO3.js';
4
4
  import { useState, useRef, useMemo, useCallback, useContext, useEffect, useId } from 'react';
5
5
  import { QueryClientContext, useQuery, useQueryClient, useMutation, keepPreviousData } from '@tanstack/react-query';
6
6
  import { useAccount, useWalletClient, useConfig, useWriteContract, useSendTransaction, useChainId, useSwitchChain, useBalance as useBalance$1, useReadContract } from 'wagmi';
@@ -9,6 +9,8 @@ import * as DialogPrimitive from '@radix-ui/react-dialog';
9
9
  import { XIcon } from 'lucide-react';
10
10
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
11
11
  import { toast } from 'sonner';
12
+ import { QRCodeSVG } from 'qrcode.react';
13
+ import { MoonPayProvider, MoonPayContext } from '@moonpay/moonpay-react';
12
14
 
13
15
  // src/sdk/signatures/eip712-types.ts
14
16
  function createDomain(chainId, verifyingContract) {
@@ -841,6 +843,31 @@ function useDeposit(options = {}) {
841
843
  reset
842
844
  };
843
845
  }
846
+ function useDepositAddress(options = {}) {
847
+ const queryClient = useContext(QueryClientContext);
848
+ const accountingContext = useSafePrivanaContext();
849
+ const hasProviders = !!queryClient && !!accountingContext;
850
+ const client = accountingContext?.client;
851
+ const { executePrivateRead, privateReadAddress, privateReadQueryScope, privateReadReady } = usePrivateReadRequest();
852
+ const isReady = hasProviders && privateReadReady && !!privateReadAddress && !!client;
853
+ const query = useQuery({
854
+ queryKey: ["accounting-deposit-address", ...privateReadQueryScope],
855
+ queryFn: async () => {
856
+ if (!privateReadAddress) throw new Error("No authenticated account available");
857
+ if (!client) throw new Error("No accounting client");
858
+ return executePrivateRead(() => client.getDepositAddress());
859
+ },
860
+ enabled: isReady && (options.enabled ?? true)
861
+ });
862
+ return {
863
+ depositAddress: query.data?.deposit_address ?? null,
864
+ isReady,
865
+ isLoading: query.isLoading,
866
+ isError: query.isError,
867
+ error: query.error,
868
+ refetch: query.refetch
869
+ };
870
+ }
844
871
  function useWithdraw(options = {}) {
845
872
  const { address } = useAccount();
846
873
  const { data: walletClient } = useWalletClient();
@@ -1589,19 +1616,6 @@ function DialogDescription({
1589
1616
  }
1590
1617
  );
1591
1618
  }
1592
- function ChevronRightIcon() {
1593
- return /* @__PURE__ */ jsx("svg", { width: "10", height: "5", viewBox: "0 0 12 6", className: "-rotate-90", children: /* @__PURE__ */ jsx(
1594
- "path",
1595
- {
1596
- d: "M0 0l6 6 6-6",
1597
- stroke: "currentColor",
1598
- strokeWidth: "1.5",
1599
- strokeLinecap: "round",
1600
- strokeLinejoin: "round",
1601
- fill: "none"
1602
- }
1603
- ) });
1604
- }
1605
1619
  function USDCIcon({ className, size = 24 }) {
1606
1620
  return /* @__PURE__ */ jsxs(
1607
1621
  "svg",
@@ -1743,6 +1757,135 @@ function getChainIcon(chainId, size) {
1743
1757
  );
1744
1758
  }
1745
1759
  }
1760
+ function CloseIcon() {
1761
+ return /* @__PURE__ */ jsx("svg", { width: "10", height: "10", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx(
1762
+ "path",
1763
+ {
1764
+ d: "M11.99997 11.99997l-5.99995-5.99995-6.00002-6.00002m6.00002 6.00002l6.00001-6.00002m-12.00003 12.00003l6.00002-6.00001",
1765
+ stroke: "currentColor",
1766
+ strokeWidth: "1.5",
1767
+ strokeLinecap: "round",
1768
+ strokeLinejoin: "round"
1769
+ }
1770
+ ) });
1771
+ }
1772
+ function ChevronRightIcon() {
1773
+ return /* @__PURE__ */ jsx("svg", { width: "10", height: "5", viewBox: "0 0 12 6", className: "-rotate-90", children: /* @__PURE__ */ jsx(
1774
+ "path",
1775
+ {
1776
+ d: "M0 0l6 6 6-6",
1777
+ stroke: "currentColor",
1778
+ strokeWidth: "1.5",
1779
+ strokeLinecap: "round",
1780
+ strokeLinejoin: "round",
1781
+ fill: "none"
1782
+ }
1783
+ ) });
1784
+ }
1785
+ function ChevronLeftIcon() {
1786
+ return /* @__PURE__ */ jsx("svg", { width: "10", height: "5", viewBox: "0 0 12 6", className: "rotate-90", children: /* @__PURE__ */ jsx(
1787
+ "path",
1788
+ {
1789
+ d: "M0 0l6 6 6-6",
1790
+ stroke: "currentColor",
1791
+ strokeWidth: "1.5",
1792
+ strokeLinecap: "round",
1793
+ strokeLinejoin: "round",
1794
+ fill: "none"
1795
+ }
1796
+ ) });
1797
+ }
1798
+ function ChevronDownIcon({
1799
+ direction = "down",
1800
+ className
1801
+ }) {
1802
+ return /* @__PURE__ */ jsx(
1803
+ "svg",
1804
+ {
1805
+ width: "16",
1806
+ height: "16",
1807
+ viewBox: "0 0 16 16",
1808
+ fill: "none",
1809
+ className: cn(
1810
+ "transition-transform",
1811
+ direction === "right" && "-rotate-90",
1812
+ direction === "up" && "rotate-180",
1813
+ className
1814
+ ),
1815
+ children: /* @__PURE__ */ jsx(
1816
+ "path",
1817
+ {
1818
+ d: "M4 6l4 4 4-4",
1819
+ stroke: "currentColor",
1820
+ strokeWidth: "1.5",
1821
+ strokeLinecap: "round",
1822
+ strokeLinejoin: "round"
1823
+ }
1824
+ )
1825
+ }
1826
+ );
1827
+ }
1828
+ function CopyIcon() {
1829
+ return /* @__PURE__ */ jsxs(
1830
+ "svg",
1831
+ {
1832
+ width: "16",
1833
+ height: "16",
1834
+ viewBox: "0 0 24 24",
1835
+ fill: "none",
1836
+ stroke: "currentColor",
1837
+ strokeWidth: "2",
1838
+ strokeLinecap: "round",
1839
+ strokeLinejoin: "round",
1840
+ children: [
1841
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
1842
+ /* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
1843
+ ]
1844
+ }
1845
+ );
1846
+ }
1847
+ function CircleCheckIcon() {
1848
+ return /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [
1849
+ /* @__PURE__ */ jsx("circle", { cx: "10", cy: "10", r: "9", stroke: "currentColor", strokeWidth: "1.5" }),
1850
+ /* @__PURE__ */ jsx(
1851
+ "path",
1852
+ {
1853
+ d: "M6 10l2.5 2.5L14 7.5",
1854
+ stroke: "currentColor",
1855
+ strokeWidth: "1.5",
1856
+ strokeLinecap: "round",
1857
+ strokeLinejoin: "round"
1858
+ }
1859
+ )
1860
+ ] });
1861
+ }
1862
+ function CircleXIcon() {
1863
+ return /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [
1864
+ /* @__PURE__ */ jsx("circle", { cx: "10", cy: "10", r: "9", stroke: "currentColor", strokeWidth: "1.5" }),
1865
+ /* @__PURE__ */ jsx(
1866
+ "path",
1867
+ {
1868
+ d: "M7 7l6 6M13 7l-6 6",
1869
+ stroke: "currentColor",
1870
+ strokeWidth: "1.5",
1871
+ strokeLinecap: "round",
1872
+ strokeLinejoin: "round"
1873
+ }
1874
+ )
1875
+ ] });
1876
+ }
1877
+ function ArrowRightIcon({ className }) {
1878
+ return /* @__PURE__ */ jsx("svg", { width: "24", height: "8", viewBox: "0 0 24 8", fill: "none", className, children: /* @__PURE__ */ jsx(
1879
+ "path",
1880
+ {
1881
+ d: "M0 4h22m0 0l-4-4m4 4l-4 4",
1882
+ stroke: "currentColor",
1883
+ strokeWidth: "1.5",
1884
+ strokeLinecap: "round",
1885
+ strokeLinejoin: "round"
1886
+ }
1887
+ ) });
1888
+ }
1746
1889
  function CheckIcon() {
1747
1890
  return /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx(
1748
1891
  "path",
@@ -2297,7 +2440,7 @@ function WithdrawForm({
2297
2440
  title: "Withdrawal Complete",
2298
2441
  message: `Your ${selectedToken.symbol} withdrawal has been processed. Funds should appear in your wallet shortly.`,
2299
2442
  explorerUrl,
2300
- explorerLabel: "View on BaseScan",
2443
+ explorerLabel: targetChain ? getExplorerLabel(targetChain.id) : void 0,
2301
2444
  onDone: handleDone
2302
2445
  }
2303
2446
  );
@@ -2405,66 +2548,6 @@ function WithdrawForm({
2405
2548
  )
2406
2549
  ] });
2407
2550
  }
2408
- function CloseIcon() {
2409
- return /* @__PURE__ */ jsx("svg", { width: "10", height: "10", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx(
2410
- "path",
2411
- {
2412
- d: "M11.99997 11.99997l-5.99995-5.99995-6.00002-6.00002m6.00002 6.00002l6.00001-6.00002m-12.00003 12.00003l6.00002-6.00001",
2413
- stroke: "currentColor",
2414
- strokeWidth: "1.5",
2415
- strokeLinecap: "round",
2416
- strokeLinejoin: "round"
2417
- }
2418
- ) });
2419
- }
2420
- function ChevronRight() {
2421
- return /* @__PURE__ */ jsx("svg", { width: "10", height: "5", viewBox: "0 0 12 6", className: "-rotate-90", children: /* @__PURE__ */ jsx(
2422
- "path",
2423
- {
2424
- d: "M0 0l6 6 6-6",
2425
- stroke: "currentColor",
2426
- strokeWidth: "1.5",
2427
- strokeLinecap: "round",
2428
- strokeLinejoin: "round",
2429
- fill: "none"
2430
- }
2431
- ) });
2432
- }
2433
- function ChevronLeft() {
2434
- return /* @__PURE__ */ jsx("svg", { width: "10", height: "5", viewBox: "0 0 12 6", className: "rotate-90", children: /* @__PURE__ */ jsx(
2435
- "path",
2436
- {
2437
- d: "M0 0l6 6 6-6",
2438
- stroke: "currentColor",
2439
- strokeWidth: "1.5",
2440
- strokeLinecap: "round",
2441
- strokeLinejoin: "round",
2442
- fill: "none"
2443
- }
2444
- ) });
2445
- }
2446
- function ChevronDown({ collapsed }) {
2447
- return /* @__PURE__ */ jsx(
2448
- "svg",
2449
- {
2450
- width: "12",
2451
- height: "6",
2452
- viewBox: "0 0 12 6",
2453
- className: cn("transition-transform", collapsed && "-rotate-90"),
2454
- children: /* @__PURE__ */ jsx(
2455
- "path",
2456
- {
2457
- d: "M0 0l6 6 6-6",
2458
- stroke: "currentColor",
2459
- strokeWidth: "1.5",
2460
- strokeLinecap: "round",
2461
- strokeLinejoin: "round",
2462
- fill: "none"
2463
- }
2464
- )
2465
- }
2466
- );
2467
- }
2468
2551
  function BalanceCards({
2469
2552
  selectedToken,
2470
2553
  onLockedFundsClick,
@@ -2494,7 +2577,7 @@ function BalanceCards({
2494
2577
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: "Balance" }),
2495
2578
  /* @__PURE__ */ jsx("span", { className: "bg-secondary text-muted-foreground rounded-full px-2 py-[5px] text-[10px] font-bold", children: selectedToken.symbol })
2496
2579
  ] }),
2497
- /* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-6 w-6 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRight, {}) })
2580
+ /* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-6 w-6 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) })
2498
2581
  ] }),
2499
2582
  /* @__PURE__ */ jsx("div", { className: "text-foreground text-xl font-medium", children: balanceLoading ? /* @__PURE__ */ jsx("span", { className: "bg-secondary inline-block h-6 w-24 animate-pulse rounded" }) : formattedBalance })
2500
2583
  ]
@@ -2515,7 +2598,7 @@ function BalanceCards({
2515
2598
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: "Locked Funds" }),
2516
2599
  /* @__PURE__ */ jsx("span", { className: "bg-secondary text-muted-foreground rounded-full px-2 py-[5px] text-[10px] font-bold", children: selectedToken.symbol })
2517
2600
  ] }),
2518
- /* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-6 w-6 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRight, {}) })
2601
+ /* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-6 w-6 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) })
2519
2602
  ] }),
2520
2603
  /* @__PURE__ */ jsx("div", { className: "text-foreground text-xl font-medium", children: lockedLoading ? /* @__PURE__ */ jsx("span", { className: "bg-secondary inline-block h-6 w-20 animate-pulse rounded" }) : formattedLocked })
2521
2604
  ]
@@ -2614,7 +2697,7 @@ function LockedFundsView({ onBack }) {
2614
2697
  {
2615
2698
  onClick: onBack,
2616
2699
  className: "text-muted-foreground hover:text-foreground -ml-2 flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
2617
- children: /* @__PURE__ */ jsx(ChevronLeft, {})
2700
+ children: /* @__PURE__ */ jsx(ChevronLeftIcon, {})
2618
2701
  }
2619
2702
  ),
2620
2703
  /* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Locked Funds" })
@@ -2634,7 +2717,12 @@ function LockedFundsView({ onBack }) {
2634
2717
  className: "text-muted-foreground hover:bg-secondary flex w-full cursor-pointer items-center justify-between rounded-lg px-4 py-4 transition-colors",
2635
2718
  children: [
2636
2719
  /* @__PURE__ */ jsx("span", { className: "text-sm", children: section.title }),
2637
- /* @__PURE__ */ jsx(ChevronDown, { collapsed: collapsedSections[section.title] })
2720
+ /* @__PURE__ */ jsx(
2721
+ ChevronDownIcon,
2722
+ {
2723
+ direction: collapsedSections[section.title] ? "right" : "down"
2724
+ }
2725
+ )
2638
2726
  ]
2639
2727
  }
2640
2728
  ),
@@ -2716,7 +2804,7 @@ function BalanceDetailsView({ onBack }) {
2716
2804
  {
2717
2805
  onClick: onBack,
2718
2806
  className: "text-muted-foreground hover:text-foreground -ml-2 flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
2719
- children: /* @__PURE__ */ jsx(ChevronLeft, {})
2807
+ children: /* @__PURE__ */ jsx(ChevronLeftIcon, {})
2720
2808
  }
2721
2809
  ),
2722
2810
  /* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Token Balances" })
@@ -2809,7 +2897,7 @@ function TokenSelectorView({
2809
2897
  {
2810
2898
  onClick: onBack,
2811
2899
  className: "text-muted-foreground hover:text-foreground -ml-2 flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
2812
- children: /* @__PURE__ */ jsx(ChevronLeft, {})
2900
+ children: /* @__PURE__ */ jsx(ChevronLeftIcon, {})
2813
2901
  }
2814
2902
  ),
2815
2903
  /* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Select Token" })
@@ -3104,7 +3192,1594 @@ function PrivanaButton({
3104
3192
  )
3105
3193
  ] });
3106
3194
  }
3195
+ var DEFAULT_MOONPAY_API_URL = "https://api.moonpay.com/v3";
3196
+ function useMoonpayLimits({
3197
+ currencyCode,
3198
+ baseCurrencyCode = "usd",
3199
+ paymentMethod = "credit_debit_card",
3200
+ apiBaseUrl = DEFAULT_MOONPAY_API_URL,
3201
+ enabled = true
3202
+ }) {
3203
+ const { apiKey } = useContext(MoonPayContext) ?? {};
3204
+ const canFetch = enabled && !!apiKey && !!currencyCode;
3205
+ const query = useQuery({
3206
+ queryKey: ["moonpay-limits", apiBaseUrl, currencyCode, baseCurrencyCode, paymentMethod, apiKey],
3207
+ enabled: canFetch,
3208
+ staleTime: 5 * 6e4,
3209
+ queryFn: async () => {
3210
+ const params = new URLSearchParams({
3211
+ apiKey,
3212
+ baseCurrencyCode,
3213
+ paymentMethod,
3214
+ areFeesIncluded: "true"
3215
+ });
3216
+ const res = await fetch(
3217
+ `${apiBaseUrl}/currencies/${currencyCode}/limits?${params.toString()}`
3218
+ );
3219
+ if (!res.ok) {
3220
+ throw new Error(`MoonPay limits request failed: ${res.status}`);
3221
+ }
3222
+ const data = await res.json();
3223
+ const asNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
3224
+ return {
3225
+ minBuyAmount: asNumber(data.baseCurrency?.minBuyAmount),
3226
+ maxBuyAmount: asNumber(data.baseCurrency?.maxBuyAmount)
3227
+ };
3228
+ }
3229
+ });
3230
+ return {
3231
+ minBuyAmount: query.data?.minBuyAmount,
3232
+ maxBuyAmount: query.data?.maxBuyAmount,
3233
+ isLoading: query.isLoading,
3234
+ error: query.error ?? null
3235
+ };
3236
+ }
3237
+ function TokenSelectorView2({ selectedTokenId, onSelect }) {
3238
+ const { enabledTokens } = usePrivanaContext();
3239
+ return /* @__PURE__ */ jsx("div", { className: "bg-muted flex flex-col rounded-[10px] p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex max-h-72 flex-col gap-1 overflow-y-auto", children: [
3240
+ enabledTokens.map((token) => {
3241
+ const isSelected = selectedTokenId === token.id;
3242
+ return /* @__PURE__ */ jsxs(
3243
+ "button",
3244
+ {
3245
+ type: "button",
3246
+ onClick: () => onSelect(token.id),
3247
+ className: cn(
3248
+ "hover:bg-secondary flex w-full cursor-pointer items-center gap-3 rounded-lg px-3 py-2 text-left transition-colors",
3249
+ isSelected && "bg-secondary"
3250
+ ),
3251
+ children: [
3252
+ /* @__PURE__ */ jsx("div", { className: "h-6 w-6 shrink-0 overflow-hidden rounded-full", children: getTokenIcon(token.symbol, 24) }),
3253
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
3254
+ /* @__PURE__ */ jsx("div", { className: "text-foreground text-sm font-medium", children: token.symbol }),
3255
+ /* @__PURE__ */ jsx("div", { className: "text-muted-foreground text-[11px]", children: token.name })
3256
+ ] }),
3257
+ isSelected && /* @__PURE__ */ jsx("div", { className: "bg-primary flex h-4 w-4 shrink-0 items-center justify-center rounded-full", children: /* @__PURE__ */ jsx(
3258
+ "svg",
3259
+ {
3260
+ width: "10",
3261
+ height: "10",
3262
+ viewBox: "0 0 10 10",
3263
+ fill: "none",
3264
+ className: "text-primary-foreground",
3265
+ children: /* @__PURE__ */ jsx(
3266
+ "path",
3267
+ {
3268
+ d: "M2 5L4 7L8 3",
3269
+ stroke: "currentColor",
3270
+ strokeWidth: "1.5",
3271
+ strokeLinecap: "round",
3272
+ strokeLinejoin: "round"
3273
+ }
3274
+ )
3275
+ }
3276
+ ) })
3277
+ ]
3278
+ },
3279
+ token.id
3280
+ );
3281
+ }),
3282
+ enabledTokens.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground px-3 py-6 text-center text-sm", children: "No tokens available" })
3283
+ ] }) });
3284
+ }
3285
+ function CreditCardWidgetView({
3286
+ token,
3287
+ amount,
3288
+ allowance
3289
+ }) {
3290
+ const moonpayCurrencyCode = token?.moonpayCurrencyCode;
3291
+ const containerRef = useRef(null);
3292
+ const [widgetTheme, setWidgetTheme] = useState();
3293
+ useEffect(() => {
3294
+ if (containerRef.current) setWidgetTheme(resolveSdkTheme(containerRef.current));
3295
+ }, []);
3296
+ return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: [
3297
+ /* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Complete your purchase" }),
3298
+ token && moonpayCurrencyCode ? /* @__PURE__ */ jsx(
3299
+ FiatOnRampForm,
3300
+ {
3301
+ tokenId: token.id,
3302
+ currencyCode: moonpayCurrencyCode,
3303
+ defaultBaseCurrencyAmount: amount || void 0,
3304
+ variant: "embedded",
3305
+ autoStart: true,
3306
+ theme: widgetTheme
3307
+ }
3308
+ ) : /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground text-sm", children: [
3309
+ token?.symbol ?? "This token",
3310
+ " isn\u2019t available for card purchases yet."
3311
+ ] })
3312
+ ] });
3313
+ }
3314
+ function resolveSdkTheme(el) {
3315
+ const scheme = getComputedStyle(el).colorScheme;
3316
+ if (scheme === "dark") return "dark";
3317
+ if (scheme === "light") return "light";
3318
+ return el.closest(".dark") ? "dark" : "light";
3319
+ }
3320
+ function PrivanaIcon({ className, size = 32 }) {
3321
+ return /* @__PURE__ */ jsxs(
3322
+ "svg",
3323
+ {
3324
+ width: size,
3325
+ height: size,
3326
+ viewBox: "0 0 32 32",
3327
+ fill: "none",
3328
+ xmlns: "http://www.w3.org/2000/svg",
3329
+ className,
3330
+ children: [
3331
+ /* @__PURE__ */ jsx("rect", { width: "32", height: "32", rx: "3.55556", fill: "black" }),
3332
+ /* @__PURE__ */ jsx(
3333
+ "path",
3334
+ {
3335
+ d: "M9.02789 9.05299L9.20884 7.82227H15.6221L16.1099 7.82683L16.5817 7.83825L17.0398 7.85652L17.4842 7.88163L17.9125 7.91588L18.3271 7.95698L18.7256 8.00722L19.1104 8.06202L19.4814 8.12595L19.8823 8.20815L20.2602 8.2972L20.6175 8.39538L20.9542 8.50042L21.2703 8.61687L21.5657 8.74017L21.8406 8.8726L22.0948 9.01645L22.1521 9.05299H9.02789ZM9.02789 12.0784L9.20884 10.8477H21.9505L22.1177 10.955L22.317 11.1057L22.4934 11.2633L22.6445 11.4322L22.7705 11.608L22.8713 11.793L22.9491 11.9871L22.9721 12.0784H9.02789ZM15.8167 11.0372H13.1369L13.0843 12.0784H18.8447L18.8264 12.0213L18.7645 11.9072L18.6844 11.7976L18.5836 11.6948L18.4645 11.6012L18.3271 11.5121L18.1736 11.4299L18.0041 11.3569L17.8209 11.2907L17.6193 11.2313L17.404 11.1811L17.1727 11.1354L16.9276 11.1011L16.6711 11.0737L16.3985 11.0532L16.1145 11.0418L15.8167 11.0372ZM9.02789 15.1038L9.20884 13.8731H22.7453L22.7728 13.9759L22.8003 14.1334L22.8232 14.3252L22.8163 14.5102L22.7819 14.6905L22.7178 14.8664L22.6239 15.0376L22.5735 15.1038H9.02789ZM13.1484 13.8731L13.0843 15.1038H17.5323L17.6674 15.0696L17.8644 15.0079L18.043 14.9372L18.2034 14.8618L18.3454 14.7796L18.4691 14.6883L18.5744 14.5946L18.6569 14.4942L18.721 14.3914L18.7622 14.2841L18.7828 14.1722V14.0558L18.7622 13.9348L18.7416 13.8731H13.1484ZM9.02789 18.1293L9.20884 16.8985H22.3605L22.2895 16.9899L22.1406 17.1406L21.9643 17.2867L21.7581 17.426L21.5268 17.5561L21.2703 17.6817L20.9862 17.7982L20.6747 17.9055L20.3381 18.006L19.9739 18.0996L19.8387 18.1293H9.02789ZM13.1484 16.8985L13.1392 17.0629H15.8144L16.1145 17.0607L16.3985 17.047L16.6665 17.0264L16.9207 16.999L17.1612 16.9625L17.388 16.9168L17.4658 16.8985H13.1484ZM9.02789 21.1547L9.20884 19.9217H19.7036L19.4562 19.9742L19.0989 20.0381L18.7256 20.0952L18.3316 20.1432L17.9239 20.1843L17.4956 20.2185L17.0536 20.2459L16.5932 20.2642L16.1168 20.2756L15.6243 20.2802H13.1301L13.0843 21.1547H9.02789ZM13.0843 24.1778H9.02789L9.20884 22.9471H13.1484L13.0843 24.1778Z",
3336
+ fill: "white"
3337
+ }
3338
+ )
3339
+ ]
3340
+ }
3341
+ );
3342
+ }
3343
+ function PolicyTermRow({
3344
+ term,
3345
+ kind
3346
+ }) {
3347
+ return /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
3348
+ /* @__PURE__ */ jsx(
3349
+ "div",
3350
+ {
3351
+ className: cn(
3352
+ "mt-0.5 shrink-0",
3353
+ kind === "permission" ? "text-emerald-500" : "text-orange-500"
3354
+ ),
3355
+ children: kind === "permission" ? /* @__PURE__ */ jsx(CircleCheckIcon, {}) : /* @__PURE__ */ jsx(CircleXIcon, {})
3356
+ }
3357
+ ),
3358
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3359
+ /* @__PURE__ */ jsx("span", { className: "text-foreground text-sm leading-5 font-medium", children: term.title }),
3360
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm leading-5", children: term.description })
3361
+ ] })
3362
+ ] });
3363
+ }
3364
+ function AllowancePolicySection({
3365
+ allowance,
3366
+ serviceName,
3367
+ serviceIcon
3368
+ }) {
3369
+ const [collapsed, setCollapsed] = useState(false);
3370
+ const permissions = allowance.terms?.permissions ?? [];
3371
+ const restrictions = allowance.terms?.restrictions ?? [];
3372
+ const hasTerms = permissions.length > 0 || restrictions.length > 0;
3373
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
3374
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
3375
+ /* @__PURE__ */ jsx("div", { className: "flex h-8 w-8 items-center justify-center overflow-hidden rounded-lg", children: serviceIcon }),
3376
+ /* @__PURE__ */ jsx(ArrowRightIcon, { className: "text-muted-foreground" }),
3377
+ /* @__PURE__ */ jsx(PrivanaIcon, { size: 32 })
3378
+ ] }),
3379
+ /* @__PURE__ */ jsxs("p", { className: "text-sm leading-5", children: [
3380
+ /* @__PURE__ */ jsx("span", { className: "text-foreground font-medium", children: serviceName }),
3381
+ " ",
3382
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "wants a policy on your Privana account." })
3383
+ ] }),
3384
+ hasTerms && /* @__PURE__ */ jsxs(Fragment, { children: [
3385
+ /* @__PURE__ */ jsxs(
3386
+ "button",
3387
+ {
3388
+ type: "button",
3389
+ onClick: () => setCollapsed((prev) => !prev),
3390
+ className: "flex w-full cursor-pointer items-center gap-2",
3391
+ children: [
3392
+ /* @__PURE__ */ jsx("span", { className: "bg-border h-px flex-1" }),
3393
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-[10px] leading-[14px] font-medium tracking-[0.2px] whitespace-nowrap uppercase", children: collapsed ? "Show details" : "Hide details" }),
3394
+ /* @__PURE__ */ jsx(
3395
+ ChevronDownIcon,
3396
+ {
3397
+ direction: collapsed ? "down" : "up",
3398
+ className: "text-foreground shrink-0"
3399
+ }
3400
+ ),
3401
+ /* @__PURE__ */ jsx("span", { className: "bg-border h-px flex-1" })
3402
+ ]
3403
+ }
3404
+ ),
3405
+ !collapsed && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
3406
+ permissions.map((term, i) => /* @__PURE__ */ jsx(PolicyTermRow, { term, kind: "permission" }, `permission-${i}`)),
3407
+ restrictions.map((term, i) => /* @__PURE__ */ jsx(PolicyTermRow, { term, kind: "restriction" }, `restriction-${i}`))
3408
+ ] })
3409
+ ] })
3410
+ ] });
3411
+ }
3412
+ function MoonPayGate({ enabled, children }) {
3413
+ const { networkConfig } = usePrivanaContext();
3414
+ const apiKey = networkConfig.moonpayApiKey;
3415
+ if (!enabled || !apiKey) return /* @__PURE__ */ jsx(Fragment, { children });
3416
+ return /* @__PURE__ */ jsx(MoonPayProvider, { apiKey, children });
3417
+ }
3418
+ function MethodTabs({
3419
+ activeTab,
3420
+ onTabChange
3421
+ }) {
3422
+ return /* @__PURE__ */ jsxs("div", { className: "bg-secondary relative flex gap-2 overflow-hidden rounded-[10px] p-1", children: [
3423
+ /* @__PURE__ */ jsx(
3424
+ "div",
3425
+ {
3426
+ className: cn(
3427
+ "bg-input absolute top-1 bottom-1 left-1 w-[calc(50%-8px)] rounded-md transition-transform duration-200",
3428
+ activeTab === "credit-card" && "translate-x-[calc(100%+8px)]"
3429
+ )
3430
+ }
3431
+ ),
3432
+ /* @__PURE__ */ jsx(
3433
+ "button",
3434
+ {
3435
+ type: "button",
3436
+ onClick: () => onTabChange("crypto"),
3437
+ className: cn(
3438
+ "relative z-10 flex-1 cursor-pointer rounded-md px-3 py-[9px] text-sm font-medium transition-colors",
3439
+ activeTab === "crypto" ? "text-foreground" : "text-muted-foreground"
3440
+ ),
3441
+ children: "Crypto"
3442
+ }
3443
+ ),
3444
+ /* @__PURE__ */ jsx(
3445
+ "button",
3446
+ {
3447
+ type: "button",
3448
+ onClick: () => onTabChange("credit-card"),
3449
+ className: cn(
3450
+ "relative z-10 flex-1 cursor-pointer rounded-md px-3 py-[9px] text-sm font-medium transition-colors",
3451
+ activeTab === "credit-card" ? "text-foreground" : "text-muted-foreground"
3452
+ ),
3453
+ children: "Credit Card"
3454
+ }
3455
+ )
3456
+ ] });
3457
+ }
3458
+ function MethodOption({
3459
+ title,
3460
+ description,
3461
+ onClick
3462
+ }) {
3463
+ return /* @__PURE__ */ jsxs(
3464
+ "button",
3465
+ {
3466
+ type: "button",
3467
+ onClick,
3468
+ className: "bg-input hover:bg-input/70 border-border flex w-full cursor-pointer items-center gap-3 rounded-lg border p-3 text-left transition-colors",
3469
+ children: [
3470
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
3471
+ /* @__PURE__ */ jsx("span", { className: "text-foreground text-sm leading-[14px] font-medium", children: title }),
3472
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs leading-3", children: description })
3473
+ ] }),
3474
+ /* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-5 w-5 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) })
3475
+ ]
3476
+ }
3477
+ );
3478
+ }
3479
+ function DepositView({
3480
+ source,
3481
+ selectedToken,
3482
+ amount,
3483
+ allowance,
3484
+ onAmountChange,
3485
+ onSelectToken,
3486
+ onConnectWallet,
3487
+ onSubmit,
3488
+ isSubmitting = false
3489
+ }) {
3490
+ const { getChainById: getChainById2, chains, serviceName, serviceIcon, networkConfig } = usePrivanaContext();
3491
+ const { address, isConnected } = useAccount();
3492
+ const appName = serviceName ?? "Privana";
3493
+ const chain = selectedToken ? getChainById2(selectedToken.chainId) : void 0;
3494
+ const targetChain = chain ?? chains[0];
3495
+ const sourceLabel = source === "connected" ? "Connected Wallet" : "External Wallet";
3496
+ const isConnectedSource = source === "connected";
3497
+ const isCreditCard = source === "credit-card";
3498
+ const isNative = selectedToken?.contract === zeroAddress;
3499
+ const { data: nativeBalanceData } = useBalance$1({
3500
+ address,
3501
+ chainId: targetChain?.id,
3502
+ query: { enabled: isConnectedSource && !!address && !!selectedToken && isNative }
3503
+ });
3504
+ const { data: erc20Balance } = useReadContract({
3505
+ address: selectedToken?.contract,
3506
+ abi: erc20Abi,
3507
+ functionName: "balanceOf",
3508
+ args: address ? [address] : void 0,
3509
+ chainId: targetChain?.id,
3510
+ query: { enabled: isConnectedSource && !!address && !!selectedToken && !isNative }
3511
+ });
3512
+ const walletBalance = isNative ? nativeBalanceData?.value : erc20Balance;
3513
+ const formattedWalletBalance = walletBalance != null && selectedToken ? formatTokenAmount(walletBalance.toString(), selectedToken.decimals) : "0.00";
3514
+ const {
3515
+ minBuyAmount: moonpayMinBuy,
3516
+ isLoading: moonpayLimitsLoading,
3517
+ error: moonpayLimitsError
3518
+ } = useMoonpayLimits({
3519
+ currencyCode: selectedToken?.moonpayCurrencyCode,
3520
+ apiBaseUrl: networkConfig.moonpayApiUrl,
3521
+ enabled: isCreditCard
3522
+ });
3523
+ const hasValidAmount = !!amount && parseFloat(amount) > 0;
3524
+ const maxAmountDecimals = isCreditCard ? 2 : selectedToken?.decimals;
3525
+ const tooManyDecimals = hasValidAmount && maxAmountDecimals != null && amount.includes(".") && amount.split(".")[1].length > maxAmountDecimals;
3526
+ const exceedsBalance = isConnectedSource && hasValidAmount && !tooManyDecimals && !!selectedToken && walletBalance != null && parseTokenAmount(amount, selectedToken.decimals) > walletBalance;
3527
+ const belowMoonpayMin = isCreditCard && hasValidAmount && moonpayMinBuy != null && parseFloat(amount) < moonpayMinBuy;
3528
+ const moonpayLimitsUnready = isCreditCard && !!selectedToken?.moonpayCurrencyCode && moonpayMinBuy == null;
3529
+ const creditCardUnavailable = isCreditCard && !!selectedToken && !selectedToken.moonpayCurrencyCode;
3530
+ const needsConnect = isConnectedSource && !isConnected;
3531
+ const canDeposit = hasValidAmount && !!selectedToken && !tooManyDecimals && !exceedsBalance && !belowMoonpayMin && !moonpayLimitsUnready && !creditCardUnavailable && !needsConnect;
3532
+ const handleMax = () => {
3533
+ const max = formattedWalletBalance.replace(/\s/g, "");
3534
+ if (parseFloat(max) > 0) onAmountChange(max);
3535
+ };
3536
+ return /* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: [
3537
+ isCreditCard ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
3538
+ /* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Buy with credit card and deposit" }),
3539
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "Enter your deposit amount and proceed to sign a policy." })
3540
+ ] }) : /* @__PURE__ */ jsxs("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: [
3541
+ "Deposit from ",
3542
+ sourceLabel
3543
+ ] }),
3544
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
3545
+ /* @__PURE__ */ jsx("label", { className: "text-muted-foreground text-sm", children: "Token" }),
3546
+ /* @__PURE__ */ jsxs(
3547
+ "button",
3548
+ {
3549
+ type: "button",
3550
+ onClick: onSelectToken,
3551
+ className: "border-border bg-input flex w-full cursor-pointer items-center gap-3 rounded-lg border p-3 text-left",
3552
+ children: [
3553
+ selectedToken ? /* @__PURE__ */ jsxs(Fragment, { children: [
3554
+ /* @__PURE__ */ jsx("div", { className: "h-8 w-8 shrink-0 overflow-hidden rounded-full", children: getTokenIcon(selectedToken.symbol, 32) }),
3555
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col items-start gap-1", children: [
3556
+ /* @__PURE__ */ jsx("span", { className: "text-foreground text-sm font-medium", children: selectedToken.symbol }),
3557
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-xs", children: [
3558
+ "on ",
3559
+ chain?.name ?? "\u2014"
3560
+ ] })
3561
+ ] })
3562
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground flex-1 text-sm", children: "Select token" }),
3563
+ /* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-5 w-5 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) })
3564
+ ]
3565
+ }
3566
+ )
3567
+ ] }),
3568
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
3569
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
3570
+ /* @__PURE__ */ jsx("label", { className: "text-muted-foreground text-sm", children: "Amount" }),
3571
+ isConnectedSource && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-sm", children: [
3572
+ "Available ",
3573
+ formattedWalletBalance,
3574
+ " ",
3575
+ selectedToken?.symbol
3576
+ ] })
3577
+ ] }),
3578
+ /* @__PURE__ */ jsxs(
3579
+ "div",
3580
+ {
3581
+ className: cn(
3582
+ "border-border bg-input flex items-center gap-2 rounded-[10px] border",
3583
+ isConnectedSource ? "py-1 pr-1 pl-3" : "px-3 py-3"
3584
+ ),
3585
+ children: [
3586
+ /* @__PURE__ */ jsx(
3587
+ "input",
3588
+ {
3589
+ type: "text",
3590
+ inputMode: "decimal",
3591
+ placeholder: "Enter Amount",
3592
+ value: amount,
3593
+ onChange: (e) => {
3594
+ const value = e.target.value.replace(/[^0-9.,]/g, "").replace(/,/g, ".");
3595
+ if (value.split(".").length <= 2) onAmountChange(value);
3596
+ },
3597
+ className: "text-foreground placeholder:text-muted-foreground/50 flex-1 bg-transparent text-sm outline-none"
3598
+ }
3599
+ ),
3600
+ isConnectedSource ? /* @__PURE__ */ jsx(
3601
+ "button",
3602
+ {
3603
+ type: "button",
3604
+ onClick: handleMax,
3605
+ className: "bg-secondary text-foreground hover:bg-secondary/80 cursor-pointer rounded px-3 py-2.5 text-xs font-semibold transition-colors",
3606
+ children: "MAX"
3607
+ }
3608
+ ) : isCreditCard ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: "USD" }) : selectedToken && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: selectedToken.symbol })
3609
+ ]
3610
+ }
3611
+ ),
3612
+ tooManyDecimals && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", children: [
3613
+ "Too many decimal places (max: ",
3614
+ maxAmountDecimals,
3615
+ ")"
3616
+ ] }),
3617
+ exceedsBalance && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: "Insufficient balance" }),
3618
+ belowMoonpayMin && moonpayMinBuy != null && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", children: [
3619
+ "Minimum purchase is $",
3620
+ moonpayMinBuy,
3621
+ " USD."
3622
+ ] }),
3623
+ isCreditCard && moonpayLimitsError && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: "Couldn\u2019t load purchase limits. Please try again." }),
3624
+ isCreditCard && moonpayLimitsLoading && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "Checking purchase limits\u2026" }),
3625
+ creditCardUnavailable && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", children: [
3626
+ selectedToken?.symbol ?? "This token",
3627
+ " isn\u2019t available for card purchases yet."
3628
+ ] })
3629
+ ] }),
3630
+ allowance && /* @__PURE__ */ jsx(
3631
+ AllowancePolicySection,
3632
+ {
3633
+ allowance,
3634
+ serviceName: appName,
3635
+ serviceIcon
3636
+ }
3637
+ ),
3638
+ /* @__PURE__ */ jsx(
3639
+ "button",
3640
+ {
3641
+ type: "button",
3642
+ disabled: needsConnect ? !onConnectWallet : !canDeposit || isSubmitting,
3643
+ onClick: () => {
3644
+ if (needsConnect) {
3645
+ onConnectWallet?.();
3646
+ return;
3647
+ }
3648
+ if (selectedToken) onSubmit({ source, tokenId: selectedToken.id, amount });
3649
+ },
3650
+ className: "bg-primary text-primary-foreground hover:bg-primary/90 flex h-10 w-full cursor-pointer items-center justify-center rounded-[10px] px-3 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50",
3651
+ children: needsConnect ? "Connect Wallet" : allowance ? "Sign Policy and Deposit" : "Deposit"
3652
+ }
3653
+ )
3654
+ ] });
3655
+ }
3656
+ function SummaryRow({ value, label }) {
3657
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm leading-5", children: [
3658
+ /* @__PURE__ */ jsx("span", { className: "text-foreground font-medium", children: value }),
3659
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label })
3660
+ ] });
3661
+ }
3662
+ function ExternalDepositView({
3663
+ token,
3664
+ amount
3665
+ }) {
3666
+ const { getChainById: getChainById2 } = usePrivanaContext();
3667
+ const { depositAddress, isReady, isLoading } = useDepositAddress();
3668
+ const chain = token ? getChainById2(token.chainId) : void 0;
3669
+ const [copied, setCopied] = useState(false);
3670
+ const handleCopy = () => {
3671
+ if (!depositAddress) return;
3672
+ void navigator.clipboard.writeText(depositAddress);
3673
+ setCopied(true);
3674
+ setTimeout(() => setCopied(false), 2e3);
3675
+ };
3676
+ return /* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: [
3677
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
3678
+ /* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Deposit from an External Wallet" }),
3679
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "Transfer crypto from external wallet or exchange." })
3680
+ ] }),
3681
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
3682
+ /* @__PURE__ */ jsx(SummaryRow, { value: chain?.name ?? "\u2014", label: "Chain" }),
3683
+ /* @__PURE__ */ jsx("div", { className: "bg-border h-px w-full" }),
3684
+ /* @__PURE__ */ jsx(SummaryRow, { value: token?.symbol ?? "\u2014", label: "Currency" }),
3685
+ /* @__PURE__ */ jsx("div", { className: "bg-border h-px w-full" }),
3686
+ /* @__PURE__ */ jsx(SummaryRow, { value: amount || "\u2014", label: "Value" })
3687
+ ] }),
3688
+ /* @__PURE__ */ jsx("div", { className: "bg-secondary flex h-50 items-center justify-center rounded-[10px]", children: !isReady ? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground px-6 text-center text-sm", children: "Connect your wallet to generate a deposit address." }) : depositAddress ? /* @__PURE__ */ jsx("div", { className: "rounded-[10px] bg-white p-3", children: /* @__PURE__ */ jsx(QRCodeSVG, { value: depositAddress, size: 160 }) }) : isLoading ? /* @__PURE__ */ jsx(Skeleton, { className: "h-full w-full rounded-[10px]" }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: "Deposit address unavailable" }) }),
3689
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
3690
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "Deposit Address" }),
3691
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
3692
+ /* @__PURE__ */ jsx("div", { className: "border-border flex h-10 min-w-0 flex-1 items-center rounded-[10px] border px-3", children: depositAddress ? /* @__PURE__ */ jsx("p", { className: "text-foreground min-w-0 flex-1 truncate text-sm", children: depositAddress }) : isReady && isLoading ? /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-3/4" }) : /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "\u2014" }) }),
3693
+ /* @__PURE__ */ jsxs(
3694
+ "button",
3695
+ {
3696
+ type: "button",
3697
+ onClick: handleCopy,
3698
+ disabled: !depositAddress,
3699
+ className: "bg-primary text-primary-foreground hover:bg-primary/90 flex h-10 shrink-0 cursor-pointer items-center gap-2 rounded-[10px] px-3 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50",
3700
+ children: [
3701
+ /* @__PURE__ */ jsx(CopyIcon, {}),
3702
+ copied ? "Copied" : "Copy"
3703
+ ]
3704
+ }
3705
+ )
3706
+ ] })
3707
+ ] })
3708
+ ] });
3709
+ }
3710
+ function DepositModalContent({
3711
+ defaultTab = "crypto",
3712
+ allowance,
3713
+ onSelectConnectedWallet,
3714
+ onSelectExternalWallet,
3715
+ onSelectCreditCard,
3716
+ onConnectWallet,
3717
+ onDeposit,
3718
+ onDepositSuccess,
3719
+ onClose,
3720
+ onCloseBlockedChange,
3721
+ onExit
3722
+ }) {
3723
+ const { serviceName, enabledTokens, defaultToken, hostedAuthConfig, getChainById: getChainById2 } = usePrivanaContext();
3724
+ const { address } = useAccount();
3725
+ const appName = serviceName ?? "Privana";
3726
+ const [activeTab, setActiveTab] = useState(defaultTab);
3727
+ const [view, setView] = useState("method");
3728
+ const [source, setSource] = useState("connected");
3729
+ const [selectedTokenId, setSelectedTokenId] = useState(defaultToken?.id ?? "");
3730
+ const [amount, setAmount] = useState("");
3731
+ const selectedToken = enabledTokens.find((t) => t.id === selectedTokenId) ?? defaultToken;
3732
+ const prevAddressRef = useRef(address);
3733
+ useEffect(() => {
3734
+ const prev = prevAddressRef.current;
3735
+ prevAddressRef.current = address;
3736
+ if (hostedAuthConfig) return;
3737
+ if (prev && address && prev !== address) {
3738
+ setView("method");
3739
+ setAmount("");
3740
+ setSelectedTokenId("");
3741
+ }
3742
+ }, [address, hostedAuthConfig]);
3743
+ const openDeposit = (next) => {
3744
+ setSource(next);
3745
+ setView("deposit");
3746
+ };
3747
+ const [showSuccess, setShowSuccess] = useState(false);
3748
+ const [showTimeout, setShowTimeout] = useState(false);
3749
+ const [cancelled, setCancelled] = useState(false);
3750
+ const {
3751
+ txHash,
3752
+ isGettingAddress,
3753
+ isSwitchingChain,
3754
+ isSendingTransaction,
3755
+ isWaitingForConfirmation,
3756
+ isWaitingForProcessing,
3757
+ verificationFailed,
3758
+ isPending,
3759
+ error: depositError,
3760
+ deposit,
3761
+ retryVerification,
3762
+ reset: resetDeposit
3763
+ } = useDeposit({
3764
+ onCredited: () => {
3765
+ setAmount("");
3766
+ if (onDepositSuccess) {
3767
+ resetDeposit();
3768
+ onDepositSuccess();
3769
+ } else {
3770
+ setShowSuccess(true);
3771
+ }
3772
+ },
3773
+ onCheckTimeout: () => {
3774
+ setAmount("");
3775
+ setShowTimeout(true);
3776
+ }
3777
+ });
3778
+ const isUnsafeToClose = (isGettingAddress || isSendingTransaction) && !cancelled;
3779
+ useEffect(() => {
3780
+ onCloseBlockedChange?.(isUnsafeToClose);
3781
+ }, [isUnsafeToClose, onCloseBlockedChange]);
3782
+ useEffect(() => {
3783
+ if (depositError && !verificationFailed) {
3784
+ toast.error(
3785
+ depositError.message.length > 100 ? `${depositError.message.slice(0, 100)}...` : depositError.message
3786
+ );
3787
+ }
3788
+ }, [depositError, verificationFailed]);
3789
+ const handleSubmit = (args) => {
3790
+ if (args.source === "external") {
3791
+ setView("external-deposit");
3792
+ return;
3793
+ }
3794
+ if (args.source === "credit-card") {
3795
+ setView("credit-card-widget");
3796
+ return;
3797
+ }
3798
+ const token = enabledTokens.find((t) => t.id === args.tokenId);
3799
+ if (!token) return;
3800
+ onDeposit?.(args);
3801
+ setCancelled(false);
3802
+ deposit({
3803
+ tokenId: token.id,
3804
+ amount: parseTokenAmount(args.amount, token.decimals)
3805
+ }).catch((err) => {
3806
+ toast.error(err instanceof Error ? err.message : "Deposit failed");
3807
+ });
3808
+ };
3809
+ const targetChain = selectedToken ? getChainById2(selectedToken.chainId) : void 0;
3810
+ const explorerTxUrl = txHash && targetChain?.explorerUrl ? `${targetChain.explorerUrl}/tx/${txHash}` : void 0;
3811
+ const depositSteps = [
3812
+ {
3813
+ label: "Getting deposit address",
3814
+ status: isGettingAddress ? "active" : isSwitchingChain || isSendingTransaction || isWaitingForConfirmation || isWaitingForProcessing ? "completed" : "pending"
3815
+ },
3816
+ {
3817
+ label: `Switching to ${targetChain?.name ?? "deposit chain"}`,
3818
+ status: isSwitchingChain ? "active" : isSendingTransaction || isWaitingForConfirmation || isWaitingForProcessing ? "completed" : "pending"
3819
+ },
3820
+ {
3821
+ label: "Confirm in wallet",
3822
+ status: isSendingTransaction ? "active" : isWaitingForConfirmation || isWaitingForProcessing ? "completed" : "pending"
3823
+ },
3824
+ {
3825
+ label: "Confirming transaction",
3826
+ status: isWaitingForConfirmation ? "active" : isWaitingForProcessing ? "completed" : "pending"
3827
+ },
3828
+ {
3829
+ label: "Verifying deposit \u2014 may take up to a few minutes",
3830
+ status: isWaitingForProcessing ? "active" : "pending"
3831
+ }
3832
+ ];
3833
+ const flowView = showSuccess ? "deposit-success" : showTimeout ? "deposit-timeout" : verificationFailed ? "deposit-error" : isPending && !cancelled ? "depositing" : null;
3834
+ const activeView = flowView ?? view;
3835
+ const handleDepositDone = () => {
3836
+ setShowSuccess(false);
3837
+ setShowTimeout(false);
3838
+ setCancelled(false);
3839
+ resetDeposit();
3840
+ };
3841
+ const handleDepositCancel = () => {
3842
+ setCancelled(true);
3843
+ resetDeposit();
3844
+ };
3845
+ const handleDismissVerificationError = () => {
3846
+ setAmount("");
3847
+ setCancelled(false);
3848
+ resetDeposit();
3849
+ };
3850
+ const handleRetryVerification = () => {
3851
+ retryVerification().catch(() => {
3852
+ });
3853
+ };
3854
+ const back = view === "external-deposit" ? { to: "deposit", label: "Deposit from External Wallet" } : view === "credit-card-widget" ? { to: "deposit", label: "Buy with credit card and deposit" } : view === "select-token" ? { to: "deposit", label: "Deposit" } : { to: "method", label: "Deposit Method" };
3855
+ const goBack = () => {
3856
+ if (back.to === "method") {
3857
+ setAmount("");
3858
+ setSelectedTokenId("");
3859
+ }
3860
+ setView(back.to);
3861
+ };
3862
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3863
+ onClose && /* @__PURE__ */ jsx(
3864
+ "button",
3865
+ {
3866
+ "data-privana-close": true,
3867
+ onClick: onClose,
3868
+ disabled: isUnsafeToClose,
3869
+ "aria-label": "Close",
3870
+ className: cn(
3871
+ "absolute top-6 right-5 z-20 flex h-5 w-5 items-center justify-center transition-colors",
3872
+ isUnsafeToClose ? "text-muted-foreground/40 cursor-not-allowed" : "text-muted-foreground hover:text-foreground cursor-pointer"
3873
+ ),
3874
+ children: /* @__PURE__ */ jsx(CloseIcon, {})
3875
+ }
3876
+ ),
3877
+ flowView || activeView === "method" && !onExit ? /* @__PURE__ */ jsx("div", { className: "flex items-center px-5 py-4", children: /* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-5 font-medium", children: appName }) }) : /* @__PURE__ */ jsxs(
3878
+ "button",
3879
+ {
3880
+ type: "button",
3881
+ onClick: activeView === "method" ? onExit : goBack,
3882
+ className: "text-foreground flex w-fit cursor-pointer items-center gap-2 px-5 py-4 text-sm font-medium transition-opacity hover:opacity-70",
3883
+ children: [
3884
+ /* @__PURE__ */ jsx(ChevronLeftIcon, {}),
3885
+ activeView === "method" ? appName : back.label
3886
+ ]
3887
+ }
3888
+ ),
3889
+ flowView && /* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: [
3890
+ activeView === "deposit-success" && /* @__PURE__ */ jsx(
3891
+ TransactionSuccessView,
3892
+ {
3893
+ title: "Deposit Successful",
3894
+ message: `Your ${selectedToken?.symbol ?? ""} deposit has been processed.`,
3895
+ onDone: handleDepositDone
3896
+ }
3897
+ ),
3898
+ activeView === "deposit-timeout" && /* @__PURE__ */ jsx(
3899
+ TransactionWarningView,
3900
+ {
3901
+ title: "Deposit Processing",
3902
+ message: "Your transaction was confirmed but the deposit is still being processed. Please check your balance - it should update shortly.",
3903
+ onDone: handleDepositDone
3904
+ }
3905
+ ),
3906
+ activeView === "deposit-error" && /* @__PURE__ */ jsx(
3907
+ TransactionErrorView,
3908
+ {
3909
+ title: "Verification failed",
3910
+ message: depositError?.message ? `Your transfer was sent on-chain but we could not verify the deposit. The funds are already at the deposit address \u2014 retry verification instead of starting a new deposit. (${depositError.message})` : "Your transfer was sent on-chain but we could not verify the deposit. The funds are already at the deposit address \u2014 retry verification instead of starting a new deposit.",
3911
+ explorerUrl: explorerTxUrl,
3912
+ explorerLabel: "View transaction",
3913
+ onRetry: handleRetryVerification,
3914
+ onDismiss: handleDismissVerificationError
3915
+ }
3916
+ ),
3917
+ activeView === "depositing" && /* @__PURE__ */ jsx(
3918
+ TransactionProgressView,
3919
+ {
3920
+ title: "Depositing...",
3921
+ steps: depositSteps,
3922
+ onCancel: isGettingAddress || isSendingTransaction ? handleDepositCancel : void 0
3923
+ }
3924
+ )
3925
+ ] }),
3926
+ activeView === "method" && /* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: [
3927
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
3928
+ /* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: activeTab === "crypto" ? "Choose the deposit method" : "Buy with credit card and deposit" }),
3929
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: activeTab === "crypto" ? "Choose the deposit method." : "Use credit card to buy crypto and deposit" })
3930
+ ] }),
3931
+ /* @__PURE__ */ jsx(MethodTabs, { activeTab, onTabChange: setActiveTab }),
3932
+ activeTab === "crypto" ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
3933
+ /* @__PURE__ */ jsx(
3934
+ MethodOption,
3935
+ {
3936
+ title: "Connected wallet",
3937
+ description: "Deposit from your connected wallet.",
3938
+ onClick: () => {
3939
+ onSelectConnectedWallet?.();
3940
+ openDeposit("connected");
3941
+ }
3942
+ }
3943
+ ),
3944
+ /* @__PURE__ */ jsx(
3945
+ MethodOption,
3946
+ {
3947
+ title: "External Wallet",
3948
+ description: "Send funds from external wallet or exchange.",
3949
+ onClick: () => {
3950
+ onSelectExternalWallet?.();
3951
+ openDeposit("external");
3952
+ }
3953
+ }
3954
+ )
3955
+ ] }) : /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx(
3956
+ MethodOption,
3957
+ {
3958
+ title: "Moonpay",
3959
+ description: "on selected address",
3960
+ onClick: () => {
3961
+ onSelectCreditCard?.();
3962
+ openDeposit("credit-card");
3963
+ }
3964
+ }
3965
+ ) })
3966
+ ] }),
3967
+ activeView === "deposit" && /* @__PURE__ */ jsx(MoonPayGate, { enabled: source === "credit-card", children: /* @__PURE__ */ jsx(
3968
+ DepositView,
3969
+ {
3970
+ source,
3971
+ selectedToken,
3972
+ amount,
3973
+ allowance,
3974
+ onAmountChange: setAmount,
3975
+ onSelectToken: () => setView("select-token"),
3976
+ onConnectWallet,
3977
+ onSubmit: handleSubmit,
3978
+ isSubmitting: isPending
3979
+ }
3980
+ ) }),
3981
+ activeView === "select-token" && /* @__PURE__ */ jsx(
3982
+ TokenSelectorView2,
3983
+ {
3984
+ selectedTokenId: selectedToken?.id,
3985
+ onSelect: (id) => {
3986
+ setSelectedTokenId(id);
3987
+ setView("deposit");
3988
+ }
3989
+ }
3990
+ ),
3991
+ activeView === "external-deposit" && /* @__PURE__ */ jsx(ExternalDepositView, { token: selectedToken, amount }),
3992
+ activeView === "credit-card-widget" && /* @__PURE__ */ jsx(MoonPayGate, { enabled: true, children: /* @__PURE__ */ jsx(CreditCardWidgetView, { token: selectedToken, amount, allowance }) })
3993
+ ] });
3994
+ }
3995
+ function DepositModal({ open, onClose, ...handlers }) {
3996
+ const titleId = useId();
3997
+ const descId = useId();
3998
+ const [isCloseBlocked, setIsCloseBlocked] = useState(false);
3999
+ const handleClose = () => {
4000
+ if (!isCloseBlocked) onClose();
4001
+ };
4002
+ return /* @__PURE__ */ jsx(
4003
+ Dialog,
4004
+ {
4005
+ open,
4006
+ onOpenChange: (isOpen) => {
4007
+ if (!isOpen) handleClose();
4008
+ },
4009
+ children: /* @__PURE__ */ jsxs(
4010
+ DialogContent,
4011
+ {
4012
+ "data-privana": true,
4013
+ showCloseButton: false,
4014
+ onInteractOutside: isCloseBlocked ? (e) => e.preventDefault() : void 0,
4015
+ onEscapeKeyDown: isCloseBlocked ? (e) => e.preventDefault() : void 0,
4016
+ className: "bg-card flex w-[560px] max-w-[95vw] flex-col gap-2 rounded-2xl border-0 p-2",
4017
+ "aria-labelledby": titleId,
4018
+ "aria-describedby": descId,
4019
+ children: [
4020
+ /* @__PURE__ */ jsx(DialogTitle, { id: titleId, className: "sr-only", children: "Deposit" }),
4021
+ /* @__PURE__ */ jsx(DialogDescription, { id: descId, className: "sr-only", children: "Deposit funds into your account." }),
4022
+ /* @__PURE__ */ jsx(
4023
+ DepositModalContent,
4024
+ {
4025
+ onClose: handleClose,
4026
+ onCloseBlockedChange: setIsCloseBlocked,
4027
+ ...handlers
4028
+ }
4029
+ )
4030
+ ]
4031
+ }
4032
+ )
4033
+ }
4034
+ );
4035
+ }
4036
+ function DepositInlineModal({ className, ...handlers }) {
4037
+ return /* @__PURE__ */ jsx(
4038
+ "div",
4039
+ {
4040
+ "data-privana": true,
4041
+ className: cn(
4042
+ "bg-card relative flex w-[560px] max-w-full flex-col gap-2 overflow-hidden rounded-2xl p-2 shadow-lg",
4043
+ className
4044
+ ),
4045
+ children: /* @__PURE__ */ jsx(DepositModalContent, { ...handlers })
4046
+ }
4047
+ );
4048
+ }
4049
+ function WithdrawView({
4050
+ selectedToken,
4051
+ amount,
4052
+ onAmountChange,
4053
+ onSelectToken,
4054
+ onPendingChange
4055
+ }) {
4056
+ const { chains, getChainById: getChainById2 } = usePrivanaContext();
4057
+ const { isConnected, address } = useAccount();
4058
+ const [showSuccess, setShowSuccess] = useState(false);
4059
+ const [showTimeout, setShowTimeout] = useState(false);
4060
+ const [cancelled, setCancelled] = useState(false);
4061
+ const targetChain = selectedToken ? getChainById2(selectedToken.chainId) ?? chains[0] : chains[0];
4062
+ const {
4063
+ balanceWei,
4064
+ isLoading: isBalanceLoading,
4065
+ isError: isBalanceError
4066
+ } = useBalance({
4067
+ tokenId: selectedToken?.id,
4068
+ enabled: !!selectedToken
4069
+ });
4070
+ const formattedBalance = selectedToken ? formatTokenAmount(balanceWei, selectedToken.decimals) : "0.00";
4071
+ const { withdraw, isPending, currentStep, error, reset } = useWithdraw({
4072
+ onProcessingSuccess: () => {
4073
+ onAmountChange("");
4074
+ setShowSuccess(true);
4075
+ },
4076
+ onProcessingTimeout: () => {
4077
+ onAmountChange("");
4078
+ setShowTimeout(true);
4079
+ }
4080
+ });
4081
+ const explorerUrl = address && targetChain ? getExplorerAddressUrl(targetChain.id, address) : void 0;
4082
+ const getStepStatus = (step, after) => {
4083
+ if (currentStep === step) return "active";
4084
+ if (after.includes(currentStep)) return "completed";
4085
+ return "pending";
4086
+ };
4087
+ const withdrawSteps = [
4088
+ {
4089
+ label: "Switching to signing chain",
4090
+ status: getStepStatus("switching-chain", ["signing", "submitting", "processing"])
4091
+ },
4092
+ { label: "Sign in wallet", status: getStepStatus("signing", ["submitting", "processing"]) },
4093
+ { label: "Submitting withdrawal", status: getStepStatus("submitting", ["processing"]) },
4094
+ { label: "Processing \u2014 may take a minute or two", status: getStepStatus("processing", []) }
4095
+ ];
4096
+ useEffect(() => {
4097
+ if (error) {
4098
+ toast.error(error.message.length > 100 ? `${error.message.slice(0, 100)}...` : error.message);
4099
+ }
4100
+ }, [error]);
4101
+ useEffect(() => {
4102
+ onPendingChange?.(isPending && !cancelled);
4103
+ }, [isPending, cancelled, onPendingChange]);
4104
+ const hasValidAmount = !!amount && parseFloat(amount) > 0;
4105
+ const tooManyDecimals = !!hasValidAmount && !!selectedToken && amount.includes(".") && amount.split(".")[1].length > selectedToken.decimals;
4106
+ const exceedsBalance = !!hasValidAmount && !tooManyDecimals && !!selectedToken && !isBalanceLoading && !isBalanceError && parseTokenAmount(amount, selectedToken.decimals) > BigInt(balanceWei);
4107
+ const canWithdraw = isConnected && hasValidAmount && !!selectedToken && !tooManyDecimals && !exceedsBalance;
4108
+ const handleMax = () => {
4109
+ if (!selectedToken) return;
4110
+ const max = formattedBalance.replace(/\s/g, "");
4111
+ if (parseFloat(max) > 0) onAmountChange(max);
4112
+ };
4113
+ const handleWithdraw = async () => {
4114
+ if (!selectedToken || !canWithdraw) return;
4115
+ setCancelled(false);
4116
+ await withdraw({
4117
+ tokenId: selectedToken.id,
4118
+ amount: parseTokenAmount(amount, selectedToken.decimals)
4119
+ });
4120
+ };
4121
+ const handleCancel = () => {
4122
+ setCancelled(true);
4123
+ reset();
4124
+ };
4125
+ const handleDone = () => {
4126
+ setShowSuccess(false);
4127
+ setShowTimeout(false);
4128
+ setCancelled(false);
4129
+ reset();
4130
+ };
4131
+ if (showSuccess && selectedToken) {
4132
+ return /* @__PURE__ */ jsx("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: /* @__PURE__ */ jsx(
4133
+ TransactionSuccessView,
4134
+ {
4135
+ title: "Withdrawal Complete",
4136
+ message: `Your ${selectedToken.symbol} withdrawal has been processed. Funds should appear in your wallet shortly.`,
4137
+ explorerUrl,
4138
+ explorerLabel: targetChain ? getExplorerLabel(targetChain.id) : void 0,
4139
+ onDone: handleDone
4140
+ }
4141
+ ) });
4142
+ }
4143
+ if (showTimeout) {
4144
+ return /* @__PURE__ */ jsx("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: /* @__PURE__ */ jsx(
4145
+ TransactionWarningView,
4146
+ {
4147
+ title: "Withdrawal Processing",
4148
+ message: "Your withdrawal is still being processed. Please check your balance \u2014 it should update shortly.",
4149
+ onDone: handleDone
4150
+ }
4151
+ ) });
4152
+ }
4153
+ if (isPending && !cancelled) {
4154
+ const canCancel = currentStep === "idle" || currentStep === "switching-chain" || currentStep === "signing";
4155
+ return /* @__PURE__ */ jsx("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: /* @__PURE__ */ jsx(
4156
+ TransactionProgressView,
4157
+ {
4158
+ title: "Withdrawing...",
4159
+ steps: withdrawSteps,
4160
+ onCancel: canCancel ? handleCancel : void 0
4161
+ }
4162
+ ) });
4163
+ }
4164
+ return /* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: [
4165
+ /* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Withdraw" }),
4166
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
4167
+ /* @__PURE__ */ jsx("label", { className: "text-muted-foreground text-sm", children: "Token" }),
4168
+ /* @__PURE__ */ jsxs(
4169
+ "button",
4170
+ {
4171
+ type: "button",
4172
+ onClick: onSelectToken,
4173
+ className: "border-border bg-input flex w-full cursor-pointer items-center gap-3 rounded-lg border p-3 text-left",
4174
+ children: [
4175
+ selectedToken ? /* @__PURE__ */ jsxs(Fragment, { children: [
4176
+ /* @__PURE__ */ jsx("div", { className: "h-8 w-8 shrink-0 overflow-hidden rounded-full", children: getTokenIcon(selectedToken.symbol, 32) }),
4177
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col items-start gap-1", children: [
4178
+ /* @__PURE__ */ jsx("span", { className: "text-foreground text-sm font-medium", children: selectedToken.symbol }),
4179
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-xs", children: [
4180
+ "on ",
4181
+ targetChain?.name ?? "\u2014"
4182
+ ] })
4183
+ ] })
4184
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground flex-1 text-sm", children: "Select token" }),
4185
+ /* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-5 w-5 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) })
4186
+ ]
4187
+ }
4188
+ )
4189
+ ] }),
4190
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
4191
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
4192
+ /* @__PURE__ */ jsx("label", { className: "text-muted-foreground text-sm", children: "Amount" }),
4193
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-sm", children: [
4194
+ "Available ",
4195
+ formattedBalance,
4196
+ " ",
4197
+ selectedToken?.symbol
4198
+ ] })
4199
+ ] }),
4200
+ /* @__PURE__ */ jsxs("div", { className: "border-border bg-input flex items-center gap-2 rounded-[10px] border py-1 pr-1 pl-3", children: [
4201
+ /* @__PURE__ */ jsx(
4202
+ "input",
4203
+ {
4204
+ type: "text",
4205
+ inputMode: "decimal",
4206
+ placeholder: "Enter Amount",
4207
+ value: amount,
4208
+ onChange: (e) => {
4209
+ const value = e.target.value.replace(/[^0-9.,]/g, "").replace(/,/g, ".");
4210
+ if (value.split(".").length <= 2) onAmountChange(value);
4211
+ },
4212
+ className: "text-foreground placeholder:text-muted-foreground/50 flex-1 bg-transparent text-sm outline-none"
4213
+ }
4214
+ ),
4215
+ /* @__PURE__ */ jsx(
4216
+ "button",
4217
+ {
4218
+ type: "button",
4219
+ onClick: handleMax,
4220
+ className: "bg-secondary text-foreground hover:bg-secondary/80 cursor-pointer rounded px-3 py-2.5 text-xs font-semibold transition-colors",
4221
+ children: "MAX"
4222
+ }
4223
+ )
4224
+ ] }),
4225
+ tooManyDecimals && selectedToken && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", children: [
4226
+ "Too many decimal places (max: ",
4227
+ selectedToken.decimals,
4228
+ ")"
4229
+ ] }),
4230
+ exceedsBalance && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: "Insufficient balance" })
4231
+ ] }),
4232
+ /* @__PURE__ */ jsx(
4233
+ "button",
4234
+ {
4235
+ type: "button",
4236
+ disabled: !canWithdraw,
4237
+ onClick: handleWithdraw,
4238
+ className: "bg-primary text-primary-foreground hover:bg-primary/90 flex h-10 w-full cursor-pointer items-center justify-center rounded-[10px] px-3 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50",
4239
+ children: !isConnected ? "Connect Wallet" : "Withdraw"
4240
+ }
4241
+ )
4242
+ ] });
4243
+ }
4244
+ function WithdrawModalContent({
4245
+ onClose,
4246
+ onPendingChange,
4247
+ onBack
4248
+ }) {
4249
+ const { serviceName, enabledTokens, defaultToken, hostedAuthConfig } = usePrivanaContext();
4250
+ const { address } = useAccount();
4251
+ const appName = serviceName ?? "Privana";
4252
+ const [view, setView] = useState("form");
4253
+ const [selectedTokenId, setSelectedTokenId] = useState(defaultToken?.id ?? "");
4254
+ const [amount, setAmount] = useState("");
4255
+ const [isPending, setIsPending] = useState(false);
4256
+ const handlePendingChange = (pending) => {
4257
+ setIsPending(pending);
4258
+ onPendingChange?.(pending);
4259
+ };
4260
+ const selectedToken = enabledTokens.find((t) => t.id === selectedTokenId) ?? defaultToken;
4261
+ const prevAddressRef = useRef(address);
4262
+ useEffect(() => {
4263
+ const prev = prevAddressRef.current;
4264
+ prevAddressRef.current = address;
4265
+ if (hostedAuthConfig) return;
4266
+ if (prev && address && prev !== address) {
4267
+ setView("form");
4268
+ setAmount("");
4269
+ setSelectedTokenId("");
4270
+ }
4271
+ }, [address, hostedAuthConfig]);
4272
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
4273
+ onClose && !isPending && /* @__PURE__ */ jsx(
4274
+ "button",
4275
+ {
4276
+ "data-privana-close": true,
4277
+ onClick: onClose,
4278
+ "aria-label": "Close",
4279
+ className: "text-muted-foreground hover:text-foreground absolute top-6 right-5 z-20 flex h-5 w-5 cursor-pointer items-center justify-center transition-colors",
4280
+ children: /* @__PURE__ */ jsx(CloseIcon, {})
4281
+ }
4282
+ ),
4283
+ view === "select-token" ? /* @__PURE__ */ jsxs(
4284
+ "button",
4285
+ {
4286
+ type: "button",
4287
+ onClick: () => setView("form"),
4288
+ className: "text-foreground flex w-fit cursor-pointer items-center gap-2 px-5 py-4 text-sm font-medium transition-opacity hover:opacity-70",
4289
+ children: [
4290
+ /* @__PURE__ */ jsx(ChevronLeftIcon, {}),
4291
+ "Withdraw"
4292
+ ]
4293
+ }
4294
+ ) : onBack && !isPending ? /* @__PURE__ */ jsxs(
4295
+ "button",
4296
+ {
4297
+ type: "button",
4298
+ onClick: onBack,
4299
+ className: "text-foreground flex w-fit cursor-pointer items-center gap-2 px-5 py-4 text-sm font-medium transition-opacity hover:opacity-70",
4300
+ children: [
4301
+ /* @__PURE__ */ jsx(ChevronLeftIcon, {}),
4302
+ appName
4303
+ ]
4304
+ }
4305
+ ) : /* @__PURE__ */ jsx("div", { className: "flex items-center px-5 py-4", children: /* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-5 font-medium", children: appName }) }),
4306
+ view === "form" && /* @__PURE__ */ jsx(
4307
+ WithdrawView,
4308
+ {
4309
+ selectedToken,
4310
+ amount,
4311
+ onAmountChange: setAmount,
4312
+ onSelectToken: () => setView("select-token"),
4313
+ onPendingChange: handlePendingChange
4314
+ }
4315
+ ),
4316
+ view === "select-token" && /* @__PURE__ */ jsx(
4317
+ TokenSelectorView2,
4318
+ {
4319
+ selectedTokenId: selectedToken?.id,
4320
+ onSelect: (id) => {
4321
+ setSelectedTokenId(id);
4322
+ setView("form");
4323
+ }
4324
+ }
4325
+ )
4326
+ ] });
4327
+ }
4328
+ function WithdrawModal({ open, onClose }) {
4329
+ const titleId = useId();
4330
+ const descId = useId();
4331
+ const [isCloseBlocked, setIsCloseBlocked] = useState(false);
4332
+ const handleClose = () => {
4333
+ if (!isCloseBlocked) onClose();
4334
+ };
4335
+ return /* @__PURE__ */ jsx(
4336
+ Dialog,
4337
+ {
4338
+ open,
4339
+ onOpenChange: (isOpen) => {
4340
+ if (!isOpen) handleClose();
4341
+ },
4342
+ children: /* @__PURE__ */ jsxs(
4343
+ DialogContent,
4344
+ {
4345
+ "data-privana": true,
4346
+ showCloseButton: false,
4347
+ onInteractOutside: isCloseBlocked ? (e) => e.preventDefault() : void 0,
4348
+ onEscapeKeyDown: isCloseBlocked ? (e) => e.preventDefault() : void 0,
4349
+ className: "bg-card flex w-[560px] max-w-[95vw] flex-col gap-2 rounded-2xl border-0 p-2",
4350
+ "aria-labelledby": titleId,
4351
+ "aria-describedby": descId,
4352
+ children: [
4353
+ /* @__PURE__ */ jsx(DialogTitle, { id: titleId, className: "sr-only", children: "Withdraw" }),
4354
+ /* @__PURE__ */ jsx(DialogDescription, { id: descId, className: "sr-only", children: "Withdraw funds from your account." }),
4355
+ /* @__PURE__ */ jsx(WithdrawModalContent, { onClose: handleClose, onPendingChange: setIsCloseBlocked })
4356
+ ]
4357
+ }
4358
+ )
4359
+ }
4360
+ );
4361
+ }
4362
+ function WithdrawInlineModal({ className }) {
4363
+ return /* @__PURE__ */ jsx(
4364
+ "div",
4365
+ {
4366
+ "data-privana": true,
4367
+ className: cn(
4368
+ "bg-card relative flex w-[560px] max-w-full flex-col gap-2 overflow-hidden rounded-2xl p-2 shadow-lg",
4369
+ className
4370
+ ),
4371
+ children: /* @__PURE__ */ jsx(WithdrawModalContent, {})
4372
+ }
4373
+ );
4374
+ }
4375
+ var AVAILABLE_COLOR = "bg-[#007bff]";
4376
+ var IN_USE_COLOR = "bg-[#4fc77f]";
4377
+ function toInUseWei(value) {
4378
+ let parsed;
4379
+ try {
4380
+ parsed = typeof value === "bigint" ? value : BigInt(value);
4381
+ } catch {
4382
+ console.warn(`[privana-sdk] Invalid session.inUse value: ${value}`);
4383
+ return 0n;
4384
+ }
4385
+ if (parsed < 0n) {
4386
+ console.warn(`[privana-sdk] Negative session.inUse value: ${value}`);
4387
+ return 0n;
4388
+ }
4389
+ return parsed;
4390
+ }
4391
+ function useNow(intervalMs, enabled) {
4392
+ const [, setTick] = useState(0);
4393
+ useEffect(() => {
4394
+ if (!enabled) return;
4395
+ const id = setInterval(() => setTick((t) => t + 1), intervalMs);
4396
+ return () => clearInterval(id);
4397
+ }, [intervalMs, enabled]);
4398
+ }
4399
+ function SegmentedBalanceBar({
4400
+ availableWei,
4401
+ inUseWei
4402
+ }) {
4403
+ const total = availableWei + inUseWei;
4404
+ const showAvailable = inUseWei === 0n || availableWei > 0n;
4405
+ const showInUse = inUseWei > 0n;
4406
+ const grow = (part) => total > 0n ? Number(part * 1000n / total) : 1;
4407
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-1.5 w-full", children: [
4408
+ showAvailable && /* @__PURE__ */ jsx(
4409
+ "div",
4410
+ {
4411
+ className: cn(AVAILABLE_COLOR, "rounded-l-full", !showInUse && "rounded-r-full"),
4412
+ style: { flexGrow: grow(availableWei) }
4413
+ }
4414
+ ),
4415
+ showInUse && /* @__PURE__ */ jsx(
4416
+ "div",
4417
+ {
4418
+ className: cn(IN_USE_COLOR, "rounded-r-full", !showAvailable && "rounded-l-full"),
4419
+ style: { flexGrow: grow(inUseWei) }
4420
+ }
4421
+ )
4422
+ ] });
4423
+ }
4424
+ function BalanceLegendItem({ color, label }) {
4425
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
4426
+ /* @__PURE__ */ jsx("span", { className: cn("h-2.5 w-2.5 rounded-full", color) }),
4427
+ /* @__PURE__ */ jsx("span", { className: "text-foreground text-sm leading-5", children: label })
4428
+ ] });
4429
+ }
4430
+ function WalletBalanceView({
4431
+ session,
4432
+ allowance,
4433
+ amount,
4434
+ onAmountChange,
4435
+ onPlay,
4436
+ onAddFunds,
4437
+ onWithdraw
4438
+ }) {
4439
+ const { serviceName, serviceIcon, defaultToken } = usePrivanaContext();
4440
+ const appName = serviceName ?? "Privana";
4441
+ const token = defaultToken;
4442
+ const {
4443
+ balanceWei,
4444
+ isLoading: isBalanceLoading,
4445
+ isError: isBalanceError
4446
+ } = useBalance({ tokenId: token?.id, enabled: !!token });
4447
+ const inUseWei = session ? toInUseWei(session.inUse) : 0n;
4448
+ const availableWei = BigInt(balanceWei);
4449
+ const variant = !session ? "idle" : inUseWei === 0n ? "session-zero" : availableWei === 0n ? "fully-in-use" : "mixed";
4450
+ const expiry = session?.expiry;
4451
+ useNow(3e4, expiry != null);
4452
+ const countdown = expiry != null ? formatTimeRemaining(expiry) : null;
4453
+ const decimals = token?.decimals ?? 18;
4454
+ const totalFormatted = formatTokenAmount((availableWei + inUseWei).toString(), decimals);
4455
+ const availableFormatted = formatTokenAmount(availableWei.toString(), decimals);
4456
+ const inUseFormatted = formatTokenAmount(inUseWei.toString(), decimals);
4457
+ const hasValidAmount = !!amount && parseFloat(amount) > 0;
4458
+ const tooManyDecimals = hasValidAmount && !!token && amount.includes(".") && amount.split(".")[1].length > token.decimals;
4459
+ const exceedsBalance = hasValidAmount && !tooManyDecimals && !!token && !isBalanceLoading && !isBalanceError && parseTokenAmount(amount, token.decimals) > availableWei;
4460
+ const canPlay = hasValidAmount && !!token && !tooManyDecimals && !exceedsBalance && !isBalanceLoading && !isBalanceError;
4461
+ const handleMax = () => {
4462
+ const max = availableFormatted.replace(/\s/g, "");
4463
+ if (parseFloat(max) > 0) onAmountChange(max);
4464
+ };
4465
+ const handlePlay = () => {
4466
+ if (!token || !canPlay || !onPlay) return;
4467
+ onPlay({ tokenId: token.id, amount });
4468
+ onAmountChange("");
4469
+ };
4470
+ const showInput = variant !== "fully-in-use";
4471
+ const showInlinePlay = variant === "session-zero" || variant === "mixed";
4472
+ return /* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: [
4473
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
4474
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
4475
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm leading-[14px]", children: "Total" }),
4476
+ /* @__PURE__ */ jsx("span", { className: "bg-secondary text-muted-foreground rounded-full px-2 py-[5px] text-[10px] leading-[10px] font-bold", children: token?.symbol ?? "\u2014" })
4477
+ ] }),
4478
+ isBalanceLoading ? /* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-40" }) : isBalanceError ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-[32px] leading-9 font-medium", children: "\u2014" }) : /* @__PURE__ */ jsx("span", { className: "text-foreground text-[32px] leading-9 font-medium", children: totalFormatted })
4479
+ ] }),
4480
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
4481
+ /* @__PURE__ */ jsx(SegmentedBalanceBar, { availableWei, inUseWei }),
4482
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
4483
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: variant === "fully-in-use" ? /* @__PURE__ */ jsx(BalanceLegendItem, { color: IN_USE_COLOR, label: "In use" }) : variant === "mixed" ? /* @__PURE__ */ jsxs(Fragment, { children: [
4484
+ /* @__PURE__ */ jsx(
4485
+ BalanceLegendItem,
4486
+ {
4487
+ color: AVAILABLE_COLOR,
4488
+ label: `Available (${availableFormatted})`
4489
+ }
4490
+ ),
4491
+ /* @__PURE__ */ jsx(BalanceLegendItem, { color: IN_USE_COLOR, label: `In use (${inUseFormatted})` })
4492
+ ] }) : /* @__PURE__ */ jsx(BalanceLegendItem, { color: AVAILABLE_COLOR, label: "Available" }) }),
4493
+ countdown && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm leading-5 whitespace-nowrap", children: countdown })
4494
+ ] })
4495
+ ] }),
4496
+ showInput && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
4497
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
4498
+ /* @__PURE__ */ jsxs("div", { className: "border-border bg-input flex h-10 flex-1 items-center gap-2 rounded-[10px] border py-1 pr-1 pl-3", children: [
4499
+ /* @__PURE__ */ jsx(
4500
+ "input",
4501
+ {
4502
+ type: "text",
4503
+ inputMode: "decimal",
4504
+ placeholder: "Enter Amount",
4505
+ value: amount,
4506
+ onChange: (e) => {
4507
+ const value = e.target.value.replace(/[^0-9.,]/g, "").replace(/,/g, ".");
4508
+ if (value.split(".").length <= 2) onAmountChange(value);
4509
+ },
4510
+ className: "text-foreground placeholder:text-muted-foreground/50 min-w-0 flex-1 bg-transparent text-sm outline-none"
4511
+ }
4512
+ ),
4513
+ /* @__PURE__ */ jsx(
4514
+ "button",
4515
+ {
4516
+ type: "button",
4517
+ onClick: handleMax,
4518
+ className: "text-foreground cursor-pointer rounded px-3 py-2.5 text-xs font-semibold",
4519
+ children: "MAX"
4520
+ }
4521
+ )
4522
+ ] }),
4523
+ showInlinePlay && /* @__PURE__ */ jsx(
4524
+ "button",
4525
+ {
4526
+ type: "button",
4527
+ disabled: !onPlay || !canPlay,
4528
+ onClick: handlePlay,
4529
+ className: "border-border flex h-10 min-w-20 cursor-pointer items-center justify-center rounded-[10px] border px-3 text-sm font-medium text-[#4fc77f] transition-opacity hover:opacity-80 disabled:cursor-not-allowed disabled:opacity-50",
4530
+ children: "Play"
4531
+ }
4532
+ )
4533
+ ] }),
4534
+ tooManyDecimals && token && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", children: [
4535
+ "Too many decimal places (max: ",
4536
+ token.decimals,
4537
+ ")"
4538
+ ] }),
4539
+ exceedsBalance && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: "Insufficient balance" })
4540
+ ] }),
4541
+ variant === "idle" && allowance && /* @__PURE__ */ jsx("div", { className: "bg-muted rounded-[10px] p-4", children: /* @__PURE__ */ jsx(
4542
+ AllowancePolicySection,
4543
+ {
4544
+ allowance,
4545
+ serviceName: appName,
4546
+ serviceIcon
4547
+ }
4548
+ ) }),
4549
+ /* @__PURE__ */ jsx("div", { className: "flex items-start gap-4", children: variant === "idle" ? /* @__PURE__ */ jsxs(Fragment, { children: [
4550
+ /* @__PURE__ */ jsx(
4551
+ "button",
4552
+ {
4553
+ type: "button",
4554
+ disabled: !onPlay || !canPlay,
4555
+ onClick: handlePlay,
4556
+ className: "bg-primary text-primary-foreground hover:bg-primary/90 flex h-10 flex-1 cursor-pointer items-center justify-center rounded-[10px] px-3 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50",
4557
+ children: "Play"
4558
+ }
4559
+ ),
4560
+ /* @__PURE__ */ jsx(
4561
+ "button",
4562
+ {
4563
+ type: "button",
4564
+ disabled: !onAddFunds,
4565
+ onClick: onAddFunds,
4566
+ className: "bg-secondary text-foreground hover:bg-secondary/80 flex h-10 flex-1 cursor-pointer items-center justify-center rounded-[10px] px-3 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50",
4567
+ children: "Add funds"
4568
+ }
4569
+ )
4570
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4571
+ /* @__PURE__ */ jsx(
4572
+ "button",
4573
+ {
4574
+ type: "button",
4575
+ disabled: !onAddFunds,
4576
+ onClick: onAddFunds,
4577
+ className: "bg-primary text-primary-foreground hover:bg-primary/90 flex h-10 flex-1 cursor-pointer items-center justify-center rounded-[10px] px-3 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50",
4578
+ children: "Add Funds"
4579
+ }
4580
+ ),
4581
+ /* @__PURE__ */ jsx(
4582
+ "button",
4583
+ {
4584
+ type: "button",
4585
+ disabled: !onWithdraw,
4586
+ onClick: onWithdraw,
4587
+ className: "bg-secondary text-foreground hover:bg-secondary/80 flex h-10 flex-1 cursor-pointer items-center justify-center rounded-[10px] px-3 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50",
4588
+ children: "Withdraw"
4589
+ }
4590
+ )
4591
+ ] }) })
4592
+ ] });
4593
+ }
4594
+ function WalletModalContent({
4595
+ session,
4596
+ allowance,
4597
+ onPlay,
4598
+ onEndSession,
4599
+ onDepositSuccess,
4600
+ onClose,
4601
+ onCloseBlockedChange,
4602
+ ...depositHandlers
4603
+ }) {
4604
+ const { serviceName, hostedAuthConfig } = usePrivanaContext();
4605
+ const { address } = useAccount();
4606
+ const appName = serviceName ?? "Privana";
4607
+ const [view, setView] = useState("balance");
4608
+ const [amount, setAmount] = useState("");
4609
+ const [depositBlocked, setDepositBlocked] = useState(false);
4610
+ const [withdrawPending, setWithdrawPending] = useState(false);
4611
+ const [endSessionError, setEndSessionError] = useState(null);
4612
+ const endSessionRunRef = useRef(0);
4613
+ const prevAddressRef = useRef(address);
4614
+ useEffect(() => {
4615
+ const prev = prevAddressRef.current;
4616
+ prevAddressRef.current = address;
4617
+ if (hostedAuthConfig) return;
4618
+ if (prev && address && prev !== address) {
4619
+ setView("balance");
4620
+ setAmount("");
4621
+ setDepositBlocked(false);
4622
+ setWithdrawPending(false);
4623
+ setEndSessionError(null);
4624
+ endSessionRunRef.current++;
4625
+ }
4626
+ }, [address, hostedAuthConfig]);
4627
+ const closeBlocked = depositBlocked || withdrawPending || view === "ending-session";
4628
+ useEffect(() => {
4629
+ onCloseBlockedChange?.(closeBlocked);
4630
+ }, [closeBlocked, onCloseBlockedChange]);
4631
+ const exitDeposit = () => {
4632
+ setDepositBlocked(false);
4633
+ setView("balance");
4634
+ };
4635
+ const exitWithdraw = () => {
4636
+ setWithdrawPending(false);
4637
+ setView("balance");
4638
+ };
4639
+ const startEndSession = () => {
4640
+ if (!onEndSession) return;
4641
+ const run = ++endSessionRunRef.current;
4642
+ setEndSessionError(null);
4643
+ setView("ending-session");
4644
+ Promise.resolve().then(() => onEndSession()).then(
4645
+ () => {
4646
+ if (endSessionRunRef.current !== run) return;
4647
+ setView("withdraw");
4648
+ },
4649
+ (err) => {
4650
+ if (endSessionRunRef.current !== run) return;
4651
+ setEndSessionError(err instanceof Error ? err.message : null);
4652
+ setView("end-session-error");
4653
+ }
4654
+ );
4655
+ };
4656
+ const handleWithdraw = () => {
4657
+ if (session && onEndSession) {
4658
+ startEndSession();
4659
+ } else {
4660
+ setView("withdraw");
4661
+ }
4662
+ };
4663
+ const dismissEndSessionError = () => {
4664
+ endSessionRunRef.current++;
4665
+ setEndSessionError(null);
4666
+ setView("balance");
4667
+ };
4668
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
4669
+ onClose && /* @__PURE__ */ jsx(
4670
+ "button",
4671
+ {
4672
+ "data-privana-close": true,
4673
+ onClick: onClose,
4674
+ disabled: closeBlocked,
4675
+ "aria-label": "Close",
4676
+ className: cn(
4677
+ "absolute top-6 right-5 z-20 flex h-5 w-5 items-center justify-center transition-colors",
4678
+ closeBlocked ? "text-muted-foreground/40 cursor-not-allowed" : "text-muted-foreground hover:text-foreground cursor-pointer"
4679
+ ),
4680
+ children: /* @__PURE__ */ jsx(CloseIcon, {})
4681
+ }
4682
+ ),
4683
+ (view === "balance" || view === "ending-session" || view === "end-session-error") && /* @__PURE__ */ jsx("div", { className: "flex items-center px-5 py-4", children: /* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-5 font-medium", children: appName }) }),
4684
+ view === "balance" && /* @__PURE__ */ jsx(
4685
+ WalletBalanceView,
4686
+ {
4687
+ session,
4688
+ allowance,
4689
+ amount,
4690
+ onAmountChange: setAmount,
4691
+ onPlay,
4692
+ onAddFunds: () => setView("deposit"),
4693
+ onWithdraw: handleWithdraw
4694
+ }
4695
+ ),
4696
+ view === "ending-session" && /* @__PURE__ */ jsx("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: /* @__PURE__ */ jsx(
4697
+ TransactionProgressView,
4698
+ {
4699
+ title: "Ending game session...",
4700
+ steps: [{ label: "Waiting for the game session to settle", status: "active" }]
4701
+ }
4702
+ ) }),
4703
+ view === "end-session-error" && /* @__PURE__ */ jsx("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: /* @__PURE__ */ jsx(
4704
+ TransactionErrorView,
4705
+ {
4706
+ title: "Could not end session",
4707
+ message: endSessionError ? `Your game session could not be ended, so the funds committed to it are not available to withdraw yet. (${endSessionError})` : "Your game session could not be ended, so the funds committed to it are not available to withdraw yet.",
4708
+ onRetry: startEndSession,
4709
+ onDismiss: dismissEndSessionError
4710
+ }
4711
+ ) }),
4712
+ view === "withdraw" && /* @__PURE__ */ jsx(WithdrawModalContent, { onBack: exitWithdraw, onPendingChange: setWithdrawPending }),
4713
+ view === "deposit" && /* @__PURE__ */ jsx(
4714
+ DepositModalContent,
4715
+ {
4716
+ ...depositHandlers,
4717
+ allowance,
4718
+ onExit: exitDeposit,
4719
+ onCloseBlockedChange: setDepositBlocked,
4720
+ onDepositSuccess: () => {
4721
+ exitDeposit();
4722
+ onDepositSuccess?.();
4723
+ }
4724
+ }
4725
+ )
4726
+ ] });
4727
+ }
4728
+ function WalletModal({ open, onClose, ...handlers }) {
4729
+ const titleId = useId();
4730
+ const descId = useId();
4731
+ const [isCloseBlocked, setIsCloseBlocked] = useState(false);
4732
+ const handleClose = () => {
4733
+ if (!isCloseBlocked) onClose();
4734
+ };
4735
+ return /* @__PURE__ */ jsx(
4736
+ Dialog,
4737
+ {
4738
+ open,
4739
+ onOpenChange: (isOpen) => {
4740
+ if (!isOpen) handleClose();
4741
+ },
4742
+ children: /* @__PURE__ */ jsxs(
4743
+ DialogContent,
4744
+ {
4745
+ "data-privana": true,
4746
+ showCloseButton: false,
4747
+ onInteractOutside: isCloseBlocked ? (e) => e.preventDefault() : void 0,
4748
+ onEscapeKeyDown: isCloseBlocked ? (e) => e.preventDefault() : void 0,
4749
+ className: "bg-card flex w-[560px] max-w-[95vw] flex-col gap-2 rounded-2xl border-0 p-2",
4750
+ "aria-labelledby": titleId,
4751
+ "aria-describedby": descId,
4752
+ children: [
4753
+ /* @__PURE__ */ jsx(DialogTitle, { id: titleId, className: "sr-only", children: "Wallet" }),
4754
+ /* @__PURE__ */ jsx(DialogDescription, { id: descId, className: "sr-only", children: "Manage your account balance." }),
4755
+ /* @__PURE__ */ jsx(
4756
+ WalletModalContent,
4757
+ {
4758
+ onClose: handleClose,
4759
+ onCloseBlockedChange: setIsCloseBlocked,
4760
+ ...handlers
4761
+ }
4762
+ )
4763
+ ]
4764
+ }
4765
+ )
4766
+ }
4767
+ );
4768
+ }
4769
+ function WalletInlineModal({ className, ...handlers }) {
4770
+ return /* @__PURE__ */ jsx(
4771
+ "div",
4772
+ {
4773
+ "data-privana": true,
4774
+ className: cn(
4775
+ "bg-card relative flex w-[560px] max-w-full flex-col gap-2 overflow-hidden rounded-2xl p-2 shadow-lg",
4776
+ className
4777
+ ),
4778
+ children: /* @__PURE__ */ jsx(WalletModalContent, { ...handlers })
4779
+ }
4780
+ );
4781
+ }
3107
4782
 
3108
- export { LOCK_TYPES, MODIFY_LOCK_TYPES, PrivanaButton, PrivanaInlineModal, PrivanaModal, TRANSFER_LOCKED_TYPES, TRANSFER_TYPES, WITHDRAW_FROM_LOCK_TYPES, WITHDRAW_TYPES, createDomain, createLockExpiry, getChainIcon, getTokenIcon, signLockMessage, signModifyLockMessage, signTransferLockedMessage, signTransferMessage, signWithdrawFromLockMessage, signWithdrawMessage, useBalance, useBatchBalances, useDeposit, useExpiredLocks, useHistory, useHostedRedirectAuth, useLockFunds, useLockedFunds, useModifyLock, usePendingWithdrawals, usePrivanaClient, useTokenInfo, useTokenList, useTotalLockedBalance, useTransfer, useUnlockFunds, useWithdraw };
4783
+ export { DepositInlineModal, DepositModal, LOCK_TYPES, MODIFY_LOCK_TYPES, PrivanaButton, PrivanaIcon, PrivanaInlineModal, PrivanaModal, TRANSFER_LOCKED_TYPES, TRANSFER_TYPES, WITHDRAW_FROM_LOCK_TYPES, WITHDRAW_TYPES, WalletInlineModal, WalletModal, WithdrawInlineModal, WithdrawModal, createDomain, createLockExpiry, getChainIcon, getTokenIcon, signLockMessage, signModifyLockMessage, signTransferLockedMessage, signTransferMessage, signWithdrawFromLockMessage, signWithdrawMessage, useBalance, useBatchBalances, useDeposit, useDepositAddress, useExpiredLocks, useHistory, useHostedRedirectAuth, useLockFunds, useLockedFunds, useModifyLock, usePendingWithdrawals, usePrivanaClient, useTokenInfo, useTokenList, useTotalLockedBalance, useTransfer, useUnlockFunds, useWithdraw };
3109
4784
  //# sourceMappingURL=index.js.map
3110
4785
  //# sourceMappingURL=index.js.map