@b3dotfun/sdk 0.0.30 → 0.0.31

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 (150) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpend.js +1 -1
  2. package/dist/cjs/anyspend/react/components/AnySpendBuySpin.js +2 -1
  3. package/dist/cjs/anyspend/react/components/AnySpendStakeB3.js +2 -1
  4. package/dist/cjs/anyspend/react/components/AnyspendDepositHype.d.ts +4 -0
  5. package/dist/cjs/anyspend/react/components/AnyspendDepositHype.js +6 -1
  6. package/dist/cjs/anyspend/react/components/common/ChainTokenIcon.d.ts +1 -1
  7. package/dist/cjs/anyspend/react/components/common/ChainTokenIcon.js +2 -1
  8. package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +23 -28
  9. package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.d.ts +3 -1
  10. package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.js +2 -2
  11. package/dist/cjs/anyspend/react/components/common/OrderDetails.js +5 -5
  12. package/dist/cjs/anyspend/react/components/common/OrderTokenAmount.js +1 -1
  13. package/dist/cjs/anyspend/react/components/common/PanelOnramp.d.ts +4 -1
  14. package/dist/cjs/anyspend/react/components/common/PanelOnramp.js +3 -3
  15. package/dist/cjs/anyspend/react/components/common/PaySection.js +1 -1
  16. package/dist/cjs/global-account/react/components/B3DynamicModal.js +2 -5
  17. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.js +5 -0
  18. package/dist/cjs/global-account/react/components/LinkAccount/LinkAccount.js +1 -0
  19. package/dist/cjs/global-account/react/components/ManageAccount/BalanceContent.d.ts +6 -0
  20. package/dist/cjs/global-account/react/components/ManageAccount/BalanceContent.js +94 -0
  21. package/dist/cjs/global-account/react/components/ManageAccount/ContentTokens.d.ts +14 -0
  22. package/dist/cjs/global-account/react/components/ManageAccount/ContentTokens.js +272 -0
  23. package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.js +9 -51
  24. package/dist/cjs/global-account/react/components/ManageAccount/TokenBalanceRow.d.ts +10 -0
  25. package/dist/cjs/global-account/react/components/ManageAccount/TokenBalanceRow.js +8 -0
  26. package/dist/cjs/global-account/react/components/TokenIcon.d.ts +11 -0
  27. package/dist/cjs/global-account/react/components/TokenIcon.js +43 -0
  28. package/dist/cjs/global-account/react/components/ui/accordion.d.ts +7 -0
  29. package/dist/cjs/global-account/react/components/ui/accordion.js +53 -0
  30. package/dist/cjs/global-account/react/components/ui/dialog.js +1 -1
  31. package/dist/cjs/global-account/react/hooks/index.d.ts +2 -0
  32. package/dist/cjs/global-account/react/hooks/index.js +5 -1
  33. package/dist/cjs/global-account/react/hooks/useAnalytics.d.ts +7 -0
  34. package/dist/cjs/global-account/react/hooks/useAnalytics.js +29 -0
  35. package/dist/cjs/global-account/react/hooks/useB3BalanceFromAddresses.js +2 -1
  36. package/dist/cjs/global-account/react/hooks/useNativeBalance.js +2 -1
  37. package/dist/cjs/global-account/react/hooks/useSimBalance.d.ts +24 -0
  38. package/dist/cjs/global-account/react/hooks/useSimBalance.js +29 -0
  39. package/dist/cjs/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +2 -1
  40. package/dist/cjs/global-account/react/stores/useModalStore.d.ts +2 -2
  41. package/dist/cjs/global-account/react/utils/profileDisplay.js +9 -0
  42. package/dist/cjs/global-account/utils/analytics.d.ts +16 -0
  43. package/dist/cjs/global-account/utils/analytics.js +55 -0
  44. package/dist/cjs/shared/constants/index.d.ts +1 -0
  45. package/dist/cjs/shared/constants/index.js +2 -1
  46. package/dist/cjs/shared/generated/chain-networks.json +185 -17
  47. package/dist/esm/anyspend/react/components/AnySpend.js +1 -1
  48. package/dist/esm/anyspend/react/components/AnySpendBuySpin.js +2 -1
  49. package/dist/esm/anyspend/react/components/AnySpendStakeB3.js +2 -1
  50. package/dist/esm/anyspend/react/components/AnyspendDepositHype.d.ts +4 -0
  51. package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +5 -1
  52. package/dist/esm/anyspend/react/components/common/ChainTokenIcon.d.ts +1 -1
  53. package/dist/esm/anyspend/react/components/common/ChainTokenIcon.js +2 -1
  54. package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +22 -27
  55. package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.d.ts +3 -1
  56. package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.js +2 -2
  57. package/dist/esm/anyspend/react/components/common/OrderDetails.js +5 -5
  58. package/dist/esm/anyspend/react/components/common/OrderTokenAmount.js +1 -1
  59. package/dist/esm/anyspend/react/components/common/PanelOnramp.d.ts +4 -1
  60. package/dist/esm/anyspend/react/components/common/PanelOnramp.js +4 -4
  61. package/dist/esm/anyspend/react/components/common/PaySection.js +1 -1
  62. package/dist/esm/global-account/react/components/B3DynamicModal.js +2 -5
  63. package/dist/esm/global-account/react/components/B3Provider/B3Provider.js +5 -0
  64. package/dist/esm/global-account/react/components/LinkAccount/LinkAccount.js +1 -0
  65. package/dist/esm/global-account/react/components/ManageAccount/BalanceContent.d.ts +6 -0
  66. package/dist/esm/global-account/react/components/ManageAccount/BalanceContent.js +88 -0
  67. package/dist/esm/global-account/react/components/ManageAccount/ContentTokens.d.ts +14 -0
  68. package/dist/esm/global-account/react/components/ManageAccount/ContentTokens.js +266 -0
  69. package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.js +12 -51
  70. package/dist/esm/global-account/react/components/ManageAccount/TokenBalanceRow.d.ts +10 -0
  71. package/dist/esm/global-account/react/components/ManageAccount/TokenBalanceRow.js +5 -0
  72. package/dist/esm/global-account/react/components/TokenIcon.d.ts +11 -0
  73. package/dist/esm/global-account/react/components/TokenIcon.js +37 -0
  74. package/dist/esm/global-account/react/components/ui/accordion.d.ts +7 -0
  75. package/dist/esm/global-account/react/components/ui/accordion.js +14 -0
  76. package/dist/esm/global-account/react/components/ui/dialog.js +1 -1
  77. package/dist/esm/global-account/react/hooks/index.d.ts +2 -0
  78. package/dist/esm/global-account/react/hooks/index.js +2 -0
  79. package/dist/esm/global-account/react/hooks/useAnalytics.d.ts +7 -0
  80. package/dist/esm/global-account/react/hooks/useAnalytics.js +26 -0
  81. package/dist/esm/global-account/react/hooks/useB3BalanceFromAddresses.js +2 -1
  82. package/dist/esm/global-account/react/hooks/useNativeBalance.js +2 -1
  83. package/dist/esm/global-account/react/hooks/useSimBalance.d.ts +24 -0
  84. package/dist/esm/global-account/react/hooks/useSimBalance.js +26 -0
  85. package/dist/esm/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +2 -1
  86. package/dist/esm/global-account/react/stores/useModalStore.d.ts +2 -2
  87. package/dist/esm/global-account/react/utils/profileDisplay.js +9 -0
  88. package/dist/esm/global-account/utils/analytics.d.ts +16 -0
  89. package/dist/esm/global-account/utils/analytics.js +50 -0
  90. package/dist/esm/shared/constants/index.d.ts +1 -0
  91. package/dist/esm/shared/constants/index.js +1 -0
  92. package/dist/esm/shared/generated/chain-networks.json +185 -17
  93. package/dist/styles/index.css +1 -1
  94. package/dist/types/anyspend/react/components/AnyspendDepositHype.d.ts +4 -0
  95. package/dist/types/anyspend/react/components/common/ChainTokenIcon.d.ts +1 -1
  96. package/dist/types/anyspend/react/components/common/CryptoReceiveSection.d.ts +3 -1
  97. package/dist/types/anyspend/react/components/common/PanelOnramp.d.ts +4 -1
  98. package/dist/types/global-account/react/components/ManageAccount/BalanceContent.d.ts +6 -0
  99. package/dist/types/global-account/react/components/ManageAccount/ContentTokens.d.ts +14 -0
  100. package/dist/types/global-account/react/components/ManageAccount/TokenBalanceRow.d.ts +10 -0
  101. package/dist/types/global-account/react/components/TokenIcon.d.ts +11 -0
  102. package/dist/types/global-account/react/components/ui/accordion.d.ts +7 -0
  103. package/dist/types/global-account/react/hooks/index.d.ts +2 -0
  104. package/dist/types/global-account/react/hooks/useAnalytics.d.ts +7 -0
  105. package/dist/types/global-account/react/hooks/useSimBalance.d.ts +24 -0
  106. package/dist/types/global-account/react/stores/useModalStore.d.ts +2 -2
  107. package/dist/types/global-account/utils/analytics.d.ts +16 -0
  108. package/dist/types/shared/constants/index.d.ts +1 -0
  109. package/package.json +10 -18
  110. package/src/anyspend/react/components/AnySpend.tsx +1 -0
  111. package/src/anyspend/react/components/AnySpendBuySpin.tsx +2 -1
  112. package/src/anyspend/react/components/AnySpendStakeB3.tsx +3 -2
  113. package/src/anyspend/react/components/AnyspendDepositHype.tsx +10 -0
  114. package/src/anyspend/react/components/AnyspendSignatureMint.tsx +4 -4
  115. package/src/anyspend/react/components/common/ChainTokenIcon.tsx +8 -2
  116. package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +56 -107
  117. package/src/anyspend/react/components/common/CryptoReceiveSection.tsx +12 -3
  118. package/src/anyspend/react/components/common/OrderDetails.tsx +5 -5
  119. package/src/anyspend/react/components/common/OrderTokenAmount.tsx +2 -2
  120. package/src/anyspend/react/components/common/PanelOnramp.tsx +11 -5
  121. package/src/anyspend/react/components/common/PaySection.tsx +1 -1
  122. package/src/global-account/react/components/B3DynamicModal.tsx +8 -7
  123. package/src/global-account/react/components/B3Provider/B3Provider.tsx +6 -0
  124. package/src/global-account/react/components/LinkAccount/LinkAccount.tsx +2 -1
  125. package/src/global-account/react/components/ManageAccount/BalanceContent.tsx +228 -0
  126. package/src/global-account/react/components/ManageAccount/ContentTokens.tsx +568 -0
  127. package/src/global-account/react/components/ManageAccount/ManageAccount.tsx +86 -341
  128. package/src/global-account/react/components/ManageAccount/TokenBalanceRow.tsx +46 -0
  129. package/src/global-account/react/components/TokenIcon.tsx +87 -0
  130. package/src/global-account/react/components/ui/accordion.tsx +53 -0
  131. package/src/global-account/react/components/ui/dialog.tsx +1 -1
  132. package/src/global-account/react/hooks/index.ts +2 -0
  133. package/src/global-account/react/hooks/useAccountAssets.ts +1 -0
  134. package/src/global-account/react/hooks/useAnalytics.tsx +30 -0
  135. package/src/global-account/react/hooks/useB3BalanceFromAddresses.ts +3 -2
  136. package/src/global-account/react/hooks/useNativeBalance.tsx +2 -1
  137. package/src/global-account/react/hooks/useSimBalance.ts +56 -0
  138. package/src/global-account/react/hooks/useUnifiedChainSwitchAndExecute.ts +3 -1
  139. package/src/global-account/react/stores/useModalStore.ts +2 -2
  140. package/src/global-account/react/utils/profileDisplay.ts +9 -0
  141. package/src/global-account/utils/analytics.ts +64 -0
  142. package/src/shared/constants/index.ts +2 -0
  143. package/src/shared/generated/chain-networks.json +185 -17
  144. package/src/{anyspend/types → types}/window.d.ts +5 -1
  145. package/dist/cjs/index.d.ts +0 -0
  146. package/dist/cjs/index.js +0 -2
  147. package/dist/esm/index.d.ts +0 -0
  148. package/dist/esm/index.js +0 -2
  149. package/dist/types/index.d.ts +0 -0
  150. package/src/index.ts +0 -1
