Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Token Network Filter UI [Mobile] #11808

Draft
wants to merge 58 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
0248c74
feat: Add sortAssets utility function
gambinish Sep 27, 2024
6a2e8c7
chore: Breakup monolithic Tokens/index.tsx into smaller components
gambinish Sep 27, 2024
7a78717
fix: Correctly handle null check for buyable footer button
gambinish Sep 27, 2024
57295ee
fix: Tweak boolean logic for rendering footer components
gambinish Sep 27, 2024
d00354f
chore: Update snapshot
gambinish Sep 27, 2024
be87f81
chore: Type out tokens as TokenI[]
gambinish Sep 27, 2024
68c7b2e
chore: Remove unecessary comments around import statements in Networt…
gambinish Sep 27, 2024
a02e139
Merge branch 'main' into chore/componetize-tokens-screen
gambinish Sep 27, 2024
de5bbed
Merge branch 'main' into chore/componetize-tokens-screen
gambinish Sep 27, 2024
0fd9ad5
Merge branch 'main' into chore/componetize-tokens-screen
gambinish Sep 27, 2024
032618c
chore: Add unit tests to utility file, provide exports from index file
gambinish Sep 30, 2024
a58f1ba
chore: Rename handleBalance to me more descriptive of what its logic …
gambinish Sep 30, 2024
1dd31e3
chore: rename Networth to PortfolioBalance for clarity
gambinish Sep 30, 2024
16ded6a
chore: Cleanup styles extra whitespace
gambinish Sep 30, 2024
52d3d85
Merge branch 'main' into chore/componetize-tokens-screen
gambinish Sep 30, 2024
dd3ffdf
fix: Update snapshot tests
gambinish Sep 30, 2024
da640bc
Merge branch 'chore/componetize-tokens-screen' of github.com:MetaMask…
gambinish Sep 30, 2024
ebcbcf6
fix: Remove unused component
gambinish Sep 30, 2024
31fad19
Merge branch 'main' into chore/componetize-tokens-screen
gambinish Sep 30, 2024
4a8d927
chore: Move PotfolioBalance above TabView
gambinish Oct 1, 2024
a7b4c17
fix: Wrap PortfolioBalance and ScrollableView in fragment for token r…
gambinish Oct 1, 2024
658fcf6
fix: Padding tweak below tab bar for consistency of token list
gambinish Oct 1, 2024
18035d4
fix: Reorganize test suite for PortfolioBalance
gambinish Oct 1, 2024
c570c2c
fix: Revert changes to wallet test
gambinish Oct 1, 2024
a97128b
fix: Update fiatBalance text style to DisplayMD
gambinish Oct 1, 2024
8036a0a
chore: Patch PreferencesController with tokenSortConfig
gambinish Oct 1, 2024
1f0ac51
chore: Patch preferences controller with type
gambinish Oct 1, 2024
34d987c
feat: Build token sorting UI, patch PreferencesController
gambinish Oct 4, 2024
d57558b
chore: Merge main, address merge conflicts
gambinish Oct 7, 2024
c5c954c
fix: ListHeaderComponent not needed in FlatList anymore
gambinish Oct 7, 2024
4f635e8
fix: Update snapshots and lint
gambinish Oct 7, 2024
469270a
chore: Merge develop, address conflicts
gambinish Oct 8, 2024
82eb1a2
chore: Remove destructive index
gambinish Oct 9, 2024
f18b820
Merge branch 'main' into feat/mmassets_357-sort-import-tokens-mobile-…
gambinish Oct 10, 2024
d3a79fc
chore: Merge main, address conflicts
gambinish Oct 10, 2024
5fc979c
chore: Repatch preferences controller with tokenSortConfig
gambinish Oct 10, 2024
2890148
fix: Declning balance sort
gambinish Oct 10, 2024
25a7238
fix: Export raw value from deriveBalanceFromAssetMarketDetails
gambinish Oct 10, 2024
6637303
fix: deriveBalanceFromAssetMarketDetails.test.ts
gambinish Oct 10, 2024
0415b73
fix: Update unit tests and snapshots
gambinish Oct 10, 2024
ff32cc4
fix: Lint unused imports from Tokens/index.tsx
gambinish Oct 10, 2024
f4f2519
chore: Update testIds and locale strings
gambinish Oct 11, 2024
bd61eff
fix: Update WalletView import selector
gambinish Oct 11, 2024
f28b6fe
fix: Update snapshots
gambinish Oct 11, 2024
7c9d5cc
chore: Cleanup
gambinish Oct 11, 2024
e747848
fix: Add navigation type
gambinish Oct 11, 2024
71ce22f
fix: fix snapshot
salimtb Oct 11, 2024
6aa6f3f
Merge branch 'main' into feat/mmassets_357-sort-import-tokens-mobile-…
salimtb Oct 15, 2024
fe21f40
chore: Update snapshots
gambinish Oct 15, 2024
6f52163
Merge branch 'feat/mmassets_357-sort-import-tokens-mobile--reorg-port…
gambinish Oct 15, 2024
579f012
fix: Update placeholders in switch statement
gambinish Oct 15, 2024
68338a3
Merge branch 'feat/mmassets_357-sort-import-tokens-mobile--token-sort…
gambinish Oct 15, 2024
ff95c72
chore: Add additional e2e test for import token footer link
gambinish Oct 15, 2024
1d929ce
chore: Update snapshots
gambinish Oct 15, 2024
9cf6337
chore: Patch PreferencesController with tokenNetworkFilter
gambinish Oct 16, 2024
fcf0d64
fix: Update to correct type in PreferenceController patch
gambinish Oct 16, 2024
e3196a3
fix: Correct method name in patched PreferenceController
gambinish Oct 16, 2024
aa5b6da
chore: Integrate Filter dropdown with PreferencesController
gambinish Oct 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions app/actions/settings/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,10 @@ export function toggleDeviceNotification(deviceNotificationEnabled) {
deviceNotificationEnabled,
};
}

