This reverts commit 81ea24f08a
.
feature/default_network_editable
parent
79867bcebe
commit
9e2935dd55
@ -1,61 +0,0 @@ |
|||||||
import { cloneDeep } from 'lodash'; |
|
||||||
import { IPFS_DEFAULT_GATEWAY_URL } from '../../../shared/constants/network'; |
|
||||||
|
|
||||||
const version = 68; |
|
||||||
|
|
||||||
function addUrlProtocolPrefix(urlString) { |
|
||||||
if (!urlString.match(/(^http:\/\/)|(^https:\/\/)/u)) { |
|
||||||
return `https://${urlString}`; |
|
||||||
} |
|
||||||
return urlString; |
|
||||||
} |
|
||||||
|
|
||||||
export default { |
|
||||||
version, |
|
||||||
|
|
||||||
async migrate(originalVersionedData) { |
|
||||||
const versionedData = cloneDeep(originalVersionedData); |
|
||||||
versionedData.meta.version = version; |
|
||||||
const state = versionedData.data; |
|
||||||
const newState = transformState(state); |
|
||||||
versionedData.data = newState; |
|
||||||
return versionedData; |
|
||||||
}, |
|
||||||
}; |
|
||||||
|
|
||||||
function transformState(state) { |
|
||||||
const PreferencesController = state?.PreferencesController || {}; |
|
||||||
const preferences = PreferencesController.preferences || {}; |
|
||||||
const oldIpfsGateWay = preferences.ipfsGateway; |
|
||||||
|
|
||||||
let newState; |
|
||||||
|
|
||||||
if (oldIpfsGateWay && oldIpfsGateWay !== 'dweb.link') { |
|
||||||
const newIpfsGateway = new URL( |
|
||||||
addUrlProtocolPrefix(oldIpfsGateWay), |
|
||||||
).toString(); |
|
||||||
newState = { |
|
||||||
...state, |
|
||||||
PreferencesController: { |
|
||||||
...PreferencesController, |
|
||||||
preferences: { |
|
||||||
...preferences, |
|
||||||
ipfsGateway: newIpfsGateway, |
|
||||||
}, |
|
||||||
}, |
|
||||||
}; |
|
||||||
} else { |
|
||||||
newState = { |
|
||||||
...state, |
|
||||||
PreferencesController: { |
|
||||||
...PreferencesController, |
|
||||||
preferences: { |
|
||||||
...preferences, |
|
||||||
ipfsGateway: IPFS_DEFAULT_GATEWAY_URL, |
|
||||||
}, |
|
||||||
}, |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
return newState; |
|
||||||
} |
|
@ -1,56 +0,0 @@ |
|||||||
import { IPFS_DEFAULT_GATEWAY_URL } from '../../../shared/constants/network'; |
|
||||||
import migration68 from './068'; |
|
||||||
|
|
||||||
describe('migration #68', () => { |
|
||||||
it('should update the version metadata', async () => { |
|
||||||
const oldStorage = { |
|
||||||
meta: { |
|
||||||
version: 67, |
|
||||||
}, |
|
||||||
data: {}, |
|
||||||
}; |
|
||||||
|
|
||||||
const newStorage = await migration68.migrate(oldStorage); |
|
||||||
expect(newStorage.meta).toStrictEqual({ |
|
||||||
version: 68, |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should set preference ipfsGateway to "https://cloudflare-ipfs.com" if ipfsGateway is old default dweb.link', async () => { |
|
||||||
const expectedValue = IPFS_DEFAULT_GATEWAY_URL; // = https://cloudflare-ipfs.com
|
|
||||||
const oldStorage = { |
|
||||||
meta: {}, |
|
||||||
data: { |
|
||||||
PreferencesController: { |
|
||||||
preferences: { |
|
||||||
ipfsGateway: 'dweb.link', |
|
||||||
}, |
|
||||||
}, |
|
||||||
}, |
|
||||||
}; |
|
||||||
|
|
||||||
const newStorage = await migration68.migrate(oldStorage); |
|
||||||
expect(newStorage.data.PreferencesController.preferences.ipfsGateway).toBe( |
|
||||||
expectedValue, |
|
||||||
); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should update preference ipfsGateway to a full url version of user set ipfsGateway if ipfsGateway is not old default dweb.link', async () => { |
|
||||||
const expectedValue = 'https://random.ipfs/'; |
|
||||||
const oldStorage = { |
|
||||||
meta: {}, |
|
||||||
data: { |
|
||||||
PreferencesController: { |
|
||||||
preferences: { |
|
||||||
ipfsGateway: 'random.ipfs', |
|
||||||
}, |
|
||||||
}, |
|
||||||
}, |
|
||||||
}; |
|
||||||
|
|
||||||
const newStorage = await migration68.migrate(oldStorage); |
|
||||||
expect(newStorage.data.PreferencesController.preferences.ipfsGateway).toBe( |
|
||||||
expectedValue, |
|
||||||
); |
|
||||||
}); |
|
||||||
}); |
|
@ -1,212 +0,0 @@ |
|||||||
import React from 'react'; |
|
||||||
import PropTypes from 'prop-types'; |
|
||||||
import { useDispatch, useSelector } from 'react-redux'; |
|
||||||
import { useHistory } from 'react-router-dom'; |
|
||||||
import { getTokenTrackerLink } from '@metamask/etherscan-link'; |
|
||||||
import Box from '../../ui/box'; |
|
||||||
import Typography from '../../ui/typography/typography'; |
|
||||||
import { |
|
||||||
COLORS, |
|
||||||
TYPOGRAPHY, |
|
||||||
BLOCK_SIZES, |
|
||||||
FONT_WEIGHT, |
|
||||||
JUSTIFY_CONTENT, |
|
||||||
FLEX_DIRECTION, |
|
||||||
OVERFLOW_WRAP, |
|
||||||
DISPLAY, |
|
||||||
} from '../../../helpers/constants/design-system'; |
|
||||||
import { useI18nContext } from '../../../hooks/useI18nContext'; |
|
||||||
import { |
|
||||||
getAssetImageURL, |
|
||||||
isEqualCaseInsensitive, |
|
||||||
shortenAddress, |
|
||||||
} from '../../../helpers/utils/util'; |
|
||||||
import { |
|
||||||
getCurrentChainId, |
|
||||||
getIpfsGateway, |
|
||||||
getRpcPrefsForCurrentProvider, |
|
||||||
getSelectedIdentity, |
|
||||||
} from '../../../selectors'; |
|
||||||
import AssetNavigation from '../../../pages/asset/components/asset-navigation'; |
|
||||||
import { getCollectibleContracts } from '../../../ducks/metamask/metamask'; |
|
||||||
import { DEFAULT_ROUTE } from '../../../helpers/constants/routes'; |
|
||||||
import { removeAndIgnoreCollectible } from '../../../store/actions'; |
|
||||||
import { |
|
||||||
GOERLI_CHAIN_ID, |
|
||||||
KOVAN_CHAIN_ID, |
|
||||||
MAINNET_CHAIN_ID, |
|
||||||
POLYGON_CHAIN_ID, |
|
||||||
RINKEBY_CHAIN_ID, |
|
||||||
ROPSTEN_CHAIN_ID, |
|
||||||
} from '../../../../shared/constants/network'; |
|
||||||
import { getEnvironmentType } from '../../../../app/scripts/lib/util'; |
|
||||||
import { ENVIRONMENT_TYPE_POPUP } from '../../../../shared/constants/app'; |
|
||||||
import CollectibleOptions from './collectible-options'; |
|
||||||
|
|
||||||
export default function CollectibleDetails({ collectible }) { |
|
||||||
const { image, name, description, address, tokenId } = collectible; |
|
||||||
const t = useI18nContext(); |
|
||||||
const history = useHistory(); |
|
||||||
const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider); |
|
||||||
const ipfsGateway = useSelector(getIpfsGateway); |
|
||||||
const collectibleContracts = useSelector(getCollectibleContracts); |
|
||||||
const currentNetwork = useSelector(getCurrentChainId); |
|
||||||
|
|
||||||
const collectibleContractName = collectibleContracts.find( |
|
||||||
({ address: contractAddress }) => |
|
||||||
isEqualCaseInsensitive(contractAddress, address), |
|
||||||
)?.name; |
|
||||||
const selectedAccountName = useSelector( |
|
||||||
(state) => getSelectedIdentity(state).name, |
|
||||||
); |
|
||||||
const collectibleImageURL = getAssetImageURL(image, ipfsGateway); |
|
||||||
const dispatch = useDispatch(); |
|
||||||
|
|
||||||
const onRemove = () => { |
|
||||||
dispatch(removeAndIgnoreCollectible(address, tokenId)); |
|
||||||
history.push(DEFAULT_ROUTE); |
|
||||||
}; |
|
||||||
|
|
||||||
const getOpenSeaLink = () => { |
|
||||||
switch (currentNetwork) { |
|
||||||
case MAINNET_CHAIN_ID: |
|
||||||
return `https://opensea.io/assets/${address}/${tokenId}`; |
|
||||||
case POLYGON_CHAIN_ID: |
|
||||||
return `https://opensea.io/assets/matic/${address}/${tokenId}`; |
|
||||||
case GOERLI_CHAIN_ID: |
|
||||||
case KOVAN_CHAIN_ID: |
|
||||||
case ROPSTEN_CHAIN_ID: |
|
||||||
case RINKEBY_CHAIN_ID: |
|
||||||
return `https://testnets.opensea.io/assets/${address}/${tokenId}`; |
|
||||||
default: |
|
||||||
return null; |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
const openSeaLink = getOpenSeaLink(); |
|
||||||
return ( |
|
||||||
<> |
|
||||||
<AssetNavigation |
|
||||||
accountName={selectedAccountName} |
|
||||||
assetName={collectibleContractName} |
|
||||||
onBack={() => history.push(DEFAULT_ROUTE)} |
|
||||||
optionsButton={ |
|
||||||
<CollectibleOptions |
|
||||||
onViewOnOpensea={ |
|
||||||
openSeaLink |
|
||||||
? () => global.platform.openTab({ url: openSeaLink }) |
|
||||||
: null |
|
||||||
} |
|
||||||
onRemove={onRemove} |
|
||||||
/> |
|
||||||
} |
|
||||||
/> |
|
||||||
<Box padding={[4, 2, 4, 2]}> |
|
||||||
<div className="collectible-details"> |
|
||||||
<Box margin={3} padding={2} justifyContent={JUSTIFY_CONTENT.CENTER}> |
|
||||||
<img style={{ width: '14rem' }} src={collectibleImageURL} /> |
|
||||||
</Box> |
|
||||||
<Box |
|
||||||
margin={3} |
|
||||||
flexDirection={FLEX_DIRECTION.COLUMN} |
|
||||||
width={ |
|
||||||
getEnvironmentType() === ENVIRONMENT_TYPE_POPUP |
|
||||||
? BLOCK_SIZES.THREE_FOURTHS |
|
||||||
: BLOCK_SIZES.HALF |
|
||||||
} |
|
||||||
> |
|
||||||
<Typography |
|
||||||
color={COLORS.BLACK} |
|
||||||
variant={TYPOGRAPHY.H4} |
|
||||||
fontWeight={FONT_WEIGHT.BOLD} |
|
||||||
> |
|
||||||
{name} |
|
||||||
</Typography> |
|
||||||
<Typography |
|
||||||
color={COLORS.UI3} |
|
||||||
variant={TYPOGRAPHY.H5} |
|
||||||
boxProps={{ marginTop: 2, marginBottom: 3 }} |
|
||||||
overflowWrap={OVERFLOW_WRAP.BREAK_WORD} |
|
||||||
> |
|
||||||
{`#${tokenId}`} |
|
||||||
</Typography> |
|
||||||
<Typography |
|
||||||
color={COLORS.BLACK} |
|
||||||
variant={TYPOGRAPHY.H6} |
|
||||||
fontWeight={FONT_WEIGHT.BOLD} |
|
||||||
className="collectible-details__description" |
|
||||||
> |
|
||||||
{t('description')} |
|
||||||
</Typography> |
|
||||||
<Typography color={COLORS.UI3} variant={TYPOGRAPHY.H6}> |
|
||||||
{description} |
|
||||||
</Typography> |
|
||||||
</Box> |
|
||||||
</div> |
|
||||||
<Box margin={4}> |
|
||||||
<Box display={DISPLAY.FLEX} flexDirection={FLEX_DIRECTION.ROW}> |
|
||||||
<Typography |
|
||||||
color={COLORS.BLACK} |
|
||||||
variant={TYPOGRAPHY.H6} |
|
||||||
fontWeight={FONT_WEIGHT.BOLD} |
|
||||||
boxProps={{ marginBottom: 3, width: BLOCK_SIZES.ONE_FOURTH }} |
|
||||||
> |
|
||||||
{t('source')} |
|
||||||
</Typography> |
|
||||||
<Typography |
|
||||||
color={COLORS.PRIMARY1} |
|
||||||
variant={TYPOGRAPHY.H6} |
|
||||||
boxProps={{ marginBottom: 3, width: BLOCK_SIZES.THREE_FOURTHS }} |
|
||||||
overflowWrap={OVERFLOW_WRAP.BREAK_WORD} |
|
||||||
> |
|
||||||
<a |
|
||||||
target="_blank" |
|
||||||
href={collectibleImageURL} |
|
||||||
rel="noopener noreferrer" |
|
||||||
style={{ overflow: 'hidden', textOverflow: 'ellipsis' }} |
|
||||||
> |
|
||||||
{image} |
|
||||||
</a> |
|
||||||
</Typography> |
|
||||||
</Box> |
|
||||||
<Box display={DISPLAY.FLEX} flexDirection={FLEX_DIRECTION.ROW}> |
|
||||||
<Typography |
|
||||||
color={COLORS.BLACK} |
|
||||||
variant={TYPOGRAPHY.H6} |
|
||||||
fontWeight={FONT_WEIGHT.BOLD} |
|
||||||
boxProps={{ width: BLOCK_SIZES.ONE_FOURTH }} |
|
||||||
> |
|
||||||
{t('contractAddress')} |
|
||||||
</Typography> |
|
||||||
<Typography |
|
||||||
color={COLORS.UI3} |
|
||||||
variant={TYPOGRAPHY.H6} |
|
||||||
overflowWrap={OVERFLOW_WRAP.BREAK_WORD} |
|
||||||
boxProps={{ width: BLOCK_SIZES.THREE_FOURTHS }} |
|
||||||
> |
|
||||||
<a |
|
||||||
target="_blank" |
|
||||||
href={getTokenTrackerLink( |
|
||||||
address, |
|
||||||
currentNetwork, |
|
||||||
null, |
|
||||||
null, |
|
||||||
rpcPrefs, |
|
||||||
)} |
|
||||||
rel="noopener noreferrer" |
|
||||||
> |
|
||||||
{getEnvironmentType() === ENVIRONMENT_TYPE_POPUP |
|
||||||
? shortenAddress(address) |
|
||||||
: address} |
|
||||||
</a> |
|
||||||
</Typography> |
|
||||||
</Box> |
|
||||||
</Box> |
|
||||||
</Box> |
|
||||||
</> |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
CollectibleDetails.propTypes = { |
|
||||||
collectible: PropTypes.object, |
|
||||||
}; |
|
@ -1,23 +0,0 @@ |
|||||||
import React from 'react'; |
|
||||||
import CollectibleDetails from './collectible-details'; |
|
||||||
|
|
||||||
export default { |
|
||||||
title: 'Components/App/CollectibleDetails', |
|
||||||
id: __filename, |
|
||||||
}; |
|
||||||
|
|
||||||
export const basic = () => { |
|
||||||
const collectible = { |
|
||||||
name: 'Catnip Spicywright', |
|
||||||
tokenId: '1124157', |
|
||||||
address: '0x06012c8cf97bead5deae237070f9587f8e7a266d', |
|
||||||
image: './images/catnip-spicywright.png', |
|
||||||
description: |
|
||||||
"Good day. My name is Catnip Spicywight, which got me teased a lot in high school. If I want to put low fat mayo all over my hamburgers, I shouldn't have to answer to anyone about it, am I right? One time I beat Arlene in an arm wrestle.", |
|
||||||
}; |
|
||||||
return ( |
|
||||||
<div style={{ width: '420px' }}> |
|
||||||
<CollectibleDetails collectible={collectible} /> |
|
||||||
</div> |
|
||||||
); |
|
||||||
}; |
|
@ -1,61 +0,0 @@ |
|||||||
import React, { useContext, useState } from 'react'; |
|
||||||
import PropTypes from 'prop-types'; |
|
||||||
|
|
||||||
import { I18nContext } from '../../../contexts/i18n'; |
|
||||||
import { Menu, MenuItem } from '../../ui/menu'; |
|
||||||
|
|
||||||
const CollectibleOptions = ({ onRemove, onViewOnOpensea }) => { |
|
||||||
const t = useContext(I18nContext); |
|
||||||
const [ |
|
||||||
collectibleOptionsButtonElement, |
|
||||||
setCollectibleOptionsButtonElement, |
|
||||||
] = useState(null); |
|
||||||
const [collectibleOptionsOpen, setCollectibleOptionsOpen] = useState(false); |
|
||||||
|
|
||||||
return ( |
|
||||||
<> |
|
||||||
<button |
|
||||||
className="fas fa-ellipsis-v collectible-options__button" |
|
||||||
data-testid="collectible-options__button" |
|
||||||
onClick={() => setCollectibleOptionsOpen(true)} |
|
||||||
ref={setCollectibleOptionsButtonElement} |
|
||||||
/> |
|
||||||
{collectibleOptionsOpen ? ( |
|
||||||
<Menu |
|
||||||
anchorElement={collectibleOptionsButtonElement} |
|
||||||
onHide={() => setCollectibleOptionsOpen(false)} |
|
||||||
> |
|
||||||
{onViewOnOpensea ? ( |
|
||||||
<MenuItem |
|
||||||
iconClassName="fas fa-qrcode" |
|
||||||
data-testid="collectible-options__view-on-opensea" |
|
||||||
onClick={() => { |
|
||||||
setCollectibleOptionsOpen(false); |
|
||||||
onViewOnOpensea(); |
|
||||||
}} |
|
||||||
> |
|
||||||
{t('viewOnOpensea')} |
|
||||||
</MenuItem> |
|
||||||
) : null} |
|
||||||
<MenuItem |
|
||||||
iconClassName="fas fa-trash-alt collectible-options__icon" |
|
||||||
data-testid="collectible-options__hide" |
|
||||||
onClick={() => { |
|
||||||
setCollectibleOptionsOpen(false); |
|
||||||
onRemove(); |
|
||||||
}} |
|
||||||
> |
|
||||||
{t('removeNFT')} |
|
||||||
</MenuItem> |
|
||||||
</Menu> |
|
||||||
) : null} |
|
||||||
</> |
|
||||||
); |
|
||||||
}; |
|
||||||
|
|
||||||
CollectibleOptions.propTypes = { |
|
||||||
onRemove: PropTypes.func.isRequired, |
|
||||||
onViewOnOpensea: PropTypes.func.isRequired, |
|
||||||
}; |
|
||||||
|
|
||||||
export default CollectibleOptions; |
|
@ -1,26 +0,0 @@ |
|||||||
.collectible-details { |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
|
|
||||||
@media screen and (min-width: $break-large) { |
|
||||||
display: flex; |
|
||||||
flex-direction: row; |
|
||||||
} |
|
||||||
|
|
||||||
&__address { |
|
||||||
overflow-wrap: break-word; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
.collectible-options { |
|
||||||
&__button { |
|
||||||
font-size: $font-size-paragraph; |
|
||||||
color: $Black-100; |
|
||||||
background-color: inherit; |
|
||||||
padding: 2px 0 2px 8px; |
|
||||||
} |
|
||||||
|
|
||||||
&__icon { |
|
||||||
font-weight: 900; |
|
||||||
} |
|
||||||
} |
|
@ -1,18 +0,0 @@ |
|||||||
.collectibles-items { |
|
||||||
&__image { |
|
||||||
border-radius: 0.625rem; |
|
||||||
width: 100%; |
|
||||||
height: 100%; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
.collection-icon { |
|
||||||
border-radius: 50%; |
|
||||||
width: 2rem; |
|
||||||
height: 2rem; |
|
||||||
padding: 0.5rem; |
|
||||||
background: $ui-4; |
|
||||||
color: $ui-white; |
|
||||||
text-align: center; |
|
||||||
line-height: 1; |
|
||||||
} |
|
Loading…
Reference in new issue