@@ -0,0 +1,266 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { ALL_CHAINS, getExplorerTxUrl } from "../../../../anyspend/index.js";
3
+ import { ChainTokenIcon } from "../../../../anyspend/react/components/common/ChainTokenIcon.js";
4
+ import { Button, TransitionPanel, useAnalytics, useSimBalance, useUnifiedChainSwitchAndExecute, } from "../../../../global-account/react/index.js";
5
+ import { formatDisplayNumber, formatTokenAmount } from "../../../../shared/utils/number.js";
6
+ import { ArrowLeft, CircleHelp, Copy, Loader2, Send } from "lucide-react";
7
+ import { useEffect, useMemo, useRef, useState } from "react";
8
+ import { NumericFormat } from "react-number-format";
9
+ import { toast } from "sonner";
10
+ import { useActiveAccount } from "thirdweb/react";
11
+ import { encodeFunctionData, erc20Abi, isAddress, parseUnits } from "viem";
12
+ import invariant from "invariant";
13
+ // Panel view enum for managing navigation between token list and send form
14
+ var TokenPanelView;
15
+ (function (TokenPanelView) {
16
+ TokenPanelView[TokenPanelView["LIST"] = 0] = "LIST";
17
+ TokenPanelView[TokenPanelView["SEND"] = 1] = "SEND";
18
+ })(TokenPanelView || (TokenPanelView = {}));
19
+ /**
20
+ * ContentTokens Component
21
+ *
22
+ * Displays user's token balances with ability to send tokens. Features:
23
+ * - Animated transitions between token list and send form
24
+ * - Smart filtering (shows all tokens when ≤5 valuable tokens or no $1+ tokens)
25
+ * - NumericFormat inputs for proper number handling
26
+ * - Focus preservation during transitions (see render functions pattern below)
27
+ */
28
+ export function ContentTokens({ activeTab }) {
29
+ // === TOKEN FILTERING STATE ===
30
+ const [showAllTokens, setShowAllTokens] = useState(false);
31
+ // === NAVIGATION STATE ===
32
+ const [tokenPanelView, setTokenPanelView] = useState(TokenPanelView.LIST);
33
+ // === SEND FORM STATE ===
34
+ const [selectedToken, setSelectedToken] = useState(null);
35
+ const [recipientAddress, setRecipientAddress] = useState("");
36
+ const [sendAmount, setSendAmount] = useState("");
37
+ const [isSending, setIsSending] = useState(false);
38
+ const [addressError, setAddressError] = useState("");
39
+ // === ANIMATION STATE ===
40
+ // CRITICAL: useRef for animation direction prevents component remounting
41
+ // This ensures input focus is preserved during panel transitions
42
+ const animationDirection = useRef(null);
43
+ // === DATA FETCHING ===
44
+ const account = useActiveAccount();
45
+ const { data: simBalance, refetch: refetchSimBalance, isLoading: isLoadingBalance } = useSimBalance(account?.address);
46
+ // === BLOCKCHAIN INTERACTION ===
47
+ const { switchChainAndExecute } = useUnifiedChainSwitchAndExecute();
48
+ // === ANALYTICS ===
49
+ const { sendAnalyticsEvent } = useAnalytics();
50
+ // === ADDRESS VALIDATION ===
51
+ // Handle recipient address change with real-time validation using viem
52
+ const handleRecipientAddressChange = (value) => {
53
+ setRecipientAddress(value);
54
+ // Only show error if user has typed something and it's invalid
55
+ // Using viem's isAddress for robust EVM address validation
56
+ if (value && !isAddress(value)) {
57
+ setAddressError("Please enter a valid EVM address (0x...)");
58
+ }
59
+ else {
60
+ setAddressError("");
61
+ }
62
+ };
63
+ // === TAB RESET EFFECT ===
64
+ // Reset all state when user switches away from tokens tab
65
+ useEffect(() => {
66
+ if (activeTab !== "tokens") {
67
+ setTokenPanelView(TokenPanelView.LIST);
68
+ setSelectedToken(null);
69
+ setRecipientAddress("");
70
+ setSendAmount("");
71
+ setIsSending(false);
72
+ setAddressError("");
73
+ animationDirection.current = null;
74
+ }
75
+ }, [activeTab]);
76
+ // === HELPER FUNCTION ===
77
+ // Get current version of selected token from fresh balance data
78
+ // 🔧 FIX: Prevents auto-navigation back to token list when balance refreshes
79
+ // The useSimBalance hook refreshes data, creating new token object references
80
+ // This helper ensures we always get the fresh token data instead of stale references
81
+ const getCurrentSelectedToken = () => {
82
+ if (!selectedToken || !simBalance?.balances) {
83
+ return null;
84
+ }
85
+ const found = simBalance.balances.find(token => token.chain_id === selectedToken.chain_id && token.address === selectedToken.address);
86
+ return found || null;
87
+ };
88
+ // ==================================================================================
89
+ // === RENDER FUNCTIONS (NOT COMPONENTS!) ===
90
+ // ==================================================================================
91
+ //
92
+ // 🚨 CRITICAL ARCHITECTURE DECISION:
93
+ // These are render functions, NOT component functions with useCallback!
94
+ //
95
+ // WHY THIS WORKS:
96
+ // ✅ Stable wrapper <div> elements with consistent keys
97
+ // ✅ React never sees these as "new components"
98
+ // ✅ Input focus is preserved during transitions
99
+ // ✅ No component remounting issues
100
+ //
101
+ // WHY useCallback DIDN'T WORK:
102
+ // ❌ useCallback(() => <JSX />, [deps]) still creates new component instances
103
+ // ❌ React treats each render as a different component
104
+ // ❌ Causes remounting and focus loss
105
+ //
106
+ // THE PATTERN:
107
+ // Instead of: {[<ComponentA />, <ComponentB />]}
108
+ // We use: {[<div key="a">{renderA()}</div>, <div key="b">{renderB()}</div>]}
109
+ // ==================================================================================
110
+ /**
111
+ * Renders the send token form panel
112
+ * Includes recipient input, amount input with NumericFormat, and percentage buttons
113
+ */
114
+ const renderSendTokenPanel = () => {
115
+ // Get fresh token data to prevent stale references
116
+ const currentToken = getCurrentSelectedToken();
117
+ // 🔧 SINGLE FALLBACK STRATEGY:
118
+ // Use fresh token data when available, fall back to selectedToken if needed
119
+ // This prevents duplication of "currentToken || selectedToken" throughout the component
120
+ const displayToken = currentToken || selectedToken;
121
+ // Handle percentage button clicks (25%, 50%, 75%, 100%)
122
+ const handlePercentageClick = (percentage) => {
123
+ if (displayToken) {
124
+ const tokenBalance = (BigInt(displayToken.amount) * BigInt(percentage)) / BigInt(100);
125
+ const amount = formatTokenAmount(tokenBalance, displayToken.decimals, 30, false);
126
+ setSendAmount(amount);
127
+ }
128
+ };
129
+ // Execute token transfer transaction
130
+ const handleSend = async () => {
131
+ if (!displayToken || !recipientAddress || !sendAmount || parseFloat(sendAmount) <= 0) {
132
+ return;
133
+ }
134
+ setIsSending(true);
135
+ const amountInWei = parseUnits(sendAmount, displayToken.decimals);
136
+ // Prepare analytics event data
137
+ const analyticsData = {
138
+ amount: sendAmount,
139
+ symbol: displayToken.symbol,
140
+ chain_id: displayToken.chain_id,
141
+ address: displayToken.address,
142
+ };
143
+ try {
144
+ invariant(isAddress(recipientAddress), "Recipient address is not a valid address");
145
+ const sendTokenData = encodeFunctionData({
146
+ abi: erc20Abi,
147
+ functionName: "transfer",
148
+ args: [recipientAddress, amountInWei],
149
+ });
150
+ const tx = await switchChainAndExecute(displayToken.chain_id, {
151
+ to: displayToken.address === "native" ? recipientAddress : displayToken.address,
152
+ data: sendTokenData,
153
+ value: displayToken.address === "native" ? amountInWei : BigInt(0),
154
+ });
155
+ if (tx) {
156
+ // Track successful send
157
+ sendAnalyticsEvent("send_token_button_click", {
158
+ ...analyticsData,
159
+ success: true,
160
+ tx: getExplorerTxUrl(displayToken.chain_id, tx),
161
+ });
162
+ // Reset form
163
+ setSendAmount("");
164
+ }
165
+ }
166
+ catch (error) {
167
+ // Track failed send
168
+ sendAnalyticsEvent("send_token_button_click", {
169
+ ...analyticsData,
170
+ success: false,
171
+ reason: error.message || "Unknown error",
172
+ });
173
+ // Error
174
+ toast.error(`Failed to send ${displayToken.symbol}: ${error.message || "Unknown error"}`);
175
+ }
176
+ finally {
177
+ // Wait 1 second to make sure the tx is indexed on sim api.
178
+ setTimeout(async () => {
179
+ // Force refetch to bypass cache and get fresh balance data
180
+ await refetchSimBalance();
181
+ }, 1000);
182
+ setIsSending(false);
183
+ }
184
+ };
185
+ // Show loading state only if no token data is available at all
186
+ if (!displayToken) {
187
+ return (_jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [_jsx("div", { className: "bg-b3-line/50 mb-4 rounded-full p-4", children: _jsx(Loader2, { className: "text-b3-foreground-muted h-8 w-8 animate-spin" }) }), _jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold mb-2", children: "Loading token data..." }), _jsx("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Please wait while we fetch the latest information" })] }));
188
+ }
189
+ return (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Button, { variant: "ghost", size: "icon", onClick: () => {
190
+ animationDirection.current = "back";
191
+ setTokenPanelView(TokenPanelView.LIST);
192
+ }, className: "hover:bg-b3-line/60", disabled: isSending, children: _jsx(ArrowLeft, { className: "h-5 w-5" }) }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-8 w-8 items-center justify-center", children: ALL_CHAINS[displayToken.chain_id]?.logoUrl ? (_jsx(ChainTokenIcon, { chainUrl: ALL_CHAINS[displayToken.chain_id].logoUrl, tokenUrl: displayToken.token_metadata?.logo, className: "size-8" })) : (_jsx(CircleHelp, { className: "text-b3-react-foreground size-8" })) }), _jsxs("h2", { className: "text-b3-grey font-neue-montreal-semibold text-lg", children: ["Send ", displayToken.symbol] })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Recipient Address" }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "relative", children: [_jsx("input", { type: "text", value: recipientAddress, onChange: e => handleRecipientAddressChange(e.target.value), placeholder: "Enter wallet address (0x...)", className: `border-b3-line bg-b3-background text-b3-grey font-neue-montreal-medium placeholder:text-b3-foreground-muted w-full rounded-xl border px-4 py-3 pr-12 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 ${addressError ? "border-red-500 focus:border-red-500" : "focus:border-b3-primary-blue"}`, disabled: isSending }), _jsx(Button, { variant: "ghost", size: "icon", className: "hover:bg-b3-line/60 absolute right-2 top-1/2 h-8 w-8 -translate-y-1/2", disabled: isSending, onClick: () => {
193
+ navigator.clipboard.readText().then(text => {
194
+ handleRecipientAddressChange(text);
195
+ });
196
+ }, children: _jsx(Copy, { className: "h-4 w-4" }) })] }), addressError && _jsx("p", { className: "font-neue-montreal-medium text-xs text-red-500", children: addressError })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Amount" }), _jsxs("div", { className: "space-y-3", children: [_jsx(NumericFormat, { decimalSeparator: ".", allowedDecimalSeparators: [","], thousandSeparator: true, inputMode: "decimal", autoComplete: "off", autoCorrect: "off", type: "text", placeholder: "0.00", minLength: 1, maxLength: 30, spellCheck: "false", className: "border-b3-line bg-b3-background text-b3-grey font-neue-montreal-medium placeholder:text-b3-foreground-muted focus:border-b3-primary-blue w-full rounded-xl border px-4 py-3 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50", pattern: "^[0-9]*[.,]?[0-9]*$", disabled: isSending, value: sendAmount, allowNegative: false, onChange: e => setSendAmount(e.currentTarget.value) }), _jsx("div", { className: "grid grid-cols-4 gap-2", children: [25, 50, 75, 100].map(percentage => (_jsxs(Button, { variant: "outline", onClick: () => handlePercentageClick(percentage), className: "hover:bg-b3-primary-wash border-b3-line text-b3-grey font-neue-montreal-medium text-sm", disabled: isSending, children: [percentage, "%"] }, percentage))) }), _jsxs("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: ["Available: ", formatTokenAmount(BigInt(displayToken.amount), displayToken.decimals), " ", displayToken.symbol] })] })] }), _jsx(Button, { onClick: handleSend, disabled: !recipientAddress ||
197
+ !sendAmount ||
198
+ parseFloat(sendAmount) <= 0 ||
199
+ isSending ||
200
+ !!addressError ||
201
+ !isAddress(recipientAddress), className: "bg-b3-primary-blue hover:bg-b3-primary-blue/90 font-neue-montreal-semibold disabled:bg-b3-line disabled:text-b3-foreground-muted w-full rounded-xl py-3 text-white", children: isSending ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Sending..."] })) : (_jsxs(_Fragment, { children: [_jsx(Send, { className: "mr-2 h-4 w-4" }), "Send ", displayToken.symbol] })) })] }));
202
+ };
203
+ // Skeleton loading component for token list
204
+ const LoadingIndicator = () => (_jsx("div", { className: "space-y-4", children: _jsx("div", { className: "space-y-1", children: [...Array(3)].map((_, index) => (_jsxs("div", { className: "flex items-center justify-between rounded-xl p-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "bg-b3-line h-10 w-10 animate-pulse rounded-full" }), _jsxs("div", { children: [_jsx("div", { className: "bg-b3-line mb-1 h-4 w-16 animate-pulse rounded" }), _jsx("div", { className: "bg-b3-line h-3 w-24 animate-pulse rounded" })] })] }), _jsxs("div", { className: "text-right", children: [_jsx("div", { className: "bg-b3-line mb-1 h-4 w-20 animate-pulse rounded" }), _jsx("div", { className: "bg-b3-line h-3 w-16 animate-pulse rounded" })] })] }, index))) }) }));
205
+ /**
206
+ * Renders the token list panel with smart filtering
207
+ * Features intelligent token display logic to reduce noise while ensuring visibility
208
+ */
209
+ const renderTokenListPanel = () => {
210
+ // Show loading indicator when balance is loading
211
+ if (isLoadingBalance) {
212
+ return _jsx(LoadingIndicator, {});
213
+ }
214
+ // Show empty state when no account or no balance data
215
+ if (!account?.address || !simBalance) {
216
+ return (_jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [_jsx("div", { className: "bg-b3-line/50 mb-4 rounded-full p-4", children: _jsx(Loader2, { className: "text-b3-foreground-muted h-8 w-8" }) }), _jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold mb-2", children: "No wallet connected" }), _jsx("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Connect your wallet to view token balances" })] }));
217
+ }
218
+ // === SMART FILTERING LOGIC ===
219
+ // Filter tokens with value >= $1 to reduce noise from dust tokens
220
+ const filteredTokens = simBalance?.balances.filter(token => token.value_usd !== undefined && token.value_usd >= 1) || [];
221
+ // 🧠 INTELLIGENT DISPLAY LOGIC:
222
+ // Show all tokens automatically when filtering would be unhelpful:
223
+ // 1. User explicitly requested to show all, OR
224
+ // 2. No tokens with value >= $1 (user has only dust), OR
225
+ // 3. 5 or fewer tokens with value >= $1 (not enough to warrant filtering)
226
+ const shouldShowAllTokens = showAllTokens || filteredTokens.length === 0 || filteredTokens.length <= 5;
227
+ const tokensToShow = shouldShowAllTokens ? simBalance?.balances || [] : filteredTokens;
228
+ const hasHiddenTokens = !shouldShowAllTokens && (simBalance?.balances.length || 0) > filteredTokens.length;
229
+ // Handle token selection and navigate to send form
230
+ const handleTokenClick = (token) => {
231
+ setSelectedToken(token);
232
+ animationDirection.current = "forward"; // Set animation direction BEFORE state change
233
+ setTokenPanelView(TokenPanelView.SEND);
234
+ // Reset form when selecting a new token
235
+ setRecipientAddress("");
236
+ setSendAmount("");
237
+ setIsSending(false);
238
+ setAddressError("");
239
+ };
240
+ // Show empty state when no tokens are available
241
+ if (tokensToShow.length === 0) {
242
+ return (_jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [_jsx("div", { className: "bg-b3-line/50 mb-4 rounded-full p-4", children: _jsx(CircleHelp, { className: "text-b3-foreground-muted h-8 w-8" }) }), _jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold mb-2", children: "No tokens found" }), _jsx("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "No token balances found in your wallet." })] }));
243
+ }
244
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx("div", { className: "space-y-1", children: tokensToShow.map(token => (_jsxs("div", { className: "hover:bg-b3-line/60 dark:hover:bg-b3-primary-wash/40 group flex cursor-pointer items-center justify-between rounded-xl p-3 transition-all duration-200", onClick: () => handleTokenClick(token), children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full", children: ALL_CHAINS[token.chain_id]?.logoUrl ? (_jsx(ChainTokenIcon, { chainUrl: ALL_CHAINS[token.chain_id].logoUrl, tokenUrl: token.token_metadata?.logo, className: "size-10" })) : (_jsx(CircleHelp, { className: "text-b3-react-foreground size-10" })) }), _jsxs("div", { children: [_jsx("div", { className: "flex items-center gap-2", children: _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold transition-colors duration-200 group-hover:font-bold group-hover:text-black", children: token.symbol }) }), _jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm transition-colors duration-200 group-hover:text-gray-700", children: token.name })] })] }), _jsxs("div", { className: "text-right", children: [_jsx("div", { className: "text-b3-grey font-neue-montreal-semibold transition-colors duration-200 group-hover:font-bold group-hover:text-black", children: formatTokenAmount(BigInt(token.amount), token.decimals) }), _jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm transition-colors duration-200 group-hover:text-gray-700", children: formatDisplayNumber(token.value_usd, { style: "currency", fractionDigits: 2 }) })] })] }, token.chain_id + "_" + token.address))) }), hasHiddenTokens && !showAllTokens && (_jsx("div", { className: "flex justify-center", children: _jsx(Button, { variant: "ghost", className: "text-b3-primary-blue hover:text-b3-primary-blue/80 font-neue-montreal-semibold text-sm", onClick: () => setShowAllTokens(true), children: "Show more" }) }))] }));
245
+ };
246
+ // === ANIMATION CONFIGURATION ===
247
+ // Memoize variants to prevent re-creation and unwanted re-renders
248
+ const variants = useMemo(() => ({
249
+ enter: (direction) => ({
250
+ x: direction === "back" ? -300 : 300, // Back: slide from left, Forward: slide from right
251
+ opacity: 0,
252
+ }),
253
+ center: { x: 0, opacity: 1 }, // Final position: centered and visible
254
+ exit: (direction) => ({
255
+ x: direction === "back" ? 300 : -300, // Back: slide to right, Forward: slide to left
256
+ opacity: 0,
257
+ }),
258
+ }), []);
259
+ // Memoize transition config for consistent spring animation
260
+ const transition = useMemo(() => ({
261
+ type: "spring",
262
+ stiffness: 300, // Spring tension
263
+ damping: 30, // Spring damping
264
+ }), []);
265
+ return (_jsx(TransitionPanel, { activeIndex: tokenPanelView, className: "min-h-[400px]", custom: animationDirection.current, variants: variants, transition: transition, children: [_jsx("div", { children: renderTokenListPanel() }, "token-list"), _jsx("div", { children: renderSendTokenPanel() }, "send-token")] }));
266
+ }
@@ -1,46 +1,28 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { Button, CopyToClipboard, TabsContentPrimitive, TabsListPrimitive, TabsPrimitive, TabTriggerPrimitive, useAccountAssets, useAuthentication, useB3BalanceFromAddresses, useGetAllTWSigners, useModalStore, useNativeBalance, useProfile, useRemoveSessionKey, } from "../../../../global-account/react/index.js";
3
- import { BankIcon } from "../../../../global-account/react/components/icons/BankIcon.js";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button, TabsContentPrimitive, TabsListPrimitive, TabsPrimitive, TabTriggerPrimitive, useAccountAssets, useAuthentication, useGetAllTWSigners, useModalStore, useRemoveSessionKey, } from "../../../../global-account/react/index.js";
4
3
  import { SignOutIcon } from "../../../../global-account/react/components/icons/SignOutIcon.js";
