-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathSwitchNetwork.tsx
More file actions
131 lines (122 loc) · 3.97 KB
/
Copy pathSwitchNetwork.tsx
File metadata and controls
131 lines (122 loc) · 3.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import { Box, Flex, Menu } from '@chakra-ui/react'
import {
type ComponentPropsWithoutRef,
type FC,
type ReactElement,
useEffect,
useState,
} from 'react'
import * as chains from 'viem/chains'
import { useChains, useSwitchChain } from 'wagmi'
import DropdownButton from '@/src/components/sharedComponents/ui/DropdownButton'
import { MenuContent, MenuItem } from '@/src/components/sharedComponents/ui/Menu'
import { useWeb3Status } from '@/src/hooks/useWeb3Status'
type NetworkItem = {
icon: ReactElement
id: number
label: string
}
export type Networks = Array<NetworkItem>
interface SwitchNetworkProps extends ComponentPropsWithoutRef<'div'> {
networks: Networks
}
/**
* SwitchNetwork component for selecting and switching blockchain networks.
*
* This component renders a dropdown menu that allows users to select from a list of
* blockchain networks and switch the connected wallet to the selected network.
*
* @param {SwitchNetworkProps} props - SwitchNetwork component props.
* @param {Networks} props.networks - List of networks to display in the dropdown.
* @param {ReactElement} props.networks[].icon - Icon representing the network.
* @param {number} props.networks[].id - Chain ID of the network.
* @param {string} props.networks[].label - Display name of the network.
* @param {ComponentPropsWithoutRef<'div'>} [props.restProps] - Additional props inherited from div element.
*
* @example
* ```tsx
* <SwitchNetwork
* networks={[
* { id: 1, label: "Ethereum", icon: <EthereumIcon /> },
* { id: 10, label: "Optimism", icon: <OptimismIcon /> }
* ]}
* />
* ```
*/
const SwitchNetwork: FC<SwitchNetworkProps> = ({ networks }: SwitchNetworkProps) => {
const findChain = (chainId: number) => Object.values(chains).find((chain) => chain.id === chainId)
const configuredChains = useChains()
const { mutate: switchChain } = useSwitchChain()
const { isWalletConnected, walletChainId, walletClient } = useWeb3Status()
const [networkItem, setNetworkItem] = useState<NetworkItem>()
const handleClick = (chainId: number) => {
/**
* First, attempt to switch to the chain if it's already configured
*/
if (configuredChains.some((chain) => chain.id === chainId)) {
switchChain({ chainId })
} else {
/**
* If the chain isn't configured, allow to switch to it based on the chain id
*/
const selectedChain = findChain(chainId)
if (selectedChain) {
walletClient?.addChain({ chain: selectedChain })
}
}
}
useEffect(() => {
setNetworkItem(networks.find((networkItem) => networkItem.id === walletChainId))
}, [walletChainId, networks])
return (
<Menu.Root positioning={{ placement: 'bottom' }}>
<Menu.Trigger asChild>
<DropdownButton disabled={!isWalletConnected}>
{networkItem ? (
<>
<Flex
alignItems="center"
borderRadius="50%"
display="flex"
height="24px"
justifyContent="center"
overflow="hidden"
width="24px"
>
<Box
rounded="full"
overflow="hidden"
>
{networkItem?.icon}
</Box>
</Flex>{' '}
{networkItem?.label}
</>
) : (
'Select a network'
)}
</DropdownButton>
</Menu.Trigger>
<Menu.Positioner>
<MenuContent width="250px">
{networks.map(({ icon, id, label }) => (
<MenuItem
key={`${id}-${label}`}
onClick={() => handleClick(id)}
value={label}
>
<Box
rounded="full"
overflow="hidden"
>
{icon}
</Box>
{label}
</MenuItem>
))}
</MenuContent>
</Menu.Positioner>
</Menu.Root>
)
}
export default SwitchNetwork