Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
47 changes: 26 additions & 21 deletions app/components/Nav/Main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
} from '../../hooks/useNetworksByNamespace/useNetworksByNamespace';
import { useNetworkSelection } from '../../hooks/useNetworkSelection/useNetworkSelection';
import { useIsOnBridgeRoute } from '../../UI/Bridge/hooks/useIsOnBridgeRoute';
import { shouldShowNetworkListToast } from './utils';

const Stack = createStackNavigator();

Expand Down Expand Up @@ -167,7 +168,7 @@
} else {
props.setInfuraAvailabilityNotBlocked();
}
// eslint-disable-next-line react-hooks/exhaustive-deps

Check warning on line 171 in app/components/Nav/Main/index.js

View workflow job for this annotation

GitHub Actions / Run `lint`

React Compiler has skipped optimizing this component because one or more React ESLint rules were disabled. React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior
}, [
props.navigation,
props.providerType,
Expand Down Expand Up @@ -298,11 +299,9 @@
);

// Emit network addition/deletion toast if network list changes
// Bridge routes are skipped as they interfere with bridge UI
if (
previousNetworkValues.length &&
currentNetworkValues.length !== previousNetworkValues.length &&
!isOnBridgeRoute
currentNetworkValues.length !== previousNetworkValues.length
) {
// Find the newly added network by comparing chainIds
const newNetwork = currentNetworkValues.find(
Expand All @@ -318,27 +317,33 @@
),
);

toastRef?.current?.showToast({
variant: ToastVariants.Plain,
labelOptions: [
{
label: `${
(newNetwork?.name || deletedNetwork?.name) ??
strings('asset_details.network')
} `,
isBold: true,
},
{
label: deletedNetwork
? strings('toast.network_removed')
: strings('toast.network_added'),
},
],
networkImageSource: networkImage,
const shouldShowToast = shouldShowNetworkListToast({
newNetworkChainId: newNetwork?.chainId,
hasDeletedNetwork: Boolean(deletedNetwork),
});
if (shouldShowToast) {
toastRef?.current?.showToast({
variant: ToastVariants.Plain,
labelOptions: [
{
label: `${
(newNetwork?.name || deletedNetwork?.name) ??
strings('asset_details.network')
} `,
isBold: true,
},
{
label: deletedNetwork
? strings('toast.network_removed')
: strings('toast.network_added'),
},
],
networkImageSource: networkImage,
});
}
}
previousNetworkConfigurations.current = networkConfigurations;
}, [isOnBridgeRoute, networkConfigurations, networkImage, toastRef]);
}, [networkConfigurations, networkImage, toastRef]);

useEffect(() => {
if (locale.current !== I18n.locale) {
Expand Down Expand Up @@ -378,7 +383,7 @@
removeConnectionStatusListener.current &&
removeConnectionStatusListener.current();
};
// eslint-disable-next-line react-hooks/exhaustive-deps

Check warning on line 386 in app/components/Nav/Main/index.js

View workflow job for this annotation

GitHub Actions / Run `lint`

React Compiler has skipped optimizing this component because one or more React ESLint rules were disabled. React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior
}, [connectionChangeHandler]);

