@b3dotfun/sdk 0.0.30 → 0.0.31-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  Button,
3
- CopyToClipboard,
4
3
  ManageAccountModalProps,
5
4
  TabsContentPrimitive,
6
5
  TabsListPrimitive,
@@ -9,29 +8,27 @@ import {
9
8
  TWSignerWithMetadata,
10
9
  useAccountAssets,
11
10
  useAuthentication,
12
- useB3BalanceFromAddresses,
13
11
  useGetAllTWSigners,
14
12
  useModalStore,
15
- useNativeBalance,
16
- useProfile,
17
13
  useRemoveSessionKey,
18
14
  } from "@b3dotfun/sdk/global-account/react";
19
- import { BankIcon } from "@b3dotfun/sdk/global-account/react/components/icons/BankIcon";
20
15
  import { SignOutIcon } from "@b3dotfun/sdk/global-account/react/components/icons/SignOutIcon";
21
- import { SwapIcon } from "@b3dotfun/sdk/global-account/react/components/icons/SwapIcon";
22
- import { formatUsername } from "@b3dotfun/sdk/shared/utils";
23
16
  import { formatNumber } from "@b3dotfun/sdk/shared/utils/formatNumber";
17
+
24
18
  import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
25
- import { LinkIcon, Loader2, Pencil, Triangle, UnlinkIcon } from "lucide-react";
19
+ import { BarChart3, Coins, Image, LinkIcon, Loader2, Settings, UnlinkIcon } from "lucide-react";
26
20
  import { useState } from "react";
27
21
  import { Chain } from "thirdweb";
28
22
  import { useActiveAccount, useProfiles, useUnlinkProfile } from "thirdweb/react";
29
23
  import { formatUnits } from "viem";
30
- import useFirstEOA from "../../hooks/useFirstEOA";
24
+
31
25
  import { getProfileDisplayInfo } from "../../utils/profileDisplay";
32
26
  import { AccountAssets } from "../AccountAssets/AccountAssets";
27
+ import { ContentTokens } from "./ContentTokens";
33
28
 
34
- type TabValue = "balance" | "assets" | "apps" | "settings";
29
+ import { BalanceContent } from "./BalanceContent";
30
+
31
+ type TabValue = "overview" | "tokens" | "nfts" | "apps" | "settings";
35
32
 
