Skip to content

Commit 017b13f

Browse files
committed
[SDK] Feature: ConnectedWalletDetails to use headless UI (#5429)
## Problem solved Short description of the bug fixed or feature added <!-- start pr-codex --> --- ## PR-Codex overview This PR focuses on refactoring the wallet connection components in the `thirdweb` package, specifically enhancing the `ConnectButton` and `ConnectedWalletDetails` components by integrating `AccountProvider` and improving the handling of wallet details. ### Detailed summary - Updated JSDoc comment in `useConnectedWalletDetails` to indicate its limited usage. - Wrapped `ConnectedWalletDetails` with `AccountProvider` in `ConnectButtonInner`. - Removed `useConnectedWalletDetails` from `ConnectedWalletDetails`. - Enhanced `ConnectedWalletDetails` to use `AccountAvatar`, `AccountName`, and `AccountBalance` components. - Updated props handling for connected account avatar and name in `ConnectedWalletDetails`. - Refactored balance display logic in `ConnectedWalletDetails` to use `AccountBalance`. - Modified `DetailsModal` to utilize `AccountProvider` and improved wallet avatar handling. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 901c3a1 commit 017b13f

File tree

3 files changed

+127
-90
lines changed

3 files changed

+127
-90
lines changed

packages/thirdweb/src/react/core/utils/wallet.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ export function useEnsAvatar(options: {
7777
}
7878

7979
/**
80-
* @internal
80+
* @internal This hook is only being used in our react-native package
81+
* It can be removed once we migrate the RN UI code to our headless components (AccountProvider, AccountName etc.)
8182
*/
8283
export function useConnectedWalletDetails(
8384
client: ThirdwebClient,

packages/thirdweb/src/react/web/ui/ConnectWallet/ConnectButton.tsx

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { Spinner } from "../components/Spinner.js";
2323
import { Container } from "../components/basic.js";
2424
import { Button } from "../components/buttons.js";
2525
import { fadeInAnimation } from "../design-system/animations.js";
26+
import { AccountProvider } from "../prebuilt/Account/provider.js";
2627
import { ConnectedWalletDetails } from "./Details.js";
2728
import ConnectModal from "./Modal/ConnectModal.js";
2829
import { LockIcon } from "./icons/LockIcon.js";
@@ -532,37 +533,39 @@ function ConnectButtonInner(
532533
}
533534

534535
return (
535-
<ConnectedWalletDetails
536-
theme={theme}
537-
detailsButton={props.detailsButton}
538-
detailsModal={props.detailsModal}
539-
supportedTokens={supportedTokens}
540-
supportedNFTs={props.supportedNFTs}
541-
onDisconnect={(info) => {
542-
// logout on explicit disconnect!
543-
if (siweAuth.requiresAuth) {
544-
siweAuth.doLogout();
545-
}
546-
props.onDisconnect?.(info);
547-
}}
548-
chains={props?.chains || []}
549-
chain={props.chain}
550-
switchButton={props.switchButton}
551-
client={props.client}
552-
connectLocale={locale}
553-
connectOptions={{
554-
accountAbstraction: props.accountAbstraction,
555-
appMetadata: props.appMetadata,
556-
chain: props.chain,
557-
chains: props.chains,
558-
connectModal: props.connectModal,
559-
recommendedWallets: props.recommendedWallets,
560-
showAllWallets: props.showAllWallets,
561-
walletConnect: props.walletConnect,
562-
wallets: props.wallets,
563-
hiddenWallets: props.detailsModal?.hiddenWallets,
564-
}}
565-
/>
536+
<AccountProvider address={activeAccount.address} client={props.client}>
537+
<ConnectedWalletDetails
538+
theme={theme}
539+
detailsButton={props.detailsButton}
540+
detailsModal={props.detailsModal}
541+
supportedTokens={supportedTokens}
542+
supportedNFTs={props.supportedNFTs}
543+
onDisconnect={(info) => {
544+
// logout on explicit disconnect!
545+
if (siweAuth.requiresAuth) {
546+
siweAuth.doLogout();
547+
}
548+
props.onDisconnect?.(info);
549+
}}
550+
chains={props?.chains || []}
551+
chain={props.chain}
552+
switchButton={props.switchButton}
553+
client={props.client}
554+
connectLocale={locale}
555+
connectOptions={{
556+
accountAbstraction: props.accountAbstraction,
557+
appMetadata: props.appMetadata,
558+
chain: props.chain,
559+
chains: props.chains,
560+
connectModal: props.connectModal,
561+
recommendedWallets: props.recommendedWallets,
562+
showAllWallets: props.showAllWallets,
563+
walletConnect: props.walletConnect,
564+
wallets: props.wallets,
565+
hiddenWallets: props.detailsModal?.hiddenWallets,
566+
}}
567+
/>
568+
</AccountProvider>
566569
);
567570
}
568571

packages/thirdweb/src/react/web/ui/ConnectWallet/Details.tsx

Lines changed: 91 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type { Chain } from "../../../../chains/types.js";
1515
import type { ThirdwebClient } from "../../../../client/client.js";
1616
import { getContract } from "../../../../contract/contract.js";
1717
import { getLastAuthProvider } from "../../../../react/core/utils/storage.js";
18+
import { shortenAddress } from "../../../../utils/address.js";
1819
import { isContractDeployed } from "../../../../utils/bytecode/is-contract-deployed.js";
1920
import { formatNumber } from "../../../../utils/formatNumber.js";
2021
import { webLocalStorage } from "../../../../utils/storage/webStorage.js";
@@ -67,10 +68,7 @@ import type {
6768
SupportedTokens,
6869
} from "../../../core/utils/defaultTokens.js";
6970
import { hasSmartAccount } from "../../../core/utils/isSmartWallet.js";
70-
import {
71-
useConnectedWalletDetails,
72-
useWalletInfo,
73-
} from "../../../core/utils/wallet.js";
71+
import { useWalletInfo } from "../../../core/utils/wallet.js";
7472
import { WalletUIStatesProvider } from "../../providers/wallet-ui-states-provider.js";
7573
import { ChainIcon } from "../components/ChainIcon.js";
7674
import { CopyIcon } from "../components/CopyIcon.js";
@@ -86,8 +84,13 @@ import { Button, IconButton } from "../components/buttons.js";
8684
import { Link, Text } from "../components/text.js";
8785
import { fadeInAnimation } from "../design-system/animations.js";
8886
import { StyledButton } from "../design-system/elements.js";
87+
import { AccountAddress } from "../prebuilt/Account/address.js";
88+
import { AccountAvatar } from "../prebuilt/Account/avatar.js";
89+
import { AccountBalance } from "../prebuilt/Account/balance.js";
90+
import { AccountBlobbie } from "../prebuilt/Account/blobbie.js";
91+
import { AccountName } from "../prebuilt/Account/name.js";
92+
import { AccountProvider } from "../prebuilt/Account/provider.js";
8993
import type { LocaleId } from "../types.js";
90-
import { Blobbie } from "./Blobbie.js";
9194
import { MenuButton, MenuLink } from "./MenuButton.js";
9295
import { ScreenSetupContext, useSetupScreen } from "./Modal/screen.js";
9396
import {
@@ -140,18 +143,10 @@ export const ConnectedWalletDetails: React.FC<{
140143
connectOptions: DetailsModalConnectOptions | undefined;
141144
}> = (props) => {
142145
const { connectLocale: locale, client } = props;
143-
144146
const setRootEl = useContext(SetRootElementContext);
145147
const activeAccount = useActiveAccount();
146148
const walletChain = useActiveWalletChain();
147149

148-
const { pfp, name, balanceQuery } = useConnectedWalletDetails(
149-
client,
150-
walletChain,
151-
activeAccount,
152-
props.detailsButton?.displayBalanceToken,
153-
);
154-
155150
function closeModal() {
156151
setRootEl(null);
157152
}
@@ -199,8 +194,6 @@ export const ConnectedWalletDetails: React.FC<{
199194
);
200195
}
201196

202-
const avatarSrc = props.detailsButton?.connectedAccountAvatarUrl || pfp;
203-
204197
const combinedClassName = `${TW_CONNECTED_WALLET} ${props.detailsButton?.className || ""}`;
205198

206199
return (
@@ -219,18 +212,27 @@ export const ConnectedWalletDetails: React.FC<{
219212
height: "35px",
220213
}}
221214
>
222-
{avatarSrc ? (
215+
{props.detailsButton?.connectedAccountAvatarUrl ? (
223216
<img
224217
alt=""
225-
src={avatarSrc}
218+
src={props.detailsButton.connectedAccountAvatarUrl}
226219
style={{
227220
height: "100%",
228221
width: "100%",
229222
objectFit: "cover",
230223
}}
231224
/>
232225
) : (
233-
activeAccount && <Blobbie address={activeAccount.address} size={35} />
226+
activeAccount && (
227+
<AccountAvatar
228+
loadingComponent={<AccountBlobbie size={35} />}
229+
fallbackComponent={<AccountBlobbie size={35} />}
230+
queryOptions={{
231+
refetchOnWindowFocus: false,
232+
refetchOnMount: false,
233+
}}
234+
/>
235+
)
234236
)}
235237
</Container>
236238
<Container
@@ -243,29 +245,47 @@ export const ConnectedWalletDetails: React.FC<{
243245
}}
244246
>
245247
{/* Address */}
246-
<Text
247-
size="xs"
248-
color="primaryText"
249-
weight={500}
250-
className={`${TW_CONNECTED_WALLET}__address`}
251-
>
252-
{props.detailsButton?.connectedAccountName ?? name}
253-
</Text>
254-
255-
{/* Balance */}
256-
{balanceQuery.data ? (
248+
{props.detailsButton?.connectedAccountName ? (
257249
<Text
258-
className={`${TW_CONNECTED_WALLET}__balance`}
259250
size="xs"
260-
color="secondaryText"
261-
weight={400}
251+
color="primaryText"
252+
weight={500}
253+
className={`${TW_CONNECTED_WALLET}__address`}
262254
>
263-
{formatBalanceOnButton(Number(balanceQuery.data.displayValue))}{" "}
264-
{balanceQuery.data.symbol}
255+
{props.detailsButton.connectedAccountName}
265256
</Text>
266257
) : (
267-
<Skeleton height={fontSize.xs} width="70px" />
258+
<Text
259+
size="xs"
260+
color="primaryText"
261+
weight={500}
262+
className={`${TW_CONNECTED_WALLET}__address`}
263+
>
264+
<AccountName
265+
loadingComponent={<AccountAddress formatFn={shortenAddress} />}
266+
fallbackComponent={<AccountAddress formatFn={shortenAddress} />}
267+
/>
268+
</Text>
268269
)}
270+
271+
<Text
272+
className={`${TW_CONNECTED_WALLET}__balance`}
273+
size="xs"
274+
color="secondaryText"
275+
weight={400}
276+
>
277+
<AccountBalance
278+
chain={walletChain}
279+
loadingComponent={<Skeleton height={fontSize.xs} width="70px" />}
280+
fallbackComponent={<Skeleton height={fontSize.xs} width="70px" />}
281+
formatFn={formatBalanceOnButton}
282+
tokenAddress={
283+
props.detailsButton?.displayBalanceToken?.[
284+
Number(walletChain?.id)
285+
]
286+
}
287+
/>
288+
</Text>
269289
</Container>
270290
</WalletInfoButton>
271291
);
@@ -295,12 +315,6 @@ function DetailsModal(props: {
295315
const { client, locale } = props;
296316
const walletChain = useActiveWalletChain();
297317
const activeAccount = useActiveAccount();
298-
const { pfp, name, balanceQuery } = useConnectedWalletDetails(
299-
client,
300-
walletChain,
301-
activeAccount,
302-
props.displayBalanceToken,
303-
);
304318
const theme = parseTheme(props.theme);
305319

306320
const activeWallet = useActiveWallet();
@@ -363,12 +377,15 @@ function DetailsModal(props: {
363377
<Text color="primaryText" size="md" multiline>
364378
{chainNameQuery.name || `Unknown chain #${walletChain?.id}`}
365379
<Text color="secondaryText" size="xs">
366-
{balanceQuery.data ? (
367-
formatNumber(Number(balanceQuery.data.displayValue), 9)
368-
) : (
369-
<Skeleton height="1em" width="100px" />
370-
)}{" "}
371-
{balanceQuery.data?.symbol}
380+
<AccountBalance
381+
fallbackComponent={<Skeleton height="1em" width="100px" />}
382+
loadingComponent={<Skeleton height="1em" width="100px" />}
383+
formatFn={(num: number) => formatNumber(num, 9)}
384+
chain={walletChain}
385+
tokenAddress={
386+
props.displayBalanceToken?.[Number(walletChain?.id)]
387+
}
388+
/>
372389
</Text>
373390
</Text>
374391
)}
@@ -384,8 +401,6 @@ function DetailsModal(props: {
384401
</MenuButton>
385402
);
386403

387-
const avatarSrc = props.detailsModal?.connectedAccountAvatarUrl ?? pfp;
388-
389404
const { hideSendFunds, hideReceiveFunds, hideBuyFunds } =
390405
props.detailsModal || {};
391406

@@ -407,9 +422,9 @@ function DetailsModal(props: {
407422
overflow: "hidden",
408423
}}
409424
>
410-
{avatarSrc ? (
425+
{props.detailsModal?.connectedAccountAvatarUrl ? (
411426
<img
412-
src={avatarSrc}
427+
src={props.detailsModal.connectedAccountAvatarUrl}
413428
style={{
414429
height: "100%",
415430
width: "100%",
@@ -419,9 +434,9 @@ function DetailsModal(props: {
419434
/>
420435
) : (
421436
activeAccount && (
422-
<Blobbie
423-
address={activeAccount.address}
424-
size={Number(iconSize.xxl)}
437+
<AccountAvatar
438+
loadingComponent={<AccountBlobbie size={Number(iconSize.xxl)} />}
439+
fallbackComponent={<AccountBlobbie size={Number(iconSize.xxl)} />}
425440
/>
426441
)
427442
)}
@@ -496,9 +511,22 @@ function DetailsModal(props: {
496511
alignItems: "center",
497512
}}
498513
>
499-
<Text color="primaryText" weight={500} size="md">
500-
{props.detailsModal?.connectedAccountName ?? name}
501-
</Text>
514+
{props.detailsModal?.connectedAccountName ? (
515+
<Text color="primaryText" weight={500} size="md">
516+
{props.detailsModal.connectedAccountName}
517+
</Text>
518+
) : (
519+
<Text color="primaryText" weight={500} size="md">
520+
<AccountName
521+
loadingComponent={
522+
<AccountAddress formatFn={shortenAddress} />
523+
}
524+
fallbackComponent={
525+
<AccountAddress formatFn={shortenAddress} />
526+
}
527+
/>
528+
</Text>
529+
)}
502530
<IconButton>
503531
<CopyIcon
504532
text={activeAccount?.address || ""}
@@ -964,7 +992,12 @@ function DetailsModal(props: {
964992
}
965993
}}
966994
>
967-
{content}
995+
<AccountProvider
996+
address={activeAccount?.address || ""}
997+
client={client}
998+
>
999+
{content}
1000+
</AccountProvider>
9681001
</Modal>
9691002
</ScreenSetupContext.Provider>
9701003
</WalletUIStatesProvider>

0 commit comments

Comments
 (0)