Skip to content

Commit 8cfc1c4

Browse files
committed
feat: added filters for categories in market section v0
1 parent aa30a40 commit 8cfc1c4

File tree

9 files changed

+283
-13
lines changed

9 files changed

+283
-13
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Trans } from '@lingui/macro';
2+
import { Box, Button, ButtonGroup } from '@mui/material';
3+
import { AssetCategory } from 'src/modules/markets/utils/assetCategories';
4+
5+
interface MarketAssetCategoryFiltersProps {
6+
selectedCategory: AssetCategory;
7+
onCategoryChange: (category: AssetCategory) => void;
8+
}
9+
10+
export const MarketAssetCategoryFilter = ({
11+
selectedCategory,
12+
onCategoryChange,
13+
}: MarketAssetCategoryFiltersProps) => {
14+
return (
15+
<Box sx={{ mt: 2, mb: 2 }}>
16+
<ButtonGroup
17+
sx={{
18+
'& .MuiButton-root': {
19+
textTransform: 'none',
20+
whiteSpace: 'nowrap',
21+
minWidth: 'auto',
22+
p: 2,
23+
fontSize: '0.875rem',
24+
},
25+
}}
26+
variant="outlined"
27+
size="small"
28+
>
29+
<Button
30+
variant={selectedCategory === AssetCategory.ALL ? 'contained' : 'outlined'}
31+
onClick={() => onCategoryChange(AssetCategory.ALL)}
32+
>
33+
<Trans>All</Trans>
34+
</Button>
35+
<Button
36+
variant={selectedCategory === AssetCategory.STABLECOINS ? 'contained' : 'outlined'}
37+
onClick={() => onCategoryChange(AssetCategory.STABLECOINS)}
38+
>
39+
<Trans>Stablecoins</Trans>
40+
</Button>
41+
<Button
42+
variant={selectedCategory === AssetCategory.ETH_CORRELATED ? 'contained' : 'outlined'}
43+
onClick={() => onCategoryChange(AssetCategory.ETH_CORRELATED)}
44+
>
45+
<Trans>ETH Correlated</Trans>
46+
</Button>
47+
</ButtonGroup>
48+
</Box>
49+
);
50+
};
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { SearchIcon } from '@heroicons/react/solid';
2+
import { Trans } from '@lingui/macro';
3+
import {
4+
Box,
5+
Button,
6+
IconButton,
7+
SvgIcon,
8+
Typography,
9+
TypographyProps,
10+
useMediaQuery,
11+
useTheme,
12+
} from '@mui/material';
13+
import { ReactNode, useState } from 'react';
14+
import { AssetCategory } from 'src/modules/markets/utils/assetCategories';
15+
16+
import { MarketAssetCategoryFilter } from './MarketAssetCategoryFilter';
17+
import { SearchInput } from './SearchInput';
18+
19+
interface TitleWithFiltersAndSearchBarProps<C extends React.ElementType> {
20+
onSearchTermChange: (value: string) => void;
21+
searchPlaceholder: string;
22+
titleProps?: TypographyProps<C, { component?: C }>;
23+
title: ReactNode;
24+
selectedCategory: AssetCategory;
25+
onCategoryChange: (category: AssetCategory) => void;
26+
}
27+
28+
export const TitleWithFiltersAndSearchBar = <T extends React.ElementType>({
29+
onSearchTermChange,
30+
searchPlaceholder,
31+
titleProps,
32+
title,
33+
selectedCategory,
34+
onCategoryChange,
35+
}: TitleWithFiltersAndSearchBarProps<T>) => {
36+
const [showSearchBar, setShowSearchBar] = useState(false);
37+
38+
const { breakpoints } = useTheme();
39+
const sm = useMediaQuery(breakpoints.down('sm'));
40+
41+
const showSearchIcon = sm && !showSearchBar;
42+
const showMarketTitle = !sm || !showSearchBar;
43+
44+
const handleCancelClick = () => {
45+
setShowSearchBar(false);
46+
onSearchTermChange('');
47+
};
48+
49+
return (
50+
<Box
51+
sx={{
52+
width: '100%',
53+
display: 'flex',
54+
alignItems: 'center',
55+
justifyContent: 'space-between',
56+
}}
57+
>
58+
{showMarketTitle && (
59+
<Typography component="div" variant="h2" sx={{ mr: 4 }} {...titleProps}>
60+
{title}
61+
</Typography>
62+
)}
63+
64+
<Box
65+
sx={{
66+
height: '40px',
67+
width: showSearchBar && sm ? '100%' : 'unset',
68+
position: 'relative',
69+
display: 'flex',
70+
alignItems: 'center',
71+
gap: 4,
72+
justifyContent: 'space-between',
73+
}}
74+
>
75+
<MarketAssetCategoryFilter
76+
selectedCategory={selectedCategory}
77+
onCategoryChange={onCategoryChange}
78+
/>
79+
{showSearchIcon && (
80+
<IconButton onClick={() => setShowSearchBar(true)}>
81+
<SvgIcon>
82+
<SearchIcon />
83+
</SvgIcon>
84+
</IconButton>
85+
)}
86+
{(showSearchBar || !sm) && (
87+
<Box sx={{ width: '100%', display: 'flex', justifyContent: 'space-between' }}>
88+
<SearchInput
89+
wrapperSx={{
90+
width: {
91+
xs: '100%',
92+
sm: '340px',
93+
},
94+
}}
95+
placeholder={searchPlaceholder}
96+
onSearchTermChange={onSearchTermChange}
97+
/>
98+
{sm && (
99+
<Button sx={{ ml: 2 }} onClick={() => handleCancelClick()}>
100+
<Typography variant="buttonM">
101+
<Trans>Cancel</Trans>
102+
</Typography>
103+
</Button>
104+
)}
105+
</Box>
106+
)}
107+
</Box>
108+
</Box>
109+
);
110+
};