36
33
  interface ManageAccountProps {
37
34
  onLogout?: () => void;
@@ -43,11 +40,6 @@ interface ManageAccountProps {
43
40
  containerClassName?: string;
44
41
  }
45
42
 
46
- function centerTruncate(str: string, length = 4) {
47
- if (str.length <= length * 2) return str;
48
- return `${str.slice(0, length)}...${str.slice(-length)}`;
49
- }
50
-
51
43
  export function ManageAccount({
52
44
  onLogout,
53
45
  onSwap: _onSwap,
@@ -57,28 +49,17 @@ export function ManageAccount({
57
49
  }: ManageAccountProps) {
58
50
  const [revokingSignerId, setRevokingSignerId] = useState<string | null>(null);
59
51
  const account = useActiveAccount();
60
- const { data: assets, isLoading } = useAccountAssets(account?.address);
61
- const { data: b3Balance } = useB3BalanceFromAddresses(account?.address);
62
- const { data: nativeBalance } = useNativeBalance(account?.address);
63
- const { address: eoaAddress } = useFirstEOA();
64
- const { data: profile } = useProfile({
65
- address: eoaAddress || account?.address,
66
- fresh: true,
67
- });
68
- const { data: eoaNativeBalance } = useNativeBalance(eoaAddress);
69
- const { data: eoaB3Balance } = useB3BalanceFromAddresses(eoaAddress);
52
+ const { data: nfts, isLoading } = useAccountAssets(account?.address);
53
+
70
54
  const { data: signers, refetch: refetchSigners } = useGetAllTWSigners({
71
55
  chain,
72
56
  accountAddress: account?.address,
73
57
  });
74
- const { setB3ModalOpen, setB3ModalContentType, contentType } = useModalStore();
75
- const { activeTab = "balance", setActiveTab } = contentType as ManageAccountModalProps;
58
+ const { setB3ModalOpen, contentType } = useModalStore();
59
+ const { activeTab = "overview", setActiveTab } = contentType as ManageAccountModalProps;
76
60
  const { logout } = useAuthentication(partnerId);
77
61
  const [logoutLoading, setLogoutLoading] = useState(false);
78
62
 
79
- console.log("account", account);
80
- console.log("eoaAddress", eoaAddress);
81
-
82
63
  const { removeSessionKey } = useRemoveSessionKey({
83
64
  chain,
84
65
  onSuccess: tx => {
@@ -105,275 +86,6 @@ export function ManageAccount({
105
86
  setLogoutLoading(false);
106
87
  };
107
88
 
108
- const BalanceContent = () => {
109
- const { info: eoaInfo } = useFirstEOA();
110
-
111
- return (
112
- <div className="flex flex-col gap-6">
113
- {/* Profile Section */}
114
- <div className="flex items-center justify-between">
115
- <div className="flex items-center gap-4">
116
- <div className="relative">
117
- {profile?.avatar ? (
118
- <img src={profile?.avatar} alt="Profile" className="size-24 rounded-full" />
119
- ) : (
120
- <div className="bg-b3-primary-wash size-24 rounded-full" />
121
- )}
122
- <div className="bg-b3-grey border-b3-background absolute -bottom-1 -right-1 flex size-8 items-center justify-center rounded-full border-4">
123
- <Pencil size={16} className="text-b3-background" />
124
- </div>
125
- </div>
126
- <div>
127
- <h2 className="text-b3-grey text-xl font-semibold">
128
- {profile?.displayName || formatUsername(profile?.name || "")}
129
- </h2>
130
- <span className="text-b3-foreground-muted">{formatUsername(profile?.name || "")}</span>
131
- </div>
132
- </div>
133
- </div>
134
- <div className="manage-account-address bg-b3-line flex h-11 items-center gap-2 rounded-full px-4">
135
- <span className="text-b3-grey font-neue-montreal-semibold">{centerTruncate(account?.address || "")}</span>
136
- <CopyToClipboard text={account?.address || ""} />
137
- </div>
138
-
139
- {/* Quick Actions */}
140
- <div className="grid grid-cols-2 gap-3">
141
- <Button
142
- 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"
143
- onClick={() => {
144
- setB3ModalOpen(true);
145
- setB3ModalContentType({
146
- type: "anySpend",
147
- defaultActiveTab: "fiat",
148
- showBackButton: true,
149
- });
150
- }}
151
- >
152
- <BankIcon size={24} className="text-b3-primary-blue shrink-0" />
153
- <div className="text-b3-grey font-neue-montreal-semibold">Deposit</div>
154
- </Button>
155
- <Button
156
- 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"
157
- onClick={() => {
158
- setB3ModalOpen(true);
159
- setB3ModalContentType({
160
- type: "anySpend",
161
- showBackButton: true,
162
- });
163
- }}
164
- >
165
- <SwapIcon size={24} className="text-b3-primary-blue" />
166
- <div className="text-b3-grey font-neue-montreal-semibold">Swap</div>
167
- </Button>
168
- </div>
169
-
170
- {/* Balance Section */}
171
- <div className="space-y-4">
172
- <h3 className="text-b3-grey font-neue-montreal-semibold">Balance</h3>
173
-
174
- {/* B3 Balance */}
175
- <div className="flex items-center justify-between">
176
- <div className="flex items-center gap-3">
177
- <div className="flex h-10 w-10 items-center justify-center rounded-full">
178
- <img src="https://cdn.b3.fun/b3-coin-3d.png" alt="B3" className="size-10" />
179
- </div>
180
- <div>
181
- <div className="flex items-center gap-2">
182
- <span className="text-b3-grey font-neue-montreal-semibold">B3</span>
183
- </div>
184
- <div className="text-b3-foreground-muted font-neue-montreal-medium text-sm">
185
- {b3Balance?.formattedTotal || "0.00"} B3
186
- </div>
187
- </div>
188
- </div>
189
- <div className="text-right">
190
- <div className="text-b3-grey font-neue-montreal-semibold">
191
- ${b3Balance?.balanceUsdFormatted || "0.00"}
192
- </div>
193
- <div className="flex items-center gap-1">
194
- {b3Balance?.priceChange24h !== null && b3Balance?.priceChange24h !== undefined ? (
195
- <>
196
- <Triangle
197
- className={`size-3 ${b3Balance.priceChange24h >= 0 ? "text-b3-positive fill-b3-positive" : "text-b3-negative fill-b3-negative rotate-180"}`}
198
- />
199
- <span
200
- className={`font-neue-montreal-medium text-sm ${b3Balance.priceChange24h >= 0 ? "text-b3-positive" : "text-b3-negative"}`}
201
- >
202
- {b3Balance.priceChange24h >= 0 ? "+" : ""}
203
- {b3Balance.priceChange24h.toFixed(2)}%
204
- </span>
205
- </>
206
- ) : (
207
- <span className="text-b3-foreground-muted font-neue-montreal-medium text-sm">--</span>
208
- )}
209
- </div>
210
- </div>
211
- </div>
212
-
213
- {/* ETH Balance */}
214
- <div className="flex items-center justify-between">
215
- <div className="flex items-center gap-3">
216
- <div className="flex h-10 w-10 items-center justify-center rounded-full">
217
- <img src="https://cdn.b3.fun/ethereum.svg" alt="ETH" className="size-10" />
218
- </div>
219
- <div>
220
- <div className="flex items-center gap-2">
221
- <span className="text-b3-grey font-neue-montreal-semibold">Ethereum</span>
222
- </div>
223
- <div className="text-b3-foreground-muted font-neue-montreal-medium text-sm">
224
- {nativeBalance?.formattedTotal || "0.00"} ETH
225
- </div>
226
- </div>
227
- </div>
228
- <div className="text-right">
229
- <div className="text-b3-grey font-neue-montreal-semibold">
230
- ${nativeBalance?.formattedTotalUsd || "0.00"}
231
- </div>
232
- <div className="flex items-center gap-2">
233
- {nativeBalance?.priceChange24h !== null && nativeBalance?.priceChange24h !== undefined ? (
234
- <>
235
- <Triangle
236
- className={`size-3 ${nativeBalance.priceChange24h >= 0 ? "text-b3-positive fill-b3-positive" : "text-b3-negative fill-b3-negative rotate-180"}`}
237
- />
238
- <span
239
- className={`font-neue-montreal-medium text-sm ${nativeBalance.priceChange24h >= 0 ? "text-b3-positive" : "text-b3-negative"}`}
240
- >
241
- {nativeBalance.priceChange24h >= 0 ? "+" : ""}
242
- {nativeBalance.priceChange24h.toFixed(2)}%
243
- </span>
244
- </>
245
- ) : (
246
- <span className="text-b3-foreground-muted font-neue-montreal-medium text-sm">--</span>
247
- )}
248
- </div>
249
- </div>
250
- </div>
251
- </div>
252
-
253
- {/* EOA Account Balance Section - matching global balance styling */}
254
- {eoaAddress && (
255
- <div className="space-y-4">
256
- <h3 className="text-b3-grey font-neue-montreal-semibold">Connected {eoaInfo?.data?.name || "Wallet"}</h3>
257
-
258
- {/* EOA Address */}
259
- <div className="manage-account-address bg-b3-line flex h-11 items-center gap-2 rounded-full px-4">
260
- <span className="text-b3-grey font-neue-montreal-semibold">{centerTruncate(eoaAddress)}</span>
261
- <CopyToClipboard text={eoaAddress} />
262
- </div>
263
-
264
- {/* EOA B3 Balance */}
265
- <div className="flex items-center justify-between">
266
- <div className="flex items-center gap-3">
267
- <div className="flex h-10 w-10 items-center justify-center rounded-full">
268
- <img src="https://cdn.b3.fun/b3-coin-3d.png" alt="B3" className="size-10" />
269
- </div>
270
- <div>
271
- <div className="flex items-center gap-2">
272
- <span className="text-b3-grey font-neue-montreal-semibold">B3</span>
273
- </div>
274
- <div className="text-b3-foreground-muted font-neue-montreal-medium text-sm">
275
- {eoaB3Balance?.formattedTotal || "0.00"} B3
276
- </div>
277
- </div>
278
- </div>
279
- <div className="text-right">
280
- <div className="text-b3-grey font-neue-montreal-semibold">
281
- ${eoaB3Balance?.balanceUsdFormatted || "0.00"}
282
- </div>
283
- <div className="flex items-center gap-1">
284
- {eoaB3Balance?.priceChange24h !== null && eoaB3Balance?.priceChange24h !== undefined ? (
285
- <>
286
- <Triangle
287
- className={`size-3 ${eoaB3Balance.priceChange24h >= 0 ? "text-b3-positive fill-b3-positive" : "text-b3-negative fill-b3-negative rotate-180"}`}
288
- />
289
- <span
290
- className={`font-neue-montreal-medium text-sm ${eoaB3Balance.priceChange24h >= 0 ? "text-b3-positive" : "text-b3-negative"}`}
291
- >
292
- {eoaB3Balance.priceChange24h >= 0 ? "+" : ""}
293
- {eoaB3Balance.priceChange24h.toFixed(2)}%
294
- </span>
295
- </>
296
- ) : (
297
- <span className="text-b3-foreground-muted font-neue-montreal-medium text-sm">--</span>
298
- )}
299
- </div>
300
- </div>
301
- </div>
302
-
303
- {/* EOA ETH Balance */}
304
- <div className="flex items-center justify-between">
305
- <div className="flex items-center gap-3">
306
- <div className="flex h-10 w-10 items-center justify-center rounded-full">
307
- <img src="https://cdn.b3.fun/ethereum.svg" alt="ETH" className="size-10" />
308
- </div>
309
- <div>
310
- <div className="flex items-center gap-2">
311
- <span className="text-b3-grey font-neue-montreal-semibold">Ethereum</span>
312
- </div>
313
- <div className="text-b3-foreground-muted font-neue-montreal-medium text-sm">
314
- {eoaNativeBalance?.formattedTotal || "0.00"} ETH
315
- </div>
316
- </div>
317
- </div>
318
- <div className="text-right">
319
- <div className="text-b3-grey font-neue-montreal-semibold">
320
- ${eoaNativeBalance?.formattedTotalUsd || "0.00"}
321
- </div>
322
- <div className="flex items-center gap-2">
323
- {eoaNativeBalance?.priceChange24h !== null && eoaNativeBalance?.priceChange24h !== undefined ? (
324
- <>
325
- <Triangle
326
- className={`size-3 ${eoaNativeBalance.priceChange24h >= 0 ? "text-b3-positive fill-b3-positive" : "text-b3-negative fill-b3-negative rotate-180"}`}
327
- />
328
- <span
329
- className={`font-neue-montreal-medium text-sm ${eoaNativeBalance.priceChange24h >= 0 ? "text-b3-positive" : "text-b3-negative"}`}
330
- >
331
- {eoaNativeBalance.priceChange24h >= 0 ? "+" : ""}
332
- {eoaNativeBalance.priceChange24h.toFixed(2)}%
333
- </span>
334
- </>
335
- ) : (
336
- <span className="text-b3-foreground-muted font-neue-montreal-medium text-sm">--</span>
337
- )}
338
- </div>
339
- </div>
340
- </div>
341
- </div>
342
- )}
343
-
344
- {/* Global Account Info */}
345
- <div className="border-b3-line flex items-center justify-between rounded-2xl border p-4">
346
- <div className="">
347
- <div className="flex items-center gap-2">
348
- <img src="https://cdn.b3.fun/b3_logo.svg" alt="B3" className="h-4" />
349
- <h3 className="font-neue-montreal-semibold text-b3-grey">Global Account</h3>
350
- </div>
351
-
352
- <p className="text-b3-foreground-muted font-neue-montreal-medium mt-2 text-sm">
353
- Your universal account for all B3-powered apps
354
- </p>
355
- </div>
356
- <button
357
- 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"
358
- onClick={onLogoutEnhanced}
359
- >
360
- {logoutLoading ? <Loader2 className="animate-spin" /> : <SignOutIcon size={16} className="text-b3-grey" />}
361
- </button>
362
- </div>
363
- </div>
364
- );
365
- };
366
-
367
- const AssetsContent = () => (
368
- <div className="grid grid-cols-3 gap-4">
369
- {assets?.nftResponse ? (
370
- <AccountAssets nfts={assets.nftResponse} isLoading={isLoading} />
371
- ) : (
372
- <div className="col-span-3 py-12 text-center text-gray-500">No NFTs found</div>
373
- )}
374
- </div>
375
- );
376
-
377
89
  const AppsContent = () => (
378
90
  <div className="space-y-4">
379
91
  {signers?.map((signer: TWSignerWithMetadata) => (
@@ -429,10 +141,7 @@ export function ManageAccount({
429
141
  const handleUnlink = async (profile: any) => {
430
142
  setUnlinkingAccountId(profile.title);
431
143
  try {
432
- await unlinkProfile({
433
- client,
434
- profileToUnlink: profile.originalProfile,
435
- });
144
+ unlinkProfile({ client, profileToUnlink: profile.originalProfile });
436
145
  } catch (error) {
437
146
  console.error("Error unlinking account:", error);
438
147
  } finally {
@@ -558,7 +267,7 @@ export function ManageAccount({
558
267
  </div>
559
268
 
560
269
  <p className="text-b3-foreground-muted font-neue-montreal-medium mt-2 text-sm">
561
- Your universal account for all B3-powered apps
270
+ Your universal account for all B3 apps
562
271
  </p>
563
272
  </div>
564
273
  <button
@@ -579,55 +288,91 @@ export function ManageAccount({
579
288
  defaultValue={activeTab}
580
289
  onValueChange={value => {
581
290
  const tab = value as TabValue;
582
- if (["balance", "assets", "apps", "settings"].includes(tab)) {
291
+ if (["overview", "tokens", "nfts", "apps", "settings"].includes(tab)) {
583
292
  setActiveTab?.(tab);
584
293
  }
585
294
  }}
586
295
  >
587
- <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">
588
- <TabTriggerPrimitive
589
- value="balance"
590
- 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"
591
- >
592
- Overview
593
- </TabTriggerPrimitive>
594
- <TabTriggerPrimitive
595
- value="assets"
596
- 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"
597
- >
598
- Mints
599
- </TabTriggerPrimitive>
600
- {/*
601
- // TODO: Apps is a remnant of session key flow. Moving forward, we should find a way to properly associate apps from linked partners that a user has logged in with
602
- https://linear.app/npclabs/issue/B3-2318/find-a-way-to-properly-display-which-partner-apps-a-user-has-logged-in
603
-
604
- <TabTriggerPrimitive
605
- value="apps"
606
- 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"
607
- >
608
- Apps
609
- </TabTriggerPrimitive> */}
610
- <TabTriggerPrimitive
611
- value="settings"
612
- 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"
613
- >
614
- Settings
615
- </TabTriggerPrimitive>
616
- </TabsListPrimitive>
296
+ <div className="px-4">
297
+ <TabsListPrimitive className="grid h-auto grid-cols-2 grid-rows-2 gap-3 rounded-none border-none bg-transparent">
298
+ <TabTriggerPrimitive
299
+ value="overview"
300
+ 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"
301
+ >
302
+ <BarChart3 size={20} className="text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" />
303
+ <span className="text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white">
304
+ Overview
305
+ </span>
306
+ </TabTriggerPrimitive>
307
+ <TabTriggerPrimitive
308
+ value="tokens"
309
+ 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"
310
+ >
311
+ <Coins size={20} className="text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" />
312
+ <span className="text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white">
313
+ Tokens
314
+ </span>
315
+ </TabTriggerPrimitive>
316
+ <TabTriggerPrimitive
317
+ value="nfts"
318
+ 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"
319
+ >
320
+ <Image size={20} className="text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" />
321
+ <span className="text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white">
322
+ NFTs
323
+ </span>
324
+ </TabTriggerPrimitive>
325
+ {/*
326
+ // TODO: Apps is a remnant of session key flow. Moving forward, we should find a way to properly associate apps from linked partners that a user has logged in with
327
+ // https://linear.app/npclabs/issue/B3-2318/find-a-way-to-properly-display-which-partner-apps-a-user-has-logged-in
328
+ <TabTriggerPrimitive
329
+ value="apps"
330
+ 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-16 w-full flex-col items-start justify-between rounded-xl border border-gray-200 bg-white p-3 text-left shadow-sm transition-all duration-200 hover:bg-gray-50 hover:shadow-md data-[state=active]:shadow-lg col-start-1 col-end-2"
331
+ >
332
+ <div className="flex w-full items-center justify-between">
333
+ <Grid3X3 size={20} className="text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" />
334
+ <span className="text-b3-grey font-neue-montreal-bold text-lg group-data-[state=active]:text-white">4</span>
335
+ </div>
336
+ <span className="text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white">
337
+ Apps
338
+ </span>
339
+ </TabTriggerPrimitive>
340
+ */}
341
+ <TabTriggerPrimitive
342
+ value="settings"
343
+ 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"
344
+ >
345
+ <Settings size={20} className="text-b3-primary-blue shrink-0 group-data-[state=active]:text-white" />
346
+ <span className="text-b3-grey font-neue-montreal-semibold text-sm group-data-[state=active]:text-white">
347
+ Settings
348
+ </span>
349
+ </TabTriggerPrimitive>
350
+ </TabsListPrimitive>
351
+ </div>
352
+
353
+ <TabsContentPrimitive value="overview" className="px-4 pb-4 pt-2">
354
+ <BalanceContent onLogout={onLogout} partnerId={partnerId} />
355
+ </TabsContentPrimitive>
617
356
 
618
- <TabsContentPrimitive value="balance" className="pt-4 md:p-4">
619
- <BalanceContent />
357
+ <TabsContentPrimitive value="tokens" className="px-4 pb-4 pt-2">
358
+ <ContentTokens activeTab={activeTab} />
620
359
  </TabsContentPrimitive>
621
360
 
622
- <TabsContentPrimitive value="assets" className="pt-4 md:p-4">
623
- <AssetsContent />
361
+ <TabsContentPrimitive value="nfts" className="px-4 pb-4 pt-2">
362
+ <div className="grid grid-cols-3 gap-4">
363
+ {nfts?.nftResponse ? (
364
+ <AccountAssets nfts={nfts.nftResponse} isLoading={isLoading} />
365
+ ) : (
366
+ <div className="col-span-3 py-12 text-center text-gray-500">No NFTs found</div>
367
+ )}
368
+ </div>
624
369
  </TabsContentPrimitive>
625
370
 
626
- <TabsContentPrimitive value="apps" className="pt-4 md:p-4">
371
+ <TabsContentPrimitive value="apps" className="px-4 pb-4 pt-2">
627
372
  <AppsContent />
628
373
  </TabsContentPrimitive>
629
374
 
630
- <TabsContentPrimitive value="settings" className="pt-4 md:p-4">
375
+ <TabsContentPrimitive value="settings" className="px-4 pb-4 pt-2">
631
376
  <SettingsContent />
632
377
  </TabsContentPrimitive>
633
378
  </TabsPrimitive>
@@ -0,0 +1,46 @@
1
+ import { Triangle } from "lucide-react";
2
+ import { ReactNode } from "react";
3
+
4
+ interface TokenBalanceRowProps {
5
+ icon: ReactNode;
6
+ name: string;
7
+ balance: string;
8
+ usdValue: string;
9
+ priceChange?: number | null;
10
+ }
11
+
12
+ export function TokenBalanceRow({ icon, name, balance, usdValue, priceChange }: TokenBalanceRowProps) {
13
+ return (
14
+ <div className="flex items-center justify-between">
15
+ <div className="flex items-center gap-3">
16
+ <div className="flex h-10 w-10 items-center justify-center rounded-full">{icon}</div>
17
+ <div>
18
+ <div className="flex items-center gap-2">
19
+ <span className="text-b3-grey font-neue-montreal-semibold">{name}</span>
20
+ </div>
21
+ <div className="text-b3-foreground-muted font-neue-montreal-medium text-sm">{balance}</div>
22
+ </div>
23
+ </div>
24
+ <div className="text-right">
25
+ <div className="text-b3-grey font-neue-montreal-semibold">${usdValue}</div>
26
+ <div className="flex items-center gap-1">
27
+ {priceChange !== null && priceChange !== undefined ? (
28
+ <>
29
+ <Triangle
30
+ className={`size-3 ${priceChange >= 0 ? "text-b3-positive fill-b3-positive" : "text-b3-negative fill-b3-negative rotate-180"}`}
31
+ />
32
+ <span
33
+ className={`font-neue-montreal-medium text-sm ${priceChange >= 0 ? "text-b3-positive" : "text-b3-negative"}`}
34
+ >
35
+ {priceChange >= 0 ? "+" : ""}
36
+ {priceChange.toFixed(2)}%
37
+ </span>
38
+ </>
39
+ ) : (
40
+ <span className="text-b3-foreground-muted font-neue-montreal-medium text-sm">--</span>
41
+ )}
42
+ </div>
43
+ </div>
44
+ </div>
45
+ );
46
+ }
@@ -0,0 +1,87 @@
1
+ import { cn } from "@b3dotfun/sdk/shared/utils";
2
+ import React, { useCallback, useMemo, useState } from "react";
3
+
4
+ interface TokenIconProps {
5
+ src: string;
6
+ alt: string;
7
+ className?: string;
8
+ size?: number;
9
+ }
10
+
11
+ // Create a global image cache to prevent re-loading
12
+ const imageCache = new Map<string, boolean>();
13
+
14
+ export const TokenIcon: React.FC<TokenIconProps> = ({ src, alt, className, size = 40 }) => {
15
+ const [isLoaded, setIsLoaded] = useState(() => imageCache.get(src) || false);
16
+ const [hasError, setHasError] = useState(false);
17
+
18
+ const handleLoad = useCallback(() => {
19
+ imageCache.set(src, true);
20
+ setIsLoaded(true);
21
+ }, [src]);
22
+
23
+ const handleError = useCallback(() => {
24
+ setHasError(true);
25
+ }, []);
26
+
27
+ // Memoize the image element to prevent unnecessary re-renders
28
+ const imageElement = useMemo(
29
+ () => (
30
+ <img
31
+ src={src}
32
+ alt={alt}
33
+ className={cn("transition-opacity duration-200", className, {
34
+ "opacity-100": isLoaded && !hasError,
35
+ "opacity-0": !isLoaded || hasError,
36
+ })}
37
+ onLoad={handleLoad}
38
+ onError={handleError}
39
+ loading="eager" // Load immediately since these are critical UI elements
40
+ decoding="async"
41
+ style={{
42
+ width: size,
43
+ height: size,
44
+ }}
45
+ />
46
+ ),
47
+ [src, alt, className, isLoaded, hasError, handleLoad, handleError, size],
48
+ );
49
+
50
+ // Show a placeholder while loading or if there's an error
51
+ const placeholder = useMemo(
52
+ () => (
53
+ <div
54
+ className={cn(
55
+ "bg-b3-primary-wash flex items-center justify-center rounded-full transition-opacity duration-200",
56
+ {
57
+ "opacity-0": isLoaded && !hasError,
58
+ "opacity-100": !isLoaded || hasError,
59
+ },
60
+ )}
61
+ style={{
62
+ width: size,
63
+ height: size,
64
+ }}
65
+ >
66
+ <span className="text-b3-grey font-neue-montreal-semibold text-xs">{alt.charAt(0).toUpperCase()}</span>
67
+ </div>
68
+ ),
69
+ [alt, isLoaded, hasError, size],
70
+ );
71
+
72
+ return (
73
+ <div className="relative inline-block" style={{ width: size, height: size }}>
74
+ {placeholder}
75
+ <div className="absolute inset-0">{imageElement}</div>
76
+ </div>
77
+ );
78
+ };
79
+
80
+ // Pre-defined token icons for common tokens
81
+ export const B3TokenIcon: React.FC<Omit<TokenIconProps, "src" | "alt">> = props => (
82
+ <TokenIcon src="https://cdn.b3.fun/b3-coin-3d.png" alt="B3" {...props} />
83
+ );
84
+
85
+ export const EthereumTokenIcon: React.FC<Omit<TokenIconProps, "src" | "alt">> = props => (
86
+ <TokenIcon src="https://cdn.b3.fun/ethereum.svg" alt="ETH" {...props} />
87
+ );