mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 01:47:00 +01:00
New network info popup (#13319)
This commit is contained in:
parent
4dab986ad2
commit
365bf11fdd
19
app/_locales/en/messages.json
generated
19
app/_locales/en/messages.json
generated
@ -369,6 +369,9 @@
|
||||
"assets": {
|
||||
"message": "Assets"
|
||||
},
|
||||
"attemptSendingAssets": {
|
||||
"message": "If you attempt to send assets directly from one network to another, this may result in permanent asset loss. Make sure to use a bridge."
|
||||
},
|
||||
"attemptToCancel": {
|
||||
"message": "Attempt to cancel?"
|
||||
},
|
||||
@ -583,6 +586,9 @@
|
||||
"message": "Click here to connect your Ledger via WebHID",
|
||||
"description": "Text that can be clicked to open a browser popup for connecting the ledger device via webhid"
|
||||
},
|
||||
"clickToManuallyAdd": {
|
||||
"message": "Click here to manually add the tokens."
|
||||
},
|
||||
"clickToRevealSeed": {
|
||||
"message": "Click here to reveal secret words"
|
||||
},
|
||||
@ -2041,6 +2047,10 @@
|
||||
"name": {
|
||||
"message": "Name"
|
||||
},
|
||||
"nativeToken": {
|
||||
"message": "The native token on this network is $1. It is the token used for gas fees.",
|
||||
"description": "$1 represents the name of the native token on the current network"
|
||||
},
|
||||
"needCryptoInWallet": {
|
||||
"message": "To interact with decentralized applications using MetaMask, you’ll need $1 in your wallet.",
|
||||
"description": "$1 represents the cypto symbol to be purchased"
|
||||
@ -3762,6 +3772,9 @@
|
||||
"switchToThisAccount": {
|
||||
"message": "Switch to this account"
|
||||
},
|
||||
"switchedTo": {
|
||||
"message": "You have switched to"
|
||||
},
|
||||
"switchingNetworksCancelsPendingConfirmations": {
|
||||
"message": "Switching networks will cancel all pending confirmations"
|
||||
},
|
||||
@ -3828,6 +3841,9 @@
|
||||
"themeDescription": {
|
||||
"message": "Choose your preferred MetaMask theme."
|
||||
},
|
||||
"thingsToKeep": {
|
||||
"message": "Things to keep in mind:"
|
||||
},
|
||||
"thisWillCreate": {
|
||||
"message": "This will create a new wallet and Secret Recovery Phrase"
|
||||
},
|
||||
@ -3890,6 +3906,9 @@
|
||||
"tokenScamSecurityRisk": {
|
||||
"message": "token scams and security risks"
|
||||
},
|
||||
"tokenShowUp": {
|
||||
"message": "Your tokens may not automatically show up in your wallet."
|
||||
},
|
||||
"tokenSymbol": {
|
||||
"message": "Token symbol"
|
||||
},
|
||||
|
@ -37,6 +37,14 @@ export default class AppStateController extends EventEmitter {
|
||||
...initState,
|
||||
qrHardware: {},
|
||||
collectiblesDropdownState: {},
|
||||
usedNetworks: {
|
||||
'0x1': true,
|
||||
'0x2a': true,
|
||||
'0x3': true,
|
||||
'0x4': true,
|
||||
'0x5': true,
|
||||
'0x539': true,
|
||||
},
|
||||
});
|
||||
this.timer = null;
|
||||
|
||||
@ -294,4 +302,18 @@ export default class AppStateController extends EventEmitter {
|
||||
collectiblesDropdownState,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the array of the first time used networks
|
||||
*
|
||||
* @param chainId
|
||||
* @returns {void}
|
||||
*/
|
||||
setFirstTimeUsedNetwork(chainId) {
|
||||
const currentState = this.store.getState();
|
||||
const { usedNetworks } = currentState;
|
||||
usedNetworks[chainId] = true;
|
||||
|
||||
this.store.updateState({ usedNetworks });
|
||||
}
|
||||
}
|
||||
|
@ -1739,6 +1739,8 @@ export default class MetamaskController extends EventEmitter {
|
||||
appStateController.updateCollectibleDropDownState.bind(
|
||||
appStateController,
|
||||
),
|
||||
setFirstTimeUsedNetwork:
|
||||
appStateController.setFirstTimeUsedNetwork.bind(appStateController),
|
||||
// EnsController
|
||||
tryReverseResolveAddress:
|
||||
ensController.reverseResolveAddress.bind(ensController),
|
||||
|
@ -36,3 +36,6 @@ export const STATIC_MAINNET_TOKEN_LIST = Object.keys(contractMap).reduce(
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
export const TOKEN_API_METASWAP_CODEFI_URL =
|
||||
'https://token-api.metaswap.codefi.network/tokens/';
|
||||
|
1
ui/components/ui/new-network-info/index.js
Normal file
1
ui/components/ui/new-network-info/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './new-network-info';
|
48
ui/components/ui/new-network-info/index.scss
Normal file
48
ui/components/ui/new-network-info/index.scss
Normal file
@ -0,0 +1,48 @@
|
||||
.new-network-info {
|
||||
&__wrapper {
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.214);
|
||||
border-radius: 8px;
|
||||
|
||||
.popover-footer {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.popover-header {
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
.fa-question-circle,
|
||||
.popover-header__button {
|
||||
color: var(--color-icon-default);
|
||||
}
|
||||
}
|
||||
|
||||
&__token-box {
|
||||
align-self: center;
|
||||
margin-top: 8px;
|
||||
max-width: 245px;
|
||||
}
|
||||
|
||||
&__bullet-paragraph {
|
||||
border-bottom: 1px solid var(--color-border-default);
|
||||
}
|
||||
|
||||
&__token-show-up {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
&__button {
|
||||
display: initial;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&__manually-add-tokens {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
.chip--with-left-icon {
|
||||
padding-left: 8px;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
225
ui/components/ui/new-network-info/new-network-info.js
Normal file
225
ui/components/ui/new-network-info/new-network-info.js
Normal file
@ -0,0 +1,225 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { I18nContext } from '../../../contexts/i18n';
|
||||
import Popover from '../popover';
|
||||
import Button from '../button';
|
||||
import Identicon from '../identicon/identicon.component';
|
||||
import { NETWORK_TYPE_RPC } from '../../../../shared/constants/network';
|
||||
import Box from '../box';
|
||||
import {
|
||||
ALIGN_ITEMS,
|
||||
COLORS,
|
||||
DISPLAY,
|
||||
FONT_WEIGHT,
|
||||
TEXT_ALIGN,
|
||||
TYPOGRAPHY,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
import Typography from '../typography';
|
||||
import { TOKEN_API_METASWAP_CODEFI_URL } from '../../../../shared/constants/tokens';
|
||||
import fetchWithCache from '../../../helpers/utils/fetch-with-cache';
|
||||
import {
|
||||
getNativeCurrencyImage,
|
||||
getProvider,
|
||||
getUseTokenDetection,
|
||||
} from '../../../selectors';
|
||||
import { IMPORT_TOKEN_ROUTE } from '../../../helpers/constants/routes';
|
||||
import Chip from '../chip/chip';
|
||||
import { setFirstTimeUsedNetwork } from '../../../store/actions';
|
||||
|
||||
const NewNetworkInfo = () => {
|
||||
const t = useContext(I18nContext);
|
||||
const history = useHistory();
|
||||
const [tokenDetectionSupported, setTokenDetectionSupported] = useState(false);
|
||||
const [showPopup, setShowPopup] = useState(true);
|
||||
const autoDetectToken = useSelector(getUseTokenDetection);
|
||||
const primaryTokenImage = useSelector(getNativeCurrencyImage);
|
||||
const currentProvider = useSelector(getProvider);
|
||||
|
||||
const onCloseClick = () => {
|
||||
setShowPopup(false);
|
||||
setFirstTimeUsedNetwork(currentProvider.chainId);
|
||||
};
|
||||
|
||||
const addTokenManually = () => {
|
||||
history.push(IMPORT_TOKEN_ROUTE);
|
||||
setShowPopup(false);
|
||||
setFirstTimeUsedNetwork(currentProvider.chainId);
|
||||
};
|
||||
|
||||
const getIsTokenDetectionSupported = async () => {
|
||||
const fetchedTokenData = await fetchWithCache(
|
||||
`${TOKEN_API_METASWAP_CODEFI_URL}${currentProvider.chainId}`,
|
||||
);
|
||||
|
||||
return !fetchedTokenData.error;
|
||||
};
|
||||
|
||||
const checkTokenDetection = async () => {
|
||||
const fetchedData = await getIsTokenDetectionSupported();
|
||||
|
||||
setTokenDetectionSupported(fetchedData);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
checkTokenDetection();
|
||||
});
|
||||
|
||||
if (!showPopup) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Popover
|
||||
onClose={onCloseClick}
|
||||
className="new-network-info__wrapper"
|
||||
footer={
|
||||
<Button type="primary" onClick={onCloseClick}>
|
||||
{t('recoveryPhraseReminderConfirm')}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Typography
|
||||
variant={TYPOGRAPHY.H4}
|
||||
color={COLORS.TEXT_DEFAULT}
|
||||
fontWeight={FONT_WEIGHT.BOLD}
|
||||
align={TEXT_ALIGN.CENTER}
|
||||
>
|
||||
{t('switchedTo')}
|
||||
</Typography>
|
||||
<Chip
|
||||
className="new-network-info__token-box"
|
||||
backgroundColor={COLORS.BACKGROUND_ALTERNATIVE}
|
||||
maxContent={false}
|
||||
label={
|
||||
currentProvider.type === NETWORK_TYPE_RPC
|
||||
? currentProvider.nickname ?? t('privateNetwork')
|
||||
: t(currentProvider.type)
|
||||
}
|
||||
labelProps={{
|
||||
color: COLORS.TEXT_DEFAULT,
|
||||
}}
|
||||
leftIcon={
|
||||
primaryTokenImage ? (
|
||||
<Identicon image={primaryTokenImage} diameter={14} />
|
||||
) : (
|
||||
<i className="fa fa-question-circle" />
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Typography
|
||||
variant={TYPOGRAPHY.H7}
|
||||
color={COLORS.TEXT_DEFAULT}
|
||||
fontWeight={FONT_WEIGHT.BOLD}
|
||||
align={TEXT_ALIGN.CENTER}
|
||||
margin={[8, 0, 0, 0]}
|
||||
>
|
||||
{t('thingsToKeep')}
|
||||
</Typography>
|
||||
<Box marginRight={4} marginLeft={5} marginTop={6}>
|
||||
{currentProvider.ticker ? (
|
||||
<Box
|
||||
display={DISPLAY.FLEX}
|
||||
alignItems={ALIGN_ITEMS.CENTER}
|
||||
marginBottom={2}
|
||||
paddingBottom={2}
|
||||
className="new-network-info__bullet-paragraph"
|
||||
>
|
||||
<Box marginRight={4} color={COLORS.TEXT_DEFAULT}>
|
||||
•
|
||||
</Box>
|
||||
<Typography
|
||||
variant={TYPOGRAPHY.H7}
|
||||
color={COLORS.TEXT_DEFAULT}
|
||||
boxProps={{ display: DISPLAY.INLINE_BLOCK }}
|
||||
key="nativeTokenInfo"
|
||||
>
|
||||
{t('nativeToken', [
|
||||
<Typography
|
||||
variant={TYPOGRAPHY.H7}
|
||||
boxProps={{ display: DISPLAY.INLINE_BLOCK }}
|
||||
fontWeight={FONT_WEIGHT.BOLD}
|
||||
key="ticker"
|
||||
>
|
||||
{currentProvider.ticker}
|
||||
</Typography>,
|
||||
])}
|
||||
</Typography>
|
||||
</Box>
|
||||
) : null}
|
||||
<Box
|
||||
display={DISPLAY.FLEX}
|
||||
alignItems={ALIGN_ITEMS.CENTER}
|
||||
marginBottom={2}
|
||||
paddingBottom={2}
|
||||
className={
|
||||
!autoDetectToken || !tokenDetectionSupported
|
||||
? 'new-network-info__bullet-paragraph'
|
||||
: null
|
||||
}
|
||||
>
|
||||
<Box marginRight={4} color={COLORS.TEXT_DEFAULT}>
|
||||
•
|
||||
</Box>
|
||||
<Typography
|
||||
variant={TYPOGRAPHY.H7}
|
||||
color={COLORS.TEXT_DEFAULT}
|
||||
boxProps={{ display: DISPLAY.INLINE_BLOCK }}
|
||||
className="new-network-info__bullet-paragraph__text"
|
||||
>
|
||||
{t('attemptSendingAssets')}{' '}
|
||||
<a
|
||||
href="https://metamask.zendesk.com/hc/en-us/articles/4404424659995"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Typography
|
||||
variant={TYPOGRAPHY.H7}
|
||||
color={COLORS.INFO_DEFAULT}
|
||||
boxProps={{ display: DISPLAY.INLINE_BLOCK }}
|
||||
>
|
||||
{t('learnMoreUpperCase')}
|
||||
</Typography>
|
||||
</a>
|
||||
</Typography>
|
||||
</Box>
|
||||
{!autoDetectToken || !tokenDetectionSupported ? (
|
||||
<Box
|
||||
display={DISPLAY.FLEX}
|
||||
alignItems={ALIGN_ITEMS.CENTER}
|
||||
marginBottom={2}
|
||||
paddingBottom={2}
|
||||
>
|
||||
<Box marginRight={4} color={COLORS.TEXT_DEFAULT}>
|
||||
•
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography
|
||||
variant={TYPOGRAPHY.H7}
|
||||
color={COLORS.TEXT_DEFAULT}
|
||||
className="new-network-info__token-show-up"
|
||||
>
|
||||
{t('tokenShowUp')}{' '}
|
||||
<Button
|
||||
type="link"
|
||||
onClick={addTokenManually}
|
||||
className="new-network-info__button"
|
||||
>
|
||||
<Typography
|
||||
variant={TYPOGRAPHY.H7}
|
||||
color={COLORS.INFO_DEFAULT}
|
||||
className="new-network-info__manually-add-tokens"
|
||||
>
|
||||
{t('clickToManuallyAdd')}
|
||||
</Typography>
|
||||
</Button>
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
) : null}
|
||||
</Box>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewNetworkInfo;
|
171
ui/components/ui/new-network-info/new-network-info.test.js
Normal file
171
ui/components/ui/new-network-info/new-network-info.test.js
Normal file
@ -0,0 +1,171 @@
|
||||
import React from 'react';
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
import nock from 'nock';
|
||||
import { renderWithProvider } from '../../../../test/lib/render-helpers';
|
||||
import NewNetworkInfo from './new-network-info';
|
||||
|
||||
const fetchWithCache =
|
||||
require('../../../helpers/utils/fetch-with-cache').default;
|
||||
|
||||
const state = {
|
||||
metamask: {
|
||||
provider: {
|
||||
ticker: 'ETH',
|
||||
nickname: '',
|
||||
chainId: '0x1',
|
||||
type: 'mainnet',
|
||||
},
|
||||
useTokenDetection: false,
|
||||
nativeCurrency: 'ETH',
|
||||
},
|
||||
};
|
||||
|
||||
describe('NewNetworkInfo', () => {
|
||||
afterEach(() => {
|
||||
nock.cleanAll();
|
||||
});
|
||||
|
||||
it('should render title', async () => {
|
||||
nock('https://token-api.metaswap.codefi.network')
|
||||
.get('/tokens/0x1')
|
||||
.reply(
|
||||
200,
|
||||
'[{"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","symbol":"SNX","decimals":18,"name":"Synthetix Network Token","iconUrl":"https://assets.coingecko.com/coins/images/3406/large/SNX.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","synthetix","zapper","zerion","zeroEx"],"occurrences":12},{"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","symbol":"UNI","decimals":18,"name":"Uniswap","iconUrl":"https://images.prismic.io/token-price-prod/d0352dd9-5de8-4633-839d-bc3422c44d9c_UNI%404x.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","zapper","zerion","zeroEx"],"occurrences":11}]',
|
||||
);
|
||||
|
||||
const updateTokenDetectionSupportStatus = await fetchWithCache(
|
||||
'https://token-api.metaswap.codefi.network/tokens/0x1',
|
||||
);
|
||||
|
||||
const store = configureMockStore()(
|
||||
state,
|
||||
updateTokenDetectionSupportStatus,
|
||||
);
|
||||
const { getByText } = renderWithProvider(<NewNetworkInfo />, store);
|
||||
|
||||
expect(getByText('You have switched to')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render a question mark icon image', async () => {
|
||||
nock('https://token-api.metaswap.codefi.network')
|
||||
.get('/tokens/0x1')
|
||||
.reply(
|
||||
200,
|
||||
'[{"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","symbol":"SNX","decimals":18,"name":"Synthetix Network Token","iconUrl":"https://assets.coingecko.com/coins/images/3406/large/SNX.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","synthetix","zapper","zerion","zeroEx"],"occurrences":12},{"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","symbol":"UNI","decimals":18,"name":"Uniswap","iconUrl":"https://images.prismic.io/token-price-prod/d0352dd9-5de8-4633-839d-bc3422c44d9c_UNI%404x.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","zapper","zerion","zeroEx"],"occurrences":11}]',
|
||||
);
|
||||
|
||||
const updateTokenDetectionSupportStatus = await fetchWithCache(
|
||||
'https://token-api.metaswap.codefi.network/tokens/0x1',
|
||||
);
|
||||
|
||||
state.metamask.nativeCurrency = '';
|
||||
|
||||
const store = configureMockStore()(
|
||||
state,
|
||||
updateTokenDetectionSupportStatus,
|
||||
);
|
||||
const { container } = renderWithProvider(<NewNetworkInfo />, store);
|
||||
const questionMark = container.querySelector('.fa fa-question-circle');
|
||||
|
||||
expect(questionMark).toBeDefined();
|
||||
});
|
||||
|
||||
it('should render Ethereum Mainnet caption', async () => {
|
||||
nock('https://token-api.metaswap.codefi.network')
|
||||
.get('/tokens/0x1')
|
||||
.reply(
|
||||
200,
|
||||
'[{"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","symbol":"SNX","decimals":18,"name":"Synthetix Network Token","iconUrl":"https://assets.coingecko.com/coins/images/3406/large/SNX.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","synthetix","zapper","zerion","zeroEx"],"occurrences":12},{"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","symbol":"UNI","decimals":18,"name":"Uniswap","iconUrl":"https://images.prismic.io/token-price-prod/d0352dd9-5de8-4633-839d-bc3422c44d9c_UNI%404x.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","zapper","zerion","zeroEx"],"occurrences":11}]',
|
||||
);
|
||||
|
||||
const updateTokenDetectionSupportStatus = await fetchWithCache(
|
||||
'https://token-api.metaswap.codefi.network/tokens/0x1',
|
||||
);
|
||||
|
||||
const store = configureMockStore()(
|
||||
state,
|
||||
updateTokenDetectionSupportStatus,
|
||||
);
|
||||
const { getByText } = renderWithProvider(<NewNetworkInfo />, store);
|
||||
|
||||
expect(getByText('Ethereum Mainnet')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render things to keep in mind text', async () => {
|
||||
nock('https://token-api.metaswap.codefi.network')
|
||||
.get('/tokens/0x1')
|
||||
.reply(
|
||||
200,
|
||||
'[{"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","symbol":"SNX","decimals":18,"name":"Synthetix Network Token","iconUrl":"https://assets.coingecko.com/coins/images/3406/large/SNX.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","synthetix","zapper","zerion","zeroEx"],"occurrences":12},{"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","symbol":"UNI","decimals":18,"name":"Uniswap","iconUrl":"https://images.prismic.io/token-price-prod/d0352dd9-5de8-4633-839d-bc3422c44d9c_UNI%404x.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","zapper","zerion","zeroEx"],"occurrences":11}]',
|
||||
);
|
||||
|
||||
const updateTokenDetectionSupportStatus = await fetchWithCache(
|
||||
'https://token-api.metaswap.codefi.network/tokens/0x1',
|
||||
);
|
||||
|
||||
const store = configureMockStore()(
|
||||
state,
|
||||
updateTokenDetectionSupportStatus,
|
||||
);
|
||||
const { getByText } = renderWithProvider(<NewNetworkInfo />, store);
|
||||
|
||||
expect(getByText('Things to keep in mind:')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render things to keep in mind text when token detection support is not available', async () => {
|
||||
nock('https://token-api.metaswap.codefi.network')
|
||||
.get('/tokens/0x3')
|
||||
.reply(200, '{"error":"ChainId 0x3 is not supported"}');
|
||||
|
||||
const updateTokenDetectionSupportStatus = await fetchWithCache(
|
||||
'https://token-api.metaswap.codefi.network/tokens/0x3',
|
||||
);
|
||||
|
||||
const store = configureMockStore()(
|
||||
state,
|
||||
updateTokenDetectionSupportStatus,
|
||||
);
|
||||
const { getByText } = renderWithProvider(<NewNetworkInfo />, store);
|
||||
|
||||
expect(getByText('Things to keep in mind:')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render first bullet when provider ticker is null', async () => {
|
||||
nock('https://token-api.metaswap.codefi.network')
|
||||
.get('/tokens/0x3')
|
||||
.reply(200, '{"error":"ChainId 0x3 is not supported"}');
|
||||
|
||||
const updateTokenDetectionSupportStatus = await fetchWithCache(
|
||||
'https://token-api.metaswap.codefi.network/tokens/0x3',
|
||||
);
|
||||
|
||||
state.metamask.provider.ticker = null;
|
||||
|
||||
const store = configureMockStore()(
|
||||
state,
|
||||
updateTokenDetectionSupportStatus,
|
||||
);
|
||||
const { container } = renderWithProvider(<NewNetworkInfo />, store);
|
||||
const firstBox = container.querySelector('new-network-info__content-box-1');
|
||||
|
||||
expect(firstBox).toBeNull();
|
||||
});
|
||||
|
||||
it('should render click to manually add link', async () => {
|
||||
nock('https://token-api.metaswap.codefi.network')
|
||||
.get('/tokens/0x3')
|
||||
.reply(200, '{"error":"ChainId 0x3 is not supported"}');
|
||||
|
||||
const updateTokenDetectionSupportStatus = await fetchWithCache(
|
||||
'https://token-api.metaswap.codefi.network/tokens/0x3',
|
||||
);
|
||||
|
||||
const store = configureMockStore()(
|
||||
state,
|
||||
updateTokenDetectionSupportStatus,
|
||||
);
|
||||
const { getByText } = renderWithProvider(<NewNetworkInfo />, store);
|
||||
|
||||
expect(getByText('Click here to manually add the tokens.')).toBeDefined();
|
||||
});
|
||||
});
|
@ -33,6 +33,7 @@
|
||||
@import 'logo/logo-coinbasepay.scss';
|
||||
@import 'loading-screen/index';
|
||||
@import 'menu/menu';
|
||||
@import 'new-network-info/index';
|
||||
@import 'numeric-input/numeric-input';
|
||||
@import 'nickname-popover/index';
|
||||
@import 'form-field/index';
|
||||
|
@ -77,6 +77,7 @@ import OnboardingFlow from '../onboarding-flow/onboarding-flow';
|
||||
import QRHardwarePopover from '../../components/app/qr-hardware-popover';
|
||||
import { SEND_STAGES } from '../../ducks/send';
|
||||
import { THEME_TYPE } from '../settings/experimental-tab/experimental-tab.constant';
|
||||
import NewNetworkInfo from '../../components/ui/new-network-info/new-network-info';
|
||||
|
||||
export default class Routes extends Component {
|
||||
static propTypes = {
|
||||
@ -104,6 +105,8 @@ export default class Routes extends Component {
|
||||
browserEnvironmentBrowser: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
sendStage: PropTypes.string,
|
||||
isNetworkUsed: PropTypes.bool,
|
||||
hasAnAccountWithNoFundsOnNetwork: PropTypes.bool,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
@ -358,11 +361,17 @@ export default class Routes extends Component {
|
||||
isMouseUser,
|
||||
browserEnvironmentOs: os,
|
||||
browserEnvironmentBrowser: browser,
|
||||
isNetworkUsed,
|
||||
hasAnAccountWithNoFundsOnNetwork,
|
||||
} = this.props;
|
||||
const loadMessage =
|
||||
loadingMessage || isNetworkLoading
|
||||
? this.getConnectingLabel(loadingMessage)
|
||||
: null;
|
||||
|
||||
const shouldShowNetworkInfo =
|
||||
isUnlocked && !isNetworkUsed && hasAnAccountWithNoFundsOnNetwork;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames('app', {
|
||||
@ -378,6 +387,7 @@ export default class Routes extends Component {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{shouldShowNetworkInfo && <NewNetworkInfo />}
|
||||
<QRHardwarePopover />
|
||||
<Modal />
|
||||
<Alert visible={this.props.alertOpen} msg={alertMessage} />
|
||||
|
@ -2,6 +2,8 @@ import { connect } from 'react-redux';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { compose } from 'redux';
|
||||
import {
|
||||
getHasAnyAccountWithNoFundsOnNetwork,
|
||||
getIsNetworkUsed,
|
||||
getNetworkIdentifier,
|
||||
getPreferences,
|
||||
isNetworkLoading,
|
||||
@ -40,6 +42,9 @@ function mapStateToProps(state) {
|
||||
providerType: state.metamask.provider?.type,
|
||||
theme: getTheme(state),
|
||||
sendStage: getSendStage(state),
|
||||
isNetworkUsed: getIsNetworkUsed(state),
|
||||
hasAnAccountWithNoFundsOnNetwork:
|
||||
getHasAnyAccountWithNoFundsOnNetwork(state),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1170,3 +1170,18 @@ export function getBlockExplorerLinkText(
|
||||
|
||||
return blockExplorerLinkText;
|
||||
}
|
||||
|
||||
export function getIsNetworkUsed(state) {
|
||||
const chainId = getCurrentChainId(state);
|
||||
const { usedNetworks } = state.metamask;
|
||||
|
||||
return Boolean(usedNetworks[chainId]);
|
||||
}
|
||||
|
||||
export function getHasAnyAccountWithNoFundsOnNetwork(state) {
|
||||
const balances = getMetaMaskCachedBalances(state) ?? {};
|
||||
const hasAnAccountWithNoFundsOnNetwork =
|
||||
Object.values(balances).indexOf('0x0');
|
||||
|
||||
return hasAnAccountWithNoFundsOnNetwork !== -1;
|
||||
}
|
||||
|
@ -3785,6 +3785,10 @@ export function setCustomNetworkListEnabled(customNetworkListEnabled) {
|
||||
};
|
||||
}
|
||||
|
||||
export function setFirstTimeUsedNetwork(chainId) {
|
||||
return promisifiedBackground.setFirstTimeUsedNetwork(chainId);
|
||||
}
|
||||
|
||||
// QR Hardware Wallets
|
||||
export async function submitQRHardwareCryptoHDKey(cbor) {
|
||||
await promisifiedBackground.submitQRHardwareCryptoHDKey(cbor);
|
||||
|
Loading…
Reference in New Issue
Block a user