11'use client' ;
22
3- import React from 'react' ;
4- import { ChevronDown , Plus , Wallet , Shield } from 'lucide-react' ;
5- import { Select , SelectContent , SelectItem , SelectTrigger , SelectValue } from '@/components/ui/select' ;
6- import { Button } from '@/components/ui/button' ;
7- import { cn } from '@/lib/utils' ;
3+ import * as React from 'react' ;
4+ import { Check , ChevronsUpDown , Shield , Wallet , Plus , Smile } from 'lucide-react' ;
85import { useRouter } from 'next/navigation' ;
9- import { useSelectedSafeAddress , useOwnerSafeAddress } from '@/providers/SafeProvider' ;
6+ import { cn } from '@/lib/utils' ;
7+
8+ import {
9+ DropdownMenu ,
10+ DropdownMenuContent ,
11+ DropdownMenuItem ,
12+ DropdownMenuTrigger ,
13+ DropdownMenuSeparator ,
14+ } from '@/components/ui/dropdown-menu' ;
15+ import { SidebarMenu , SidebarMenuButton , SidebarMenuItem } from '@/components/ui/sidebar' ;
16+ import { Button } from '@/components/ui/button' ;
17+ import { useSelectedSafeAddress , useOwnerSafeAddress , useCurrentChain } from '@/providers/SafeProvider' ;
1018import { useWallet } from '@/hooks/useWallet' ;
19+ import { getNetworkIcon } from '@/components/BlockChainNetworkIcon' ;
1120
1221export function SafeWalletSelect ( ) {
1322 const { selectedSafeAddress, setSelectedSafeAddress } = useSelectedSafeAddress ( ) ;
1423 const ownerSafeAddress = useOwnerSafeAddress ( ) ;
15- const { account : eoaAddress , isConnected } = useWallet ( ) ;
24+ const { chainName, chainId } = useCurrentChain ( ) ;
25+ const { account, isConnected } = useWallet ( ) ;
1626 const router = useRouter ( ) ;
1727
18- const handleSafeSelect = async ( safeAddress : string ) => {
28+ const handleSafeSelect = ( safeAddress : string ) => {
1929 setSelectedSafeAddress ( safeAddress ) ;
2030 } ;
2131
2232 const handleCreateSafe = ( ) => {
2333 router . push ( '/wallets/create' ) ;
2434 } ;
2535
26- const handleConnectWallet = ( ) => {
27- // TODO: Implement wallet connection logic
28- console . log ( 'Connect wallet clicked' ) ;
29- } ;
30-
3136 const formatAddress = ( address : string ) => {
3237 return `${ address . slice ( 0 , 6 ) } ...${ address . slice ( - 4 ) } ` ;
3338 } ;
@@ -54,74 +59,140 @@ export function SafeWalletSelect() {
5459 return address . slice ( 2 , 4 ) . toUpperCase ( ) ;
5560 } ;
5661
57- // EOA not connected state
62+ const getNetworkId = ( chainId : number | null ) : string => {
63+ if ( ! chainId ) return '' ;
64+
65+ const networkMap : { [ key : number ] : string } = {
66+ 1 : 'ethereum' ,
67+ 10 : 'optimism' ,
68+ 56 : 'bsc' ,
69+ 100 : 'gnosis' ,
70+ 137 : 'polygon' ,
71+ 324 : 'polygon-zkevm' ,
72+ 8453 : 'base' ,
73+ 42161 : 'arbitrum' ,
74+ 43114 : 'avalanche' ,
75+ 84532 : 'BaseSepolia' ,
76+ 11155111 : 'ethereum' , // Sepolia uses ethereum icon
77+ } ;
78+
79+ return networkMap [ chainId ] || '' ;
80+ } ;
81+
82+ // Hardware wallet not connected state
5883 if ( ! isConnected ) {
5984 return (
60- < div className = 'h-14 px-4 flex items-center gap-2' >
61- < Wallet className = 'w-4 h-4 text-muted-foreground' />
62- < span className = 'text-sm text-muted-foreground' > Connect Wallet to Continue</ span >
63- </ div >
85+ < SidebarMenu >
86+ < SidebarMenuItem >
87+ < SidebarMenuButton size = 'lg' disabled >
88+ < div className = 'bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg' >
89+ < Smile className = 'size-4' />
90+ </ div >
91+ < div className = 'flex flex-col gap-0.5 leading-none' >
92+ < span className = 'font-medium text-sidebar-muted-foreground' > Hello</ span >
93+ < span className = 'text-xs text-sidebar-muted-foreground/70' > Nice to meet you</ span >
94+ </ div >
95+ </ SidebarMenuButton >
96+ </ SidebarMenuItem >
97+ </ SidebarMenu >
6498 ) ;
6599 }
66100
67101 // EOA connected but no Safe wallets
68102 if ( ownerSafeAddress . length === 0 ) {
69103 return (
70- < div className = 'h-14 px-4 flex items-center gap-3' >
71- < div className = 'flex items-center gap-2' >
72- < Shield className = 'w-4 h-4 text-muted-foreground' />
73- < span className = 'text-sm text-muted-foreground' > No Safe Wallets</ span >
74- </ div >
75- < Button variant = 'outline' size = 'sm' onClick = { handleCreateSafe } className = 'h-8 px-3' >
76- < Plus className = 'w-3 h-3 mr-1' />
77- Create
78- </ Button >
79- </ div >
104+ < SidebarMenu >
105+ < SidebarMenuItem >
106+ < SidebarMenuButton size = 'lg' onClick = { handleCreateSafe } >
107+ < div className = 'bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg' >
108+ < Shield className = 'size-4' />
109+ </ div >
110+ < div className = 'flex flex-col gap-0.5 leading-none' >
111+ < span className = 'font-medium' > No Safe Wallets</ span >
112+ < span className = 'text-xs text-sidebar-muted-foreground' > Create your first Safe</ span >
113+ </ div >
114+ < Plus className = 'ml-auto size-4' />
115+ </ SidebarMenuButton >
116+ </ SidebarMenuItem >
117+ </ SidebarMenu >
80118 ) ;
81119 }
82120
83121 // EOA connected and has Safe wallets
122+ const currentSafe = selectedSafeAddress || ownerSafeAddress [ 0 ] ;
123+
84124 return (
85- < Select value = { selectedSafeAddress || undefined } onValueChange = { handleSafeSelect } >
86- < SelectTrigger className = 'h-14 px-4 w-auto min-w-[200px] border-0 bg-transparent hover:bg-accent transition-colors' >
87- < div className = 'flex items-center gap-3' >
88- < div
89- className = { cn (
90- 'w-6 h-6 rounded-full flex items-center justify-center text-xs font-medium text-white' ,
91- getAddressColor ( selectedSafeAddress || ownerSafeAddress [ 0 ] )
92- ) }
93- >
94- { getAddressAvatar ( selectedSafeAddress || ownerSafeAddress [ 0 ] ) }
95- </ div >
96- < div className = 'flex flex-col items-start' >
97- < span className = 'text-sm font-medium' > { formatAddress ( selectedSafeAddress || ownerSafeAddress [ 0 ] ) } </ span >
98- < span className = 'text-xs text-muted-foreground' > Safe Wallet</ span >
99- </ div >
100- </ div >
101- </ SelectTrigger >
102- < SelectContent >
103- { ownerSafeAddress . map ( ( safeAddr ) => (
104- < SelectItem key = { safeAddr } value = { safeAddr } >
105- < div className = 'flex items-center gap-3' >
106- < div
107- className = { cn (
108- 'w-5 h-5 rounded-full flex items-center justify-center text-xs font-medium text-white' ,
109- getAddressColor ( safeAddr )
125+ < SidebarMenu >
126+ < SidebarMenuItem >
127+ < DropdownMenu >
128+ < DropdownMenuTrigger asChild >
129+ < SidebarMenuButton
130+ size = 'lg'
131+ className = 'data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground'
132+ >
133+ < div className = 'flex items-center justify-center ' >
134+ { getNetworkIcon ( {
135+ networkId : getNetworkId ( chainId ) ,
136+ variant : 'mono' ,
137+ size : 26 ,
138+ } ) || (
139+ < div
140+ className = { cn (
141+ 'flex aspect-square size-8 items-center justify-center rounded-lg text-white text-xs font-medium' ,
142+ getAddressColor ( currentSafe )
143+ ) }
144+ >
145+ { getAddressAvatar ( currentSafe ) }
146+ </ div >
110147 ) }
148+ </ div >
149+ < div className = 'flex flex-col gap-0.5 leading-none' >
150+ < span className = 'font-medium' > { formatAddress ( currentSafe ) } </ span >
151+ < span className = 'text-xs text-sidebar-muted-foreground' > { chainName || 'Safe Wallet' } </ span >
152+ </ div >
153+ < ChevronsUpDown className = 'ml-auto size-4' />
154+ </ SidebarMenuButton >
155+ </ DropdownMenuTrigger >
156+ < DropdownMenuContent className = 'w-[280px]' align = 'start' side = 'right' >
157+ { ownerSafeAddress . map ( ( safeAddr ) => (
158+ < DropdownMenuItem
159+ key = { safeAddr }
160+ onClick = { ( ) => handleSafeSelect ( safeAddr ) }
161+ className = 'flex items-center gap-3 py-3'
111162 >
112- { getAddressAvatar ( safeAddr ) }
163+ < div className = 'flex items-center justify-center' >
164+ { getNetworkIcon ( {
165+ networkId : getNetworkId ( chainId ) ,
166+ variant : 'branded' ,
167+ size : 30 ,
168+ } ) || (
169+ < div
170+ className = { cn (
171+ 'flex aspect-square size-6 items-center justify-center rounded-full text-white text-xs font-medium' ,
172+ getAddressColor ( safeAddr )
173+ ) }
174+ >
175+ { getAddressAvatar ( safeAddr ) }
176+ </ div >
177+ ) }
178+ </ div >
179+ < div className = 'flex flex-col gap-0.5' >
180+ < span className = 'font-medium' > { formatAddress ( safeAddr ) } </ span >
181+ < span className = 'text-xs text-muted-foreground' > { chainName || 'Safe Wallet' } </ span >
182+ </ div >
183+ { safeAddr === selectedSafeAddress && < Check className = 'ml-auto size-4 text-primary' /> }
184+ </ DropdownMenuItem >
185+ ) ) }
186+ < DropdownMenuSeparator />
187+ < DropdownMenuItem onClick = { handleCreateSafe } className = 'py-3' >
188+ < div className = 'flex aspect-square size-6 items-center justify-center rounded-full bg-sidebar-muted' >
189+ < Plus className = 'size-3' />
113190 </ div >
114- < span > { formatAddress ( safeAddr ) } </ span >
115- </ div >
116- </ SelectItem >
117- ) ) }
118- < div className = 'border-t pt-2 mt-2' >
119- < Button variant = 'ghost' size = 'sm' onClick = { handleCreateSafe } className = 'w-full justify-start h-8' >
120- < Plus className = 'w-3 h-3 mr-2' />
121- Create New Safe
122- </ Button >
123- </ div >
124- </ SelectContent >
125- </ Select >
191+ < span className = 'ml-3' > Create New Safe</ span >
192+ </ DropdownMenuItem >
193+ </ DropdownMenuContent >
194+ </ DropdownMenu >
195+ </ SidebarMenuItem >
196+ </ SidebarMenu >
126197 ) ;
127198}
0 commit comments