Skip to content

Commit dd8c382

Browse files
committed
[SDK] Options to custonize ViewAssets's tabs (#5126)
## Problem solved Short description of the bug fixed or feature added <!-- start pr-codex --> --- ## PR-Codex overview This PR focuses on enhancing the `ConnectButton` component by allowing customization of the asset tab display order in the "View Assets" section. Users can now specify whether to show the "Tokens" or "NFTs" tab first, and an empty array will hide the "View Funds" button. ### Detailed summary - Added `assetTabs` prop to `ConnectButton` for customizing asset tab order. - Updated `ViewAssets` to dynamically render tabs based on `assetTabs` prop. - Modified `DetailsModal` to conditionally display "View Funds" button based on `assetTabs` length. - Enhanced documentation with instructions for using the new feature. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 57553b7 commit dd8c382

File tree

5 files changed

+118
-40
lines changed

5 files changed

+118
-40
lines changed

.changeset/mean-mails-exercise.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
"thirdweb": minor
3+
---
4+
5+
Allow to customize the display order of Asset tabs
6+
7+
When you click on "View Assets", by default the "Tokens" tab is shown first.
8+
9+
If you want to show the "NFTs" tab first, change the order of the asset tabs to: ["nft", "token"]
10+
11+
Note: If an empty array is passed, the [View Funds] button will be hidden
12+
13+
```tsx
14+
<ConnectButton
15+
client={client}
16+
detailsModal={{
17+
assetTabs: ["nft", "token"],
18+
}}
19+
/>
20+
```

packages/thirdweb/src/react/core/hooks/connection/ConnectButtonProps.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { ThirdwebClient } from "../../../../client/client.js";
33
import type { BuyWithCryptoStatus } from "../../../../pay/buyWithCrypto/getStatus.js";
44
import type { BuyWithFiatStatus } from "../../../../pay/buyWithFiat/getStatus.js";
55
import type { FiatProvider } from "../../../../pay/utils/commonTypes.js";
6+
import type { AssetTabs } from "../../../../react/web/ui/ConnectWallet/screens/ViewAssets.js";
67
import type { PreparedTransaction } from "../../../../transaction/prepare-transaction.js";
78
import type { Prettify } from "../../../../utils/type-utils.js";
89
import type { Account, Wallet } from "../../../../wallets/interfaces/wallet.js";
@@ -311,6 +312,13 @@ export type ConnectButton_detailsModalOptions = {
311312
* All wallet IDs included in this array will be hidden from wallet selection when connected.
312313
*/
313314
hiddenWallets?: WalletId[];
315+
316+
/**
317+
* When you click on "View Assets", by default the "Tokens" tab is shown first.
318+
* If you want to show the "NFTs" tab first, change the order of the asset tabs to: ["nft", "token"]
319+
* Note: If an empty array is passed, the [View Funds] button will be hidden
320+
*/
321+
assetTabs?: AssetTabs[];
314322
};
315323

316324
/**

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,20 @@ const TW_CONNECT_WALLET = "tw-connect-wallet";
247247
* />
248248
* ```
249249
*
250+
* ### Customizing the orders of the tabs in the [View Funds] screen
251+
* When you click on "View Assets", by default the "Tokens" tab is shown first.
252+
* If you want to show the "NFTs" tab first, change the order of the asset tabs to: ["nft", "token"]
253+
* Note: If an empty array is passed, the [View Funds] button will be hidden
254+
*
255+
* ```tsx
256+
* <ConnectButton
257+
* client={client}
258+
* detailsModal={{
259+
* assetTabs: ["nft", "token"],
260+
* }}
261+
* />
262+
* ```
263+
*
250264
* @param props
251265
* Props for the `ConnectButton` component
252266
*

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

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ import { ManageWalletScreen } from "./screens/ManageWalletScreen.js";
109109
import { PrivateKey } from "./screens/PrivateKey.js";
110110
import { ReceiveFunds } from "./screens/ReceiveFunds.js";
111111
import { SendFunds } from "./screens/SendFunds.js";
112-
import { ViewAssets } from "./screens/ViewAssets.js";
112+
import { type AssetTabs, ViewAssets } from "./screens/ViewAssets.js";
113113
import { ViewNFTs } from "./screens/ViewNFTs.js";
114114
import { ViewTokens } from "./screens/ViewTokens.js";
115115
import { WalletConnectReceiverScreen } from "./screens/WalletConnectReceiverScreen.js";
@@ -170,6 +170,7 @@ export const ConnectedWalletDetails: React.FC<{
170170
chains={props.chains}
171171
displayBalanceToken={props.detailsButton?.displayBalanceToken}
172172
connectOptions={props.connectOptions}
173+
assetTabs={props.detailsModal?.assetTabs}
173174
/>,
174175
);
175176
}
@@ -284,6 +285,7 @@ function DetailsModal(props: {
284285
chains: Chain[];
285286
displayBalanceToken?: Record<number, string>;
286287
connectOptions: DetailsModalConnectOptions | undefined;
288+
assetTabs?: AssetTabs[];
287289
}) {
288290
const [screen, setScreen] = useState<WalletDetailsModalScreen>("main");
289291
const { disconnect } = useDisconnect();
@@ -627,21 +629,24 @@ function DetailsModal(props: {
627629
</MenuButton>
628630

629631
{/* View Funds */}
630-
<MenuButton
631-
onClick={() => {
632-
setScreen("view-assets");
633-
}}
634-
style={{
635-
fontSize: fontSize.sm,
636-
}}
637-
>
638-
<CoinsIcon size={iconSize.md} />
639-
<Text color="primaryText">
640-
{props.supportedNFTs
641-
? locale.viewFunds.viewAssets
642-
: locale.viewFunds.title}
643-
</Text>
644-
</MenuButton>
632+
{/* Hide the View Funds button if the assetTabs props is set to an empty array */}
633+
{(props.assetTabs === undefined || props.assetTabs.length) && (
634+
<MenuButton
635+
onClick={() => {
636+
setScreen("view-assets");
637+
}}
638+
style={{
639+
fontSize: fontSize.sm,
640+
}}
641+
>
642+
<CoinsIcon size={iconSize.md} />
643+
<Text color="primaryText">
644+
{props.supportedNFTs
645+
? locale.viewFunds.viewAssets
646+
: locale.viewFunds.title}
647+
</Text>
648+
</MenuButton>
649+
)}
645650