export function setTokenSortConfig(tokenSortConfig) {
return {
type: 'SET_TOKEN_SORT_CONFIG',
tokenSortConfig,
};
}
141 changes: 141 additions & 0 deletions app/components/UI/Tokens/TokenList/PortfolioBalance/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import React from 'react';
import { fireEvent } from '@testing-library/react-native';
import { BN } from 'ethereumjs-util';
import renderWithProvider from '../../../../../util/test/renderWithProvider';
import { backgroundState } from '../../../../../util/test/initial-root-state';
import AppConstants from '../../../../../../app/core/AppConstants';
import Routes from '../../../../../../app/constants/navigation/Routes';
import { WalletViewSelectorsIDs } from '../../../../../../e2e/selectors/wallet/WalletView.selectors';
import { PortfolioBalance } from '.';

jest.mock('../../../../../core/Engine', () => ({
getTotalFiatAccountBalance: jest.fn(),
context: {
TokensController: {
ignoreTokens: jest.fn(() => Promise.resolve()),
},
},
}));

const initialState = {
engine: {
backgroundState: {
...backgroundState,
TokensController: {
tokens: [
{
name: 'Ethereum',
symbol: 'ETH',
address: '0x0',
decimals: 18,
isETH: true,

balanceFiat: '< $0.01',
iconUrl: '',
},
{
name: 'Bat',
symbol: 'BAT',
address: '0x01',
decimals: 18,
balanceFiat: '$0',
iconUrl: '',
},
{
name: 'Link',
symbol: 'LINK',
address: '0x02',
decimals: 18,
balanceFiat: '$0',
iconUrl: '',
},
],
},
TokenRatesController: {
marketData: {
'0x1': {
'0x0': { price: 0.005 },
'0x01': { price: 0.005 },
'0x02': { price: 0.005 },
},
},
},
CurrencyRateController: {
currentCurrency: 'USD',
currencyRates: {
ETH: {
conversionRate: 1,
},
},
},
TokenBalancesController: {
contractBalances: {
'0x00': new BN(2),
'0x01': new BN(2),
'0x02': new BN(0),
},
},
},
},
settings: {
primaryCurrency: 'usd',
hideZeroBalanceTokens: true,
},
security: {
dataCollectionForMarketing: true,
},
};

const mockNavigate = jest.fn();
const mockPush = jest.fn();

jest.mock('@react-navigation/native', () => {
const actualReactNavigation = jest.requireActual('@react-navigation/native');
return {
...actualReactNavigation,
useNavigation: () => ({
navigate: mockNavigate,
push: mockPush,
}),
};
});

// TODO: Replace "any" with type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const renderPortfolioBalance = (state: any = {}) =>
renderWithProvider(<PortfolioBalance />, { state });