5
- import { SwapIcon } from "../../../../global-account/react/components/icons/SwapIcon.js";
6
- import { formatUsername } from "../../../../shared/utils/index.js";
7
4
  import { formatNumber } from "../../../../shared/utils/formatNumber.js";
8
5
  import { client } from "../../../../shared/utils/thirdweb.js";
9
- import { LinkIcon, Loader2, Pencil, Triangle, UnlinkIcon } from "lucide-react";
6
+ import { BarChart3, Coins, Image, LinkIcon, Loader2, Settings, UnlinkIcon } from "lucide-react";
10
7
  import { useState } from "react";
11
8
  import { useActiveAccount, useProfiles, useUnlinkProfile } from "thirdweb/react";
12
9
  import { formatUnits } from "viem";
13
- import useFirstEOA from "../../hooks/useFirstEOA.js";
14
10
  import { getProfileDisplayInfo } from "../../utils/profileDisplay.js";
15
11
  import { AccountAssets } from "../AccountAssets/AccountAssets.js";
16
- function centerTruncate(str, length = 4) {
17
- if (str.length <= length * 2)
18
- return str;
19
- return `${str.slice(0, length)}...${str.slice(-length)}`;
20
- }
12
+ import { ContentTokens } from "./ContentTokens.js";
13
+ import { BalanceContent } from "./BalanceContent.js";
21
14
  export function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit, chain, partnerId, }) {
22
15
  const [revokingSignerId, setRevokingSignerId] = useState(null);
23
16
  const account = useActiveAccount();
24
- const { data: assets, isLoading } = useAccountAssets(account?.address);
25
- const { data: b3Balance } = useB3BalanceFromAddresses(account?.address);
26
- const { data: nativeBalance } = useNativeBalance(account?.address);
27
- const { address: eoaAddress } = useFirstEOA();
28
- const { data: profile } = useProfile({
29
- address: eoaAddress || account?.address,
30
- fresh: true,
31
- });
32
- const { data: eoaNativeBalance } = useNativeBalance(eoaAddress);
33
- const { data: eoaB3Balance } = useB3BalanceFromAddresses(eoaAddress);
17
+ const { data: nfts, isLoading } = useAccountAssets(account?.address);
34
18
  const { data: signers, refetch: refetchSigners } = useGetAllTWSigners({
35
19
  chain,
36
20
  accountAddress: account?.address,
37
21
  });
38
- const { setB3ModalOpen, setB3ModalContentType, contentType } = useModalStore();
39
- const { activeTab = "balance", setActiveTab } = contentType;
22
+ const { setB3ModalOpen, contentType } = useModalStore();
23
+ const { activeTab = "overview", setActiveTab } = contentType;
40
24
  const { logout } = useAuthentication(partnerId);
41
25
  const [logoutLoading, setLogoutLoading] = useState(false);
42
- console.log("account", account);
43
- console.log("eoaAddress", eoaAddress);
44
26
  const { removeSessionKey } = useRemoveSessionKey({
45
27
  chain,
46
28
  onSuccess: tx => {
@@ -64,24 +46,6 @@ export function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit
64
46
  setB3ModalOpen(false);
65
47
  setLogoutLoading(false);
66
48
  };
67
- const BalanceContent = () => {
68
- const { info: eoaInfo } = useFirstEOA();
69
- return (_jsxs("div", { className: "flex flex-col gap-6", children: [_jsx("div", { className: "flex items-center justify-between", children: _jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "relative", children: [profile?.avatar ? (_jsx("img", { src: profile?.avatar, alt: "Profile", className: "size-24 rounded-full" })) : (_jsx("div", { className: "bg-b3-primary-wash size-24 rounded-full" })), _jsx("div", { className: "bg-b3-grey border-b3-background absolute -bottom-1 -right-1 flex size-8 items-center justify-center rounded-full border-4", children: _jsx(Pencil, { size: 16, className: "text-b3-background" }) })] }), _jsxs("div", { children: [_jsx("h2", { className: "text-b3-grey text-xl font-semibold", children: profile?.displayName || formatUsername(profile?.name || "") }), _jsx("span", { className: "text-b3-foreground-muted", children: formatUsername(profile?.name || "") })] })] }) }), _jsxs("div", { className: "manage-account-address bg-b3-line flex h-11 items-center gap-2 rounded-full px-4", children: [_jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: centerTruncate(account?.address || "") }), _jsx(CopyToClipboard, { text: account?.address || "" })] }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs(Button, { className: "manage-account-deposit bg-b3-primary-wash hover:bg-b3-primary-wash/70 h-[84px] w-full flex-col items-start gap-2 rounded-2xl", onClick: () => {
70
- setB3ModalOpen(true);
71
- setB3ModalContentType({
72
- type: "anySpend",
73
- defaultActiveTab: "fiat",
74
- showBackButton: true,
75
- });
76
- }, children: [_jsx(BankIcon, { size: 24, className: "text-b3-primary-blue shrink-0" }), _jsx("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Deposit" })] }), _jsxs(Button, { className: "manage-account-swap bg-b3-primary-wash hover:bg-b3-primary-wash/70 flex h-[84px] w-full flex-col items-start gap-2 rounded-2xl", onClick: () => {
77
- setB3ModalOpen(true);
78
- setB3ModalContentType({
79
- type: "anySpend",
80
- showBackButton: true,
81
- });
82
- }, children: [_jsx(SwapIcon, { size: 24, className: "text-b3-primary-blue" }), _jsx("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Swap" })] })] }), _jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold", children: "Balance" }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full", children: _jsx("img", { src: "https://cdn.b3.fun/b3-coin-3d.png", alt: "B3", className: "size-10" }) }), _jsxs("div", { children: [_jsx("div", { className: "flex items-center gap-2", children: _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: "B3" }) }), _jsxs("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: [b3Balance?.formattedTotal || "0.00", " B3"] })] })] }), _jsxs("div", { className: "text-right", children: [_jsxs("div", { className: "text-b3-grey font-neue-montreal-semibold", children: ["$", b3Balance?.balanceUsdFormatted || "0.00"] }), _jsx("div", { className: "flex items-center gap-1", children: b3Balance?.priceChange24h !== null && b3Balance?.priceChange24h !== undefined ? (_jsxs(_Fragment, { children: [_jsx(Triangle, { className: `size-3 ${b3Balance.priceChange24h >= 0 ? "text-b3-positive fill-b3-positive" : "text-b3-negative fill-b3-negative rotate-180"}` }), _jsxs("span", { className: `font-neue-montreal-medium text-sm ${b3Balance.priceChange24h >= 0 ? "text-b3-positive" : "text-b3-negative"}`, children: [b3Balance.priceChange24h >= 0 ? "+" : "", b3Balance.priceChange24h.toFixed(2), "%"] })] })) : (_jsx("span", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "--" })) })] })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full", children: _jsx("img", { src: "https://cdn.b3.fun/ethereum.svg", alt: "ETH", className: "size-10" }) }), _jsxs("div", { children: [_jsx("div", { className: "flex items-center gap-2", children: _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: "Ethereum" }) }), _jsxs("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: [nativeBalance?.formattedTotal || "0.00", " ETH"] })] })] }), _jsxs("div", { className: "text-right", children: [_jsxs("div", { className: "text-b3-grey font-neue-montreal-semibold", children: ["$", nativeBalance?.formattedTotalUsd || "0.00"] }), _jsx("div", { className: "flex items-center gap-2", children: nativeBalance?.priceChange24h !== null && nativeBalance?.priceChange24h !== undefined ? (_jsxs(_Fragment, { children: [_jsx(Triangle, { className: `size-3 ${nativeBalance.priceChange24h >= 0 ? "text-b3-positive fill-b3-positive" : "text-b3-negative fill-b3-negative rotate-180"}` }), _jsxs("span", { className: `font-neue-montreal-medium text-sm ${nativeBalance.priceChange24h >= 0 ? "text-b3-positive" : "text-b3-negative"}`, children: [nativeBalance.priceChange24h >= 0 ? "+" : "", nativeBalance.priceChange24h.toFixed(2), "%"] })] })) : (_jsx("span", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "--" })) })] })] })] }), eoaAddress && (_jsxs("div", { className: "space-y-4", children: [_jsxs("h3", { className: "text-b3-grey font-neue-montreal-semibold", children: ["Connected ", eoaInfo?.data?.name || "Wallet"] }), _jsxs("div", { className: "manage-account-address bg-b3-line flex h-11 items-center gap-2 rounded-full px-4", children: [_jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: centerTruncate(eoaAddress) }), _jsx(CopyToClipboard, { text: eoaAddress })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full", children: _jsx("img", { src: "https://cdn.b3.fun/b3-coin-3d.png", alt: "B3", className: "size-10" }) }), _jsxs("div", { children: [_jsx("div", { className: "flex items-center gap-2", children: _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: "B3" }) }), _jsxs("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: [eoaB3Balance?.formattedTotal || "0.00", " B3"] })] })] }), _jsxs("div", { className: "text-right", children: [_jsxs("div", { className: "text-b3-grey font-neue-montreal-semibold", children: ["$", eoaB3Balance?.balanceUsdFormatted || "0.00"] }), _jsx("div", { className: "flex items-center gap-1", children: eoaB3Balance?.priceChange24h !== null && eoaB3Balance?.priceChange24h !== undefined ? (_jsxs(_Fragment, { children: [_jsx(Triangle, { className: `size-3 ${eoaB3Balance.priceChange24h >= 0 ? "text-b3-positive fill-b3-positive" : "text-b3-negative fill-b3-negative rotate-180"}` }), _jsxs("span", { className: `font-neue-montreal-medium text-sm ${eoaB3Balance.priceChange24h >= 0 ? "text-b3-positive" : "text-b3-negative"}`, children: [eoaB3Balance.priceChange24h >= 0 ? "+" : "", eoaB3Balance.priceChange24h.toFixed(2), "%"] })] })) : (_jsx("span", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "--" })) })] })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full", children: _jsx("img", { src: "https://cdn.b3.fun/ethereum.svg", alt: "ETH", className: "size-10" }) }), _jsxs("div", { children: [_jsx("div", { className: "flex items-center gap-2", children: _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: "Ethereum" }) }), _jsxs("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: [eoaNativeBalance?.formattedTotal || "0.00", " ETH"] })] })] }), _jsxs("div", { className: "text-right", children: [_jsxs("div", { className: "text-b3-grey font-neue-montreal-semibold", children: ["$", eoaNativeBalance?.formattedTotalUsd || "0.00"] }), _jsx("div", { className: "flex items-center gap-2", children: eoaNativeBalance?.priceChange24h !== null && eoaNativeBalance?.priceChange24h !== undefined ? (_jsxs(_Fragment, { children: [_jsx(Triangle, { className: `size-3 ${eoaNativeBalance.priceChange24h >= 0 ? "text-b3-positive fill-b3-positive" : "text-b3-negative fill-b3-negative rotate-180"}` }), _jsxs("span", { className: `font-neue-montreal-medium text-sm ${eoaNativeBalance.priceChange24h >= 0 ? "text-b3-positive" : "text-b3-negative"}`, children: [eoaNativeBalance.priceChange24h >= 0 ? "+" : "", eoaNativeBalance.priceChange24h.toFixed(2), "%"] })] })) : (_jsx("span", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "--" })) })] })] })] })), _jsxs("div", { className: "border-b3-line flex items-center justify-between rounded-2xl border p-4", children: [_jsxs("div", { className: "", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("img", { src: "https://cdn.b3.fun/b3_logo.svg", alt: "B3", className: "h-4" }), _jsx("h3", { className: "font-neue-montreal-semibold text-b3-grey", children: "Global Account" })] }), _jsx("p", { className: "text-b3-foreground-muted font-neue-montreal-medium mt-2 text-sm", children: "Your universal account for all B3-powered apps" })] }), _jsx("button", { className: "text-b3-grey hover:text-b3-grey/80 hover:bg-b3-line border-b3-line flex size-12 items-center justify-center rounded-full border", onClick: onLogoutEnhanced, children: logoutLoading ? _jsx(Loader2, { className: "animate-spin" }) : _jsx(SignOutIcon, { size: 16, className: "text-b3-grey" }) })] })] }));
83
- };
84
- const AssetsContent = () => (_jsx("div", { className: "grid grid-cols-3 gap-4", children: assets?.nftResponse ? (_jsx(AccountAssets, { nfts: assets.nftResponse, isLoading: isLoading })) : (_jsx("div", { className: "col-span-3 py-12 text-center text-gray-500", children: "No NFTs found" })) }));
85
49
  const AppsContent = () => (_jsxs("div", { className: "space-y-4", children: [signers?.map((signer) => (_jsx("div", { className: "rounded-xl border border-gray-200 p-4 dark:border-gray-800", children: _jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-gray-100 dark:bg-gray-800", children: _jsx("span", { className: "text-xs font-medium text-gray-600 dark:text-gray-400", children: "App" }) }), _jsxs("div", { children: [_jsx("h3", { className: "font-medium text-gray-900 dark:text-white", children: signer.partner.name }), _jsxs("div", { className: "mt-2 space-y-1", children: [_jsxs("p", { className: "text-xs text-gray-500", children: ["Added ", new Date(signer.createdAt).toLocaleDateString()] }), _jsxs("p", { className: "text-xs text-gray-500", children: ["Expires ", new Date(Number(signer.endTimestamp) * 1000).toLocaleDateString()] }), _jsxs("p", { className: "text-xs text-gray-500", children: ["Max spend: ", formatNumber(Number(formatUnits(signer.nativeTokenLimitPerTransaction, 18))), " ETH"] })] })] })] }), _jsx(Button, { variant: "outline", size: "sm", className: "border-red-200 text-red-500 hover:border-red-300 hover:text-red-600", onClick: () => handleRevoke(signer), disabled: revokingSignerId === signer.id, children: revokingSignerId === signer.id ? "Revoking..." : "Revoke" })] }) }, signer.id))), !signers?.length && _jsx("div", { className: "py-12 text-center text-gray-500", children: "No connected apps" })] }));
86
50
  const SettingsContent = () => {
87
51
  const [unlinkingAccountId, setUnlinkingAccountId] = useState(null);
@@ -97,10 +61,7 @@ export function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit
97
61
  const handleUnlink = async (profile) => {
98
62
  setUnlinkingAccountId(profile.title);
99
63
  try {
100
- await unlinkProfile({
101
- client,
102
- profileToUnlink: profile.originalProfile,
103
- });
64
+ unlinkProfile({ client, profileToUnlink: profile.originalProfile });
104
65
  }
105
66
  catch (error) {
106
67
  console.error("Error unlinking account:", error);
@@ -127,12 +88,12 @@ export function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit
127
88
  },
128
89
  });
129
90
  };
130
- return (_jsxs("div", { className: "space-y-8", children: [_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Linked Accounts" }), _jsxs(Button, { className: "bg-b3-primary-wash hover:bg-b3-primary-wash/70 flex items-center gap-2 rounded-full px-4 py-2", onClick: handleOpenLinkModal, disabled: isLinking, children: [isLinking ? (_jsx(Loader2, { className: "text-b3-primary-blue animate-spin", size: 16 })) : (_jsx(LinkIcon, { size: 16, className: "text-b3-primary-blue" })), _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: isLinking ? "Linking..." : "Link New Account" })] })] }), isLoadingProfiles ? (_jsx("div", { className: "flex justify-center py-8", children: _jsx(Loader2, { className: "text-b3-grey animate-spin" }) })) : profiles.length > 0 ? (_jsx("div", { className: "space-y-4", children: profiles.map(profile => (_jsxs("div", { className: "bg-b3-line flex items-center justify-between rounded-xl p-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [profile.imageUrl ? (_jsx("img", { src: profile.imageUrl, alt: profile.title, className: "size-10 rounded-full" })) : (_jsx("div", { className: "bg-b3-primary-wash flex h-10 w-10 items-center justify-center rounded-full", children: _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm uppercase", children: profile.initial }) })), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: profile.title }), _jsx("span", { className: "text-b3-foreground-muted font-neue-montreal-medium bg-b3-primary-wash rounded px-2 py-0.5 text-xs", children: profile.type.toUpperCase() })] }), _jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: profile.subtitle })] })] }), _jsx(Button, { variant: "ghost", size: "icon", className: "text-b3-grey hover:text-b3-negative", onClick: () => handleUnlink(profile), disabled: unlinkingAccountId === profile.title || isUnlinking, children: unlinkingAccountId === profile.title || isUnlinking ? (_jsx(Loader2, { className: "animate-spin" })) : (_jsx(UnlinkIcon, { size: 16 })) })] }, profile.title))) })) : (_jsx("div", { className: "text-b3-foreground-muted py-8 text-center", children: "No linked accounts found" }))] }), _jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Account Preferences" }), _jsx("div", { className: "bg-b3-line rounded-xl p-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Dark Mode" }), _jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Switch between light and dark theme" })] }), _jsx("div", { className: "bg-b3-primary-wash h-6 w-12 rounded-full" })] }) })] }), _jsxs("div", { className: "border-b3-line flex items-center justify-between rounded-2xl border p-4", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("img", { src: "https://cdn.b3.fun/b3_logo.svg", alt: "B3", className: "h-4" }), _jsx("h3", { className: "font-neue-montreal-semibold text-b3-grey", children: "Global Account" })] }), _jsx("p", { className: "text-b3-foreground-muted font-neue-montreal-medium mt-2 text-sm", children: "Your universal account for all B3-powered apps" })] }), _jsx("button", { className: "text-b3-grey hover:text-b3-grey/80 hover:bg-b3-line border-b3-line flex size-12 items-center justify-center rounded-full border", onClick: onLogoutEnhanced, children: logoutLoading ? _jsx(Loader2, { className: "animate-spin" }) : _jsx(SignOutIcon, { size: 16, className: "text-b3-grey" }) })] })] }));
91
+ return (_jsxs("div", { className: "space-y-8", children: [_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Linked Accounts" }), _jsxs(Button, { className: "bg-b3-primary-wash hover:bg-b3-primary-wash/70 flex items-center gap-2 rounded-full px-4 py-2", onClick: handleOpenLinkModal, disabled: isLinking, children: [isLinking ? (_jsx(Loader2, { className: "text-b3-primary-blue animate-spin", size: 16 })) : (_jsx(LinkIcon, { size: 16, className: "text-b3-primary-blue" })), _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: isLinking ? "Linking..." : "Link New Account" })] })] }), isLoadingProfiles ? (_jsx("div", { className: "flex justify-center py-8", children: _jsx(Loader2, { className: "text-b3-grey animate-spin" }) })) : profiles.length > 0 ? (_jsx("div", { className: "space-y-4", children: profiles.map(profile => (_jsxs("div", { className: "bg-b3-line flex items-center justify-between rounded-xl p-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [profile.imageUrl ? (_jsx("img", { src: profile.imageUrl, alt: profile.title, className: "size-10 rounded-full" })) : (_jsx("div", { className: "bg-b3-primary-wash flex h-10 w-10 items-center justify-center rounded-full", children: _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm uppercase", children: profile.initial }) })), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: profile.title }), _jsx("span", { className: "text-b3-foreground-muted font-neue-montreal-medium bg-b3-primary-wash rounded px-2 py-0.5 text-xs", children: profile.type.toUpperCase() })] }), _jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: profile.subtitle })] })] }), _jsx(Button, { variant: "ghost", size: "icon", className: "text-b3-grey hover:text-b3-negative", onClick: () => handleUnlink(profile), disabled: unlinkingAccountId === profile.title || isUnlinking, children: unlinkingAccountId === profile.title || isUnlinking ? (_jsx(Loader2, { className: "animate-spin" })) : (_jsx(UnlinkIcon, { size: 16 })) })] }, profile.title))) })) : (_jsx("div", { className: "text-b3-foreground-muted py-8 text-center", children: "No linked accounts found" }))] }), _jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "Account Preferences" }), _jsx("div", { className: "bg-b3-line rounded-xl p-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Dark Mode" }), _jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Switch between light and dark theme" })] }), _jsx("div", { className: "bg-b3-primary-wash h-6 w-12 rounded-full" })] }) })] }), _jsxs("div", { className: "border-b3-line flex items-center justify-between rounded-2xl border p-4", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("img", { src: "https://cdn.b3.fun/b3_logo.svg", alt: "B3", className: "h-4" }), _jsx("h3", { className: "font-neue-montreal-semibold text-b3-grey", children: "Global Account" })] }), _jsx("p", { className: "text-b3-foreground-muted font-neue-montreal-medium mt-2 text-sm", children: "Your universal account for all B3 apps" })] }), _jsx("button", { className: "text-b3-grey hover:text-b3-grey/80 hover:bg-b3-line border-b3-line flex size-12 items-center justify-center rounded-full border", onClick: onLogoutEnhanced, children: logoutLoading ? _jsx(Loader2, { className: "animate-spin" }) : _jsx(SignOutIcon, { size: 16, className: "text-b3-grey" }) })] })] }));
131
92
  };