src/locales/el/messages.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/locales/en/messages.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/locales/en/messages.po

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,7 @@ msgstr "Invalid amount to mint"
628628
msgid "Disconnect Wallet"
629629
msgstr "Disconnect Wallet"
630630

631+
#: src/modules/markets/MarketAssetsListContainer.tsx
631632
#: src/modules/markets/MarketAssetsListContainer.tsx
632633
msgid "assets"
633634
msgstr "assets"
@@ -1213,6 +1214,10 @@ msgstr "{0}"
12131214
msgid "Manage analytics"
12141215
msgstr "Manage analytics"
12151216

1217+
#: src/components/MarketAssetCategoryFilter.tsx
1218+
msgid "Stablecoins"
1219+
msgstr "Stablecoins"
1220+
12161221
#: src/components/transactions/UnStake/UnStakeActions.tsx
12171222
#: src/modules/umbrella/UnstakeModalActions.tsx
12181223
msgid "Unstaking {symbol}"
@@ -1224,6 +1229,10 @@ msgstr "Unstaking {symbol}"
12241229
msgid "Swapping"
12251230
msgstr "Swapping"
12261231

1232+
#: src/components/MarketAssetCategoryFilter.tsx
1233+
msgid "ETH Correlated"
1234+
msgstr "ETH Correlated"
1235+
12271236
#: src/components/transactions/CollateralChange/CollateralChangeModalContent.tsx
12281237
msgid "You can not use this currency as collateral"
12291238
msgstr "You can not use this currency as collateral"
@@ -1463,6 +1472,10 @@ msgstr "Invalid return value of the flashloan executor function"
14631472
msgid "Learn more about the Kernel points distribution"
14641473
msgstr "Learn more about the Kernel points distribution"
14651474

1475+
#: src/components/MarketAssetCategoryFilter.tsx
1476+
msgid "All"
1477+
msgstr "All"
1478+
14661479
#: src/components/isolationMode/IsolatedBadge.tsx
14671480
msgid "Asset can be only used as collateral in isolation mode with limited borrowing power. To enter isolation mode, disable all other collateral."
14681481
msgstr "Asset can be only used as collateral in isolation mode with limited borrowing power. To enter isolation mode, disable all other collateral."
@@ -2340,6 +2353,7 @@ msgstr "You did not participate in this proposal"
23402353
msgid "Governance"
23412354
msgstr "Governance"
23422355

2356+
#: src/components/TitleWithFiltersAndSearchBar.tsx
23432357
#: src/components/TitleWithSearchBar.tsx
23442358
#: src/modules/history/HistoryWrapperMobile.tsx
23452359
msgid "Cancel"

src/locales/es/messages.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/locales/fr/messages.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/modules/markets/MarketAssetsListContainer.tsx

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import { Trans } from '@lingui/macro';
33
import { Box, Switch, Typography, useMediaQuery, useTheme } from '@mui/material';
44
import { useState } from 'react';
55
import { ListWrapper } from 'src/components/lists/ListWrapper';
6+
import { MarketAssetCategoryFilter } from 'src/components/MarketAssetCategoryFilter';
67
import { NoSearchResults } from 'src/components/NoSearchResults';
78
import { Link } from 'src/components/primitives/Link';
89
import { Warning } from 'src/components/primitives/Warning';
10+
import { TitleWithFiltersAndSearchBar } from 'src/components/TitleWithFiltersAndSearchBar';
911
import { TitleWithSearchBar } from 'src/components/TitleWithSearchBar';
1012
import { useAppDataContext } from 'src/hooks/app-data-provider/useAppDataProvider';
1113
import MarketAssetsList from 'src/modules/markets/MarketAssetsList';
@@ -16,6 +18,7 @@ import { useShallow } from 'zustand/shallow';
1618

1719
import { GENERAL } from '../../utils/events';
1820
import { SavingsGhoBanner } from './Gho/GhoBanner';
21+
import { AssetCategory, isAssetInCategory } from './utils/assetCategories';
1922