describe('PortfolioBalance', () => {
afterEach(() => {
mockNavigate.mockClear();
mockPush.mockClear();
});

it('fiat balance must be defined', () => {
const { getByTestId } = renderPortfolioBalance(initialState);
expect(
getByTestId(WalletViewSelectorsIDs.TOTAL_BALANCE_TEXT),
).toBeDefined();
});

it('portfolio button should render correctly', () => {
const { getByTestId } = renderPortfolioBalance(initialState);

expect(getByTestId(WalletViewSelectorsIDs.PORTFOLIO_BUTTON)).toBeDefined();
});

it('navigates to Portfolio url when portfolio button is pressed', () => {
const { getByTestId } = renderPortfolioBalance(initialState);

const expectedUrl = `${AppConstants.PORTFOLIO.URL}/?metamaskEntry=mobile&metricsEnabled=false&marketingEnabled=${initialState.security.dataCollectionForMarketing}`;

fireEvent.press(getByTestId(WalletViewSelectorsIDs.PORTFOLIO_BUTTON));
expect(mockNavigate).toHaveBeenCalledWith(Routes.BROWSER.HOME, {
params: {
newTabUrl: expectedUrl,
timestamp: 123,
},
screen: Routes.BROWSER.VIEW,
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ import Button, {
ButtonSize,
ButtonWidthTypes,
} from '../../../../../component-library/components/Buttons/Button';
import Text from '../../../../../component-library/components/Texts/Text';
import Text, {
TextVariant,
} from '../../../../../component-library/components/Texts/Text';
import AggregatedPercentage from '../../../../../component-library/components-temp/Price/AggregatedPercentage';
import { IconName } from '../../../../../component-library/components/Icons/Icon';
import { BrowserTab } from '../../types';
Expand Down Expand Up @@ -110,8 +112,8 @@ export const PortfolioBalance = () => {
<View style={styles.portfolioBalance}>
<View>
<Text
style={styles.fiatBalance}
testID={WalletViewSelectorsIDs.TOTAL_BALANCE_TEXT}
variant={TextVariant.DisplayMD}
>
{fiatBalance}
</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ import { TokenI } from '../../types';

interface TokenListFooterProps {
tokens: TokenI[];
isAddTokenEnabled: boolean;
goToAddToken: () => void;
showDetectedTokens: () => void;
isAddTokenEnabled: boolean;
}

export const TokenListFooter = ({
tokens,
isAddTokenEnabled,
goToAddToken,
showDetectedTokens,
isAddTokenEnabled,
}: TokenListFooterProps) => {
const navigation = useNavigation();
const { colors } = useTheme();
Expand Down Expand Up @@ -106,7 +106,7 @@ export const TokenListFooter = ({
style={styles.add}
onPress={goToAddToken}
disabled={!isAddTokenEnabled}
testID={WalletViewSelectorsIDs.IMPORT_TOKEN_BUTTON}
testID={WalletViewSelectorsIDs.IMPORT_TOKEN_FOOTER_LINK}
>
<Text style={styles.centered}>
<Text style={styles.emptyText}>
Expand Down
21 changes: 7 additions & 14 deletions app/components/UI/Tokens/TokenList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@ import createStyles from '../styles';
import Text from '../../../../component-library/components/Texts/Text';
import { TokenI } from '../types';
import { strings } from '../../../../../locales/i18n';
import { PortfolioBalance } from './PortfolioBalance';
import { TokenListFooter } from './TokenListFooter';
import { TokenListItem } from './TokenListItem';

interface TokenListProps {
tokens: TokenI[];
refreshing: boolean;
isAddTokenEnabled: boolean;
onRefresh: () => void;
showRemoveMenu: (arg: TokenI) => void;
goToAddToken: () => void;
setIsAddTokenEnabled: (arg: boolean) => void;
}

interface TokenListNavigationParamList {
Expand All @@ -35,8 +37,11 @@ interface TokenListNavigationParamList {
export const TokenList = ({
tokens,
refreshing,
isAddTokenEnabled,
onRefresh,
showRemoveMenu,
goToAddToken,
setIsAddTokenEnabled,
}: TokenListProps) => {
const navigation =
useNavigation<
Expand All @@ -49,20 +54,9 @@ export const TokenList = ({
const detectedTokens = useSelector(selectDetectedTokens);

const [showScamWarningModal, setShowScamWarningModal] = useState(false);
const [isAddTokenEnabled, setIsAddTokenEnabled] = useState(true);

const styles = createStyles(colors);

const goToAddToken = () => {
setIsAddTokenEnabled(false);
navigation.push('AddAsset', { assetType: 'token' });
trackEvent(MetaMetricsEvents.TOKEN_IMPORT_CLICKED, {
source: 'manual',
chain_id: getDecimalChainId(chainId),
});
setIsAddTokenEnabled(true);
};

const showDetectedTokens = () => {
navigation.navigate(...createDetectedTokensNavDetails());
trackEvent(MetaMetricsEvents.TOKEN_IMPORT_CLICKED, {
Expand All @@ -77,7 +71,6 @@ export const TokenList = ({

return tokens?.length ? (
<FlatList
ListHeaderComponent={<PortfolioBalance />}
data={tokens}
renderItem={({ item }) => (
<TokenListItem
Expand All @@ -91,9 +84,9 @@ export const TokenList = ({
ListFooterComponent={
<TokenListFooter
tokens={tokens}
isAddTokenEnabled={isAddTokenEnabled}
goToAddToken={goToAddToken}
showDetectedTokens={showDetectedTokens}
isAddTokenEnabled={isAddTokenEnabled}
/>
}
refreshControl={
Expand Down
Loading
Loading