132
93
  return (_jsx("div", { className: "b3-manage-account bg-b3-background flex flex-col rounded-xl", children: _jsx("div", { className: "flex-1", children: _jsxs(TabsPrimitive, { defaultValue: activeTab, onValueChange: value => {
133
94
  const tab = value;
134
- if (["balance", "assets", "apps", "settings"].includes(tab)) {
95
+ if (["overview", "tokens", "nfts", "apps", "settings"].includes(tab)) {
135
96
  setActiveTab?.(tab);
136
97
  }
137
- }, children: [_jsxs(TabsListPrimitive, { className: "font-neue-montreal-semibold text-b3-grey flex h-8 w-full items-start justify-start gap-8 border-0 text-xl md:p-4", children: [_jsx(TabTriggerPrimitive, { value: "balance", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Overview" }), _jsx(TabTriggerPrimitive, { value: "assets", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Mints" }), _jsx(TabTriggerPrimitive, { value: "settings", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Settings" })] }), _jsx(TabsContentPrimitive, { value: "balance", className: "pt-4 md:p-4", children: _jsx(BalanceContent, {}) }), _jsx(TabsContentPrimitive, { value: "assets", className: "pt-4 md:p-4", children: _jsx(AssetsContent, {}) }), _jsx(TabsContentPrimitive, { value: "apps", className: "pt-4 md:p-4", children: _jsx(AppsContent, {}) }), _jsx(TabsContentPrimitive, { value: "settings", className: "pt-4 md:p-4", children: _jsx(SettingsContent, {}) })] }) }) }));
98
+ }, children: [_jsx("div", { className: "px-4", children: _jsxs(TabsListPrimitive, { className: "grid h-auto grid-cols-2 grid-rows-2 gap-3 rounded-none border-none bg-transparent", children: [_jsxs(TabTriggerPrimitive, { value: "overview", className: "data-[state=active]:bg-b3-primary-blue data-[state=active]:hover:bg-b3-primary-blue data-[state=active]:border-b3-primary-blue group flex h-12 w-full items-center justify-center gap-2 rounded-xl border border-gray-200 bg-white p-2 text-center shadow-sm transition-all duration-200 hover:bg-gray-50 hover:shadow-md data-[state=active]:shadow-lg", children: [_jsx(BarChart3, { size: 20, className: "text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" }), _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white", children: "Overview" })] }), _jsxs(TabTriggerPrimitive, { value: "tokens", className: "data-[state=active]:bg-b3-primary-blue data-[state=active]:hover:bg-b3-primary-blue data-[state=active]:border-b3-primary-blue group flex h-12 w-full items-center justify-center gap-2 rounded-xl border border-gray-200 bg-white p-2 text-center shadow-sm transition-all duration-200 hover:bg-gray-50 hover:shadow-md data-[state=active]:shadow-lg", children: [_jsx(Coins, { size: 20, className: "text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" }), _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white", children: "Tokens" })] }), _jsxs(TabTriggerPrimitive, { value: "nfts", className: "data-[state=active]:bg-b3-primary-blue data-[state=active]:hover:bg-b3-primary-blue data-[state=active]:border-b3-primary-blue group flex h-12 w-full items-center justify-center gap-2 rounded-xl border border-gray-200 bg-white p-2 text-center shadow-sm transition-all duration-200 hover:bg-gray-50 hover:shadow-md data-[state=active]:shadow-lg", children: [_jsx(Image, { size: 20, className: "text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" }), _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white", children: "NFTs" })] }), _jsxs(TabTriggerPrimitive, { value: "settings", className: "data-[state=active]:bg-b3-primary-blue data-[state=active]:hover:bg-b3-primary-blue data-[state=active]:border-b3-primary-blue group flex h-12 w-full items-center justify-center gap-2 rounded-xl border border-gray-200 bg-white p-2 text-center shadow-sm transition-all duration-200 hover:bg-gray-50 hover:shadow-md data-[state=active]:shadow-lg", children: [_jsx(Settings, { size: 20, className: "text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" }), _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white", children: "Settings" })] })] }) }), _jsx(TabsContentPrimitive, { value: "overview", className: "px-4 pb-4 pt-2", children: _jsx(BalanceContent, { onLogout: onLogout, partnerId: partnerId }) }), _jsx(TabsContentPrimitive, { value: "tokens", className: "px-4 pb-4 pt-2", children: _jsx(ContentTokens, { activeTab: activeTab }) }), _jsx(TabsContentPrimitive, { value: "nfts", className: "px-4 pb-4 pt-2", children: _jsx("div", { className: "grid grid-cols-3 gap-4", children: nfts?.nftResponse ? (_jsx(AccountAssets, { nfts: nfts.nftResponse, isLoading: isLoading })) : (_jsx("div", { className: "col-span-3 py-12 text-center text-gray-500", children: "No NFTs found" })) }) }), _jsx(TabsContentPrimitive, { value: "apps", className: "px-4 pb-4 pt-2", children: _jsx(AppsContent, {}) }), _jsx(TabsContentPrimitive, { value: "settings", className: "px-4 pb-4 pt-2", children: _jsx(SettingsContent, {}) })] }) }) }));
138
99
  }
@@ -0,0 +1,10 @@
1
+ import { ReactNode } from "react";
2
+ interface TokenBalanceRowProps {
3
+ icon: ReactNode;
4
+ name: string;
5
+ balance: string;
6
+ usdValue: string;
7
+ priceChange?: number | null;
8
+ }
9
+ export declare function TokenBalanceRow({ icon, name, balance, usdValue, priceChange }: TokenBalanceRowProps): import("react/jsx-runtime").JSX.Element;
10
+ export {};
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Triangle } from "lucide-react";
3
+ export function TokenBalanceRow({ icon, name, balance, usdValue, priceChange }) {
4
+ return (_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full", children: icon }), _jsxs("div", { children: [_jsx("div", { className: "flex items-center gap-2", children: _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold", children: name }) }), _jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: balance })] })] }), _jsxs("div", { className: "text-right", children: [_jsxs("div", { className: "text-b3-grey font-neue-montreal-semibold", children: ["$", usdValue] }), _jsx("div", { className: "flex items-center gap-1", children: priceChange !== null && priceChange !== undefined ? (_jsxs(_Fragment, { children: [_jsx(Triangle, { className: `size-3 ${priceChange >= 0 ? "text-b3-positive fill-b3-positive" : "text-b3-negative fill-b3-negative rotate-180"}` }), _jsxs("span", { className: `font-neue-montreal-medium text-sm ${priceChange >= 0 ? "text-b3-positive" : "text-b3-negative"}`, children: [priceChange >= 0 ? "+" : "", priceChange.toFixed(2), "%"] })] })) : (_jsx("span", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "--" })) })] })] }));
5
+ }
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ interface TokenIconProps {
3
+ src: string;
4
+ alt: string;
5
+ className?: string;
6
+ size?: number;
7
+ }
8
+ export declare const TokenIcon: React.FC<TokenIconProps>;
9
+ export declare const B3TokenIcon: React.FC<Omit<TokenIconProps, "src" | "alt">>;
10
+ export declare const EthereumTokenIcon: React.FC<Omit<TokenIconProps, "src" | "alt">>;
11
+ export {};
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../../../shared/utils/index.js";
3
+ import { useCallback, useMemo, useState } from "react";
4
+ // Create a global image cache to prevent re-loading
5
+ const imageCache = new Map();
6
+ export const TokenIcon = ({ src, alt, className, size = 40 }) => {
7
+ const [isLoaded, setIsLoaded] = useState(() => imageCache.get(src) || false);
8
+ const [hasError, setHasError] = useState(false);
9
+ const handleLoad = useCallback(() => {
10
+ imageCache.set(src, true);
11
+ setIsLoaded(true);
12
+ }, [src]);
13
+ const handleError = useCallback(() => {
14
+ setHasError(true);
15
+ }, []);
16
+ // Memoize the image element to prevent unnecessary re-renders
17
+ const imageElement = useMemo(() => (_jsx("img", { src: src, alt: alt, className: cn("transition-opacity duration-200", className, {
18
+ "opacity-100": isLoaded && !hasError,
19
+ "opacity-0": !isLoaded || hasError,
20
+ }), onLoad: handleLoad, onError: handleError, loading: "eager" // Load immediately since these are critical UI elements
21
+ , decoding: "async", style: {
22
+ width: size,
23
+ height: size,
24
+ } })), [src, alt, className, isLoaded, hasError, handleLoad, handleError, size]);
25
+ // Show a placeholder while loading or if there's an error
26
+ const placeholder = useMemo(() => (_jsx("div", { className: cn("bg-b3-primary-wash flex items-center justify-center rounded-full transition-opacity duration-200", {
27
+ "opacity-0": isLoaded && !hasError,
28
+ "opacity-100": !isLoaded || hasError,
29
+ }), style: {
30
+ width: size,
31
+ height: size,
32
+ }, children: _jsx("span", { className: "text-b3-grey font-neue-montreal-semibold text-xs", children: alt.charAt(0).toUpperCase() }) })), [alt, isLoaded, hasError, size]);
33
+ return (_jsxs("div", { className: "relative inline-block", style: { width: size, height: size }, children: [placeholder, _jsx("div", { className: "absolute inset-0", children: imageElement })] }));
34
+ };
35
+ // Pre-defined token icons for common tokens
36
+ export const B3TokenIcon = props => (_jsx(TokenIcon, { src: "https://cdn.b3.fun/b3-coin-3d.png", alt: "B3", ...props }));
37
+ export const EthereumTokenIcon = props => (_jsx(TokenIcon, { src: "https://cdn.b3.fun/ethereum.svg", alt: "ETH", ...props }));
@@ -0,0 +1,7 @@
1
+ import * as AccordionPrimitive from "@radix-ui/react-accordion";
2
+ import * as React from "react";
3
+ declare const Accordion: React.ForwardRefExoticComponent<(AccordionPrimitive.AccordionSingleProps | AccordionPrimitive.AccordionMultipleProps) & React.RefAttributes<HTMLDivElement>>;
4
+ declare const AccordionItem: React.ForwardRefExoticComponent<Omit<AccordionPrimitive.AccordionItemProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
5
+ declare const AccordionTrigger: React.ForwardRefExoticComponent<Omit<AccordionPrimitive.AccordionTriggerProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
6
+ declare const AccordionContent: React.ForwardRefExoticComponent<Omit<AccordionPrimitive.AccordionContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
7
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as AccordionPrimitive from "@radix-ui/react-accordion";
4
+ import { ChevronDown } from "lucide-react";
5
+ import * as React from "react";
6
+ import { cn } from "../../../../shared/utils/index.js";
7
+ const Accordion = AccordionPrimitive.Root;
8
+ const AccordionItem = React.forwardRef(({ className, ...props }, ref) => (_jsx(AccordionPrimitive.Item, { ref: ref, className: cn("border-b3-line border-b", className), ...props })));
9
+ AccordionItem.displayName = "AccordionItem";
10
+ const AccordionTrigger = React.forwardRef(({ className, children, ...props }, ref) => (_jsx(AccordionPrimitive.Header, { className: "flex", children: _jsxs(AccordionPrimitive.Trigger, { ref: ref, className: cn("flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180", className), ...props, children: [children, _jsx(ChevronDown, { className: "h-4 w-4 shrink-0 transition-transform duration-200" })] }) })));
11
+ AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
12
+ const AccordionContent = React.forwardRef(({ className, children, ...props }, ref) => (_jsx(AccordionPrimitive.Content, { ref: ref, className: "data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm transition-all", ...props, children: _jsx("div", { className: cn("pb-4 pt-0", className), children: children }) })));
13
+ AccordionContent.displayName = AccordionPrimitive.Content.displayName;
14
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
@@ -12,7 +12,7 @@ const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => (_jsx(D
12
12
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
13
13
  const DialogContent = React.forwardRef(({ className, children, hideCloseButton = false, closeBtnClassName, ...props }, ref) => {
14
14
  const container = typeof window !== "undefined" ? document.getElementById("b3-root") : null;
15
- return (_jsxs(DialogPortal, { container: container, children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { ref: ref, className: cn("bg-b3-react-background fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border p-6 shadow-lg !outline-none", "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 duration-500", "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95", "data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]", "[perspective:1200px] [transform-style:preserve-3d] sm:rounded-xl", "transition-all ease-out", className), ...props, children: [children, !hideCloseButton && (_jsxs(DialogPrimitive.Close, { className: cn("data-[state=open]:bg-b3-react-background data-[state=open]:text-b3-react-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none dark:data-[state=open]:bg-gray-800 dark:data-[state=open]:text-gray-400", closeBtnClassName), children: [_jsx(X, { className: "h-5 w-5" }), _jsx("span", { className: "sr-only", children: "Close" })] }))] })] }));
15
+ return (_jsxs(DialogPortal, { container: container, children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { ref: ref, className: cn("bg-b3-react-background fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border p-6 shadow-lg !outline-none", "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 duration-500", "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95", "data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]", "[perspective:1200px] [transform-style:preserve-3d] sm:rounded-xl", "transition-all ease-out", className), ...props, children: [children, !hideCloseButton && (_jsxs(DialogPrimitive.Close, { className: cn("modal-close-button data-[state=open]:bg-b3-react-background data-[state=open]:text-b3-react-muted-foreground absolute right-2 top-2 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none dark:data-[state=open]:bg-gray-800 dark:data-[state=open]:text-gray-400", closeBtnClassName), children: [_jsx(X, { className: "h-5 w-5" }), _jsx("span", { className: "sr-only", children: "Close" })] }))] })] }));
16
16
  });
