1- import { useState } from "react" ;
1+ import { useState , useEffect , useCallback } from "react" ;
22import { useWallet } from "@meshsdk/react" ;
33import { Dialog , DialogContent , DialogHeader , DialogTitle , DialogDescription } from "@/components/ui/dialog" ;
44import { Button } from "@/components/ui/button" ;
@@ -9,14 +9,16 @@ interface WalletAuthModalProps {
99 open : boolean ;
1010 onClose : ( ) => void ;
1111 onAuthorized ?: ( ) => void ;
12+ autoAuthorize ?: boolean ; // If true, automatically trigger authorization when modal opens
1213}
1314
14- export function WalletAuthModal ( { address, open, onClose, onAuthorized } : WalletAuthModalProps ) {
15+ export function WalletAuthModal ( { address, open, onClose, onAuthorized, autoAuthorize = false } : WalletAuthModalProps ) {
1516 const { wallet, connected } = useWallet ( ) ;
1617 const { toast } = useToast ( ) ;
1718 const [ submitting , setSubmitting ] = useState ( false ) ;
19+ const [ hasAutoAuthorized , setHasAutoAuthorized ] = useState ( false ) ;
1820
19- const handleAuthorize = async ( ) => {
21+ const handleAuthorize = useCallback ( async ( ) => {
2022 if ( ! wallet || ! connected ) {
2123 toast ( {
2224 title : "No wallet connected" ,
@@ -27,11 +29,33 @@ export function WalletAuthModal({ address, open, onClose, onAuthorized }: Wallet
2729 }
2830 setSubmitting ( true ) ;
2931 try {
30- // Resolve the payment address the wallet uses (match Swagger flow)
31- const usedAddresses = await wallet . getUsedAddresses ( ) ;
32- const signingAddress = usedAddresses [ 0 ] ;
32+ // Resolve the payment address the wallet uses
33+ // Try used addresses first, fall back to unused addresses if needed
34+ let signingAddress : string | undefined ;
35+ try {
36+ const usedAddresses = await wallet . getUsedAddresses ( ) ;
37+ signingAddress = usedAddresses [ 0 ] ;
38+ } catch ( error ) {
39+ if ( error instanceof Error && error . message . includes ( "account changed" ) ) {
40+ throw error ;
41+ }
42+ // If getUsedAddresses fails for other reasons, try unused addresses
43+ }
44+
45+ // Fall back to unused addresses if no used addresses found
46+ if ( ! signingAddress ) {
47+ try {
48+ const unusedAddresses = await wallet . getUnusedAddresses ( ) ;
49+ signingAddress = unusedAddresses [ 0 ] ;
50+ } catch ( error ) {
51+ if ( error instanceof Error && error . message . includes ( "account changed" ) ) {
52+ throw error ;
53+ }
54+ }
55+ }
56+
3357 if ( ! signingAddress ) {
34- throw new Error ( "No used addresses found for wallet" ) ;
58+ throw new Error ( "No addresses found for wallet" ) ;
3559 }
3660
3761 // 1) Get nonce from existing endpoint
@@ -100,7 +124,6 @@ export function WalletAuthModal({ address, open, onClose, onAuthorized }: Wallet
100124 onAuthorized ?.( ) ;
101125 onClose ( ) ;
102126 } catch ( error : any ) {
103- console . error ( "WalletAuthModal authorize error:" , error ) ;
104127 toast ( {
105128 title : "Authorization failed" ,
106129 description : error ?. message || "Unable to authorize wallet. Please try again." ,
@@ -109,16 +132,56 @@ export function WalletAuthModal({ address, open, onClose, onAuthorized }: Wallet
109132 } finally {
110133 setSubmitting ( false ) ;
111134 }
112- } ;
135+ } , [ wallet , connected , toast , onAuthorized , onClose ] ) ;
136+
137+ // Auto-authorize when modal opens if autoAuthorize is true (only once)
138+ useEffect ( ( ) => {
139+ if ( open && autoAuthorize && ! hasAutoAuthorized && wallet && connected && ! submitting ) {
140+ // Small delay to ensure modal is fully rendered before triggering wallet prompt
141+ const timeoutId = setTimeout ( ( ) => {
142+ setHasAutoAuthorized ( true ) ;
143+ void handleAuthorize ( ) ;
144+ } , 100 ) ;
145+
146+ return ( ) => clearTimeout ( timeoutId ) ;
147+ }
148+ } , [ open , autoAuthorize , hasAutoAuthorized , wallet , connected , submitting , handleAuthorize ] ) ;
149+
150+ // Reset auto-authorize flag when modal closes
151+ useEffect ( ( ) => {
152+ if ( ! open ) {
153+ setHasAutoAuthorized ( false ) ;
154+ }
155+ } , [ open ] ) ;
113156
114157 return (
115- < Dialog open = { open } onOpenChange = { ( open ) => ! open && ! submitting && onClose ( ) } >
116- < DialogContent >
158+ < Dialog open = { open } onOpenChange = { ( open ) => {
159+ // Prevent closing during authorization
160+ if ( ! open && ! submitting ) {
161+ onClose ( ) ;
162+ }
163+ } } >
164+ < DialogContent onPointerDownOutside = { ( e ) => {
165+ // Prevent closing by clicking outside during authorization
166+ if ( submitting ) {
167+ e . preventDefault ( ) ;
168+ }
169+ } } onEscapeKeyDown = { ( e ) => {
170+ // Prevent closing with Escape key during authorization
171+ if ( submitting ) {
172+ e . preventDefault ( ) ;
173+ }
174+ } } >
117175 < DialogHeader >
118176 < DialogTitle > Authorize this wallet</ DialogTitle >
119177 < DialogDescription >
120178 To use this wallet with multisig, we need to confirm you control it by signing a
121179 short message. This does not move any funds or create a transaction.
180+ { autoAuthorize && ! hasAutoAuthorized && (
181+ < span className = "block mt-2 text-sm font-medium" >
182+ Please approve the signing request in your wallet.
183+ </ span >
184+ ) }
122185 </ DialogDescription >
123186 </ DialogHeader >
124187 < div className = "mt-4 space-y-2 text-sm text-muted-foreground break-all" >
@@ -127,9 +190,11 @@ export function WalletAuthModal({ address, open, onClose, onAuthorized }: Wallet
127190 </ div >
128191 </ div >
129192 < div className = "mt-6 flex justify-end gap-2" >
130- < Button variant = "outline" onClick = { onClose } disabled = { submitting } >
131- Cancel
132- </ Button >
193+ { ! autoAuthorize && (
194+ < Button variant = "outline" onClick = { onClose } disabled = { submitting } >
195+ Cancel
196+ </ Button >
197+ ) }
133198 < Button onClick = { handleAuthorize } disabled = { submitting } >
134199 { submitting ? "Authorizing..." : "Authorize" }
135200 </ Button >
0 commit comments