2023
function shouldDisplayGhoBanner(marketTitle: string, searchTerm: string): boolean {
2124
// GHO banner is only displayed on markets where new GHO is mintable (i.e. Ethereum)
@@ -45,6 +48,7 @@ export const MarketAssetsListContainer = () => {
4548
])
4649
);
4750
const [searchTerm, setSearchTerm] = useState('');
51+
const [selectedCategory, setSelectedCategory] = useState<AssetCategory>(AssetCategory.ALL);
4852
const { breakpoints } = useTheme();
4953
const sm = useMediaQuery(breakpoints.down('sm'));
5054

@@ -63,6 +67,8 @@ export const MarketAssetsListContainer = () => {
6367
res.underlyingAsset.toLowerCase().includes(term)
6468
);
6569
})
70+
// Filter by category
71+
.filter((res) => isAssetInCategory(res.symbol, selectedCategory))
6672
// Transform the object for list to consume it
6773
.map((reserve) => ({
6874
...reserve,
@@ -88,15 +94,45 @@ export const MarketAssetsListContainer = () => {
8894
return (
8995
<ListWrapper
9096
titleComponent={
91-
<TitleWithSearchBar
92-
onSearchTermChange={setSearchTerm}
93-
title={
94-
<>
95-
{currentMarketData.marketTitle} <Trans>assets</Trans>
96-
</>
97-
}
98-
searchPlaceholder={sm ? 'Search asset' : 'Search asset name, symbol, or address'}
99-
/>
97+
sm ? (
98+
<Box sx={{ width: '100%' }}>
99+
<TitleWithSearchBar
100+
onSearchTermChange={setSearchTerm}
101+
title={
102+
<>
103+
{currentMarketData.marketTitle} <Trans>assets</Trans>
104+
</>
105+
}
106+
searchPlaceholder={sm ? 'Search asset' : 'Search asset name, symbol, or address'}
107+
/>
108+
109+
<Box
110+
sx={{
111+
display: 'flex',
112+
justifyContent: 'center',
113+
width: '100%',
114+
pt: 1,
115+
}}
116+
>
117+
<MarketAssetCategoryFilter
118+
selectedCategory={selectedCategory}
119+
onCategoryChange={setSelectedCategory}
120+
/>
121+
</Box>
122+
</Box>
123+
) : (
124+
<TitleWithFiltersAndSearchBar
125+
onSearchTermChange={setSearchTerm}
126+
title={
127+
<>
128+
{currentMarketData.marketTitle} <Trans>assets</Trans>
129+
</>
130+
}
131+
searchPlaceholder={sm ? 'Search asset' : 'Search asset name, symbol, or address'}
132+
selectedCategory={selectedCategory}
133+
onCategoryChange={setSelectedCategory}
134+
/>
135+
)
100136
}
101137
>
102138
{displayGhoBanner && (
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
export enum AssetCategory {
2+
ALL = 'all',
3+
STABLECOINS = 'stablecoins',
4+
ETH_CORRELATED = 'eth_correlated',
5+
}
6+
7+
export const STABLECOINS_SYMBOLS = [
8+
//proto_mainnet_v3
9+
'USDT',
10+
'USDC',
11+
'PT SUSDE SEPTEMBER',
12+
'PT USDE SEPTEMBER 25TH 2025',
13+
'USDE',
14+
'RLUSD',
15+
'GHO',
16+
'DAI',
17+
'USDtb',
18+
'PT EUSDE AUGUST',
19+
'USDS',
20+
'PYUSD',
21+
'LUSD',
22+
'EUSDE',
23+
'FRAX',
24+
'crvUSD',
25+
'PT SUSDE JULY',
26+
'PT EUSDE MAY',
27+
'PT USDE JULY',
28+
];
29+
export const ETH_CORRELATED_SYMBOLS = [
30+
//proto_mainnet_v3
31+
'ETH',
32+
'WEETH',
33+
'WSTETH',
34+
'RSETH',
35+
'OSETH',
36+
'RETH',
37+
'ETHX',
38+
'CBETH',
39+
];
40+
export const categorizeAsset = (symbol: string): AssetCategory[] => {
41+
const categories: AssetCategory[] = [AssetCategory.ALL];
42+
43+
const normalizedSymbol = symbol.toUpperCase();
44+
if (STABLECOINS_SYMBOLS.includes(normalizedSymbol)) {
45+
categories.push(AssetCategory.STABLECOINS);
46+
}
47+
48+
if (ETH_CORRELATED_SYMBOLS.includes(normalizedSymbol)) {
49+
categories.push(AssetCategory.ETH_CORRELATED);
50+
}
51+
52+
return categories;
53+
};
54+
55+
export const isAssetInCategory = (symbol: string, category: AssetCategory): boolean => {
56+
if (category === AssetCategory.ALL) {
57+
return true;
58+
}
59+
return categorizeAsset(symbol).includes(category);
60+
};

0 commit comments

Comments
 (0)