17
17
  DialogContent.displayName = DialogPrimitive.Content.displayName;
18
18
  const DialogHeader = ({ className, ...props }) => (_jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props }));
@@ -1,6 +1,7 @@
1
1
  export { useAccountAssets } from "./useAccountAssets";
2
2
  export { useAccountWallet } from "./useAccountWallet";
3
3
  export { useAddTWSessionKey } from "./useAddTWSessionKey";
4
+ export { useAnalytics } from "./useAnalytics";
4
5
  export { useAuthentication } from "./useAuthentication";
5
6
  export { useB3BalanceFromAddresses } from "./useB3BalanceFromAddresses";
6
7
  export { useB3EnsName } from "./useB3EnsName";
@@ -24,6 +25,7 @@ export { useQueryBSMNT } from "./useQueryBSMNT";
24
25
  export { useRemoveSessionKey } from "./useRemoveSessionKey";
25
26
  export { useRouter } from "./useRouter";
26
27
  export { useSearchParamsSSR } from "./useSearchParamsSSR";
28
+ export { useSimBalance } from "./useSimBalance";
27
29
  export { useSiwe } from "./useSiwe";
28
30
  export { useTokenBalance } from "./useTokenBalance";
29
31
  export { useTokenBalancesByChain } from "./useTokenBalancesByChain";
