From da7a49d8568c9a657e05f4e29ba68ba502c8f00a Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Thu, 5 Sep 2024 12:23:15 -0700 Subject: [PATCH 001/151] Convert js files to ts --- .../{asset-list.js => asset-list.tsx} | 50 +++++--- .../assets/asset-list/{index.js => index.ts} | 0 .../__snapshots__/token-cell.test.js.snap | 12 +- .../{token-cell.js => token-cell.tsx} | 30 +++-- .../assets/token-list/{index.js => index.ts} | 0 .../{token-list.js => token-list.tsx} | 20 +-- ...token-list-item.js => token-list-item.tsx} | 114 +++++++----------- 7 files changed, 110 insertions(+), 116 deletions(-) rename ui/components/app/assets/asset-list/{asset-list.js => asset-list.tsx} (89%) rename ui/components/app/assets/asset-list/{index.js => index.ts} (100%) rename ui/components/app/assets/token-cell/{token-cell.js => token-cell.tsx} (80%) rename ui/components/app/assets/token-list/{index.js => index.ts} (100%) rename ui/components/app/assets/token-list/{token-list.js => token-list.tsx} (73%) rename ui/components/multichain/token-list-item/{token-list-item.js => token-list-item.tsx} (85%) diff --git a/ui/components/app/assets/asset-list/asset-list.js b/ui/components/app/assets/asset-list/asset-list.tsx similarity index 89% rename from ui/components/app/assets/asset-list/asset-list.js rename to ui/components/app/assets/asset-list/asset-list.tsx index 81c70d433dc9..f1631f71f1e4 100644 --- a/ui/components/app/assets/asset-list/asset-list.js +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -1,5 +1,4 @@ import React, { useContext, useState } from 'react'; -import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import TokenList from '../token-list'; import { PRIMARY, SECONDARY } from '../../../../helpers/constants/common'; @@ -49,9 +48,22 @@ import { RampsCard, } from '../../../multichain/ramps-card/ramps-card'; import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; +import { zeroAddress } from 'ethereumjs-util'; ///: END:ONLY_INCLUDE_IF -const AssetList = ({ onClickAsset, showTokensLinks }) => { +export type TokenWithBalance = { + address: string; + symbol: string; + string: string; + image: string; +}; + +interface AssetListProps { + onClickAsset: (arg: string) => void; + showTokensLinks: boolean; +} + +const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const [showDetectedTokens, setShowDetectedTokens] = useState(false); const nativeCurrency = useSelector(getMultichainNativeCurrency); const showFiat = useSelector(getMultichainShouldShowFiat); @@ -101,13 +113,22 @@ const AssetList = ({ onClickAsset, showTokensLinks }) => { getIstokenDetectionInactiveOnNonMainnetSupportedNetwork, ); - const { tokensWithBalances, loading } = useAccountTotalFiatBalance( + const accountTotalFiatBalance = useAccountTotalFiatBalance( selectedAccount, shouldHideZeroBalanceTokens, ); + + const tokensWithBalances = + accountTotalFiatBalance.tokensWithBalances as TokenWithBalance[]; + + const loading = accountTotalFiatBalance.loading; + tokensWithBalances.forEach((token) => { // token.string is the balance displayed in the TokenList UI - token.string = roundToDecimalPlacesRemovingExtraZeroes(token.string, 5); + token.string = roundToDecimalPlacesRemovingExtraZeroes( + token.string, + 5, + ) as string; }); const balanceIsZero = useSelector( @@ -138,6 +159,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }) => { {detectedTokens.length > 0 && !isTokenDetectionInactiveOnNonMainnetSupportedNetwork && ( setShowDetectedTokens(true)} margin={4} /> @@ -156,6 +178,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }) => { ///: END:ONLY_INCLUDE_IF } onClickAsset(nativeCurrency)} title={nativeCurrency} // The primary and secondary currencies are subject to change based on the user's settings @@ -166,12 +189,12 @@ const AssetList = ({ onClickAsset, showTokensLinks }) => { useNativeCurrencyAsPrimaryCurrency, ) ? secondaryCurrencyDisplay - : undefined + : '' } tokenSymbol={ useNativeCurrencyAsPrimaryCurrency - ? primaryCurrencyProperties.suffix - : secondaryCurrencyProperties.suffix + ? primaryCurrencyProperties.suffix || '' + : secondaryCurrencyProperties.suffix || '' } secondary={ showFiat && @@ -180,7 +203,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }) => { useNativeCurrencyAsPrimaryCurrency, ) ? primaryCurrencyDisplay - : undefined + : '' } tokenImage={balanceIsLoading ? null : primaryTokenImage} isOriginalTokenSymbol={isOriginalNativeSymbol} @@ -189,9 +212,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }) => { showPercentage /> { + onTokenClick={(tokenAddress: string) => { onClickAsset(tokenAddress); trackEvent({ event: MetaMetricsEventName.TokenScreenOpened, @@ -202,6 +223,8 @@ const AssetList = ({ onClickAsset, showTokensLinks }) => { }, }); }} + tokens={tokensWithBalances} + loading={loading} /> {shouldShowTokensLinks && ( { ); }; -AssetList.propTypes = { - onClickAsset: PropTypes.func.isRequired, - showTokensLinks: PropTypes.bool, -}; - export default AssetList; diff --git a/ui/components/app/assets/asset-list/index.js b/ui/components/app/assets/asset-list/index.ts similarity index 100% rename from ui/components/app/assets/asset-list/index.js rename to ui/components/app/assets/asset-list/index.ts diff --git a/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.js.snap b/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.js.snap index e40a15f69863..1726dd7ff47c 100644 --- a/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.js.snap +++ b/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.js.snap @@ -48,14 +48,12 @@ exports[`Token Cell should match snapshot 1`] = ` > TEST -
-

-

+ TEST +