646651
{/* Manage Wallet */}
647652
<MenuButton
@@ -799,6 +804,7 @@ function DetailsModal(props: {
799804
setScreen={setScreen}
800805
client={client}
801806
connectLocale={locale}
807+
assetTabs={props.detailsModal?.assetTabs}
802808
/>
803809
);
804810
} else {
@@ -1458,6 +1464,13 @@ export type UseWalletDetailsModalOptions = {
14581464
* By default the "Buy Funds" button is shown.
14591465
*/
14601466
hideBuyFunds?: boolean;
1467+
1468+
/**
1469+
* When you click on "View Assets", by default the "Tokens" tab is shown first.
1470+
* If you want to show the "NFTs" tab first, change the order of the asset tabs to: ["nft", "token"]
1471+
* Note: If an empty array is passed, the [View Funds] button will be hidden
1472+
*/
1473+
assetTabs?: AssetTabs[];
14611474
};
14621475

14631476
/**
@@ -1515,6 +1528,7 @@ export function useWalletDetailsModal() {
15151528
hideBuyFunds: props.hideBuyFunds,
15161529
hideReceiveFunds: props.hideReceiveFunds,
15171530
hideSendFunds: props.hideSendFunds,
1531+
assetTabs: props.assetTabs,
15181532
}}
15191533
displayBalanceToken={props.displayBalanceToken}
15201534
theme={props.theme || "dark"}

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/ViewAssets.tsx

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from "react";
1+
import { useMemo, useState } from "react";
22
import type { ThirdwebClient } from "../../../../../client/client.js";
33
import { type Theme, iconSize } from "../../../../core/design-system/index.js";
44
import type {
@@ -15,6 +15,29 @@ import { ViewNFTsContent } from "./ViewNFTs.js";
1515
import { ViewTokensContent } from "./ViewTokens.js";
1616
import type { WalletDetailsModalScreen } from "./types.js";
1717

18+
/**
19+
* @internal
20+
*/
21+
export type AssetTabs = "token" | "nft";
22+
23+
const TokenTab = {
24+
label: (
25+
<span className="flex gap-2">
26+
<CoinsIcon size={iconSize.sm} /> Tokens
27+
</span>
28+
),
29+
value: "Tokens",
30+
};
31+
32+
const NftTab = {
33+
label: (
34+
<span className="flex gap-2">
35+
<ImageIcon size={iconSize.sm} /> NFTs
36+
</span>
37+
),
38+
value: "NFTs",
39+
};
40+
1841
/**
1942
* @internal
2043
*/
@@ -26,9 +49,29 @@ export function ViewAssets(props: {
2649
setScreen: (screen: WalletDetailsModalScreen) => void;
2750
client: ThirdwebClient;
2851
connectLocale: ConnectLocale;
52+
assetTabs?: AssetTabs[];
2953
}) {
30-
const [activeTab, setActiveTab] = useState("Tokens");
3154
const { connectLocale } = props;
55+
const options = useMemo(() => {
56+
if (!props.assetTabs) {
57+
return [TokenTab, NftTab];
58+
}
59+
if (!props.assetTabs.length) {
60+
return [];
61+
}
62+
const tabs = [];
63+
for (const item of props.assetTabs) {
64+
if (item === "token") {
65+
tabs.push(TokenTab);
66+
} else if (item === "nft") {
67+
tabs.push(NftTab);
68+
}
69+
}
70+
return tabs;
71+
}, [props.assetTabs]);
72+
73+
// Since `options` is now a dynamic value, the default active tab is set to the value of the first tab in `options`
74+
const [activeTab, setActiveTab] = useState(options[0]?.value || "Tokens");
3275

3376
return (
3477
<Container
@@ -52,28 +95,7 @@ export function ViewAssets(props: {
5295
}}
5396
>
5497
<Spacer y="md" />
55-
<Tabs
56-
options={[
57-
{
58-
label: (
59-
<span className="flex gap-2">
60-
<CoinsIcon size={iconSize.sm} /> Tokens
61-
</span>
62-
),
63-
value: "Tokens",
64-
},
65-
{
66-
label: (
67-
<span className="flex gap-2">
68-
<ImageIcon size={iconSize.sm} /> NFTs
69-
</span>
70-
),
71-
value: "NFTs",
72-
},
73-
]}
74-
selected={activeTab}
75-
onSelect={setActiveTab}
76-
>
98+
<Tabs options={options} selected={activeTab} onSelect={setActiveTab}>
7799
<Container
78100
scrollY
79101
style={{

0 commit comments

Comments
 (0)