@@ -28,6 +28,8 @@ import {
2828 Database01Icon ,
2929 CoinsSwapIcon ,
3030 Coins01Icon ,
31+ InformationCircleIcon ,
32+ Cancel01Icon ,
3133} from "hugeicons-react" ;
3234import Image from "next/image" ;
3335import { useInjectedWallet } from "../context" ;
@@ -59,8 +61,9 @@ import { CopyAddressWarningModal } from "./CopyAddressWarningModal";
5961import { useFundWalletHandler } from "../hooks/useFundWalletHandler" ;
6062import { useCNGNRate } from "../hooks/useCNGNRate" ;
6163import { EarnConsentModal } from "./EarnConsentModal" ;
64+ import { EarnUnavailableModal } from "./EarnUnavailableModal" ;
6265import { useEarnAccess } from "../hooks/useEarnAccess" ;
63- import { isEarnUiVisible } from "../lib/earnFeature" ;
66+ import { isEarnEnabled , isEarnUiVisible } from "../lib/earnFeature" ;
6467import { isReferralEnabled , formatTokenAmount } from "../utils" ;
6568import { isBridgeUiVisible } from "../lib/bridgeFeature" ;
6669import { BridgeForm } from "./bridge/BridgeForm" ;
@@ -72,6 +75,50 @@ const Divider = () => (
7275 < div className = "w-full border border-dashed border-[#EBEBEF] dark:border-[#FFFFFF1A]" />
7376) ;
7477
78+ /** Pixel-matched callout for the Earn action-item when it's shown on a
79+ * network Earn doesn't support yet (Figma node 2208:82749). Anchored to the
80+ * bottom-right of the action row with an upward-pointing tail toward Earn. */
81+ const EarnUnavailableTooltip = ( {
82+ isOpen,
83+ onClose,
84+ } : {
85+ isOpen : boolean ;
86+ onClose : ( ) => void ;
87+ } ) => (
88+ < AnimatePresence >
89+ { isOpen && (
90+ < motion . div
91+ initial = { { opacity : 0 , y : - 4 } }
92+ animate = { { opacity : 1 , y : 0 } }
93+ exit = { { opacity : 0 , y : - 4 } }
94+ transition = { { duration : 0.15 } }
95+ className = "absolute right-0 top-full z-10 mt-2 w-[266px]"
96+ >
97+ < div
98+ className = "absolute -top-1.5 right-8 size-3 rotate-45 rounded-[2px] border-l border-t border-border-light bg-white dark:border-white/10 dark:bg-[#2c2c2c]"
99+ aria-hidden
100+ />
101+ < div className = "relative rounded-2xl border border-border-light bg-white p-2.5 pr-9 shadow-lg dark:border-white/10 dark:bg-[#2c2c2c]" >
102+ < p className = "text-[11px] font-medium leading-5 text-text-body dark:text-white" >
103+ Earn is currently available on Starknet.
104+ </ p >
105+ < p className = "mt-[3px] text-[10px] leading-[13px] text-text-secondary dark:text-white/50" >
106+ Switch your wallet to Starknet to start earning on your USDC.
107+ </ p >
108+ < button
109+ type = "button"
110+ aria-label = "Dismiss"
111+ onClick = { onClose }
112+ className = "absolute right-2.5 top-2.5 text-text-secondary hover:text-text-body dark:text-white/50 dark:hover:text-white"
113+ >
114+ < Cancel01Icon className = "size-4" />
115+ </ button >
116+ </ div >
117+ </ motion . div >
118+ ) }
119+ </ AnimatePresence >
120+ ) ;
121+
75122export const WalletDetails = ( ) => {
76123 const { trackBridge } = useBridgeStatusTracker ( ) ;
77124 const [ isTransferModalOpen , setIsTransferModalOpen ] =
@@ -80,6 +127,9 @@ export const WalletDetails = () => {
80127 const [ isConvertModalOpen , setIsConvertModalOpen ] = useState ( false ) ;
81128 const [ isEarnFormOpen , setIsEarnFormOpen ] = useState ( false ) ;
82129 const [ earnFormTab , setEarnFormTab ] = useState < "deposit" | "withdraw" > ( "deposit" ) ;
130+ const [ isEarnHintOpen , setIsEarnHintOpen ] = useState ( false ) ;
131+ const [ isEarnUnavailableModalOpen , setIsEarnUnavailableModalOpen ] =
132+ useState ( false ) ;
83133 const [ sidebarView , setSidebarView ] = useState <
84134 "wallet" | "earn" | "referrals"
85135 > ( "wallet" ) ;
@@ -284,6 +334,8 @@ export const WalletDetails = () => {
284334 setSelectedTransaction ( null ) ;
285335 setSelectedEarnActivity ( null ) ;
286336 setIsNetworkListOpen ( false ) ;
337+ setIsEarnHintOpen ( false ) ;
338+ setIsEarnUnavailableModalOpen ( false ) ;
287339 } ;
288340
289341 // Copy wallet address to clipboard with feedback
@@ -480,111 +532,95 @@ export const WalletDetails = () => {
480532 </ button >
481533 </ div >
482534
483- { ! isInjectedWallet &&
484- ( showEarnUi ? (
485- < div className = "flex flex-row items-start justify-between gap-2" >
486- < button
487- type = "button"
488- title = "Fund wallet"
489- onClick = { ( ) => setIsFundModalOpen ( true ) }
490- className = "group flex flex-1 flex-col items-center gap-2"
491- >
492- < span className = "flex size-[60px] items-center justify-center rounded-full bg-lavender-500 text-white transition-all group-hover:scale-[0.98] group-active:scale-95" >
493- < ArrowDownLeft01Icon className = "size-6" strokeWidth = { 2 } />
494- </ span >
495- < span className = "text-sm font-medium text-text-body dark:text-white" >
496- Fund
497- </ span >
498- </ button >
535+ { ! isInjectedWallet && (
536+ < div className = "flex flex-row items-start justify-between gap-2" >
537+ < button
538+ type = "button"
539+ title = "Fund wallet"
540+ onClick = { ( ) => setIsFundModalOpen ( true ) }
541+ className = "group flex flex-1 flex-col items-center gap-2"
542+ >
543+ < span className = "flex size-[60px] items-center justify-center rounded-full bg-lavender-500 text-white transition-all group-hover:scale-[0.98] group-active:scale-95" >
544+ < ArrowDownLeft01Icon className = "size-6" strokeWidth = { 2 } />
545+ </ span >
546+ < span className = "text-sm font-medium text-text-body dark:text-white" >
547+ Fund
548+ </ span >
549+ </ button >
550+ < button
551+ type = "button"
552+ title = "Transfer funds"
553+ onClick = { ( ) => setIsTransferModalOpen ( true ) }
554+ className = "group flex flex-1 flex-col items-center gap-2"
555+ >
556+ < span className = "flex size-[60px] items-center justify-center rounded-full bg-accent-gray text-gray-900 transition-all group-hover:scale-[0.98] group-hover:bg-[#EBEBEF] group-active:scale-95 dark:bg-white/5 dark:text-white dark:group-hover:bg-white/10" >
557+ < ArrowUpRight01Icon className = "size-6" strokeWidth = { 2 } />
558+ </ span >
559+ < span className = "text-sm font-medium text-text-body dark:text-white" >
560+ Transfer
561+ </ span >
562+ </ button >
563+ { isBridgeUiVisible ( ) && (
499564 < button
500565 type = "button"
501- title = "Transfer funds "
502- onClick = { ( ) => setIsTransferModalOpen ( true ) }
566+ title = "Convert tokens "
567+ onClick = { ( ) => setIsConvertModalOpen ( true ) }
503568 className = "group flex flex-1 flex-col items-center gap-2"
504569 >
505570 < span className = "flex size-[60px] items-center justify-center rounded-full bg-accent-gray text-gray-900 transition-all group-hover:scale-[0.98] group-hover:bg-[#EBEBEF] group-active:scale-95 dark:bg-white/5 dark:text-white dark:group-hover:bg-white/10" >
506- < ArrowUpRight01Icon className = "size-6" strokeWidth = { 2 } />
571+ < CoinsSwapIcon className = "size-6" strokeWidth = { 2 } />
507572 </ span >
508573 < span className = "text-sm font-medium text-text-body dark:text-white" >
509- Transfer
574+ Convert
510575 </ span >
511576 </ button >
512- { isBridgeUiVisible ( ) && (
513- < button
514- type = "button"
515- title = "Convert tokens"
516- onClick = { ( ) => setIsConvertModalOpen ( true ) }
517- className = "group flex flex-1 flex-col items-center gap-2"
518- >
519- < span className = "flex size-[60px] items-center justify-center rounded-full bg-accent-gray text-gray-900 transition-all group-hover:scale-[0.98] group-hover:bg-[#EBEBEF] group-active:scale-95 dark:bg-white/5 dark:text-white dark:group-hover:bg-white/10" >
520- < CoinsSwapIcon className = "size-6" strokeWidth = { 2 } />
521- </ span >
522- < span className = "text-sm font-medium text-text-body dark:text-white" >
523- Convert
524- </ span >
525- </ button >
526- ) }
527- < button
528- type = "button"
529- title = "Earn yield on USDC via Vesu"
530- onClick = { ( ) =>
531- requestEarnAccess ( "earn-hub" , onEarnAccessAction )
577+ ) }
578+ { isEarnEnabled ( ) && (
579+ < div
580+ className = "relative flex flex-1 flex-col items-center"
581+ onMouseEnter = { ( ) =>
582+ ! showEarnUi && setIsEarnHintOpen ( true )
532583 }
533- className = "group flex flex-1 flex-col items-center gap-2"
534- >
535- < span className = "flex size-[60px] items-center justify-center rounded-full bg-accent-gray text-gray-900 transition-all group-hover:scale-[0.98] group-hover:bg-[#EBEBEF] group-active:scale-95 dark:bg-white/5 dark:text-white dark:group-hover:bg-white/10" >
536- < Coins01Icon className = "size-6" strokeWidth = { 2 } />
537- </ span >
538- < span className = "text-sm font-medium text-text-body dark:text-white" >
539- Earn
540- </ span >
541- </ button >
542- </ div >
543- ) : (
544- < div className = "flex flex-row items-start justify-between gap-2" >
545- < button
546- type = "button"
547- title = "Fund wallet"
548- onClick = { ( ) => setIsFundModalOpen ( true ) }
549- className = "group flex flex-1 flex-col items-center gap-2"
584+ onMouseLeave = { ( ) => setIsEarnHintOpen ( false ) }
550585 >
551- < span className = "flex size-[60px] items-center justify-center rounded-full bg-lavender-500 text-white transition-all group-hover:scale-[0.98] group-active:scale-95" >
552- < ArrowDownLeft01Icon className = "size-6" strokeWidth = { 2 } />
553- </ span >
554- < span className = "text-sm font-medium text-text-body dark:text-white" >
555- Fund
556- </ span >
557- </ button >
558- < button
559- type = "button"
560- title = "Transfer funds"
561- onClick = { ( ) => setIsTransferModalOpen ( true ) }
562- className = "group flex flex-1 flex-col items-center gap-2"
563- >
564- < span className = "flex size-[60px] items-center justify-center rounded-full bg-accent-gray text-gray-900 transition-all group-hover:scale-[0.98] group-hover:bg-[#EBEBEF] group-active:scale-95 dark:bg-white/5 dark:text-white dark:group-hover:bg-white/10" >
565- < ArrowUpRight01Icon className = "size-6" strokeWidth = { 2 } />
566- </ span >
567- < span className = "text-sm font-medium text-text-body dark:text-white" >
568- Transfer
569- </ span >
570- </ button >
571- { isBridgeUiVisible ( ) && (
572586 < button
573587 type = "button"
574- title = "Convert tokens"
575- onClick = { ( ) => setIsConvertModalOpen ( true ) }
576- className = "group flex flex-1 flex-col items-center gap-2"
588+ title = {
589+ showEarnUi
590+ ? "Earn yield on USDC via Vesu"
591+ : "Earn is currently available on Starknet"
592+ }
593+ onClick = { ( ) => {
594+ if ( showEarnUi ) {
595+ requestEarnAccess (
596+ "earn-hub" ,
597+ onEarnAccessAction ,
598+ ) ;
599+ } else {
600+ setIsEarnHintOpen ( false ) ;
601+ setIsEarnUnavailableModalOpen ( true ) ;
602+ }
603+ } }
604+ className = "group flex flex-col items-center gap-2"
577605 >
578606 < span className = "flex size-[60px] items-center justify-center rounded-full bg-accent-gray text-gray-900 transition-all group-hover:scale-[0.98] group-hover:bg-[#EBEBEF] group-active:scale-95 dark:bg-white/5 dark:text-white dark:group-hover:bg-white/10" >
579- < CoinsSwapIcon className = "size-6" strokeWidth = { 2 } />
607+ < Coins01Icon className = "size-6" strokeWidth = { 2 } />
580608 </ span >
581- < span className = "text-sm font-medium text-text-body dark:text-white" >
582- Convert
609+ < span className = "flex items-center gap-1 text-sm font-medium text-text-body dark:text-white" >
610+ Earn
611+ { ! showEarnUi && (
612+ < InformationCircleIcon className = "size-4 text-text-secondary dark:text-white/50" />
613+ ) }
583614 </ span >
584615 </ button >
585- ) }
586- </ div >
587- ) ) }
616+ < EarnUnavailableTooltip
617+ isOpen = { isEarnHintOpen }
618+ onClose = { ( ) => setIsEarnHintOpen ( false ) }
619+ />
620+ </ div >
621+ ) }
622+ </ div >
623+ ) }
588624 </ div >
589625 </ div >
590626
@@ -898,6 +934,11 @@ export const WalletDetails = () => {
898934 >
899935 < BridgeForm onClose = { ( ) => setIsConvertModalOpen ( false ) } onBridgeSubmit = { trackBridge } />
900936 </ AnimatedModal >
937+
938+ < EarnUnavailableModal
939+ isOpen = { isEarnUnavailableModalOpen }
940+ onClose = { ( ) => setIsEarnUnavailableModalOpen ( false ) }
941+ />
901942 </ >
902943 ) }
903944
0 commit comments