11import { ChevronDownIcon } from '@heroicons/react/outline' ;
2- import { ExternalLinkIcon } from '@heroicons/react/solid' ;
2+ import { ExternalLinkIcon , StarIcon } from '@heroicons/react/solid' ;
33import { Trans } from '@lingui/macro' ;
44import {
55 Box ,
66 BoxProps ,
7+ IconButton ,
78 ListItemText ,
89 MenuItem ,
910 SvgIcon ,
@@ -111,6 +112,35 @@ enum SelectedMarketVersion {
111112 V3 ,
112113}
113114
115+ // Custom market order requested by BD - TODO: move logic to the backend base on TVL
116+ const MARKET_ORDER_BY_TITLE : { [ title : string ] : number } = {
117+ Core : 0 ,
118+ Prime : 1 ,
119+ Base : 2 ,
120+ Arbitrum : 3 ,
121+ Avalanche : 4 ,
122+ Linea : 5 ,
123+ 'Horizon RWA' : 6 ,
124+ Sonic : 7 ,
125+ OP : 8 ,
126+ Gnosis : 9 ,
127+ Aptos : 10 ,
128+ 'BNB Chain' : 11 ,
129+ Polygon : 12 ,
130+ Scroll : 13 ,
131+ ZKsync : 14 ,
132+ Celo : 15 ,
133+ Metis : 16 ,
134+ Soneium : 17 ,
135+ EtherFi : 18 ,
136+ } ;
137+
138+ const getMarketOrder = ( marketId : CustomMarket ) : number => {
139+ const { market } = getMarketInfoById ( marketId ) ;
140+ const marketTitle = market . marketTitle ;
141+ return MARKET_ORDER_BY_TITLE [ marketTitle ] ?? 999 ; // Default to end if not found
142+ } ;
143+
114144export const MarketSwitcher = ( ) => {
115145 const [ selectedMarketVersion , setSelectedMarketVersion ] = useState < SelectedMarketVersion > (
116146 SelectedMarketVersion . V3
@@ -121,6 +151,10 @@ export const MarketSwitcher = () => {
121151 const [ trackEvent , currentMarket , setCurrentMarket ] = useRootStore (
122152 useShallow ( ( store ) => [ store . trackEvent , store . currentMarket , store . setCurrentMarket ] )
123153 ) ;
154+ const isFavoriteMarket = useRootStore ( ( store ) => store . isFavoriteMarket ) ;
155+ const toggleFavoriteMarket = useRootStore ( ( store ) => store . toggleFavoriteMarket ) ;
156+ // Subscribe to favoriteMarkets to trigger re-renders when favorites change
157+ useRootStore ( ( store ) => store . favoriteMarkets ) ;
124158
125159 const isV3MarketsAvailable = availableMarkets
126160 . map ( ( marketId : CustomMarket ) => {
@@ -143,6 +177,12 @@ export const MarketSwitcher = () => {
143177 setCurrentMarket ( selectedMarket ) ;
144178 } ;
145179
180+ const handleStarClick = ( e : React . MouseEvent , marketId : CustomMarket ) => {
181+ e . stopPropagation ( ) ;
182+ e . preventDefault ( ) ;
183+ toggleFavoriteMarket ( marketId ) ;
184+ } ;
185+
146186 const marketBlurbs : { [ key : string ] : JSX . Element } = {
147187 proto_mainnet_v3 : (
148188 < Trans > Main Ethereum market with the largest selection of assets and yield options</ Trans >
@@ -385,53 +425,94 @@ export const MarketSwitcher = () => {
385425 </ StyledToggleButtonGroup >
386426 </ Box >
387427 ) }
388- { availableMarkets . map ( ( marketId : CustomMarket ) => {
389- const { market, logo } = getMarketInfoById ( marketId ) ;
390- const marketNaming = getMarketHelpData ( market . marketTitle ) ;
391- return (
392- < MenuItem
393- key = { marketId }
394- data-cy = { `marketSelector_${ marketId } ` }
395- value = { marketId }
396- sx = { {
397- '.MuiListItemIcon-root' : { minWidth : 'unset' } ,
398- display :
399- ( market . v3 && selectedMarketVersion === SelectedMarketVersion . V2 ) ||
400- ( ! market . v3 && selectedMarketVersion === SelectedMarketVersion . V3 )
401- ? 'none'
402- : 'flex' ,
403- } }
404- >
405- < MarketLogo size = { 32 } logo = { logo } testChainName = { marketNaming . testChainName } />
406- < ListItemText sx = { { mr : 0 } } >
407- { marketNaming . name } { market . isFork ? 'Fork' : '' }
408- </ ListItemText >
409- < ListItemText
428+ { availableMarkets
429+ . slice ( ) // Create a copy to avoid mutating the original array
430+ . sort ( ( a , b ) => {
431+ const aIsFavorite = isFavoriteMarket ( a ) ;
432+ const bIsFavorite = isFavoriteMarket ( b ) ;
433+
434+ // If both are favorites or both are not favorites, maintain custom order
435+ if ( aIsFavorite === bIsFavorite ) {
436+ return getMarketOrder ( a ) - getMarketOrder ( b ) ;
437+ }
438+
439+ // Otherwise, favorites come first
440+ return aIsFavorite ? - 1 : 1 ;
441+ } )
442+ . map ( ( marketId : CustomMarket ) => {
443+ const { market, logo } = getMarketInfoById ( marketId ) ;
444+ const marketNaming = getMarketHelpData ( market . marketTitle ) ;
445+ const isFavorite = isFavoriteMarket ( marketId ) ;
446+ return (
447+ < MenuItem
448+ key = { marketId }
449+ data-cy = { `marketSelector_${ marketId } ` }
450+ value = { marketId }
410451 sx = { {
411- textAlign : 'right' ,
412- display : 'flex' ,
413- alignItems : 'center' ,
414- flexDirection : 'row-reverse' ,
415- gap : 1 ,
452+ '.MuiListItemIcon-root' : { minWidth : 'unset' } ,
453+ display :
454+ ( market . v3 && selectedMarketVersion === SelectedMarketVersion . V2 ) ||
455+ ( ! market . v3 && selectedMarketVersion === SelectedMarketVersion . V3 )
456+ ? 'none'
457+ : 'flex' ,
416458 } }
417459 >
418- < Typography color = "text.muted" variant = "description" >
419- { marketNaming . testChainName }
420- </ Typography >
421- { market . externalUrl && (
422- < SvgIcon
423- sx = { {
424- fontSize : '16px' ,
425- color : 'text.muted' ,
426- } }
427- >
428- < ExternalLinkIcon />
429- </ SvgIcon >
430- ) }
431- </ ListItemText >
432- </ MenuItem >
433- ) ;
434- } ) }
460+ < MarketLogo size = { 32 } logo = { logo } testChainName = { marketNaming . testChainName } />
461+ < ListItemText sx = { { mr : 0 } } >
462+ { marketNaming . name } { market . isFork ? 'Fork' : '' }
463+ </ ListItemText >
464+ < ListItemText
465+ sx = { {
466+ textAlign : 'right' ,
467+ display : 'flex' ,
468+ alignItems : 'center' ,
469+ flexDirection : 'row-reverse' ,
470+ gap : 1 ,
471+ } }
472+ >
473+ < Typography color = "text.muted" variant = "description" >
474+ { marketNaming . testChainName }
475+ </ Typography >
476+ < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 0.5 } } >
477+ { market . externalUrl && (
478+ < SvgIcon
479+ sx = { {
480+ fontSize : '16px' ,
481+ color : 'text.muted' ,
482+ } }
483+ >
484+ < ExternalLinkIcon />
485+ </ SvgIcon >
486+ ) }
487+ < Tooltip title = { isFavorite ? 'Remove from favorites' : 'Add to favorites' } >
488+ < IconButton
489+ size = "small"
490+ onClick = { ( e ) => handleStarClick ( e , marketId ) }
491+ sx = { {
492+ padding : '2px' ,
493+ '&:hover' : {
494+ backgroundColor : 'rgba(255, 255, 255, 0.1)' ,
495+ } ,
496+ } }
497+ >
498+ < SvgIcon
499+ sx = { {
500+ fontSize : '18px' ,
501+ color : isFavorite ? '#FBCC5F' : 'text.disabled' ,
502+ '&:hover' : {
503+ color : isFavorite ? '#FBCC5F' : 'text.secondary' ,
504+ } ,
505+ } }
506+ >
507+ < StarIcon />
508+ </ SvgIcon >
509+ </ IconButton >
510+ </ Tooltip >
511+ </ Box >
512+ </ ListItemText >
513+ </ MenuItem >
514+ ) ;
515+ } ) }
435516 </ TextField >
436517 ) ;
437518} ;
0 commit comments