Merge pull request #1603 from MetaMask/AddTokenList
Add popular token listfeature/default_network_editable
commit
f022c7c714
@ -1,4 +1,4 @@ |
||||
{ |
||||
"presets": ["es2015"], |
||||
"plugins": ["transform-runtime"] |
||||
"presets": ["es2015", "stage-0"], |
||||
"plugins": ["transform-runtime", "transform-async-to-generator"] |
||||
} |
||||
|
@ -0,0 +1,89 @@ |
||||
const Component = require('react').Component |
||||
const h = require('react-hyperscript') |
||||
const inherits = require('util').inherits |
||||
const formatBalance = require('../util').formatBalance |
||||
const generateBalanceObject = require('../util').generateBalanceObject |
||||
const Tooltip = require('./tooltip.js') |
||||
const FiatValue = require('./fiat-value.js') |
||||
|
||||
module.exports = EthBalanceComponent |
||||
|
||||
inherits(EthBalanceComponent, Component) |
||||
function EthBalanceComponent () { |
||||
Component.call(this) |
||||
} |
||||
|
||||
EthBalanceComponent.prototype.render = function () { |
||||
var props = this.props |
||||
let { value } = props |
||||
var style = props.style |
||||
var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true |
||||
value = value ? formatBalance(value, 6, needsParse) : '...' |
||||
var width = props.width |
||||
|
||||
return ( |
||||
|
||||
h('.ether-balance.ether-balance-amount', { |
||||
style: style, |
||||
}, [ |
||||
h('div', { |
||||
style: { |
||||
display: 'inline', |
||||
width: width, |
||||
}, |
||||
}, this.renderBalance(value)), |
||||
]) |
||||
|
||||
) |
||||
} |
||||
EthBalanceComponent.prototype.renderBalance = function (value) { |
||||
var props = this.props |
||||
if (value === 'None') return value |
||||
if (value === '...') return value |
||||
var balanceObj = generateBalanceObject(value, props.shorten ? 1 : 3) |
||||
var balance |
||||
var splitBalance = value.split(' ') |
||||
var ethNumber = splitBalance[0] |
||||
var ethSuffix = splitBalance[1] |
||||
const showFiat = 'showFiat' in props ? props.showFiat : true |
||||
|
||||
if (props.shorten) { |
||||
balance = balanceObj.shortBalance |
||||
} else { |
||||
balance = balanceObj.balance |
||||
} |
||||
|
||||
var label = balanceObj.label |
||||
|
||||
return ( |
||||
h(Tooltip, { |
||||
position: 'bottom', |
||||
title: `${ethNumber} ${ethSuffix}`, |
||||
}, h('div.flex-column', [ |
||||
h('.flex-row', { |
||||
style: { |
||||
alignItems: 'flex-end', |
||||
lineHeight: '13px', |
||||
fontFamily: 'Montserrat Light', |
||||
textRendering: 'geometricPrecision', |
||||
}, |
||||
}, [ |
||||
h('div', { |
||||
style: { |
||||
width: '100%', |
||||
textAlign: 'right', |
||||
}, |
||||
}, this.props.incoming ? `+${balance}` : balance), |
||||
h('div', { |
||||
style: { |
||||
color: ' #AEAEAE', |
||||
fontSize: '12px', |
||||
marginLeft: '5px', |
||||
}, |
||||
}, label), |
||||
]), |
||||
|
||||
showFiat ? h(FiatValue, { value: props.value }) : null, |
||||
])) |
||||
) |
||||
} |
@ -0,0 +1,46 @@ |
||||
const Component = require('react').Component |
||||
const h = require('react-hyperscript') |
||||
const inherits = require('util').inherits |
||||
const Identicon = require('./identicon') |
||||
|
||||
module.exports = TokenCell |
||||
|
||||
inherits(TokenCell, Component) |
||||
function TokenCell () { |
||||
Component.call(this) |
||||
} |
||||
|
||||
TokenCell.prototype.render = function () { |
||||
const props = this.props |
||||
const { address, symbol, string, network, userAddress } = props |
||||
|
||||
return ( |
||||
h('li.token-cell', { |
||||
style: { cursor: network === '1' ? 'pointer' : 'default' }, |
||||
onClick: (event) => { |
||||
const url = urlFor(address, userAddress, network) |
||||
if (url) { |
||||
navigateTo(url) |
||||
} |
||||
}, |
||||
}, [ |
||||
|
||||
h(Identicon, { |
||||
diameter: 50, |
||||
address, |
||||
network, |
||||
}), |
||||
|
||||
h('h3', `${string || 0} ${symbol}`), |
||||
]) |
||||
) |
||||
} |
||||
|
||||
function navigateTo (url) { |
||||
global.platform.openWindow({ url }) |
||||
} |
||||
|
||||
function urlFor (tokenAddress, address, network) { |
||||
return `https://etherscan.io/token/${tokenAddress}?a=${address}` |
||||
} |
||||
|
@ -0,0 +1,147 @@ |
||||
const Component = require('react').Component |
||||
const h = require('react-hyperscript') |
||||
const inherits = require('util').inherits |
||||
const TokenTracker = require('eth-token-tracker') |
||||
const TokenCell = require('./token-cell.js') |
||||
const contracts = require('eth-contract-metadata') |
||||
|
||||
const tokens = [] |
||||
for (const address in contracts) { |
||||
const contract = contracts[address] |
||||
if (contract.erc20) { |
||||
contract.address = address |
||||
tokens.push(contract) |
||||
} |
||||
} |
||||
|
||||
module.exports = TokenList |
||||
|
||||
inherits(TokenList, Component) |
||||
function TokenList () { |
||||
this.state = { tokens, isLoading: true, network: null } |
||||
Component.call(this) |
||||
} |
||||
|
||||
TokenList.prototype.render = function () { |
||||
const state = this.state |
||||
const { tokens, isLoading, error } = state |
||||
|
||||
const { userAddress } = this.props |
||||
|
||||
if (isLoading) { |
||||
return this.message('Loading') |
||||
} |
||||
|
||||
if (error) { |
||||
log.error(error) |
||||
return this.message('There was a problem loading your token balances.') |
||||
} |
||||
|
||||
const network = this.props.network |
||||
|
||||
const tokenViews = tokens.map((tokenData) => { |
||||
tokenData.network = network |
||||
tokenData.userAddress = userAddress |
||||
return h(TokenCell, tokenData) |
||||
}) |
||||
|
||||
return ( |
||||
h('ol', { |
||||
style: { |
||||
height: '302px', |
||||
overflowY: 'auto', |
||||
}, |
||||
}, [h('style', ` |
||||
|
||||
li.token-cell { |
||||
display: flex; |
||||
flex-direction: row; |
||||
align-items: center; |
||||
padding: 10px; |
||||
} |
||||
|
||||
li.token-cell > h3 { |
||||
margin-left: 12px; |
||||
} |
||||
|
||||
li.token-cell:hover { |
||||
background: white; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
`)].concat(tokenViews.length ? tokenViews : this.message('No Tokens Found.')))
|
||||
) |
||||
} |
||||
|
||||
TokenList.prototype.message = function (body) { |
||||
return h('div', { |
||||
style: { |
||||
display: 'flex', |
||||
height: '250px', |
||||
alignItems: 'center', |
||||
justifyContent: 'center', |
||||
}, |
||||
}, body) |
||||
} |
||||
|
||||
TokenList.prototype.componentDidMount = function () { |
||||
this.createFreshTokenTracker() |
||||
} |
||||
|
||||
TokenList.prototype.createFreshTokenTracker = function () { |
||||
if (this.tracker) { |
||||
// Clean up old trackers when refreshing:
|
||||
this.tracker.stop() |
||||
this.tracker.removeListener('update', this.balanceUpdater) |
||||
this.tracker.removeListener('error', this.showError) |
||||
} |
||||
|
||||
if (!global.ethereumProvider) return |
||||
const { userAddress } = this.props |
||||
this.tracker = new TokenTracker({ |
||||
userAddress, |
||||
provider: global.ethereumProvider, |
||||
tokens: tokens, |
||||
pollingInterval: 8000, |
||||
}) |
||||
|
||||
|
||||
// Set up listener instances for cleaning up
|
||||
this.balanceUpdater = this.updateBalances.bind(this) |
||||
this.showError = (error) => { |
||||
this.setState({ error, isLoading: false }) |
||||
} |
||||
this.tracker.on('update', this.balanceUpdater) |
||||
this.tracker.on('error', this.showError) |
||||
|
||||
this.tracker.updateBalances() |
||||
.then(() => { |
||||
this.updateBalances(this.tracker.serialize()) |
||||
}) |
||||
.catch((reason) => { |
||||
log.error(`Problem updating balances`, reason) |
||||
this.setState({ isLoading: false }) |
||||
}) |
||||
} |
||||
|
||||
TokenList.prototype.componentWillUpdate = function (nextProps) { |
||||
if (nextProps.network === 'loading') return |
||||
const oldNet = this.props.network |
||||
const newNet = nextProps.network |
||||
|
||||
if (oldNet && newNet && newNet !== oldNet) { |
||||
this.setState({ isLoading: true }) |
||||
this.createFreshTokenTracker() |
||||
} |
||||
} |
||||
|
||||
TokenList.prototype.updateBalances = function (tokenData) { |
||||
const heldTokens = tokenData.filter(token => token.balance !== '0' && token.string !== '0.000') |
||||
this.setState({ tokens: heldTokens, isLoading: false }) |
||||
} |
||||
|
||||
TokenList.prototype.componentWillUnmount = function () { |
||||
if (!this.tracker) return |
||||
this.tracker.stop() |
||||
} |
||||
|
Loading…
Reference in new issue