affected components to new files
This commit is contained in:
parent
2393f3691b
commit
984c4594e3
|
@ -21,9 +21,8 @@ const NoticeScreen = require('./components/notice')
|
||||||
const generateLostAccountsNotice = require('../lib/lost-accounts-notice')
|
const generateLostAccountsNotice = require('../lib/lost-accounts-notice')
|
||||||
// other views
|
// other views
|
||||||
const ConfigScreen = require('./config')
|
const ConfigScreen = require('./config')
|
||||||
// const AddTokenScreen = require('../../ui/app/components/pages/add-token')
|
const AddTokenScreen = require('./components/add-token.js')
|
||||||
const AddTokenScreen = require('./add-token')
|
const ConfirmAddTokenScreen = require('./components/confirm-add-token')
|
||||||
const ConfirmAddTokenScreen = require('../../ui/app/components/pages/confirm-add-token')
|
|
||||||
const RemoveTokenScreen = require('./remove-token')
|
const RemoveTokenScreen = require('./remove-token')
|
||||||
const Import = require('./accounts/import')
|
const Import = require('./accounts/import')
|
||||||
const InfoScreen = require('./info')
|
const InfoScreen = require('./info')
|
||||||
|
|
|
@ -2,15 +2,15 @@ const React = require('react')
|
||||||
const { Component } = React
|
const { Component } = React
|
||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const connect = require('react-redux').connect
|
const connect = require('react-redux').connect
|
||||||
const actions = require('../../ui/app/actions')
|
const actions = require('../../../ui/app/actions')
|
||||||
const { setPendingTokens, clearPendingTokens, displayWarning, goHome, addToken } = actions
|
const { setPendingTokens, clearPendingTokens, displayWarning, goHome, addToken } = actions
|
||||||
const Tooltip = require('./components/tooltip.js')
|
const Tooltip = require('./tooltip.js')
|
||||||
const TabBar = require('./components/tab-bar')
|
const TabBar = require('./tab-bar')
|
||||||
// const { CONFIRM_ADD_TOKEN_ROUTE } = require('../../ui/app/routes')
|
// const { CONFIRM_ADD_TOKEN_ROUTE } = require('../../ui/app/routes')
|
||||||
const { checkExistingAddresses } = require('../../ui/app/components/pages/add-token/util')
|
const { checkExistingAddresses } = require('../../../ui/app/components/pages/add-token/util')
|
||||||
const TokenList = require('../../ui/app/components/pages/add-token/token-list')
|
const TokenList = require('../../../ui/app/components/pages/add-token/token-list')
|
||||||
const TokenSearch = require('../../ui/app/components/pages/add-token/token-search')
|
const TokenSearch = require('../../../ui/app/components/pages/add-token/token-search')
|
||||||
const { tokenInfoGetter } = require('../../ui/app/token-util')
|
const { tokenInfoGetter } = require('../../../ui/app/token-util')
|
||||||
const ethUtil = require('ethereumjs-util')
|
const ethUtil = require('ethereumjs-util')
|
||||||
const abi = require('human-standard-token-abi')
|
const abi = require('human-standard-token-abi')
|
||||||
const Eth = require('ethjs-query')
|
const Eth = require('ethjs-query')
|
||||||
|
@ -311,7 +311,7 @@ class AddTokenScreen extends Component {
|
||||||
goHome()
|
goHome()
|
||||||
},
|
},
|
||||||
}, 'Cancel' /* this.context.t('cancel')*/),
|
}, 'Cancel' /* this.context.t('cancel')*/),
|
||||||
h('button', {
|
h('button.btn-primary', {
|
||||||
onClick: () => this.handleNext(),
|
onClick: () => this.handleNext(),
|
||||||
disabled: this.hasError() || !this.hasSelected(),
|
disabled: this.hasError() || !this.hasSelected(),
|
||||||
}, 'Next' /* this.context.t('next')*/),
|
}, 'Next' /* this.context.t('next')*/),
|
|
@ -0,0 +1,351 @@
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import ethUtil from 'ethereumjs-util'
|
||||||
|
import { checkExistingAddresses } from './util'
|
||||||
|
import { tokenInfoGetter } from '../../../token-util'
|
||||||
|
import { DEFAULT_ROUTE, CONFIRM_ADD_TOKEN_ROUTE } from '../../../routes'
|
||||||
|
import Button from '../../button'
|
||||||
|
import TextField from '../../text-field'
|
||||||
|
import TokenList from './token-list'
|
||||||
|
import TokenSearch from './token-search'
|
||||||
|
|
||||||
|
const emptyAddr = '0x0000000000000000000000000000000000000000'
|
||||||
|
const SEARCH_TAB = 'SEARCH'
|
||||||
|
const CUSTOM_TOKEN_TAB = 'CUSTOM_TOKEN'
|
||||||
|
|
||||||
|
class AddToken extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
t: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
history: PropTypes.object,
|
||||||
|
setPendingTokens: PropTypes.func,
|
||||||
|
pendingTokens: PropTypes.object,
|
||||||
|
clearPendingTokens: PropTypes.func,
|
||||||
|
tokens: PropTypes.array,
|
||||||
|
identities: PropTypes.object,
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
customAddress: '',
|
||||||
|
customSymbol: '',
|
||||||
|
customDecimals: 0,
|
||||||
|
searchResults: [],
|
||||||
|
selectedTokens: {},
|
||||||
|
tokenSelectorError: null,
|
||||||
|
customAddressError: null,
|
||||||
|
customSymbolError: null,
|
||||||
|
customDecimalsError: null,
|
||||||
|
autoFilled: false,
|
||||||
|
displayedTab: SEARCH_TAB,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
this.tokenInfoGetter = tokenInfoGetter()
|
||||||
|
const { pendingTokens = {} } = this.props
|
||||||
|
const pendingTokenKeys = Object.keys(pendingTokens)
|
||||||
|
|
||||||
|
if (pendingTokenKeys.length > 0) {
|
||||||
|
let selectedTokens = {}
|
||||||
|
let customToken = {}
|
||||||
|
|
||||||
|
pendingTokenKeys.forEach(tokenAddress => {
|
||||||
|
const token = pendingTokens[tokenAddress]
|
||||||
|
const { isCustom } = token
|
||||||
|
|
||||||
|
if (isCustom) {
|
||||||
|
customToken = { ...token }
|
||||||
|
} else {
|
||||||
|
selectedTokens = { ...selectedTokens, [tokenAddress]: { ...token } }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const {
|
||||||
|
address: customAddress = '',
|
||||||
|
symbol: customSymbol = '',
|
||||||
|
decimals: customDecimals = 0,
|
||||||
|
} = customToken
|
||||||
|
|
||||||
|
const displayedTab = Object.keys(selectedTokens).length > 0 ? SEARCH_TAB : CUSTOM_TOKEN_TAB
|
||||||
|
this.setState({ selectedTokens, customAddress, customSymbol, customDecimals, displayedTab })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleToggleToken (token) {
|
||||||
|
const { address } = token
|
||||||
|
const { selectedTokens = {} } = this.state
|
||||||
|
const selectedTokensCopy = { ...selectedTokens }
|
||||||
|
|
||||||
|
if (address in selectedTokensCopy) {
|
||||||
|
delete selectedTokensCopy[address]
|
||||||
|
} else {
|
||||||
|
selectedTokensCopy[address] = token
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
selectedTokens: selectedTokensCopy,
|
||||||
|
tokenSelectorError: null,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
hasError () {
|
||||||
|
const {
|
||||||
|
tokenSelectorError,
|
||||||
|
customAddressError,
|
||||||
|
customSymbolError,
|
||||||
|
customDecimalsError,
|
||||||
|
} = this.state
|
||||||
|
|
||||||
|
return tokenSelectorError || customAddressError || customSymbolError || customDecimalsError
|
||||||
|
}
|
||||||
|
|
||||||
|
hasSelected () {
|
||||||
|
const { customAddress = '', selectedTokens = {} } = this.state
|
||||||
|
return customAddress || Object.keys(selectedTokens).length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
handleNext () {
|
||||||
|
if (this.hasError()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.hasSelected()) {
|
||||||
|
this.setState({ tokenSelectorError: this.context.t('mustSelectOne') })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const { setPendingTokens, history } = this.props
|
||||||
|
const {
|
||||||
|
customAddress: address,
|
||||||
|
customSymbol: symbol,
|
||||||
|
customDecimals: decimals,
|
||||||
|
selectedTokens,
|
||||||
|
} = this.state
|
||||||
|
|
||||||
|
const customToken = {
|
||||||
|
address,
|
||||||
|
symbol,
|
||||||
|
decimals,
|
||||||
|
}
|
||||||
|
|
||||||
|
setPendingTokens({ customToken, selectedTokens })
|
||||||
|
history.push(CONFIRM_ADD_TOKEN_ROUTE)
|
||||||
|
}
|
||||||
|
|
||||||
|
async attemptToAutoFillTokenParams (address) {
|
||||||
|
const { symbol = '', decimals = 0 } = await this.tokenInfoGetter(address)
|
||||||
|
|
||||||
|
const autoFilled = Boolean(symbol && decimals)
|
||||||
|
this.setState({ autoFilled })
|
||||||
|
this.handleCustomSymbolChange(symbol || '')
|
||||||
|
this.handleCustomDecimalsChange(decimals)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCustomAddressChange (value) {
|
||||||
|
const customAddress = value.trim()
|
||||||
|
this.setState({
|
||||||
|
customAddress,
|
||||||
|
customAddressError: null,
|
||||||
|
tokenSelectorError: null,
|
||||||
|
autoFilled: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
const isValidAddress = ethUtil.isValidAddress(customAddress)
|
||||||
|
const standardAddress = ethUtil.addHexPrefix(customAddress).toLowerCase()
|
||||||
|
|
||||||
|
switch (true) {
|
||||||
|
case !isValidAddress:
|
||||||
|
this.setState({
|
||||||
|
customAddressError: this.context.t('invalidAddress'),
|
||||||
|
customSymbol: '',
|
||||||
|
customDecimals: 0,
|
||||||
|
customSymbolError: null,
|
||||||
|
customDecimalsError: null,
|
||||||
|
})
|
||||||
|
|
||||||
|
break
|
||||||
|
case Boolean(this.props.identities[standardAddress]):
|
||||||
|
this.setState({
|
||||||
|
customAddressError: this.context.t('personalAddressDetected'),
|
||||||
|
})
|
||||||
|
|
||||||
|
break
|
||||||
|
case checkExistingAddresses(customAddress, this.props.tokens):
|
||||||
|
this.setState({
|
||||||
|
customAddressError: this.context.t('tokenAlreadyAdded'),
|
||||||
|
})
|
||||||
|
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
if (customAddress !== emptyAddr) {
|
||||||
|
this.attemptToAutoFillTokenParams(customAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCustomSymbolChange (value) {
|
||||||
|
const customSymbol = value.trim()
|
||||||
|
const symbolLength = customSymbol.length
|
||||||
|
let customSymbolError = null
|
||||||
|
|
||||||
|
if (symbolLength <= 0 || symbolLength >= 10) {
|
||||||
|
customSymbolError = this.context.t('symbolBetweenZeroTen')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ customSymbol, customSymbolError })
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCustomDecimalsChange (value) {
|
||||||
|
const customDecimals = value.trim()
|
||||||
|
const validDecimals = customDecimals !== null &&
|
||||||
|
customDecimals !== '' &&
|
||||||
|
customDecimals >= 0 &&
|
||||||
|
customDecimals < 36
|
||||||
|
let customDecimalsError = null
|
||||||
|
|
||||||
|
if (!validDecimals) {
|
||||||
|
customDecimalsError = this.context.t('decimalsMustZerotoTen')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ customDecimals, customDecimalsError })
|
||||||
|
}
|
||||||
|
|
||||||
|
renderCustomTokenForm () {
|
||||||
|
const {
|
||||||
|
customAddress,
|
||||||
|
customSymbol,
|
||||||
|
customDecimals,
|
||||||
|
customAddressError,
|
||||||
|
customSymbolError,
|
||||||
|
customDecimalsError,
|
||||||
|
autoFilled,
|
||||||
|
} = this.state
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="add-token__custom-token-form">
|
||||||
|
<TextField
|
||||||
|
id="custom-address"
|
||||||
|
label={this.context.t('tokenAddress')}
|
||||||
|
type="text"
|
||||||
|
value={customAddress}
|
||||||
|
onChange={e => this.handleCustomAddressChange(e.target.value)}
|
||||||
|
error={customAddressError}
|
||||||
|
fullWidth
|
||||||
|
margin="normal"
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
id="custom-symbol"
|
||||||
|
label={this.context.t('tokenSymbol')}
|
||||||
|
type="text"
|
||||||
|
value={customSymbol}
|
||||||
|
onChange={e => this.handleCustomSymbolChange(e.target.value)}
|
||||||
|
error={customSymbolError}
|
||||||
|
fullWidth
|
||||||
|
margin="normal"
|
||||||
|
disabled={autoFilled}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
id="custom-decimals"
|
||||||
|
label={this.context.t('decimal')}
|
||||||
|
type="number"
|
||||||
|
value={customDecimals}
|
||||||
|
onChange={e => this.handleCustomDecimalsChange(e.target.value)}
|
||||||
|
error={customDecimalsError}
|
||||||
|
fullWidth
|
||||||
|
margin="normal"
|
||||||
|
disabled={autoFilled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSearchToken () {
|
||||||
|
const { tokenSelectorError, selectedTokens, searchResults } = this.state
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="add-token__search-token">
|
||||||
|
<TokenSearch
|
||||||
|
onSearch={({ results = [] }) => this.setState({ searchResults: results })}
|
||||||
|
error={tokenSelectorError}
|
||||||
|
/>
|
||||||
|
<div className="add-token__token-list">
|
||||||
|
<TokenList
|
||||||
|
results={searchResults}
|
||||||
|
selectedTokens={selectedTokens}
|
||||||
|
onToggleToken={token => this.handleToggleToken(token)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { displayedTab } = this.state
|
||||||
|
const { history, clearPendingTokens } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="page-container">
|
||||||
|
<div className="page-container__header page-container__header--no-padding-bottom">
|
||||||
|
<div className="page-container__title">
|
||||||
|
{ this.context.t('addTokens') }
|
||||||
|
</div>
|
||||||
|
<div className="page-container__tabs">
|
||||||
|
<div
|
||||||
|
className={classnames('page-container__tab', {
|
||||||
|
'page-container__tab--selected': displayedTab === SEARCH_TAB,
|
||||||
|
})}
|
||||||
|
onClick={() => this.setState({ displayedTab: SEARCH_TAB })}
|
||||||
|
>
|
||||||
|
{ this.context.t('search') }
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classnames('page-container__tab', {
|
||||||
|
'page-container__tab--selected': displayedTab === CUSTOM_TOKEN_TAB,
|
||||||
|
})}
|
||||||
|
onClick={() => this.setState({ displayedTab: CUSTOM_TOKEN_TAB })}
|
||||||
|
>
|
||||||
|
{ this.context.t('customToken') }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="page-container__content">
|
||||||
|
{
|
||||||
|
displayedTab === CUSTOM_TOKEN_TAB
|
||||||
|
? this.renderCustomTokenForm()
|
||||||
|
: this.renderSearchToken()
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div className="page-container__footer">
|
||||||
|
<Button
|
||||||
|
type="default"
|
||||||
|
large
|
||||||
|
className="page-container__footer-button"
|
||||||
|
onClick={() => {
|
||||||
|
clearPendingTokens()
|
||||||
|
history.push(DEFAULT_ROUTE)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ this.context.t('cancel') }
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
large
|
||||||
|
className="page-container__footer-button"
|
||||||
|
onClick={() => this.handleNext()}
|
||||||
|
disabled={this.hasError() || !this.hasSelected()}
|
||||||
|
>
|
||||||
|
{ this.context.t('next') }
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AddToken
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import AddToken from './add-token.component'
|
||||||
|
|
||||||
|
const { setPendingTokens, clearPendingTokens, showConfirmAddTokenPage } = require('../../../actions')
|
||||||
|
|
||||||
|
const mapStateToProps = ({ metamask }) => {
|
||||||
|
const { identities, tokens, pendingTokens } = metamask
|
||||||
|
return {
|
||||||
|
identities,
|
||||||
|
tokens,
|
||||||
|
pendingTokens,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
setPendingTokens: tokens => dispatch(setPendingTokens(tokens)),
|
||||||
|
clearPendingTokens: () => dispatch(clearPendingTokens()),
|
||||||
|
showConfirmAddTokenPage: () => dispatch(showConfirmAddTokenPage()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(AddToken)
|
|
@ -0,0 +1,2 @@
|
||||||
|
import AddToken from './add-token.container'
|
||||||
|
module.exports = AddToken
|
|
@ -0,0 +1,25 @@
|
||||||
|
@import './token-list/index';
|
||||||
|
|
||||||
|
.add-token {
|
||||||
|
&__custom-token-form {
|
||||||
|
padding: 8px 16px 16px;
|
||||||
|
|
||||||
|
input[type="number"]::-webkit-inner-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="number"]:hover::-webkit-inner-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__search-token {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__token-list {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
import TokenList from './token-list.container'
|
||||||
|
module.exports = TokenList
|
|
@ -0,0 +1,65 @@
|
||||||
|
@import './token-list-placeholder/index';
|
||||||
|
|
||||||
|
.token-list {
|
||||||
|
&__title {
|
||||||
|
font-size: .75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__tokens-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__token {
|
||||||
|
transition: 200ms ease-in-out;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px;
|
||||||
|
margin-top: 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border: 2px solid rgba($malibu-blue, .5);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--selected {
|
||||||
|
border: 2px solid $malibu-blue !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--disabled {
|
||||||
|
opacity: .4;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__token-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: contain;
|
||||||
|
background-position: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: $white;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba($black, .24);
|
||||||
|
margin-right: 12px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__token-data {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__token-name {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
import TokenListPlaceholder from './token-list-placeholder.component'
|
||||||
|
module.exports = TokenListPlaceholder
|
|
@ -0,0 +1,23 @@
|
||||||
|
.token-list-placeholder {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 36px;
|
||||||
|
flex-direction: column;
|
||||||
|
line-height: 22px;
|
||||||
|
opacity: .5;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
color: $silver-chalice;
|
||||||
|
width: 50%;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 8px;
|
||||||
|
|
||||||
|
@media screen and (max-width: 575px) {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
color: $curious-blue;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
|
export default class TokenListPlaceholder extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
t: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div className="token-list-placeholder">
|
||||||
|
<img src="images/tokensearch.svg" />
|
||||||
|
<div className="token-list-placeholder__text">
|
||||||
|
{`Add the tokens you've acquired using Nifty Wallet` /* this.context.t('addAcquiredTokens')*/}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import { checkExistingAddresses } from '../util'
|
||||||
|
import TokenListPlaceholder from './token-list-placeholder'
|
||||||
|
import h from 'react-hyperscript'
|
||||||
|
import Tooltip from '../../tooltip.js'
|
||||||
|
|
||||||
|
export default class InfoBox extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
t: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
tokens: PropTypes.array,
|
||||||
|
results: PropTypes.array,
|
||||||
|
selectedTokens: PropTypes.object,
|
||||||
|
onToggleToken: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { results = [], selectedTokens = {}, onToggleToken, tokens = [] } = this.props
|
||||||
|
|
||||||
|
return results.length === 0
|
||||||
|
? <TokenListPlaceholder />
|
||||||
|
: (
|
||||||
|
<div className="token-list">
|
||||||
|
<div className="token-list__title">
|
||||||
|
{ 'searchResults' /* this.context.t('searchResults')*/ }
|
||||||
|
</div>
|
||||||
|
<div className="token-list__tokens-container">
|
||||||
|
{
|
||||||
|
Array(6).fill(undefined)
|
||||||
|
.map((_, i) => {
|
||||||
|
const { logo, symbol, name, address } = results[i] || {}
|
||||||
|
const tokenAlreadyAdded = checkExistingAddresses(address, tokens)
|
||||||
|
const title = `${name} (${symbol})`
|
||||||
|
const isLongTitle = title.length > 28
|
||||||
|
|
||||||
|
const tokenRow = (key) => h(`.${classnames('token-list__token', {
|
||||||
|
'token-list__token--selected': selectedTokens[address],
|
||||||
|
'token-list__token--disabled': tokenAlreadyAdded,
|
||||||
|
}).split(' ').join('.')}`, {
|
||||||
|
onClick: () => !tokenAlreadyAdded && onToggleToken(results[i]),
|
||||||
|
key: key || 'tokenRow',
|
||||||
|
}, [
|
||||||
|
h('.token-list__token-icon', {
|
||||||
|
style: {
|
||||||
|
backgroundImage: logo && `url(images/contract/${logo})`,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
h('.token-list__token-data', [
|
||||||
|
h('span.token-list__token-name', title),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
|
||||||
|
return Boolean(logo || symbol || name) && (
|
||||||
|
isLongTitle ? h(Tooltip, {
|
||||||
|
position: 'top',
|
||||||
|
title: title,
|
||||||
|
key: i,
|
||||||
|
}, [
|
||||||
|
tokenRow(),
|
||||||
|
]) : tokenRow(i)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import TokenList from './token-list.component'
|
||||||
|
|
||||||
|
const mapStateToProps = ({ metamask }) => {
|
||||||
|
const { tokens } = metamask
|
||||||
|
return {
|
||||||
|
tokens,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(TokenList)
|
|
@ -0,0 +1,2 @@
|
||||||
|
import TokenSearch from './token-search.component'
|
||||||
|
module.exports = TokenSearch
|
|
@ -0,0 +1,85 @@
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import contractMap from 'eth-contract-metadata'
|
||||||
|
import Fuse from 'fuse.js'
|
||||||
|
import InputAdornment from '@material-ui/core/InputAdornment'
|
||||||
|
import TextField from '../../../text-field'
|
||||||
|
|
||||||
|
const contractList = Object.entries(contractMap)
|
||||||
|
.map(([ _, tokenData]) => tokenData)
|
||||||
|
.filter(tokenData => Boolean(tokenData.erc20))
|
||||||
|
|
||||||
|
const fuse = new Fuse(contractList, {
|
||||||
|
shouldSort: true,
|
||||||
|
threshold: 0.45,
|
||||||
|
location: 0,
|
||||||
|
distance: 100,
|
||||||
|
maxPatternLength: 32,
|
||||||
|
minMatchCharLength: 1,
|
||||||
|
keys: [
|
||||||
|
{ name: 'name', weight: 0.5 },
|
||||||
|
{ name: 'symbol', weight: 0.5 },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
export default class TokenSearch extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
t: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
error: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
onSearch: PropTypes.func,
|
||||||
|
error: PropTypes.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
searchQuery: '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSearch (searchQuery) {
|
||||||
|
this.setState({ searchQuery })
|
||||||
|
const fuseSearchResult = fuse.search(searchQuery)
|
||||||
|
const addressSearchResult = contractList.filter(token => {
|
||||||
|
return token.address.toLowerCase() === searchQuery.toLowerCase()
|
||||||
|
})
|
||||||
|
const results = [...addressSearchResult, ...fuseSearchResult]
|
||||||
|
this.props.onSearch({ searchQuery, results })
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAdornment () {
|
||||||
|
return (
|
||||||
|
<InputAdornment
|
||||||
|
position="start"
|
||||||
|
style={{ marginRight: '12px' }}
|
||||||
|
>
|
||||||
|
<img src="images/search.svg" />
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { error } = this.props
|
||||||
|
const { searchQuery } = this.state
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
id="search-tokens"
|
||||||
|
placeholder={'Search Tokens' /* this.context.t('searchTokens')*/}
|
||||||
|
type="text"
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={e => this.handleSearch(e.target.value)}
|
||||||
|
error={error}
|
||||||
|
fullWidth
|
||||||
|
startAdornment={this.renderAdornment()}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
import R from 'ramda'
|
||||||
|
|
||||||
|
export function checkExistingAddresses (address, tokenList = []) {
|
||||||
|
if (!address) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const matchesAddress = existingToken => {
|
||||||
|
return existingToken.address.toLowerCase() === address.toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
return R.any(matchesAddress)(tokenList)
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
// import { DEFAULT_ROUTE, ADD_TOKEN_ROUTE } from '../../../routes'
|
||||||
|
import Button from '../../../../ui/app/components/button'
|
||||||
|
import Identicon from '../identicon'
|
||||||
|
import TokenBalance from './token-balance'
|
||||||
|
|
||||||
|
export default class ConfirmAddToken extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
t: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
// history: PropTypes.object,
|
||||||
|
clearPendingTokens: PropTypes.func,
|
||||||
|
addTokens: PropTypes.func,
|
||||||
|
pendingTokens: PropTypes.object,
|
||||||
|
goHome: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
const { pendingTokens = {}, goHome /*, history*/ } = this.props
|
||||||
|
|
||||||
|
if (Object.keys(pendingTokens).length === 0) {
|
||||||
|
goHome()
|
||||||
|
// history.push(DEFAULT_ROUTE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getTokenName (name, symbol) {
|
||||||
|
return typeof name === 'undefined'
|
||||||
|
? symbol
|
||||||
|
: `${name} (${symbol})`
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { /* history,*/ addTokens, clearPendingTokens, pendingTokens, goHome } = this.props
|
||||||
|
const areMultipleTokens = pendingTokens && Object.keys(pendingTokens).length > 1
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="page-container">
|
||||||
|
<div className="page-container__header">
|
||||||
|
<h2 className="page-subtitle">
|
||||||
|
{ 'Add Tokens' /* this.context.t('addTokens')*/ }
|
||||||
|
</h2>
|
||||||
|
<p className="confirm-label">
|
||||||
|
{ areMultipleTokens ? 'Would you like to add these tokens?' : 'Would you like to add this token?' /* this.context.t('likeToAddTokens')*/ }
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="page-container__content">
|
||||||
|
<div className="confirm-add-token">
|
||||||
|
<div className="confirm-add-token__header">
|
||||||
|
<div className="confirm-add-token__token">
|
||||||
|
{ 'Token' /* this.context.t('token')*/ }
|
||||||
|
</div>
|
||||||
|
<div className="confirm-add-token__balance">
|
||||||
|
{ 'Balance' /* this.context.t('balance')*/ }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="confirm-add-token__token-list">
|
||||||
|
{
|
||||||
|
pendingTokens && Object.entries(pendingTokens)
|
||||||
|
.map(([ address, token ]) => {
|
||||||
|
const { name, symbol } = token
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="confirm-add-token__token-list-item"
|
||||||
|
key={address}
|
||||||
|
>
|
||||||
|
<div className="confirm-add-token__token confirm-add-token__data">
|
||||||
|
<Identicon
|
||||||
|
className="confirm-add-token__token-icon"
|
||||||
|
diameter={48}
|
||||||
|
address={address}
|
||||||
|
/>
|
||||||
|
<div className="confirm-add-token__name">
|
||||||
|
{ this.getTokenName(name, symbol) }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="confirm-add-token__balance">
|
||||||
|
<TokenBalance token={token} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="page-container__footer">
|
||||||
|
<div className="page-container__footer-container">
|
||||||
|
<Button
|
||||||
|
type="default"
|
||||||
|
className="btn-violet"
|
||||||
|
onClick={() => goHome()}// history.push(ADD_TOKEN_ROUTE)}
|
||||||
|
>
|
||||||
|
{ 'Cancel' /* this.context.t('back')*/ }
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={() => {
|
||||||
|
addTokens(pendingTokens)
|
||||||
|
.then(() => {
|
||||||
|
clearPendingTokens()
|
||||||
|
goHome()
|
||||||
|
// history.push(DEFAULT_ROUTE)
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ 'Add Tokens' /* this.context.t('addTokens')*/ }
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import ConfirmAddToken from './confirm-add-token.component'
|
||||||
|
|
||||||
|
const { addTokens, clearPendingTokens, goHome } = require('../../../../ui/app/actions')
|
||||||
|
|
||||||
|
const mapStateToProps = ({ metamask }) => {
|
||||||
|
const { pendingTokens } = metamask
|
||||||
|
return {
|
||||||
|
pendingTokens,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
addTokens: tokens => dispatch(addTokens(tokens)),
|
||||||
|
clearPendingTokens: () => dispatch(clearPendingTokens()),
|
||||||
|
goHome: () => dispatch(goHome()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(ConfirmAddToken)
|
|
@ -0,0 +1,2 @@
|
||||||
|
import ConfirmAddToken from './confirm-add-token.container'
|
||||||
|
module.exports = ConfirmAddToken
|
|
@ -0,0 +1,69 @@
|
||||||
|
.confirm-add-token {
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
font-size: .75rem;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__token {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__balance {
|
||||||
|
flex: 0 0 30%;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__token-list {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
|
||||||
|
.token-balance {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
&__amount {
|
||||||
|
color: $scorpion;
|
||||||
|
font-size: 43px;
|
||||||
|
line-height: 43px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__symbol {
|
||||||
|
color: $scorpion;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__token-list-item {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__data {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
min-width: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__token-icon {
|
||||||
|
margin-right: 12px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
import TokenBalance from './token-balance.container'
|
||||||
|
module.exports = TokenBalance
|
|
@ -0,0 +1,16 @@
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
|
export default class TokenBalance extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
string: PropTypes.string,
|
||||||
|
symbol: PropTypes.string,
|
||||||
|
error: PropTypes.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div className="hide-text-overflow">{ this.props.string }</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { compose } from 'recompose'
|
||||||
|
import withTokenTracker from '../../../../../ui/app/helpers/with-token-tracker'
|
||||||
|
import TokenBalance from './token-balance.component'
|
||||||
|
import selectors from '../../../../../ui/app/selectors'
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
return {
|
||||||
|
userAddress: selectors.getSelectedAddress(state),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
connect(mapStateToProps),
|
||||||
|
withTokenTracker
|
||||||
|
)(TokenBalance)
|
|
@ -8453,7 +8453,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"eth-contract-metadata": {
|
"eth-contract-metadata": {
|
||||||
"version": "github:MetaMask/eth-contract-metadata#966a891dd9c79b873fd8968a0155b067ca630502",
|
"version": "github:MetaMask/eth-contract-metadata#bd23fa120512dcbb6fad31559297f96f17c3a8e0",
|
||||||
"from": "github:MetaMask/eth-contract-metadata#master"
|
"from": "github:MetaMask/eth-contract-metadata#master"
|
||||||
},
|
},
|
||||||
"eth-ens-namehash": {
|
"eth-ens-namehash": {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import AddToken from './add-token.component'
|
import AddToken from './add-token.component'
|
||||||
|
|
||||||
const { setPendingTokens, clearPendingTokens, showConfirmAddTokenPage } = require('../../../actions')
|
const { setPendingTokens, clearPendingTokens } = require('../../../actions')
|
||||||
|
|
||||||
const mapStateToProps = ({ metamask }) => {
|
const mapStateToProps = ({ metamask }) => {
|
||||||
const { identities, tokens, pendingTokens } = metamask
|
const { identities, tokens, pendingTokens } = metamask
|
||||||
|
@ -16,7 +16,6 @@ const mapDispatchToProps = dispatch => {
|
||||||
return {
|
return {
|
||||||
setPendingTokens: tokens => dispatch(setPendingTokens(tokens)),
|
setPendingTokens: tokens => dispatch(setPendingTokens(tokens)),
|
||||||
clearPendingTokens: () => dispatch(clearPendingTokens()),
|
clearPendingTokens: () => dispatch(clearPendingTokens()),
|
||||||
showConfirmAddTokenPage: () => dispatch(showConfirmAddTokenPage()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,16 @@ export default class TokenListPlaceholder extends Component {
|
||||||
<div className="token-list-placeholder">
|
<div className="token-list-placeholder">
|
||||||
<img src="images/tokensearch.svg" />
|
<img src="images/tokensearch.svg" />
|
||||||
<div className="token-list-placeholder__text">
|
<div className="token-list-placeholder__text">
|
||||||
{`Add the tokens you've acquired using Nifty Wallet` /* this.context.t('addAcquiredTokens')*/}
|
{ this.context.t('addAcquiredTokens') }
|
||||||
</div>
|
</div>
|
||||||
|
<a
|
||||||
|
className="token-list-placeholder__link"
|
||||||
|
href="https://consensys.zendesk.com/hc/en-us/articles/360004135092"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
{ this.context.t('learnMore') }
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,6 @@ import PropTypes from 'prop-types'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { checkExistingAddresses } from '../util'
|
import { checkExistingAddresses } from '../util'
|
||||||
import TokenListPlaceholder from './token-list-placeholder'
|
import TokenListPlaceholder from './token-list-placeholder'
|
||||||
import h from 'react-hyperscript'
|
|
||||||
import Tooltip from '../../../../../../old-ui/app/components/tooltip.js'
|
|
||||||
|
|
||||||
export default class InfoBox extends Component {
|
export default class InfoBox extends Component {
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
|
@ -26,7 +24,7 @@ export default class InfoBox extends Component {
|
||||||
: (
|
: (
|
||||||
<div className="token-list">
|
<div className="token-list">
|
||||||
<div className="token-list__title">
|
<div className="token-list__title">
|
||||||
{ 'searchResults' /* this.context.t('searchResults')*/ }
|
{ this.context.t('searchResults') }
|
||||||
</div>
|
</div>
|
||||||
<div className="token-list__tokens-container">
|
<div className="token-list__tokens-container">
|
||||||
{
|
{
|
||||||
|
@ -34,34 +32,24 @@ export default class InfoBox extends Component {
|
||||||
.map((_, i) => {
|
.map((_, i) => {
|
||||||
const { logo, symbol, name, address } = results[i] || {}
|
const { logo, symbol, name, address } = results[i] || {}
|
||||||
const tokenAlreadyAdded = checkExistingAddresses(address, tokens)
|
const tokenAlreadyAdded = checkExistingAddresses(address, tokens)
|
||||||
const title = `${name} (${symbol})`
|
|
||||||
const isLongTitle = title.length > 28
|
|
||||||
|
|
||||||
const tokenRow = (key) => h(`.${classnames('token-list__token', {
|
|
||||||
'token-list__token--selected': selectedTokens[address],
|
|
||||||
'token-list__token--disabled': tokenAlreadyAdded,
|
|
||||||
}).split(' ').join('.')}`, {
|
|
||||||
onClick: () => !tokenAlreadyAdded && onToggleToken(results[i]),
|
|
||||||
key: key || 'tokenRow',
|
|
||||||
}, [
|
|
||||||
h('.token-list__token-icon', {
|
|
||||||
style: {
|
|
||||||
backgroundImage: logo && `url(images/contract/${logo})`,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
h('.token-list__token-data', [
|
|
||||||
h('span.token-list__token-name', title),
|
|
||||||
]),
|
|
||||||
])
|
|
||||||
|
|
||||||
return Boolean(logo || symbol || name) && (
|
return Boolean(logo || symbol || name) && (
|
||||||
isLongTitle ? h(Tooltip, {
|
<div
|
||||||
position: 'top',
|
className={classnames('token-list__token', {
|
||||||
title: title,
|
'token-list__token--selected': selectedTokens[address],
|
||||||
key: i,
|
'token-list__token--disabled': tokenAlreadyAdded,
|
||||||
}, [
|
})}
|
||||||
tokenRow(),
|
onClick={() => !tokenAlreadyAdded && onToggleToken(results[i])}
|
||||||
]) : tokenRow(i)
|
key={i}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="token-list__token-icon"
|
||||||
|
style={{ backgroundImage: logo && `url(images/contract/${logo})` }}>
|
||||||
|
</div>
|
||||||
|
<div className="token-list__token-data">
|
||||||
|
<span className="token-list__token-name">{ `${name} (${symbol})` }</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ export default class TokenSearch extends Component {
|
||||||
return (
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
id="search-tokens"
|
id="search-tokens"
|
||||||
placeholder={'Search Tokens' /* this.context.t('searchTokens')*/}
|
placeholder={this.context.t('searchTokens')}
|
||||||
type="text"
|
type="text"
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
onChange={e => this.handleSearch(e.target.value)}
|
onChange={e => this.handleSearch(e.target.value)}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
// import { DEFAULT_ROUTE, ADD_TOKEN_ROUTE } from '../../../routes'
|
import { DEFAULT_ROUTE, ADD_TOKEN_ROUTE } from '../../../routes'
|
||||||
import Button from '../../button'
|
import Button from '../../button'
|
||||||
import Identicon from '../../../components/identicon'
|
import Identicon from '../../../components/identicon'
|
||||||
import TokenBalance from './token-balance'
|
import TokenBalance from './token-balance'
|
||||||
|
@ -11,7 +11,7 @@ export default class ConfirmAddToken extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
// history: PropTypes.object,
|
history: PropTypes.object,
|
||||||
clearPendingTokens: PropTypes.func,
|
clearPendingTokens: PropTypes.func,
|
||||||
addTokens: PropTypes.func,
|
addTokens: PropTypes.func,
|
||||||
pendingTokens: PropTypes.object,
|
pendingTokens: PropTypes.object,
|
||||||
|
@ -19,11 +19,11 @@ export default class ConfirmAddToken extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const { pendingTokens = {}, goHome /*, history*/ } = this.props
|
const { pendingTokens = {}, goHome , history } = this.props
|
||||||
|
|
||||||
if (Object.keys(pendingTokens).length === 0) {
|
if (Object.keys(pendingTokens).length === 0) {
|
||||||
goHome()
|
goHome()
|
||||||
// history.push(DEFAULT_ROUTE)
|
history.push(DEFAULT_ROUTE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ export default class ConfirmAddToken extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { /* history,*/ addTokens, clearPendingTokens, pendingTokens, goHome } = this.props
|
const { history, addTokens, clearPendingTokens, pendingTokens, goHome } = this.props
|
||||||
const areMultipleTokens = pendingTokens && Object.keys(pendingTokens).length > 1
|
const areMultipleTokens = pendingTokens && Object.keys(pendingTokens).length > 1
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -93,7 +93,7 @@ export default class ConfirmAddToken extends Component {
|
||||||
<Button
|
<Button
|
||||||
type="default"
|
type="default"
|
||||||
className="btn-violet"
|
className="btn-violet"
|
||||||
onClick={() => goHome()}// history.push(ADD_TOKEN_ROUTE)}
|
onClick={() => history.push(ADD_TOKEN_ROUTE)}
|
||||||
>
|
>
|
||||||
{ 'Cancel' /* this.context.t('back')*/ }
|
{ 'Cancel' /* this.context.t('back')*/ }
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -103,8 +103,8 @@ export default class ConfirmAddToken extends Component {
|
||||||
addTokens(pendingTokens)
|
addTokens(pendingTokens)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
clearPendingTokens()
|
clearPendingTokens()
|
||||||
goHome()
|
//goHome()
|
||||||
// history.push(DEFAULT_ROUTE)
|
history.push(DEFAULT_ROUTE)
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import ConfirmAddToken from './confirm-add-token.component'
|
import ConfirmAddToken from './confirm-add-token.component'
|
||||||
|
|
||||||
const { addTokens, clearPendingTokens, goHome } = require('../../../actions')
|
const { addTokens, clearPendingTokens } = require('../../../actions')
|
||||||
|
|
||||||
const mapStateToProps = ({ metamask }) => {
|
const mapStateToProps = ({ metamask }) => {
|
||||||
const { pendingTokens } = metamask
|
const { pendingTokens } = metamask
|
||||||
|
@ -14,7 +14,6 @@ const mapDispatchToProps = dispatch => {
|
||||||
return {
|
return {
|
||||||
addTokens: tokens => dispatch(addTokens(tokens)),
|
addTokens: tokens => dispatch(addTokens(tokens)),
|
||||||
clearPendingTokens: () => dispatch(clearPendingTokens()),
|
clearPendingTokens: () => dispatch(clearPendingTokens()),
|
||||||
goHome: () => dispatch(goHome()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue