Skip to content

Commit 69b1ee9

Browse files
committed
[TOOL-3082] Dashboard: Replace NetworkSelectorButton with SingleNetworkSelector where switching chain in wallet is not required (#6031)
<!-- start pr-codex --> ## PR-Codex overview This PR introduces enhancements to the `SingleNetworkSelector` component and its usage across various files. It adds new props for alignment and positioning, replaces existing network selector buttons, and integrates chain ID handling in several components. ### Detailed summary - Added `side`, `disableChainId`, and `align` props to `SingleNetworkSelector`. - Updated `SingleNetworkSelector` to conditionally render the chain ID badge. - Replaced `NetworkSelectorButton` with `SingleNetworkSelector` in multiple components. - Integrated `chainId` state management using `useState` in `BackendWalletsSection` and `ImportForm`. - Updated `BackendWalletsTable` and `BackendWalletBalanceCell` to accept `chainId` as a prop. - Changed the way active chains are retrieved with `useActiveChainAsDashboardChain` to `useV5DashboardChain`. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 0a19142 commit 69b1ee9

File tree

5 files changed

+63
-24
lines changed

5 files changed

+63
-24
lines changed

apps/dashboard/src/@/components/blocks/NetworkSelectors.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ export function SingleNetworkSelector(props: {
9090
popoverContentClassName?: string;
9191
// if specified - only these chains will be shown
9292
chainIds?: number[];
93+
side?: "left" | "right" | "top" | "bottom";
94+
disableChainId?: boolean;
95+
align?: "center" | "start" | "end";
9396
}) {
9497
const { allChains, idToChain } = useAllChainsData();
9598

@@ -142,14 +145,17 @@ export function SingleNetworkSelector(props: {
142145
/>
143146
{chain.name}
144147
</span>
145-
<Badge variant="outline" className="gap-2 max-sm:hidden">
146-
<span className="text-muted-foreground">Chain ID</span>
147-
{chain.chainId}
148-
</Badge>
148+
149+
{!props.disableChainId && (
150+
<Badge variant="outline" className="gap-2 max-sm:hidden">
151+
<span className="text-muted-foreground">Chain ID</span>
152+
{chain.chainId}
153+
</Badge>
154+
)}
149155
</div>
150156
);
151157
},
152-
[idToChain],
158+
[idToChain, props.disableChainId],
153159
);
154160

155161
const isLoadingChains = allChains.length === 0;
@@ -168,6 +174,8 @@ export function SingleNetworkSelector(props: {
168174
className={props.className}
169175
popoverContentClassName={props.popoverContentClassName}
170176
disabled={isLoadingChains}
177+
side={props.side}
178+
align={props.align}
171179
/>
172180
);
173181
}

apps/dashboard/src/@/components/blocks/select-with-search.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ interface SelectWithSearchProps
3131
) => boolean;
3232
renderOption?: (option: { value: string; label: string }) => React.ReactNode;
3333
popoverContentClassName?: string;
34+
side?: "left" | "right" | "top" | "bottom";
35+
align?: "center" | "start" | "end";
3436
}
3537

3638
export const SelectWithSearch = React.forwardRef<
@@ -107,7 +109,7 @@ export const SelectWithSearch = React.forwardRef<
107109
}, [searchValue]);
108110

109111
return (
110-
<Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
112+
<Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen} modal>
111113
<PopoverTrigger asChild>
112114
<Button
113115
ref={ref}
@@ -118,23 +120,24 @@ export const SelectWithSearch = React.forwardRef<
118120
className,
119121
)}
120122
>
121-
<div className="flex w-full items-center justify-between">
123+
<div className="flex w-full items-center justify-between gap-2">
122124
<span
123125
className={cn(
124-
"text-muted-foreground text-sm",
126+
"truncate text-muted-foreground text-sm",
125127
selectedOption && "text-foreground",
126128
)}
127129
>
128130
{selectedOption?.label || placeholder}
129131
</span>
130-
<ChevronDown className="h-4 cursor-pointer text-muted-foreground" />
132+
<ChevronDown className="size-4 cursor-pointer text-muted-foreground" />
131133
</div>
132134
</Button>
133135
</PopoverTrigger>
134136

135137
<PopoverContent
136138
className={cn("z-[10001] p-0", popoverContentClassName)}
137-
align="center"
139+
align={props.align || "center"}
140+
side={props.side}
138141
sideOffset={10}
139142
onEscapeKeyDown={() => setIsPopoverOpen(false)}
140143
style={{

apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/overview/components/backend-wallets-table.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ import { ChainIcon } from "components/icons/ChainIcon";
3535
import { TWTable } from "components/shared/TWTable";
3636
import { useTrack } from "hooks/analytics/useTrack";
3737
import { EngineBackendWalletOptions } from "lib/engine";
38-
import { useActiveChainAsDashboardChain } from "lib/v5-adapter";
38+
import {
39+
useActiveChainAsDashboardChain,
40+
useV5DashboardChain,
41+
} from "lib/v5-adapter";
3942
import {
4043
DownloadIcon,
4144
PencilIcon,
@@ -59,6 +62,7 @@ interface BackendWalletsTableProps {
5962
isPending: boolean;
6063
isFetched: boolean;
6164
authToken: string;
65+
chainId: number;
6266
}
6367

6468
interface BackendWalletDashboard extends BackendWallet {
@@ -72,19 +76,21 @@ interface BackendWalletBalanceCellProps {
7276
instanceUrl: string;
7377
address: string;
7478
authToken: string;
79+
chainId: number;
7580
}
7681

7782
const BackendWalletBalanceCell: React.FC<BackendWalletBalanceCellProps> = ({
7883
instanceUrl,
7984
address,
8085
authToken,
86+
chainId,
8187
}) => {
8288
const { data: backendWalletBalance } = useEngineBackendWalletBalance({
8389
instanceUrl: instanceUrl,
8490
address,
8591
authToken,
8692
});
87-
const chain = useActiveChainAsDashboardChain();
93+
const chain = useV5DashboardChain(chainId);
8894
if (!chain || !backendWalletBalance) {
8995
return;
9096
}
@@ -100,7 +106,7 @@ const BackendWalletBalanceCell: React.FC<BackendWalletBalanceCellProps> = ({
100106
</Text>
101107
);
102108

103-
const explorer = chain?.explorers?.[0];
109+
const explorer = chain.blockExplorers?.[0];
104110
if (!explorer) {
105111
return balanceComponent;
106112
}
@@ -123,6 +129,7 @@ export const BackendWalletsTable: React.FC<BackendWalletsTableProps> = ({
123129
isPending,
124130
isFetched,
125131
authToken,
132+
chainId,
126133
}) => {
127134
const editDisclosure = useDisclosure();
128135
const receiveDisclosure = useDisclosure();
@@ -163,13 +170,14 @@ export const BackendWalletsTable: React.FC<BackendWalletsTableProps> = ({
163170
instanceUrl={instanceUrl}
164171
address={address}
165172
authToken={authToken}
173+
chainId={chainId}
166174
/>
167175
);
168176
},
169177
id: "balance",
170178
}),
171179
];
172-
}, [instanceUrl, authToken]);
180+
}, [instanceUrl, authToken, chainId]);
173181

174182
const [selectedBackendWallet, setSelectedBackendWallet] =
175183
useState<BackendWallet>();

