@b3dotfun/sdk 0.0.30-alpha.4 → 0.0.30-alpha.5
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/cjs/anyspend/react/components/common/ChainTokenIcon.d.ts +1 -1
- package/dist/cjs/anyspend/react/components/common/ChainTokenIcon.js +2 -1
- package/dist/cjs/global-account/react/components/ManageAccount/ContentTokens.d.ts +14 -0
- package/dist/cjs/global-account/react/components/ManageAccount/ContentTokens.js +246 -0
- package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.js +2 -5
- package/dist/cjs/global-account/react/hooks/index.d.ts +1 -0
- package/dist/cjs/global-account/react/hooks/index.js +3 -1
- package/dist/cjs/global-account/react/hooks/useSimBalance.d.ts +24 -0
- package/dist/cjs/global-account/react/hooks/useSimBalance.js +25 -0
- package/dist/cjs/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +0 -1
- package/dist/esm/anyspend/react/components/common/ChainTokenIcon.d.ts +1 -1
- package/dist/esm/anyspend/react/components/common/ChainTokenIcon.js +2 -1
- package/dist/esm/global-account/react/components/ManageAccount/ContentTokens.d.ts +14 -0
- package/dist/esm/global-account/react/components/ManageAccount/ContentTokens.js +243 -0
- package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.js +2 -5
- package/dist/esm/global-account/react/hooks/index.d.ts +1 -0
- package/dist/esm/global-account/react/hooks/index.js +1 -0
- package/dist/esm/global-account/react/hooks/useSimBalance.d.ts +24 -0
- package/dist/esm/global-account/react/hooks/useSimBalance.js +22 -0
- package/dist/esm/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +0 -1
- package/dist/styles/index.css +1 -1
- package/dist/types/anyspend/react/components/common/ChainTokenIcon.d.ts +1 -1
- package/dist/types/global-account/react/components/ManageAccount/ContentTokens.d.ts +14 -0
- package/dist/types/global-account/react/hooks/index.d.ts +1 -0
- package/dist/types/global-account/react/hooks/useSimBalance.d.ts +24 -0
- package/package.json +1 -1
- package/src/anyspend/react/components/common/ChainTokenIcon.tsx +8 -2
- package/src/global-account/react/components/ManageAccount/ContentTokens.tsx +539 -0
- package/src/global-account/react/components/ManageAccount/ManageAccount.tsx +10 -64
- package/src/global-account/react/hooks/index.ts +1 -0
- package/src/global-account/react/hooks/useAccountAssets.ts +1 -0
- package/src/global-account/react/hooks/useSimBalance.ts +53 -0
- package/src/global-account/react/hooks/useUnifiedChainSwitchAndExecute.ts +0 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ChainTokenIcon = ChainTokenIcon;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const lucide_react_1 = require("lucide-react");
|
|
5
6
|
function ChainTokenIcon({ chainUrl, tokenUrl, className = "", }) {
|
|
6
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: `relative ${className}`, children: [(0, jsx_runtime_1.jsx)("img", { src: tokenUrl, alt: "Token", className: "h-full w-full rounded-full" }), (0, jsx_runtime_1.jsx)("div", { className: "bg-as-on-surface-1 border-as-stroke absolute bottom-0 right-0 h-[45%] w-[45%] rounded border", children: (0, jsx_runtime_1.jsx)("img", { src: chainUrl, alt: "Chain", className: "h-full w-full rounded" }) })] }));
|
|
7
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: `relative ${className}`, children: [tokenUrl ? ((0, jsx_runtime_1.jsx)("img", { src: tokenUrl, alt: "Token", className: "h-full w-full rounded-full" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.HelpCircle, { className: "text-b3-react-foreground h-full w-full" })), (0, jsx_runtime_1.jsx)("div", { className: "bg-as-on-surface-1 border-as-stroke absolute bottom-0 right-0 h-[45%] w-[45%] rounded border", children: (0, jsx_runtime_1.jsx)("img", { src: chainUrl, alt: "Chain", className: "h-full w-full rounded" }) })] }));
|
|
7
8
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface ContentTokensProps {
|
|
2
|
+
activeTab: string;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* ContentTokens Component
|
|
6
|
+
*
|
|
7
|
+
* Displays user's token balances with ability to send tokens. Features:
|
|
8
|
+
* - Animated transitions between token list and send form
|
|
9
|
+
* - Smart filtering (shows all tokens when ≤5 valuable tokens or no $1+ tokens)
|
|
10
|
+
* - NumericFormat inputs for proper number handling
|
|
11
|
+
* - Focus preservation during transitions (see render functions pattern below)
|
|
12
|
+
*/
|
|
13
|
+
export declare function ContentTokens({ activeTab }: ContentTokensProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContentTokens = ContentTokens;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const anyspend_1 = require("../../../../anyspend");
|
|
6
|
+
const ChainTokenIcon_1 = require("../../../../anyspend/react/components/common/ChainTokenIcon");
|
|
7
|
+
const react_1 = require("../../../../global-account/react");
|
|
8
|
+
const number_1 = require("../../../../shared/utils/number");
|
|
9
|
+
const lucide_react_1 = require("lucide-react");
|
|
10
|
+
const react_2 = require("react");
|
|
11
|
+
const react_number_format_1 = require("react-number-format");
|
|
12
|
+
const sonner_1 = require("sonner");
|
|
13
|
+
const react_3 = require("thirdweb/react");
|
|
14
|
+
const viem_1 = require("viem");
|
|
15
|
+
// Panel view enum for managing navigation between token list and send form
|
|
16
|
+
var TokenPanelView;
|
|
17
|
+
(function (TokenPanelView) {
|
|
18
|
+
TokenPanelView[TokenPanelView["LIST"] = 0] = "LIST";
|
|
19
|
+
TokenPanelView[TokenPanelView["SEND"] = 1] = "SEND";
|
|
20
|
+
})(TokenPanelView || (TokenPanelView = {}));
|
|
21
|
+
/**
|
|
22
|
+
* ContentTokens Component
|
|
23
|
+
*
|
|
24
|
+
* Displays user's token balances with ability to send tokens. Features:
|
|
25
|
+
* - Animated transitions between token list and send form
|
|
26
|
+
* - Smart filtering (shows all tokens when ≤5 valuable tokens or no $1+ tokens)
|
|
27
|
+
* - NumericFormat inputs for proper number handling
|
|
28
|
+
* - Focus preservation during transitions (see render functions pattern below)
|
|
29
|
+
*/
|
|
30
|
+
function ContentTokens({ activeTab }) {
|
|
31
|
+
// === TOKEN FILTERING STATE ===
|
|
32
|
+
const [showAllTokens, setShowAllTokens] = (0, react_2.useState)(false);
|
|
33
|
+
// === NAVIGATION STATE ===
|
|
34
|
+
const [tokenPanelView, setTokenPanelView] = (0, react_2.useState)(TokenPanelView.LIST);
|
|
35
|
+
// === SEND FORM STATE ===
|
|
36
|
+
const [selectedToken, setSelectedToken] = (0, react_2.useState)(null);
|
|
37
|
+
const [recipientAddress, setRecipientAddress] = (0, react_2.useState)("");
|
|
38
|
+
const [sendAmount, setSendAmount] = (0, react_2.useState)("");
|
|
39
|
+
const [isSending, setIsSending] = (0, react_2.useState)(false);
|
|
40
|
+
const [addressError, setAddressError] = (0, react_2.useState)("");
|
|
41
|
+
// === ANIMATION STATE ===
|
|
42
|
+
// CRITICAL: useRef for animation direction prevents component remounting
|
|
43
|
+
// This ensures input focus is preserved during panel transitions
|
|
44
|
+
const animationDirection = (0, react_2.useRef)(null);
|
|
45
|
+
// === DATA FETCHING ===
|
|
46
|
+
const account = (0, react_3.useActiveAccount)();
|
|
47
|
+
const { data: simBalance, refetch: refetchSimBalance, isLoading: isLoadingBalance } = (0, react_1.useSimBalance)(account?.address);
|
|
48
|
+
// === BLOCKCHAIN INTERACTION ===
|
|
49
|
+
const { switchChainAndExecute } = (0, react_1.useUnifiedChainSwitchAndExecute)();
|
|
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 && !(0, viem_1.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
|
+
(0, react_2.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 = (0, number_1.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 = (0, viem_1.parseUnits)(sendAmount, displayToken.decimals);
|
|
136
|
+
try {
|
|
137
|
+
const sendTokenData = (0, viem_1.encodeFunctionData)({
|
|
138
|
+
abi: viem_1.erc20Abi,
|
|
139
|
+
functionName: "transfer",
|
|
140
|
+
args: [recipientAddress, amountInWei],
|
|
141
|
+
});
|
|
142
|
+
const tx = await switchChainAndExecute(displayToken.chain_id, {
|
|
143
|
+
to: displayToken.address === "native" ? recipientAddress : displayToken.address,
|
|
144
|
+
data: sendTokenData,
|
|
145
|
+
value: displayToken.address === "native" ? amountInWei : BigInt(0),
|
|
146
|
+
});
|
|
147
|
+
if (tx) {
|
|
148
|
+
// Reset form
|
|
149
|
+
setSendAmount("");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
// Error
|
|
154
|
+
sonner_1.toast.error(`Failed to send ${displayToken.symbol}: ${error.message || "Unknown error"}`);
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
// Wait 1 second to make sure the tx is indexed on sim api.
|
|
158
|
+
setTimeout(async () => {
|
|
159
|
+
// Force refetch to bypass cache and get fresh balance data
|
|
160
|
+
await refetchSimBalance();
|
|
161
|
+
}, 1000);
|
|
162
|
+
setIsSending(false);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
// Show loading state only if no token data is available at all
|
|
166
|
+
if (!displayToken) {
|
|
167
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [(0, jsx_runtime_1.jsx)("div", { className: "bg-b3-line/50 mb-4 rounded-full p-4", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "text-b3-foreground-muted h-8 w-8 animate-spin" }) }), (0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold mb-2", children: "Loading token data..." }), (0, jsx_runtime_1.jsx)("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Please wait while we fetch the latest information" })] }));
|
|
168
|
+
}
|
|
169
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)(react_1.Button, { variant: "ghost", size: "icon", onClick: () => {
|
|
170
|
+
animationDirection.current = "back";
|
|
171
|
+
setTokenPanelView(TokenPanelView.LIST);
|
|
172
|
+
}, className: "hover:bg-b3-line/60", disabled: isSending, children: (0, jsx_runtime_1.jsx)(lucide_react_1.ArrowLeft, { className: "h-5 w-5" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-8 w-8 items-center justify-center", children: anyspend_1.ALL_CHAINS[displayToken.chain_id]?.logoUrl ? ((0, jsx_runtime_1.jsx)(ChainTokenIcon_1.ChainTokenIcon, { chainUrl: anyspend_1.ALL_CHAINS[displayToken.chain_id].logoUrl, tokenUrl: displayToken.token_metadata?.logo, className: "size-8" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.CircleHelp, { className: "text-b3-react-foreground size-8" })) }), (0, jsx_runtime_1.jsxs)("h2", { className: "text-b3-grey font-neue-montreal-semibold text-lg", children: ["Send ", displayToken.symbol] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Recipient Address" }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-1", children: [(0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.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 }), (0, jsx_runtime_1.jsx)(react_1.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: () => {
|
|
173
|
+
navigator.clipboard.readText().then(text => {
|
|
174
|
+
handleRecipientAddressChange(text);
|
|
175
|
+
});
|
|
176
|
+
}, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { className: "h-4 w-4" }) })] }), addressError && (0, jsx_runtime_1.jsx)("p", { className: "font-neue-montreal-medium text-xs text-red-500", children: addressError })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Amount" }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-3", children: [(0, jsx_runtime_1.jsx)(react_number_format_1.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) }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-4 gap-2", children: [25, 50, 75, 100].map(percentage => ((0, jsx_runtime_1.jsxs)(react_1.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))) }), (0, jsx_runtime_1.jsxs)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: ["Available: ", (0, number_1.formatTokenAmount)(BigInt(displayToken.amount), displayToken.decimals), " ", displayToken.symbol] })] })] }), (0, jsx_runtime_1.jsx)(react_1.Button, { onClick: handleSend, disabled: !recipientAddress ||
|
|
177
|
+
!sendAmount ||
|
|
178
|
+
parseFloat(sendAmount) <= 0 ||
|
|
179
|
+
isSending ||
|
|
180
|
+
!!addressError ||
|
|
181
|
+
!(0, viem_1.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 ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Sending..."] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Send, { className: "mr-2 h-4 w-4" }), "Send ", displayToken.symbol] })) })] }));
|
|
182
|
+
};
|
|
183
|
+
// Skeleton loading component for token list
|
|
184
|
+
const LoadingIndicator = () => ((0, jsx_runtime_1.jsx)("div", { className: "space-y-4", children: (0, jsx_runtime_1.jsx)("div", { className: "space-y-1", children: [...Array(3)].map((_, index) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between rounded-xl p-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "bg-b3-line h-10 w-10 animate-pulse rounded-full" }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "bg-b3-line mb-1 h-4 w-16 animate-pulse rounded" }), (0, jsx_runtime_1.jsx)("div", { className: "bg-b3-line h-3 w-24 animate-pulse rounded" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-right", children: [(0, jsx_runtime_1.jsx)("div", { className: "bg-b3-line mb-1 h-4 w-20 animate-pulse rounded" }), (0, jsx_runtime_1.jsx)("div", { className: "bg-b3-line h-3 w-16 animate-pulse rounded" })] })] }, index))) }) }));
|
|
185
|
+
/**
|
|
186
|
+
* Renders the token list panel with smart filtering
|
|
187
|
+
* Features intelligent token display logic to reduce noise while ensuring visibility
|
|
188
|
+
*/
|
|
189
|
+
const renderTokenListPanel = () => {
|
|
190
|
+
// Show loading indicator when balance is loading
|
|
191
|
+
if (isLoadingBalance) {
|
|
192
|
+
return (0, jsx_runtime_1.jsx)(LoadingIndicator, {});
|
|
193
|
+
}
|
|
194
|
+
// Show empty state when no account or no balance data
|
|
195
|
+
if (!account?.address || !simBalance) {
|
|
196
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [(0, jsx_runtime_1.jsx)("div", { className: "bg-b3-line/50 mb-4 rounded-full p-4", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "text-b3-foreground-muted h-8 w-8" }) }), (0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold mb-2", children: "No wallet connected" }), (0, jsx_runtime_1.jsx)("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Connect your wallet to view token balances" })] }));
|
|
197
|
+
}
|
|
198
|
+
// === SMART FILTERING LOGIC ===
|
|
199
|
+
// Filter tokens with value >= $1 to reduce noise from dust tokens
|
|
200
|
+
const filteredTokens = simBalance?.balances.filter(token => token.value_usd !== undefined && token.value_usd >= 1) || [];
|
|
201
|
+
// 🧠 INTELLIGENT DISPLAY LOGIC:
|
|
202
|
+
// Show all tokens automatically when filtering would be unhelpful:
|
|
203
|
+
// 1. User explicitly requested to show all, OR
|
|
204
|
+
// 2. No tokens with value >= $1 (user has only dust), OR
|
|
205
|
+
// 3. 5 or fewer tokens with value >= $1 (not enough to warrant filtering)
|
|
206
|
+
const shouldShowAllTokens = showAllTokens || filteredTokens.length === 0 || filteredTokens.length <= 5;
|
|
207
|
+
const tokensToShow = shouldShowAllTokens ? simBalance?.balances || [] : filteredTokens;
|
|
208
|
+
const hasHiddenTokens = !shouldShowAllTokens && (simBalance?.balances.length || 0) > filteredTokens.length;
|
|
209
|
+
// Handle token selection and navigate to send form
|
|
210
|
+
const handleTokenClick = (token) => {
|
|
211
|
+
setSelectedToken(token);
|
|
212
|
+
animationDirection.current = "forward"; // Set animation direction BEFORE state change
|
|
213
|
+
setTokenPanelView(TokenPanelView.SEND);
|
|
214
|
+
// Reset form when selecting a new token
|
|
215
|
+
setRecipientAddress("");
|
|
216
|
+
setSendAmount("");
|
|
217
|
+
setIsSending(false);
|
|
218
|
+
setAddressError("");
|
|
219
|
+
};
|
|
220
|
+
// Show empty state when no tokens are available
|
|
221
|
+
if (tokensToShow.length === 0) {
|
|
222
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [(0, jsx_runtime_1.jsx)("div", { className: "bg-b3-line/50 mb-4 rounded-full p-4", children: (0, jsx_runtime_1.jsx)(lucide_react_1.CircleHelp, { className: "text-b3-foreground-muted h-8 w-8" }) }), (0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold mb-2", children: "No tokens found" }), (0, jsx_runtime_1.jsx)("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "No token balances found in your wallet." })] }));
|
|
223
|
+
}
|
|
224
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "space-y-1", children: tokensToShow.map(token => ((0, jsx_runtime_1.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: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-10 w-10 items-center justify-center rounded-full", children: anyspend_1.ALL_CHAINS[token.chain_id]?.logoUrl ? ((0, jsx_runtime_1.jsx)(ChainTokenIcon_1.ChainTokenIcon, { chainUrl: anyspend_1.ALL_CHAINS[token.chain_id].logoUrl, tokenUrl: token.token_metadata?.logo, className: "size-10" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.CircleHelp, { className: "text-b3-react-foreground size-10" })) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: (0, jsx_runtime_1.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 }) }), (0, jsx_runtime_1.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 })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-right", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-b3-grey font-neue-montreal-semibold transition-colors duration-200 group-hover:font-bold group-hover:text-black", children: (0, number_1.formatTokenAmount)(BigInt(token.amount), token.decimals) }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm transition-colors duration-200 group-hover:text-gray-700", children: (0, number_1.formatDisplayNumber)(token.value_usd, { style: "currency", fractionDigits: 2 }) })] })] }, token.chain_id + "_" + token.address))) }), hasHiddenTokens && !showAllTokens && ((0, jsx_runtime_1.jsx)("div", { className: "flex justify-center", children: (0, jsx_runtime_1.jsx)(react_1.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" }) }))] }));
|
|
225
|
+
};
|
|
226
|
+
// === ANIMATION CONFIGURATION ===
|
|
227
|
+
// Memoize variants to prevent re-creation and unwanted re-renders
|
|
228
|
+
const variants = (0, react_2.useMemo)(() => ({
|
|
229
|
+
enter: (direction) => ({
|
|
230
|
+
x: direction === "back" ? -300 : 300, // Back: slide from left, Forward: slide from right
|
|
231
|
+
opacity: 0,
|
|
232
|
+
}),
|
|
233
|
+
center: { x: 0, opacity: 1 }, // Final position: centered and visible
|
|
234
|
+
exit: (direction) => ({
|
|
235
|
+
x: direction === "back" ? 300 : -300, // Back: slide to right, Forward: slide to left
|
|
236
|
+
opacity: 0,
|
|
237
|
+
}),
|
|
238
|
+
}), []);
|
|
239
|
+
// Memoize transition config for consistent spring animation
|
|
240
|
+
const transition = (0, react_2.useMemo)(() => ({
|
|
241
|
+
type: "spring",
|
|
242
|
+
stiffness: 300, // Spring tension
|
|
243
|
+
damping: 30, // Spring damping
|
|
244
|
+
}), []);
|
|
245
|
+
return ((0, jsx_runtime_1.jsx)(react_1.TransitionPanel, { activeIndex: tokenPanelView, className: "min-h-[400px]", custom: animationDirection.current, variants: variants, transition: transition, children: [(0, jsx_runtime_1.jsx)("div", { children: renderTokenListPanel() }, "token-list"), (0, jsx_runtime_1.jsx)("div", { children: renderSendTokenPanel() }, "send-token")] }));
|
|
246
|
+
}
|
|
@@ -19,6 +19,7 @@ const viem_1 = require("viem");
|
|
|
19
19
|
const useFirstEOA_1 = __importDefault(require("../../hooks/useFirstEOA"));
|
|
20
20
|
const profileDisplay_1 = require("../../utils/profileDisplay");
|
|
21
21
|
const AccountAssets_1 = require("../AccountAssets/AccountAssets");
|
|
22
|
+
const ContentTokens_1 = require("./ContentTokens");
|
|
22
23
|
function centerTruncate(str, length = 4) {
|
|
23
24
|
if (str.length <= length * 2)
|
|
24
25
|
return str;
|
|
@@ -45,8 +46,6 @@ function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit, chain
|
|
|
45
46
|
const { activeTab = "overview", setActiveTab } = contentType;
|
|
46
47
|
const { logout } = (0, react_1.useAuthentication)(partnerId);
|
|
47
48
|
const [logoutLoading, setLogoutLoading] = (0, react_2.useState)(false);
|
|
48
|
-
console.log("account", account);
|
|
49
|
-
console.log("eoaAddress", eoaAddress);
|
|
50
49
|
const { removeSessionKey } = (0, react_1.useRemoveSessionKey)({
|
|
51
50
|
chain,
|
|
52
51
|
onSuccess: tx => {
|
|
@@ -87,8 +86,6 @@ function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit, chain
|
|
|
87
86
|
});
|
|
88
87
|
}, children: [(0, jsx_runtime_1.jsx)(SwapIcon_1.SwapIcon, { size: 24, className: "text-b3-primary-blue" }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: "Swap" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold", children: "Balance" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-10 w-10 items-center justify-center rounded-full", children: (0, jsx_runtime_1.jsx)("img", { src: "https://cdn.b3.fun/b3-coin-3d.png", alt: "B3", className: "size-10" }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: "B3" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: [b3Balance?.formattedTotal || "0.00", " B3"] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-right", children: [(0, jsx_runtime_1.jsxs)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: ["$", b3Balance?.balanceUsdFormatted || "0.00"] }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-1", children: b3Balance?.priceChange24h !== null && b3Balance?.priceChange24h !== undefined ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Triangle, { className: `size-3 ${b3Balance.priceChange24h >= 0 ? "text-b3-positive fill-b3-positive" : "text-b3-negative fill-b3-negative rotate-180"}` }), (0, jsx_runtime_1.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), "%"] })] })) : ((0, jsx_runtime_1.jsx)("span", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "--" })) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-10 w-10 items-center justify-center rounded-full", children: (0, jsx_runtime_1.jsx)("img", { src: "https://cdn.b3.fun/ethereum.svg", alt: "ETH", className: "size-10" }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: "Ethereum" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: [nativeBalance?.formattedTotal || "0.00", " ETH"] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-right", children: [(0, jsx_runtime_1.jsxs)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: ["$", nativeBalance?.formattedTotalUsd || "0.00"] }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: nativeBalance?.priceChange24h !== null && nativeBalance?.priceChange24h !== undefined ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Triangle, { className: `size-3 ${nativeBalance.priceChange24h >= 0 ? "text-b3-positive fill-b3-positive" : "text-b3-negative fill-b3-negative rotate-180"}` }), (0, jsx_runtime_1.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), "%"] })] })) : ((0, jsx_runtime_1.jsx)("span", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "--" })) })] })] })] }), eoaAddress && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsxs)("h3", { className: "text-b3-grey font-neue-montreal-semibold", children: ["Connected ", eoaInfo?.data?.name || "Wallet"] }), (0, jsx_runtime_1.jsxs)("div", { className: "border-b3-line bg-b3-line/20 hover:bg-b3-line/40 flex w-fit items-center gap-2 rounded-full border px-3 py-1 transition-colors", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-b3-foreground-muted font-mono text-xs", children: centerTruncate(eoaAddress, 6) }), (0, jsx_runtime_1.jsx)(react_1.CopyToClipboard, { text: eoaAddress })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-10 w-10 items-center justify-center rounded-full", children: (0, jsx_runtime_1.jsx)("img", { src: "https://cdn.b3.fun/b3-coin-3d.png", alt: "B3", className: "size-10" }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: "B3" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: [eoaB3Balance?.formattedTotal || "0.00", " B3"] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-right", children: [(0, jsx_runtime_1.jsxs)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: ["$", eoaB3Balance?.balanceUsdFormatted || "0.00"] }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-1", children: eoaB3Balance?.priceChange24h !== null && eoaB3Balance?.priceChange24h !== undefined ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Triangle, { className: `size-3 ${eoaB3Balance.priceChange24h >= 0 ? "text-b3-positive fill-b3-positive" : "text-b3-negative fill-b3-negative rotate-180"}` }), (0, jsx_runtime_1.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), "%"] })] })) : ((0, jsx_runtime_1.jsx)("span", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "--" })) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-10 w-10 items-center justify-center rounded-full", children: (0, jsx_runtime_1.jsx)("img", { src: "https://cdn.b3.fun/ethereum.svg", alt: "ETH", className: "size-10" }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: "Ethereum" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: [eoaNativeBalance?.formattedTotal || "0.00", " ETH"] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-right", children: [(0, jsx_runtime_1.jsxs)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: ["$", eoaNativeBalance?.formattedTotalUsd || "0.00"] }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: eoaNativeBalance?.priceChange24h !== null && eoaNativeBalance?.priceChange24h !== undefined ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Triangle, { className: `size-3 ${eoaNativeBalance.priceChange24h >= 0 ? "text-b3-positive fill-b3-positive" : "text-b3-negative fill-b3-negative rotate-180"}` }), (0, jsx_runtime_1.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), "%"] })] })) : ((0, jsx_runtime_1.jsx)("span", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "--" })) })] })] })] })), (0, jsx_runtime_1.jsxs)("div", { className: "border-b3-line flex items-center justify-between rounded-2xl border p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("img", { src: "https://cdn.b3.fun/b3_logo.svg", alt: "B3", className: "h-4" }), (0, jsx_runtime_1.jsx)("h3", { className: "font-neue-montreal-semibold text-b3-grey", children: "Global Account" })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-b3-foreground-muted font-neue-montreal-medium mt-2 text-sm", children: "Your universal account for all B3 apps" })] }), (0, jsx_runtime_1.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 ? (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" }) : (0, jsx_runtime_1.jsx)(SignOutIcon_1.SignOutIcon, { size: 16, className: "text-b3-grey" }) })] })] }));
|
|
89
88
|
};
|
|
90
|
-
const TokensContent = () => ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-b3-grey font-neue-montreal-semibold text-xl", children: "My Tokens" }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-10 w-10 items-center justify-center rounded-full", children: (0, jsx_runtime_1.jsx)("img", { src: "https://cdn.b3.fun/b3-coin-3d.png", alt: "B3", className: "size-10" }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: "B3" }) }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "B3 Token" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-right", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: b3Balance?.formattedTotal || "0.00" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: ["$", b3Balance?.balanceUsdFormatted || "0.00"] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-10 w-10 items-center justify-center rounded-full", children: (0, jsx_runtime_1.jsx)("img", { src: "https://cdn.b3.fun/ethereum.svg", alt: "ETH", className: "size-10" }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold", children: "Ethereum" }) }), (0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "ETH" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-right", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-b3-grey font-neue-montreal-semibold", children: nativeBalance?.formattedTotal || "0.00" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: ["$", nativeBalance?.formattedTotalUsd || "0.00"] })] })] })] })] }));
|
|
91
|
-
const AssetsContent = () => ((0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-3 gap-4", children: nfts?.nftResponse ? ((0, jsx_runtime_1.jsx)(AccountAssets_1.AccountAssets, { nfts: nfts.nftResponse, isLoading: isLoading })) : ((0, jsx_runtime_1.jsx)("div", { className: "col-span-3 py-12 text-center text-gray-500", children: "No NFTs found" })) }));
|
|
92
89
|
const AppsContent = () => ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [signers?.map((signer) => ((0, jsx_runtime_1.jsx)("div", { className: "rounded-xl border border-gray-200 p-4 dark:border-gray-800", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-start justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-gray-100 dark:bg-gray-800", children: (0, jsx_runtime_1.jsx)("span", { className: "text-xs font-medium text-gray-600 dark:text-gray-400", children: "App" }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "font-medium text-gray-900 dark:text-white", children: signer.partner.name }), (0, jsx_runtime_1.jsxs)("div", { className: "mt-2 space-y-1", children: [(0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-gray-500", children: ["Added ", new Date(signer.createdAt).toLocaleDateString()] }), (0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-gray-500", children: ["Expires ", new Date(Number(signer.endTimestamp) * 1000).toLocaleDateString()] }), (0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-gray-500", children: ["Max spend: ", (0, formatNumber_1.formatNumber)(Number((0, viem_1.formatUnits)(signer.nativeTokenLimitPerTransaction, 18))), " ETH"] })] })] })] }), (0, jsx_runtime_1.jsx)(react_1.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 && (0, jsx_runtime_1.jsx)("div", { className: "py-12 text-center text-gray-500", children: "No connected apps" })] }));
|
|
93
90
|
const SettingsContent = () => {
|
|
94
91
|
const [unlinkingAccountId, setUnlinkingAccountId] = (0, react_2.useState)(null);
|
|
@@ -138,5 +135,5 @@ function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit, chain
|
|
|
138
135
|
if (["overview", "tokens", "nfts", "apps", "settings"].includes(tab)) {
|
|
139
136
|
setActiveTab?.(tab);
|
|
140
137
|
}
|
|
141
|
-
}, children: [(0, jsx_runtime_1.jsx)("div", { className: "px-4", children: (0, jsx_runtime_1.jsxs)(react_1.TabsListPrimitive, { className: "grid h-auto grid-cols-2 grid-rows-2 gap-3 rounded-none border-none bg-transparent", children: [(0, jsx_runtime_1.jsxs)(react_1.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: [(0, jsx_runtime_1.jsx)(lucide_react_1.BarChart3, { size: 20, className: "text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" }), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white", children: "Overview" })] }), (0, jsx_runtime_1.jsxs)(react_1.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: [(0, jsx_runtime_1.jsx)(lucide_react_1.Coins, { size: 20, className: "text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" }), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white", children: "Tokens" })] }), (0, jsx_runtime_1.jsxs)(react_1.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: [(0, jsx_runtime_1.jsx)(lucide_react_1.Image, { size: 20, className: "text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" }), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white", children: "NFTs" })] }), (0, jsx_runtime_1.jsxs)(react_1.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: [(0, jsx_runtime_1.jsx)(lucide_react_1.Settings, { size: 20, className: "text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" }), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white", children: "Settings" })] })] }) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "overview", className: "px-4 pb-4 pt-2", children: (0, jsx_runtime_1.jsx)(BalanceContent, {}) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "tokens", className: "px-4 pb-4 pt-2", children: (0, jsx_runtime_1.jsx)(
|
|
138
|
+
}, children: [(0, jsx_runtime_1.jsx)("div", { className: "px-4", children: (0, jsx_runtime_1.jsxs)(react_1.TabsListPrimitive, { className: "grid h-auto grid-cols-2 grid-rows-2 gap-3 rounded-none border-none bg-transparent", children: [(0, jsx_runtime_1.jsxs)(react_1.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: [(0, jsx_runtime_1.jsx)(lucide_react_1.BarChart3, { size: 20, className: "text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" }), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white", children: "Overview" })] }), (0, jsx_runtime_1.jsxs)(react_1.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: [(0, jsx_runtime_1.jsx)(lucide_react_1.Coins, { size: 20, className: "text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" }), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white", children: "Tokens" })] }), (0, jsx_runtime_1.jsxs)(react_1.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: [(0, jsx_runtime_1.jsx)(lucide_react_1.Image, { size: 20, className: "text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" }), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white", children: "NFTs" })] }), (0, jsx_runtime_1.jsxs)(react_1.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: [(0, jsx_runtime_1.jsx)(lucide_react_1.Settings, { size: 20, className: "text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" }), (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white", children: "Settings" })] })] }) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "overview", className: "px-4 pb-4 pt-2", children: (0, jsx_runtime_1.jsx)(BalanceContent, {}) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "tokens", className: "px-4 pb-4 pt-2", children: (0, jsx_runtime_1.jsx)(ContentTokens_1.ContentTokens, { activeTab: activeTab }) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "nfts", className: "px-4 pb-4 pt-2", children: (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-3 gap-4", children: nfts?.nftResponse ? ((0, jsx_runtime_1.jsx)(AccountAssets_1.AccountAssets, { nfts: nfts.nftResponse, isLoading: isLoading })) : ((0, jsx_runtime_1.jsx)("div", { className: "col-span-3 py-12 text-center text-gray-500", children: "No NFTs found" })) }) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "apps", className: "px-4 pb-4 pt-2", children: (0, jsx_runtime_1.jsx)(AppsContent, {}) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "settings", className: "px-4 pb-4 pt-2", children: (0, jsx_runtime_1.jsx)(SettingsContent, {}) })] }) }) }));
|
|
142
139
|
}
|
|
@@ -18,6 +18,7 @@ export { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect";
|
|
|
18
18
|
export { useMediaQuery } from "./useMediaQuery";
|
|
19
19
|
export { useNativeBalance, useNativeBalanceFromRPC } from "./useNativeBalance";
|
|
20
20
|
export { useOneBalance } from "./useOneBalance";
|
|
21
|
+
export { useSimBalance } from "./useSimBalance";
|
|
21
22
|
export { useProfile, useProfilePreference, type CombinedProfile, type PreferenceRequestBody, type Profile, } from "./useProfile";
|
|
22
23
|
export { useQueryB3 } from "./useQueryB3";
|
|
23
24
|
export { useQueryBSMNT } from "./useQueryBSMNT";
|
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.useURLParams = exports.useUnifiedChainSwitchAndExecute = exports.useTokensFromAddress = exports.useTokenPriceWithFallback = exports.useTokenPrice = exports.useTokenFromUrl = exports.useTokenData = exports.useTokenBalancesByChain = exports.useTokenBalance = exports.useSiwe = exports.useSearchParamsSSR = exports.useRouter = exports.useRemoveSessionKey = exports.useQueryBSMNT = exports.useQueryB3 = exports.useProfilePreference = exports.useProfile = exports.useOneBalance = exports.useNativeBalanceFromRPC = exports.useNativeBalance = exports.useMediaQuery = exports.useIsomorphicLayoutEffect = exports.useIsMobile = exports.useHasMounted = exports.useHandleConnectWithPrivy = exports.useGetGeo = exports.useGetAllTWSigners = exports.useExchangeRate = exports.useConnect = exports.useChainSwitchWithAction = exports.useBestTransactionPath = exports.useB3EnsName = exports.useB3BalanceFromAddresses = exports.useAuthentication = exports.useAddTWSessionKey = exports.useAccountWallet = exports.useAccountAssets = void 0;
|
|
17
|
+
exports.useURLParams = exports.useUnifiedChainSwitchAndExecute = exports.useTokensFromAddress = exports.useTokenPriceWithFallback = exports.useTokenPrice = exports.useTokenFromUrl = exports.useTokenData = exports.useTokenBalancesByChain = exports.useTokenBalance = exports.useSiwe = exports.useSearchParamsSSR = exports.useRouter = exports.useRemoveSessionKey = exports.useQueryBSMNT = exports.useQueryB3 = exports.useProfilePreference = exports.useProfile = exports.useSimBalance = exports.useOneBalance = exports.useNativeBalanceFromRPC = exports.useNativeBalance = exports.useMediaQuery = exports.useIsomorphicLayoutEffect = exports.useIsMobile = exports.useHasMounted = exports.useHandleConnectWithPrivy = exports.useGetGeo = exports.useGetAllTWSigners = exports.useExchangeRate = exports.useConnect = exports.useChainSwitchWithAction = exports.useBestTransactionPath = exports.useB3EnsName = exports.useB3BalanceFromAddresses = exports.useAuthentication = exports.useAddTWSessionKey = exports.useAccountWallet = exports.useAccountAssets = void 0;
|
|
18
18
|
var useAccountAssets_1 = require("./useAccountAssets");
|
|
19
19
|
Object.defineProperty(exports, "useAccountAssets", { enumerable: true, get: function () { return useAccountAssets_1.useAccountAssets; } });
|
|
20
20
|
var useAccountWallet_1 = require("./useAccountWallet");
|
|
@@ -55,6 +55,8 @@ Object.defineProperty(exports, "useNativeBalance", { enumerable: true, get: func
|
|
|
55
55
|
Object.defineProperty(exports, "useNativeBalanceFromRPC", { enumerable: true, get: function () { return useNativeBalance_1.useNativeBalanceFromRPC; } });
|
|
56
56
|
var useOneBalance_1 = require("./useOneBalance");
|
|
57
57
|
Object.defineProperty(exports, "useOneBalance", { enumerable: true, get: function () { return useOneBalance_1.useOneBalance; } });
|
|
58
|
+
var useSimBalance_1 = require("./useSimBalance");
|
|
59
|
+
Object.defineProperty(exports, "useSimBalance", { enumerable: true, get: function () { return useSimBalance_1.useSimBalance; } });
|
|
58
60
|
var useProfile_1 = require("./useProfile");
|
|
59
61
|
Object.defineProperty(exports, "useProfile", { enumerable: true, get: function () { return useProfile_1.useProfile; } });
|
|
60
62
|
Object.defineProperty(exports, "useProfilePreference", { enumerable: true, get: function () { return useProfile_1.useProfilePreference; } });
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface SimTokenMetadata {
|
|
2
|
+
logo?: string;
|
|
3
|
+
}
|
|
4
|
+
export interface SimBalanceItem {
|
|
5
|
+
chain: string;
|
|
6
|
+
chain_id: number;
|
|
7
|
+
address: string;
|
|
8
|
+
amount: string;
|
|
9
|
+
symbol: string;
|
|
10
|
+
decimals: number;
|
|
11
|
+
price_usd?: number;
|
|
12
|
+
value_usd?: number;
|
|
13
|
+
name?: string;
|
|
14
|
+
token_metadata?: SimTokenMetadata;
|
|
15
|
+
pool_size?: number;
|
|
16
|
+
low_liquidity?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface SimBalanceResponse {
|
|
19
|
+
request_time: string;
|
|
20
|
+
response_time: string;
|
|
21
|
+
wallet_address: string;
|
|
22
|
+
balances: SimBalanceItem[];
|
|
23
|
+
}
|
|
24
|
+
export declare function useSimBalance(address?: string): import("@tanstack/react-query").UseQueryResult<SimBalanceResponse, Error>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useSimBalance = useSimBalance;
|
|
4
|
+
const react_query_1 = require("@tanstack/react-query");
|
|
5
|
+
async function fetchSimBalance(address) {
|
|
6
|
+
if (!address)
|
|
7
|
+
throw new Error("Address is required");
|
|
8
|
+
const response = await fetch(`https://simdune-api.sean-430.workers.dev/?url=https://api.sim.dune.com/v1/evm/balances/${address}?metadata=logo&localkey=${process.env.PUBLIC_LOCAL_KEY}`);
|
|
9
|
+
if (!response.ok) {
|
|
10
|
+
throw new Error(`Failed to fetch balance: ${response.statusText}`);
|
|
11
|
+
}
|
|
12
|
+
const balanceData = await response.json();
|
|
13
|
+
return balanceData;
|
|
14
|
+
}
|
|
15
|
+
function useSimBalance(address) {
|
|
16
|
+
return (0, react_query_1.useQuery)({
|
|
17
|
+
queryKey: ["simBalance", address],
|
|
18
|
+
queryFn: () => {
|
|
19
|
+
if (!address)
|
|
20
|
+
throw new Error("Address is required");
|
|
21
|
+
return fetchSimBalance(address);
|
|
22
|
+
},
|
|
23
|
+
enabled: Boolean(address),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -110,7 +110,6 @@ function useUnifiedChainSwitchAndExecute() {
|
|
|
110
110
|
try {
|
|
111
111
|
setIsSwitchingOrExecuting(true);
|
|
112
112
|
const chain = (0, supported_1.getThirdwebChain)(targetChainId);
|
|
113
|
-
sonner_1.toast.info("Preparing transaction…");
|
|
114
113
|
const transaction = (0, thirdweb_2.prepareTransaction)({
|
|
115
114
|
client: thirdweb_1.client,
|
|
116
115
|
chain,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { HelpCircle } from "lucide-react";
|
|
2
3
|
export function ChainTokenIcon({ chainUrl, tokenUrl, className = "", }) {
|
|
3
|
-
return (_jsxs("div", { className: `relative ${className}`, children: [_jsx("img", { src: tokenUrl, alt: "Token", className: "h-full w-full rounded-full" }), _jsx("div", { className: "bg-as-on-surface-1 border-as-stroke absolute bottom-0 right-0 h-[45%] w-[45%] rounded border", children: _jsx("img", { src: chainUrl, alt: "Chain", className: "h-full w-full rounded" }) })] }));
|
|
4
|
+
return (_jsxs("div", { className: `relative ${className}`, children: [tokenUrl ? (_jsx("img", { src: tokenUrl, alt: "Token", className: "h-full w-full rounded-full" })) : (_jsx(HelpCircle, { className: "text-b3-react-foreground h-full w-full" })), _jsx("div", { className: "bg-as-on-surface-1 border-as-stroke absolute bottom-0 right-0 h-[45%] w-[45%] rounded border", children: _jsx("img", { src: chainUrl, alt: "Chain", className: "h-full w-full rounded" }) })] }));
|
|
4
5
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface ContentTokensProps {
|
|
2
|
+
activeTab: string;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* ContentTokens Component
|
|
6
|
+
*
|
|
7
|
+
* Displays user's token balances with ability to send tokens. Features:
|
|
8
|
+
* - Animated transitions between token list and send form
|
|
9
|
+
* - Smart filtering (shows all tokens when ≤5 valuable tokens or no $1+ tokens)
|
|
10
|
+
* - NumericFormat inputs for proper number handling
|
|
11
|
+
* - Focus preservation during transitions (see render functions pattern below)
|
|
12
|
+
*/
|
|
13
|
+
export declare function ContentTokens({ activeTab }: ContentTokensProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export {};
|