import React, { Component } from 'react' 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 TextField from '../../text-field' import TokenList from './token-list' import TokenSearch from './token-search' import PageContainer from '../../page-container' import { Tabs, Tab } from '../../tabs' 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 (