Skip to content

Commit b2b7c35

Browse files
authored
feat: wallet connector dropdown and testnet (#76)
Signed-off-by: JaeBrian <[email protected]>
1 parent a4f0071 commit b2b7c35

File tree

2 files changed

+174
-32
lines changed

2 files changed

+174
-32
lines changed

src/components/WalletConnection.tsx

Lines changed: 168 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import { ConnectWalletList } from '@cardano-foundation/cardano-connect-with-wallet'
2+
import { NetworkType } from '@cardano-foundation/cardano-connect-with-wallet-core'
13
import { useWalletStore } from '../stores/walletStore'
24
import { useNavigate } from 'react-router'
5+
import { useState, useRef, useEffect } from 'react'
36

47
interface WalletConnectionProps {
58
variant?: 'default' | 'white'
@@ -14,30 +17,53 @@ const WalletConnection = ({
1417
}: WalletConnectionProps) => {
1518
const { isConnected, connect, disconnect } = useWalletStore()
1619
const navigate = useNavigate()
20+
const [showWalletList, setShowWalletList] = useState(false)
21+
const [connectionError, setConnectionError] = useState<string | null>(null)
22+
const [isConnecting, setIsConnecting] = useState(false)
23+
const dropdownRef = useRef<HTMLDivElement>(null)
1724

18-
const handleConnect = async () => {
25+
const onConnectWallet = async (walletName: string) => {
26+
setIsConnecting(true)
27+
setConnectionError(null)
28+
1929
try {
20-
const walletNames = ['nami', 'eternl', 'flint', 'yoroi', 'gerowallet']
21-
let connected = false
30+
const success = await connect(walletName)
2231

23-
for (const walletName of walletNames) {
24-
const success = await connect(walletName)
25-
if (success) {
26-
console.log(`Connected to ${walletName}`)
27-
connected = true
28-
navigate('/account')
29-
break
30-
}
31-
}
32-
33-
if (!connected) {
34-
console.warn('No compatible wallets found. Please install a supported Cardano wallet.')
32+
if (success) {
33+
setShowWalletList(false)
34+
navigate('/account')
35+
} else {
36+
console.error(`Failed to connect to ${walletName} - connect function returned false`)
37+
setConnectionError(`Failed to connect to ${walletName}. Please try again.`)
3538
}
3639
} catch (error) {
37-
console.error('Failed to connect wallet:', error)
40+
console.error(`Error connecting to ${walletName}:`, error)
41+
setConnectionError(`Error connecting to ${walletName}: ${error instanceof Error ? error.message : 'Unknown error'}`)
42+
} finally {
43+
setIsConnecting(false)
3844
}
3945
}
4046

47+
// Add error handler for ConnectWalletList
48+
const onConnectError = (walletName: string, error: Error) => {
49+
console.error(`ConnectWalletList error for ${walletName}:`, error)
50+
setConnectionError(`Error with ${walletName}: ${error.message}`)
51+
}
52+
53+
useEffect(() => {
54+
const handleClickOutside = (event: MouseEvent) => {
55+
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
56+
setShowWalletList(false)
57+
setConnectionError(null);
58+
}
59+
}
60+
61+
document.addEventListener('mousedown', handleClickOutside)
62+
return () => {
63+
document.removeEventListener('mousedown', handleClickOutside)
64+
}
65+
}, [])
66+
4167
if (isConnected) {
4268
return (
4369
<div className="flex items-center space-x-4">
@@ -53,14 +79,13 @@ const WalletConnection = ({
5379

5480
const buttonClasses = variant === 'white'
5581
? "flex py-3 px-8 justify-center items-center gap-2.5 rounded-md bg-white text-black font-medium cursor-pointer text-lg md:text-base"
56-
: "flex py-2.5 px-6 justify-center items-center gap-2.5 self-stretch rounded-md border border-white/20 backdrop-blur-sm text-white font-medium z-40 cursor-pointer"
82+
: "flex py-2.5 px-10 justify-center items-center gap-2.5 self-stretch rounded-md border border-white/20 backdrop-blur-sm text-white font-medium z-40 cursor-pointer"
5783

5884
if (showTitle || showDescription) {
5985
return (
6086
<div className="flex flex-col items-center justify-center w-full max-w-4xl mx-auto">
6187
<div className="border-2 border-white rounded-3xl p-8 md:p-12 w-full">
6288
<div className="flex items-start gap-4 mb-6">
63-
{/* Logomark Icon */}
6489
<div className="flex-shrink-0">
6590
<img
6691
src="/wallet-icon-white.svg"
@@ -84,24 +109,137 @@ const WalletConnection = ({
84109
</p>
85110
)}
86111

87-
<button
88-
onClick={handleConnect}
89-
className="bg-white text-black font-medium py-3 px-8 rounded-lg text-lg cursor-pointer"
90-
>
91-
Connect
92-
</button>
112+
<div className="relative" ref={dropdownRef}>
113+
<button
114+
onClick={() => setShowWalletList(!showWalletList)}
115+
className="bg-white text-black font-medium py-3 px-8 rounded-lg text-lg cursor-pointer"
116+
disabled={isConnecting}
117+
>
118+
{isConnecting ? 'Connecting...' : 'Connect'}
119+
</button>
120+
121+
{showWalletList && (
122+
<div className="absolute top-full left-0 mt-2 backdrop-blur-sm p-4 z-50 min-w-[200px]">
123+
{connectionError && (
124+
<div className="mb-3 p-2 bg-red-100 border border-red-300 rounded text-red-700 text-sm">
125+
{connectionError}
126+
</div>
127+
)}
128+
<ConnectWalletList
129+
borderRadius={15}
130+
gap={12}
131+
primaryColor="#000000"
132+
onConnect={onConnectWallet}
133+
onConnectError={onConnectError}
134+
supportedWallets={['eternl', 'yoroi', 'gerowallet', 'begin', 'nufi', 'lace', 'vespr']}
135+
showUnavailableWallets={0}
136+
peerConnectEnabled={false}
137+
limitNetwork={NetworkType.TESTNET}
138+
customCSS={`
139+
font-family: Helvetica Light, sans-serif;
140+
font-size: 1rem;
141+
font-weight: 700;
142+
width: 100%;
143+
& > span {
144+
padding: 10px 24px;
145+
color: #ffffff;
146+
border: 1px solid rgba(255, 255, 255, 0.2);
147+
border-radius: 6px;
148+
margin-bottom: 12px;
149+
display: flex;
150+
align-items: center;
151+
justify-content: center;
152+
gap: 8px;
153+
background: transparent;
154+
backdrop-filter: blur(10px);
155+
transition: all 0.2s ease;
156+
cursor: pointer;
157+
}
158+
& > span:hover {
159+
background: rgba(255, 255, 255, 0.1);
160+
border-color: rgba(255, 255, 255, 0.3);
161+
}
162+
`}
163+
/>
164+
</div>
165+
)}
166+
</div>
93167
</div>
94168
</div>
95169
)
96170
}
97171

98172
return (
99-
<button
100-
onClick={handleConnect}
101-
className={buttonClasses}
102-
>
103-
Connect Wallet
104-
</button>
173+
<div className="relative" ref={dropdownRef}>
174+
<button
175+
onClick={() => setShowWalletList(!showWalletList)}
176+
className={buttonClasses}
177+
disabled={isConnecting}
178+
>
179+
{isConnecting ? 'Connecting...' : 'Connect Wallet'}
180+
</button>
181+
182+
{showWalletList && (
183+
<div className="absolute top-full left-0 right-0 pt-3 z-50 animate-in slide-in-from-top-2 duration-300">
184+
<ConnectWalletList
185+
borderRadius={15}
186+
gap={12}
187+
primaryColor="#000000"
188+
onConnect={onConnectWallet}
189+
onConnectError={onConnectError}
190+
supportedWallets={['eternl', 'yoroi', 'begin', 'nufi', 'lace', 'vespr']}
191+
showUnavailableWallets={0}
192+
peerConnectEnabled={false}
193+
limitNetwork={NetworkType.TESTNET} // MUST BE CHANGED TO MAINNET to work on mainnet
194+
customCSS={`
195+
font-family: Helvetica Light, sans-serif;
196+
font-size: 0.875rem;
197+
font-weight: 700;
198+
width: 100%;
199+
& > span {
200+
padding: 10px 12px;
201+
color: #ffffff;
202+
border: 1px solid rgba(255, 255, 255, 0.2);
203+
border-radius: 6px;
204+
margin-bottom: 10px;
205+
display: flex;
206+
align-items: center;
207+
justify-content: start;
208+
gap: 8px;
209+
background: transparent;
210+
backdrop-filter: blur(10px);
211+
transition: all 0.2s ease;
212+
cursor: pointer;
213+
opacity: 0;
214+
transform: translateY(-10px);
215+
animation: cascadeIn 0.4s ease-out forwards;
216+
}
217+
& > span:nth-child(1) { animation-delay: 0.02s; }
218+
& > span:nth-child(2) { animation-delay: 0.08s; }
219+
& > span:nth-child(3) { animation-delay: 0.12s; }
220+
& > span:nth-child(4) { animation-delay: 0.17s; }
221+
& > span:nth-child(5) { animation-delay: 0.22s; }
222+
& > span:nth-child(6) { animation-delay: 0.27s; }
223+
& > span:hover {
224+
background: rgba(255, 255, 255, 0.1);
225+
border-color: rgba(255, 255, 255, 0.3);
226+
transform: translateY(-2px);
227+
}
228+
@keyframes cascadeIn {
229+
from {
230+
opacity: 0;
231+
transform: translateY(-10px);
232+
}
233+
to {
234+
opacity: 1;
235+
transform: translateY(0);
236+
}
237+
}
238+
`}
239+
/>
240+
</div>
241+
)}
242+
</div>
105243
)
106244
}
107245

src/stores/walletStore.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,12 @@ export const useWalletStore = create<WalletState>()(
111111
walletApi,
112112
})
113113

114-
const { getBalance, getWalletAddress } = get()
115-
await Promise.all([getBalance(), getWalletAddress()])
114+
try {
115+
const { getBalance, getWalletAddress } = get()
116+
await Promise.all([getBalance(), getWalletAddress()])
117+
} catch (error) {
118+
console.warn('Failed to get balance or address, but wallet is connected:', error)
119+
}
116120

117121
return true
118122
} catch (error) {

0 commit comments

Comments
 (0)