const openDeprecatedNetworksArticle = () => {
Expand Down
48 changes: 47 additions & 1 deletion app/components/Nav/Main/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { ImageSourcePropType } from 'react-native';
import { handleShowNetworkActiveToast } from './utils';
import {
handleShowNetworkActiveToast,
shouldShowNetworkListToast,
} from './utils';
import { ToastVariants } from '../../../component-library/components/Toast';
import { strings } from '../../../../locales/i18n';
import {
clearSuppressedNetworkAddedToast,
consumeSuppressedNetworkAddedToast,
resetSuppressedNetworkAddedToasts,
suppressNextNetworkAddedToast,
} from '../../../util/networks/networkToastSuppression';

describe('handleShowNetworkActiveToast', () => {
const mockToastRef = {
Expand All @@ -16,6 +25,7 @@ describe('handleShowNetworkActiveToast', () => {

beforeEach(() => {
jest.clearAllMocks();
resetSuppressedNetworkAddedToasts();
});

it('shows toast when not on bridge route', () => {
Expand Down Expand Up @@ -134,3 +144,39 @@ describe('handleShowNetworkActiveToast', () => {
expect(calledWith.networkImageSource).toBe(customNetworkImage);
});
});

describe('shouldShowNetworkListToast', () => {
beforeEach(() => {
resetSuppressedNetworkAddedToasts();
});

it('suppresses an added-network toast only once', () => {
suppressNextNetworkAddedToast('0xa');

expect(
shouldShowNetworkListToast({
newNetworkChainId: '0xa',
hasDeletedNetwork: false,
}),
).toBe(false);

expect(
shouldShowNetworkListToast({
newNetworkChainId: '0xa',
hasDeletedNetwork: false,
}),
).toBe(true);
});

it('clears suppressed added-network toasts explicitly', () => {
suppressNextNetworkAddedToast('0xa');

clearSuppressedNetworkAddedToast('0xa');

expect(consumeSuppressedNetworkAddedToast('0xa')).toBe(false);
});

it('returns false when consuming without a chain id', () => {
expect(consumeSuppressedNetworkAddedToast()).toBe(false);
});
});
15 changes: 15 additions & 0 deletions app/components/Nav/Main/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ImageSourcePropType } from 'react-native';
import { ToastVariants } from '../../../component-library/components/Toast';
import { strings } from '../../../../locales/i18n';
import { consumeSuppressedNetworkAddedToast } from '../../../util/networks/networkToastSuppression';

export const handleShowNetworkActiveToast = (
isOnBridgeRoute: boolean,
Expand All @@ -23,3 +24,17 @@ export const handleShowNetworkActiveToast = (
});
}
};

export const shouldShowNetworkListToast = ({
newNetworkChainId,
hasDeletedNetwork,
}: {
newNetworkChainId?: string;
hasDeletedNetwork: boolean;
}) => {
const shouldShowNetworkAddedToast =
Boolean(newNetworkChainId) &&
!consumeSuppressedNetworkAddedToast(newNetworkChainId);

return shouldShowNetworkAddedToast || hasDeletedNetwork;
};
6 changes: 6 additions & 0 deletions app/components/UI/Bridge/hooks/useTokenSelection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import { createMockToken } from '../testUtils/fixtures';
import Routes from '../../../../constants/navigation/Routes';
import { BridgeToken, TokenSelectorType } from '../types';
import { selectNetworkConfigurations } from '../../../../selectors/networkController';
import {
consumeSuppressedNetworkAddedToast,
resetSuppressedNetworkAddedToasts,
} from '../../../../util/networks/networkToastSuppression';

const mockDispatch = jest.fn();
const mockHandleSwitchTokensInner = jest.fn().mockResolvedValue(undefined);
Expand Down Expand Up @@ -176,6 +180,7 @@ const renderTokenSelectionHook = (
describe('useTokenSelection', () => {
beforeEach(() => {
jest.clearAllMocks();
resetSuppressedNetworkAddedToasts();
// Non-stock token behavior
mockIsStockToken.mockReturnValue(false);
mockIsTokenTradingOpen.mockReturnValue(true);
Expand Down Expand Up @@ -312,6 +317,7 @@ describe('useTokenSelection', () => {
expect(mockDispatch).not.toHaveBeenCalled();
expect(mockAutoUpdateDestToken).not.toHaveBeenCalled();
expect(mockGoBack).toHaveBeenCalledTimes(1);
expect(consumeSuppressedNetworkAddedToast('0xa')).toBe(false);
});

it('continues dest selection when addNetwork rejects', async () => {
Expand Down
6 changes: 6 additions & 0 deletions app/components/UI/Bridge/hooks/useTokenSelection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import { Hex } from '@metamask/utils';
import Engine from '../../../../core/Engine';
import { selectNetworkConfigurations } from '../../../../selectors/networkController';
import { PopularList } from '../../../../util/networks/customNetworks';
import {
clearSuppressedNetworkAddedToast,
suppressNextNetworkAddedToast,
} from '../../../../util/networks/networkToastSuppression';

/**
* Hook to manage token selection logic for Bridge token selector
Expand Down Expand Up @@ -69,6 +73,7 @@ export const useTokenSelection = (type: TokenSelectorType) => {
try {
const hexChainId = toHex(popularNetwork.chainId) as Hex;
const { blockExplorerUrl } = popularNetwork.rpcPrefs;
suppressNextNetworkAddedToast(popularNetwork.chainId);
await Engine.context.NetworkController.addNetwork({
chainId: hexChainId,
blockExplorerUrls: blockExplorerUrl ? [blockExplorerUrl] : [],
Expand All @@ -86,6 +91,7 @@ export const useTokenSelection = (type: TokenSelectorType) => {
],
});
} catch {
clearSuppressedNetworkAddedToast(popularNetwork.chainId);
if (isSourcePicker) {
// Source requires a configured network to sign transactions.
// Abort selection if the network couldn't be added.
Expand Down
Loading
Loading