1
1
"use client" ;
2
2
3
- import { Copy , LogOut } from "lucide-react" ;
3
+ import {
4
+ ChevronDown ,
5
+ ArrowRight ,
6
+ Copy ,
7
+ LogOut ,
8
+ User ,
9
+ ArrowLeft ,
10
+ } from "lucide-react" ;
4
11
import { useCallback , useEffect , useState } from "react" ;
5
12
6
13
import { useToast } from "@/components/ui/use-toast" ;
7
- import { useCrossChainWallet } from "@aptos-labs/cross-chain-react" ;
14
+ import {
15
+ useCrossChainWallet ,
16
+ AptosNotDetectedWallet ,
17
+ } from "@aptos-labs/cross-chain-react" ;
8
18
import { Button } from "@/components/ui/button" ;
9
19
import {
10
20
DropdownMenu ,
@@ -15,6 +25,7 @@ import {
15
25
import {
16
26
Dialog ,
17
27
DialogContent ,
28
+ DialogHeader ,
18
29
DialogTitle ,
19
30
DialogTrigger ,
20
31
} from "@/components/ui/dialog" ;
@@ -24,6 +35,16 @@ import {
24
35
AdapterWallet ,
25
36
WalletReadyState ,
26
37
} from "@aptos-labs/wallet-adapter-aggregator-core" ;
38
+ import { isAptosConnectWallet } from "@aptos-labs/wallet-adapter-core" ;
39
+ import { CollapsibleContent } from "@/components/ui/collapsible" ;
40
+ import { CollapsibleTrigger } from "@/components/ui/collapsible" ;
41
+ import { APTOS_CONNECT_ACCOUNT_URL } from "@aptos-labs/wallet-adapter-core" ;
42
+ import {
43
+ AboutAptosConnect ,
44
+ AboutAptosConnectEducationScreen ,
45
+ AptosPrivacyPolicy ,
46
+ } from "@aptos-labs/wallet-adapter-react" ;
47
+ import { Collapsible } from "@/components/ui/collapsible" ;
27
48
28
49
export function WalletSelector ( {
29
50
transactionInProgress,
@@ -67,6 +88,18 @@ export function WalletSelector({
67
88
< DropdownMenuItem onSelect = { copyAddress } className = "gap-2" >
68
89
< Copy className = "h-4 w-4" /> Copy address
69
90
</ DropdownMenuItem >
91
+ { wallet && isAptosConnectWallet ( wallet ) && (
92
+ < DropdownMenuItem asChild >
93
+ < a
94
+ href = { APTOS_CONNECT_ACCOUNT_URL }
95
+ target = "_blank"
96
+ rel = "noopener noreferrer"
97
+ className = "flex gap-2"
98
+ >
99
+ < User className = "h-4 w-4" /> Account
100
+ </ a >
101
+ </ DropdownMenuItem >
102
+ ) }
70
103
< DropdownMenuItem onSelect = { disconnect } className = "gap-2" >
71
104
< LogOut className = "h-4 w-4" /> Disconnect
72
105
</ DropdownMenuItem >
@@ -75,7 +108,7 @@ export function WalletSelector({
75
108
) : (
76
109
< Dialog open = { isDialogOpen } onOpenChange = { setIsDialogOpen } >
77
110
< DialogTrigger asChild >
78
- < Button disabled = { ! sourceChain } > Connect Wallet</ Button >
111
+ < Button disabled = { ! sourceChain } > Connect a Wallet</ Button >
79
112
</ DialogTrigger >
80
113
< ConnectWalletDialog close = { closeDialog } sourceChain = { sourceChain } />
81
114
</ Dialog >
@@ -88,8 +121,15 @@ interface ConnectWalletDialogProps {
88
121
}
89
122
90
123
function ConnectWalletDialog ( { close, sourceChain } : ConnectWalletDialogProps ) {
91
- const { getSolanaWallets, getAptosWallets, getEthereumWallets } =
92
- useCrossChainWallet ( ) ;
124
+ const {
125
+ getSolanaWallets,
126
+ getAptosWallets,
127
+ getEthereumWallets,
128
+ fetchAptosNotDetectedWallets,
129
+ } = useCrossChainWallet ( ) ;
130
+ const [ aptosNotDetectedWallets , setAptosNotDetectedWallets ] = useState <
131
+ ReadonlyArray < AptosNotDetectedWallet >
132
+ > ( [ ] ) ;
93
133
94
134
const [ wallets , setWallets ] = useState < ReadonlyArray < AdapterWallet > > ( [ ] ) ;
95
135
@@ -102,7 +142,9 @@ function ConnectWalletDialog({ close, sourceChain }: ConnectWalletDialogProps) {
102
142
break ;
103
143
case "Aptos" :
104
144
const aptosWallets = await getAptosWallets ( ) ;
145
+ const notDetectedWallets = fetchAptosNotDetectedWallets ( ) ;
105
146
setWallets ( aptosWallets ) ;
147
+ setAptosNotDetectedWallets ( notDetectedWallets ) ;
106
148
break ;
107
149
default :
108
150
const ethereumWallets = await getEthereumWallets ( ) ;
@@ -112,6 +154,77 @@ function ConnectWalletDialog({ close, sourceChain }: ConnectWalletDialogProps) {
112
154
getWallets ( ) ;
113
155
} , [ sourceChain ] ) ;
114
156
157
+ if ( sourceChain === "Aptos" ) {
158
+ const aptosConnectWallets = wallets . filter ( ( item ) =>
159
+ isAptosConnectWallet ( item )
160
+ ) ;
161
+ const aptosWallets = wallets . filter ( ( item ) => ! isAptosConnectWallet ( item ) ) ;
162
+
163
+ return (
164
+ < DialogContent className = "max-h-screen overflow-auto" >
165
+ < AboutAptosConnect renderEducationScreen = { renderEducationScreen } >
166
+ < DialogHeader >
167
+ < DialogTitle className = "flex flex-col text-center leading-snug" >
168
+ < >
169
+ < span > Log in or sign up</ span >
170
+ < span > with Social + Aptos Connect</ span >
171
+ </ >
172
+ </ DialogTitle >
173
+ </ DialogHeader >
174
+
175
+ < div className = "flex flex-col gap-2 pt-3" >
176
+ { aptosConnectWallets . map ( ( wallet ) => (
177
+ < AptosConnectWalletRow
178
+ key = { wallet . name }
179
+ wallet = { wallet }
180
+ onConnect = { close }
181
+ />
182
+ ) ) }
183
+ < p className = "flex gap-1 justify-center items-center text-muted-foreground text-sm" >
184
+ Learn more about{ " " }
185
+ < AboutAptosConnect . Trigger className = "flex gap-1 py-3 items-center text-foreground" >
186
+ Aptos Connect < ArrowRight size = { 16 } />
187
+ </ AboutAptosConnect . Trigger >
188
+ </ p >
189
+ < AptosPrivacyPolicy className = "flex flex-col items-center py-1" >
190
+ < p className = "text-xs leading-5" >
191
+ < AptosPrivacyPolicy . Disclaimer /> { " " }
192
+ < AptosPrivacyPolicy . Link className = "text-muted-foreground underline underline-offset-4" />
193
+ < span className = "text-muted-foreground" > .</ span >
194
+ </ p >
195
+ < AptosPrivacyPolicy . PoweredBy className = "flex gap-1.5 items-center text-xs leading-5 text-muted-foreground" />
196
+ </ AptosPrivacyPolicy >
197
+ < div className = "flex items-center gap-3 pt-4 text-muted-foreground" >
198
+ < div className = "h-px w-full bg-secondary" />
199
+ Or
200
+ < div className = "h-px w-full bg-secondary" />
201
+ </ div >
202
+ </ div >
203
+
204
+ < div className = "flex flex-col gap-3 pt-3" >
205
+ { aptosWallets . map ( ( wallet ) => (
206
+ < WalletRow key = { wallet . name } wallet = { wallet } onConnect = { close } />
207
+ ) ) }
208
+ { ! ! aptosNotDetectedWallets . length && (
209
+ < Collapsible className = "flex flex-col gap-3" >
210
+ < CollapsibleTrigger asChild >
211
+ < Button size = "sm" variant = "ghost" className = "gap-2" >
212
+ More wallets < ChevronDown />
213
+ </ Button >
214
+ </ CollapsibleTrigger >
215
+ < CollapsibleContent className = "flex flex-col gap-3" >
216
+ { aptosNotDetectedWallets . map ( ( wallet ) => (
217
+ < WalletRow key = { wallet . name } wallet = { wallet } />
218
+ ) ) }
219
+ </ CollapsibleContent >
220
+ </ Collapsible >
221
+ ) }
222
+ </ div >
223
+ </ AboutAptosConnect >
224
+ </ DialogContent >
225
+ ) ;
226
+ }
227
+
115
228
return (
116
229
< DialogContent className = "max-h-screen overflow-auto" >
117
230
< DialogTitle className = "flex flex-col text-center leading-snug" >
@@ -132,7 +245,7 @@ function ConnectWalletDialog({ close, sourceChain }: ConnectWalletDialogProps) {
132
245
}
133
246
134
247
interface WalletRowProps {
135
- wallet : AdapterWallet ;
248
+ wallet : AdapterWallet | AptosNotDetectedWallet ;
136
249
onConnect ?: ( ) => void ;
137
250
onSignInWith ?: ( ) => void ;
138
251
}
@@ -167,3 +280,66 @@ function WalletRow({ wallet, onConnect, onSignInWith }: WalletRowProps) {
167
280
</ WalletItem >
168
281
) ;
169
282
}
283
+
284
+ function AptosConnectWalletRow ( { wallet, onConnect } : WalletRowProps ) {
285
+ return (
286
+ < WalletItem wallet = { wallet } onConnect = { onConnect } >
287
+ < WalletItem . ConnectButton asChild >
288
+ < Button size = "lg" variant = "outline" className = "w-full gap-4" >
289
+ < WalletItem . Icon className = "h-5 w-5" />
290
+ < WalletItem . Name className = "text-base font-normal" />
291
+ </ Button >
292
+ </ WalletItem . ConnectButton >
293
+ </ WalletItem >
294
+ ) ;
295
+ }
296
+
297
+ function renderEducationScreen ( screen : AboutAptosConnectEducationScreen ) {
298
+ return (
299
+ < >
300
+ < DialogHeader className = "grid grid-cols-[1fr_4fr_1fr] items-center space-y-0" >
301
+ < Button variant = "ghost" size = "icon" onClick = { screen . cancel } >
302
+ < ArrowLeft />
303
+ </ Button >
304
+ < DialogTitle className = "leading-snug text-base text-center" >
305
+ About Aptos Connect
306
+ </ DialogTitle >
307
+ </ DialogHeader >
308
+
309
+ < div className = "flex h-[162px] pb-3 items-end justify-center" >
310
+ < screen . Graphic />
311
+ </ div >
312
+ < div className = "flex flex-col gap-2 text-center pb-4" >
313
+ < screen . Title className = "text-xl" />
314
+ < screen . Description className = "text-sm text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a]:text-foreground" />
315
+ </ div >
316
+
317
+ < div className = "grid grid-cols-3 items-center" >
318
+ < Button
319
+ size = "sm"
320
+ variant = "ghost"
321
+ onClick = { screen . back }
322
+ className = "justify-self-start"
323
+ >
324
+ Back
325
+ </ Button >
326
+ < div className = "flex items-center gap-2 place-self-center" >
327
+ { screen . screenIndicators . map ( ( ScreenIndicator , i ) => (
328
+ < ScreenIndicator key = { i } className = "py-4" >
329
+ < div className = "h-0.5 w-6 transition-colors bg-muted [[data-active]>&]:bg-foreground" />
330
+ </ ScreenIndicator >
331
+ ) ) }
332
+ </ div >
333
+ < Button
334
+ size = "sm"
335
+ variant = "ghost"
336
+ onClick = { screen . next }
337
+ className = "gap-2 justify-self-end"
338
+ >
339
+ { screen . screenIndex === screen . totalScreens - 1 ? "Finish" : "Next" }
340
+ < ArrowRight size = { 16 } />
341
+ </ Button >
342
+ </ div >
343
+ </ >
344
+ ) ;
345
+ }
0 commit comments