diff --git a/dev.html b/dev.html index 9645e11..0f73162 100644 --- a/dev.html +++ b/dev.html @@ -386,7 +386,7 @@
Solana Token from MetaPlex
ReactDOM.createRoot( document.getElementById('solanaTokenFromMetaPlex') ).render( - React.createElement(window.ReactTokenImage.TokenImage, { className:"Token", blockchain: 'solana', address: 'SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt' }), + React.createElement(window.ReactTokenImage.TokenImage, { className:"Token", blockchain: 'solana', address: 'METAewgxyPbgwsseH8T16a39CQ5VyVxZi9zXiDPY18m' }), ) @@ -512,7 +512,7 @@
Fantom Token from Trustwallet
-
Polygon Token from DePay API
+
Fantom Token from DePay API
@@ -531,6 +531,98 @@
Polygon Token from DePay API
+
+

Avalanche

+ +
+
+
+
+
Token: Avalanche Fantom
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
Avalance Token from web3-blockchains
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
Avalanche Token from Trustwallet
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
Avalanche Token from DePay API
+
+
+
+
+
+ +
+
+
+
+
+

NFTS

diff --git a/dist/esm/index.evm.js b/dist/esm/index.evm.js index d58af0e..2036794 100644 --- a/dist/esm/index.evm.js +++ b/dist/esm/index.evm.js @@ -3,8 +3,8 @@ import Token from '@depay/web3-tokens-evm'; import React, { useState, useEffect } from 'react'; import Blockchains from '@depay/web3-blockchains'; -let supported = ['ethereum', 'bsc', 'polygon', 'fantom', 'velas']; -supported.evm = ['ethereum', 'bsc', 'polygon', 'fantom', 'velas']; +let supported = ['ethereum', 'bsc', 'polygon', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism']; +supported.evm = ['ethereum', 'bsc', 'polygon', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism']; supported.solana = []; const _jsxFileName = "/Users/sebastian/Work/DePay/react-token-image/src/index.js"; function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } @@ -15,34 +15,46 @@ const UNKNOWN_IMAGE = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmN let TokenImage = function(props){ - const [src, _setSrc] = useState(); - const [source, setSource] = useState(); + const [src, setSrc] = useState(); + const [source, _setSource] = useState(); const blockchain = props.blockchain.toLowerCase(); const address = props.address; const id = props.id; const date = new Date(); - const localStorageKey = ['react-token-image', blockchain, address, [date.getFullYear(), date.getMonth(), date.getDate()].join('-')].join('-'); + const getLocalStorageKey = (blockchain, address)=>{ + return [ + 'react-token-image', + blockchain, + address, + [date.getFullYear(), date.getMonth(), date.getDate()].join('-') + ].join('-') + }; - const setSrc = (_src)=>{ - localStorage.setItem(localStorageKey, _src); - _setSrc(_src); + const setSource = (src, source)=>{ + setSrc(src); + _setSource(source); + if(source != 'unknown') { + localStorage.setItem(getLocalStorageKey(blockchain, address), src); + } }; useEffect(()=>{ - const storedImage = localStorage.getItem(localStorageKey); - if(storedImage && storedImage.length && storedImage != UNKNOWN_IMAGE) { return setSrc(storedImage) } + const storedImage = localStorage.getItem(getLocalStorageKey(blockchain, address)); + if(storedImage && storedImage.length && storedImage != UNKNOWN_IMAGE) { + return setSource(storedImage, 'stored') + } const foundMajorToken = Blockchains[blockchain].tokens.find((token)=> token.address.toLowerCase() === address.toLowerCase()); if(foundMajorToken) { - setSrc(foundMajorToken.logo); + setSource(foundMajorToken.logo, 'web3-blockchains'); } else { if(supported.evm.includes(blockchain)) { - setSource('repository'); - setSrc(logoFromRepository({ blockchain, address })); + setSource(logoFromRepository({ blockchain, address }), 'repository'); } else if(blockchain === 'solana') { - setSource('metaplex'); logoFromMetaplex({ blockchain, address }).then((image)=>{ - setSrc(image); + setSource(image, 'metaplex'); + }).catch((error)=>{ + setSource(logoFromRepository({ blockchain, address }), 'repository'); }); } } @@ -69,6 +81,7 @@ let TokenImage = function(props){ api: Token.solana.METADATA_LAYOUT, cache: 86400000, // 1 day }); + if(_optionalChain([metaData, 'optionalAccess', _ => _.data, 'optionalAccess', _2 => _2.uri])) { @@ -80,26 +93,22 @@ let TokenImage = function(props){ if(json && json.image) { resolve(json.image); } else { - resolve(''); + reject('image not found on metaplex'); } - }).catch(()=>resolve('')); + }).catch(()=>reject('image not found on metaplex')); } else { - resolve(''); + reject('image not found on metaplex'); } } else { - resolve(''); + reject('image not found on metaplex'); } - } catch (e) { resolve(''); } + } catch (e) { reject('image not found on metaplex'); } }) }; const logoFromRepository = ({ blockchain, address })=> { - if(['ethereum', 'bsc', 'polygon', 'fantom', 'solana'].includes(blockchain)) { - return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${mapBlockchainNameToTrustWalletAssets(blockchain)}/assets/${address}/logo.png` - } else if(blockchain == 'velas'){ - return `https://raw.githubusercontent.com/wagyuswapapp/assets/master/blockchains/velas/assets/${address.toLowerCase()}/logo.png` - } + return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${mapBlockchainNameToTrustWalletAssets(blockchain)}/assets/${address}/logo.png` }; const mapBlockchainNameToTrustWalletAssets = (blockchain)=>{ @@ -128,8 +137,7 @@ let TokenImage = function(props){ }; const setUnknown = ()=>{ - setSource('unknown'); - setSrc(UNKNOWN_IMAGE); + setSource(UNKNOWN_IMAGE, 'unknown'); }; const uriToImage = (tokenURI)=>{ @@ -147,8 +155,7 @@ let TokenImage = function(props){ if(image.match(/^ipfs/)) { image = `https://ipfs.io/ipfs/${image.split('://')[1]}`; } - setSource('meta'); - setSrc(image); + setSource(image, 'meta'); } else { setUnknown(); } @@ -157,12 +164,13 @@ let TokenImage = function(props){ }; const handleLoadError = (error)=> { + delete localStorage[getLocalStorageKey(blockchain, address)]; if(source == 'metaplex') { - setSource('repository'); - setSrc(logoFromRepository({ blockchain, address })); + setSource(logoFromRepository({ blockchain, address }), 'repository'); + } else if(source == 'web3-blockchains') { + setSource(logoFromRepository({ blockchain, address }), 'repository'); } else if(source == 'repository') { - setSource('depay'); - setSrc(`https://integrate.depay.com/tokens/${blockchain}/${address}/image`); + setSource(`https://integrate.depay.com/tokens/${blockchain}/${address}/image`, 'depay'); } else if (source == 'depay' && supported.evm.includes(blockchain)) { if(id) { request({ blockchain, address, api: uriAPI, method: 'uri', params: [id] }).then((uri)=>{ @@ -177,13 +185,17 @@ let TokenImage = function(props){ } }; - if(src == undefined) { return null } + if(src == undefined) { + return( + React.createElement('div', { className: props.className , __self: this, __source: {fileName: _jsxFileName, lineNumber: 197}} ) + ) + } return( React.createElement('img', { className: props.className , src: src , - onError: handleLoadError , __self: this, __source: {fileName: _jsxFileName, lineNumber: 190}} + onError: handleLoadError , __self: this, __source: {fileName: _jsxFileName, lineNumber: 202}} ) ) }; diff --git a/dist/esm/index.js b/dist/esm/index.js index f4569f5..b3bc35b 100644 --- a/dist/esm/index.js +++ b/dist/esm/index.js @@ -4,8 +4,8 @@ import Token from '@depay/web3-tokens'; import React, { useState, useEffect } from 'react'; import Blockchains from '@depay/web3-blockchains'; -let supported = ['ethereum', 'bsc', 'polygon', 'solana', 'fantom', 'velas']; -supported.evm = ['ethereum', 'bsc', 'polygon', 'fantom', 'velas']; +let supported = ['ethereum', 'bsc', 'polygon', 'solana', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism']; +supported.evm = ['ethereum', 'bsc', 'polygon', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism']; supported.solana = ['solana']; const _jsxFileName = "/Users/sebastian/Work/DePay/react-token-image/src/index.js"; function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } @@ -16,34 +16,46 @@ const UNKNOWN_IMAGE = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmN let TokenImage = function(props){ - const [src, _setSrc] = useState(); - const [source, setSource] = useState(); + const [src, setSrc] = useState(); + const [source, _setSource] = useState(); const blockchain = props.blockchain.toLowerCase(); const address = props.address; const id = props.id; const date = new Date(); - const localStorageKey = ['react-token-image', blockchain, address, [date.getFullYear(), date.getMonth(), date.getDate()].join('-')].join('-'); + const getLocalStorageKey = (blockchain, address)=>{ + return [ + 'react-token-image', + blockchain, + address, + [date.getFullYear(), date.getMonth(), date.getDate()].join('-') + ].join('-') + }; - const setSrc = (_src)=>{ - localStorage.setItem(localStorageKey, _src); - _setSrc(_src); + const setSource = (src, source)=>{ + setSrc(src); + _setSource(source); + if(source != 'unknown') { + localStorage.setItem(getLocalStorageKey(blockchain, address), src); + } }; useEffect(()=>{ - const storedImage = localStorage.getItem(localStorageKey); - if(storedImage && storedImage.length && storedImage != UNKNOWN_IMAGE) { return setSrc(storedImage) } + const storedImage = localStorage.getItem(getLocalStorageKey(blockchain, address)); + if(storedImage && storedImage.length && storedImage != UNKNOWN_IMAGE) { + return setSource(storedImage, 'stored') + } const foundMajorToken = Blockchains[blockchain].tokens.find((token)=> token.address.toLowerCase() === address.toLowerCase()); if(foundMajorToken) { - setSrc(foundMajorToken.logo); + setSource(foundMajorToken.logo, 'web3-blockchains'); } else { if(supported.evm.includes(blockchain)) { - setSource('repository'); - setSrc(logoFromRepository({ blockchain, address })); + setSource(logoFromRepository({ blockchain, address }), 'repository'); } else if(blockchain === 'solana') { - setSource('metaplex'); logoFromMetaplex({ blockchain, address }).then((image)=>{ - setSrc(image); + setSource(image, 'metaplex'); + }).catch((error)=>{ + setSource(logoFromRepository({ blockchain, address }), 'repository'); }); } } @@ -70,6 +82,7 @@ let TokenImage = function(props){ api: Token.solana.METADATA_LAYOUT, cache: 86400000, // 1 day }); + if(_optionalChain([metaData, 'optionalAccess', _ => _.data, 'optionalAccess', _2 => _2.uri])) { @@ -81,26 +94,22 @@ let TokenImage = function(props){ if(json && json.image) { resolve(json.image); } else { - resolve(''); + reject('image not found on metaplex'); } - }).catch(()=>resolve('')); + }).catch(()=>reject('image not found on metaplex')); } else { - resolve(''); + reject('image not found on metaplex'); } } else { - resolve(''); + reject('image not found on metaplex'); } - } catch (e) { resolve(''); } + } catch (e) { reject('image not found on metaplex'); } }) }; const logoFromRepository = ({ blockchain, address })=> { - if(['ethereum', 'bsc', 'polygon', 'fantom', 'solana'].includes(blockchain)) { - return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${mapBlockchainNameToTrustWalletAssets(blockchain)}/assets/${address}/logo.png` - } else if(blockchain == 'velas'){ - return `https://raw.githubusercontent.com/wagyuswapapp/assets/master/blockchains/velas/assets/${address.toLowerCase()}/logo.png` - } + return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${mapBlockchainNameToTrustWalletAssets(blockchain)}/assets/${address}/logo.png` }; const mapBlockchainNameToTrustWalletAssets = (blockchain)=>{ @@ -129,8 +138,7 @@ let TokenImage = function(props){ }; const setUnknown = ()=>{ - setSource('unknown'); - setSrc(UNKNOWN_IMAGE); + setSource(UNKNOWN_IMAGE, 'unknown'); }; const uriToImage = (tokenURI)=>{ @@ -148,8 +156,7 @@ let TokenImage = function(props){ if(image.match(/^ipfs/)) { image = `https://ipfs.io/ipfs/${image.split('://')[1]}`; } - setSource('meta'); - setSrc(image); + setSource(image, 'meta'); } else { setUnknown(); } @@ -158,12 +165,13 @@ let TokenImage = function(props){ }; const handleLoadError = (error)=> { + delete localStorage[getLocalStorageKey(blockchain, address)]; if(source == 'metaplex') { - setSource('repository'); - setSrc(logoFromRepository({ blockchain, address })); + setSource(logoFromRepository({ blockchain, address }), 'repository'); + } else if(source == 'web3-blockchains') { + setSource(logoFromRepository({ blockchain, address }), 'repository'); } else if(source == 'repository') { - setSource('depay'); - setSrc(`https://integrate.depay.com/tokens/${blockchain}/${address}/image`); + setSource(`https://integrate.depay.com/tokens/${blockchain}/${address}/image`, 'depay'); } else if (source == 'depay' && supported.evm.includes(blockchain)) { if(id) { request({ blockchain, address, api: uriAPI, method: 'uri', params: [id] }).then((uri)=>{ @@ -178,13 +186,17 @@ let TokenImage = function(props){ } }; - if(src == undefined) { return null } + if(src == undefined) { + return( + React.createElement('div', { className: props.className , __self: this, __source: {fileName: _jsxFileName, lineNumber: 198}} ) + ) + } return( React.createElement('img', { className: props.className , src: src , - onError: handleLoadError , __self: this, __source: {fileName: _jsxFileName, lineNumber: 191}} + onError: handleLoadError , __self: this, __source: {fileName: _jsxFileName, lineNumber: 203}} ) ) }; diff --git a/dist/esm/index.solana.js b/dist/esm/index.solana.js index aa27432..ec33f40 100644 --- a/dist/esm/index.solana.js +++ b/dist/esm/index.solana.js @@ -16,34 +16,46 @@ const UNKNOWN_IMAGE = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmN let TokenImage = function(props){ - const [src, _setSrc] = useState(); - const [source, setSource] = useState(); + const [src, setSrc] = useState(); + const [source, _setSource] = useState(); const blockchain = props.blockchain.toLowerCase(); const address = props.address; const id = props.id; const date = new Date(); - const localStorageKey = ['react-token-image', blockchain, address, [date.getFullYear(), date.getMonth(), date.getDate()].join('-')].join('-'); + const getLocalStorageKey = (blockchain, address)=>{ + return [ + 'react-token-image', + blockchain, + address, + [date.getFullYear(), date.getMonth(), date.getDate()].join('-') + ].join('-') + }; - const setSrc = (_src)=>{ - localStorage.setItem(localStorageKey, _src); - _setSrc(_src); + const setSource = (src, source)=>{ + setSrc(src); + _setSource(source); + if(source != 'unknown') { + localStorage.setItem(getLocalStorageKey(blockchain, address), src); + } }; useEffect(()=>{ - const storedImage = localStorage.getItem(localStorageKey); - if(storedImage && storedImage.length && storedImage != UNKNOWN_IMAGE) { return setSrc(storedImage) } + const storedImage = localStorage.getItem(getLocalStorageKey(blockchain, address)); + if(storedImage && storedImage.length && storedImage != UNKNOWN_IMAGE) { + return setSource(storedImage, 'stored') + } const foundMajorToken = Blockchains[blockchain].tokens.find((token)=> token.address.toLowerCase() === address.toLowerCase()); if(foundMajorToken) { - setSrc(foundMajorToken.logo); + setSource(foundMajorToken.logo, 'web3-blockchains'); } else { if(supported.evm.includes(blockchain)) { - setSource('repository'); - setSrc(logoFromRepository({ blockchain, address })); + setSource(logoFromRepository({ blockchain, address }), 'repository'); } else if(blockchain === 'solana') { - setSource('metaplex'); logoFromMetaplex({ blockchain, address }).then((image)=>{ - setSrc(image); + setSource(image, 'metaplex'); + }).catch((error)=>{ + setSource(logoFromRepository({ blockchain, address }), 'repository'); }); } } @@ -70,6 +82,7 @@ let TokenImage = function(props){ api: Token.solana.METADATA_LAYOUT, cache: 86400000, // 1 day }); + if(_optionalChain([metaData, 'optionalAccess', _ => _.data, 'optionalAccess', _2 => _2.uri])) { @@ -81,26 +94,22 @@ let TokenImage = function(props){ if(json && json.image) { resolve(json.image); } else { - resolve(''); + reject('image not found on metaplex'); } - }).catch(()=>resolve('')); + }).catch(()=>reject('image not found on metaplex')); } else { - resolve(''); + reject('image not found on metaplex'); } } else { - resolve(''); + reject('image not found on metaplex'); } - } catch (e) { resolve(''); } + } catch (e) { reject('image not found on metaplex'); } }) }; const logoFromRepository = ({ blockchain, address })=> { - if(['ethereum', 'bsc', 'polygon', 'fantom', 'solana'].includes(blockchain)) { - return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${mapBlockchainNameToTrustWalletAssets(blockchain)}/assets/${address}/logo.png` - } else if(blockchain == 'velas'){ - return `https://raw.githubusercontent.com/wagyuswapapp/assets/master/blockchains/velas/assets/${address.toLowerCase()}/logo.png` - } + return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${mapBlockchainNameToTrustWalletAssets(blockchain)}/assets/${address}/logo.png` }; const mapBlockchainNameToTrustWalletAssets = (blockchain)=>{ @@ -129,8 +138,7 @@ let TokenImage = function(props){ }; const setUnknown = ()=>{ - setSource('unknown'); - setSrc(UNKNOWN_IMAGE); + setSource(UNKNOWN_IMAGE, 'unknown'); }; const uriToImage = (tokenURI)=>{ @@ -148,8 +156,7 @@ let TokenImage = function(props){ if(image.match(/^ipfs/)) { image = `https://ipfs.io/ipfs/${image.split('://')[1]}`; } - setSource('meta'); - setSrc(image); + setSource(image, 'meta'); } else { setUnknown(); } @@ -158,12 +165,13 @@ let TokenImage = function(props){ }; const handleLoadError = (error)=> { + delete localStorage[getLocalStorageKey(blockchain, address)]; if(source == 'metaplex') { - setSource('repository'); - setSrc(logoFromRepository({ blockchain, address })); + setSource(logoFromRepository({ blockchain, address }), 'repository'); + } else if(source == 'web3-blockchains') { + setSource(logoFromRepository({ blockchain, address }), 'repository'); } else if(source == 'repository') { - setSource('depay'); - setSrc(`https://integrate.depay.com/tokens/${blockchain}/${address}/image`); + setSource(`https://integrate.depay.com/tokens/${blockchain}/${address}/image`, 'depay'); } else if (source == 'depay' && supported.evm.includes(blockchain)) { if(id) { request({ blockchain, address, api: uriAPI, method: 'uri', params: [id] }).then((uri)=>{ @@ -178,13 +186,17 @@ let TokenImage = function(props){ } }; - if(src == undefined) { return null } + if(src == undefined) { + return( + React.createElement('div', { className: props.className , __self: this, __source: {fileName: _jsxFileName, lineNumber: 198}} ) + ) + } return( React.createElement('img', { className: props.className , src: src , - onError: handleLoadError , __self: this, __source: {fileName: _jsxFileName, lineNumber: 191}} + onError: handleLoadError , __self: this, __source: {fileName: _jsxFileName, lineNumber: 203}} ) ) }; diff --git a/dist/umd/index.evm.js b/dist/umd/index.evm.js index a8fecf9..e55de32 100644 --- a/dist/umd/index.evm.js +++ b/dist/umd/index.evm.js @@ -10,8 +10,8 @@ var React__default = /*#__PURE__*/_interopDefaultLegacy(React); var Blockchains__default = /*#__PURE__*/_interopDefaultLegacy(Blockchains); - let supported = ['ethereum', 'bsc', 'polygon', 'fantom', 'velas']; - supported.evm = ['ethereum', 'bsc', 'polygon', 'fantom', 'velas']; + let supported = ['ethereum', 'bsc', 'polygon', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism']; + supported.evm = ['ethereum', 'bsc', 'polygon', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism']; supported.solana = []; const _jsxFileName = "/Users/sebastian/Work/DePay/react-token-image/src/index.js"; function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } @@ -22,34 +22,46 @@ let TokenImage = function(props){ - const [src, _setSrc] = React.useState(); - const [source, setSource] = React.useState(); + const [src, setSrc] = React.useState(); + const [source, _setSource] = React.useState(); const blockchain = props.blockchain.toLowerCase(); const address = props.address; const id = props.id; const date = new Date(); - const localStorageKey = ['react-token-image', blockchain, address, [date.getFullYear(), date.getMonth(), date.getDate()].join('-')].join('-'); + const getLocalStorageKey = (blockchain, address)=>{ + return [ + 'react-token-image', + blockchain, + address, + [date.getFullYear(), date.getMonth(), date.getDate()].join('-') + ].join('-') + }; - const setSrc = (_src)=>{ - localStorage.setItem(localStorageKey, _src); - _setSrc(_src); + const setSource = (src, source)=>{ + setSrc(src); + _setSource(source); + if(source != 'unknown') { + localStorage.setItem(getLocalStorageKey(blockchain, address), src); + } }; React.useEffect(()=>{ - const storedImage = localStorage.getItem(localStorageKey); - if(storedImage && storedImage.length && storedImage != UNKNOWN_IMAGE) { return setSrc(storedImage) } + const storedImage = localStorage.getItem(getLocalStorageKey(blockchain, address)); + if(storedImage && storedImage.length && storedImage != UNKNOWN_IMAGE) { + return setSource(storedImage, 'stored') + } const foundMajorToken = Blockchains__default['default'][blockchain].tokens.find((token)=> token.address.toLowerCase() === address.toLowerCase()); if(foundMajorToken) { - setSrc(foundMajorToken.logo); + setSource(foundMajorToken.logo, 'web3-blockchains'); } else { if(supported.evm.includes(blockchain)) { - setSource('repository'); - setSrc(logoFromRepository({ blockchain, address })); + setSource(logoFromRepository({ blockchain, address }), 'repository'); } else if(blockchain === 'solana') { - setSource('metaplex'); logoFromMetaplex({ blockchain, address }).then((image)=>{ - setSrc(image); + setSource(image, 'metaplex'); + }).catch((error)=>{ + setSource(logoFromRepository({ blockchain, address }), 'repository'); }); } } @@ -76,6 +88,7 @@ api: Token__default['default'].solana.METADATA_LAYOUT, cache: 86400000, // 1 day }); + if(_optionalChain([metaData, 'optionalAccess', _ => _.data, 'optionalAccess', _2 => _2.uri])) { @@ -87,26 +100,22 @@ if(json && json.image) { resolve(json.image); } else { - resolve(''); + reject('image not found on metaplex'); } - }).catch(()=>resolve('')); + }).catch(()=>reject('image not found on metaplex')); } else { - resolve(''); + reject('image not found on metaplex'); } } else { - resolve(''); + reject('image not found on metaplex'); } - } catch (e) { resolve(''); } + } catch (e) { reject('image not found on metaplex'); } }) }; const logoFromRepository = ({ blockchain, address })=> { - if(['ethereum', 'bsc', 'polygon', 'fantom', 'solana'].includes(blockchain)) { - return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${mapBlockchainNameToTrustWalletAssets(blockchain)}/assets/${address}/logo.png` - } else if(blockchain == 'velas'){ - return `https://raw.githubusercontent.com/wagyuswapapp/assets/master/blockchains/velas/assets/${address.toLowerCase()}/logo.png` - } + return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${mapBlockchainNameToTrustWalletAssets(blockchain)}/assets/${address}/logo.png` }; const mapBlockchainNameToTrustWalletAssets = (blockchain)=>{ @@ -135,8 +144,7 @@ }; const setUnknown = ()=>{ - setSource('unknown'); - setSrc(UNKNOWN_IMAGE); + setSource(UNKNOWN_IMAGE, 'unknown'); }; const uriToImage = (tokenURI)=>{ @@ -154,8 +162,7 @@ if(image.match(/^ipfs/)) { image = `https://ipfs.io/ipfs/${image.split('://')[1]}`; } - setSource('meta'); - setSrc(image); + setSource(image, 'meta'); } else { setUnknown(); } @@ -164,12 +171,13 @@ }; const handleLoadError = (error)=> { + delete localStorage[getLocalStorageKey(blockchain, address)]; if(source == 'metaplex') { - setSource('repository'); - setSrc(logoFromRepository({ blockchain, address })); + setSource(logoFromRepository({ blockchain, address }), 'repository'); + } else if(source == 'web3-blockchains') { + setSource(logoFromRepository({ blockchain, address }), 'repository'); } else if(source == 'repository') { - setSource('depay'); - setSrc(`https://integrate.depay.com/tokens/${blockchain}/${address}/image`); + setSource(`https://integrate.depay.com/tokens/${blockchain}/${address}/image`, 'depay'); } else if (source == 'depay' && supported.evm.includes(blockchain)) { if(id) { web3ClientEvm.request({ blockchain, address, api: uriAPI, method: 'uri', params: [id] }).then((uri)=>{ @@ -184,13 +192,17 @@ } }; - if(src == undefined) { return null } + if(src == undefined) { + return( + React__default['default'].createElement('div', { className: props.className , __self: this, __source: {fileName: _jsxFileName, lineNumber: 197}} ) + ) + } return( React__default['default'].createElement('img', { className: props.className , src: src , - onError: handleLoadError , __self: this, __source: {fileName: _jsxFileName, lineNumber: 190}} + onError: handleLoadError , __self: this, __source: {fileName: _jsxFileName, lineNumber: 202}} ) ) }; diff --git a/dist/umd/index.js b/dist/umd/index.js index 6c9569a..3a276a5 100644 --- a/dist/umd/index.js +++ b/dist/umd/index.js @@ -10,8 +10,8 @@ var React__default = /*#__PURE__*/_interopDefaultLegacy(React); var Blockchains__default = /*#__PURE__*/_interopDefaultLegacy(Blockchains); - let supported = ['ethereum', 'bsc', 'polygon', 'solana', 'fantom', 'velas']; - supported.evm = ['ethereum', 'bsc', 'polygon', 'fantom', 'velas']; + let supported = ['ethereum', 'bsc', 'polygon', 'solana', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism']; + supported.evm = ['ethereum', 'bsc', 'polygon', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism']; supported.solana = ['solana']; const _jsxFileName = "/Users/sebastian/Work/DePay/react-token-image/src/index.js"; function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } @@ -22,34 +22,46 @@ let TokenImage = function(props){ - const [src, _setSrc] = React.useState(); - const [source, setSource] = React.useState(); + const [src, setSrc] = React.useState(); + const [source, _setSource] = React.useState(); const blockchain = props.blockchain.toLowerCase(); const address = props.address; const id = props.id; const date = new Date(); - const localStorageKey = ['react-token-image', blockchain, address, [date.getFullYear(), date.getMonth(), date.getDate()].join('-')].join('-'); + const getLocalStorageKey = (blockchain, address)=>{ + return [ + 'react-token-image', + blockchain, + address, + [date.getFullYear(), date.getMonth(), date.getDate()].join('-') + ].join('-') + }; - const setSrc = (_src)=>{ - localStorage.setItem(localStorageKey, _src); - _setSrc(_src); + const setSource = (src, source)=>{ + setSrc(src); + _setSource(source); + if(source != 'unknown') { + localStorage.setItem(getLocalStorageKey(blockchain, address), src); + } }; React.useEffect(()=>{ - const storedImage = localStorage.getItem(localStorageKey); - if(storedImage && storedImage.length && storedImage != UNKNOWN_IMAGE) { return setSrc(storedImage) } + const storedImage = localStorage.getItem(getLocalStorageKey(blockchain, address)); + if(storedImage && storedImage.length && storedImage != UNKNOWN_IMAGE) { + return setSource(storedImage, 'stored') + } const foundMajorToken = Blockchains__default['default'][blockchain].tokens.find((token)=> token.address.toLowerCase() === address.toLowerCase()); if(foundMajorToken) { - setSrc(foundMajorToken.logo); + setSource(foundMajorToken.logo, 'web3-blockchains'); } else { if(supported.evm.includes(blockchain)) { - setSource('repository'); - setSrc(logoFromRepository({ blockchain, address })); + setSource(logoFromRepository({ blockchain, address }), 'repository'); } else if(blockchain === 'solana') { - setSource('metaplex'); logoFromMetaplex({ blockchain, address }).then((image)=>{ - setSrc(image); + setSource(image, 'metaplex'); + }).catch((error)=>{ + setSource(logoFromRepository({ blockchain, address }), 'repository'); }); } } @@ -76,6 +88,7 @@ api: Token__default['default'].solana.METADATA_LAYOUT, cache: 86400000, // 1 day }); + if(_optionalChain([metaData, 'optionalAccess', _ => _.data, 'optionalAccess', _2 => _2.uri])) { @@ -87,26 +100,22 @@ if(json && json.image) { resolve(json.image); } else { - resolve(''); + reject('image not found on metaplex'); } - }).catch(()=>resolve('')); + }).catch(()=>reject('image not found on metaplex')); } else { - resolve(''); + reject('image not found on metaplex'); } } else { - resolve(''); + reject('image not found on metaplex'); } - } catch (e) { resolve(''); } + } catch (e) { reject('image not found on metaplex'); } }) }; const logoFromRepository = ({ blockchain, address })=> { - if(['ethereum', 'bsc', 'polygon', 'fantom', 'solana'].includes(blockchain)) { - return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${mapBlockchainNameToTrustWalletAssets(blockchain)}/assets/${address}/logo.png` - } else if(blockchain == 'velas'){ - return `https://raw.githubusercontent.com/wagyuswapapp/assets/master/blockchains/velas/assets/${address.toLowerCase()}/logo.png` - } + return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${mapBlockchainNameToTrustWalletAssets(blockchain)}/assets/${address}/logo.png` }; const mapBlockchainNameToTrustWalletAssets = (blockchain)=>{ @@ -135,8 +144,7 @@ }; const setUnknown = ()=>{ - setSource('unknown'); - setSrc(UNKNOWN_IMAGE); + setSource(UNKNOWN_IMAGE, 'unknown'); }; const uriToImage = (tokenURI)=>{ @@ -154,8 +162,7 @@ if(image.match(/^ipfs/)) { image = `https://ipfs.io/ipfs/${image.split('://')[1]}`; } - setSource('meta'); - setSrc(image); + setSource(image, 'meta'); } else { setUnknown(); } @@ -164,12 +171,13 @@ }; const handleLoadError = (error)=> { + delete localStorage[getLocalStorageKey(blockchain, address)]; if(source == 'metaplex') { - setSource('repository'); - setSrc(logoFromRepository({ blockchain, address })); + setSource(logoFromRepository({ blockchain, address }), 'repository'); + } else if(source == 'web3-blockchains') { + setSource(logoFromRepository({ blockchain, address }), 'repository'); } else if(source == 'repository') { - setSource('depay'); - setSrc(`https://integrate.depay.com/tokens/${blockchain}/${address}/image`); + setSource(`https://integrate.depay.com/tokens/${blockchain}/${address}/image`, 'depay'); } else if (source == 'depay' && supported.evm.includes(blockchain)) { if(id) { web3Client.request({ blockchain, address, api: uriAPI, method: 'uri', params: [id] }).then((uri)=>{ @@ -184,13 +192,17 @@ } }; - if(src == undefined) { return null } + if(src == undefined) { + return( + React__default['default'].createElement('div', { className: props.className , __self: this, __source: {fileName: _jsxFileName, lineNumber: 198}} ) + ) + } return( React__default['default'].createElement('img', { className: props.className , src: src , - onError: handleLoadError , __self: this, __source: {fileName: _jsxFileName, lineNumber: 191}} + onError: handleLoadError , __self: this, __source: {fileName: _jsxFileName, lineNumber: 203}} ) ) }; diff --git a/dist/umd/index.solana.js b/dist/umd/index.solana.js index f45dae5..6e8f889 100644 --- a/dist/umd/index.solana.js +++ b/dist/umd/index.solana.js @@ -22,34 +22,46 @@ let TokenImage = function(props){ - const [src, _setSrc] = React.useState(); - const [source, setSource] = React.useState(); + const [src, setSrc] = React.useState(); + const [source, _setSource] = React.useState(); const blockchain = props.blockchain.toLowerCase(); const address = props.address; const id = props.id; const date = new Date(); - const localStorageKey = ['react-token-image', blockchain, address, [date.getFullYear(), date.getMonth(), date.getDate()].join('-')].join('-'); + const getLocalStorageKey = (blockchain, address)=>{ + return [ + 'react-token-image', + blockchain, + address, + [date.getFullYear(), date.getMonth(), date.getDate()].join('-') + ].join('-') + }; - const setSrc = (_src)=>{ - localStorage.setItem(localStorageKey, _src); - _setSrc(_src); + const setSource = (src, source)=>{ + setSrc(src); + _setSource(source); + if(source != 'unknown') { + localStorage.setItem(getLocalStorageKey(blockchain, address), src); + } }; React.useEffect(()=>{ - const storedImage = localStorage.getItem(localStorageKey); - if(storedImage && storedImage.length && storedImage != UNKNOWN_IMAGE) { return setSrc(storedImage) } + const storedImage = localStorage.getItem(getLocalStorageKey(blockchain, address)); + if(storedImage && storedImage.length && storedImage != UNKNOWN_IMAGE) { + return setSource(storedImage, 'stored') + } const foundMajorToken = Blockchains__default['default'][blockchain].tokens.find((token)=> token.address.toLowerCase() === address.toLowerCase()); if(foundMajorToken) { - setSrc(foundMajorToken.logo); + setSource(foundMajorToken.logo, 'web3-blockchains'); } else { if(supported.evm.includes(blockchain)) { - setSource('repository'); - setSrc(logoFromRepository({ blockchain, address })); + setSource(logoFromRepository({ blockchain, address }), 'repository'); } else if(blockchain === 'solana') { - setSource('metaplex'); logoFromMetaplex({ blockchain, address }).then((image)=>{ - setSrc(image); + setSource(image, 'metaplex'); + }).catch((error)=>{ + setSource(logoFromRepository({ blockchain, address }), 'repository'); }); } } @@ -76,6 +88,7 @@ api: Token__default['default'].solana.METADATA_LAYOUT, cache: 86400000, // 1 day }); + if(_optionalChain([metaData, 'optionalAccess', _ => _.data, 'optionalAccess', _2 => _2.uri])) { @@ -87,26 +100,22 @@ if(json && json.image) { resolve(json.image); } else { - resolve(''); + reject('image not found on metaplex'); } - }).catch(()=>resolve('')); + }).catch(()=>reject('image not found on metaplex')); } else { - resolve(''); + reject('image not found on metaplex'); } } else { - resolve(''); + reject('image not found on metaplex'); } - } catch (e) { resolve(''); } + } catch (e) { reject('image not found on metaplex'); } }) }; const logoFromRepository = ({ blockchain, address })=> { - if(['ethereum', 'bsc', 'polygon', 'fantom', 'solana'].includes(blockchain)) { - return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${mapBlockchainNameToTrustWalletAssets(blockchain)}/assets/${address}/logo.png` - } else if(blockchain == 'velas'){ - return `https://raw.githubusercontent.com/wagyuswapapp/assets/master/blockchains/velas/assets/${address.toLowerCase()}/logo.png` - } + return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${mapBlockchainNameToTrustWalletAssets(blockchain)}/assets/${address}/logo.png` }; const mapBlockchainNameToTrustWalletAssets = (blockchain)=>{ @@ -135,8 +144,7 @@ }; const setUnknown = ()=>{ - setSource('unknown'); - setSrc(UNKNOWN_IMAGE); + setSource(UNKNOWN_IMAGE, 'unknown'); }; const uriToImage = (tokenURI)=>{ @@ -154,8 +162,7 @@ if(image.match(/^ipfs/)) { image = `https://ipfs.io/ipfs/${image.split('://')[1]}`; } - setSource('meta'); - setSrc(image); + setSource(image, 'meta'); } else { setUnknown(); } @@ -164,12 +171,13 @@ }; const handleLoadError = (error)=> { + delete localStorage[getLocalStorageKey(blockchain, address)]; if(source == 'metaplex') { - setSource('repository'); - setSrc(logoFromRepository({ blockchain, address })); + setSource(logoFromRepository({ blockchain, address }), 'repository'); + } else if(source == 'web3-blockchains') { + setSource(logoFromRepository({ blockchain, address }), 'repository'); } else if(source == 'repository') { - setSource('depay'); - setSrc(`https://integrate.depay.com/tokens/${blockchain}/${address}/image`); + setSource(`https://integrate.depay.com/tokens/${blockchain}/${address}/image`, 'depay'); } else if (source == 'depay' && supported.evm.includes(blockchain)) { if(id) { web3ClientSolana.request({ blockchain, address, api: uriAPI, method: 'uri', params: [id] }).then((uri)=>{ @@ -184,13 +192,17 @@ } }; - if(src == undefined) { return null } + if(src == undefined) { + return( + React__default['default'].createElement('div', { className: props.className , __self: this, __source: {fileName: _jsxFileName, lineNumber: 198}} ) + ) + } return( React__default['default'].createElement('img', { className: props.className , src: src , - onError: handleLoadError , __self: this, __source: {fileName: _jsxFileName, lineNumber: 191}} + onError: handleLoadError , __self: this, __source: {fileName: _jsxFileName, lineNumber: 203}} ) ) }; diff --git a/package.evm.json b/package.evm.json index 7c637c2..253de17 100644 --- a/package.evm.json +++ b/package.evm.json @@ -1,7 +1,7 @@ { "name": "@depay/react-token-image-evm", "moduleName": "ReactTokenImage", - "version": "4.14.1", + "version": "4.14.2", "description": "React component to display token images with fallbacks and unknown state.", "main": "./dist/umd/index.evm.js", "module": "./dist/esm/index.evm.js", diff --git a/package.json b/package.json index 86235e1..07aa6ec 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@depay/react-token-image", "moduleName": "ReactTokenImage", - "version": "4.14.1", + "version": "4.14.2", "description": "React component to display token images with fallbacks and unknown state.", "main": "./dist/umd/index.js", "module": "./dist/esm/index.js", diff --git a/package.solana.json b/package.solana.json index 1642dd1..f2df22e 100644 --- a/package.solana.json +++ b/package.solana.json @@ -1,7 +1,7 @@ { "name": "@depay/react-token-image-solana", "moduleName": "ReactTokenImage", - "version": "4.14.1", + "version": "4.14.2", "description": "React component to display token images with fallbacks and unknown state.", "main": "./dist/umd/index.solana.js", "module": "./dist/esm/index.solana.js", diff --git a/src/blockchains.js b/src/blockchains.js index 5cd5cbf..54a101a 100644 --- a/src/blockchains.js +++ b/src/blockchains.js @@ -1,7 +1,7 @@ /*#if _EVM -let supported = ['ethereum', 'bsc', 'polygon', 'fantom', 'velas'] -supported.evm = ['ethereum', 'bsc', 'polygon', 'fantom', 'velas'] +let supported = ['ethereum', 'bsc', 'polygon', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism'] +supported.evm = ['ethereum', 'bsc', 'polygon', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism'] supported.solana = [] /*#elif _SOLANA @@ -12,8 +12,8 @@ supported.solana = ['solana'] //#else */ -let supported = ['ethereum', 'bsc', 'polygon', 'solana', 'fantom', 'velas'] -supported.evm = ['ethereum', 'bsc', 'polygon', 'fantom', 'velas'] +let supported = ['ethereum', 'bsc', 'polygon', 'solana', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism'] +supported.evm = ['ethereum', 'bsc', 'polygon', 'fantom', 'arbitrum', 'avalanche', 'gnosis', 'optimism'] supported.solana = ['solana'] //#endif diff --git a/src/index.js b/src/index.js index c65ba91..d6d94c7 100644 --- a/src/index.js +++ b/src/index.js @@ -27,34 +27,46 @@ const UNKNOWN_IMAGE = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmN let TokenImage = function(props){ - const [src, _setSrc] = useState() - const [source, setSource] = useState() + const [src, setSrc] = useState() + const [source, _setSource] = useState() const blockchain = props.blockchain.toLowerCase() const address = props.address const id = props.id const date = new Date() - const localStorageKey = ['react-token-image', blockchain, address, [date.getFullYear(), date.getMonth(), date.getDate()].join('-')].join('-') + const getLocalStorageKey = (blockchain, address)=>{ + return [ + 'react-token-image', + blockchain, + address, + [date.getFullYear(), date.getMonth(), date.getDate()].join('-') + ].join('-') + } - const setSrc = (_src)=>{ - localStorage.setItem(localStorageKey, _src) - _setSrc(_src) + const setSource = (src, source)=>{ + setSrc(src) + _setSource(source) + if(source != 'unknown') { + localStorage.setItem(getLocalStorageKey(blockchain, address), src) + } } useEffect(()=>{ - const storedImage = localStorage.getItem(localStorageKey) - if(storedImage && storedImage.length && storedImage != UNKNOWN_IMAGE) { return setSrc(storedImage) } + const storedImage = localStorage.getItem(getLocalStorageKey(blockchain, address)) + if(storedImage && storedImage.length && storedImage != UNKNOWN_IMAGE) { + return setSource(storedImage, 'stored') + } const foundMajorToken = Blockchains[blockchain].tokens.find((token)=> token.address.toLowerCase() === address.toLowerCase()) if(foundMajorToken) { - setSrc(foundMajorToken.logo) + setSource(foundMajorToken.logo, 'web3-blockchains') } else { if(supported.evm.includes(blockchain)) { - setSource('repository') - setSrc(logoFromRepository({ blockchain, address })) + setSource(logoFromRepository({ blockchain, address }), 'repository') } else if(blockchain === 'solana') { - setSource('metaplex') logoFromMetaplex({ blockchain, address }).then((image)=>{ - setSrc(image) + setSource(image, 'metaplex') + }).catch((error)=>{ + setSource(logoFromRepository({ blockchain, address }), 'repository') }) } } @@ -81,6 +93,7 @@ let TokenImage = function(props){ api: Token.solana.METADATA_LAYOUT, cache: 86400000, // 1 day }) + if(metaData?.data?.uri) { @@ -92,26 +105,22 @@ let TokenImage = function(props){ if(json && json.image) { resolve(json.image) } else { - resolve('') + reject('image not found on metaplex') } - }).catch(()=>resolve('')) + }).catch(()=>reject('image not found on metaplex')) } else { - resolve('') + reject('image not found on metaplex') } } else { - resolve('') + reject('image not found on metaplex') } - } catch { resolve('') } + } catch { reject('image not found on metaplex') } }) } const logoFromRepository = ({ blockchain, address })=> { - if(['ethereum', 'bsc', 'polygon', 'fantom', 'solana'].includes(blockchain)) { - return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${mapBlockchainNameToTrustWalletAssets(blockchain)}/assets/${address}/logo.png` - } else if(blockchain == 'velas'){ - return `https://raw.githubusercontent.com/wagyuswapapp/assets/master/blockchains/velas/assets/${address.toLowerCase()}/logo.png` - } + return `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${mapBlockchainNameToTrustWalletAssets(blockchain)}/assets/${address}/logo.png` } const mapBlockchainNameToTrustWalletAssets = (blockchain)=>{ @@ -149,8 +158,7 @@ let TokenImage = function(props){ } const setUnknown = ()=>{ - setSource('unknown') - setSrc(UNKNOWN_IMAGE) + setSource(UNKNOWN_IMAGE, 'unknown') } const uriToImage = (tokenURI)=>{ @@ -168,8 +176,7 @@ let TokenImage = function(props){ if(image.match(/^ipfs/)) { image = `https://ipfs.io/ipfs/${image.split('://')[1]}` } - setSource('meta') - setSrc(image) + setSource(image, 'meta') } else { setUnknown() } @@ -178,12 +185,13 @@ let TokenImage = function(props){ } const handleLoadError = (error)=> { + delete localStorage[getLocalStorageKey(blockchain, address)] if(source == 'metaplex') { - setSource('repository') - setSrc(logoFromRepository({ blockchain, address })) + setSource(logoFromRepository({ blockchain, address }), 'repository') + } else if(source == 'web3-blockchains') { + setSource(logoFromRepository({ blockchain, address }), 'repository') } else if(source == 'repository') { - setSource('depay') - setSrc(`https://integrate.depay.com/tokens/${blockchain}/${address}/image`) + setSource(`https://integrate.depay.com/tokens/${blockchain}/${address}/image`, 'depay') } else if (source == 'depay' && supported.evm.includes(blockchain)) { if(id) { request({ blockchain, address, api: uriAPI, method: 'uri', params: [id] }).then((uri)=>{ @@ -198,7 +206,11 @@ let TokenImage = function(props){ } } - if(src == undefined) { return null } + if(src == undefined) { + return( +
+ ) + } return(