apps/dashboard/src/app/team/[team_slug]/(team)/~/engine/(instance)/[engineId]/overview/components/engine-overview.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
"use client";
2+
import { SingleNetworkSelector } from "@/components/blocks/NetworkSelectors";
23
import {
34
type EngineInstance,
45
useEngineBackendWallets,
56
useEngineWalletConfig,
67
} from "@3rdweb-sdk/react/hooks/useEngine";
7-
import { NetworkSelectorButton } from "components/selects/NetworkSelectorButton";
88
import Link from "next/link";
9+
import { useState } from "react";
10+
import { useActiveWalletChain } from "thirdweb/react";
911
import { BackendWalletsTable } from "./backend-wallets-table";
1012
import { CreateBackendWalletButton } from "./create-backend-wallet-button";
1113
import { ImportBackendWalletButton } from "./import-backend-wallet-button";
@@ -43,6 +45,10 @@ function BackendWalletsSection(props: {
4345
authToken: string;
4446
}) {
4547
const { instance, teamSlug, authToken } = props;
48+
const activeWalletChain = useActiveWalletChain();
49+
const [_chainId, setChainId] = useState<number>();
50+
const chainId = _chainId || activeWalletChain?.id || 1;
51+
4652
const backendWallets = useEngineBackendWallets({
4753
instanceUrl: instance.url,
4854
authToken,
@@ -105,9 +111,14 @@ function BackendWalletsSection(props: {
105111
<div className="flex justify-end">
106112
<div className="flex items-center gap-2">
107113
<span className="text-sm">Show balance for</span>
108-
{/* TODO - Replace with simple network selector - there's no need for user to switch chain */}
109114
<div className="flex flex-row">
110-
<NetworkSelectorButton />
115+
<SingleNetworkSelector
116+
chainId={chainId}
117+
onChange={setChainId}
118+
className="min-w-40 max-w-52 lg:max-w-60"
119+
popoverContentClassName="!w-[80vw] md:!w-[500px]"
120+
align="end"
121+
/>
111122
</div>
112123
</div>
113124
</div>
@@ -120,6 +131,7 @@ function BackendWalletsSection(props: {
120131
isPending={backendWallets.isPending}
121132
isFetched={backendWallets.isFetched}
122133
authToken={authToken}
134+
chainId={chainId}
123135
/>
124136
</section>
125137
);

apps/dashboard/src/components/contract-components/import-contract/modal.tsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
"use client";
2+
3+
import { SingleNetworkSelector } from "@/components/blocks/NetworkSelectors";
24
import { Spinner } from "@/components/ui/Spinner/Spinner";
35
import { Button } from "@/components/ui/button";
46
import {
@@ -24,7 +26,6 @@ import {
2426
useAllContractList,
2527
} from "@3rdweb-sdk/react/hooks/useRegistry";
2628
import { zodResolver } from "@hookform/resolvers/zod";
27-
import { NetworkSelectorButton } from "components/selects/NetworkSelectorButton";
2829
import { useChainSlug } from "hooks/chains/chainSlug";
2930
import { PlusIcon } from "lucide-react";
3031
import { useState } from "react";
@@ -82,17 +83,22 @@ const importFormSchema = z.object({
8283
message: "Invalid contract address",
8384
},
8485
),
86+
chainId: z.coerce.number(),
8587
});
8688

8789
function ImportForm() {
8890
const router = useDashboardRouter();
89-
const chainId = useActiveWalletChain()?.id;
90-
const chainSlug = useChainSlug(chainId || 1);
91+
const activeChainId = useActiveWalletChain()?.id;
9192
const [isRedirecting, setIsRedirecting] = useState(false);
9293

9394
const form = useForm({
9495
resolver: zodResolver(importFormSchema),
96+
values: {
97+
contractAddress: "",
98+
chainId: activeChainId || 1,
99+
},
95100
});
101+
const chainSlug = useChainSlug(form.watch("chainId"));
96102
const addToDashboard = useAddContractMutation();
97103
const address = useActiveAccount()?.address;
98104
const registry = useAllContractList(address);
@@ -107,9 +113,7 @@ function ImportForm() {
107113
<Form {...form}>
108114
<form
109115
onSubmit={form.handleSubmit(async (data) => {
110-
if (!chainId) {
111-
throw new Error("No chain ID");
112-
}
116+
const { chainId } = data;
113117
let contractAddress: string;
114118

115119
try {
@@ -199,7 +203,11 @@ function ImportForm() {
199203
<div className="h-3" />
200204
<div>
201205
<Label className="mb-3 inline-block">Network</Label>
202-
<NetworkSelectorButton />
206+
<SingleNetworkSelector
207+
chainId={form.watch("chainId")}
208+
onChange={(v) => form.setValue("chainId", v)}
209+
side="top"
210+
/>
203211
</div>
204212

205213
<div className="h-8" />

0 commit comments

Comments
 (0)