@@ -1,6 +1,7 @@
1
1
  export { useAccountAssets } from "./useAccountAssets.js";
2
2
  export { useAccountWallet } from "./useAccountWallet.js";
3
3
  export { useAddTWSessionKey } from "./useAddTWSessionKey.js";
4
+ export { useAnalytics } from "./useAnalytics.js";
4
5
  export { useAuthentication } from "./useAuthentication.js";
5
6
  export { useB3BalanceFromAddresses } from "./useB3BalanceFromAddresses.js";
6
7
  export { useB3EnsName } from "./useB3EnsName.js";
@@ -24,6 +25,7 @@ export { useQueryBSMNT } from "./useQueryBSMNT.js";
24
25
  export { useRemoveSessionKey } from "./useRemoveSessionKey.js";
25
26
  export { useRouter } from "./useRouter.js";
26
27
  export { useSearchParamsSSR } from "./useSearchParamsSSR.js";
28
+ export { useSimBalance } from "./useSimBalance.js";
27
29
  export { useSiwe } from "./useSiwe.js";
28
30
  export { useTokenBalance } from "./useTokenBalance.js";
29
31
  export { useTokenBalancesByChain } from "./useTokenBalancesByChain.js";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Analytics hook that provides sendAnalyticsEvent function
3
+ * Automatically includes user address from useAccountWallet
4
+ */
5
+ export declare function useAnalytics(): {
6
+ sendAnalyticsEvent: (eventName: string, parameters?: Record<string, any>) => void;
7
+ };