void; +} + +export default function TokenCell({ + address, + image, + symbol, + string, + onClick, +}: TokenCellProps) { const tokenList = useSelector(getTokenList); const tokenData = Object.values(tokenList).find( (token) => @@ -17,11 +30,11 @@ export default function TokenCell({ address, image, symbol, string, onClick }) { ); const title = tokenData?.name || symbol; const tokenImage = tokenData?.iconUrl || image; - const formattedFiat = useTokenFiatAmount(address, string, symbol); + const formattedFiat = useTokenFiatAmount(address, string, symbol, {}, false); const locale = useSelector(getIntlLocale); const primary = new Intl.NumberFormat(locale, { minimumSignificantDigits: 1, - }).format(string.toString()); + }).format(parseInt(string, 10)); const isOriginalTokenSymbol = useIsOriginalTokenSymbol(address, symbol); @@ -35,15 +48,6 @@ export default function TokenCell({ address, image, symbol, string, onClick }) { title={title} isOriginalTokenSymbol={isOriginalTokenSymbol} address={address} - showPercentage /> ); } - -TokenCell.propTypes = { - address: PropTypes.string, - symbol: PropTypes.string, - string: PropTypes.string, - onClick: PropTypes.func, - image: PropTypes.string, -}; diff --git a/ui/components/app/assets/token-list/index.js b/ui/components/app/assets/token-list/index.ts similarity index 100% rename from ui/components/app/assets/token-list/index.js rename to ui/components/app/assets/token-list/index.ts diff --git a/ui/components/app/assets/token-list/token-list.js b/ui/components/app/assets/token-list/token-list.tsx similarity index 73% rename from ui/components/app/assets/token-list/token-list.js rename to ui/components/app/assets/token-list/token-list.tsx index 4dd8f57412db..477c4a5aab00 100644 --- a/ui/components/app/assets/token-list/token-list.js +++ b/ui/components/app/assets/token-list/token-list.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; import TokenCell from '../token-cell'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import { Box } from '../../../component-library'; @@ -8,8 +7,19 @@ import { Display, JustifyContent, } from '../../../../helpers/constants/design-system'; +import { TokenWithBalance } from '../asset-list/asset-list'; -export default function TokenList({ onTokenClick, tokens, loading = false }) { +interface TokenListProps { + onTokenClick: (arg: string) => void; + tokens: TokenWithBalance[]; + loading: boolean; +} + +export default function TokenList({ + onTokenClick, + tokens, + loading = false, +}: TokenListProps) { const t = useI18nContext(); if (loading) { @@ -34,9 +44,3 @@ export default function TokenList({ onTokenClick, tokens, loading = false }) {
); } - -TokenList.propTypes = { - onTokenClick: PropTypes.func.isRequired, - tokens: PropTypes.array.isRequired, - loading: PropTypes.bool, -}; diff --git a/ui/components/multichain/token-list-item/token-list-item.js b/ui/components/multichain/token-list-item/token-list-item.tsx similarity index 85% rename from ui/components/multichain/token-list-item/token-list-item.js rename to ui/components/multichain/token-list-item/token-list-item.tsx index f28a53bcd075..809df38da523 100644 --- a/ui/components/multichain/token-list-item/token-list-item.js +++ b/ui/components/multichain/token-list-item/token-list-item.tsx @@ -1,5 +1,4 @@ import React, { useContext, useState } from 'react'; -import PropTypes from 'prop-types'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; import classnames from 'classnames'; @@ -24,6 +23,7 @@ import { BadgeWrapper, Box, ButtonIcon, + ButtonIconSize, ButtonSecondary, Icon, IconName, @@ -63,8 +63,24 @@ import { getProviderConfig } from '../../../ducks/metamask/metamask'; import { getPortfolioUrl } from '../../../helpers/utils/portfolio'; import { PercentageChange } from './price/percentage-change/percentage-change'; +interface TokenListItemProps { + className?: string; + onClick?: (arg?: string) => void; + tokenSymbol: string; + tokenImage: string; + primary: string; + secondary?: string | null; + title: string; + tooltipText?: string; + isOriginalTokenSymbol?: boolean | null; + isNativeCurrency?: boolean; + isStakeable?: boolean; + address?: string | null; + showPercentage?: boolean; +} + export const TokenListItem = ({ - className, + className = '', onClick, tokenSymbol, tokenImage, @@ -77,7 +93,7 @@ export const TokenListItem = ({ isStakeable = false, address = null, showPercentage = false, -}) => { +}: TokenListItemProps) => { const t = useI18nContext(); const isEvm = useSelector(getMultichainIsEvm); const trackEvent = useContext(MetaMetricsContext); @@ -114,8 +130,9 @@ export const TokenListItem = ({ const tokensMarketData = useSelector(getTokensMarketData); - const tokenPercentageChange = - tokensMarketData?.[address]?.pricePercentChange1d; + const tokenPercentageChange = address + ? tokensMarketData?.[address]?.pricePercentChange1d + : null; const tokenTitle = getTokenTitle(); const tokenMainTitleToDisplay = showPercentage ? tokenTitle : tokenSymbol; @@ -129,8 +146,8 @@ export const TokenListItem = ({ paddingInline={0} paddingInlineStart={1} paddingInlineEnd={1} - tabIndex="0" - onClick={(e) => { + tabIndex={0} + onClick={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); const url = getPortfolioUrl( @@ -199,7 +216,7 @@ export const TokenListItem = ({ {...(onClick && { as: 'a', href: '#', - onClick: (e) => { + onClick: (e: React.MouseEvent) => { e.preventDefault(); if (showScamWarningModal) { @@ -224,7 +241,7 @@ export const TokenListItem = ({ badge={ )} @@ -321,15 +342,18 @@ export const TokenListItem = ({ > { + onClick={( + e: React.MouseEvent, + ) => { e.preventDefault(); e.stopPropagation(); setShowScamWarningModal(true); }} color={IconColor.errorDefault} - size={IconSize.Md} + size={ButtonIconSize.Md} backgroundColor={BackgroundColor.transparent} data-testid="scam-warning" + ariaLabel={''} /> {isEvm && showScamWarningModal ? ( - + setShowScamWarningModal(false)}> - setShowScamWarningModal(false)}> - {t('nativeTokenScamWarningTitle')} - + {t('nativeTokenScamWarningTitle')} {t('nativeTokenScamWarningDescription', [tokenSymbol])} @@ -396,7 +418,10 @@ export const TokenListItem = ({ if (isFullScreen) { history.push(NETWORKS_ROUTE); } else { - global.platform.openExtensionInBrowser(NETWORKS_ROUTE); + global.platform && + typeof global.platform.openExtensionInBrowser === + 'function' && + global.platform.openExtensionInBrowser(NETWORKS_ROUTE); } }} block @@ -410,58 +435,3 @@ export const TokenListItem = ({ ); }; - -TokenListItem.propTypes = { - /** - * An additional className to apply to the TokenList. - */ - className: PropTypes.string, - /** - * The onClick handler to be passed to the TokenListItem component - */ - onClick: PropTypes.func, - /** - * tokenSymbol represents the symbol of the Token - */ - tokenSymbol: PropTypes.string, - /** - * title represents the name of the token and if name is not available then Symbol - */ - title: PropTypes.string, - /** - * tooltipText represents the text to show in the tooltip when hovering over the token - */ - tooltipText: PropTypes.string, - /** - * tokenImage represents the image of the token icon - */ - tokenImage: PropTypes.string, - /** - * primary represents the balance - */ - primary: PropTypes.string, - /** - * secondary represents the balance in dollars - */ - secondary: PropTypes.string, - /** - * isOriginalTokenSymbol represents a boolean value to check if the token symbol is original or not - */ - isOriginalTokenSymbol: PropTypes.bool, - /** - * isNativeCurrency represents if this item is the native currency - */ - isNativeCurrency: PropTypes.bool, - /** - * isStakeable represents if this item is stakeable - */ - isStakeable: PropTypes.bool, - /** - * address represents the token address - */ - address: PropTypes.string, - /** - * showPercentage represents if the increase decrease percentage will be hidden - */ - showPercentage: PropTypes.bool, -}; From ede7e0058d4018f90e6aa7510c25fefd8c9b3645 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Thu, 5 Sep 2024 13:45:57 -0700 Subject: [PATCH 002/151] Update to non-deprecated modal --- .../token-list-item/token-list-item.tsx | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/ui/components/multichain/token-list-item/token-list-item.tsx b/ui/components/multichain/token-list-item/token-list-item.tsx index 809df38da523..d4212e6ba0e2 100644 --- a/ui/components/multichain/token-list-item/token-list-item.tsx +++ b/ui/components/multichain/token-list-item/token-list-item.tsx @@ -29,11 +29,13 @@ import { IconName, IconSize, Modal, + ModalBody, + ModalContent, + ModalFooter, + ModalHeader, ModalOverlay, Text, } from '../../component-library'; -import { ModalContent } from '../../component-library/modal-content/deprecated'; -import { ModalHeader } from '../../component-library/modal-header/deprecated'; import { getMetaMetricsId, getTestNetworkBackgroundColor, @@ -406,10 +408,12 @@ export const TokenListItem = ({ {t('nativeTokenScamWarningTitle')} - - {t('nativeTokenScamWarningDescription', [tokenSymbol])} - - + + + {t('nativeTokenScamWarningDescription', [tokenSymbol])} + + + { dispatch( @@ -428,7 +432,7 @@ export const TokenListItem = ({ > {t('nativeTokenScamWarningConversion')} - + ) : null} From 7d8aee9d1c9039ecd682e82767fcc50324c4510b Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Thu, 5 Sep 2024 14:02:27 -0700 Subject: [PATCH 003/151] Update snapshots --- .../app/assets/asset-list/asset-list.tsx | 14 +++++------ .../token-list-item/token-list-item.tsx | 4 ++-- .../__snapshots__/asset-page.test.tsx.snap | 24 ++++++++----------- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index f1631f71f1e4..9d9f258519bd 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -48,7 +48,6 @@ import { RampsCard, } from '../../../multichain/ramps-card/ramps-card'; import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; -import { zeroAddress } from 'ethereumjs-util'; ///: END:ONLY_INCLUDE_IF export type TokenWithBalance = { @@ -178,7 +177,6 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { ///: END:ONLY_INCLUDE_IF } onClickAsset(nativeCurrency)} title={nativeCurrency} // The primary and secondary currencies are subject to change based on the user's settings @@ -189,12 +187,12 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { useNativeCurrencyAsPrimaryCurrency, ) ? secondaryCurrencyDisplay - : '' + : undefined } tokenSymbol={ useNativeCurrencyAsPrimaryCurrency - ? primaryCurrencyProperties.suffix || '' - : secondaryCurrencyProperties.suffix || '' + ? primaryCurrencyProperties.suffix + : secondaryCurrencyProperties.suffix } secondary={ showFiat && @@ -203,7 +201,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { useNativeCurrencyAsPrimaryCurrency, ) ? primaryCurrencyDisplay - : '' + : undefined } tokenImage={balanceIsLoading ? null : primaryTokenImage} isOriginalTokenSymbol={isOriginalNativeSymbol} @@ -212,6 +210,8 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { showPercentage /> { onClickAsset(tokenAddress); trackEvent({ @@ -223,8 +223,6 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { }, }); }} - tokens={tokensWithBalances} - loading={loading} /> {shouldShowTokensLinks && ( void; - tokenSymbol: string; + tokenSymbol?: string; tokenImage: string; - primary: string; + primary?: string; secondary?: string | null; title: string; tooltipText?: string; diff --git a/ui/pages/asset/components/__snapshots__/asset-page.test.tsx.snap b/ui/pages/asset/components/__snapshots__/asset-page.test.tsx.snap index 6bdd3d16c128..d7676f405ee3 100644 --- a/ui/pages/asset/components/__snapshots__/asset-page.test.tsx.snap +++ b/ui/pages/asset/components/__snapshots__/asset-page.test.tsx.snap @@ -498,14 +498,12 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` > TEST -
-

-

+ TEST +

TEST -
-

-

+ TEST +

Date: Thu, 5 Sep 2024 14:30:20 -0700 Subject: [PATCH 004/151] Use types instead of interfaces --- ui/components/app/assets/asset-list/asset-list.tsx | 4 ++-- ui/components/app/assets/token-cell/token-cell.tsx | 4 ++-- ui/components/app/assets/token-list/token-list.tsx | 4 ++-- ui/components/multichain/token-list-item/token-list-item.tsx | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index 9d9f258519bd..7ec3e24ef790 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -57,10 +57,10 @@ export type TokenWithBalance = { image: string; }; -interface AssetListProps { +type AssetListProps = { onClickAsset: (arg: string) => void; showTokensLinks: boolean; -} +}; const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const [showDetectedTokens, setShowDetectedTokens] = useState(false); diff --git a/ui/components/app/assets/token-cell/token-cell.tsx b/ui/components/app/assets/token-cell/token-cell.tsx index 30c0bf3135fb..6644d6d5b706 100644 --- a/ui/components/app/assets/token-cell/token-cell.tsx +++ b/ui/components/app/assets/token-cell/token-cell.tsx @@ -7,13 +7,13 @@ import { isEqualCaseInsensitive } from '../../../../../shared/modules/string-uti import { useIsOriginalTokenSymbol } from '../../../../hooks/useIsOriginalTokenSymbol'; import { getIntlLocale } from '../../../../ducks/locale/locale'; -interface TokenCellProps { +type TokenCellProps = { address: string; symbol: string; string: string; image: string; onClick?: (arg: string) => void; -} +}; export default function TokenCell({ address, diff --git a/ui/components/app/assets/token-list/token-list.tsx b/ui/components/app/assets/token-list/token-list.tsx index 477c4a5aab00..194ea2762191 100644 --- a/ui/components/app/assets/token-list/token-list.tsx +++ b/ui/components/app/assets/token-list/token-list.tsx @@ -9,11 +9,11 @@ import { } from '../../../../helpers/constants/design-system'; import { TokenWithBalance } from '../asset-list/asset-list'; -interface TokenListProps { +type TokenListProps = { onTokenClick: (arg: string) => void; tokens: TokenWithBalance[]; loading: boolean; -} +}; export default function TokenList({ onTokenClick, diff --git a/ui/components/multichain/token-list-item/token-list-item.tsx b/ui/components/multichain/token-list-item/token-list-item.tsx index 14ed383e0feb..a0aa1406abfa 100644 --- a/ui/components/multichain/token-list-item/token-list-item.tsx +++ b/ui/components/multichain/token-list-item/token-list-item.tsx @@ -65,7 +65,7 @@ import { getProviderConfig } from '../../../ducks/metamask/metamask'; import { getPortfolioUrl } from '../../../helpers/utils/portfolio'; import { PercentageChange } from './price/percentage-change/percentage-change'; -interface TokenListItemProps { +type TokenListItemProps = { className?: string; onClick?: (arg?: string) => void; tokenSymbol?: string; @@ -79,7 +79,7 @@ interface TokenListItemProps { isStakeable?: boolean; address?: string | null; showPercentage?: boolean; -} +}; export const TokenListItem = ({ className = '', From b787923e543001af1bdd92e161e0e353fc744cb7 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Thu, 5 Sep 2024 14:45:34 -0700 Subject: [PATCH 005/151] Prefer object destructuring --- ui/components/app/assets/asset-list/asset-list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index 7ec3e24ef790..583ece78eb91 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -120,7 +120,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const tokensWithBalances = accountTotalFiatBalance.tokensWithBalances as TokenWithBalance[]; - const loading = accountTotalFiatBalance.loading; + const { loading } = accountTotalFiatBalance; tokensWithBalances.forEach((token) => { // token.string is the balance displayed in the TokenList UI From 2e688f2c1df0d1123285bd4f4671e8c8bac81745 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Thu, 5 Sep 2024 16:56:12 -0700 Subject: [PATCH 006/151] Init sortAssets logic --- .../app/assets/asset-list/asset-list.tsx | 2 + ui/components/app/assets/util/sort.test.ts | 79 +++++++++++++++++++ ui/components/app/assets/util/sort.ts | 41 ++++++++++ 3 files changed, 122 insertions(+) create mode 100644 ui/components/app/assets/util/sort.test.ts create mode 100644 ui/components/app/assets/util/sort.ts diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index 583ece78eb91..4380ca1f318f 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -48,6 +48,7 @@ import { RampsCard, } from '../../../multichain/ramps-card/ramps-card'; import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; +import { Button } from '../../../component-library'; ///: END:ONLY_INCLUDE_IF export type TokenWithBalance = { @@ -176,6 +177,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { ) : null ///: END:ONLY_INCLUDE_IF } + onClickAsset(nativeCurrency)} title={nativeCurrency} diff --git a/ui/components/app/assets/util/sort.test.ts b/ui/components/app/assets/util/sort.test.ts new file mode 100644 index 000000000000..0cca2389b269 --- /dev/null +++ b/ui/components/app/assets/util/sort.test.ts @@ -0,0 +1,79 @@ +// Import necessary modules (assuming your function is in 'sort.ts') +import { sortAssets } from './sort'; + +// Define the MockAsset type for the test +type MockAsset = { + name: string; + balance: number; + profile: { + lastUpdated: Date; + }; +}; + +// Test data with balance at the root of MockAsset +const mockAssets: MockAsset[] = [ + { + name: 'Asset Z', + balance: 500, + profile: { lastUpdated: new Date('2023-01-01') }, + }, + { + name: 'Asset A', + balance: 400, + profile: { lastUpdated: new Date('2023-02-01') }, + }, + { + name: 'Asset B', + balance: 400, + profile: { lastUpdated: new Date('2023-03-01') }, + }, + { + name: 'Asset Y', + balance: 600, + profile: { lastUpdated: new Date('2023-04-01') }, + }, +]; + +// Define the sorting tests +describe('sortAssets function', () => { + test('should sort by balance in descending order', () => { + const sortedByBalance = sortAssets(mockAssets, { + key: 'balance', + sortCallback: 'alphanumeric', + order: 'dsc', + }); + + // The first item should have the highest balance + expect(sortedByBalance[0].balance).toBe(600); + // The last item should have the lowest balance + expect(sortedByBalance[sortedByBalance.length - 1].balance).toBe(400); + }); + + test('should sort by lastUpdated (date) in ascending order', () => { + const sortedByDate = sortAssets(mockAssets, { + key: 'profile.lastUpdated', + sortCallback: 'date', + order: 'asc', + }); + + // The first item should have the earliest date + expect(sortedByDate[0].profile.lastUpdated).toEqual(new Date('2023-01-01')); + // The last item should have the latest date + expect(sortedByDate[sortedByDate.length - 1].profile.lastUpdated).toEqual( + new Date('2023-04-01'), + ); + }); + + test('should sort by name in alphabetical order', () => { + const sortedByName = sortAssets(mockAssets, { + key: 'name', + sortCallback: 'string', + order: 'asc', + }); + + // The first item should be Asset A (alphabetically first) + expect(sortedByName[0].name).toBe('Asset A'); + // The last item should be Asset Z (alphabetically last) + expect(sortedByName[sortedByName.length - 1].name).toBe('Asset Z'); + }); +}); diff --git a/ui/components/app/assets/util/sort.ts b/ui/components/app/assets/util/sort.ts new file mode 100644 index 000000000000..5db4120c1881 --- /dev/null +++ b/ui/components/app/assets/util/sort.ts @@ -0,0 +1,41 @@ +interface SortCriteria { + key: string; // Deeply nested keys supported: 'profile.balance' + order?: SortOrder; + sortCallback?: string; +} + +type SortOrder = 'asc' | 'dsc'; + +// All sortingCallbacks should be asc order, sortAssets function handles asc/dsc +const sortingCallbacks: { [key: string]: (a: any, b: any) => number } = { + numeric: (a: number, b: number) => a - b, + alphaNumeric: (a: string, b: string) => a.localeCompare(b), + date: (a: Date, b: Date) => a.getTime() - b.getTime(), +}; + +// Utility function to access nested properties by key path +function getNestedValue(obj: T, keyPath: string): any { + return keyPath + .split('.') + .reduce((value: any, key: string) => value[key], obj); +} + +export function sortAssets(array: T[], criteria: SortCriteria): T[] { + const { key, order = 'asc', sortCallback } = criteria; + + return array.sort((a, b) => { + const aValue = getNestedValue(a, key); + const bValue = getNestedValue(b, key); + + let comparison: number; + + if (sortCallback && sortingCallbacks[sortCallback]) { + comparison = sortingCallbacks[sortCallback](aValue, bValue); + } else { + comparison = aValue < bValue ? -1 : aValue > bValue ? 1 : 0; + } + + // modify to sort in asc or dsc order + return order === 'asc' ? comparison : -comparison; + }); +} From 159622cf60ff51b8861c11aa03abc0f7b3523c31 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Thu, 5 Sep 2024 19:43:27 -0700 Subject: [PATCH 007/151] Working --- .../app/assets/asset-list/asset-list.tsx | 40 ++---- .../assets/asset-list/sort-control/index.ts | 1 + .../asset-list/sort-control/sort-control.tsx | 116 ++++++++++++++++++ ui/components/app/assets/util/sort.ts | 3 +- 4 files changed, 130 insertions(+), 30 deletions(-) create mode 100644 ui/components/app/assets/asset-list/sort-control/index.ts create mode 100644 ui/components/app/assets/asset-list/sort-control/sort-control.tsx diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index 4380ca1f318f..834272288656 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -6,8 +6,6 @@ import { useUserPreferencedCurrency } from '../../../../hooks/useUserPreferenced import { getDetectedTokensInCurrentNetwork, getIstokenDetectionInactiveOnNonMainnetSupportedNetwork, - getShouldHideZeroBalanceTokens, - getSelectedAccount, getPreferences, } from '../../../../selectors'; import { @@ -35,20 +33,18 @@ import { TokenListItem, ImportTokenLink, } from '../../../multichain'; -import { useAccountTotalFiatBalance } from '../../../../hooks/useAccountTotalFiatBalance'; import { useIsOriginalNativeTokenSymbol } from '../../../../hooks/useIsOriginalNativeTokenSymbol'; import { showPrimaryCurrency, showSecondaryCurrency, } from '../../../../../shared/modules/currency-display.utils'; -import { roundToDecimalPlacesRemovingExtraZeroes } from '../../../../helpers/utils/util'; ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) import { RAMPS_CARD_VARIANT_TYPES, RampsCard, } from '../../../multichain/ramps-card/ramps-card'; import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; -import { Button } from '../../../component-library'; +import SortControl from './sort-control'; ///: END:ONLY_INCLUDE_IF export type TokenWithBalance = { @@ -56,6 +52,7 @@ export type TokenWithBalance = { symbol: string; string: string; image: string; + tokenFiatAmount?: string; }; type AssetListProps = { @@ -64,6 +61,8 @@ type AssetListProps = { }; const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { + const [tokenList, setTokenList] = useState([]); + const [loading, setLoading] = useState(false); const [showDetectedTokens, setShowDetectedTokens] = useState(false); const nativeCurrency = useSelector(getMultichainNativeCurrency); const showFiat = useSelector(getMultichainShouldShowFiat); @@ -81,10 +80,6 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const trackEvent = useContext(MetaMetricsContext); const balance = useSelector(getMultichainSelectedAccountCachedBalance); const balanceIsLoading = !balance; - const selectedAccount = useSelector(getSelectedAccount); - const shouldHideZeroBalanceTokens = useSelector( - getShouldHideZeroBalanceTokens, - ); const { currency: primaryCurrency, @@ -113,24 +108,6 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { getIstokenDetectionInactiveOnNonMainnetSupportedNetwork, ); - const accountTotalFiatBalance = useAccountTotalFiatBalance( - selectedAccount, - shouldHideZeroBalanceTokens, - ); - - const tokensWithBalances = - accountTotalFiatBalance.tokensWithBalances as TokenWithBalance[]; - - const { loading } = accountTotalFiatBalance; - - tokensWithBalances.forEach((token) => { - // token.string is the balance displayed in the TokenList UI - token.string = roundToDecimalPlacesRemovingExtraZeroes( - token.string, - 5, - ) as string; - }); - const balanceIsZero = useSelector( getMultichainSelectedAccountCachedBalanceIsZero, ); @@ -177,7 +154,12 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { ) : null ///: END:ONLY_INCLUDE_IF } - + + onClickAsset(nativeCurrency)} title={nativeCurrency} @@ -212,7 +194,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { showPercentage /> { onClickAsset(tokenAddress); diff --git a/ui/components/app/assets/asset-list/sort-control/index.ts b/ui/components/app/assets/asset-list/sort-control/index.ts new file mode 100644 index 000000000000..7e5ecace780f --- /dev/null +++ b/ui/components/app/assets/asset-list/sort-control/index.ts @@ -0,0 +1 @@ +export { default } from './sort-control'; diff --git a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx new file mode 100644 index 000000000000..51c451f67cd5 --- /dev/null +++ b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx @@ -0,0 +1,116 @@ +import React, { useEffect, useMemo } from 'react'; +import { Button } from '../../../../component-library'; +import { TokenWithBalance } from '../asset-list'; +import { SortOrder, sortAssets } from '../../util/sort'; +import { useAccountTotalFiatBalance } from '../../../../../hooks/useAccountTotalFiatBalance'; +import { shallowEqual, useSelector } from 'react-redux'; +import { + getConfirmationExchangeRates, + getCurrentCurrency, + getSelectedAccount, + getShouldHideZeroBalanceTokens, + getTokenExchangeRates, +} from '../../../../../selectors'; +import { roundToDecimalPlacesRemovingExtraZeroes } from '../../../../../helpers/utils/util'; +import { isEqualCaseInsensitive } from '../../../../../../shared/modules/string-utils'; +import { getConversionRate } from '../../../../../ducks/metamask/metamask'; +import { getTokenFiatAmount } from '../../../../../helpers/utils/token-util'; + +type SortControlProps = { + tokenList: TokenWithBalance[]; + setTokenList: (arg: TokenWithBalance[]) => void; + setLoading: (arg: boolean) => void; +}; + +const SortControl = ({ + tokenList, + setTokenList, + setLoading, +}: SortControlProps) => { + const selectedAccount = useSelector(getSelectedAccount); + const shouldHideZeroBalanceTokens = useSelector( + getShouldHideZeroBalanceTokens, + ); + const conversionRate = useSelector(getConversionRate); + const currentCurrency = useSelector(getCurrentCurrency); + + // tokenExchangeRate + const contractExchangeRates = useSelector( + getTokenExchangeRates, + shallowEqual, + ); + const confirmationExchangeRates = useSelector(getConfirmationExchangeRates); + const mergedRates = { + ...contractExchangeRates, + ...confirmationExchangeRates, + }; + const accountTotalFiatBalance = useAccountTotalFiatBalance( + selectedAccount, + shouldHideZeroBalanceTokens, + ); + + const { loading } = accountTotalFiatBalance; + + useEffect(() => { + setLoading(loading); + const tokensWithBalances = + accountTotalFiatBalance.tokensWithBalances as TokenWithBalance[]; + + tokensWithBalances.forEach((token) => { + // token.string is the balance displayed in the TokenList UI + token.string = roundToDecimalPlacesRemovingExtraZeroes( + token.string, + 5, + ) as string; + }); + + // to sort by fiat balance, we need to compute this at this level + // should this get passed down as props to token-cell as props, rather than recomputing there? + tokensWithBalances.forEach((token) => { + const contractExchangeTokenKey = Object.keys(mergedRates).find((key) => + isEqualCaseInsensitive(key, token.address), + ); + + const tokenExchangeRate = + contractExchangeTokenKey && mergedRates[contractExchangeTokenKey]; + + token.tokenFiatAmount = + getTokenFiatAmount( + tokenExchangeRate, + conversionRate, + currentCurrency, + token.string, // tokenAmount + token.symbol, // tokenSymbol + false, // no currency symbol prefix + false, // no ticker symbol suffix + ) || '0'; + }); + + setTokenList(tokensWithBalances); + setLoading(loading); + }, [accountTotalFiatBalance]); + + const handleSort = (key: string, sortCallback: string, order: SortOrder) => { + const sorted = sortAssets(tokenList, { + key, + sortCallback, + order, + }); + setTokenList(sorted); + }; + + return ( + <> + + + + ); +}; + +export default SortControl; diff --git a/ui/components/app/assets/util/sort.ts b/ui/components/app/assets/util/sort.ts index 5db4120c1881..000ebc7989ef 100644 --- a/ui/components/app/assets/util/sort.ts +++ b/ui/components/app/assets/util/sort.ts @@ -4,11 +4,12 @@ interface SortCriteria { sortCallback?: string; } -type SortOrder = 'asc' | 'dsc'; +export type SortOrder = 'asc' | 'dsc'; // All sortingCallbacks should be asc order, sortAssets function handles asc/dsc const sortingCallbacks: { [key: string]: (a: any, b: any) => number } = { numeric: (a: number, b: number) => a - b, + stringNumeric: (a: string, b: string) => parseInt(a) - parseInt(b), alphaNumeric: (a: string, b: string) => a.localeCompare(b), date: (a: Date, b: Date) => a.getTime() - b.getTime(), }; From 95881ef62cb0999b0f6d254659eff603260f2902 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Tue, 10 Sep 2024 06:44:47 -0700 Subject: [PATCH 008/151] Temporary fix to sorting logic --- .../asset-list/sort-control/sort-control.tsx | 70 ++++++++++--------- ui/components/app/assets/util/sort.ts | 2 +- 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx index 51c451f67cd5..7c5109f65658 100644 --- a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx +++ b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useMemo } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { Button } from '../../../../component-library'; import { TokenWithBalance } from '../asset-list'; import { SortOrder, sortAssets } from '../../util/sort'; @@ -27,6 +27,7 @@ const SortControl = ({ setTokenList, setLoading, }: SortControlProps) => { + const [sorted, setSorted] = useState(false); const selectedAccount = useSelector(getSelectedAccount); const shouldHideZeroBalanceTokens = useSelector( getShouldHideZeroBalanceTokens, @@ -52,42 +53,45 @@ const SortControl = ({ const { loading } = accountTotalFiatBalance; useEffect(() => { - setLoading(loading); - const tokensWithBalances = - accountTotalFiatBalance.tokensWithBalances as TokenWithBalance[]; + if (!sorted) { + console.log('hello world'); + setLoading(loading); + const tokensWithBalances = + accountTotalFiatBalance.tokensWithBalances as TokenWithBalance[]; - tokensWithBalances.forEach((token) => { - // token.string is the balance displayed in the TokenList UI - token.string = roundToDecimalPlacesRemovingExtraZeroes( - token.string, - 5, - ) as string; - }); + tokensWithBalances.forEach((token) => { + // token.string is the balance displayed in the TokenList UI + token.string = roundToDecimalPlacesRemovingExtraZeroes( + token.string, + 5, + ) as string; + }); - // to sort by fiat balance, we need to compute this at this level - // should this get passed down as props to token-cell as props, rather than recomputing there? - tokensWithBalances.forEach((token) => { - const contractExchangeTokenKey = Object.keys(mergedRates).find((key) => - isEqualCaseInsensitive(key, token.address), - ); + // to sort by fiat balance, we need to compute this at this level + // should this get passed down as props to token-cell as props, rather than recomputing there? + tokensWithBalances.forEach((token) => { + const contractExchangeTokenKey = Object.keys(mergedRates).find((key) => + isEqualCaseInsensitive(key, token.address), + ); - const tokenExchangeRate = - contractExchangeTokenKey && mergedRates[contractExchangeTokenKey]; + const tokenExchangeRate = + contractExchangeTokenKey && mergedRates[contractExchangeTokenKey]; - token.tokenFiatAmount = - getTokenFiatAmount( - tokenExchangeRate, - conversionRate, - currentCurrency, - token.string, // tokenAmount - token.symbol, // tokenSymbol - false, // no currency symbol prefix - false, // no ticker symbol suffix - ) || '0'; - }); + token.tokenFiatAmount = + getTokenFiatAmount( + tokenExchangeRate, + conversionRate, + currentCurrency, + token.string, // tokenAmount + token.symbol, // tokenSymbol + false, // no currency symbol prefix + false, // no ticker symbol suffix + ) || '0'; + }); - setTokenList(tokensWithBalances); - setLoading(loading); + setTokenList(tokensWithBalances); + setLoading(loading); + } }, [accountTotalFiatBalance]); const handleSort = (key: string, sortCallback: string, order: SortOrder) => { @@ -96,6 +100,8 @@ const SortControl = ({ sortCallback, order, }); + console.log('SORTED', sorted); + setSorted(true); setTokenList(sorted); }; diff --git a/ui/components/app/assets/util/sort.ts b/ui/components/app/assets/util/sort.ts index 000ebc7989ef..7ab92ea5540c 100644 --- a/ui/components/app/assets/util/sort.ts +++ b/ui/components/app/assets/util/sort.ts @@ -24,7 +24,7 @@ function getNestedValue(obj: T, keyPath: string): any { export function sortAssets(array: T[], criteria: SortCriteria): T[] { const { key, order = 'asc', sortCallback } = criteria; - return array.sort((a, b) => { + return [...array].sort((a, b) => { const aValue = getNestedValue(a, key); const bValue = getNestedValue(b, key); From 6fad3b220aabe10975ef74588c8889088215ac3a Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Wed, 11 Sep 2024 11:50:04 -0700 Subject: [PATCH 009/151] Init dropdown styles --- ui/components/app/app-components.scss | 1 + .../asset-list-control-bar.tsx | 74 +++++++++++++++++++ .../asset-list-control-bar/index.scss | 67 +++++++++++++++++ .../asset-list-control-bar/index.ts | 1 + .../app/assets/asset-list/asset-list.tsx | 3 +- .../asset-list/sort-control/sort-control.tsx | 15 ++-- 6 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx create mode 100644 ui/components/app/assets/asset-list/asset-list-control-bar/index.scss create mode 100644 ui/components/app/assets/asset-list/asset-list-control-bar/index.ts diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index cdbe492029b8..ff2e1d1e875a 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -54,6 +54,7 @@ @import 'srp-input/srp-input'; @import 'snaps/snap-privacy-warning/index'; @import 'tab-bar/index'; +@import 'assets/asset-list/asset-list-control-bar/index'; @import 'assets/token-cell/token-cell'; @import 'assets/token-list-display/token-list-display'; @import 'transaction-activity-log/index'; diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx new file mode 100644 index 000000000000..b76965e1f486 --- /dev/null +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -0,0 +1,74 @@ +import React, { useEffect, useRef, useState } from 'react'; +import classnames from 'classnames'; +import { + Box, + Button, + ButtonSize, + IconName, + Popover, + PopoverPosition, +} from '../../../../component-library'; +import { TokenWithBalance } from '../asset-list'; +import { SortOrder, sortAssets } from '../../util/sort'; +import { useAccountTotalFiatBalance } from '../../../../../hooks/useAccountTotalFiatBalance'; +import { shallowEqual, useSelector } from 'react-redux'; +import { + getConfirmationExchangeRates, + getCurrentCurrency, + getSelectedAccount, + getShouldHideZeroBalanceTokens, + getTokenExchangeRates, +} from '../../../../../selectors'; +import { roundToDecimalPlacesRemovingExtraZeroes } from '../../../../../helpers/utils/util'; +import { isEqualCaseInsensitive } from '../../../../../../shared/modules/string-utils'; +import { getConversionRate } from '../../../../../ducks/metamask/metamask'; +import { getTokenFiatAmount } from '../../../../../helpers/utils/token-util'; +import SortControl from '../sort-control'; + +type AssetListControlBarProps = { + tokenList: TokenWithBalance[]; + setTokenList: (arg: TokenWithBalance[]) => void; + setLoading: (arg: boolean) => void; +}; + +const AssetListControlBar = ({ + tokenList, + setTokenList, + setLoading, +}: AssetListControlBarProps) => { + const controlBarRef = useRef(null); // Create a ref + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const handleOpenPopover = () => { + setIsPopoverOpen(!isPopoverOpen); + }; + return ( + <> + + + + + + + + + ); +}; + +export default AssetListControlBar; diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss b/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss new file mode 100644 index 000000000000..34073f8ca6a5 --- /dev/null +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss @@ -0,0 +1,67 @@ + + +.asset-list-control-bar { + display: flex; + position: relative; + justify-content: space-between; + cursor: pointer; + // outline: solid green 2px; + padding-top: 16px; + padding-left: 16px; + padding-right: 16px; +} + +// intentionally used generic naming convention for styled selectable list item +// inspired from ui/components/multichain/network-list-item/index.scss +// should probably be broken out into component library +.selectable-list-item { + position: relative; + cursor: pointer; + + &:not(.selectable-list-item--selected) { + &:hover, + &:focus-within { + background: var(--color-background-default-hover); + } + } + + a:hover, + a:focus { + color: inherit; + } + + &:hover, + &:focus, + &:focus-within { + .selectable-list-item__delete { + visibility: visible; + } + } + + &__network-name { + width: 100%; + flex: 1; + overflow: hidden; + text-align: start; + + button:hover { + opacity: 1; + } + } + + &__tooltip { + display: inline; + } + + &__selected-indicator { + width: 4px; + height: calc(100% - 8px); + position: absolute; + top: 4px; + left: 4px; + } + + &__delete { + visibility: hidden; + } +} \ No newline at end of file diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/index.ts b/ui/components/app/assets/asset-list/asset-list-control-bar/index.ts new file mode 100644 index 000000000000..c9eff91c6fcf --- /dev/null +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/index.ts @@ -0,0 +1 @@ +export { default } from './asset-list-control-bar'; diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index 834272288656..b59f4dce3190 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -45,6 +45,7 @@ import { } from '../../../multichain/ramps-card/ramps-card'; import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; import SortControl from './sort-control'; +import AssetListControlBar from './asset-list-control-bar'; ///: END:ONLY_INCLUDE_IF export type TokenWithBalance = { @@ -154,7 +155,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { ) : null ///: END:ONLY_INCLUDE_IF } - - - + ); }; From b7d6e47a26ad873c835615b8a80c0839e1c93048 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Wed, 11 Sep 2024 14:36:14 -0700 Subject: [PATCH 010/151] Init css for SelectableListItem --- ui/components/app/app-components.scss | 1 + .../asset-list-control-bar.tsx | 10 ++- .../asset-list-control-bar/index.scss | 61 +----------------- .../assets/asset-list/sort-control/index.scss | 33 ++++++++++ .../asset-list/sort-control/sort-control.tsx | 62 ++++++++++++++++--- 5 files changed, 96 insertions(+), 71 deletions(-) create mode 100644 ui/components/app/assets/asset-list/sort-control/index.scss diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index ff2e1d1e875a..3912632ab6d7 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -55,6 +55,7 @@ @import 'snaps/snap-privacy-warning/index'; @import 'tab-bar/index'; @import 'assets/asset-list/asset-list-control-bar/index'; +@import 'assets/asset-list/sort-control/index'; @import 'assets/token-cell/token-cell'; @import 'assets/token-list-display/token-list-display'; @import 'transaction-activity-log/index'; diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index b76965e1f486..52cfc1a20faf 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -55,10 +55,16 @@ const AssetListControlBar = ({ Import { + const [sortKey, setSortKey] = useState(null); const [sorted, setSorted] = useState(false); const selectedAccount = useSelector(getSelectedAccount); const shouldHideZeroBalanceTokens = useSelector( @@ -54,7 +61,6 @@ const SortControl = ({ useEffect(() => { if (!sorted) { - console.log('hello world'); setLoading(loading); const tokensWithBalances = accountTotalFiatBalance.tokensWithBalances as TokenWithBalance[]; @@ -95,6 +101,7 @@ const SortControl = ({ }, [accountTotalFiatBalance]); const handleSort = (key: string, sortCallback: string, order: SortOrder) => { + setSortKey(key); const sorted = sortAssets(tokenList, { key, sortCallback, @@ -106,20 +113,55 @@ const SortControl = ({ return ( <> - handleSort('symbol', 'alphanumeric', 'asc')} > - Sort by Symbol - - + handleSort('tokenFiatAmount', 'stringNumeric', 'dsc')} > - Sort by Balance - + Declining balance ($ high-low) + ); }; +// intentionally used generic naming convention for styled selectable list item +// inspired from ui/components/multichain/network-list-item +// should probably be broken out into component library +type SelectableListItemProps = { + isSelected: boolean; + onClick?: React.MouseEventHandler; + children: ReactNode; +}; + +export const SelectableListItem = ({ + isSelected, + onClick, + children, +}: SelectableListItemProps) => { + return ( + + + {children} + + {isSelected && ( + + )} + + ); +}; + export default SortControl; From 0d7c10e56eaf21814dd711583768a3f748def8ea Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Wed, 11 Sep 2024 15:49:34 -0700 Subject: [PATCH 011/151] Polish controlbar styles --- .../asset-list-control-bar.tsx | 110 ++++++++++++++++-- .../asset-list-control-bar/index.scss | 4 + .../app/assets/asset-list/asset-list.tsx | 4 +- .../asset-list/sort-control/sort-control.tsx | 84 +------------ ui/css/design-system/_colors.scss | 2 + ui/helpers/constants/design-system.ts | 2 + 6 files changed, 116 insertions(+), 90 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index 52cfc1a20faf..f39920dac91c 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -1,15 +1,15 @@ import React, { useEffect, useRef, useState } from 'react'; -import classnames from 'classnames'; import { Box, Button, + ButtonBase, + ButtonBaseSize, ButtonSize, IconName, Popover, PopoverPosition, } from '../../../../component-library'; import { TokenWithBalance } from '../asset-list'; -import { SortOrder, sortAssets } from '../../util/sort'; import { useAccountTotalFiatBalance } from '../../../../../hooks/useAccountTotalFiatBalance'; import { shallowEqual, useSelector } from 'react-redux'; import { @@ -24,6 +24,13 @@ import { isEqualCaseInsensitive } from '../../../../../../shared/modules/string- import { getConversionRate } from '../../../../../ducks/metamask/metamask'; import { getTokenFiatAmount } from '../../../../../helpers/utils/token-util'; import SortControl from '../sort-control'; +import { + BackgroundColor, + BorderColor, + BorderStyle, + FontStyle, + TextColor, +} from '../../../../../helpers/constants/design-system'; type AssetListControlBarProps = { tokenList: TokenWithBalance[]; @@ -38,24 +45,110 @@ const AssetListControlBar = ({ }: AssetListControlBarProps) => { const controlBarRef = useRef(null); // Create a ref const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const selectedAccount = useSelector(getSelectedAccount); + const shouldHideZeroBalanceTokens = useSelector( + getShouldHideZeroBalanceTokens, + ); + const conversionRate = useSelector(getConversionRate); + const currentCurrency = useSelector(getCurrentCurrency); + + // tokenExchangeRate + const contractExchangeRates = useSelector( + getTokenExchangeRates, + shallowEqual, + ); + const confirmationExchangeRates = useSelector(getConfirmationExchangeRates); + const mergedRates = { + ...contractExchangeRates, + ...confirmationExchangeRates, + }; + const accountTotalFiatBalance = useAccountTotalFiatBalance( + selectedAccount, + shouldHideZeroBalanceTokens, + ); + + const { loading } = accountTotalFiatBalance; + + const [sorted, setSorted] = useState(false); + + useEffect(() => { + if (!sorted) { + setLoading(loading); + const tokensWithBalances = + accountTotalFiatBalance.tokensWithBalances as TokenWithBalance[]; + + tokensWithBalances.forEach((token) => { + // token.string is the balance displayed in the TokenList UI + token.string = roundToDecimalPlacesRemovingExtraZeroes( + token.string, + 5, + ) as string; + }); + + // to sort by fiat balance, we need to compute this at this level + // should this get passed down as props to token-cell as props, rather than recomputing there? + tokensWithBalances.forEach((token) => { + const contractExchangeTokenKey = Object.keys(mergedRates).find((key) => + isEqualCaseInsensitive(key, token.address), + ); + + const tokenExchangeRate = + contractExchangeTokenKey && mergedRates[contractExchangeTokenKey]; + + token.tokenFiatAmount = + getTokenFiatAmount( + tokenExchangeRate, + conversionRate, + currentCurrency, + token.string, // tokenAmount + token.symbol, // tokenSymbol + false, // no currency symbol prefix + false, // no ticker symbol suffix + ) || '0'; + }); + + setTokenList(tokensWithBalances); + setLoading(loading); + } + }, [accountTotalFiatBalance]); const handleOpenPopover = () => { setIsPopoverOpen(!isPopoverOpen); }; + return ( <> - - + diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss b/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss index 21e73fb05074..052acd24ded9 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss @@ -7,4 +7,8 @@ padding-top: 16px; margin-left: 16px; margin-right: 16px; + + button:hover { + background-color: var(--color-background-hover); + } } \ No newline at end of file diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index b59f4dce3190..4cb6a0985374 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -161,7 +161,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { setLoading={setLoading} /> - onClickAsset(nativeCurrency)} title={nativeCurrency} // The primary and secondary currencies are subject to change based on the user's settings @@ -193,7 +193,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { isNativeCurrency isStakeable={isStakeable} showPercentage - /> + /> */} void; setLoading: (arg: boolean) => void; + setSorted: (arg: boolean) => void; }; const SortControl = ({ tokenList, setTokenList, setLoading, + setSorted, }: SortControlProps) => { const [sortKey, setSortKey] = useState(null); - const [sorted, setSorted] = useState(false); - const selectedAccount = useSelector(getSelectedAccount); - const shouldHideZeroBalanceTokens = useSelector( - getShouldHideZeroBalanceTokens, - ); - const conversionRate = useSelector(getConversionRate); - const currentCurrency = useSelector(getCurrentCurrency); - - // tokenExchangeRate - const contractExchangeRates = useSelector( - getTokenExchangeRates, - shallowEqual, - ); - const confirmationExchangeRates = useSelector(getConfirmationExchangeRates); - const mergedRates = { - ...contractExchangeRates, - ...confirmationExchangeRates, - }; - const accountTotalFiatBalance = useAccountTotalFiatBalance( - selectedAccount, - shouldHideZeroBalanceTokens, - ); - - const { loading } = accountTotalFiatBalance; - - useEffect(() => { - if (!sorted) { - setLoading(loading); - const tokensWithBalances = - accountTotalFiatBalance.tokensWithBalances as TokenWithBalance[]; - - tokensWithBalances.forEach((token) => { - // token.string is the balance displayed in the TokenList UI - token.string = roundToDecimalPlacesRemovingExtraZeroes( - token.string, - 5, - ) as string; - }); - - // to sort by fiat balance, we need to compute this at this level - // should this get passed down as props to token-cell as props, rather than recomputing there? - tokensWithBalances.forEach((token) => { - const contractExchangeTokenKey = Object.keys(mergedRates).find((key) => - isEqualCaseInsensitive(key, token.address), - ); - - const tokenExchangeRate = - contractExchangeTokenKey && mergedRates[contractExchangeTokenKey]; - - token.tokenFiatAmount = - getTokenFiatAmount( - tokenExchangeRate, - conversionRate, - currentCurrency, - token.string, // tokenAmount - token.symbol, // tokenSymbol - false, // no currency symbol prefix - false, // no ticker symbol suffix - ) || '0'; - }); - - setTokenList(tokensWithBalances); - setLoading(loading); - } - }, [accountTotalFiatBalance]); const handleSort = (key: string, sortCallback: string, order: SortOrder) => { setSortKey(key); diff --git a/ui/css/design-system/_colors.scss b/ui/css/design-system/_colors.scss index f8ac7cf93da9..2d948b928012 100644 --- a/ui/css/design-system/_colors.scss +++ b/ui/css/design-system/_colors.scss @@ -1,6 +1,8 @@ $color-map: ( 'background-default': --color-background-default, 'background-alternative': --color-background-alternative, + 'background-hover': --color-background-hover, + 'background-pressed': --color-background-pressed, 'text-default': --color-text-default, 'text-alternative': --color-text-alternative, 'text-muted': --color-text-muted, diff --git a/ui/helpers/constants/design-system.ts b/ui/helpers/constants/design-system.ts index f8d4f19389a5..8374e812b017 100644 --- a/ui/helpers/constants/design-system.ts +++ b/ui/helpers/constants/design-system.ts @@ -54,6 +54,8 @@ export enum Color { export enum BackgroundColor { backgroundDefault = 'background-default', backgroundAlternative = 'background-alternative', + backgroundHover = 'background-hover', + backgroundPressed = 'background-pressed', overlayDefault = 'overlay-default', overlayAlternative = 'overlay-alternative', primaryDefault = 'primary-default', From 313af199449f384612efdb39bf4d30133bffb843 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Wed, 11 Sep 2024 15:57:31 -0700 Subject: [PATCH 012/151] Cleanup --- .../asset-list-control-bar/asset-list-control-bar.tsx | 1 - ui/components/app/assets/asset-list/asset-list.tsx | 5 ++--- .../app/assets/asset-list/sort-control/sort-control.tsx | 2 -- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index f39920dac91c..ca1812b3a72e 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -162,7 +162,6 @@ const AssetListControlBar = ({ diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index 4cb6a0985374..0d277b1f0635 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -44,7 +44,6 @@ import { RampsCard, } from '../../../multichain/ramps-card/ramps-card'; import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; -import SortControl from './sort-control'; import AssetListControlBar from './asset-list-control-bar'; ///: END:ONLY_INCLUDE_IF @@ -161,7 +160,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { setLoading={setLoading} /> - {/* onClickAsset(nativeCurrency)} title={nativeCurrency} // The primary and secondary currencies are subject to change based on the user's settings @@ -193,7 +192,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { isNativeCurrency isStakeable={isStakeable} showPercentage - /> */} + /> void; - setLoading: (arg: boolean) => void; setSorted: (arg: boolean) => void; }; const SortControl = ({ tokenList, setTokenList, - setLoading, setSorted, }: SortControlProps) => { const [sortKey, setSortKey] = useState(null); From 0f7b5ac891fc7cddf3edead55af76df1dce70ec0 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Thu, 12 Sep 2024 13:55:24 -0700 Subject: [PATCH 013/151] Use tsignore for string variable in token-cell --- .../tests/tokens/custom-token-send-transfer.spec.js | 3 ++- ui/components/app/assets/asset-list/asset-list.tsx | 7 +++---- ui/components/app/assets/token-cell/token-cell.tsx | 9 +++++++-- .../multichain/token-list-item/token-list-item.tsx | 11 ++++++----- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/test/e2e/tests/tokens/custom-token-send-transfer.spec.js b/test/e2e/tests/tokens/custom-token-send-transfer.spec.js index a5ae0fea449e..bafc060e3a69 100644 --- a/test/e2e/tests/tokens/custom-token-send-transfer.spec.js +++ b/test/e2e/tests/tokens/custom-token-send-transfer.spec.js @@ -97,7 +97,7 @@ describe('Transfer custom tokens @no-mmi', function () { ); }); - it('transfer custom tokens from dapp customizing gas values', async function () { + it.only('transfer custom tokens from dapp customizing gas values', async function () { await withFixtures( { dapp: true, @@ -114,6 +114,7 @@ describe('Transfer custom tokens @no-mmi', function () { smartContract, ); await unlockWallet(driver); + console.log('FOO'); // transfer token from dapp await openDapp(driver, contractAddress); diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index 583ece78eb91..bfee6f37fead 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -124,10 +124,9 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { tokensWithBalances.forEach((token) => { // token.string is the balance displayed in the TokenList UI - token.string = roundToDecimalPlacesRemovingExtraZeroes( - token.string, - 5, - ) as string; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + token.string = roundToDecimalPlacesRemovingExtraZeroes(token.string, 5); }); const balanceIsZero = useSelector( diff --git a/ui/components/app/assets/token-cell/token-cell.tsx b/ui/components/app/assets/token-cell/token-cell.tsx index 6644d6d5b706..c06306bba59d 100644 --- a/ui/components/app/assets/token-cell/token-cell.tsx +++ b/ui/components/app/assets/token-cell/token-cell.tsx @@ -30,11 +30,15 @@ export default function TokenCell({ ); const title = tokenData?.name || symbol; const tokenImage = tokenData?.iconUrl || image; - const formattedFiat = useTokenFiatAmount(address, string, symbol, {}, false); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const formattedFiat = useTokenFiatAmount(address, string, symbol); const locale = useSelector(getIntlLocale); const primary = new Intl.NumberFormat(locale, { minimumSignificantDigits: 1, - }).format(parseInt(string, 10)); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + }).format(string.toString()); const isOriginalTokenSymbol = useIsOriginalTokenSymbol(address, symbol); @@ -48,6 +52,7 @@ export default function TokenCell({ title={title} isOriginalTokenSymbol={isOriginalTokenSymbol} address={address} + showPercentage /> ); } diff --git a/ui/components/multichain/token-list-item/token-list-item.tsx b/ui/components/multichain/token-list-item/token-list-item.tsx index a0aa1406abfa..b588efe6601b 100644 --- a/ui/components/multichain/token-list-item/token-list-item.tsx +++ b/ui/components/multichain/token-list-item/token-list-item.tsx @@ -82,7 +82,7 @@ type TokenListItemProps = { }; export const TokenListItem = ({ - className = '', + className, onClick, tokenSymbol, tokenImage, @@ -132,9 +132,10 @@ export const TokenListItem = ({ const tokensMarketData = useSelector(getTokensMarketData); - const tokenPercentageChange = address - ? tokensMarketData?.[address]?.pricePercentChange1d - : null; + const tokenPercentageChange = + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + tokensMarketData?.[address]?.pricePercentChange1d; const tokenTitle = getTokenTitle(); const tokenMainTitleToDisplay = showPercentage ? tokenTitle : tokenSymbol; @@ -196,7 +197,7 @@ export const TokenListItem = ({ return ( Date: Thu, 12 Sep 2024 14:20:51 -0700 Subject: [PATCH 014/151] Remove unecessary ts-ignores, and unskip unit tests --- test/e2e/tests/tokens/custom-token-send-transfer.spec.js | 2 +- ui/components/app/assets/asset-list/asset-list.tsx | 8 ++++---- ui/components/app/assets/token-cell/token-cell.tsx | 4 +--- .../multichain/token-list-item/token-list-item.tsx | 7 +++---- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/test/e2e/tests/tokens/custom-token-send-transfer.spec.js b/test/e2e/tests/tokens/custom-token-send-transfer.spec.js index bafc060e3a69..71004f1cd940 100644 --- a/test/e2e/tests/tokens/custom-token-send-transfer.spec.js +++ b/test/e2e/tests/tokens/custom-token-send-transfer.spec.js @@ -97,7 +97,7 @@ describe('Transfer custom tokens @no-mmi', function () { ); }); - it.only('transfer custom tokens from dapp customizing gas values', async function () { + it('transfer custom tokens from dapp customizing gas values', async function () { await withFixtures( { dapp: true, diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index bfee6f37fead..c59f17f9e606 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -123,10 +123,10 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const { loading } = accountTotalFiatBalance; tokensWithBalances.forEach((token) => { - // token.string is the balance displayed in the TokenList UI - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - token.string = roundToDecimalPlacesRemovingExtraZeroes(token.string, 5); + token.string = roundToDecimalPlacesRemovingExtraZeroes( + token.string, + 5, + ) as string; }); const balanceIsZero = useSelector( diff --git a/ui/components/app/assets/token-cell/token-cell.tsx b/ui/components/app/assets/token-cell/token-cell.tsx index c06306bba59d..2cd5cb84b8ab 100644 --- a/ui/components/app/assets/token-cell/token-cell.tsx +++ b/ui/components/app/assets/token-cell/token-cell.tsx @@ -30,9 +30,7 @@ export default function TokenCell({ ); const title = tokenData?.name || symbol; const tokenImage = tokenData?.iconUrl || image; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const formattedFiat = useTokenFiatAmount(address, string, symbol); + const formattedFiat = useTokenFiatAmount(address, string, symbol, {}, false); const locale = useSelector(getIntlLocale); const primary = new Intl.NumberFormat(locale, { minimumSignificantDigits: 1, diff --git a/ui/components/multichain/token-list-item/token-list-item.tsx b/ui/components/multichain/token-list-item/token-list-item.tsx index b588efe6601b..78ca5e501ebf 100644 --- a/ui/components/multichain/token-list-item/token-list-item.tsx +++ b/ui/components/multichain/token-list-item/token-list-item.tsx @@ -132,10 +132,9 @@ export const TokenListItem = ({ const tokensMarketData = useSelector(getTokensMarketData); - const tokenPercentageChange = - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - tokensMarketData?.[address]?.pricePercentChange1d; + const tokenPercentageChange = address + ? tokensMarketData?.[address]?.pricePercentChange1d + : null; const tokenTitle = getTokenTitle(); const tokenMainTitleToDisplay = showPercentage ? tokenTitle : tokenSymbol; From 5c5b22e555a03754afdfcdb765eddd204d027c20 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Thu, 12 Sep 2024 14:53:55 -0700 Subject: [PATCH 015/151] Update snapshots --- .../__snapshots__/token-cell.test.js.snap | 12 ++++++---- .../__snapshots__/asset-page.test.tsx.snap | 24 +++++++++++-------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.js.snap b/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.js.snap index 1726dd7ff47c..e40a15f69863 100644 --- a/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.js.snap +++ b/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.js.snap @@ -48,12 +48,14 @@ exports[`Token Cell should match snapshot 1`] = ` > TEST -

- TEST -

+

+

TEST -

- TEST -

+

+

TEST -

- TEST -

+

+

Date: Thu, 12 Sep 2024 18:13:03 -0700 Subject: [PATCH 016/151] Remove foo --- test/e2e/tests/tokens/custom-token-send-transfer.spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/e2e/tests/tokens/custom-token-send-transfer.spec.js b/test/e2e/tests/tokens/custom-token-send-transfer.spec.js index 71004f1cd940..a5ae0fea449e 100644 --- a/test/e2e/tests/tokens/custom-token-send-transfer.spec.js +++ b/test/e2e/tests/tokens/custom-token-send-transfer.spec.js @@ -114,7 +114,6 @@ describe('Transfer custom tokens @no-mmi', function () { smartContract, ); await unlockWallet(driver); - console.log('FOO'); // transfer token from dapp await openDapp(driver, contractAddress); From 2bdb02fb041ed280898666a477262114a9711894 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Fri, 13 Sep 2024 10:47:16 -0700 Subject: [PATCH 017/151] Convert asset-list.test to ts --- .../{asset-list.test.js => asset-list.test.tsx} | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) rename ui/components/app/assets/asset-list/{asset-list.test.js => asset-list.test.tsx} (88%) diff --git a/ui/components/app/assets/asset-list/asset-list.test.js b/ui/components/app/assets/asset-list/asset-list.test.tsx similarity index 88% rename from ui/components/app/assets/asset-list/asset-list.test.js rename to ui/components/app/assets/asset-list/asset-list.test.tsx index e0ec77157194..329c29a6108e 100644 --- a/ui/components/app/assets/asset-list/asset-list.test.js +++ b/ui/components/app/assets/asset-list/asset-list.test.tsx @@ -1,14 +1,14 @@ import React from 'react'; import { screen, act, waitFor } from '@testing-library/react'; import { renderWithProvider } from '../../../../../test/jest'; -import configureStore from '../../../../store/store'; +import configureStore, { MetaMaskReduxState } from '../../../../store/store'; import mockState from '../../../../../test/data/mock-state.json'; import { CHAIN_IDS } from '../../../../../shared/constants/network'; import { useIsOriginalNativeTokenSymbol } from '../../../../hooks/useIsOriginalNativeTokenSymbol'; import { getTokenSymbol } from '../../../../store/actions'; import { getSelectedInternalAccountFromMockState } from '../../../../../test/jest/mocks'; import { mockNetworkState } from '../../../../../test/stub/networks'; -import AssetList from './asset-list'; +import AssetList from '.'; // Specific to just the ETH FIAT conversion const CONVERSION_RATE = 1597.32; @@ -67,8 +67,9 @@ jest.mock('../../../../store/actions', () => { }; }); -const mockSelectedInternalAccount = - getSelectedInternalAccountFromMockState(mockState); +const mockSelectedInternalAccount = getSelectedInternalAccountFromMockState( + mockState as unknown as MetaMaskReduxState, +); const render = (balance = ETH_BALANCE, chainId = CHAIN_IDS.MAINNET) => { const state = { @@ -102,15 +103,15 @@ const render = (balance = ETH_BALANCE, chainId = CHAIN_IDS.MAINNET) => { }; const store = configureStore(state); return renderWithProvider( - undefined} />, + undefined} showTokensLinks />, store, ); }; describe('AssetList', () => { - useIsOriginalNativeTokenSymbol.mockReturnValue(true); + (useIsOriginalNativeTokenSymbol as jest.Mock).mockReturnValue(true); - getTokenSymbol.mockImplementation(async (address) => { + (getTokenSymbol as jest.Mock).mockImplementation(async (address) => { if (address === USDC_CONTRACT) { return 'USDC'; } From 692001c6a921e37e17c82136c0906e15a289df92 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Fri, 13 Sep 2024 10:52:05 -0700 Subject: [PATCH 018/151] Update token-cell tests to ts --- .../__snapshots__/token-cell.test.tsx.snap | 86 +++++++++++++++++++ .../assets/token-cell/{index.js => index.ts} | 0 ...token-cell.test.js => token-cell.test.tsx} | 12 ++- 3 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 ui/components/app/assets/token-cell/__snapshots__/token-cell.test.tsx.snap rename ui/components/app/assets/token-cell/{index.js => index.ts} (100%) rename ui/components/app/assets/token-cell/{token-cell.test.js => token-cell.test.tsx} (90%) diff --git a/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.tsx.snap b/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.tsx.snap new file mode 100644 index 000000000000..e40a15f69863 --- /dev/null +++ b/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.tsx.snap @@ -0,0 +1,86 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Token Cell should match snapshot 1`] = ` +
+ +`; diff --git a/ui/components/app/assets/token-cell/index.js b/ui/components/app/assets/token-cell/index.ts similarity index 100% rename from ui/components/app/assets/token-cell/index.js rename to ui/components/app/assets/token-cell/index.ts diff --git a/ui/components/app/assets/token-cell/token-cell.test.js b/ui/components/app/assets/token-cell/token-cell.test.tsx similarity index 90% rename from ui/components/app/assets/token-cell/token-cell.test.js rename to ui/components/app/assets/token-cell/token-cell.test.tsx index 6404f3603e58..4fe2c7c26ebc 100644 --- a/ui/components/app/assets/token-cell/token-cell.test.js +++ b/ui/components/app/assets/token-cell/token-cell.test.tsx @@ -47,7 +47,7 @@ describe('Token Cell', () => { }, }; - useIsOriginalTokenSymbol.mockReturnValue(true); + (useIsOriginalTokenSymbol as jest.Mock).mockReturnValue(true); // two tokens with the same symbol but different addresses const MOCK_GET_TOKEN_LIST = { @@ -78,6 +78,7 @@ describe('Token Cell', () => { symbol: 'TEST', string: '5.000', currentCurrency: 'usd', + image: '', onClick: jest.fn(), }; @@ -86,10 +87,11 @@ describe('Token Cell', () => { symbol: 'TEST', string: '5000000', currentCurrency: 'usd', + image: '', onClick: jest.fn(), }; - useSelector.mockReturnValue(MOCK_GET_TOKEN_LIST); - useTokenFiatAmount.mockReturnValue('5.00'); + (useSelector as jest.Mock).mockReturnValue(MOCK_GET_TOKEN_LIST); + (useTokenFiatAmount as jest.Mock).mockReturnValue('5.00'); it('should match snapshot', () => { const { container } = renderWithProvider( @@ -106,7 +108,9 @@ describe('Token Cell', () => { mockStore, ); - fireEvent.click(queryByTestId('multichain-token-list-button')); + const targetElem = queryByTestId('multichain-token-list-button'); + + if (targetElem) fireEvent.click(targetElem); expect(props.onClick).toHaveBeenCalled(); }); From 0aab9fc4055f8fa62d100aa21ab47b26174b9a90 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Fri, 13 Sep 2024 11:03:58 -0700 Subject: [PATCH 019/151] Lint --- .../app/assets/token-cell/token-cell.test.tsx | 2 +- .../token-list-item/{index.js => index.ts} | 0 ...-item.test.js => token-list-item.test.tsx} | 31 +++++++++++-------- 3 files changed, 19 insertions(+), 14 deletions(-) rename ui/components/multichain/token-list-item/{index.js => index.ts} (100%) rename ui/components/multichain/token-list-item/{token-list-item.test.js => token-list-item.test.tsx} (82%) diff --git a/ui/components/app/assets/token-cell/token-cell.test.tsx b/ui/components/app/assets/token-cell/token-cell.test.tsx index 4fe2c7c26ebc..d92be927acdc 100644 --- a/ui/components/app/assets/token-cell/token-cell.test.tsx +++ b/ui/components/app/assets/token-cell/token-cell.test.tsx @@ -110,7 +110,7 @@ describe('Token Cell', () => { const targetElem = queryByTestId('multichain-token-list-button'); - if (targetElem) fireEvent.click(targetElem); + targetElem && fireEvent.click(targetElem); expect(props.onClick).toHaveBeenCalled(); }); diff --git a/ui/components/multichain/token-list-item/index.js b/ui/components/multichain/token-list-item/index.ts similarity index 100% rename from ui/components/multichain/token-list-item/index.js rename to ui/components/multichain/token-list-item/index.ts diff --git a/ui/components/multichain/token-list-item/token-list-item.test.js b/ui/components/multichain/token-list-item/token-list-item.test.tsx similarity index 82% rename from ui/components/multichain/token-list-item/token-list-item.test.js rename to ui/components/multichain/token-list-item/token-list-item.test.tsx index d62284c6fb19..18ad27665c9b 100644 --- a/ui/components/multichain/token-list-item/token-list-item.test.js +++ b/ui/components/multichain/token-list-item/token-list-item.test.tsx @@ -35,7 +35,7 @@ const state = { }, }; -let openTabSpy; +let openTabSpy: jest.SpyInstance; jest.mock('../../../ducks/locale/locale', () => ({ getIntlLocale: jest.fn(), @@ -45,9 +45,9 @@ const mockGetIntlLocale = getIntlLocale; describe('TokenListItem', () => { beforeAll(() => { - global.platform = { openTab: jest.fn() }; + global.platform = { openTab: jest.fn(), closeCurrentWindow: jest.fn() }; openTabSpy = jest.spyOn(global.platform, 'openTab'); - mockGetIntlLocale.mockReturnValue('en-US'); + (mockGetIntlLocale as unknown as jest.Mock).mockReturnValue('en-US'); }); const props = { onClick: jest.fn(), @@ -55,8 +55,7 @@ describe('TokenListItem', () => { it('should render correctly', () => { const store = configureMockStore()(state); const { getByTestId, container } = renderWithProvider( - // eslint-disable-next-line no-empty-function - {}} />, + undefined} tokenImage="" title="" />, store, ); expect(getByTestId('multichain-token-list-item')).toBeDefined(); @@ -66,7 +65,11 @@ describe('TokenListItem', () => { it('should render with custom className', () => { const store = configureMockStore()(state); const { getByTestId } = renderWithProvider( - , + , store, ); expect(getByTestId('multichain-token-list-item')).toHaveClass( @@ -82,7 +85,7 @@ describe('TokenListItem', () => { isOriginalTokenSymbol: false, }; const { getByText } = renderWithProvider( - , + , store, ); expect(getByText('11.9751 ETH')).toBeInTheDocument(); @@ -97,7 +100,7 @@ describe('TokenListItem', () => { showPercentage: true, }; const { getByTestId, getByText } = renderWithProvider( - , + , store, ); @@ -121,7 +124,7 @@ describe('TokenListItem', () => { }; const { getByText } = renderWithProvider( - , + , store, ); expect(getByText('11.9751 ETH')).toBeInTheDocument(); @@ -130,11 +133,13 @@ describe('TokenListItem', () => { it('handles click action and fires onClick', () => { const store = configureMockStore()(state); const { queryByTestId } = renderWithProvider( - , + , store, ); - fireEvent.click(queryByTestId('multichain-token-list-button')); + const targetElem = queryByTestId('multichain-token-list-button'); + + targetElem && fireEvent.click(targetElem); expect(props.onClick).toHaveBeenCalled(); }); @@ -142,7 +147,7 @@ describe('TokenListItem', () => { it('handles clicking staking opens tab', async () => { const store = configureMockStore()(state); const { queryByTestId } = renderWithProvider( - , + , store, ); @@ -153,7 +158,7 @@ describe('TokenListItem', () => { expect(stakeButton).toBeInTheDocument(); expect(stakeButton).not.toBeDisabled(); - fireEvent.click(stakeButton); + stakeButton && fireEvent.click(stakeButton); expect(openTabSpy).toHaveBeenCalledTimes(1); await waitFor(() => From 431583b774354664368f6f75373483f888cfd018 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Fri, 13 Sep 2024 11:21:39 -0700 Subject: [PATCH 020/151] Update snapshots --- .../__snapshots__/token-cell.test.js.snap | 86 ------------------- ....js.snap => token-list-item.test.tsx.snap} | 0 2 files changed, 86 deletions(-) delete mode 100644 ui/components/app/assets/token-cell/__snapshots__/token-cell.test.js.snap rename ui/components/multichain/token-list-item/__snapshots__/{token-list-item.test.js.snap => token-list-item.test.tsx.snap} (100%) diff --git a/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.js.snap b/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.js.snap deleted file mode 100644 index e40a15f69863..000000000000 --- a/ui/components/app/assets/token-cell/__snapshots__/token-cell.test.js.snap +++ /dev/null @@ -1,86 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Token Cell should match snapshot 1`] = ` -
- -`; diff --git a/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.js.snap b/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.tsx.snap similarity index 100% rename from ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.js.snap rename to ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.tsx.snap From 9f6a228342d1094d1316295afce1568c7cd746b7 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Fri, 13 Sep 2024 12:51:25 -0700 Subject: [PATCH 021/151] Begin linting ts --- .../asset-list-control-bar.tsx | 5 +- .../asset-list/sort-control/sort-control.tsx | 75 +++++++++---------- ui/components/app/assets/util/sort.ts | 32 +++++--- 3 files changed, 59 insertions(+), 53 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index ca1812b3a72e..305275666f7a 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -1,17 +1,15 @@ import React, { useEffect, useRef, useState } from 'react'; +import { shallowEqual, useSelector } from 'react-redux'; import { Box, - Button, ButtonBase, ButtonBaseSize, - ButtonSize, IconName, Popover, PopoverPosition, } from '../../../../component-library'; import { TokenWithBalance } from '../asset-list'; import { useAccountTotalFiatBalance } from '../../../../../hooks/useAccountTotalFiatBalance'; -import { shallowEqual, useSelector } from 'react-redux'; import { getConfirmationExchangeRates, getCurrentCurrency, @@ -28,7 +26,6 @@ import { BackgroundColor, BorderColor, BorderStyle, - FontStyle, TextColor, } from '../../../../../helpers/constants/design-system'; diff --git a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx index 1cb76aea20ae..a2eeee3938e0 100644 --- a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx +++ b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx @@ -1,4 +1,5 @@ -import React, { useState } from 'react'; +import React, { useState, ReactNode } from 'react'; +import classnames from 'classnames'; import { Box } from '../../../../component-library'; import { TokenWithBalance } from '../asset-list'; import { SortOrder, sortAssets } from '../../util/sort'; @@ -6,8 +7,41 @@ import { BackgroundColor, BorderRadius, } from '../../../../../helpers/constants/design-system'; -import { ReactNode } from 'react-markdown'; -import classnames from 'classnames'; + +// intentionally used generic naming convention for styled selectable list item +// inspired from ui/components/multichain/network-list-item +// should probably be broken out into component library +type SelectableListItemProps = { + isSelected: boolean; + onClick?: React.MouseEventHandler; + children: ReactNode; +}; + +export const SelectableListItem = ({ + isSelected, + onClick, + children, +}: SelectableListItemProps) => { + return ( + + + {children} + + {isSelected && ( + + )} + + ); +}; type SortControlProps = { tokenList: TokenWithBalance[]; @@ -51,39 +85,4 @@ const SortControl = ({ ); }; -// intentionally used generic naming convention for styled selectable list item -// inspired from ui/components/multichain/network-list-item -// should probably be broken out into component library -type SelectableListItemProps = { - isSelected: boolean; - onClick?: React.MouseEventHandler; - children: ReactNode; -}; - -export const SelectableListItem = ({ - isSelected, - onClick, - children, -}: SelectableListItemProps) => { - return ( - - - {children} - - {isSelected && ( - - )} - - ); -}; - export default SortControl; diff --git a/ui/components/app/assets/util/sort.ts b/ui/components/app/assets/util/sort.ts index 7ab92ea5540c..8026d09012cc 100644 --- a/ui/components/app/assets/util/sort.ts +++ b/ui/components/app/assets/util/sort.ts @@ -1,13 +1,21 @@ -interface SortCriteria { - key: string; // Deeply nested keys supported: 'profile.balance' - order?: SortOrder; - sortCallback?: string; -} - export type SortOrder = 'asc' | 'dsc'; +type SortingType = number | string | Date; +type SortingCallbacks = { + numeric: (a: number, b: number) => number; + stringNumeric: (a: string, b: string) => number; + alphaNumeric: (a: string, b: string) => number; + date: (a: Date, b: Date) => number; +}; +type SortCallbackKeys = keyof SortingCallbacks; +type SortCriteria = { + key: string; + order?: 'asc' | 'desc'; + sortCallback: SortCallbackKeys; +}; + // All sortingCallbacks should be asc order, sortAssets function handles asc/dsc -const sortingCallbacks: { [key: string]: (a: any, b: any) => number } = { +const sortingCallbacks: SortingCallbacks = { numeric: (a: number, b: number) => a - b, stringNumeric: (a: string, b: string) => parseInt(a) - parseInt(b), alphaNumeric: (a: string, b: string) => a.localeCompare(b), @@ -15,13 +23,13 @@ const sortingCallbacks: { [key: string]: (a: any, b: any) => number } = { }; // Utility function to access nested properties by key path -function getNestedValue(obj: T, keyPath: string): any { +function getNestedValue(obj: T, keyPath: string): SortingType { return keyPath .split('.') .reduce((value: any, key: string) => value[key], obj); } -export function sortAssets(array: T[], criteria: SortCriteria): T[] { +export function sortAssets(array: T[], criteria: SortCriteria): T[] { const { key, order = 'asc', sortCallback } = criteria; return [...array].sort((a, b) => { @@ -30,8 +38,10 @@ export function sortAssets(array: T[], criteria: SortCriteria): T[] { let comparison: number; - if (sortCallback && sortingCallbacks[sortCallback]) { - comparison = sortingCallbacks[sortCallback](aValue, bValue); + let callback = sortingCallbacks[sortCallback]; + + if (sortCallback && callback) { + comparison = callback(aValue, bValue); } else { comparison = aValue < bValue ? -1 : aValue > bValue ? 1 : 0; } From 0ea31d0bc483529caaa807c56b85b06666e02b62 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Fri, 13 Sep 2024 14:57:38 -0700 Subject: [PATCH 022/151] Add refinements to sorting logic --- .../asset-list/sort-control/sort-control.tsx | 10 +- ui/components/app/assets/util/sort.test.ts | 256 +++++++++++++++--- ui/components/app/assets/util/sort.ts | 58 ++-- .../token-list-item/token-list-item.tsx | 5 +- 4 files changed, 268 insertions(+), 61 deletions(-) diff --git a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx index a2eeee3938e0..03246eda1575 100644 --- a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx +++ b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx @@ -2,7 +2,7 @@ import React, { useState, ReactNode } from 'react'; import classnames from 'classnames'; import { Box } from '../../../../component-library'; import { TokenWithBalance } from '../asset-list'; -import { SortOrder, sortAssets } from '../../util/sort'; +import { SortOrder, SortingCallbacksT, sortAssets } from '../../util/sort'; import { BackgroundColor, BorderRadius, @@ -56,7 +56,11 @@ const SortControl = ({ }: SortControlProps) => { const [sortKey, setSortKey] = useState(null); - const handleSort = (key: string, sortCallback: string, order: SortOrder) => { + const handleSort = ( + key: string, + sortCallback: keyof SortingCallbacksT, + order: SortOrder, + ) => { setSortKey(key); const sorted = sortAssets(tokenList, { key, @@ -71,7 +75,7 @@ const SortControl = ({ <> handleSort('symbol', 'alphanumeric', 'asc')} + onClick={() => handleSort('symbol', 'alphaNumeric', 'asc')} > Alphabetically (A-Z) diff --git a/ui/components/app/assets/util/sort.test.ts b/ui/components/app/assets/util/sort.test.ts index 0cca2389b269..34efdd7c9a3f 100644 --- a/ui/components/app/assets/util/sort.test.ts +++ b/ui/components/app/assets/util/sort.test.ts @@ -4,76 +4,264 @@ import { sortAssets } from './sort'; // Define the MockAsset type for the test type MockAsset = { name: string; - balance: number; + balance: string; + createdAt: Date; // Added date for testing date sorting profile: { - lastUpdated: Date; + id: string; + info?: { + category?: string; + }; }; }; -// Test data with balance at the root of MockAsset +// Test data with profile.id as a nested value in MockAsset +// Test data with profile.id as a nested value in MockAsset and createdAt as a date const mockAssets: MockAsset[] = [ { name: 'Asset Z', - balance: 500, - profile: { lastUpdated: new Date('2023-01-01') }, + balance: '500', + createdAt: new Date('2023-01-01'), // Added date + profile: { id: '1', info: { category: 'gold' } }, }, { name: 'Asset A', - balance: 400, - profile: { lastUpdated: new Date('2023-02-01') }, + balance: '600', + createdAt: new Date('2022-05-15'), // Added date + profile: { id: '4', info: { category: 'silver' } }, }, { name: 'Asset B', - balance: 400, - profile: { lastUpdated: new Date('2023-03-01') }, - }, - { - name: 'Asset Y', - balance: 600, - profile: { lastUpdated: new Date('2023-04-01') }, + balance: '400', + createdAt: new Date('2021-07-20'), // Added date + profile: { id: '2', info: { category: 'bronze' } }, }, ]; // Define the sorting tests -describe('sortAssets function', () => { - test('should sort by balance in descending order', () => { - const sortedByBalance = sortAssets(mockAssets, { +describe('sortAssets function - nested value handling with dates and numeric sorting', () => { + test('sorts by name in ascending order', () => { + const sortedById = sortAssets(mockAssets, { + key: 'name', + sortCallback: 'alphaNumeric', + order: 'asc', + }); + + expect(sortedById[0].name).toBe('Asset A'); + expect(sortedById[sortedById.length - 1].name).toBe('Asset Z'); + }); + + test('sorts by balance in ascending order (stringNumeric)', () => { + const sortedById = sortAssets(mockAssets, { + key: 'balance', + sortCallback: 'stringNumeric', + order: 'asc', + }); + + expect(sortedById[0].balance).toBe('400'); + expect(sortedById[sortedById.length - 1].balance).toBe('600'); + }); + + test('sorts by balance in ascending order (numeric)', () => { + const sortedById = sortAssets(mockAssets, { key: 'balance', - sortCallback: 'alphanumeric', + sortCallback: 'numeric', + order: 'asc', + }); + + expect(sortedById[0].balance).toBe('400'); + expect(sortedById[sortedById.length - 1].balance).toBe('600'); + }); + + test('sorts by profile.id in ascending order', () => { + const sortedById = sortAssets(mockAssets, { + key: 'profile.id', + sortCallback: 'stringNumeric', + order: 'asc', + }); + + expect(sortedById[0].profile.id).toBe('1'); + expect(sortedById[sortedById.length - 1].profile.id).toBe('4'); + }); + + test('sorts by profile.id in descending order', () => { + const sortedById = sortAssets(mockAssets, { + key: 'profile.id', + sortCallback: 'stringNumeric', order: 'dsc', }); - // The first item should have the highest balance - expect(sortedByBalance[0].balance).toBe(600); - // The last item should have the lowest balance - expect(sortedByBalance[sortedByBalance.length - 1].balance).toBe(400); + expect(sortedById[0].profile.id).toBe('4'); + expect(sortedById[sortedById.length - 1].profile.id).toBe('1'); + }); + + test('sorts by deeply nested profile.info.category in ascending order', () => { + const sortedByCategory = sortAssets(mockAssets, { + key: 'profile.info.category', + sortCallback: 'alphaNumeric', + order: 'asc', + }); + + // Expecting the assets with defined categories to be sorted first + expect(sortedByCategory[0].profile.info?.category).toBe('bronze'); + expect( + sortedByCategory[sortedByCategory.length - 1].profile.info?.category, + ).toBe('silver'); }); - test('should sort by lastUpdated (date) in ascending order', () => { + test('sorts by createdAt (date) in ascending order', () => { const sortedByDate = sortAssets(mockAssets, { - key: 'profile.lastUpdated', + key: 'createdAt', sortCallback: 'date', order: 'asc', }); - // The first item should have the earliest date - expect(sortedByDate[0].profile.lastUpdated).toEqual(new Date('2023-01-01')); - // The last item should have the latest date - expect(sortedByDate[sortedByDate.length - 1].profile.lastUpdated).toEqual( - new Date('2023-04-01'), + expect(sortedByDate[0].createdAt).toEqual(new Date('2021-07-20')); + expect(sortedByDate[sortedByDate.length - 1].createdAt).toEqual( + new Date('2023-01-01'), ); }); - test('should sort by name in alphabetical order', () => { - const sortedByName = sortAssets(mockAssets, { + test('sorts by createdAt (date) in descending order', () => { + const sortedByDate = sortAssets(mockAssets, { + key: 'createdAt', + sortCallback: 'date', + order: 'dsc', + }); + + expect(sortedByDate[0].createdAt).toEqual(new Date('2023-01-01')); + expect(sortedByDate[sortedByDate.length - 1].createdAt).toEqual( + new Date('2021-07-20'), + ); + }); + + test('handles undefined deeply nested value gracefully when sorting', () => { + const invlaidAsset = { + name: 'Asset Y', + balance: '600', + createdAt: new Date('2024-01-01'), // Added date + profile: { id: '3' }, // No category info + }; + const sortedByCategory = sortAssets([...mockAssets, invlaidAsset], { + key: 'profile.info.category', + sortCallback: 'alphaNumeric', + order: 'asc', + }); + + // Expect the undefined categories to be at the end + expect( + // @ts-ignore // testing for undefined value + sortedByCategory[sortedByCategory.length - 1].profile.info?.category, + ).toBeUndefined(); + }); +}); + +// Utility function to generate large mock data +function generateLargeMockData(size: number): MockAsset[] { + const mockData: MockAsset[] = []; + for (let i = 0; i < size; i++) { + mockData.push({ + name: `Asset ${String.fromCharCode(65 + (i % 26))}`, + balance: `${Math.floor(Math.random() * 1000)}`, // Random balance between 0 and 999 + createdAt: new Date(Date.now() - Math.random() * 10000000000), // Random date within the past ~115 days + profile: { + id: `${i + 1}`, + info: { + category: ['gold', 'silver', 'bronze'][i % 3], // Cycles between 'gold', 'silver', 'bronze' + }, + }, + }); + } + return mockData; +} + +// Generate a large dataset for testing +const largeDataset = generateLargeMockData(10000); // 10,000 mock assets + +// Define the sorting tests for large datasets +describe('sortAssets function - large dataset handling', () => { + const MAX_EXECUTION_TIME_MS = 500; // Set max allowed execution time (in milliseconds) + + test('sorts large dataset by name in ascending order', () => { + const startTime = Date.now(); + const sortedByName = sortAssets(largeDataset, { key: 'name', - sortCallback: 'string', + sortCallback: 'alphaNumeric', order: 'asc', }); - // The first item should be Asset A (alphabetically first) + const endTime = Date.now(); + const executionTime = endTime - startTime; + expect(sortedByName[0].name).toBe('Asset A'); - // The last item should be Asset Z (alphabetically last) expect(sortedByName[sortedByName.length - 1].name).toBe('Asset Z'); + expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); // Ensure execution time is under limit + }); + + test('sorts large dataset by balance in ascending order', () => { + const startTime = Date.now(); + const sortedByBalance = sortAssets(largeDataset, { + key: 'balance', + sortCallback: 'numeric', + order: 'asc', + }); + + const endTime = Date.now(); + const executionTime = endTime - startTime; + + const balances = sortedByBalance.map((asset) => asset.balance); + expect(balances).toEqual( + balances.slice().sort((a, b) => parseInt(a, 10) - parseInt(b, 10)), + ); + expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); // Ensure execution time is under limit + }); + + test('sorts large dataset by balance in descending order', () => { + const startTime = Date.now(); + const sortedByBalance = sortAssets(largeDataset, { + key: 'balance', + sortCallback: 'numeric', + order: 'dsc', + }); + + const endTime = Date.now(); + const executionTime = endTime - startTime; + + const balances = sortedByBalance.map((asset) => asset.balance); + expect(balances).toEqual( + balances.slice().sort((a, b) => parseInt(b, 10) - parseInt(a, 10)), + ); + expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); // Ensure execution time is under limit + }); + + test('sorts large dataset by createdAt (date) in ascending order', () => { + const startTime = Date.now(); + const sortedByDate = sortAssets(largeDataset, { + key: 'createdAt', + sortCallback: 'date', + order: 'asc', + }); + + const endTime = Date.now(); + const executionTime = endTime - startTime; + + const dates = sortedByDate.map((asset) => asset.createdAt.getTime()); + expect(dates).toEqual(dates.slice().sort((a, b) => a - b)); + expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); // Ensure execution time is under limit + }); + + test('sorts large dataset by createdAt (date) in descending order', () => { + const startTime = Date.now(); + const sortedByDate = sortAssets(largeDataset, { + key: 'createdAt', + sortCallback: 'date', + order: 'dsc', + }); + + const endTime = Date.now(); + const executionTime = endTime - startTime; + + const dates = sortedByDate.map((asset) => asset.createdAt.getTime()); + expect(dates).toEqual(dates.slice().sort((a, b) => b - a)); + expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); // Ensure execution time is under limit }); }); diff --git a/ui/components/app/assets/util/sort.ts b/ui/components/app/assets/util/sort.ts index 8026d09012cc..f91d24d30436 100644 --- a/ui/components/app/assets/util/sort.ts +++ b/ui/components/app/assets/util/sort.ts @@ -1,32 +1,33 @@ +import { get } from 'lodash'; + export type SortOrder = 'asc' | 'dsc'; +export type SortCriteria = { + key: string; + order?: 'asc' | 'dsc'; + sortCallback: SortCallbackKeys; +}; + +export type SortingType = number | string | Date; +type SortCallbackKeys = keyof SortingCallbacksT; -type SortingType = number | string | Date; -type SortingCallbacks = { +export type SortingCallbacksT = { numeric: (a: number, b: number) => number; stringNumeric: (a: string, b: string) => number; alphaNumeric: (a: string, b: string) => number; date: (a: Date, b: Date) => number; }; -type SortCallbackKeys = keyof SortingCallbacks; -type SortCriteria = { - key: string; - order?: 'asc' | 'desc'; - sortCallback: SortCallbackKeys; -}; // All sortingCallbacks should be asc order, sortAssets function handles asc/dsc -const sortingCallbacks: SortingCallbacks = { +const sortingCallbacks: SortingCallbacksT = { numeric: (a: number, b: number) => a - b, - stringNumeric: (a: string, b: string) => parseInt(a) - parseInt(b), + stringNumeric: (a: string, b: string) => parseInt(a, 10) - parseInt(b, 10), alphaNumeric: (a: string, b: string) => a.localeCompare(b), date: (a: Date, b: Date) => a.getTime() - b.getTime(), }; // Utility function to access nested properties by key path function getNestedValue(obj: T, keyPath: string): SortingType { - return keyPath - .split('.') - .reduce((value: any, key: string) => value[key], obj); + return get(obj, keyPath) as SortingType; } export function sortAssets(array: T[], criteria: SortCriteria): T[] { @@ -36,17 +37,34 @@ export function sortAssets(array: T[], criteria: SortCriteria): T[] { const aValue = getNestedValue(a, key); const bValue = getNestedValue(b, key); - let comparison: number; + // Always move undefined values to the end, regardless of sort order + if (aValue === undefined) return 1; + if (bValue === undefined) return -1; - let callback = sortingCallbacks[sortCallback]; + let comparison: number; - if (sortCallback && callback) { - comparison = callback(aValue, bValue); - } else { - comparison = aValue < bValue ? -1 : aValue > bValue ? 1 : 0; + switch (sortCallback) { + case 'stringNumeric': + case 'alphaNumeric': + comparison = sortingCallbacks[sortCallback]( + aValue as string, + bValue as string, + ); + break; + case 'numeric': + comparison = sortingCallbacks.numeric( + aValue as number, + bValue as number, + ); + break; + case 'date': + comparison = sortingCallbacks.date(aValue as Date, bValue as Date); + break; + default: + comparison = aValue < bValue ? -1 : aValue > bValue ? 1 : 0; } - // modify to sort in asc or dsc order + // Modify to sort in ascending or descending order return order === 'asc' ? comparison : -comparison; }); } diff --git a/ui/components/multichain/token-list-item/token-list-item.tsx b/ui/components/multichain/token-list-item/token-list-item.tsx index 78ca5e501ebf..c227a1806245 100644 --- a/ui/components/multichain/token-list-item/token-list-item.tsx +++ b/ui/components/multichain/token-list-item/token-list-item.tsx @@ -422,10 +422,7 @@ export const TokenListItem = ({ if (isFullScreen) { history.push(NETWORKS_ROUTE); } else { - global.platform && - typeof global.platform.openExtensionInBrowser === - 'function' && - global.platform.openExtensionInBrowser(NETWORKS_ROUTE); + global.platform.openExtensionInBrowser?.(NETWORKS_ROUTE); } }} block From 94d0dd8a602956c2e00b61defc8eda5cedac842d Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Fri, 13 Sep 2024 15:02:52 -0700 Subject: [PATCH 023/151] Cleanup mocks --- ui/components/app/assets/util/sort.test.ts | 24 +++++++++------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/ui/components/app/assets/util/sort.test.ts b/ui/components/app/assets/util/sort.test.ts index 34efdd7c9a3f..58e0a8f6f89c 100644 --- a/ui/components/app/assets/util/sort.test.ts +++ b/ui/components/app/assets/util/sort.test.ts @@ -1,11 +1,9 @@ -// Import necessary modules (assuming your function is in 'sort.ts') import { sortAssets } from './sort'; -// Define the MockAsset type for the test type MockAsset = { name: string; balance: string; - createdAt: Date; // Added date for testing date sorting + createdAt: Date; profile: { id: string; info?: { @@ -14,25 +12,23 @@ type MockAsset = { }; }; -// Test data with profile.id as a nested value in MockAsset -// Test data with profile.id as a nested value in MockAsset and createdAt as a date const mockAssets: MockAsset[] = [ { name: 'Asset Z', balance: '500', - createdAt: new Date('2023-01-01'), // Added date + createdAt: new Date('2023-01-01'), profile: { id: '1', info: { category: 'gold' } }, }, { name: 'Asset A', balance: '600', - createdAt: new Date('2022-05-15'), // Added date + createdAt: new Date('2022-05-15'), profile: { id: '4', info: { category: 'silver' } }, }, { name: 'Asset B', balance: '400', - createdAt: new Date('2021-07-20'), // Added date + createdAt: new Date('2021-07-20'), profile: { id: '2', info: { category: 'bronze' } }, }, ]; @@ -138,7 +134,7 @@ describe('sortAssets function - nested value handling with dates and numeric sor const invlaidAsset = { name: 'Asset Y', balance: '600', - createdAt: new Date('2024-01-01'), // Added date + createdAt: new Date('2024-01-01'), profile: { id: '3' }, // No category info }; const sortedByCategory = sortAssets([...mockAssets, invlaidAsset], { @@ -194,7 +190,7 @@ describe('sortAssets function - large dataset handling', () => { expect(sortedByName[0].name).toBe('Asset A'); expect(sortedByName[sortedByName.length - 1].name).toBe('Asset Z'); - expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); // Ensure execution time is under limit + expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); }); test('sorts large dataset by balance in ascending order', () => { @@ -212,7 +208,7 @@ describe('sortAssets function - large dataset handling', () => { expect(balances).toEqual( balances.slice().sort((a, b) => parseInt(a, 10) - parseInt(b, 10)), ); - expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); // Ensure execution time is under limit + expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); }); test('sorts large dataset by balance in descending order', () => { @@ -230,7 +226,7 @@ describe('sortAssets function - large dataset handling', () => { expect(balances).toEqual( balances.slice().sort((a, b) => parseInt(b, 10) - parseInt(a, 10)), ); - expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); // Ensure execution time is under limit + expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); }); test('sorts large dataset by createdAt (date) in ascending order', () => { @@ -246,7 +242,7 @@ describe('sortAssets function - large dataset handling', () => { const dates = sortedByDate.map((asset) => asset.createdAt.getTime()); expect(dates).toEqual(dates.slice().sort((a, b) => a - b)); - expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); // Ensure execution time is under limit + expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); }); test('sorts large dataset by createdAt (date) in descending order', () => { @@ -262,6 +258,6 @@ describe('sortAssets function - large dataset handling', () => { const dates = sortedByDate.map((asset) => asset.createdAt.getTime()); expect(dates).toEqual(dates.slice().sort((a, b) => b - a)); - expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); // Ensure execution time is under limit + expect(executionTime).toBeLessThan(MAX_EXECUTION_TIME_MS); }); }); From 66d9da17e09f37441e8881355bd2d4f528a22b62 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 07:16:32 -0700 Subject: [PATCH 024/151] Init native token inclusion --- .../app/assets/asset-list/asset-list.tsx | 37 ++++++++++++++++++- .../token-list-item/token-list-item.test.tsx | 26 +++++++------ 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index 7fae84deff9a..bcc56280a441 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -54,9 +54,15 @@ import AssetListControlBar from './asset-list-control-bar'; export type TokenWithBalance = { address: string; symbol: string; - string: string; + string?: string; image: string; tokenFiatAmount?: string; + // bottom is for Native token + title?: string; + isOriginalTokenSymbol?: boolean | null; + isNativeCurrency?: boolean; + isStakeable?: boolean; + showPercentage?: boolean; }; type AssetListProps = { @@ -145,6 +151,33 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { isStakeable = false; ///: END:ONLY_INCLUDE_IF + const nativeTokenWithBalance: TokenWithBalance = { + title: nativeCurrency, + address: '', + symbol: nativeCurrency, + string: showSecondaryCurrency( + isOriginalNativeSymbol, + useNativeCurrencyAsPrimaryCurrency, + ) + ? secondaryCurrencyDisplay + : undefined, + image: primaryTokenImage, + tokenFiatAmount: + showFiat && + showPrimaryCurrency( + isOriginalNativeSymbol, + useNativeCurrencyAsPrimaryCurrency, + ) + ? primaryCurrencyDisplay + : undefined, + isOriginalTokenSymbol: isOriginalNativeSymbol, + isNativeCurrency: true, + isStakeable: isStakeable, + showPercentage: true, + }; + + console.log('nativeTokenWithBalance: ', nativeTokenWithBalance); + return ( <> {detectedTokens.length > 0 && @@ -211,7 +244,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { showPercentage /> { onClickAsset(tokenAddress); diff --git a/ui/components/multichain/token-list-item/token-list-item.test.tsx b/ui/components/multichain/token-list-item/token-list-item.test.tsx index 18ad27665c9b..e08962a84060 100644 --- a/ui/components/multichain/token-list-item/token-list-item.test.tsx +++ b/ui/components/multichain/token-list-item/token-list-item.test.tsx @@ -51,11 +51,13 @@ describe('TokenListItem', () => { }); const props = { onClick: jest.fn(), + tokenImage: '', + title: '', }; it('should render correctly', () => { const store = configureMockStore()(state); const { getByTestId, container } = renderWithProvider( - undefined} tokenImage="" title="" />, + , store, ); expect(getByTestId('multichain-token-list-item')).toBeDefined(); @@ -65,11 +67,7 @@ describe('TokenListItem', () => { it('should render with custom className', () => { const store = configureMockStore()(state); const { getByTestId } = renderWithProvider( - , + , store, ); expect(getByTestId('multichain-token-list-item')).toHaveClass( @@ -83,9 +81,11 @@ describe('TokenListItem', () => { primary: '11.9751 ETH', isNativeCurrency: true, isOriginalTokenSymbol: false, + tokenImage: '', + title: '', }; const { getByText } = renderWithProvider( - , + , store, ); expect(getByText('11.9751 ETH')).toBeInTheDocument(); @@ -98,9 +98,11 @@ describe('TokenListItem', () => { isNativeCurrency: true, isOriginalTokenSymbol: false, showPercentage: true, + tokenImage: '', + title: '', }; const { getByTestId, getByText } = renderWithProvider( - , + , store, ); @@ -121,10 +123,12 @@ describe('TokenListItem', () => { primary: '11.9751 ETH', isNativeCurrency: true, isOriginalTokenSymbol: false, + tokenImage: '', + title: '', }; const { getByText } = renderWithProvider( - , + , store, ); expect(getByText('11.9751 ETH')).toBeInTheDocument(); @@ -133,7 +137,7 @@ describe('TokenListItem', () => { it('handles click action and fires onClick', () => { const store = configureMockStore()(state); const { queryByTestId } = renderWithProvider( - , + , store, ); @@ -147,7 +151,7 @@ describe('TokenListItem', () => { it('handles clicking staking opens tab', async () => { const store = configureMockStore()(state); const { queryByTestId } = renderWithProvider( - , + , store, ); From e4179b153839f8c4bd59ae6687f06a459845a6b3 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 10:54:57 -0700 Subject: [PATCH 025/151] Include native token in sorting logic --- .../asset-list-control-bar.tsx | 7 +- .../app/assets/asset-list/asset-list.tsx | 128 ++++-------------- .../assets/asset-list/native-token/index.ts | 1 + .../asset-list/native-token/native-token.tsx | 69 ++++++++++ .../native-token/use-native-balance.ts | 80 +++++++++++ .../asset-list/sort-control/sort-control.tsx | 7 +- .../app/assets/token-cell/token-cell.tsx | 2 +- .../app/assets/token-list/token-list.tsx | 13 +- 8 files changed, 195 insertions(+), 112 deletions(-) create mode 100644 ui/components/app/assets/asset-list/native-token/index.ts create mode 100644 ui/components/app/assets/asset-list/native-token/native-token.tsx create mode 100644 ui/components/app/assets/asset-list/native-token/use-native-balance.ts diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index 305275666f7a..66f7ee0650f7 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -33,12 +33,16 @@ type AssetListControlBarProps = { tokenList: TokenWithBalance[]; setTokenList: (arg: TokenWithBalance[]) => void; setLoading: (arg: boolean) => void; + sorted: boolean; + setSorted: (arg: boolean) => void; }; const AssetListControlBar = ({ tokenList, setTokenList, setLoading, + sorted, + setSorted, }: AssetListControlBarProps) => { const controlBarRef = useRef(null); // Create a ref const [isPopoverOpen, setIsPopoverOpen] = useState(false); @@ -66,8 +70,6 @@ const AssetListControlBar = ({ const { loading } = accountTotalFiatBalance; - const [sorted, setSorted] = useState(false); - useEffect(() => { if (!sorted) { setLoading(loading); @@ -108,6 +110,7 @@ const AssetListControlBar = ({ setLoading(loading); } }, [accountTotalFiatBalance]); + const handleOpenPopover = () => { setIsPopoverOpen(!isPopoverOpen); }; diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index bcc56280a441..40a567921334 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -1,19 +1,16 @@ import React, { useContext, useState } from 'react'; import { useSelector } from 'react-redux'; import TokenList from '../token-list'; -import { PRIMARY, SECONDARY } from '../../../../helpers/constants/common'; +import { PRIMARY } from '../../../../helpers/constants/common'; import { useUserPreferencedCurrency } from '../../../../hooks/useUserPreferencedCurrency'; import { getDetectedTokensInCurrentNetwork, getIstokenDetectionInactiveOnNonMainnetSupportedNetwork, - getPreferences, getSelectedAccount, } from '../../../../selectors'; import { - getMultichainCurrentNetwork, getMultichainNativeCurrency, getMultichainIsEvm, - getMultichainShouldShowFiat, getMultichainCurrencyImage, getMultichainIsMainnet, getMultichainSelectedAccountCachedBalance, @@ -31,16 +28,10 @@ import { import DetectedToken from '../../detected-token/detected-token'; import { DetectedTokensBanner, - TokenListItem, ImportTokenLink, ReceiveModal, } from '../../../multichain'; -import { useIsOriginalNativeTokenSymbol } from '../../../../hooks/useIsOriginalNativeTokenSymbol'; import { useI18nContext } from '../../../../hooks/useI18nContext'; -import { - showPrimaryCurrency, - showSecondaryCurrency, -} from '../../../../../shared/modules/currency-display.utils'; import { FundingMethodModal } from '../../../multichain/funding-method-modal/funding-method-modal'; ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) import { @@ -49,70 +40,47 @@ import { } from '../../../multichain/ramps-card/ramps-card'; import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; import AssetListControlBar from './asset-list-control-bar'; +import { useNativeTokenBalance } from './native-token/use-native-balance'; +import NativeToken from './native-token'; ///: END:ONLY_INCLUDE_IF export type TokenWithBalance = { address: string; symbol: string; - string?: string; + string: string; image: string; - tokenFiatAmount?: string; - // bottom is for Native token - title?: string; - isOriginalTokenSymbol?: boolean | null; - isNativeCurrency?: boolean; - isStakeable?: boolean; - showPercentage?: boolean; + tokenFiatAmount: string; + isNative?: boolean; }; -type AssetListProps = { +export type AssetListProps = { onClickAsset: (arg: string) => void; - showTokensLinks: boolean; + showTokensLinks?: boolean; }; const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const [tokenList, setTokenList] = useState([]); const [loading, setLoading] = useState(false); + const [sorted, setSorted] = useState(false); // TODO: Set to preferences const [showDetectedTokens, setShowDetectedTokens] = useState(false); const selectedAccount = useSelector(getSelectedAccount); const nativeCurrency = useSelector(getMultichainNativeCurrency); - const showFiat = useSelector(getMultichainShouldShowFiat); const isMainnet = useSelector(getMultichainIsMainnet); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); - const { chainId, ticker, type, rpcUrl } = useSelector( - getMultichainCurrentNetwork, - ); - const isOriginalNativeSymbol = useIsOriginalNativeTokenSymbol( - chainId, - ticker, - type, - rpcUrl, - ); const t = useI18nContext(); const trackEvent = useContext(MetaMetricsContext); const balance = useSelector(getMultichainSelectedAccountCachedBalance); - const balanceIsLoading = !balance; + const { primaryBalance, secondaryBalance, tokenSymbol } = + useNativeTokenBalance(); const { currency: primaryCurrency, numberOfDecimals: primaryNumberOfDecimals, } = useUserPreferencedCurrency(PRIMARY, { ethNumberOfDecimals: 4 }); - const { - currency: secondaryCurrency, - numberOfDecimals: secondaryNumberOfDecimals, - } = useUserPreferencedCurrency(SECONDARY, { ethNumberOfDecimals: 4 }); - - const [primaryCurrencyDisplay, primaryCurrencyProperties] = - useCurrencyDisplay(balance, { - numberOfDecimals: primaryNumberOfDecimals, - currency: primaryCurrency, - }); - const [secondaryCurrencyDisplay, secondaryCurrencyProperties] = - useCurrencyDisplay(balance, { - numberOfDecimals: secondaryNumberOfDecimals, - currency: secondaryCurrency, - }); + const [_, primaryCurrencyProperties] = useCurrencyDisplay(balance, { + numberOfDecimals: primaryNumberOfDecimals, + currency: primaryCurrency, + }); const primaryTokenImage = useSelector(getMultichainCurrencyImage); const detectedTokens = useSelector(getDetectedTokensInCurrentNetwork) || []; @@ -152,32 +120,14 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { ///: END:ONLY_INCLUDE_IF const nativeTokenWithBalance: TokenWithBalance = { - title: nativeCurrency, address: '', symbol: nativeCurrency, - string: showSecondaryCurrency( - isOriginalNativeSymbol, - useNativeCurrencyAsPrimaryCurrency, - ) - ? secondaryCurrencyDisplay - : undefined, + string: primaryBalance || '', image: primaryTokenImage, - tokenFiatAmount: - showFiat && - showPrimaryCurrency( - isOriginalNativeSymbol, - useNativeCurrencyAsPrimaryCurrency, - ) - ? primaryCurrencyDisplay - : undefined, - isOriginalTokenSymbol: isOriginalNativeSymbol, - isNativeCurrency: true, - isStakeable: isStakeable, - showPercentage: true, + tokenFiatAmount: secondaryBalance || '', + isNative: true, }; - console.log('nativeTokenWithBalance: ', nativeTokenWithBalance); - return ( <> {detectedTokens.length > 0 && @@ -205,46 +155,16 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { ///: END:ONLY_INCLUDE_IF } - - onClickAsset(nativeCurrency)} - title={nativeCurrency} - // The primary and secondary currencies are subject to change based on the user's settings - // TODO: rename this primary/secondary concept here to be more intuitive, regardless of setting - primary={ - showSecondaryCurrency( - isOriginalNativeSymbol, - useNativeCurrencyAsPrimaryCurrency, - ) - ? secondaryCurrencyDisplay - : undefined - } - tokenSymbol={ - useNativeCurrencyAsPrimaryCurrency - ? primaryCurrencyProperties.suffix - : secondaryCurrencyProperties.suffix - } - secondary={ - showFiat && - showPrimaryCurrency( - isOriginalNativeSymbol, - useNativeCurrencyAsPrimaryCurrency, - ) - ? primaryCurrencyDisplay - : undefined - } - tokenImage={balanceIsLoading ? null : primaryTokenImage} - isOriginalTokenSymbol={isOriginalNativeSymbol} - isNativeCurrency - isStakeable={isStakeable} - showPercentage - /> + {!sorted && } } + tokens={tokenList} loading={loading} onTokenClick={(tokenAddress: string) => { onClickAsset(tokenAddress); diff --git a/ui/components/app/assets/asset-list/native-token/index.ts b/ui/components/app/assets/asset-list/native-token/index.ts new file mode 100644 index 000000000000..6feb276bed54 --- /dev/null +++ b/ui/components/app/assets/asset-list/native-token/index.ts @@ -0,0 +1 @@ +export { default } from './native-token'; diff --git a/ui/components/app/assets/asset-list/native-token/native-token.tsx b/ui/components/app/assets/asset-list/native-token/native-token.tsx new file mode 100644 index 000000000000..cf0ee1ee7cdb --- /dev/null +++ b/ui/components/app/assets/asset-list/native-token/native-token.tsx @@ -0,0 +1,69 @@ +import React from 'react'; +import { useSelector } from 'react-redux'; +import { PRIMARY, SECONDARY } from '../../../../../helpers/constants/common'; +import { useUserPreferencedCurrency } from '../../../../../hooks/useUserPreferencedCurrency'; +import { getPreferences } from '../../../../../selectors'; +import { + getMultichainCurrentNetwork, + getMultichainNativeCurrency, + getMultichainIsEvm, + getMultichainShouldShowFiat, + getMultichainCurrencyImage, + getMultichainIsMainnet, + getMultichainSelectedAccountCachedBalance, +} from '../../../../../selectors/multichain'; +import { useCurrencyDisplay } from '../../../../../hooks/useCurrencyDisplay'; +import { TokenListItem } from '../../../../multichain'; +import { useIsOriginalNativeTokenSymbol } from '../../../../../hooks/useIsOriginalNativeTokenSymbol'; +import { + showPrimaryCurrency, + showSecondaryCurrency, +} from '../../../../../../shared/modules/currency-display.utils'; +import { AssetListProps } from '../asset-list'; +import { useNativeTokenBalance } from './use-native-balance'; + +const NativeToken = ({ onClickAsset }: AssetListProps) => { + const nativeCurrency = useSelector(getMultichainNativeCurrency); + const isMainnet = useSelector(getMultichainIsMainnet); + const { chainId, ticker, type, rpcUrl } = useSelector( + getMultichainCurrentNetwork, + ); + const isOriginalNativeSymbol = useIsOriginalNativeTokenSymbol( + chainId, + ticker, + type, + rpcUrl, + ); + const balance = useSelector(getMultichainSelectedAccountCachedBalance); + const balanceIsLoading = !balance; + + const { primaryBalance, secondaryBalance, tokenSymbol } = + useNativeTokenBalance(); + + const primaryTokenImage = useSelector(getMultichainCurrencyImage); + + const isEvm = useSelector(getMultichainIsEvm); + + let isStakeable = isMainnet && isEvm; + ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) + isStakeable = false; + ///: END:ONLY_INCLUDE_IF + return ( + onClickAsset(nativeCurrency)} + title={nativeCurrency} + // The primary and secondary currencies are subject to change based on the user's settings + // TODO: rename this primary/secondary concept here to be more intuitive, regardless of setting + primary={primaryBalance} + tokenSymbol={tokenSymbol} + secondary={secondaryBalance} + tokenImage={balanceIsLoading ? null : primaryTokenImage} + isOriginalTokenSymbol={isOriginalNativeSymbol} + isNativeCurrency + isStakeable={isStakeable} + showPercentage + /> + ); +}; + +export default NativeToken; diff --git a/ui/components/app/assets/asset-list/native-token/use-native-balance.ts b/ui/components/app/assets/asset-list/native-token/use-native-balance.ts new file mode 100644 index 000000000000..8cb5e244564d --- /dev/null +++ b/ui/components/app/assets/asset-list/native-token/use-native-balance.ts @@ -0,0 +1,80 @@ +import { useSelector } from 'react-redux'; +import { + showPrimaryCurrency, + showSecondaryCurrency, +} from '../../../../../../shared/modules/currency-display.utils'; +import { + getMultichainCurrentNetwork, + getMultichainSelectedAccountCachedBalance, + getMultichainShouldShowFiat, +} from '../../../../../selectors/multichain'; +import { getPreferences } from '../../../../../selectors'; +import { useIsOriginalNativeTokenSymbol } from '../../../../../hooks/useIsOriginalNativeTokenSymbol'; +import { PRIMARY, SECONDARY } from '../../../../../helpers/constants/common'; +import { useUserPreferencedCurrency } from '../../../../../hooks/useUserPreferencedCurrency'; +import { useCurrencyDisplay } from '../../../../../hooks/useCurrencyDisplay'; + +export type SafeChain = { + chainId: string; + name: string; + nativeCurrency: { symbol: string }; + rpc: string[]; +}; + +export const useNativeTokenBalance = () => { + const showFiat = useSelector(getMultichainShouldShowFiat); + const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); + const { chainId, ticker, type, rpcUrl } = useSelector( + getMultichainCurrentNetwork, + ); + const isOriginalNativeSymbol = useIsOriginalNativeTokenSymbol( + chainId, + ticker, + type, + rpcUrl, + ); + const balance = useSelector(getMultichainSelectedAccountCachedBalance); + + const { + currency: primaryCurrency, + numberOfDecimals: primaryNumberOfDecimals, + } = useUserPreferencedCurrency(PRIMARY, { ethNumberOfDecimals: 4 }); + const { + currency: secondaryCurrency, + numberOfDecimals: secondaryNumberOfDecimals, + } = useUserPreferencedCurrency(SECONDARY, { ethNumberOfDecimals: 4 }); + + const [primaryCurrencyDisplay, primaryCurrencyProperties] = + useCurrencyDisplay(balance, { + numberOfDecimals: primaryNumberOfDecimals, + currency: primaryCurrency, + }); + + const [secondaryCurrencyDisplay, secondaryCurrencyProperties] = + useCurrencyDisplay(balance, { + numberOfDecimals: secondaryNumberOfDecimals, + currency: secondaryCurrency, + }); + + const primaryBalance = showSecondaryCurrency( + isOriginalNativeSymbol, + useNativeCurrencyAsPrimaryCurrency, + ) + ? secondaryCurrencyDisplay + : undefined; + + const secondaryBalance = + showFiat && + showPrimaryCurrency( + isOriginalNativeSymbol, + useNativeCurrencyAsPrimaryCurrency, + ) + ? primaryCurrencyDisplay + : undefined; + + const tokenSymbol = useNativeCurrencyAsPrimaryCurrency + ? primaryCurrencyProperties.suffix + : secondaryCurrencyProperties.suffix; + + return { primaryBalance, secondaryBalance, tokenSymbol }; +}; diff --git a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx index 03246eda1575..78042f4f511b 100644 --- a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx +++ b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx @@ -61,12 +61,17 @@ const SortControl = ({ sortCallback: keyof SortingCallbacksT, order: SortOrder, ) => { + const [nativeToken] = tokenList.filter((token) => token.isNative); + const nonNativeTokens = tokenList.filter((token) => !token.isNative); + const dedupedTokenList = [nativeToken, ...nonNativeTokens]; + setSortKey(key); - const sorted = sortAssets(tokenList, { + const sorted = sortAssets(dedupedTokenList, { key, sortCallback, order, }); + setSorted(true); setTokenList(sorted); }; diff --git a/ui/components/app/assets/token-cell/token-cell.tsx b/ui/components/app/assets/token-cell/token-cell.tsx index 2cd5cb84b8ab..5f5b43d6c098 100644 --- a/ui/components/app/assets/token-cell/token-cell.tsx +++ b/ui/components/app/assets/token-cell/token-cell.tsx @@ -10,7 +10,7 @@ import { getIntlLocale } from '../../../../ducks/locale/locale'; type TokenCellProps = { address: string; symbol: string; - string: string; + string?: string; image: string; onClick?: (arg: string) => void; }; diff --git a/ui/components/app/assets/token-list/token-list.tsx b/ui/components/app/assets/token-list/token-list.tsx index 194ea2762191..b13d66961b72 100644 --- a/ui/components/app/assets/token-list/token-list.tsx +++ b/ui/components/app/assets/token-list/token-list.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { ReactNode } from 'react'; import TokenCell from '../token-cell'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import { Box } from '../../../component-library'; @@ -11,12 +11,14 @@ import { TokenWithBalance } from '../asset-list/asset-list'; type TokenListProps = { onTokenClick: (arg: string) => void; + nativeToken: ReactNode; tokens: TokenWithBalance[]; loading: boolean; }; export default function TokenList({ onTokenClick, + nativeToken, tokens, loading = false, }: TokenListProps) { @@ -38,9 +40,12 @@ export default function TokenList({ return (
- {tokens.map((tokenData, index) => ( - - ))} + {tokens.map((tokenData, index) => { + if (tokenData?.isNative) { + return nativeToken; + } + return ; + })}
); } From 34b8c620c25f065538aed71a6763841732b56913 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 11:07:02 -0700 Subject: [PATCH 026/151] Fix merge conflict --- ui/components/app/assets/asset-list/asset-list.tsx | 3 +++ ui/components/app/assets/token-cell/token-cell.tsx | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index 40a567921334..6b51671f07d6 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -119,6 +119,9 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { isStakeable = false; ///: END:ONLY_INCLUDE_IF + // we need to calculate these values here in order to sort native token correctly + // native token is computed differently than normal tokens, and is rendered as a ReactNode native-token.tsx + // the data here is passed into sort control along with the other non-native tokens, in order to determine the order of the native token in the larger list list const nativeTokenWithBalance: TokenWithBalance = { address: '', symbol: nativeCurrency, diff --git a/ui/components/app/assets/token-cell/token-cell.tsx b/ui/components/app/assets/token-cell/token-cell.tsx index 8b9f1683019f..5f5b43d6c098 100644 --- a/ui/components/app/assets/token-cell/token-cell.tsx +++ b/ui/components/app/assets/token-cell/token-cell.tsx @@ -10,11 +10,7 @@ import { getIntlLocale } from '../../../../ducks/locale/locale'; type TokenCellProps = { address: string; symbol: string; -<<<<<<< HEAD string?: string; -======= - string: string; ->>>>>>> develop image: string; onClick?: (arg: string) => void; }; From 8dd7e75138c9fcd2c39c73ce8bdd6a90772a708a Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 11:38:00 -0700 Subject: [PATCH 027/151] Lint --- .../app/assets/asset-list/asset-list.tsx | 13 ++----------- .../asset-list/native-token/native-token.tsx | 9 --------- ui/components/app/assets/util/sort.test.ts | 2 +- ui/components/app/assets/util/sort.ts | 17 ++++++++++++++--- 4 files changed, 17 insertions(+), 24 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index 6b51671f07d6..04d938da3cf0 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -9,10 +9,8 @@ import { getSelectedAccount, } from '../../../../selectors'; import { - getMultichainNativeCurrency, getMultichainIsEvm, getMultichainCurrencyImage, - getMultichainIsMainnet, getMultichainSelectedAccountCachedBalance, ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) getMultichainIsBitcoin, @@ -64,8 +62,6 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const [sorted, setSorted] = useState(false); // TODO: Set to preferences const [showDetectedTokens, setShowDetectedTokens] = useState(false); const selectedAccount = useSelector(getSelectedAccount); - const nativeCurrency = useSelector(getMultichainNativeCurrency); - const isMainnet = useSelector(getMultichainIsMainnet); const t = useI18nContext(); const trackEvent = useContext(MetaMetricsContext); const balance = useSelector(getMultichainSelectedAccountCachedBalance); @@ -77,7 +73,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { numberOfDecimals: primaryNumberOfDecimals, } = useUserPreferencedCurrency(PRIMARY, { ethNumberOfDecimals: 4 }); - const [_, primaryCurrencyProperties] = useCurrencyDisplay(balance, { + const [, primaryCurrencyProperties] = useCurrencyDisplay(balance, { numberOfDecimals: primaryNumberOfDecimals, currency: primaryCurrency, }); @@ -114,17 +110,12 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const isBtc = useSelector(getMultichainIsBitcoin); ///: END:ONLY_INCLUDE_IF - let isStakeable = isMainnet && isEvm; - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - isStakeable = false; - ///: END:ONLY_INCLUDE_IF - // we need to calculate these values here in order to sort native token correctly // native token is computed differently than normal tokens, and is rendered as a ReactNode native-token.tsx // the data here is passed into sort control along with the other non-native tokens, in order to determine the order of the native token in the larger list list const nativeTokenWithBalance: TokenWithBalance = { address: '', - symbol: nativeCurrency, + symbol: tokenSymbol || '', string: primaryBalance || '', image: primaryTokenImage, tokenFiatAmount: secondaryBalance || '', diff --git a/ui/components/app/assets/asset-list/native-token/native-token.tsx b/ui/components/app/assets/asset-list/native-token/native-token.tsx index cf0ee1ee7cdb..6f55860c64d6 100644 --- a/ui/components/app/assets/asset-list/native-token/native-token.tsx +++ b/ui/components/app/assets/asset-list/native-token/native-token.tsx @@ -1,24 +1,15 @@ import React from 'react'; import { useSelector } from 'react-redux'; -import { PRIMARY, SECONDARY } from '../../../../../helpers/constants/common'; -import { useUserPreferencedCurrency } from '../../../../../hooks/useUserPreferencedCurrency'; -import { getPreferences } from '../../../../../selectors'; import { getMultichainCurrentNetwork, getMultichainNativeCurrency, getMultichainIsEvm, - getMultichainShouldShowFiat, getMultichainCurrencyImage, getMultichainIsMainnet, getMultichainSelectedAccountCachedBalance, } from '../../../../../selectors/multichain'; -import { useCurrencyDisplay } from '../../../../../hooks/useCurrencyDisplay'; import { TokenListItem } from '../../../../multichain'; import { useIsOriginalNativeTokenSymbol } from '../../../../../hooks/useIsOriginalNativeTokenSymbol'; -import { - showPrimaryCurrency, - showSecondaryCurrency, -} from '../../../../../../shared/modules/currency-display.utils'; import { AssetListProps } from '../asset-list'; import { useNativeTokenBalance } from './use-native-balance'; diff --git a/ui/components/app/assets/util/sort.test.ts b/ui/components/app/assets/util/sort.test.ts index 58e0a8f6f89c..f4a99e31b641 100644 --- a/ui/components/app/assets/util/sort.test.ts +++ b/ui/components/app/assets/util/sort.test.ts @@ -145,7 +145,7 @@ describe('sortAssets function - nested value handling with dates and numeric sor // Expect the undefined categories to be at the end expect( - // @ts-ignore // testing for undefined value + // @ts-expect-error // testing for undefined value sortedByCategory[sortedByCategory.length - 1].profile.info?.category, ).toBeUndefined(); }); diff --git a/ui/components/app/assets/util/sort.ts b/ui/components/app/assets/util/sort.ts index f91d24d30436..5609f7248306 100644 --- a/ui/components/app/assets/util/sort.ts +++ b/ui/components/app/assets/util/sort.ts @@ -38,8 +38,13 @@ export function sortAssets(array: T[], criteria: SortCriteria): T[] { const bValue = getNestedValue(b, key); // Always move undefined values to the end, regardless of sort order - if (aValue === undefined) return 1; - if (bValue === undefined) return -1; + if (aValue === undefined) { + return 1; + } + + if (bValue === undefined) { + return -1; + } let comparison: number; @@ -61,7 +66,13 @@ export function sortAssets(array: T[], criteria: SortCriteria): T[] { comparison = sortingCallbacks.date(aValue as Date, bValue as Date); break; default: - comparison = aValue < bValue ? -1 : aValue > bValue ? 1 : 0; + if (aValue < bValue) { + comparison = -1; + } else if (aValue > bValue) { + comparison = 1; + } else { + comparison = 0; + } } // Modify to sort in ascending or descending order From 7d35d44c8a0534d7366b6d7f8556e5885fc51d4f Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 12:28:42 -0700 Subject: [PATCH 028/151] More linting --- .../app/assets/asset-list/asset-list-control-bar/index.scss | 2 -- ui/components/app/assets/asset-list/sort-control/index.scss | 3 --- 2 files changed, 5 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss b/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss index 052acd24ded9..771b89a9bb3b 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss @@ -1,5 +1,3 @@ - - .asset-list-control-bar { display: flex; justify-content: space-between; diff --git a/ui/components/app/assets/asset-list/sort-control/index.scss b/ui/components/app/assets/asset-list/sort-control/index.scss index f054c7d4f6c0..8e3aacd03ca3 100644 --- a/ui/components/app/assets/asset-list/sort-control/index.scss +++ b/ui/components/app/assets/asset-list/sort-control/index.scss @@ -1,6 +1,3 @@ -// intentionally used generic naming convention for styled selectable list item -// inspired from ui/components/multichain/network-list-item/index.scss -// should probably be broken out into component library .selectable-list-item-wrapper { position: relative; } From 24becef23e1590d9bd94590eb953ba1de7865aaf Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 13:13:03 -0700 Subject: [PATCH 029/151] More liting to fix e2e --- test/e2e/json-rpc/eth_accounts.spec.js | 2 +- .../app/assets/asset-list/asset-list-control-bar/index.scss | 2 +- ui/components/app/assets/asset-list/asset-list.tsx | 2 +- .../app/assets/asset-list/native-token/native-token.tsx | 3 ++- .../{use-native-balance.ts => use-native-token-balance.ts} | 0 ui/components/app/assets/asset-list/sort-control/index.scss | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) rename ui/components/app/assets/asset-list/native-token/{use-native-balance.ts => use-native-token-balance.ts} (100%) diff --git a/test/e2e/json-rpc/eth_accounts.spec.js b/test/e2e/json-rpc/eth_accounts.spec.js index af3568a41208..0fcb48671620 100644 --- a/test/e2e/json-rpc/eth_accounts.spec.js +++ b/test/e2e/json-rpc/eth_accounts.spec.js @@ -7,7 +7,7 @@ const { const FixtureBuilder = require('../fixture-builder'); describe('eth_accounts', function () { - it('executes a eth_accounts json rpc call', async function () { + it.only('executes a eth_accounts json rpc call', async function () { await withFixtures( { dapp: true, diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss b/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss index 771b89a9bb3b..5313ad9ed860 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/index.scss @@ -9,4 +9,4 @@ button:hover { background-color: var(--color-background-hover); } -} \ No newline at end of file +} diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index 04d938da3cf0..c19b7cd9812c 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -38,7 +38,7 @@ import { } from '../../../multichain/ramps-card/ramps-card'; import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; import AssetListControlBar from './asset-list-control-bar'; -import { useNativeTokenBalance } from './native-token/use-native-balance'; +import { useNativeTokenBalance } from './native-token/use-native-token-balance'; import NativeToken from './native-token'; ///: END:ONLY_INCLUDE_IF diff --git a/ui/components/app/assets/asset-list/native-token/native-token.tsx b/ui/components/app/assets/asset-list/native-token/native-token.tsx index 6f55860c64d6..43c5c5424efa 100644 --- a/ui/components/app/assets/asset-list/native-token/native-token.tsx +++ b/ui/components/app/assets/asset-list/native-token/native-token.tsx @@ -11,7 +11,7 @@ import { import { TokenListItem } from '../../../../multichain'; import { useIsOriginalNativeTokenSymbol } from '../../../../../hooks/useIsOriginalNativeTokenSymbol'; import { AssetListProps } from '../asset-list'; -import { useNativeTokenBalance } from './use-native-balance'; +import { useNativeTokenBalance } from './use-native-token-balance'; const NativeToken = ({ onClickAsset }: AssetListProps) => { const nativeCurrency = useSelector(getMultichainNativeCurrency); @@ -39,6 +39,7 @@ const NativeToken = ({ onClickAsset }: AssetListProps) => { ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) isStakeable = false; ///: END:ONLY_INCLUDE_IF + return ( onClickAsset(nativeCurrency)} diff --git a/ui/components/app/assets/asset-list/native-token/use-native-balance.ts b/ui/components/app/assets/asset-list/native-token/use-native-token-balance.ts similarity index 100% rename from ui/components/app/assets/asset-list/native-token/use-native-balance.ts rename to ui/components/app/assets/asset-list/native-token/use-native-token-balance.ts diff --git a/ui/components/app/assets/asset-list/sort-control/index.scss b/ui/components/app/assets/asset-list/sort-control/index.scss index 8e3aacd03ca3..ddf35ed90101 100644 --- a/ui/components/app/assets/asset-list/sort-control/index.scss +++ b/ui/components/app/assets/asset-list/sort-control/index.scss @@ -27,4 +27,4 @@ top: 4px; left: 4px; } -} \ No newline at end of file +} From 70cb82d80797a9e3945658fc5301775c67ae1638 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 13:14:08 -0700 Subject: [PATCH 030/151] Unskip test --- test/e2e/json-rpc/eth_accounts.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/json-rpc/eth_accounts.spec.js b/test/e2e/json-rpc/eth_accounts.spec.js index 0fcb48671620..af3568a41208 100644 --- a/test/e2e/json-rpc/eth_accounts.spec.js +++ b/test/e2e/json-rpc/eth_accounts.spec.js @@ -7,7 +7,7 @@ const { const FixtureBuilder = require('../fixture-builder'); describe('eth_accounts', function () { - it.only('executes a eth_accounts json rpc call', async function () { + it('executes a eth_accounts json rpc call', async function () { await withFixtures( { dapp: true, From 13ee970924359eaeceebdf430fd997fc40b0df04 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 14:44:20 -0700 Subject: [PATCH 031/151] Allow undefined value for Native balance while fetching --- ui/components/app/assets/asset-list/asset-list.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index c19b7cd9812c..8ad30771dced 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -45,9 +45,9 @@ import NativeToken from './native-token'; export type TokenWithBalance = { address: string; symbol: string; - string: string; + string?: string; image: string; - tokenFiatAmount: string; + tokenFiatAmount?: string; isNative?: boolean; }; @@ -116,9 +116,9 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const nativeTokenWithBalance: TokenWithBalance = { address: '', symbol: tokenSymbol || '', - string: primaryBalance || '', + string: primaryBalance, image: primaryTokenImage, - tokenFiatAmount: secondaryBalance || '', + tokenFiatAmount: secondaryBalance, isNative: true, }; From d8815a29ba4348493f18a2ad28c3df50cb26b5c5 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 15:30:35 -0700 Subject: [PATCH 032/151] Add tokenSortCriteria to appState --- .../asset-list-control-bar.tsx | 7 +++++++ .../assets/asset-list/sort-control/sort-control.tsx | 10 ++++++++++ ui/ducks/app/app.ts | 12 ++++++++++++ ui/store/actionConstants.ts | 2 ++ 4 files changed, 31 insertions(+) diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index 66f7ee0650f7..0262f1820c47 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -70,6 +70,13 @@ const AssetListControlBar = ({ const { loading } = accountTotalFiatBalance; + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const appState = useSelector((state: any) => { + return state; + }); + console.log('APP STATE: ', appState); + useEffect(() => { if (!sorted) { setLoading(loading); diff --git a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx index 78042f4f511b..d64f718359c2 100644 --- a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx +++ b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx @@ -7,6 +7,8 @@ import { BackgroundColor, BorderRadius, } from '../../../../../helpers/constants/design-system'; +import { useDispatch } from 'react-redux'; +import { setSortOrderCriteria } from '../../../../../ducks/app/app'; // intentionally used generic naming convention for styled selectable list item // inspired from ui/components/multichain/network-list-item @@ -54,6 +56,7 @@ const SortControl = ({ setTokenList, setSorted, }: SortControlProps) => { + const dispatch = useDispatch(); const [sortKey, setSortKey] = useState(null); const handleSort = ( @@ -73,6 +76,13 @@ const SortControl = ({ }); setSorted(true); + dispatch( + setSortOrderCriteria({ + key, + sortCallback, + order, + }), + ); setTokenList(sorted); }; diff --git a/ui/ducks/app/app.ts b/ui/ducks/app/app.ts index d053b32e4e6e..072f14795e76 100644 --- a/ui/ducks/app/app.ts +++ b/ui/ducks/app/app.ts @@ -5,6 +5,7 @@ import { HardwareTransportStates, } from '../../../shared/constants/hardware-wallets'; import * as actionConstants from '../../store/actionConstants'; +import { SortCriteria } from '../../components/app/assets/util/sort'; type AppState = { shouldClose: boolean; @@ -101,6 +102,7 @@ type AppState = { snapsInstallPrivacyWarningShown: boolean; isAddingNewNetwork: boolean; isMultiRpcOnboarding: boolean; + tokenSortCriteria: undefined | SortCriteria; }; type AppSliceState = { @@ -185,6 +187,7 @@ const initialState: AppState = { snapsInstallPrivacyWarningShown: false, isAddingNewNetwork: false, isMultiRpcOnboarding: false, + tokenSortCriteria: undefined, }; export default function reduceApp( @@ -611,6 +614,11 @@ export default function reduceApp( result: 'none', }, }; + case actionConstants.TOKEN_SORT_CRITERIA: + return { + ...appState, + tokenSortCriteria: { ...action.payload }, + }; ///: END:ONLY_INCLUDE_IF default: @@ -702,3 +710,7 @@ export function getLedgerWebHidConnectedStatus( export function getLedgerTransportStatus(state: AppSliceState): string | null { return state.appState.ledgerTransportStatus; } + +export function setSortOrderCriteria(payload: SortCriteria) { + return { type: actionConstants.TOKEN_SORT_CRITERIA, payload }; +} diff --git a/ui/store/actionConstants.ts b/ui/store/actionConstants.ts index a54a5a220be8..5381b6ff918c 100644 --- a/ui/store/actionConstants.ts +++ b/ui/store/actionConstants.ts @@ -158,3 +158,5 @@ export const HIDE_KEYRING_SNAP_REMOVAL_RESULT = export const SET_SHOW_NFT_AUTO_DETECT_MODAL_UPGRADE = 'SET_SHOW_NFT_AUTO_DETECT_MODAL_UPGRADE'; + +export const TOKEN_SORT_CRITERIA = 'TOKEN_SORT_CRITERIA'; From 91cb3c6eca377e1eabb5358e553bac724acfa9f2 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 17:28:30 -0700 Subject: [PATCH 033/151] setTokenSortConfig works --- .../asset-list-control-bar.tsx | 7 --- .../asset-list/sort-control/sort-control.tsx | 43 ++++++++++--------- ui/ducks/metamask/metamask.js | 1 + ui/store/actions.ts | 6 +++ 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index 0262f1820c47..66f7ee0650f7 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -70,13 +70,6 @@ const AssetListControlBar = ({ const { loading } = accountTotalFiatBalance; - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const appState = useSelector((state: any) => { - return state; - }); - console.log('APP STATE: ', appState); - useEffect(() => { if (!sorted) { setLoading(loading); diff --git a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx index d64f718359c2..fabf049ef071 100644 --- a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx +++ b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx @@ -1,4 +1,5 @@ -import React, { useState, ReactNode } from 'react'; +import React, { useState, ReactNode, useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import classnames from 'classnames'; import { Box } from '../../../../component-library'; import { TokenWithBalance } from '../asset-list'; @@ -7,8 +8,8 @@ import { BackgroundColor, BorderRadius, } from '../../../../../helpers/constants/design-system'; -import { useDispatch } from 'react-redux'; -import { setSortOrderCriteria } from '../../../../../ducks/app/app'; +// import { setSortOrderCriteria } from '../../../../../ducks/app/app'; +import { setTokenSortConfig } from '../../../../../store/actions'; // intentionally used generic naming convention for styled selectable list item // inspired from ui/components/multichain/network-list-item @@ -56,46 +57,46 @@ const SortControl = ({ setTokenList, setSorted, }: SortControlProps) => { + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const tokenSortConfig = useSelector((state: any) => { + return state.metamask.preferences.tokenSortConfig; + }); const dispatch = useDispatch(); - const [sortKey, setSortKey] = useState(null); - const handleSort = ( - key: string, - sortCallback: keyof SortingCallbacksT, - order: SortOrder, - ) => { + useEffect(() => { const [nativeToken] = tokenList.filter((token) => token.isNative); const nonNativeTokens = tokenList.filter((token) => !token.isNative); const dedupedTokenList = [nativeToken, ...nonNativeTokens]; - setSortKey(key); - const sorted = sortAssets(dedupedTokenList, { - key, - sortCallback, - order, - }); - + const sorted = sortAssets(dedupedTokenList, tokenSortConfig); + setTokenList(sorted); setSorted(true); + }, [tokenSortConfig]); + + const handleSort = ( + key: string, + sortCallback: keyof SortingCallbacksT, + order: SortOrder, + ) => { dispatch( - setSortOrderCriteria({ + setTokenSortConfig({ key, sortCallback, order, }), ); - setTokenList(sorted); }; - return ( <> handleSort('symbol', 'alphaNumeric', 'asc')} > Alphabetically (A-Z) handleSort('tokenFiatAmount', 'stringNumeric', 'dsc')} > Declining balance ($ high-low) diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js index e3d16b6fa78d..cf0accb5a5a2 100644 --- a/ui/ducks/metamask/metamask.js +++ b/ui/ducks/metamask/metamask.js @@ -54,6 +54,7 @@ const initialState = { useNativeCurrencyAsPrimaryCurrency: true, petnamesEnabled: true, featureNotificationsEnabled: false, + tokenSortConfig: {}, }, firstTimeFlowType: null, completedOnboarding: false, diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 499acba711bd..fdaeaf70d9b5 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -130,6 +130,7 @@ import { MetaMaskReduxState, TemporaryMessageDataType, } from './store'; +import { SortCriteria } from '../components/app/assets/util/sort'; type CustomGasSettings = { gas?: string; @@ -2989,6 +2990,7 @@ export function setPreference( reject(err); return; } + console.log('updatedPreferences', updatedPreferences); resolve(updatedPreferences as TemporaryPreferenceFlagDef); }, ); @@ -3047,6 +3049,10 @@ export function setRedesignedConfirmationsDeveloperEnabled(value: boolean) { return setPreference('isRedesignedConfirmationsDeveloperEnabled', value); } +export function setTokenSortConfig(value: SortCriteria) { + return setPreference('tokenSortConfig', value); +} + export function setSmartTransactionsOptInStatus( value: boolean, ): ThunkAction { From 663e0aea7201d2068d5d240255ecd0d4826e5c01 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 19:25:25 -0700 Subject: [PATCH 034/151] Subscribe to tokenSortConfig to sort assets --- .../asset-list-control-bar.tsx | 1 + .../app/assets/asset-list/asset-list.tsx | 2 + .../native-token/use-native-token-balance.ts | 7 -- .../asset-list/sort-control/sort-control.tsx | 8 +- .../app/assets/token-list/use-token-list.ts | 85 +++++++++++++++++++ 5 files changed, 93 insertions(+), 10 deletions(-) create mode 100644 ui/components/app/assets/token-list/use-token-list.ts diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index 66f7ee0650f7..4f7667d4a608 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -163,6 +163,7 @@ const AssetListControlBar = ({ tokenList={tokenList} setTokenList={setTokenList} setSorted={setSorted} + sorted={sorted} />
diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index 8ad30771dced..a442d70db3e4 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -40,6 +40,7 @@ import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; import AssetListControlBar from './asset-list-control-bar'; import { useNativeTokenBalance } from './native-token/use-native-token-balance'; import NativeToken from './native-token'; +import { useTokenList } from '../token-list/use-token-list'; ///: END:ONLY_INCLUDE_IF export type TokenWithBalance = { @@ -58,6 +59,7 @@ export type AssetListProps = { const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const [tokenList, setTokenList] = useState([]); + // const { tokenList } = useTokenList(); const [loading, setLoading] = useState(false); const [sorted, setSorted] = useState(false); // TODO: Set to preferences const [showDetectedTokens, setShowDetectedTokens] = useState(false); diff --git a/ui/components/app/assets/asset-list/native-token/use-native-token-balance.ts b/ui/components/app/assets/asset-list/native-token/use-native-token-balance.ts index 8cb5e244564d..71c9502bdca9 100644 --- a/ui/components/app/assets/asset-list/native-token/use-native-token-balance.ts +++ b/ui/components/app/assets/asset-list/native-token/use-native-token-balance.ts @@ -14,13 +14,6 @@ import { PRIMARY, SECONDARY } from '../../../../../helpers/constants/common'; import { useUserPreferencedCurrency } from '../../../../../hooks/useUserPreferencedCurrency'; import { useCurrencyDisplay } from '../../../../../hooks/useCurrencyDisplay'; -export type SafeChain = { - chainId: string; - name: string; - nativeCurrency: { symbol: string }; - rpc: string[]; -}; - export const useNativeTokenBalance = () => { const showFiat = useSelector(getMultichainShouldShowFiat); const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); diff --git a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx index fabf049ef071..a8da49edcc65 100644 --- a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx +++ b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx @@ -1,4 +1,4 @@ -import React, { useState, ReactNode, useEffect } from 'react'; +import React, { ReactNode, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import classnames from 'classnames'; import { Box } from '../../../../component-library'; @@ -10,6 +10,7 @@ import { } from '../../../../../helpers/constants/design-system'; // import { setSortOrderCriteria } from '../../../../../ducks/app/app'; import { setTokenSortConfig } from '../../../../../store/actions'; +// import { useTokenList } from '../../token-list/use-token-list'; // intentionally used generic naming convention for styled selectable list item // inspired from ui/components/multichain/network-list-item @@ -50,6 +51,7 @@ type SortControlProps = { tokenList: TokenWithBalance[]; setTokenList: (arg: TokenWithBalance[]) => void; setSorted: (arg: boolean) => void; + sorted: boolean; }; const SortControl = ({ @@ -69,9 +71,9 @@ const SortControl = ({ const nonNativeTokens = tokenList.filter((token) => !token.isNative); const dedupedTokenList = [nativeToken, ...nonNativeTokens]; - const sorted = sortAssets(dedupedTokenList, tokenSortConfig); - setTokenList(sorted); + const sortedAssets = sortAssets(dedupedTokenList, tokenSortConfig); setSorted(true); + setTokenList(sortedAssets); }, [tokenSortConfig]); const handleSort = ( diff --git a/ui/components/app/assets/token-list/use-token-list.ts b/ui/components/app/assets/token-list/use-token-list.ts new file mode 100644 index 000000000000..80d89f93659e --- /dev/null +++ b/ui/components/app/assets/token-list/use-token-list.ts @@ -0,0 +1,85 @@ +import { useSelector, shallowEqual } from 'react-redux'; +import { useEffect, useState } from 'react'; +import { + getSelectedAccount, + getShouldHideZeroBalanceTokens, + getCurrentCurrency, + getTokenExchangeRates, + getConfirmationExchangeRates, +} from '../../../../selectors'; +import { useAccountTotalFiatBalance } from '../../../../hooks/useAccountTotalFiatBalance'; +import { roundToDecimalPlacesRemovingExtraZeroes } from '../../../../helpers/utils/util'; +import { TokenWithBalance } from '../asset-list/asset-list'; +import { isEqualCaseInsensitive } from '../../../../../shared/modules/string-utils'; +import { getTokenFiatAmount } from '../../../../helpers/utils/token-util'; +import { getConversionRate } from '../../../../ducks/metamask/metamask'; +// import useAccountTotalFiatBalance from './useAccountTotalFiatBalance'; +// import { roundToDecimalPlacesRemovingExtraZeroes, getTokenFiatAmount } from './utils'; +// import isEqualCaseInsensitive from './isEqualCaseInsensitive'; // Assume this is a utility function + +export const useTokenList = () => { + const selectedAccount = useSelector(getSelectedAccount); + const shouldHideZeroBalanceTokens = useSelector( + getShouldHideZeroBalanceTokens, + ); + const conversionRate = useSelector(getConversionRate); + const currentCurrency = useSelector(getCurrentCurrency); + + const contractExchangeRates = useSelector( + getTokenExchangeRates, + shallowEqual, + ); + const confirmationExchangeRates = useSelector(getConfirmationExchangeRates); + const mergedRates = { + ...contractExchangeRates, + ...confirmationExchangeRates, + }; + + const accountTotalFiatBalance = useAccountTotalFiatBalance( + selectedAccount, + shouldHideZeroBalanceTokens, + ); + + const [tokenList, setTokenList] = useState([]); + const [loading, setLoading] = useState(accountTotalFiatBalance.loading); + + useEffect(() => { + console.log('sorting....'); + setLoading(accountTotalFiatBalance.loading); + + const tokensWithBalances = + accountTotalFiatBalance.tokensWithBalances as TokenWithBalance[]; + + tokensWithBalances.forEach((token) => { + token.string = roundToDecimalPlacesRemovingExtraZeroes( + token.string, + 5, + ) as string; + }); + + tokensWithBalances.forEach((token) => { + const contractExchangeTokenKey = Object.keys(mergedRates).find((key) => + isEqualCaseInsensitive(key, token.address), + ); + + const tokenExchangeRate = + contractExchangeTokenKey && mergedRates[contractExchangeTokenKey]; + + token.tokenFiatAmount = + getTokenFiatAmount( + tokenExchangeRate, + conversionRate, + currentCurrency, + token.string, + token.symbol, + false, + false, + ) || '0'; + }); + + setTokenList(tokensWithBalances); + setLoading(accountTotalFiatBalance.loading); + }, [accountTotalFiatBalance, conversionRate, currentCurrency, mergedRates]); + + return { tokenList, setTokenList, loading }; +}; From 77b95157d5e22c43b066e122b9f0123253fabcde Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 19:42:24 -0700 Subject: [PATCH 035/151] Sort order persisting, need to include nativeToken --- .../asset-list-control-bar.tsx | 19 +++++++++++++++++-- .../app/assets/asset-list/asset-list.tsx | 4 ++-- .../asset-list/sort-control/sort-control.tsx | 9 +++++---- .../app/assets/token-list/token-list.tsx | 6 +++--- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index 4f7667d4a608..963583638d5e 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -28,6 +28,7 @@ import { BorderStyle, TextColor, } from '../../../../../helpers/constants/design-system'; +import { sortAssets } from '../../util/sort'; type AssetListControlBarProps = { tokenList: TokenWithBalance[]; @@ -53,6 +54,12 @@ const AssetListControlBar = ({ const conversionRate = useSelector(getConversionRate); const currentCurrency = useSelector(getCurrentCurrency); + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const tokenSortConfig = useSelector((state: any) => { + return state.metamask.preferences.tokenSortConfig; + }); + // tokenExchangeRate const contractExchangeRates = useSelector( getTokenExchangeRates, @@ -70,6 +77,8 @@ const AssetListControlBar = ({ const { loading } = accountTotalFiatBalance; + console.log(tokenList); + useEffect(() => { if (!sorted) { setLoading(loading); @@ -106,10 +115,16 @@ const AssetListControlBar = ({ ) || '0'; }); - setTokenList(tokensWithBalances); + if (tokenSortConfig) { + const sortedTokenList = sortAssets(tokensWithBalances, tokenSortConfig); + setTokenList(sortedTokenList); + } else { + setTokenList(tokensWithBalances); + } + setLoading(loading); } - }, [accountTotalFiatBalance]); + }, [tokenSortConfig]); const handleOpenPopover = () => { setIsPopoverOpen(!isPopoverOpen); diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index a442d70db3e4..db523d3dd7ea 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -151,13 +151,13 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { ///: END:ONLY_INCLUDE_IF } - {!sorted && } + {/* {!sorted && } */} } tokens={tokenList} diff --git a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx index a8da49edcc65..19bd6d7058d5 100644 --- a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx +++ b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx @@ -67,11 +67,12 @@ const SortControl = ({ const dispatch = useDispatch(); useEffect(() => { - const [nativeToken] = tokenList.filter((token) => token.isNative); - const nonNativeTokens = tokenList.filter((token) => !token.isNative); - const dedupedTokenList = [nativeToken, ...nonNativeTokens]; + // const [nativeToken] = tokenList.filter((token) => token.isNative); + // const nonNativeTokens = tokenList.filter((token) => !token.isNative); + // const dedupedTokenList = [nativeToken, ...nonNativeTokens]; - const sortedAssets = sortAssets(dedupedTokenList, tokenSortConfig); + // const sortedAssets = sortAssets(dedupedTokenList, tokenSortConfig); + const sortedAssets = sortAssets(tokenList, tokenSortConfig); setSorted(true); setTokenList(sortedAssets); }, [tokenSortConfig]); diff --git a/ui/components/app/assets/token-list/token-list.tsx b/ui/components/app/assets/token-list/token-list.tsx index b13d66961b72..b4686c20175e 100644 --- a/ui/components/app/assets/token-list/token-list.tsx +++ b/ui/components/app/assets/token-list/token-list.tsx @@ -41,9 +41,9 @@ export default function TokenList({ return (
{tokens.map((tokenData, index) => { - if (tokenData?.isNative) { - return nativeToken; - } + // if (tokenData?.isNative) { + // return nativeToken; + // } return ; })}
From a9d4bd346f8789dace12d2068d36b77e39140e76 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 19:54:40 -0700 Subject: [PATCH 036/151] Fully functional --- .../asset-list-control-bar.tsx | 20 ++++++++++-- .../app/assets/asset-list/asset-list.tsx | 19 ----------- .../asset-list/sort-control/sort-control.tsx | 11 +++---- .../app/assets/token-list/token-list.tsx | 6 ++-- ui/store/actions.ts | 32 ++++++++++++++++++- 5 files changed, 56 insertions(+), 32 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index 963583638d5e..9a05d660cf92 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -29,6 +29,8 @@ import { TextColor, } from '../../../../../helpers/constants/design-system'; import { sortAssets } from '../../util/sort'; +import { useNativeTokenBalance } from '../native-token/use-native-token-balance'; +import { getMultichainCurrencyImage } from '../../../../../selectors/multichain'; type AssetListControlBarProps = { tokenList: TokenWithBalance[]; @@ -77,7 +79,18 @@ const AssetListControlBar = ({ const { loading } = accountTotalFiatBalance; - console.log(tokenList); + const { primaryBalance, secondaryBalance, tokenSymbol } = + useNativeTokenBalance(); + const primaryTokenImage = useSelector(getMultichainCurrencyImage); + + const nativeTokenWithBalance: TokenWithBalance = { + address: '', + symbol: tokenSymbol || '', + string: primaryBalance, + image: primaryTokenImage, + tokenFiatAmount: secondaryBalance, + isNative: true, + }; useEffect(() => { if (!sorted) { @@ -116,7 +129,10 @@ const AssetListControlBar = ({ }); if (tokenSortConfig) { - const sortedTokenList = sortAssets(tokensWithBalances, tokenSortConfig); + const sortedTokenList = sortAssets( + [nativeTokenWithBalance, ...tokensWithBalances], + tokenSortConfig, + ); setTokenList(sortedTokenList); } else { setTokenList(tokensWithBalances); diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index db523d3dd7ea..e5f2f41516c0 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -10,7 +10,6 @@ import { } from '../../../../selectors'; import { getMultichainIsEvm, - getMultichainCurrencyImage, getMultichainSelectedAccountCachedBalance, ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) getMultichainIsBitcoin, @@ -38,9 +37,7 @@ import { } from '../../../multichain/ramps-card/ramps-card'; import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; import AssetListControlBar from './asset-list-control-bar'; -import { useNativeTokenBalance } from './native-token/use-native-token-balance'; import NativeToken from './native-token'; -import { useTokenList } from '../token-list/use-token-list'; ///: END:ONLY_INCLUDE_IF export type TokenWithBalance = { @@ -59,7 +56,6 @@ export type AssetListProps = { const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const [tokenList, setTokenList] = useState([]); - // const { tokenList } = useTokenList(); const [loading, setLoading] = useState(false); const [sorted, setSorted] = useState(false); // TODO: Set to preferences const [showDetectedTokens, setShowDetectedTokens] = useState(false); @@ -67,8 +63,6 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const t = useI18nContext(); const trackEvent = useContext(MetaMetricsContext); const balance = useSelector(getMultichainSelectedAccountCachedBalance); - const { primaryBalance, secondaryBalance, tokenSymbol } = - useNativeTokenBalance(); const { currency: primaryCurrency, @@ -80,7 +74,6 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { currency: primaryCurrency, }); - const primaryTokenImage = useSelector(getMultichainCurrencyImage); const detectedTokens = useSelector(getDetectedTokensInCurrentNetwork) || []; const isTokenDetectionInactiveOnNonMainnetSupportedNetwork = useSelector( getIstokenDetectionInactiveOnNonMainnetSupportedNetwork, @@ -112,18 +105,6 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const isBtc = useSelector(getMultichainIsBitcoin); ///: END:ONLY_INCLUDE_IF - // we need to calculate these values here in order to sort native token correctly - // native token is computed differently than normal tokens, and is rendered as a ReactNode native-token.tsx - // the data here is passed into sort control along with the other non-native tokens, in order to determine the order of the native token in the larger list list - const nativeTokenWithBalance: TokenWithBalance = { - address: '', - symbol: tokenSymbol || '', - string: primaryBalance, - image: primaryTokenImage, - tokenFiatAmount: secondaryBalance, - isNative: true, - }; - return ( <> {detectedTokens.length > 0 && diff --git a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx index 19bd6d7058d5..97aabcd7aee1 100644 --- a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx +++ b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx @@ -8,9 +8,7 @@ import { BackgroundColor, BorderRadius, } from '../../../../../helpers/constants/design-system'; -// import { setSortOrderCriteria } from '../../../../../ducks/app/app'; import { setTokenSortConfig } from '../../../../../store/actions'; -// import { useTokenList } from '../../token-list/use-token-list'; // intentionally used generic naming convention for styled selectable list item // inspired from ui/components/multichain/network-list-item @@ -67,12 +65,11 @@ const SortControl = ({ const dispatch = useDispatch(); useEffect(() => { - // const [nativeToken] = tokenList.filter((token) => token.isNative); - // const nonNativeTokens = tokenList.filter((token) => !token.isNative); - // const dedupedTokenList = [nativeToken, ...nonNativeTokens]; + const [nativeToken] = tokenList.filter((token) => token.isNative); + const nonNativeTokens = tokenList.filter((token) => !token.isNative); + const dedupedTokenList = [nativeToken, ...nonNativeTokens]; - // const sortedAssets = sortAssets(dedupedTokenList, tokenSortConfig); - const sortedAssets = sortAssets(tokenList, tokenSortConfig); + const sortedAssets = sortAssets(dedupedTokenList, tokenSortConfig); setSorted(true); setTokenList(sortedAssets); }, [tokenSortConfig]); diff --git a/ui/components/app/assets/token-list/token-list.tsx b/ui/components/app/assets/token-list/token-list.tsx index b4686c20175e..b13d66961b72 100644 --- a/ui/components/app/assets/token-list/token-list.tsx +++ b/ui/components/app/assets/token-list/token-list.tsx @@ -41,9 +41,9 @@ export default function TokenList({ return (
{tokens.map((tokenData, index) => { - // if (tokenData?.isNative) { - // return nativeToken; - // } + if (tokenData?.isNative) { + return nativeToken; + } return ; })}
diff --git a/ui/store/actions.ts b/ui/store/actions.ts index fdaeaf70d9b5..5d7ecde209ca 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -2998,6 +2998,36 @@ export function setPreference( }; } +export function setPreferenceWithoutLoader( + preference: string, + value: boolean | string | object, +): ThunkAction< + Promise, + MetaMaskReduxState, + unknown, + AnyAction +> { + return (dispatch: MetaMaskReduxDispatch) => { + // dispatch(showLoadingIndication()); + return new Promise((resolve, reject) => { + callBackgroundMethod( + 'setPreference', + [preference, value], + (err, updatedPreferences) => { + // dispatch(hideLoadingIndication()); + if (err) { + dispatch(displayWarning(err)); + reject(err); + return; + } + console.log('updatedPreferences', updatedPreferences); + resolve(updatedPreferences as TemporaryPreferenceFlagDef); + }, + ); + }); + }; +} + export function setDefaultHomeActiveTabName( value: string, ): ThunkAction { @@ -3050,7 +3080,7 @@ export function setRedesignedConfirmationsDeveloperEnabled(value: boolean) { } export function setTokenSortConfig(value: SortCriteria) { - return setPreference('tokenSortConfig', value); + return setPreferenceWithoutLoader('tokenSortConfig', value); } export function setSmartTransactionsOptInStatus( From c8b4526307d3b1970110dd2589723c5c42089786 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 20:21:48 -0700 Subject: [PATCH 037/151] Clean up hooks logic computation into utility files --- .../asset-list-control-bar.tsx | 29 +------- .../use-account-total-fiat-balances.ts | 73 +++++++++++++++++++ .../native-token/use-native-token-balance.ts | 4 +- 3 files changed, 80 insertions(+), 26 deletions(-) create mode 100644 ui/components/app/assets/asset-list/asset-list-control-bar/use-account-total-fiat-balances.ts diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index 9a05d660cf92..01d90ecb0736 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -30,7 +30,7 @@ import { } from '../../../../../helpers/constants/design-system'; import { sortAssets } from '../../util/sort'; import { useNativeTokenBalance } from '../native-token/use-native-token-balance'; -import { getMultichainCurrencyImage } from '../../../../../selectors/multichain'; +import { useAccountTotalFiatBalancesHook } from './use-account-total-fiat-balances'; type AssetListControlBarProps = { tokenList: TokenWithBalance[]; @@ -49,39 +49,18 @@ const AssetListControlBar = ({ }: AssetListControlBarProps) => { const controlBarRef = useRef(null); // Create a ref const [isPopoverOpen, setIsPopoverOpen] = useState(false); - const selectedAccount = useSelector(getSelectedAccount); - const shouldHideZeroBalanceTokens = useSelector( - getShouldHideZeroBalanceTokens, - ); const conversionRate = useSelector(getConversionRate); const currentCurrency = useSelector(getCurrentCurrency); - // TODO: Replace `any` with type // eslint-disable-next-line @typescript-eslint/no-explicit-any const tokenSortConfig = useSelector((state: any) => { return state.metamask.preferences.tokenSortConfig; }); + const { accountTotalFiatBalance, mergedRates, loading } = + useAccountTotalFiatBalancesHook(); - // tokenExchangeRate - const contractExchangeRates = useSelector( - getTokenExchangeRates, - shallowEqual, - ); - const confirmationExchangeRates = useSelector(getConfirmationExchangeRates); - const mergedRates = { - ...contractExchangeRates, - ...confirmationExchangeRates, - }; - const accountTotalFiatBalance = useAccountTotalFiatBalance( - selectedAccount, - shouldHideZeroBalanceTokens, - ); - - const { loading } = accountTotalFiatBalance; - - const { primaryBalance, secondaryBalance, tokenSymbol } = + const { primaryBalance, secondaryBalance, tokenSymbol, primaryTokenImage } = useNativeTokenBalance(); - const primaryTokenImage = useSelector(getMultichainCurrencyImage); const nativeTokenWithBalance: TokenWithBalance = { address: '', diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/use-account-total-fiat-balances.ts b/ui/components/app/assets/asset-list/asset-list-control-bar/use-account-total-fiat-balances.ts new file mode 100644 index 000000000000..4e140f622ba9 --- /dev/null +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/use-account-total-fiat-balances.ts @@ -0,0 +1,73 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { shallowEqual, useSelector } from 'react-redux'; +import { + Box, + ButtonBase, + ButtonBaseSize, + IconName, + Popover, + PopoverPosition, +} from '../../../../component-library'; +import { TokenWithBalance } from '../asset-list'; +import { useAccountTotalFiatBalance } from '../../../../../hooks/useAccountTotalFiatBalance'; +import { + getConfirmationExchangeRates, + getCurrentCurrency, + getSelectedAccount, + getShouldHideZeroBalanceTokens, + getTokenExchangeRates, +} from '../../../../../selectors'; +import { roundToDecimalPlacesRemovingExtraZeroes } from '../../../../../helpers/utils/util'; +import { isEqualCaseInsensitive } from '../../../../../../shared/modules/string-utils'; +import { getConversionRate } from '../../../../../ducks/metamask/metamask'; +import { getTokenFiatAmount } from '../../../../../helpers/utils/token-util'; +import SortControl from '../sort-control'; +import { + BackgroundColor, + BorderColor, + BorderStyle, + TextColor, +} from '../../../../../helpers/constants/design-system'; +import { sortAssets } from '../../util/sort'; +import { useNativeTokenBalance } from '../native-token/use-native-token-balance'; +import { getMultichainCurrencyImage } from '../../../../../selectors/multichain'; + +export const useAccountTotalFiatBalancesHook = () => { + // Selectors from the Redux store + const selectedAccount = useSelector(getSelectedAccount); + const shouldHideZeroBalanceTokens = useSelector( + getShouldHideZeroBalanceTokens, + ); + const conversionRate = useSelector(getConversionRate); + const currentCurrency = useSelector(getCurrentCurrency); + + // Token sort config, replacing `any` with a more appropriate type + const tokenSortConfig = useSelector((state: any) => { + return state.metamask.preferences.tokenSortConfig; + }); + + // Fetching exchange rates from the Redux store + const contractExchangeRates = useSelector( + getTokenExchangeRates, + shallowEqual, + ); + const confirmationExchangeRates = useSelector(getConfirmationExchangeRates); + + // Merging exchange rates + const mergedRates = { + ...contractExchangeRates, + ...confirmationExchangeRates, + }; + + // Getting total fiat balance for the account + const accountTotalFiatBalance = useAccountTotalFiatBalance( + selectedAccount, + shouldHideZeroBalanceTokens, + ); + + return { + accountTotalFiatBalance, + mergedRates, + loading: accountTotalFiatBalance.loading, + }; +}; diff --git a/ui/components/app/assets/asset-list/native-token/use-native-token-balance.ts b/ui/components/app/assets/asset-list/native-token/use-native-token-balance.ts index 71c9502bdca9..0d59fa803119 100644 --- a/ui/components/app/assets/asset-list/native-token/use-native-token-balance.ts +++ b/ui/components/app/assets/asset-list/native-token/use-native-token-balance.ts @@ -4,6 +4,7 @@ import { showSecondaryCurrency, } from '../../../../../../shared/modules/currency-display.utils'; import { + getMultichainCurrencyImage, getMultichainCurrentNetwork, getMultichainSelectedAccountCachedBalance, getMultichainShouldShowFiat, @@ -16,6 +17,7 @@ import { useCurrencyDisplay } from '../../../../../hooks/useCurrencyDisplay'; export const useNativeTokenBalance = () => { const showFiat = useSelector(getMultichainShouldShowFiat); + const primaryTokenImage = useSelector(getMultichainCurrencyImage); const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); const { chainId, ticker, type, rpcUrl } = useSelector( getMultichainCurrentNetwork, @@ -69,5 +71,5 @@ export const useNativeTokenBalance = () => { ? primaryCurrencyProperties.suffix : secondaryCurrencyProperties.suffix; - return { primaryBalance, secondaryBalance, tokenSymbol }; + return { primaryBalance, secondaryBalance, tokenSymbol, primaryTokenImage }; }; From 9e3961ed4fa9c4ffd201953eaa5e23164b55f653 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 20:23:28 -0700 Subject: [PATCH 038/151] Cleanup --- ui/components/app/assets/asset-list/asset-list.tsx | 1 - ui/components/app/assets/token-list/use-token-list.ts | 3 --- ui/store/actions.ts | 2 -- 3 files changed, 6 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index e5f2f41516c0..e946d281bc88 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -138,7 +138,6 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { sorted={sorted} setSorted={setSorted} /> - {/* {!sorted && } */} } tokens={tokenList} diff --git a/ui/components/app/assets/token-list/use-token-list.ts b/ui/components/app/assets/token-list/use-token-list.ts index 80d89f93659e..9d6ac14aed75 100644 --- a/ui/components/app/assets/token-list/use-token-list.ts +++ b/ui/components/app/assets/token-list/use-token-list.ts @@ -13,9 +13,6 @@ import { TokenWithBalance } from '../asset-list/asset-list'; import { isEqualCaseInsensitive } from '../../../../../shared/modules/string-utils'; import { getTokenFiatAmount } from '../../../../helpers/utils/token-util'; import { getConversionRate } from '../../../../ducks/metamask/metamask'; -// import useAccountTotalFiatBalance from './useAccountTotalFiatBalance'; -// import { roundToDecimalPlacesRemovingExtraZeroes, getTokenFiatAmount } from './utils'; -// import isEqualCaseInsensitive from './isEqualCaseInsensitive'; // Assume this is a utility function export const useTokenList = () => { const selectedAccount = useSelector(getSelectedAccount); diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 5d7ecde209ca..74d1afb0b2a2 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -3008,13 +3008,11 @@ export function setPreferenceWithoutLoader( AnyAction > { return (dispatch: MetaMaskReduxDispatch) => { - // dispatch(showLoadingIndication()); return new Promise((resolve, reject) => { callBackgroundMethod( 'setPreference', [preference, value], (err, updatedPreferences) => { - // dispatch(hideLoadingIndication()); if (err) { dispatch(displayWarning(err)); reject(err); From 6f6436564427bbe75cb33652174cbec17f9912bb Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Mon, 16 Sep 2024 20:55:00 -0700 Subject: [PATCH 039/151] Cleanup --- .../asset-list-control-bar/asset-list-control-bar.tsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index 01d90ecb0736..c345d53616c4 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useRef, useState } from 'react'; -import { shallowEqual, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import { Box, ButtonBase, @@ -9,14 +9,7 @@ import { PopoverPosition, } from '../../../../component-library'; import { TokenWithBalance } from '../asset-list'; -import { useAccountTotalFiatBalance } from '../../../../../hooks/useAccountTotalFiatBalance'; -import { - getConfirmationExchangeRates, - getCurrentCurrency, - getSelectedAccount, - getShouldHideZeroBalanceTokens, - getTokenExchangeRates, -} from '../../../../../selectors'; +import { getCurrentCurrency } from '../../../../../selectors'; import { roundToDecimalPlacesRemovingExtraZeroes } from '../../../../../helpers/utils/util'; import { isEqualCaseInsensitive } from '../../../../../../shared/modules/string-utils'; import { getConversionRate } from '../../../../../ducks/metamask/metamask'; From b12fb4adddfc315b3e02d0da377688567ba9fe24 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Tue, 17 Sep 2024 08:20:58 -0700 Subject: [PATCH 040/151] Fix lint errors --- .../use-account-total-fiat-balances.ts | 32 ------------------- ui/store/actions.ts | 2 +- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/use-account-total-fiat-balances.ts b/ui/components/app/assets/asset-list/asset-list-control-bar/use-account-total-fiat-balances.ts index 4e140f622ba9..661660b346d6 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/use-account-total-fiat-balances.ts +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/use-account-total-fiat-balances.ts @@ -1,36 +1,11 @@ -import React, { useEffect, useRef, useState } from 'react'; import { shallowEqual, useSelector } from 'react-redux'; -import { - Box, - ButtonBase, - ButtonBaseSize, - IconName, - Popover, - PopoverPosition, -} from '../../../../component-library'; -import { TokenWithBalance } from '../asset-list'; import { useAccountTotalFiatBalance } from '../../../../../hooks/useAccountTotalFiatBalance'; import { getConfirmationExchangeRates, - getCurrentCurrency, getSelectedAccount, getShouldHideZeroBalanceTokens, getTokenExchangeRates, } from '../../../../../selectors'; -import { roundToDecimalPlacesRemovingExtraZeroes } from '../../../../../helpers/utils/util'; -import { isEqualCaseInsensitive } from '../../../../../../shared/modules/string-utils'; -import { getConversionRate } from '../../../../../ducks/metamask/metamask'; -import { getTokenFiatAmount } from '../../../../../helpers/utils/token-util'; -import SortControl from '../sort-control'; -import { - BackgroundColor, - BorderColor, - BorderStyle, - TextColor, -} from '../../../../../helpers/constants/design-system'; -import { sortAssets } from '../../util/sort'; -import { useNativeTokenBalance } from '../native-token/use-native-token-balance'; -import { getMultichainCurrencyImage } from '../../../../../selectors/multichain'; export const useAccountTotalFiatBalancesHook = () => { // Selectors from the Redux store @@ -38,13 +13,6 @@ export const useAccountTotalFiatBalancesHook = () => { const shouldHideZeroBalanceTokens = useSelector( getShouldHideZeroBalanceTokens, ); - const conversionRate = useSelector(getConversionRate); - const currentCurrency = useSelector(getCurrentCurrency); - - // Token sort config, replacing `any` with a more appropriate type - const tokenSortConfig = useSelector((state: any) => { - return state.metamask.preferences.tokenSortConfig; - }); // Fetching exchange rates from the Redux store const contractExchangeRates = useSelector( diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 74d1afb0b2a2..d356d1779f41 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -116,6 +116,7 @@ import { getMethodDataAsync } from '../../shared/lib/four-byte'; import { DecodedTransactionDataResponse } from '../../shared/types/transaction-decode'; import { LastInteractedConfirmationInfo } from '../pages/confirmations/types/confirm'; import { EndTraceRequest } from '../../shared/lib/trace'; +import { SortCriteria } from '../components/app/assets/util/sort'; import * as actionConstants from './actionConstants'; ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) import { updateCustodyState } from './institutional/institution-actions'; @@ -130,7 +131,6 @@ import { MetaMaskReduxState, TemporaryMessageDataType, } from './store'; -import { SortCriteria } from '../components/app/assets/util/sort'; type CustomGasSettings = { gas?: string; From 48ca7f9744555939ab259844224e9a266267c088 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Tue, 17 Sep 2024 10:05:22 -0700 Subject: [PATCH 041/151] Move useNativeTokenBalance outside of mmi codefence --- ui/components/app/assets/asset-list/asset-list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index 8ad30771dced..e5427af052da 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -37,10 +37,10 @@ import { RampsCard, } from '../../../multichain/ramps-card/ramps-card'; import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; +///: END:ONLY_INCLUDE_IF import AssetListControlBar from './asset-list-control-bar'; import { useNativeTokenBalance } from './native-token/use-native-token-balance'; import NativeToken from './native-token'; -///: END:ONLY_INCLUDE_IF export type TokenWithBalance = { address: string; From 8ee6bd01679b8a9491c1d83706c283b77d793de7 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Tue, 17 Sep 2024 11:06:55 -0700 Subject: [PATCH 042/151] Move components out of mmi code fence --- ui/components/app/assets/asset-list/asset-list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index e946d281bc88..8ba795cbf4cd 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -36,9 +36,9 @@ import { RampsCard, } from '../../../multichain/ramps-card/ramps-card'; import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; +///: END:ONLY_INCLUDE_IF import AssetListControlBar from './asset-list-control-bar'; import NativeToken from './native-token'; -///: END:ONLY_INCLUDE_IF export type TokenWithBalance = { address: string; From 8d8baca83fa4969b94d9b9465aeec3b0dcceee80 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Tue, 17 Sep 2024 12:38:40 -0700 Subject: [PATCH 043/151] Cleanup loader --- .../asset-list-control-bar/asset-list-control-bar.tsx | 9 +++------ ui/components/app/assets/asset-list/asset-list.tsx | 6 ++++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index c345d53616c4..bde929bf4bff 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -28,7 +28,7 @@ import { useAccountTotalFiatBalancesHook } from './use-account-total-fiat-balanc type AssetListControlBarProps = { tokenList: TokenWithBalance[]; setTokenList: (arg: TokenWithBalance[]) => void; - setLoading: (arg: boolean) => void; + // setLoading: (arg: boolean) => void; sorted: boolean; setSorted: (arg: boolean) => void; }; @@ -36,7 +36,7 @@ type AssetListControlBarProps = { const AssetListControlBar = ({ tokenList, setTokenList, - setLoading, + // setLoading, sorted, setSorted, }: AssetListControlBarProps) => { @@ -49,7 +49,7 @@ const AssetListControlBar = ({ const tokenSortConfig = useSelector((state: any) => { return state.metamask.preferences.tokenSortConfig; }); - const { accountTotalFiatBalance, mergedRates, loading } = + const { accountTotalFiatBalance, mergedRates } = useAccountTotalFiatBalancesHook(); const { primaryBalance, secondaryBalance, tokenSymbol, primaryTokenImage } = @@ -66,7 +66,6 @@ const AssetListControlBar = ({ useEffect(() => { if (!sorted) { - setLoading(loading); const tokensWithBalances = accountTotalFiatBalance.tokensWithBalances as TokenWithBalance[]; @@ -109,8 +108,6 @@ const AssetListControlBar = ({ } else { setTokenList(tokensWithBalances); } - - setLoading(loading); } }, [tokenSortConfig]); diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index 8ba795cbf4cd..df217c7051de 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -39,6 +39,7 @@ import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; ///: END:ONLY_INCLUDE_IF import AssetListControlBar from './asset-list-control-bar'; import NativeToken from './native-token'; +import { useAccountTotalFiatBalancesHook } from './asset-list-control-bar/use-account-total-fiat-balances'; export type TokenWithBalance = { address: string; @@ -56,7 +57,6 @@ export type AssetListProps = { const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const [tokenList, setTokenList] = useState([]); - const [loading, setLoading] = useState(false); const [sorted, setSorted] = useState(false); // TODO: Set to preferences const [showDetectedTokens, setShowDetectedTokens] = useState(false); const selectedAccount = useSelector(getSelectedAccount); @@ -64,6 +64,8 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { const trackEvent = useContext(MetaMetricsContext); const balance = useSelector(getMultichainSelectedAccountCachedBalance); + const { loading } = useAccountTotalFiatBalancesHook(); + const { currency: primaryCurrency, numberOfDecimals: primaryNumberOfDecimals, @@ -134,7 +136,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { From 85337c2fb3cfe9e252846dbf5cd5581a973fb570 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Tue, 17 Sep 2024 13:03:39 -0700 Subject: [PATCH 044/151] Remove uneeded ducks changes --- ui/ducks/app/app.ts | 12 ------------ ui/ducks/metamask/metamask.js | 1 - 2 files changed, 13 deletions(-) diff --git a/ui/ducks/app/app.ts b/ui/ducks/app/app.ts index 072f14795e76..d053b32e4e6e 100644 --- a/ui/ducks/app/app.ts +++ b/ui/ducks/app/app.ts @@ -5,7 +5,6 @@ import { HardwareTransportStates, } from '../../../shared/constants/hardware-wallets'; import * as actionConstants from '../../store/actionConstants'; -import { SortCriteria } from '../../components/app/assets/util/sort'; type AppState = { shouldClose: boolean; @@ -102,7 +101,6 @@ type AppState = { snapsInstallPrivacyWarningShown: boolean; isAddingNewNetwork: boolean; isMultiRpcOnboarding: boolean; - tokenSortCriteria: undefined | SortCriteria; }; type AppSliceState = { @@ -187,7 +185,6 @@ const initialState: AppState = { snapsInstallPrivacyWarningShown: false, isAddingNewNetwork: false, isMultiRpcOnboarding: false, - tokenSortCriteria: undefined, }; export default function reduceApp( @@ -614,11 +611,6 @@ export default function reduceApp( result: 'none', }, }; - case actionConstants.TOKEN_SORT_CRITERIA: - return { - ...appState, - tokenSortCriteria: { ...action.payload }, - }; ///: END:ONLY_INCLUDE_IF default: @@ -710,7 +702,3 @@ export function getLedgerWebHidConnectedStatus( export function getLedgerTransportStatus(state: AppSliceState): string | null { return state.appState.ledgerTransportStatus; } - -export function setSortOrderCriteria(payload: SortCriteria) { - return { type: actionConstants.TOKEN_SORT_CRITERIA, payload }; -} diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js index cf0accb5a5a2..e3d16b6fa78d 100644 --- a/ui/ducks/metamask/metamask.js +++ b/ui/ducks/metamask/metamask.js @@ -54,7 +54,6 @@ const initialState = { useNativeCurrencyAsPrimaryCurrency: true, petnamesEnabled: true, featureNotificationsEnabled: false, - tokenSortConfig: {}, }, firstTimeFlowType: null, completedOnboarding: false, From d7f4cc2c2a0e23eacd64d533649d1035b87c7f0c Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Tue, 17 Sep 2024 13:04:46 -0700 Subject: [PATCH 045/151] More cleanup --- .../asset-list-control-bar/asset-list-control-bar.tsx | 2 -- ui/components/app/assets/asset-list/asset-list.tsx | 1 - 2 files changed, 3 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index bde929bf4bff..deabd031358c 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -28,7 +28,6 @@ import { useAccountTotalFiatBalancesHook } from './use-account-total-fiat-balanc type AssetListControlBarProps = { tokenList: TokenWithBalance[]; setTokenList: (arg: TokenWithBalance[]) => void; - // setLoading: (arg: boolean) => void; sorted: boolean; setSorted: (arg: boolean) => void; }; @@ -36,7 +35,6 @@ type AssetListControlBarProps = { const AssetListControlBar = ({ tokenList, setTokenList, - // setLoading, sorted, setSorted, }: AssetListControlBarProps) => { diff --git a/ui/components/app/assets/asset-list/asset-list.tsx b/ui/components/app/assets/asset-list/asset-list.tsx index df217c7051de..11b52dd6c3a1 100644 --- a/ui/components/app/assets/asset-list/asset-list.tsx +++ b/ui/components/app/assets/asset-list/asset-list.tsx @@ -136,7 +136,6 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { From e7424eef44ad313a028c3c937f099cd72c9563b5 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Tue, 17 Sep 2024 13:07:21 -0700 Subject: [PATCH 046/151] Add tokenSortConfig to e2e fixtureBuilder --- test/e2e/fixture-builder.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js index 357cd95600f4..6836b733fa7f 100644 --- a/test/e2e/fixture-builder.js +++ b/test/e2e/fixture-builder.js @@ -72,6 +72,11 @@ function onboardingFixture() { petnamesEnabled: true, isRedesignedConfirmationsDeveloperEnabled: false, showConfirmationAdvancedDetails: false, + tokenSortConfig: { + key: 'tokenFiatAmount', + order: 'dsc', + sortCriteria: 'stringNumeric', + }, }, useExternalServices: true, theme: 'light', From eb23bfb50321a6fab89851ea52f7c839712bd85d Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Tue, 17 Sep 2024 14:10:37 -0700 Subject: [PATCH 047/151] Integrate import controls --- .../asset-list-control-bar.tsx | 19 ++----- .../import-control/import-control.tsx | 49 +++++++++++++++++++ .../assets/asset-list/import-control/index.ts | 1 + 3 files changed, 54 insertions(+), 15 deletions(-) create mode 100644 ui/components/app/assets/asset-list/import-control/import-control.tsx create mode 100644 ui/components/app/assets/asset-list/import-control/index.ts diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index deabd031358c..152b5f528cd8 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useRef, useState } from 'react'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { Box, ButtonBase, @@ -24,6 +24,8 @@ import { import { sortAssets } from '../../util/sort'; import { useNativeTokenBalance } from '../native-token/use-native-token-balance'; import { useAccountTotalFiatBalancesHook } from './use-account-total-fiat-balances'; +import { showImportTokensModal } from '../../../../../store/actions'; +import ImportControl from '../import-control'; type AssetListControlBarProps = { tokenList: TokenWithBalance[]; @@ -131,20 +133,7 @@ const AssetListControlBar = ({ > Sort By - - Import - + { + const dispatch = useDispatch(); + const trackEvent = useContext(MetaMetricsContext); + + return ( + { + dispatch(showImportTokensModal()); + trackEvent({ + category: MetaMetricsEventCategory.Navigation, + event: MetaMetricsEventName.TokenImportButtonClicked, + properties: { + location: 'HOME', + }, + }); + }} + > + Import + + ); +}; + +export default AssetListControlBar; diff --git a/ui/components/app/assets/asset-list/import-control/index.ts b/ui/components/app/assets/asset-list/import-control/index.ts new file mode 100644 index 000000000000..b871f41ae8b4 --- /dev/null +++ b/ui/components/app/assets/asset-list/import-control/index.ts @@ -0,0 +1 @@ +export { default } from './import-control'; From 95caf84588ad47e4cb70276d743fe2c0892fca4e Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Tue, 17 Sep 2024 14:27:37 -0700 Subject: [PATCH 048/151] Remove existing import token link --- .../asset-list-control-bar.tsx | 7 +-- .../app/assets/asset-list/asset-list.tsx | 6 +-- .../import-control/import-control.tsx | 32 +++++++++++-- .../import-token-link/import-token-link.tsx | 47 ++----------------- 4 files changed, 38 insertions(+), 54 deletions(-) diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index 152b5f528cd8..e345f9f960c8 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -23,15 +23,15 @@ import { } from '../../../../../helpers/constants/design-system'; import { sortAssets } from '../../util/sort'; import { useNativeTokenBalance } from '../native-token/use-native-token-balance'; -import { useAccountTotalFiatBalancesHook } from './use-account-total-fiat-balances'; -import { showImportTokensModal } from '../../../../../store/actions'; import ImportControl from '../import-control'; +import { useAccountTotalFiatBalancesHook } from './use-account-total-fiat-balances'; type AssetListControlBarProps = { tokenList: TokenWithBalance[]; setTokenList: (arg: TokenWithBalance[]) => void; sorted: boolean; setSorted: (arg: boolean) => void; + showTokensLinks?: boolean; }; const AssetListControlBar = ({ @@ -39,6 +39,7 @@ const AssetListControlBar = ({ setTokenList, sorted, setSorted, + showTokensLinks, }: AssetListControlBarProps) => { const controlBarRef = useRef(null); // Create a ref const [isPopoverOpen, setIsPopoverOpen] = useState(false); @@ -133,7 +134,7 @@ const AssetListControlBar = ({ > Sort By - + { ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) const isBuyableChain = useSelector(getIsNativeTokenBuyable); const shouldShowBuy = isBuyableChain && balanceIsZero; + const isBtc = useSelector(getMultichainIsBitcoin); ///: END:ONLY_INCLUDE_IF const isEvm = useSelector(getMultichainIsEvm); @@ -103,10 +104,6 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { // for EVM assets const shouldShowTokensLinks = showTokensLinks ?? isEvm; - ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) - const isBtc = useSelector(getMultichainIsBitcoin); - ///: END:ONLY_INCLUDE_IF - return ( <> {detectedTokens.length > 0 && @@ -138,6 +135,7 @@ const AssetList = ({ onClickAsset, showTokensLinks }: AssetListProps) => { setTokenList={setTokenList} sorted={sorted} setSorted={setSorted} + showTokensLinks={showTokensLinks} /> } diff --git a/ui/components/app/assets/asset-list/import-control/import-control.tsx b/ui/components/app/assets/asset-list/import-control/import-control.tsx index 7d2d3f419096..a93e9f1cd705 100644 --- a/ui/components/app/assets/asset-list/import-control/import-control.tsx +++ b/ui/components/app/assets/asset-list/import-control/import-control.tsx @@ -1,5 +1,5 @@ import React, { useContext } from 'react'; -import { useDispatch } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { ButtonBase, ButtonBaseSize, @@ -17,13 +17,39 @@ import { MetaMetricsEventCategory, MetaMetricsEventName, } from '../../../../../../shared/constants/metametrics'; +import { getMultichainIsEvm } from '../../../../../selectors/multichain'; +import { + getIsTokenDetectionInactiveOnMainnet, + getIsTokenDetectionSupported, +} from '../../../../../selectors'; +import { useI18nContext } from '../../../../../hooks/useI18nContext'; + +type AssetListControlBarProps = { + showTokensLinks?: boolean; +}; -const AssetListControlBar = () => { +const AssetListControlBar = ({ showTokensLinks }: AssetListControlBarProps) => { const dispatch = useDispatch(); const trackEvent = useContext(MetaMetricsContext); + const t = useI18nContext(); + const isTokenDetectionSupported = useSelector(getIsTokenDetectionSupported); + const isTokenDetectionInactiveOnMainnet = useSelector( + getIsTokenDetectionInactiveOnMainnet, + ); + const isEvm = useSelector(getMultichainIsEvm); + // NOTE: Since we can parametrize it now, we keep the original behavior + // for EVM assets + const shouldShowTokensLinks = showTokensLinks ?? isEvm; + + const isTokenDetectionAvailable = + isTokenDetectionSupported || + isTokenDetectionInactiveOnMainnet || + Boolean(process.env.IN_TEST); return ( { }); }} > - Import + {t('import')} ); }; diff --git a/ui/components/multichain/import-token-link/import-token-link.tsx b/ui/components/multichain/import-token-link/import-token-link.tsx index 6c7c9b6a8e6b..022369dd5002 100644 --- a/ui/components/multichain/import-token-link/import-token-link.tsx +++ b/ui/components/multichain/import-token-link/import-token-link.tsx @@ -1,5 +1,5 @@ -import React, { useContext } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import React from 'react'; +import { useDispatch } from 'react-redux'; import classnames from 'classnames'; import { ButtonLink, @@ -9,16 +9,7 @@ import { } from '../../component-library'; import { AlignItems, Display } from '../../../helpers/constants/design-system'; import { useI18nContext } from '../../../hooks/useI18nContext'; -import { detectTokens, showImportTokensModal } from '../../../store/actions'; -import { MetaMetricsContext } from '../../../contexts/metametrics'; -import { - MetaMetricsEventCategory, - MetaMetricsEventName, -} from '../../../../shared/constants/metametrics'; -import { - getIsTokenDetectionSupported, - getIsTokenDetectionInactiveOnMainnet, -} from '../../../selectors'; +import { detectTokens } from '../../../store/actions'; import type { BoxProps } from '../../component-library/box'; import type { ImportTokenLinkProps } from './import-token-link.types'; @@ -26,46 +17,14 @@ export const ImportTokenLink: React.FC = ({ className = '', ...props }): JSX.Element => { - const trackEvent = useContext(MetaMetricsContext); const t = useI18nContext(); const dispatch = useDispatch(); - const isTokenDetectionSupported = useSelector(getIsTokenDetectionSupported); - const isTokenDetectionInactiveOnMainnet = useSelector( - getIsTokenDetectionInactiveOnMainnet, - ); - - const isTokenDetectionAvailable = - isTokenDetectionSupported || - isTokenDetectionInactiveOnMainnet || - Boolean(process.env.IN_TEST); return ( )} > - - { - dispatch(showImportTokensModal()); - trackEvent({ - category: MetaMetricsEventCategory.Navigation, - event: MetaMetricsEventName.TokenImportButtonClicked, - properties: { - location: 'HOME', - }, - }); - }} - > - {isTokenDetectionAvailable - ? t('importTokensCamelCase') - : t('importTokensCamelCase').charAt(0).toUpperCase() + - t('importTokensCamelCase').slice(1)} - - Date: Tue, 17 Sep 2024 14:30:20 -0700 Subject: [PATCH 049/151] Cleanup --- .../asset-list/import-control/import-control.tsx | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/ui/components/app/assets/asset-list/import-control/import-control.tsx b/ui/components/app/assets/asset-list/import-control/import-control.tsx index a93e9f1cd705..588169c817ad 100644 --- a/ui/components/app/assets/asset-list/import-control/import-control.tsx +++ b/ui/components/app/assets/asset-list/import-control/import-control.tsx @@ -18,10 +18,6 @@ import { MetaMetricsEventName, } from '../../../../../../shared/constants/metametrics'; import { getMultichainIsEvm } from '../../../../../selectors/multichain'; -import { - getIsTokenDetectionInactiveOnMainnet, - getIsTokenDetectionSupported, -} from '../../../../../selectors'; import { useI18nContext } from '../../../../../hooks/useI18nContext'; type AssetListControlBarProps = { @@ -32,20 +28,11 @@ const AssetListControlBar = ({ showTokensLinks }: AssetListControlBarProps) => { const dispatch = useDispatch(); const trackEvent = useContext(MetaMetricsContext); const t = useI18nContext(); - const isTokenDetectionSupported = useSelector(getIsTokenDetectionSupported); - const isTokenDetectionInactiveOnMainnet = useSelector( - getIsTokenDetectionInactiveOnMainnet, - ); const isEvm = useSelector(getMultichainIsEvm); // NOTE: Since we can parametrize it now, we keep the original behavior // for EVM assets const shouldShowTokensLinks = showTokensLinks ?? isEvm; - const isTokenDetectionAvailable = - isTokenDetectionSupported || - isTokenDetectionInactiveOnMainnet || - Boolean(process.env.IN_TEST); - return ( Date: Tue, 17 Sep 2024 14:58:25 -0700 Subject: [PATCH 050/151] Add telemetry to sort --- app/scripts/controllers/metametrics.js | 2 ++ shared/constants/metametrics.ts | 2 ++ .../asset-list-control-bar.tsx | 2 +- .../asset-list/sort-control/sort-control.tsx | 16 +++++++++++++++- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/metametrics.js b/app/scripts/controllers/metametrics.js index d815607d27e8..1a7260d5ead8 100644 --- a/app/scripts/controllers/metametrics.js +++ b/app/scripts/controllers/metametrics.js @@ -850,6 +850,8 @@ export default class MetaMetricsController { metamaskState.participateInMetaMetrics, [MetaMetricsUserTrait.HasMarketingConsent]: metamaskState.dataCollectionForMarketing, + [MetaMetricsUserTrait.TokenSortPreference]: + metamaskState.tokenSortConfig.key, }; if (!previousUserTraits) { diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index 502f166c8e91..2dd5caf8804d 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -468,6 +468,7 @@ export enum MetaMetricsUserTrait { MmiIsCustodian = 'mmi_is_custodian', ///: END:ONLY_INCLUDE_IF PetnameAddressCount = 'petname_addresses_count', + TokenSortPreference = 'token_sort_preference', } /** @@ -618,6 +619,7 @@ export enum MetaMetricsEventName { TokenScreenOpened = 'Token Screen Opened', TokenAdded = 'Token Added', TokenRemoved = 'Token Removed', + TokenSortPreference = 'Token Sort Preference', NFTRemoved = 'NFT Removed', TokenDetected = 'Token Detected', TokenHidden = 'Token Hidden', diff --git a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx index e345f9f960c8..13c057d5126f 100644 --- a/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx +++ b/ui/components/app/assets/asset-list/asset-list-control-bar/asset-list-control-bar.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useRef, useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import { Box, ButtonBase, diff --git a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx index 97aabcd7aee1..0176adca4a9d 100644 --- a/ui/components/app/assets/asset-list/sort-control/sort-control.tsx +++ b/ui/components/app/assets/asset-list/sort-control/sort-control.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode, useEffect } from 'react'; +import React, { ReactNode, useContext, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import classnames from 'classnames'; import { Box } from '../../../../component-library'; @@ -9,6 +9,12 @@ import { BorderRadius, } from '../../../../../helpers/constants/design-system'; import { setTokenSortConfig } from '../../../../../store/actions'; +import { MetaMetricsContext } from '../../../../../contexts/metametrics'; +import { + MetaMetricsEventCategory, + MetaMetricsEventName, + MetaMetricsUserTrait, +} from '../../../../../../shared/constants/metametrics'; // intentionally used generic naming convention for styled selectable list item // inspired from ui/components/multichain/network-list-item @@ -57,6 +63,7 @@ const SortControl = ({ setTokenList, setSorted, }: SortControlProps) => { + const trackEvent = useContext(MetaMetricsContext); // TODO: Replace `any` with type // eslint-disable-next-line @typescript-eslint/no-explicit-any const tokenSortConfig = useSelector((state: any) => { @@ -86,6 +93,13 @@ const SortControl = ({ order, }), ); + trackEvent({ + category: MetaMetricsEventCategory.Settings, + event: MetaMetricsEventName.TokenSortPreference, + properties: { + [MetaMetricsUserTrait.TokenSortPreference]: key, + }, + }); }; return ( <> From d5ae8fe5f5fe2d2b443d528a7599a4947da07fb3 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Tue, 17 Sep 2024 15:19:05 -0700 Subject: [PATCH 051/151] Update metametrics unit test --- app/scripts/controllers/metametrics.test.js | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/app/scripts/controllers/metametrics.test.js b/app/scripts/controllers/metametrics.test.js index de75170b8e58..d2c93a481786 100644 --- a/app/scripts/controllers/metametrics.test.js +++ b/app/scripts/controllers/metametrics.test.js @@ -1090,6 +1090,11 @@ describe('MetaMetricsController', function () { }, }, }, + tokenSortConfig: { + key: 'token-sort-key', + order: 'dsc', + sortCriteria: 'stringNumeric', + }, }); expect(traits).toStrictEqual({ @@ -1121,6 +1126,7 @@ describe('MetaMetricsController', function () { ///: BEGIN:ONLY_INCLUDE_IF(petnames) [MetaMetricsUserTrait.PetnameAddressCount]: 3, ///: END:ONLY_INCLUDE_IF + [MetaMetricsUserTrait.TokenSortPreference]: 'token-sort-key', }); }); @@ -1150,6 +1156,11 @@ describe('MetaMetricsController', function () { theme: 'default', useTokenDetection: true, useNativeCurrencyAsPrimaryCurrency: true, + tokenSortConfig: { + key: 'token-sort-key', + order: 'dsc', + sortCriteria: 'stringNumeric', + }, }); const updatedTraits = metaMetricsController._buildUserTraitsObject({ @@ -1177,6 +1188,11 @@ describe('MetaMetricsController', function () { theme: 'default', useTokenDetection: true, useNativeCurrencyAsPrimaryCurrency: false, + tokenSortConfig: { + key: 'token-sort-key', + order: 'dsc', + sortCriteria: 'stringNumeric', + }, }); expect(updatedTraits).toStrictEqual({ @@ -1214,6 +1230,11 @@ describe('MetaMetricsController', function () { theme: 'default', useTokenDetection: true, useNativeCurrencyAsPrimaryCurrency: true, + tokenSortConfig: { + key: 'token-sort-key', + order: 'dsc', + sortCriteria: 'stringNumeric', + }, }); const updatedTraits = metaMetricsController._buildUserTraitsObject({ @@ -1236,6 +1257,11 @@ describe('MetaMetricsController', function () { theme: 'default', useTokenDetection: true, useNativeCurrencyAsPrimaryCurrency: true, + tokenSortConfig: { + key: 'token-sort-key', + order: 'dsc', + sortCriteria: 'stringNumeric', + }, }); expect(updatedTraits).toStrictEqual(null); }); From ed2aba15e27dcc6d8976363287e6d572fa27fa1d Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Tue, 17 Sep 2024 17:58:10 -0700 Subject: [PATCH 052/151] update account-overview-btc.test.tsx --- .../multichain/account-overview/account-overview-btc.test.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/components/multichain/account-overview/account-overview-btc.test.tsx b/ui/components/multichain/account-overview/account-overview-btc.test.tsx index 34cbed54c127..9d265657432b 100644 --- a/ui/components/multichain/account-overview/account-overview-btc.test.tsx +++ b/ui/components/multichain/account-overview/account-overview-btc.test.tsx @@ -40,7 +40,9 @@ describe('AccountOverviewBtc', () => { const { queryByTestId } = render(); expect(queryByTestId('account-overview__asset-tab')).toBeInTheDocument(); - expect(queryByTestId('import-token-button')).not.toBeInTheDocument(); + const button = queryByTestId('import-token-button'); + expect(button).toBeInTheDocument(); // Verify the button is present + expect(button).toBeDisabled(); // Verify the button is disabled // TODO: This one might be required, but we do not really handle tokens for BTC yet... expect(queryByTestId('refresh-list-button')).not.toBeInTheDocument(); }); From 8862bebea6c17631cbbb631a6366751252cf5147 Mon Sep 17 00:00:00 2001 From: Nicholas Gambino Date: Tue, 17 Sep 2024 18:37:56 -0700 Subject: [PATCH 053/151] Fix unit tests and update snapshots --- app/scripts/controllers/metametrics.js | 2 +- .../import-token-link.test.js.snap | 28 ------------------- .../import-token-link.test.js | 7 +++-- .../blockaid-banner-alert.test.js.snap | 12 ++++---- .../hooks/useConfirmationAlertMetrics.test.ts | 8 +++++- 5 files changed, 18 insertions(+), 39 deletions(-) diff --git a/app/scripts/controllers/metametrics.js b/app/scripts/controllers/metametrics.js index 1a7260d5ead8..8c8b871fa0f6 100644 --- a/app/scripts/controllers/metametrics.js +++ b/app/scripts/controllers/metametrics.js @@ -851,7 +851,7 @@ export default class MetaMetricsController { [MetaMetricsUserTrait.HasMarketingConsent]: metamaskState.dataCollectionForMarketing, [MetaMetricsUserTrait.TokenSortPreference]: - metamaskState.tokenSortConfig.key, + metamaskState.tokenSortConfig?.key || '', }; if (!previousUserTraits) { diff --git a/ui/components/multichain/import-token-link/__snapshots__/import-token-link.test.js.snap b/ui/components/multichain/import-token-link/__snapshots__/import-token-link.test.js.snap index 9dd39fea147f..e8fa1e945dba 100644 --- a/ui/components/multichain/import-token-link/__snapshots__/import-token-link.test.js.snap +++ b/ui/components/multichain/import-token-link/__snapshots__/import-token-link.test.js.snap @@ -5,20 +5,6 @@ exports[`Import Token Link should match snapshot for goerli chainId 1`] = ` @@ -236,7 +236,7 @@ exports[`AssetPage should render a native asset 1`] = ` data-testid="multichain-token-list-item-secondary-value" />

0 TEST @@ -352,7 +352,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` data-theme="light" >

@@ -371,7 +371,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` data-theme="light" >
@@ -390,7 +390,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` data-theme="light" >
@@ -409,7 +409,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` data-theme="light" > @@ -427,7 +427,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` data-theme="light" > @@ -446,7 +446,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` data-theme="light" > @@ -515,7 +515,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` class="mm-box mm-box--display-flex" >

@@ -528,7 +528,7 @@ exports[`AssetPage should render an ERC20 asset without prices 1`] = ` data-testid="multichain-token-list-item-secondary-value" />

0 @@ -835,7 +835,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` data-theme="light" > @@ -854,7 +854,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` data-theme="light" > @@ -873,7 +873,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` data-theme="light" > @@ -892,7 +892,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` data-theme="light" > @@ -910,7 +910,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` data-theme="light" > @@ -929,7 +929,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` data-theme="light" > @@ -998,7 +998,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` class="mm-box mm-box--display-flex" >

@@ -1011,7 +1011,7 @@ exports[`AssetPage should render an ERC20 token with prices 1`] = ` data-testid="multichain-token-list-item-secondary-value" />

0 diff --git a/ui/pages/asset/components/asset-page.test.tsx b/ui/pages/asset/components/asset-page.test.tsx index bf616d0aaac9..35721a30a1c2 100644 --- a/ui/pages/asset/components/asset-page.test.tsx +++ b/ui/pages/asset/components/asset-page.test.tsx @@ -49,9 +49,7 @@ describe('AssetPage', () => { }, }, useCurrencyRateCheck: true, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, internalAccounts: { accounts: { 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { diff --git a/ui/pages/asset/components/token-buttons.tsx b/ui/pages/asset/components/token-buttons.tsx index a07cdaca2d48..bb3f129bade8 100644 --- a/ui/pages/asset/components/token-buttons.tsx +++ b/ui/pages/asset/components/token-buttons.tsx @@ -48,7 +48,12 @@ import { JustifyContent, } from '../../../helpers/constants/design-system'; import IconButton from '../../../components/ui/icon-button/icon-button'; -import { Box, Icon, IconName } from '../../../components/component-library'; +import { + Box, + Icon, + IconName, + IconSize, +} from '../../../components/component-library'; ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) import { getIsNativeTokenBuyable } from '../../../ducks/ramps'; ///: END:ONLY_INCLUDE_IF @@ -115,7 +120,11 @@ const TokenButtons = ({ + } label={t('buyAndSell')} data-testid="token-overview-buy" @@ -144,7 +153,11 @@ const TokenButtons = ({ + } label={t('stake')} data-testid="token-overview-mmi-stake" @@ -163,6 +176,7 @@ const TokenButtons = ({ } label={t('portfolio')} @@ -215,6 +229,7 @@ const TokenButtons = ({ } label={t('send')} @@ -229,6 +244,7 @@ const TokenButtons = ({ } onClick={() => { @@ -281,7 +297,11 @@ const TokenButtons = ({ className="token-overview__button" data-testid="token-overview-bridge" Icon={ - + } label={t('bridge')} onClick={() => { diff --git a/ui/pages/confirm-decrypt-message/confirm-decrypt-message.container.js b/ui/pages/confirm-decrypt-message/confirm-decrypt-message.container.js index fd6585381a27..88d7c8deb40b 100644 --- a/ui/pages/confirm-decrypt-message/confirm-decrypt-message.container.js +++ b/ui/pages/confirm-decrypt-message/confirm-decrypt-message.container.js @@ -10,9 +10,7 @@ import { decryptMsgInline, } from '../../store/actions'; import { - conversionRateSelector, getCurrentCurrency, - getPreferences, getTargetAccountWithSendEtherInfo, unconfirmedTransactionsListSelector, } from '../../selectors'; @@ -21,13 +19,12 @@ import { getMostRecentOverviewPage } from '../../ducks/history/history'; import { getNativeCurrency } from '../../ducks/metamask/metamask'; import ConfirmDecryptMessage from './confirm-decrypt-message.component'; +// ConfirmDecryptMessage component is not used in codebase, removing usage of useNativeCurrencyAsPrimaryCurrency function mapStateToProps(state) { const { metamask: { subjectMetadata = {} }, } = state; - const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state); - const unconfirmedTransactions = unconfirmedTransactionsListSelector(state); const txData = cloneDeep(unconfirmedTransactions[0]); @@ -43,9 +40,7 @@ function mapStateToProps(state) { fromAccount, requester: null, requesterAddress: null, - conversionRate: useNativeCurrencyAsPrimaryCurrency - ? null - : conversionRateSelector(state), + conversionRate: null, mostRecentOverviewPage: getMostRecentOverviewPage(state), nativeCurrency: getNativeCurrency(state), currentCurrency: getCurrentCurrency(state), diff --git a/ui/pages/confirm-encryption-public-key/__snapshots__/confirm-encryption-public-key.component.test.js.snap b/ui/pages/confirm-encryption-public-key/__snapshots__/confirm-encryption-public-key.component.test.js.snap index 05cee4e7016f..b6ae6ed60c6f 100644 --- a/ui/pages/confirm-encryption-public-key/__snapshots__/confirm-encryption-public-key.component.test.js.snap +++ b/ui/pages/confirm-encryption-public-key/__snapshots__/confirm-encryption-public-key.component.test.js.snap @@ -208,252 +208,6 @@ exports[`ConfirmDecryptMessage Component should match snapshot when preference i -

- - test - -
- would like your public encryption key. By consenting, this site will be able to compose encrypted messages to you. - -
- - - - - - - -`; - -exports[`ConfirmDecryptMessage Component should match snapshot when preference is Fiat currency 1`] = ` -
-
-
-
-
- Request encryption public key -
-
-
-
-
-
- -
-
- - T - -
- - -
diff --git a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.js b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.js index 1595576a4fac..dd84bea68360 100644 --- a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.js +++ b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.js @@ -10,8 +10,6 @@ import { MetaMetricsEventCategory } from '../../../shared/constants/metametrics' import SiteOrigin from '../../components/ui/site-origin'; import { Numeric } from '../../../shared/modules/Numeric'; import { EtherDenomination } from '../../../shared/constants/common'; -import { formatCurrency } from '../../helpers/utils/confirm-tx.util'; -import { getValueFromWeiHex } from '../../../shared/modules/conversion.utils'; export default class ConfirmEncryptionPublicKey extends Component { static contextTypes = { @@ -34,8 +32,6 @@ export default class ConfirmEncryptionPublicKey extends Component { subjectMetadata: PropTypes.object, mostRecentOverviewPage: PropTypes.string.isRequired, nativeCurrency: PropTypes.string.isRequired, - currentCurrency: PropTypes.string.isRequired, - conversionRate: PropTypes.number, }; renderHeader = () => { @@ -73,30 +69,20 @@ export default class ConfirmEncryptionPublicKey extends Component { renderBalance = () => { const { - conversionRate, nativeCurrency, - currentCurrency, fromAccount: { balance }, } = this.props; const { t } = this.context; - const nativeCurrencyBalance = conversionRate - ? formatCurrency( - getValueFromWeiHex({ - value: balance, - fromCurrency: nativeCurrency, - toCurrency: currentCurrency, - conversionRate, - numberOfDecimals: 6, - toDenomination: EtherDenomination.ETH, - }), - currentCurrency, - ) - : new Numeric(balance, 16, EtherDenomination.WEI) - .toDenomination(EtherDenomination.ETH) - .round(6) - .toBase(10) - .toString(); + const nativeCurrencyBalance = new Numeric( + balance, + 16, + EtherDenomination.WEI, + ) + .toDenomination(EtherDenomination.ETH) + .round(6) + .toBase(10) + .toString(); return (
@@ -104,9 +90,7 @@ export default class ConfirmEncryptionPublicKey extends Component { {`${t('balance')}:`}
- {`${nativeCurrencyBalance} ${ - conversionRate ? currentCurrency?.toUpperCase() : nativeCurrency - }`} + {`${nativeCurrencyBalance} ${nativeCurrency}`}
); diff --git a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js index 771a5a5f5ef7..3edc10e9d313 100644 --- a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js +++ b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js @@ -61,19 +61,6 @@ describe('ConfirmDecryptMessage Component', () => { ).toMatchInlineSnapshot(`"966.987986 ABC"`); }); - it('should match snapshot when preference is Fiat currency', () => { - const { container } = renderWithProvider( - , - store, - ); - - expect(container).toMatchSnapshot(); - expect( - container.querySelector('.request-encryption-public-key__balance-value') - .textContent, - ).toMatchInlineSnapshot(`"1520956.064158 DEF"`); - }); - it('should match snapshot when there is no txData', () => { const newProps = { ...baseProps, diff --git a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.container.js b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.container.js index 489d7d088033..554ba41fdaa4 100644 --- a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.container.js +++ b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.container.js @@ -9,11 +9,8 @@ import { } from '../../store/actions'; import { - conversionRateSelector, unconfirmedTransactionsListSelector, getTargetAccountWithSendEtherInfo, - getPreferences, - getCurrentCurrency, } from '../../selectors'; import { clearConfirmTransaction } from '../../ducks/confirm-transaction/confirm-transaction.duck'; @@ -26,8 +23,6 @@ function mapStateToProps(state) { metamask: { subjectMetadata = {} }, } = state; - const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state); - const unconfirmedTransactions = unconfirmedTransactionsListSelector(state); const txData = unconfirmedTransactions[0]; @@ -43,12 +38,8 @@ function mapStateToProps(state) { fromAccount, requester: null, requesterAddress: null, - conversionRate: useNativeCurrencyAsPrimaryCurrency - ? null - : conversionRateSelector(state), mostRecentOverviewPage: getMostRecentOverviewPage(state), nativeCurrency: getNativeCurrency(state), - currentCurrency: getCurrentCurrency(state), }; } diff --git a/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js b/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js index c80ef735222b..c1d4ae838301 100644 --- a/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js +++ b/ui/pages/confirmations/components/confirm-gas-display/confirm-gas-display.test.js @@ -39,9 +39,7 @@ const render = async ({ transactionProp = {}, contextProps = {} } = {}) => { balance: '0x1F4', }, }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, gasFeeEstimatesByChainId: { diff --git a/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js b/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js index 34440be28693..70d5ed1070f4 100644 --- a/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js +++ b/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js @@ -5,7 +5,6 @@ import { useSelector } from 'react-redux'; import { useI18nContext } from '../../../../../hooks/useI18nContext'; import { getIsMainnet, - getPreferences, getUnapprovedTransactions, getUseCurrencyRateCheck, transactionFeeSelector, @@ -34,7 +33,6 @@ const ConfirmLegacyGasDisplay = ({ 'data-testid': dataTestId } = {}) => { // state selectors const isMainnet = useSelector(getIsMainnet); const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); const unapprovedTxs = useSelector(getUnapprovedTransactions); const transactionData = useDraftTransactionWithTxParams(); const txData = useSelector((state) => txDataSelector(state)); @@ -108,7 +106,7 @@ const ConfirmLegacyGasDisplay = ({ 'data-testid': dataTestId } = {}) => {
) @@ -119,7 +117,6 @@ const ConfirmLegacyGasDisplay = ({ 'data-testid': dataTestId } = {}) => { { key="editGasSubTextFeeAmount" type={PRIMARY} value={estimatedHexMaxFeeTotal} - hideLabel={!useNativeCurrencyAsPrimaryCurrency} />
diff --git a/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.test.js b/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.test.js index df5b9ea0e50f..4952fb87edca 100644 --- a/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.test.js +++ b/ui/pages/confirmations/components/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.test.js @@ -21,9 +21,6 @@ const mmState = { balance: '0x1F4', }, }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, }, confirmTransaction: { txData: { diff --git a/ui/pages/confirmations/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.test.js b/ui/pages/confirmations/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.test.js index 5b1e505ddc14..5d3065e8a3d3 100644 --- a/ui/pages/confirmations/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.test.js +++ b/ui/pages/confirmations/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.test.js @@ -11,9 +11,7 @@ describe('Confirm Detail Row Component', () => { metamask: { currencyRates: {}, ...mockNetworkState({ chainId: CHAIN_IDS.GOERLI }), - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, internalAccounts: defaultMockState.metamask.internalAccounts, }, }; diff --git a/ui/pages/confirmations/components/confirm-subtitle/confirm-subtitle.js b/ui/pages/confirmations/components/confirm-subtitle/confirm-subtitle.js index e1219d299288..da99ade8210c 100644 --- a/ui/pages/confirmations/components/confirm-subtitle/confirm-subtitle.js +++ b/ui/pages/confirmations/components/confirm-subtitle/confirm-subtitle.js @@ -29,7 +29,6 @@ const ConfirmSubTitle = ({ if (subtitleComponent) { return subtitleComponent; } - return ( { const t = useI18nContext(); - const { useNativeCurrencyAsPrimaryCurrency: isNativeCurrencyUsed } = - useSelector(getPreferences); - const { currentConfirmation: transactionMeta } = useConfirmContext(); @@ -56,14 +51,14 @@ export const EditGasFeesRow = ({ color={TextColor.textDefault} data-testid="first-gas-field" > - {isNativeCurrencyUsed ? nativeFee : fiatFee} + {nativeFee} - {isNativeCurrencyUsed ? fiatFee : nativeFee} + {fiatFee} { - const { useNativeCurrencyAsPrimaryCurrency: isNativeCurrencyUsed } = - useSelector(getPreferences); - return ( - {isNativeCurrencyUsed ? nativeFee : fiatFee} - - - {isNativeCurrencyUsed ? fiatFee : nativeFee} + {nativeFee} + {fiatFee} ); diff --git a/ui/pages/confirmations/components/fee-details-component/fee-details-component.js b/ui/pages/confirmations/components/fee-details-component/fee-details-component.js index 19bcc25e445f..84ea244ec8cd 100644 --- a/ui/pages/confirmations/components/fee-details-component/fee-details-component.js +++ b/ui/pages/confirmations/components/fee-details-component/fee-details-component.js @@ -1,6 +1,6 @@ import React, { useCallback, useMemo, useState } from 'react'; -import { useSelector } from 'react-redux'; import PropTypes from 'prop-types'; +import { useSelector } from 'react-redux'; import { AlignItems, Display, @@ -19,7 +19,7 @@ import { Text, } from '../../../../components/component-library'; import TransactionDetailItem from '../transaction-detail-item/transaction-detail-item.component'; -import { getPreferences, getShouldShowFiat } from '../../../../selectors'; +import { getShouldShowFiat } from '../../../../selectors'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import LoadingHeartBeat from '../../../../components/ui/loading-heartbeat'; import UserPreferencedCurrencyDisplay from '../../../../components/app/user-preferenced-currency-display/user-preferenced-currency-display.component'; @@ -36,8 +36,6 @@ export default function FeeDetailsComponent({ const [expandFeeDetails, setExpandFeeDetails] = useState(false); const shouldShowFiat = useSelector(getShouldShowFiat); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); - const t = useI18nContext(); const { minimumCostInHexWei: hexMinimumTransactionFee } = useGasFeeContext(); @@ -64,13 +62,13 @@ export default function FeeDetailsComponent({ color: TextColor.textAlternative, variant: TextVariant.bodySmBold, }} - hideLabel={Boolean(useNativeCurrencyAsPrimaryCurrency)} + hideLabel /> )}
); }, - [txData, useNativeCurrencyAsPrimaryCurrency], + [txData], ); const renderTotalDetailValue = useCallback( @@ -91,13 +89,12 @@ export default function FeeDetailsComponent({ color: TextColor.textAlternative, variant: TextVariant.bodySm, }} - hideLabel={!useNativeCurrencyAsPrimaryCurrency} /> )} ); }, - [txData, useNativeCurrencyAsPrimaryCurrency], + [txData], ); const hasLayer1GasFee = layer1GasFee !== null; diff --git a/ui/pages/confirmations/components/gas-details-item/gas-details-item.js b/ui/pages/confirmations/components/gas-details-item/gas-details-item.js index 90ccbb09ce23..c861a9dce9d9 100644 --- a/ui/pages/confirmations/components/gas-details-item/gas-details-item.js +++ b/ui/pages/confirmations/components/gas-details-item/gas-details-item.js @@ -17,7 +17,6 @@ import { import { PRIMARY, SECONDARY } from '../../../../helpers/constants/common'; import { PriorityLevels } from '../../../../../shared/constants/gas'; import { - getPreferences, getShouldShowFiat, getTxData, transactionFeeSelector, @@ -68,7 +67,6 @@ const GasDetailsItem = ({ supportsEIP1559, } = useGasFeeContext(); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); const getTransactionFeeTotal = useMemo(() => { if (layer1GasFee) { return sumHexes(hexMinimumTransactionFee, layer1GasFee); @@ -148,7 +146,7 @@ const GasDetailsItem = ({ }} type={SECONDARY} value={getTransactionFeeTotal} - hideLabel={Boolean(useNativeCurrencyAsPrimaryCurrency)} + hideLabel // Label not required here as it will always display fiat value. /> )}
@@ -168,7 +166,7 @@ const GasDetailsItem = ({ }} type={PRIMARY} value={getTransactionFeeTotal || draftHexMinimumTransactionFee} - hideLabel={!useNativeCurrencyAsPrimaryCurrency} + // Label required here as it will always display crypto value />
} @@ -216,7 +214,6 @@ const GasDetailsItem = ({ value={ getMaxTransactionFeeTotal || draftHexMaximumTransactionFee } - hideLabel={!useNativeCurrencyAsPrimaryCurrency} />
diff --git a/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js b/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js index ca85dd9abae9..3e45b4c87722 100644 --- a/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js +++ b/ui/pages/confirmations/components/gas-details-item/gas-details-item.test.js @@ -35,9 +35,7 @@ const render = async ({ contextProps } = {}) => { balance: '0x1F4', }, }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, gasFeeEstimates: mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates, gasFeeEstimatesByChainId: { diff --git a/ui/pages/confirmations/components/signature-request-header/signature-request-header.js b/ui/pages/confirmations/components/signature-request-header/signature-request-header.js index 30f839b3f78c..9c91ca476ebb 100644 --- a/ui/pages/confirmations/components/signature-request-header/signature-request-header.js +++ b/ui/pages/confirmations/components/signature-request-header/signature-request-header.js @@ -9,10 +9,8 @@ import { } from '../../../../ducks/metamask/metamask'; import { accountsWithSendEtherInfoSelector, - conversionRateSelector, getCurrentChainId, getCurrentCurrency, - getPreferences, } from '../../../../selectors'; import { formatCurrency } from '../../../../helpers/utils/confirm-tx.util'; import { @@ -38,11 +36,8 @@ const SignatureRequestHeader = ({ txData }) => { const providerConfig = useSelector(getProviderConfig); const networkName = getNetworkNameFromProviderType(providerConfig.type); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); - const conversionRateFromSelector = useSelector(conversionRateSelector); - const conversionRate = useNativeCurrencyAsPrimaryCurrency - ? null - : conversionRateFromSelector; + + const conversionRate = null; // setting conversion rate to null by default to display balance in native const currentNetwork = networkName === '' diff --git a/ui/pages/confirmations/components/signature-request/signature-request.test.js b/ui/pages/confirmations/components/signature-request/signature-request.test.js index 0d50f906e5ca..9851cdbef454 100644 --- a/ui/pages/confirmations/components/signature-request/signature-request.test.js +++ b/ui/pages/confirmations/components/signature-request/signature-request.test.js @@ -45,9 +45,7 @@ const mockStore = { rpcUrl: 'http://localhost:8545', ticker: 'ETH', }), - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, accounts: { '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5': { address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', diff --git a/ui/pages/confirmations/components/simulation-details/simulation-details.stories.tsx b/ui/pages/confirmations/components/simulation-details/simulation-details.stories.tsx index 15bfab8a2428..7c4fdc6e0d22 100644 --- a/ui/pages/confirmations/components/simulation-details/simulation-details.stories.tsx +++ b/ui/pages/confirmations/components/simulation-details/simulation-details.stories.tsx @@ -29,7 +29,7 @@ const storeMock = configureStore({ ...mockState.metamask, preferences: { ...mockState.metamask.preferences, - useNativeCurrencyAsPrimaryCurrency: false, + showNativeTokenAsMainBalance: false, }, ...mockNetworkState({ chainId: CHAIN_ID_MOCK }), useTokenDetection: true, diff --git a/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.js b/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.js index cbe80f86fe8b..ebd57c35a141 100644 --- a/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.js +++ b/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.js @@ -86,7 +86,6 @@ export default class ConfirmApproveContent extends Component { setUserAcknowledgedGasMissing: PropTypes.func, renderSimulationFailureWarning: PropTypes.bool, useCurrencyRateCheck: PropTypes.bool, - useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, }; state = { @@ -159,7 +158,6 @@ export default class ConfirmApproveContent extends Component { userAcknowledgedGasMissing, renderSimulationFailureWarning, useCurrencyRateCheck, - useNativeCurrencyAsPrimaryCurrency, } = this.props; if ( !hasLayer1GasFee && @@ -183,7 +181,6 @@ export default class ConfirmApproveContent extends Component { } noBold diff --git a/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js b/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js index 2abec9ef4c13..ba1c7c5a568c 100644 --- a/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js +++ b/ui/pages/confirmations/confirm-approve/confirm-approve-content/confirm-approve-content.component.test.js @@ -11,9 +11,7 @@ const renderComponent = (props) => { const store = configureMockStore([])({ metamask: { ...mockNetworkState({ chainId: '0x0' }), - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, currencyRates: {}, }, }); diff --git a/ui/pages/confirmations/confirm-approve/confirm-approve.js b/ui/pages/confirmations/confirm-approve/confirm-approve.js index 0828c236a38f..a5dcaeb6202d 100644 --- a/ui/pages/confirmations/confirm-approve/confirm-approve.js +++ b/ui/pages/confirmations/confirm-approve/confirm-approve.js @@ -27,7 +27,6 @@ import { getRpcPrefsForCurrentProvider, checkNetworkAndAccountSupports1559, getUseCurrencyRateCheck, - getPreferences, } from '../../../selectors'; import { useApproveTransaction } from '../hooks/useApproveTransaction'; import { useSimulationFailureWarning } from '../hooks/useSimulationFailureWarning'; @@ -84,7 +83,6 @@ export default function ConfirmApprove({ isAddressLedgerByFromAddress(userAddress), ); const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck); - const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); const [customPermissionAmount, setCustomPermissionAmount] = useState(''); const [submitWarning, setSubmitWarning] = useState(''); const [isContract, setIsContract] = useState(false); @@ -298,9 +296,6 @@ export default function ConfirmApprove({ hasLayer1GasFee={layer1GasFee !== undefined} supportsEIP1559={supportsEIP1559} useCurrencyRateCheck={useCurrencyRateCheck} - useNativeCurrencyAsPrimaryCurrency={ - useNativeCurrencyAsPrimaryCurrency - } /> {showCustomizeGasPopover && !supportsEIP1559 && (
0.000021 + + ETH +
@@ -431,13 +436,18 @@ exports[`Confirm Transaction Base should match snapshot 1`] = `
0.000021 + + ETH +
diff --git a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js index 31149997a39c..96fd5315e317 100644 --- a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js +++ b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js @@ -146,7 +146,6 @@ export default class ConfirmTransactionBase extends Component { secondaryTotalTextOverride: PropTypes.string, gasIsLoading: PropTypes.bool, primaryTotalTextOverrideMaxAmount: PropTypes.string, - useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, maxFeePerGas: PropTypes.string, maxPriorityFeePerGas: PropTypes.string, baseFeePerGas: PropTypes.string, @@ -399,7 +398,6 @@ export default class ConfirmTransactionBase extends Component { nextNonce, getNextNonce, txData, - useNativeCurrencyAsPrimaryCurrency, primaryTotalTextOverrideMaxAmount, showLedgerSteps, nativeCurrency, @@ -459,7 +457,6 @@ export default class ConfirmTransactionBase extends Component { type={PRIMARY} key="total-max-amount" value={getTotalAmount(useMaxFee)} - hideLabel={!useNativeCurrencyAsPrimaryCurrency} /> ); } @@ -468,9 +465,8 @@ export default class ConfirmTransactionBase extends Component { const primaryTotal = useMaxFee ? primaryTotalTextOverrideMaxAmount : primaryTotalTextOverride; - const totalMaxAmount = useNativeCurrencyAsPrimaryCurrency - ? primaryTotal - : secondaryTotalTextOverride; + + const totalMaxAmount = primaryTotal; return isBoldTextAndNotOverridden ? ( {totalMaxAmount} @@ -500,14 +496,12 @@ export default class ConfirmTransactionBase extends Component { color: TextColor.textDefault, variant: TextVariant.bodyMdBold, }} - hideLabel={Boolean(useNativeCurrencyAsPrimaryCurrency)} + hideLabel /> ); } - return useNativeCurrencyAsPrimaryCurrency - ? secondaryTotalTextOverride - : primaryTotalTextOverride; + return secondaryTotalTextOverride; }; const nextNonceValue = diff --git a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js index ed012d07e5ce..5d92a1af9c56 100644 --- a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js +++ b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js @@ -45,7 +45,6 @@ import { getIsEthGasPriceFetched, getShouldShowFiat, checkNetworkAndAccountSupports1559, - getPreferences, doesAddressRequireLedgerHidConnection, getTokenList, getEnsResolutionByAddress, @@ -266,7 +265,6 @@ const mapStateToProps = (state, ownProps) => { customNonceValue = getCustomNonceValue(state); const isEthGasPriceFetched = getIsEthGasPriceFetched(state); const noGasPrice = !supportsEIP1559 && getNoGasPriceFetched(state); - const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state); const gasFeeIsCustom = fullTxData.userFeeLevel === CUSTOM_GAS_ESTIMATE || txParamsAreDappSuggested(fullTxData); @@ -347,7 +345,6 @@ const mapStateToProps = (state, ownProps) => { noGasPrice, supportsEIP1559, gasIsLoading: isGasEstimatesLoading || gasLoadingAnimationIsShowing, - useNativeCurrencyAsPrimaryCurrency, maxFeePerGas: gasEstimationObject.maxFeePerGas, maxPriorityFeePerGas: gasEstimationObject.maxPriorityFeePerGas, baseFeePerGas: gasEstimationObject.baseFeePerGas, diff --git a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.test.js b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.test.js index f8a7b40430fb..bea6aef1d84d 100644 --- a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.test.js +++ b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.test.js @@ -108,9 +108,7 @@ const baseStore = { chainId: CHAIN_IDS.GOERLI, }), tokens: [], - preferences: { - useNativeCurrencyAsPrimaryCurrency: false, - }, + preferences: {}, currentCurrency: 'USD', currencyRates: {}, featureFlags: { diff --git a/ui/pages/confirmations/hooks/test-utils.js b/ui/pages/confirmations/hooks/test-utils.js index 8af6bcf3ba40..908f600564f8 100644 --- a/ui/pages/confirmations/hooks/test-utils.js +++ b/ui/pages/confirmations/hooks/test-utils.js @@ -10,10 +10,10 @@ import { import { getCurrentCurrency, getShouldShowFiat, - getPreferences, txDataSelector, getCurrentKeyring, getTokenExchangeRates, + getPreferences, } from '../../../selectors'; import { @@ -118,7 +118,7 @@ export const generateUseSelectorRouter = } if (selector === getPreferences) { return { - useNativeCurrencyAsPrimaryCurrency: true, + showNativeTokenAsMainBalance: true, }; } if ( diff --git a/ui/pages/confirmations/send/gas-display/gas-display.js b/ui/pages/confirmations/send/gas-display/gas-display.js index 5fbad8445cd6..33a011c2966a 100644 --- a/ui/pages/confirmations/send/gas-display/gas-display.js +++ b/ui/pages/confirmations/send/gas-display/gas-display.js @@ -48,6 +48,7 @@ import { MetaMetricsContext } from '../../../../contexts/metametrics'; import useRamps from '../../../../hooks/ramps/useRamps/useRamps'; import { getIsNativeTokenBuyable } from '../../../../ducks/ramps'; +// This function is no longer used in codebase, to be deleted. export default function GasDisplay({ gasError }) { const t = useContext(I18nContext); const dispatch = useDispatch(); @@ -61,8 +62,7 @@ export default function GasDisplay({ gasError }) { const isBuyableChain = useSelector(getIsNativeTokenBuyable); const draftTransaction = useSelector(getCurrentDraftTransaction); const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck); - const { showFiatInTestnets, useNativeCurrencyAsPrimaryCurrency } = - useSelector(getPreferences); + const { showFiatInTestnets } = useSelector(getPreferences); const unapprovedTxs = useSelector(getUnapprovedTransactions); const nativeCurrency = useSelector(getNativeCurrency); const { chainId } = providerConfig; @@ -132,7 +132,6 @@ export default function GasDisplay({ gasError }) { type={PRIMARY} key="total-detail-value" value={hexTransactionTotal} - hideLabel={!useNativeCurrencyAsPrimaryCurrency} /> ); @@ -144,10 +143,9 @@ export default function GasDisplay({ gasError }) { draftTransaction.amount.value, hexMaximumTransactionFee, )} - hideLabel={!useNativeCurrencyAsPrimaryCurrency} /> ); - } else if (useNativeCurrencyAsPrimaryCurrency) { + } else { detailTotal = primaryTotalTextOverrideMaxAmount; maxAmount = primaryTotalTextOverrideMaxAmount; } @@ -177,7 +175,7 @@ export default function GasDisplay({ gasError }) { type={SECONDARY} key="total-detail-text" value={hexTransactionTotal} - hideLabel={Boolean(useNativeCurrencyAsPrimaryCurrency)} + hideLabel /> ) diff --git a/ui/pages/home/index.scss b/ui/pages/home/index.scss index 03b4cd5d7cf9..5a85a3eb5d3c 100644 --- a/ui/pages/home/index.scss +++ b/ui/pages/home/index.scss @@ -20,6 +20,7 @@ min-width: 0; display: flex; flex-direction: column; + padding-top: 8px; } &__connect-status-text { diff --git a/ui/pages/institutional/confirm-add-custodian-token/confirm-add-custodian-token.test.tsx b/ui/pages/institutional/confirm-add-custodian-token/confirm-add-custodian-token.test.tsx index cdefb3986d1f..d7a474ad3b24 100644 --- a/ui/pages/institutional/confirm-add-custodian-token/confirm-add-custodian-token.test.tsx +++ b/ui/pages/institutional/confirm-add-custodian-token/confirm-add-custodian-token.test.tsx @@ -17,9 +17,7 @@ jest.mock('../../../store/institutional/institution-background', () => ({ describe('Confirm Add Custodian Token', () => { const mockStore = { metamask: { - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, institutionalFeatures: { connectRequests: [ { @@ -50,9 +48,7 @@ describe('Confirm Add Custodian Token', () => { it('tries to connect to custodian with empty token', async () => { const customMockedStore = { metamask: { - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, institutionalFeatures: { connectRequests: [ { diff --git a/ui/pages/institutional/confirm-connect-custodian-modal/confirm-connect-custodian-modal.test.tsx b/ui/pages/institutional/confirm-connect-custodian-modal/confirm-connect-custodian-modal.test.tsx index 5719fb38015f..5044d6085812 100644 --- a/ui/pages/institutional/confirm-connect-custodian-modal/confirm-connect-custodian-modal.test.tsx +++ b/ui/pages/institutional/confirm-connect-custodian-modal/confirm-connect-custodian-modal.test.tsx @@ -9,9 +9,7 @@ describe('Confirm Add Custodian Token', () => { const mockStore = { metamask: { - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, }, history: { push: '/', diff --git a/ui/pages/institutional/custody/custody.test.tsx b/ui/pages/institutional/custody/custody.test.tsx index 383e615492da..577e599397ba 100644 --- a/ui/pages/institutional/custody/custody.test.tsx +++ b/ui/pages/institutional/custody/custody.test.tsx @@ -99,9 +99,7 @@ describe('CustodyPage', function () { }, ], }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, - }, + preferences: {}, appState: { isLoading: false, }, diff --git a/ui/pages/settings/advanced-tab/__snapshots__/advanced-tab.component.test.js.snap b/ui/pages/settings/advanced-tab/__snapshots__/advanced-tab.component.test.js.snap index fcc11ec8336b..6318abd37570 100644 --- a/ui/pages/settings/advanced-tab/__snapshots__/advanced-tab.component.test.js.snap +++ b/ui/pages/settings/advanced-tab/__snapshots__/advanced-tab.component.test.js.snap @@ -501,7 +501,7 @@ exports[`AdvancedTab Component should match snapshot 1`] = ` class="MuiFormControl-root MuiTextField-root MuiFormControl-marginDense MuiFormControl-fullWidth" >
{ return ( - + ); }; @@ -73,7 +79,11 @@ export default function SettingsSearch({ onClick={() => handleSearch('')} style={{ cursor: 'pointer' }} > - + )} @@ -93,6 +103,7 @@ export default function SettingsSearch({ autoComplete="off" startAdornment={renderStartAdornment()} endAdornment={renderEndAdornment()} + theme="bordered" /> ); } diff --git a/ui/pages/settings/settings-tab/settings-tab.component.js b/ui/pages/settings/settings-tab/settings-tab.component.js index b998cde80515..191bbbc78685 100644 --- a/ui/pages/settings/settings-tab/settings-tab.component.js +++ b/ui/pages/settings/settings-tab/settings-tab.component.js @@ -62,12 +62,10 @@ export default class SettingsTab extends PureComponent { currentLocale: PropTypes.string, useBlockie: PropTypes.bool, currentCurrency: PropTypes.string, - nativeCurrency: PropTypes.string, - useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, - setUseNativeCurrencyAsPrimaryCurrencyPreference: PropTypes.func, + showNativeTokenAsMainBalance: PropTypes.bool, + setShowNativeTokenAsMainBalancePreference: PropTypes.func, hideZeroBalanceTokens: PropTypes.bool, setHideZeroBalanceTokens: PropTypes.func, - lastFetchedConversionDate: PropTypes.number, selectedAddress: PropTypes.string, tokenList: PropTypes.object, theme: PropTypes.string, @@ -94,8 +92,7 @@ export default class SettingsTab extends PureComponent { renderCurrentConversion() { const { t } = this.context; - const { currentCurrency, setCurrentCurrency, lastFetchedConversionDate } = - this.props; + const { currentCurrency, setCurrentCurrency } = this.props; return (
- {t('currencyConversion')} - - {lastFetchedConversionDate - ? t('updatedWithDate', [ - new Date(lastFetchedConversionDate * 1000).toString(), - ]) - : t('noConversionDateAvailable')} - + + {t('currencyConversion')} +
@@ -131,6 +127,7 @@ export default class SettingsTab extends PureComponent { }, }); }} + className="settings-page__content-item__dropdown" />
@@ -141,10 +138,6 @@ export default class SettingsTab extends PureComponent { renderCurrentLocale() { const { t } = this.context; const { updateCurrentLocale, currentLocale } = this.props; - const currentLocaleMeta = locales.find( - (locale) => locale.code === currentLocale, - ); - const currentLocaleName = currentLocaleMeta ? currentLocaleMeta.name : ''; return (
- + {t('currentLanguage')} - - - {currentLocaleName} - +
@@ -191,15 +185,20 @@ export default class SettingsTab extends PureComponent { id="toggle-zero-balance" >
- {t('hideZeroBalanceTokens')} + + {t('hideZeroBalanceTokens')} +
setHideZeroBalanceTokens(!value)} - offLabel={t('off')} - onLabel={t('on')} + data-testid="toggle-zero-balance-button" />
@@ -229,14 +228,19 @@ export default class SettingsTab extends PureComponent {
{t('accountIdenticon')} - + {t('jazzAndBlockies')} - +