@@ -44,6 +44,11 @@ export default function Profile() {
4444 const [ programmableBalanceError , setProgrammableBalanceError ] = useState < string | null > ( null ) ;
4545 const [ programmableBalanceRefreshKey , setProgrammableBalanceRefreshKey ] = useState ( 0 ) ;
4646 const [ selectedTokenHex , setSelectedTokenHex ] = useState ( '' ) ;
47+ const [ isSendingTokens , setIsSendingTokens ] = useState ( false ) ;
48+ const [ isUserMinting , setIsUserMinting ] = useState ( false ) ;
49+ const [ isUserFreezing , setIsUserFreezing ] = useState ( false ) ;
50+ const [ isUserUnfreezing , setIsUserUnfreezing ] = useState ( false ) ;
51+ const [ isUserSeizing , setIsUserSeizing ] = useState ( false ) ;
4752
4853 const demoEnv = useContext ( DemoEnvironmentContext ) ;
4954
@@ -276,6 +281,9 @@ export default function Profile() {
276281 } , [ accounts . walletUser . regular_address , currentUser , programmableBalanceRefreshKey ] ) ;
277282
278283 const onSend = async ( ) => {
284+ if ( isSendingTokens ) {
285+ return ;
286+ }
279287 if ( getUserAccountDetails ( ) ?. status === 'Frozen' && ! overrideTx ) {
280288 changeAlertInfo ( {
281289 severity : 'error' ,
@@ -346,6 +354,7 @@ export default function Profile() {
346354 } ) ;
347355 return ;
348356 }
357+ setIsSendingTokens ( true ) ;
349358 const requestData = {
350359 asset_name : selectedTokenHex ,
351360 issuer : issuerForPolicy ,
@@ -370,9 +379,17 @@ export default function Profile() {
370379 await updateAccountBalance ( sendRecipientAddress ) ;
371380 await updateAccountBalance ( accountInfo . regular_address ) ;
372381 setProgrammableBalanceRefreshKey ( ( key ) => key + 1 ) ;
373- changeAlertInfo ( { severity : 'success' , message : 'Transaction sent successfully!' , open : true , link : `${ demoEnv . explorer_url } /${ txId } ` } ) ;
382+ changeAlertInfo ( {
383+ severity : 'success' ,
384+ message : 'Transaction sent successfully!' ,
385+ open : true ,
386+ link : `${ demoEnv . explorer_url } /${ txId } ` ,
387+ actionText : 'View on Explorer'
388+ } ) ;
374389 } catch ( error ) {
375390 console . error ( 'Send failed:' , error ) ;
391+ } finally {
392+ setIsSendingTokens ( false ) ;
376393 }
377394 } ;
378395
@@ -422,7 +439,8 @@ export default function Profile() {
422439 severity : 'success' ,
423440 message : msg ,
424441 open : true ,
425- link : txId ? `${ demoEnv . explorer_url } /${ txId } ` : ''
442+ link : txId ? `${ demoEnv . explorer_url } /${ txId } ` : '' ,
443+ actionText : txId ? 'View on Explorer' : undefined
426444 } ) ;
427445 } ;
428446
@@ -494,7 +512,8 @@ export default function Profile() {
494512 severity : 'success' ,
495513 message : 'Blacklist initialised successfully!' ,
496514 open : true ,
497- link : `${ demoEnv . explorer_url } /${ txId } `
515+ link : `${ demoEnv . explorer_url } /${ txId } ` ,
516+ actionText : 'View on Explorer'
498517 } ) ;
499518 } catch ( error ) {
500519 console . error ( 'Blacklist init failed:' , error ) ;
@@ -550,6 +569,9 @@ export default function Profile() {
550569 } ;
551570
552571 const onUserMint = async ( ) => {
572+ if ( isUserMinting ) {
573+ return ;
574+ }
553575 const issuerAddress = ensureWalletReady ( ) ;
554576 if ( ! issuerAddress ) return ;
555577 if ( ! userAddressCleared ) {
@@ -570,6 +592,7 @@ export default function Profile() {
570592 quantity : userMintAmount ,
571593 recipient
572594 } ;
595+ setIsUserMinting ( true ) ;
573596 try {
574597 const response = await axios . post (
575598 '/api/v1/tx/programmable-token/issue' ,
@@ -584,7 +607,8 @@ export default function Profile() {
584607 severity : 'success' ,
585608 message : 'Mint successful!' ,
586609 open : true ,
587- link : `${ demoEnv . explorer_url } /${ txId } `
610+ link : `${ demoEnv . explorer_url } /${ txId } ` ,
611+ actionText : 'View on Explorer'
588612 } ) ;
589613 await updateAccountBalance ( recipient ) ;
590614 await updateAccountBalance ( issuerAddress ) ;
@@ -597,10 +621,15 @@ export default function Profile() {
597621 open : true ,
598622 link : ''
599623 } ) ;
624+ } finally {
625+ setIsUserMinting ( false ) ;
600626 }
601627 } ;
602628
603629 const onUserFreeze = async ( ) => {
630+ if ( isUserFreezing ) {
631+ return ;
632+ }
604633 const issuerAddress = ensureWalletReady ( ) ;
605634 if ( ! issuerAddress || ! userFreezeAddress ) return ;
606635 changeAlertInfo ( { severity : 'info' , message : 'Processing freeze request…' , open : true , link : '' } ) ;
@@ -609,6 +638,7 @@ export default function Profile() {
609638 blacklist_address : userFreezeAddress ,
610639 reason : userFreezeReason
611640 } ;
641+ setIsUserFreezing ( true ) ;
612642 try {
613643 const response = await axios . post (
614644 '/api/v1/tx/programmable-token/blacklist' ,
@@ -621,7 +651,8 @@ export default function Profile() {
621651 severity : 'success' ,
622652 message : 'Address frozen.' ,
623653 open : true ,
624- link : `${ demoEnv . explorer_url } /${ txId } `
654+ link : `${ demoEnv . explorer_url } /${ txId } ` ,
655+ actionText : 'View on Explorer'
625656 } ) ;
626657 const frozenWalletKey = ( Object . keys ( accounts ) as ( keyof Accounts ) [ ] ) . find (
627658 ( key ) => accounts [ key ] . regular_address === userFreezeAddress
@@ -643,10 +674,15 @@ export default function Profile() {
643674 } else {
644675 console . error ( 'Connected wallet freeze failed:' , error ) ;
645676 }
677+ } finally {
678+ setIsUserFreezing ( false ) ;
646679 }
647680 } ;
648681
649682 const onUserUnfreeze = async ( ) => {
683+ if ( isUserUnfreezing ) {
684+ return ;
685+ }
650686 const issuerAddress = ensureWalletReady ( ) ;
651687 if ( ! issuerAddress || ! userUnfreezeAddress ) return ;
652688 changeAlertInfo ( { severity : 'info' , message : 'Processing unfreeze request…' , open : true , link : '' } ) ;
@@ -655,6 +691,7 @@ export default function Profile() {
655691 blacklist_address : userUnfreezeAddress ,
656692 reason : '(unfreeze)'
657693 } ;
694+ setIsUserUnfreezing ( true ) ;
658695 try {
659696 const response = await axios . post (
660697 '/api/v1/tx/programmable-token/unblacklist' ,
@@ -667,7 +704,8 @@ export default function Profile() {
667704 severity : 'success' ,
668705 message : 'Address unfrozen.' ,
669706 open : true ,
670- link : `${ demoEnv . explorer_url } /${ txId } `
707+ link : `${ demoEnv . explorer_url } /${ txId } ` ,
708+ actionText : 'View on Explorer'
671709 } ) ;
672710 const unfrozenWalletKey = ( Object . keys ( accounts ) as ( keyof Accounts ) [ ] ) . find (
673711 ( key ) => accounts [ key ] . regular_address === userUnfreezeAddress
@@ -689,10 +727,15 @@ export default function Profile() {
689727 } else {
690728 console . error ( 'Connected wallet unfreeze failed:' , error ) ;
691729 }
730+ } finally {
731+ setIsUserUnfreezing ( false ) ;
692732 }
693733 } ;
694734
695735 const onUserSeize = async ( ) => {
736+ if ( isUserSeizing ) {
737+ return ;
738+ }
696739 const issuerAddress = ensureWalletReady ( ) ;
697740 if ( ! issuerAddress || ! userSeizeAddress ) return ;
698741 changeAlertInfo ( { severity : 'info' , message : 'Processing seizure request…' , open : true , link : '' } ) ;
@@ -701,6 +744,7 @@ export default function Profile() {
701744 target : userSeizeAddress ,
702745 reason : userSeizeReason
703746 } ;
747+ setIsUserSeizing ( true ) ;
704748 try {
705749 const response = await axios . post (
706750 '/api/v1/tx/programmable-token/seize' ,
@@ -714,7 +758,8 @@ export default function Profile() {
714758 severity : 'success' ,
715759 message : 'Funds seized.' ,
716760 open : true ,
717- link : `${ demoEnv . explorer_url } /${ txId } `
761+ link : `${ demoEnv . explorer_url } /${ txId } ` ,
762+ actionText : 'View on Explorer'
718763 } ) ;
719764 } catch ( error ) {
720765 console . error ( 'Connected wallet seize failed:' , error ) ;
@@ -724,6 +769,8 @@ export default function Profile() {
724769 open : true ,
725770 link : ''
726771 } ) ;
772+ } finally {
773+ setIsUserSeizing ( false ) ;
727774 }
728775 } ;
729776
@@ -956,9 +1003,10 @@ export default function Profile() {
9561003 {
9571004 label : 'Send' ,
9581005 content : sendContent ,
959- buttonLabel : 'Send' ,
1006+ buttonLabel : isSendingTokens ? 'Sending…' : 'Send' ,
9601007 onAction : onSend ,
961- buttonDisabled : ! sendAmountValid
1008+ buttonDisabled : ! sendAmountValid || isSendingTokens ,
1009+ buttonLoading : isSendingTokens
9621010 } ,
9631011 {
9641012 label : 'Receive' ,
@@ -1011,26 +1059,34 @@ export default function Profile() {
10111059 {
10121060 label : 'Mint' ,
10131061 content : userMintContent ,
1014- buttonLabel : 'Mint' ,
1015- onAction : onUserMint
1062+ buttonLabel : isUserMinting ? 'Minting…' : 'Mint' ,
1063+ onAction : onUserMint ,
1064+ buttonDisabled : isUserMinting ,
1065+ buttonLoading : isUserMinting
10161066 } ,
10171067 {
10181068 label : 'Freeze' ,
10191069 content : userFreezeContent ,
1020- buttonLabel : 'Freeze' ,
1021- onAction : onUserFreeze
1070+ buttonLabel : isUserFreezing ? 'Freezing…' : 'Freeze' ,
1071+ onAction : onUserFreeze ,
1072+ buttonDisabled : isUserFreezing ,
1073+ buttonLoading : isUserFreezing
10221074 } ,
10231075 {
10241076 label : 'Unfreeze' ,
10251077 content : userUnfreezeContent ,
1026- buttonLabel : 'Unfreeze' ,
1027- onAction : onUserUnfreeze
1078+ buttonLabel : isUserUnfreezing ? 'Unfreezing…' : 'Unfreeze' ,
1079+ onAction : onUserUnfreeze ,
1080+ buttonDisabled : isUserUnfreezing ,
1081+ buttonLoading : isUserUnfreezing
10281082 } ,
10291083 {
10301084 label : 'Seize' ,
10311085 content : userSeizeContent ,
1032- buttonLabel : 'Seize' ,
1033- onAction : onUserSeize
1086+ buttonLabel : isUserSeizing ? 'Seizing…' : 'Seize' ,
1087+ onAction : onUserSeize ,
1088+ buttonDisabled : isUserSeizing ,
1089+ buttonLoading : isUserSeizing
10341090 }
10351091 ] } />
10361092 </ div >
@@ -1113,14 +1169,16 @@ export default function Profile() {
11131169 content : registerContent ,
11141170 buttonLabel : isRegistering ? 'Registering…' : 'Register Asset' ,
11151171 onAction : onRegisterAsset ,
1116- buttonDisabled : isRegistering
1172+ buttonDisabled : isRegistering ,
1173+ buttonLoading : isRegistering
11171174 } ,
11181175 {
11191176 label : 'Blacklist Init' ,
11201177 content : blacklistInitContent ,
11211178 buttonLabel : isInitializingBlacklist ? 'Initializing…' : 'Initialize Blacklist' ,
11221179 onAction : onBlacklistInit ,
1123- buttonDisabled : isInitializingBlacklist
1180+ buttonDisabled : isInitializingBlacklist ,
1181+ buttonLoading : isInitializingBlacklist
11241182 }
11251183 ] } />
11261184 </ div >
0 commit comments