New network info popup (#13319)
parent
4dab986ad2
commit
365bf11fdd
@ -0,0 +1 @@ |
||||
export { default } from './new-network-info'; |
@ -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; |
||||
} |
@ -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; |
@ -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(); |
||||
}); |
||||
}); |
Loading…
Reference in new issue