From 67e2265ce72d8375f5ab5b67524cace62b883e5b Mon Sep 17 00:00:00 2001 From: Douglas Daniel Date: Mon, 28 Mar 2022 12:03:08 -0600 Subject: [PATCH] feat(wallet): Multichain Portfolio Network Filter --- .../browser/brave_wallet_constants.h | 5 +- .../common/actions/wallet_actions.ts | 1 + .../brave_wallet_ui/common/async/handlers.ts | 6 + .../brave_wallet_ui/common/async/lib.ts | 30 ++-- .../common/reducers/wallet_reducer.ts | 16 +- .../components/desktop/index.ts | 4 +- .../desktop/network-filter-selector/index.tsx | 132 ++++++++++++++ .../network-filter-item.tsx | 79 +++++++++ .../desktop/network-filter-selector/style.ts | 162 ++++++++++++++++++ .../desktop/portfolio-asset-item/index.tsx | 5 +- .../desktop/portfolio-asset-item/style.ts | 8 + .../components/token-lists/index.tsx | 11 +- .../desktop/views/portfolio/index.tsx | 28 +-- .../desktop/views/portfolio/style.ts | 8 + .../shared/create-network-icon/index.tsx | 4 +- .../shared/create-network-icon/style.ts | 10 +- .../components/shared/search-bar/style.ts | 4 +- components/brave_wallet_ui/constants/types.ts | 3 +- .../options/network-filter-options.ts | 21 +++ components/brave_wallet_ui/page/container.tsx | 27 ++- components/brave_wallet_ui/stories/locale.ts | 6 +- .../stories/mock-data/mock-wallet-state.ts | 4 +- components/resources/wallet_strings.grdp | 2 + 23 files changed, 519 insertions(+), 57 deletions(-) create mode 100644 components/brave_wallet_ui/components/desktop/network-filter-selector/index.tsx create mode 100644 components/brave_wallet_ui/components/desktop/network-filter-selector/network-filter-item.tsx create mode 100644 components/brave_wallet_ui/components/desktop/network-filter-selector/style.ts create mode 100644 components/brave_wallet_ui/options/network-filter-options.ts diff --git a/components/brave_wallet/browser/brave_wallet_constants.h b/components/brave_wallet/browser/brave_wallet_constants.h index 8c1c30b7b17e..57b08f6d10ac 100644 --- a/components/brave_wallet/browser/brave_wallet_constants.h +++ b/components/brave_wallet/browser/brave_wallet_constants.h @@ -626,7 +626,10 @@ constexpr webui::LocalizedString kLocalizedStrings[] = { IDS_BRAVE_WALLET_SWEEPSTAKES_DESCRIPTION}, {"braveWalletSweepstakesCallToAction", IDS_BRAVE_WALLET_SWEEPSTAKES_CALL_TO_ACTION}, - {"braveWalletNotValidFilAddress", IDS_BRAVE_WALLET_NOT_VALID_FIL_ADDRESS}}; + {"braveWalletNotValidFilAddress", IDS_BRAVE_WALLET_NOT_VALID_FIL_ADDRESS}, + {"braveWalletNetworkFilterAll", IDS_BRAVE_WALLET_NETWORK_FILTER_ALL}, + {"braveWalletNetworkFilterSecondary", + IDS_BRAVE_WALLET_NETWORK_FILTER_SECONDARY}}; // Swap constants const char kRopstenSwapBaseAPIURL[] = "https://ropsten.api.0x.org/"; diff --git a/components/brave_wallet_ui/common/actions/wallet_actions.ts b/components/brave_wallet_ui/common/actions/wallet_actions.ts index 2053ad7554ad..95a0385d2ec2 100644 --- a/components/brave_wallet_ui/common/actions/wallet_actions.ts +++ b/components/brave_wallet_ui/common/actions/wallet_actions.ts @@ -117,3 +117,4 @@ export const refreshBalancesAndPriceHistory = createAction('refreshBalancesAndPr export const setTransactionProviderError = createAction('setTransactionProviderError') export const setSelectedCoin = createAction('setSelectedCoin') export const setDefaultNetworks = createAction('setDefaultNetworks') +export const setSelectedNetworkFilter = createAction('setSelectedNetworkFilter') diff --git a/components/brave_wallet_ui/common/async/handlers.ts b/components/brave_wallet_ui/common/async/handlers.ts index a9b8787461c5..bd653199f71e 100644 --- a/components/brave_wallet_ui/common/async/handlers.ts +++ b/components/brave_wallet_ui/common/async/handlers.ts @@ -590,4 +590,10 @@ handler.on(WalletActions.expandWalletNetworks.getType(), async (store) => { }) }) +handler.on(WalletActions.setSelectedNetworkFilter.getType(), async (store: Store, payload: BraveWallet.NetworkInfo) => { + const state = getWalletState(store) + const { selectedPortfolioTimeline } = state + await store.dispatch(refreshTokenPriceHistory(selectedPortfolioTimeline)) +}) + export default handler.middleware diff --git a/components/brave_wallet_ui/common/async/lib.ts b/components/brave_wallet_ui/common/async/lib.ts index 6b20ac1ed5d4..6c604c733e40 100644 --- a/components/brave_wallet_ui/common/async/lib.ts +++ b/components/brave_wallet_ui/common/async/lib.ts @@ -22,7 +22,7 @@ import { import * as WalletActions from '../actions/wallet_actions' // Utils -import { getNetworkInfo, getNetworksByCoinType } from '../../utils/network-utils' +import { getNetworkInfo, getNetworksByCoinType, getTokensCoinType } from '../../utils/network-utils' import { getTokenParam, getFlattenedAccountBalances } from '../../utils/api-utils' import Amount from '../../utils/amount' @@ -33,6 +33,7 @@ import { GetAccountsHardwareOperationResult } from '../hardware/types' import LedgerBridgeKeyring from '../hardware/ledgerjs/eth_ledger_bridge_keyring' import TrezorBridgeKeyring from '../hardware/trezor/trezor_bridge_keyring' import FilecoinLedgerKeyring from '../hardware/ledgerjs/filecoin_ledger_keyring' +import { AllNetworksOption } from '../../options/network-filter-options' export const getERC20Allowance = ( contractAddress: string, @@ -368,14 +369,25 @@ export function refreshTokenPriceHistory (selectedPortfolioTimeline: BraveWallet const apiProxy = getAPIProxy() const { assetRatioService } = apiProxy - const { wallet: { accounts, defaultCurrencies, userVisibleTokensInfo } } = getState() + const { wallet: { accounts, defaultCurrencies, userVisibleTokensInfo, selectedNetworkFilter, networkList } } = getState() + + // By default we do not fetch Price history for Test Networks Tokens if + // Selected Network Filter is all + const filteredTokenInfo = selectedNetworkFilter.chainId === AllNetworksOption.chainId + ? userVisibleTokensInfo.filter((token) => !SupportedTestNetworks.includes(token.chainId)) + // If chainId is Localhost we also do a check for coinType to only + // fetch Price History for for the correct tokens + : selectedNetworkFilter.chainId === BraveWallet.LOCALHOST_CHAIN_ID + ? userVisibleTokensInfo.filter((token) => + token.chainId === selectedNetworkFilter.chainId && + getTokensCoinType(networkList, token) === selectedNetworkFilter.coin) + // Fetch Price History for Tokens by Selected Network Filter's chainId + : userVisibleTokensInfo.filter((token) => token.chainId === selectedNetworkFilter.chainId) // Get all Price History - const priceHistory = await Promise.all(getFlattenedAccountBalances(accounts, userVisibleTokensInfo) + const priceHistory = await Promise.all(getFlattenedAccountBalances(accounts, filteredTokenInfo) // If a tokens balance is 0 we do not make an unnecessary api call for price history of that token - // Will remove testnetwork filter when this is implemented - // https://github.com/brave/brave-browser/issues/20780 - .filter(({ token, balance }) => !token.isErc721 && balance > 0 && !SupportedTestNetworks.includes(token.chainId)) + .filter(({ token, balance }) => !token.isErc721 && balance > 0) .map(async ({ token }) => ({ // If a visible asset has a contractAddress of '' // it is a native asset so we use a symbol instead. @@ -388,10 +400,8 @@ export function refreshTokenPriceHistory (selectedPortfolioTimeline: BraveWallet // Combine Price History and Balances const priceHistoryWithBalances = accounts.map((account) => { - return userVisibleTokensInfo - // Will remove testnetwork filter when this is implemented - // https://github.com/brave/brave-browser/issues/20780 - .filter((token) => !token.isErc721 && !SupportedTestNetworks.includes(token.chainId)) + return filteredTokenInfo + .filter((token) => !token.isErc721) .map((token) => { const balance = token.contractAddress ? account.tokenBalanceRegistry[token.contractAddress.toLowerCase()] diff --git a/components/brave_wallet_ui/common/reducers/wallet_reducer.ts b/components/brave_wallet_ui/common/reducers/wallet_reducer.ts index 9b552eaffb96..99da398d9bec 100644 --- a/components/brave_wallet_ui/common/reducers/wallet_reducer.ts +++ b/components/brave_wallet_ui/common/reducers/wallet_reducer.ts @@ -34,6 +34,7 @@ import * as WalletActions from '../actions/wallet_actions' import { mojoTimeDeltaToJSDate } from '../../../common/mojomUtils' import { sortTransactionByDate } from '../../utils/tx-utils' import Amount from '../../utils/amount' +import { AllNetworksOption } from '../../options/network-filter-options' const defaultState: WalletState = { hasInitialized: false, @@ -86,7 +87,8 @@ const defaultState: WalletState = { crypto: '' }, transactionProviderErrorRegistry: {}, - defaultNetworks: [] as BraveWallet.NetworkInfo[] + defaultNetworks: [] as BraveWallet.NetworkInfo[], + selectedNetworkFilter: AllNetworksOption } const getAccountType = (info: AccountInfo) => { @@ -309,8 +311,8 @@ export const createWalletReducer = (initialState: WalletState) => { reducer.on(WalletActions.transactionStatusChanged, (state: WalletState, payload: TransactionStatusChanged): WalletState => { const newPendingTransactions = state.pendingTransactions - .filter((tx: BraveWallet.TransactionInfo) => tx.id !== payload.txInfo.id) - .concat(payload.txInfo.txStatus === BraveWallet.TransactionStatus.Unapproved ? [payload.txInfo] : []) + .filter((tx: BraveWallet.TransactionInfo) => tx.id !== payload.txInfo.id) + .concat(payload.txInfo.txStatus === BraveWallet.TransactionStatus.Unapproved ? [payload.txInfo] : []) const sortedTransactionList = sortTransactionByDate(newPendingTransactions) @@ -481,6 +483,14 @@ export const createWalletReducer = (initialState: WalletState) => { } }) + reducer.on(WalletActions.setSelectedNetworkFilter, (state: WalletState, payload: BraveWallet.NetworkInfo): WalletState => { + return { + ...state, + isFetchingPortfolioPriceHistory: true, + selectedNetworkFilter: payload + } + }) + return reducer } diff --git a/components/brave_wallet_ui/components/desktop/index.ts b/components/brave_wallet_ui/components/desktop/index.ts index 8d64515e02a2..88d4063eda3f 100644 --- a/components/brave_wallet_ui/components/desktop/index.ts +++ b/components/brave_wallet_ui/components/desktop/index.ts @@ -23,6 +23,7 @@ import SelectNetworkDropdown from './select-network-dropdown' import TransactionPopup from './transaction-popup' import SwapTooltip from './swap-tooltip' import WithHideBalancePlaceholder from './with-hide-balance-placeholder' +import NetworkFilterSelector from './network-filter-selector' import { CryptoView, PortfolioView } from './views' import { OnboardingWelcome, @@ -68,5 +69,6 @@ export { OnboardingImportMetaMaskOrLegacy, TransactionPopup, SwapTooltip, - WithHideBalancePlaceholder + WithHideBalancePlaceholder, + NetworkFilterSelector } diff --git a/components/brave_wallet_ui/components/desktop/network-filter-selector/index.tsx b/components/brave_wallet_ui/components/desktop/network-filter-selector/index.tsx new file mode 100644 index 000000000000..1a71fe4876a6 --- /dev/null +++ b/components/brave_wallet_ui/components/desktop/network-filter-selector/index.tsx @@ -0,0 +1,132 @@ +import * as React from 'react' +import { useSelector, useDispatch } from 'react-redux' + +// Types +import { BraveWallet, SupportedTestNetworks, WalletState } from '../../../constants/types' + +// Components +import NetworkFilterItem from './network-filter-item' +import { CreateNetworkIcon } from '../../shared' + +// Utils +import { reduceNetworkDisplayName } from '../../../utils/network-utils' +import { WalletActions } from '../../../common/actions' +import { getLocale } from '../../../../common/locale' +import { + AllNetworksOption, + SupportedTopLevelChainIds +} from '../../../options/network-filter-options' + +// Styled Components +import { + StyledWrapper, + DropDown, + DropDownButton, + DropDownIcon, + LeftSide, + SubDropDown, + SecondaryNetworkText, + ClickAwayArea +} from './style' + +function NetworkFilterSelector () { + const [showNetworkFilter, setShowNetworkFilter] = React.useState(false) + + // redux + const { + selectedNetworkFilter, + networkList + } = useSelector(({ wallet }: { wallet: WalletState }) => wallet) + + const dispatch = useDispatch() + + const sortedNetworks = React.useMemo(() => { + const onlyMainnets = networkList.filter((network) => SupportedTopLevelChainIds.includes(network.chainId)) + const removedMainnets = networkList.filter((network) => !SupportedTopLevelChainIds.includes(network.chainId)) + return [AllNetworksOption, ...onlyMainnets, ...removedMainnets] + }, [networkList]) + + const primaryNetworks = React.useMemo(() => { + const onlyMainnets = networkList.filter((network) => SupportedTopLevelChainIds.includes(network.chainId)) + return [AllNetworksOption, ...onlyMainnets] + }, [sortedNetworks]) + + const secondaryNetworks = React.useMemo(() => { + const primaryList = [AllNetworksOption.chainId, ...SupportedTopLevelChainIds, ...SupportedTestNetworks] + return sortedNetworks.filter((network) => !primaryList.includes(network.chainId)) + }, [sortedNetworks]) + + const toggleShowNetworkFilter = () => { + setShowNetworkFilter(!showNetworkFilter) + } + + const onSelectAndClose = (network: BraveWallet.NetworkInfo) => { + dispatch(WalletActions.setSelectedNetworkFilter(network)) + toggleShowNetworkFilter() + } + + const hideNetworkFilter = () => { + setShowNetworkFilter(false) + } + + return ( + + + + {selectedNetworkFilter.chainId !== AllNetworksOption.chainId && + + } + {selectedNetworkFilter.chainId !== AllNetworksOption.chainId ? reduceNetworkDisplayName(selectedNetworkFilter.chainName) : selectedNetworkFilter.chainName} + + + + {showNetworkFilter && + + {primaryNetworks.map((network: BraveWallet.NetworkInfo) => + + + {sortedNetworks.filter((n) => + n.coin === network.coin && + n.symbol.toLowerCase() === network.symbol.toLowerCase()) + .map((subNetwork) => + + )} + + + )} + {secondaryNetworks.length > 0 && + <> + {getLocale('braveWalletNetworkFilterSecondary')} + {secondaryNetworks.map((network) => + + )} + + } + + } + {showNetworkFilter && + + } + + ) +} + +export default NetworkFilterSelector diff --git a/components/brave_wallet_ui/components/desktop/network-filter-selector/network-filter-item.tsx b/components/brave_wallet_ui/components/desktop/network-filter-selector/network-filter-item.tsx new file mode 100644 index 000000000000..20511e78b7b3 --- /dev/null +++ b/components/brave_wallet_ui/components/desktop/network-filter-selector/network-filter-item.tsx @@ -0,0 +1,79 @@ +import * as React from 'react' + +// Types +import { BraveWallet } from '../../../constants/types' + +// Components +import { CreateNetworkIcon } from '../../shared' + +// Utils +import { reduceNetworkDisplayName } from '../../../utils/network-utils' +import { AllNetworksOption } from '../../../options/network-filter-options' + +// Styled Components +import { + NetworkItemButton, + NetworkName, + LeftSide, + NetworkItemWrapper, + BigCheckMark +} from './style' + +export interface Props { + children?: React.ReactNode + selectedNetwork: BraveWallet.NetworkInfo + network: BraveWallet.NetworkInfo + isSubItem: boolean + onSelectNetwork: (network?: BraveWallet.NetworkInfo) => void +} + +function NetworkFilterItem (props: Props) { + const { network, onSelectNetwork, children, selectedNetwork, isSubItem } = props + const [showSubMenu, setShowSubMenu] = React.useState(false) + + const showTip = () => { + if (!isSubItem) { + setShowSubMenu(true) + } + } + + const hideTip = () => { + if (!isSubItem) { + setShowSubMenu(false) + } + } + + const onClickSelectNetwork = () => { + if (!isSubItem) { + return + } + setShowSubMenu(false) + onSelectNetwork(network) + } + + return ( + + + + {network.chainId !== AllNetworksOption.chainId && + + } + {isSubItem ? network.chainName : reduceNetworkDisplayName(network.chainName)} + + {network.chainId === selectedNetwork.chainId && + network.symbol.toLowerCase() === selectedNetwork.symbol.toLowerCase() && + isSubItem && + + } + + {showSubMenu && !isSubItem && + <>{children} + } + + ) +} + +export default NetworkFilterItem diff --git a/components/brave_wallet_ui/components/desktop/network-filter-selector/style.ts b/components/brave_wallet_ui/components/desktop/network-filter-selector/style.ts new file mode 100644 index 000000000000..bcd2fdeeb15c --- /dev/null +++ b/components/brave_wallet_ui/components/desktop/network-filter-selector/style.ts @@ -0,0 +1,162 @@ +import styled from 'styled-components' +import { WalletButton } from '../../shared/style' +import { CaratStrongDownIcon } from 'brave-ui/components/icons' +import CheckMark from '../../../assets/svg-icons/big-checkmark.svg' + +export const StyledWrapper = styled.div` + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + margin-left: 14px; + position: relative; +` + +export const DropDownButton = styled(WalletButton)` + display: flex; + align-items: center; + justify-content: space-between; + flex-direction: row; + background-color: ${(p) => p.theme.color.background02}; + width: 175px; + cursor: pointer; + outline: none; + background: none; + border: ${(p) => `1px solid ${p.theme.color.interactive08}`}; + border-radius: 4px; + font-family: Poppins; + font-style: normal; + font-size: 13px; + line-height: 20px; + letter-spacing: 0.01em; + padding: 8px 12px; + margin-bottom: 8px; + color: ${(p) => p.theme.color.text01}; +` + +export const DropDownIcon = styled(CaratStrongDownIcon)` + width: 18px; + height: 18px; + color: ${(p) => p.theme.color.interactive07}; +` + +export const DropDown = styled.div` + display: flex; + flex-direction: column; + align-items: flex-start; + justify-conent: flex-start; + width: 250px; + padding: 5px; + background-color: ${(p) => p.theme.color.background02}; + border: 1px solid ${(p) => p.theme.color.divider01}; + border-radius: 8px; + box-shadow: 0px 0px 16px rgba(99, 105, 110, 0.18); + @media (prefers-color-scheme: dark) { + box-shadow: 0px 0px 16px rgba(0, 0, 0, 0.36); + } + position: absolute; + top: 38px; + z-index: 8; + @media screen and (max-width: 800px) { + right: 0px; + } + ` + +export const NetworkItemWrapper = styled.div` + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + position: relative; + width: 100%; +` + +export const NetworkItemButton = styled(WalletButton)` + display: flex; + width: 100%; + flex-direction: row; + align-items: center; + justify-content: space-between; + cursor: pointer; + outline: none; + background: none; + border: none; + margin: 0px; + padding: 8px 8px 8px 12px; + height: 40px; + box-sizing: border-box; + border-radius: 6px; + &:hover { + background-color: ${(p) => p.theme.color.divider01}; + } +` + +export const LeftSide = styled.div` + display: flex; + align-items: center; + justify-content: flex-start; + flex-direction: row; +` + +export const NetworkName = styled.span` + font-family: Poppins; + font-size: 14px; + letter-spacing: 0.01em; + font-weight: 400; + color: ${(p) => p.theme.color.text01}; + text-align: left; +` + +export const BigCheckMark = styled.div` + width: 14px; + height: 14px; + background-color: ${(p) => p.theme.color.text01}; + -webkit-mask-image: url(${CheckMark}); + mask-image: url(${CheckMark}); + margin-right: 8px; +` + +export const SubDropDown = styled.div` + display: flex; + flex-direction: column; + align-items: flex-start; + justify-conent: flex-start; + width: 250px; + max-height: 262px; + padding: 5px; + background-color: ${(p) => p.theme.color.background02}; + border: 1px solid ${(p) => p.theme.color.divider01}; + border-radius: 8px; + box-shadow: 0px 0px 16px rgba(99, 105, 110, 0.18); + @media (prefers-color-scheme: dark) { + box-shadow: 0px 0px 16px rgba(0, 0, 0, 0.36); + } + position: absolute; + top: -6px; + left: 240px; + z-index: 9; + overflow-y: scroll; + overflow-x: hidden; + @media screen and (max-width: 800px) { + left: -252px; + } + ` + +export const SecondaryNetworkText = styled.span` + font-family: Poppins; + font-size: 12px; + letter-spacing: 0.01em; + font-weight: 400; + color: ${(p) => p.theme.color.text03}; + text-align: left; + margin: 10px 0px 10px 10px; +` + +export const ClickAwayArea = styled.div` + left: 0; + right: 0; + top: 0; + bottom: 0; + position: fixed; + z-index: 7; +` diff --git a/components/brave_wallet_ui/components/desktop/portfolio-asset-item/index.tsx b/components/brave_wallet_ui/components/desktop/portfolio-asset-item/index.tsx index 08c5ef622d8c..6cbe6cc8d69d 100644 --- a/components/brave_wallet_ui/components/desktop/portfolio-asset-item/index.tsx +++ b/components/brave_wallet_ui/components/desktop/portfolio-asset-item/index.tsx @@ -19,7 +19,8 @@ import { IconsWrapper, NetworkIconWrapper, NameColumn, - Spacer + Spacer, + NetworkDescriptionText } from './style' import { withPlaceholderIcon, CreateNetworkIcon, LoadingSkeleton } from '../../shared' import { WithHideBalancePlaceholder } from '../' @@ -144,7 +145,7 @@ const PortfolioAssetItem = (props: Props) => { : '' } - {NetworkDescription} + {NetworkDescription} } diff --git a/components/brave_wallet_ui/components/desktop/portfolio-asset-item/style.ts b/components/brave_wallet_ui/components/desktop/portfolio-asset-item/style.ts index a20c951a7ca8..5ed823510cfe 100644 --- a/components/brave_wallet_ui/components/desktop/portfolio-asset-item/style.ts +++ b/components/brave_wallet_ui/components/desktop/portfolio-asset-item/style.ts @@ -98,3 +98,11 @@ export const Spacer = styled.div` display: flex; height: 4px; ` + +export const NetworkDescriptionText = styled.span` + font-family: Poppins; + font-size: 13px; + line-height: 20px; + letter-spacing: 0.01em; + color: ${(p) => p.theme.color.text03}; +` diff --git a/components/brave_wallet_ui/components/desktop/views/portfolio/components/token-lists/index.tsx b/components/brave_wallet_ui/components/desktop/views/portfolio/components/token-lists/index.tsx index e595393e1187..e762c7383a22 100644 --- a/components/brave_wallet_ui/components/desktop/views/portfolio/components/token-lists/index.tsx +++ b/components/brave_wallet_ui/components/desktop/views/portfolio/components/token-lists/index.tsx @@ -14,7 +14,8 @@ import { getLocale } from '../../../../../../../common/locale' import { SearchBar } from '../../../../../shared' import { PortfolioAssetItem, - AddButton + AddButton, + NetworkFilterSelector } from '../../../../' // Styled Components @@ -22,7 +23,8 @@ import { ButtonRow, DividerText, SubDivider, - Spacer + Spacer, + FilterTokenRow } from '../../style' export interface Props { @@ -72,7 +74,10 @@ const TokenLists = (props: Props) => { return ( <> - + + + + {filteredAssetList.filter((asset) => !asset.asset.isErc721).map((item) => { foundTokenInfoByContractAddress } = props - // This will be removed once Network Filtering is integrated here - // https://github.com/brave/brave-browser/issues/20780 - const mainnetAssets = React.useMemo(() => { - return userAssetList.filter((asset) => !SupportedTestNetworks.includes(asset.asset.chainId)) - }, [userAssetList]) - - const [filteredAssetList, setfilteredAssetList] = React.useState(mainnetAssets) + const [filteredAssetList, setfilteredAssetList] = React.useState(userAssetList) const [fullPortfolioFiatBalance, setFullPortfolioFiatBalance] = React.useState(portfolioBalance) const [hoverBalance, setHoverBalance] = React.useState() const [hoverPrice, setHoverPrice] = React.useState() - const [showNetworkDropdown, setShowNetworkDropdown] = React.useState(false) const [hideBalances, setHideBalances] = React.useState(false) const parseTransaction = useTransactionParser(selectedNetwork, accounts, transactionSpotPrices, userVisibleTokensInfo) @@ -160,8 +152,8 @@ const Portfolio = (props: Props) => { }, [portfolioBalance]) React.useEffect(() => { - setfilteredAssetList(mainnetAssets) - }, [mainnetAssets]) + setfilteredAssetList(userAssetList) + }, [userAssetList]) const portfolioHistory = React.useMemo(() => { return portfolioPriceHistory @@ -174,7 +166,7 @@ const Portfolio = (props: Props) => { const goBack = () => { onSelectAsset(undefined) - setfilteredAssetList(mainnetAssets) + setfilteredAssetList(userAssetList) toggleNav() } @@ -194,12 +186,6 @@ const Portfolio = (props: Props) => { } } - const onHideNetworkDropdown = () => { - if (showNetworkDropdown) { - setShowNetworkDropdown(false) - } - } - const toggleShowVisibleAssetModal = () => { onShowVisibleAssetsModal(!showVisibleAssetsModal) } @@ -275,7 +261,7 @@ const Portfolio = (props: Props) => { }, [selectedAsset, networkList]) return ( - + {!selectedAsset ? ( @@ -384,7 +370,7 @@ const Portfolio = (props: Props) => { {!selectedAsset && >` mask-image: url(${(p) => p.hideBalances ? EyeOffIcon : EyeOnIcon}); mask-size: cover; ` + +export const FilterTokenRow = styled.div` + display: flex; + align-items: center; + justify-content: space-between; + flex-direction: row; + width: 100%; +` diff --git a/components/brave_wallet_ui/components/shared/create-network-icon/index.tsx b/components/brave_wallet_ui/components/shared/create-network-icon/index.tsx index a5a069d43cac..cbc39509fcb4 100644 --- a/components/brave_wallet_ui/components/shared/create-network-icon/index.tsx +++ b/components/brave_wallet_ui/components/shared/create-network-icon/index.tsx @@ -16,10 +16,11 @@ import { makeNetworkAsset } from '../../../options/asset-options' interface Props { network: BraveWallet.NetworkInfo marginRight: number + size?: 'big' | 'small' } function CreateNetworkIcon (props: Props) { - const { network, marginRight } = props + const { network, marginRight, size } = props if (!network) { return null } @@ -79,6 +80,7 @@ function CreateNetworkIcon (props: Props) { isTestnet={SupportedTestNetworks.includes(network.chainId)} > >` background-size: cover; ` -export const NetworkIcon = AssetIconFactory({ - width: '15px', +interface IconProps extends AssetIconProps { + size?: 'big' | 'small' +} + +export const NetworkIcon = AssetIconFactory(props => ({ + width: props.size === 'big' ? '25px' : '15px', height: 'auto' -}) +})) diff --git a/components/brave_wallet_ui/components/shared/search-bar/style.ts b/components/brave_wallet_ui/components/shared/search-bar/style.ts index 0bd841554e7a..0b70f4b51bc3 100644 --- a/components/brave_wallet_ui/components/shared/search-bar/style.ts +++ b/components/brave_wallet_ui/components/shared/search-bar/style.ts @@ -7,10 +7,10 @@ export const StyledWrapper = styled.div` justify-content: space-between; flex-direction: row; width: 100%; - height: 32px; + height: 36px; border: ${(p) => `1px solid ${p.theme.color.interactive08}`}; box-sizing: border-box; - border-radius: 8px; + border-radius: 4px; background-color: ${(p) => p.theme.color.background02}; margin-bottom: 10px; overflow: hidden; diff --git a/components/brave_wallet_ui/constants/types.ts b/components/brave_wallet_ui/constants/types.ts index 6c13d11bea53..4ab6aae7bccb 100644 --- a/components/brave_wallet_ui/constants/types.ts +++ b/components/brave_wallet_ui/constants/types.ts @@ -219,6 +219,7 @@ export interface WalletState { defaultCurrencies: DefaultCurrencies transactionProviderErrorRegistry: TransactionProviderErrorRegistry defaultNetworks: BraveWallet.NetworkInfo[] + selectedNetworkFilter: BraveWallet.NetworkInfo } export interface PanelState { @@ -371,7 +372,7 @@ interface BaseTransactionParams { coin: BraveWallet.CoinType } -interface BaseEthTransactionParams extends BaseTransactionParams{ +interface BaseEthTransactionParams extends BaseTransactionParams { gas?: string // Legacy gas pricing diff --git a/components/brave_wallet_ui/options/network-filter-options.ts b/components/brave_wallet_ui/options/network-filter-options.ts new file mode 100644 index 000000000000..1c4f4841c0ba --- /dev/null +++ b/components/brave_wallet_ui/options/network-filter-options.ts @@ -0,0 +1,21 @@ +import { BraveWallet } from '../constants/types' +import { getLocale } from '../../common/locale' + +export const AllNetworksOption: BraveWallet.NetworkInfo = { + blockExplorerUrls: [], + chainId: 'all', + chainName: getLocale('braveWalletNetworkFilterAll'), + coin: 0, + decimals: 0, + iconUrls: [], + rpcUrls: [], + symbol: 'all', + symbolName: 'all', + data: {} as BraveWallet.NetworkInfoData +} + +export const SupportedTopLevelChainIds = [ + BraveWallet.MAINNET_CHAIN_ID, + BraveWallet.SOLANA_MAINNET, + BraveWallet.FILECOIN_MAINNET +] diff --git a/components/brave_wallet_ui/page/container.tsx b/components/brave_wallet_ui/page/container.tsx index 35f26d01fc59..55c45695fcfc 100644 --- a/components/brave_wallet_ui/page/container.tsx +++ b/components/brave_wallet_ui/page/container.tsx @@ -34,6 +34,7 @@ import { import BuySendSwap from '../stories/screens/buy-send-swap' import Onboarding from '../stories/screens/onboarding' import BackupWallet from '../stories/screens/backup-wallet' +import { AllNetworksOption } from '../options/network-filter-options' // Utils import Amount from '../utils/amount' @@ -96,7 +97,8 @@ function Container (props: Props) { isMetaMaskInstalled, defaultCurrencies, fullTokenList, - userVisibleTokensInfo + userVisibleTokensInfo, + selectedNetworkFilter } = props.wallet // Page Props @@ -297,11 +299,25 @@ function Container (props: Props) { // This looks at the users asset list and returns the full balance for each asset const userAssetList = React.useMemo(() => { - return userVisibleTokensInfo.map((asset) => ({ + const allAssets = userVisibleTokensInfo.map((asset) => ({ asset: asset, assetBalance: fullAssetBalance(asset) }) as UserAssetInfoType) - }, [userVisibleTokensInfo, fullAssetBalance]) + // By default we dont show any testnetwork assets + if (selectedNetworkFilter.chainId === AllNetworksOption.chainId) { + return allAssets.filter((asset) => !SupportedTestNetworks.includes(asset.asset.chainId)) + } + // If chainId is Localhost we also do a check for coinType to return + // the correct asset + if (selectedNetworkFilter.chainId === BraveWallet.LOCALHOST_CHAIN_ID) { + return allAssets.filter((asset) => + asset.asset.chainId === selectedNetworkFilter.chainId && + getTokensCoinType(networkList, asset.asset) === selectedNetworkFilter.coin + ) + } + // Filter by all other assets by chainId's + return allAssets.filter((asset) => asset.asset.chainId === selectedNetworkFilter.chainId) + }, [userVisibleTokensInfo, selectedNetworkFilter, fullAssetBalance, networkList]) const onSelectAsset = (asset: BraveWallet.BlockchainToken) => { props.walletPageActions.selectAsset({ asset: asset, timeFrame: selectedTimeline }) @@ -309,13 +325,10 @@ function Container (props: Props) { // This will scrape all of the user's accounts and combine the fiat value for every asset const fullPortfolioBalance = React.useMemo(() => { - // Will remove testnetwork filter when this is implemented - // https://github.com/brave/brave-browser/issues/20780 const visibleAssetOptions = userAssetList .filter((token) => token.asset.visible && - !token.asset.isErc721 && - !SupportedTestNetworks.includes(token.asset.chainId) + !token.asset.isErc721 ) if (visibleAssetOptions.length === 0) { diff --git a/components/brave_wallet_ui/stories/locale.ts b/components/brave_wallet_ui/stories/locale.ts index 7ce76da8fb03..2ced767fc30b 100644 --- a/components/brave_wallet_ui/stories/locale.ts +++ b/components/brave_wallet_ui/stories/locale.ts @@ -477,5 +477,9 @@ provideStrings({ // Sweepstakes braveWalletSweepstakesTitle: 'Brave Swap-stakes', braveWalletSweepstakesDescription: '7 days of crypto giveaways, ~$500k in prizes.', - braveWalletSweepstakesCallToAction: 'Enter now!' + braveWalletSweepstakesCallToAction: 'Enter now!', + + // Network Filter + braveWalletNetworkFilterAll: 'All Networks', + braveWalletNetworkFilterSecondary: 'Secondary Networks' }) diff --git a/components/brave_wallet_ui/stories/mock-data/mock-wallet-state.ts b/components/brave_wallet_ui/stories/mock-data/mock-wallet-state.ts index be7f7eef6df1..4524fc5b1dc9 100644 --- a/components/brave_wallet_ui/stories/mock-data/mock-wallet-state.ts +++ b/components/brave_wallet_ui/stories/mock-data/mock-wallet-state.ts @@ -1,5 +1,6 @@ import { mockNetwork } from '../../common/constants/mocks' import { BraveWallet, WalletAccountType, WalletState } from '../../constants/types' +import { AllNetworksOption } from '../../options/network-filter-options' const mockAccount: WalletAccountType = { accountType: 'Primary', @@ -277,5 +278,6 @@ export const mockWalletState: WalletState = { transactionProviderErrorRegistry: {}, defaultNetworks: [mockNetwork], isTestNetworksEnabled: true, - selectedCoin: BraveWallet.CoinType.ETH + selectedCoin: BraveWallet.CoinType.ETH, + selectedNetworkFilter: AllNetworksOption } diff --git a/components/resources/wallet_strings.grdp b/components/resources/wallet_strings.grdp index c7627db56f1e..f7c738abc66a 100644 --- a/components/resources/wallet_strings.grdp +++ b/components/resources/wallet_strings.grdp @@ -437,4 +437,6 @@ Enter now! Not a valid FIL address + All Networks + Secondary Networks