diff options
author | Alexander Tseung <alextsg@gmail.com> | 2017-11-29 12:24:35 +0800 |
---|---|---|
committer | Alexander Tseung <alextsg@gmail.com> | 2017-12-15 04:50:20 +0800 |
commit | e226b10a89d87af07c7c35ff1251a8264f3bb1b8 (patch) | |
tree | 2a1507463ac1074a39e4ebd3ae609be0a2962bc6 /ui/app/add-token.js | |
parent | 339eb7d1a687f141e822c745c568063783d44f15 (diff) | |
download | tangerine-wallet-browser-e226b10a89d87af07c7c35ff1251a8264f3bb1b8.tar.gz tangerine-wallet-browser-e226b10a89d87af07c7c35ff1251a8264f3bb1b8.tar.zst tangerine-wallet-browser-e226b10a89d87af07c7c35ff1251a8264f3bb1b8.zip |
Add react-router to allow use of the browser back button
Diffstat (limited to 'ui/app/add-token.js')
-rw-r--r-- | ui/app/add-token.js | 357 |
1 files changed, 0 insertions, 357 deletions
diff --git a/ui/app/add-token.js b/ui/app/add-token.js deleted file mode 100644 index 10aaae103..000000000 --- a/ui/app/add-token.js +++ /dev/null @@ -1,357 +0,0 @@ -const inherits = require('util').inherits -const Component = require('react').Component -const classnames = require('classnames') -const h = require('react-hyperscript') -const connect = require('react-redux').connect -const Fuse = require('fuse.js') -const contractMap = require('eth-contract-metadata') -const TokenBalance = require('./components/token-balance') -const Identicon = require('./components/identicon') -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: ['address', 'name', 'symbol'], -}) -const actions = require('./actions') -const ethUtil = require('ethereumjs-util') -const { tokenInfoGetter } = require('./token-util') -const R = require('ramda') - -const emptyAddr = '0x0000000000000000000000000000000000000000' - -module.exports = connect(mapStateToProps, mapDispatchToProps)(AddTokenScreen) - -function mapStateToProps (state) { - const { identities, tokens } = state.metamask - return { - identities, - tokens, - } -} - -function mapDispatchToProps (dispatch) { - return { - goHome: () => dispatch(actions.goHome()), - addTokens: tokens => dispatch(actions.addTokens(tokens)), - } -} - -inherits(AddTokenScreen, Component) -function AddTokenScreen () { - this.state = { - isShowingConfirmation: false, - customAddress: '', - customSymbol: '', - customDecimals: 0, - searchQuery: '', - isCollapsed: true, - selectedTokens: {}, - errors: {}, - } - this.tokenAddressDidChange = this.tokenAddressDidChange.bind(this) - this.onNext = this.onNext.bind(this) - Component.call(this) -} - -AddTokenScreen.prototype.componentWillMount = function () { - this.tokenInfoGetter = tokenInfoGetter() -} - -AddTokenScreen.prototype.toggleToken = function (address, token) { - const { selectedTokens, errors } = this.state - const { [address]: selectedToken } = selectedTokens - this.setState({ - selectedTokens: { - ...selectedTokens, - [address]: selectedToken ? null : token, - }, - errors: { - ...errors, - tokenSelector: null, - }, - }) -} - -AddTokenScreen.prototype.onNext = function () { - const { isValid, errors } = this.validate() - - return !isValid - ? this.setState({ errors }) - : this.setState({ isShowingConfirmation: true }) -} - -AddTokenScreen.prototype.tokenAddressDidChange = function (e) { - const customAddress = e.target.value.trim() - this.setState({ customAddress }) - if (ethUtil.isValidAddress(customAddress) && customAddress !== emptyAddr) { - this.attemptToAutoFillTokenParams(customAddress) - } else { - this.setState({ - customSymbol: '', - customDecimals: 0, - }) - } -} - -AddTokenScreen.prototype.checkExistingAddresses = function (address) { - if (!address) return false - const tokensList = this.props.tokens - const matchesAddress = existingToken => { - return existingToken.address.toLowerCase() === address.toLowerCase() - } - - return R.any(matchesAddress)(tokensList) -} - -AddTokenScreen.prototype.validate = function () { - const errors = {} - const identitiesList = Object.keys(this.props.identities) - const { customAddress, customSymbol, customDecimals, selectedTokens } = this.state - const standardAddress = ethUtil.addHexPrefix(customAddress).toLowerCase() - - if (customAddress) { - const validAddress = ethUtil.isValidAddress(customAddress) - if (!validAddress) { - errors.customAddress = 'Address is invalid. ' - } - - const validDecimals = customDecimals >= 0 && customDecimals < 36 - if (!validDecimals) { - errors.customDecimals = 'Decimals must be at least 0, and not over 36.' - } - - const symbolLen = customSymbol.trim().length - const validSymbol = symbolLen > 0 && symbolLen < 10 - if (!validSymbol) { - errors.customSymbol = 'Symbol must be between 0 and 10 characters.' - } - - const ownAddress = identitiesList.includes(standardAddress) - if (ownAddress) { - errors.customAddress = 'Personal address detected. Input the token contract address.' - } - - const tokenAlreadyAdded = this.checkExistingAddresses(customAddress) - if (tokenAlreadyAdded) { - errors.customAddress = 'Token has already been added.' - } - } else if ( - Object.entries(selectedTokens) - .reduce((isEmpty, [ symbol, isSelected ]) => ( - isEmpty && !isSelected - ), true) - ) { - errors.tokenSelector = 'Must select at least 1 token.' - } - - return { - isValid: !Object.keys(errors).length, - errors, - } -} - -AddTokenScreen.prototype.attemptToAutoFillTokenParams = async function (address) { - const { symbol, decimals } = await this.tokenInfoGetter(address) - if (symbol && decimals) { - this.setState({ - customSymbol: symbol, - customDecimals: decimals.toString(), - }) - } -} - -AddTokenScreen.prototype.renderCustomForm = function () { - const { customAddress, customSymbol, customDecimals, errors } = this.state - - return !this.state.isCollapsed && ( - h('div.add-token__add-custom-form', [ - h('div', { - className: classnames('add-token__add-custom-field', { - 'add-token__add-custom-field--error': errors.customAddress, - }), - }, [ - h('div.add-token__add-custom-label', 'Token Address'), - h('input.add-token__add-custom-input', { - type: 'text', - onChange: this.tokenAddressDidChange, - value: customAddress, - }), - h('div.add-token__add-custom-error-message', errors.customAddress), - ]), - h('div', { - className: classnames('add-token__add-custom-field', { - 'add-token__add-custom-field--error': errors.customSymbol, - }), - }, [ - h('div.add-token__add-custom-label', 'Token Symbol'), - h('input.add-token__add-custom-input', { - type: 'text', - value: customSymbol, - disabled: true, - }), - h('div.add-token__add-custom-error-message', errors.customSymbol), - ]), - h('div', { - className: classnames('add-token__add-custom-field', { - 'add-token__add-custom-field--error': errors.customDecimals, - }), - }, [ - h('div.add-token__add-custom-label', 'Decimals of Precision'), - h('input.add-token__add-custom-input', { - type: 'number', - value: customDecimals, - disabled: true, - }), - h('div.add-token__add-custom-error-message', errors.customDecimals), - ]), - ]) - ) -} - -AddTokenScreen.prototype.renderTokenList = function () { - const { searchQuery = '', selectedTokens } = this.state - const results = searchQuery - ? fuse.search(searchQuery) || [] - : contractList - - return Array(6).fill(undefined) - .map((_, i) => { - const { logo, symbol, name, address } = results[i] || {} - const tokenAlreadyAdded = this.checkExistingAddresses(address) - return Boolean(logo || symbol || name) && ( - h('div.add-token__token-wrapper', { - className: classnames({ - 'add-token__token-wrapper--selected': selectedTokens[address], - 'add-token__token-wrapper--disabled': tokenAlreadyAdded, - }), - onClick: () => !tokenAlreadyAdded && this.toggleToken(address, results[i]), - }, [ - h('div.add-token__token-icon', { - style: { - backgroundImage: `url(images/contract/${logo})`, - }, - }), - h('div.add-token__token-data', [ - h('div.add-token__token-symbol', symbol), - h('div.add-token__token-name', name), - ]), - // tokenAlreadyAdded && ( - // h('div.add-token__token-message', 'Already added') - // ), - ]) - ) - }) -} - -AddTokenScreen.prototype.renderConfirmation = function () { - const { - customAddress: address, - customSymbol: symbol, - customDecimals: decimals, - selectedTokens, - } = this.state - - const { addTokens, goHome } = this.props - - const customToken = { - address, - symbol, - decimals, - } - - const tokens = address && symbol && decimals - ? { ...selectedTokens, [address]: customToken } - : selectedTokens - - return ( - h('div.add-token', [ - h('div.add-token__wrapper', [ - h('div.add-token__title-container.add-token__confirmation-title', [ - h('div.add-token__title', 'Add Token'), - h('div.add-token__description', 'Would you like to add these tokens?'), - ]), - h('div.add-token__content-container.add-token__confirmation-content', [ - h('div.add-token__description.add-token__confirmation-description', 'Your balances'), - h('div.add-token__confirmation-token-list', - Object.entries(tokens) - .map(([ address, token ]) => ( - h('span.add-token__confirmation-token-list-item', [ - h(Identicon, { - className: 'add-token__confirmation-token-icon', - diameter: 75, - address, - }), - h(TokenBalance, { token }), - ]) - )) - ), - ]), - ]), - h('div.add-token__buttons', [ - h('button.btn-secondary', { - onClick: () => addTokens(tokens).then(goHome), - }, 'Add Tokens'), - h('button.btn-tertiary', { - onClick: () => this.setState({ isShowingConfirmation: false }), - }, 'Back'), - ]), - ]) - ) -} - -AddTokenScreen.prototype.render = function () { - const { isCollapsed, errors, isShowingConfirmation } = this.state - const { goHome } = this.props - - return isShowingConfirmation - ? this.renderConfirmation() - : ( - h('div.add-token', [ - h('div.add-token__wrapper', [ - h('div.add-token__title-container', [ - h('div.add-token__title', 'Add Token'), - h('div.add-token__description', 'Keep track of the tokens you’ve bought with your MetaMask account. If you bought tokens using a different account, those tokens will not appear here.'), - h('div.add-token__description', 'Search for tokens or select from our list of popular tokens.'), - ]), - h('div.add-token__content-container', [ - h('div.add-token__input-container', [ - h('input.add-token__input', { - type: 'text', - placeholder: 'Search', - onChange: e => this.setState({ searchQuery: e.target.value }), - }), - h('div.add-token__search-input-error-message', errors.tokenSelector), - ]), - h( - 'div.add-token__token-icons-container', - this.renderTokenList(), - ), - ]), - h('div.add-token__footers', [ - h('div.add-token__add-custom', { - onClick: () => this.setState({ isCollapsed: !isCollapsed }), - }, [ - 'Add custom token', - h(`i.fa.fa-angle-${isCollapsed ? 'down' : 'up'}`), - ]), - this.renderCustomForm(), - ]), - ]), - h('div.add-token__buttons', [ - h('button.btn-secondary', { - onClick: this.onNext, - }, 'Next'), - h('button.btn-tertiary', { - onClick: goHome, - }, 'Cancel'), - ]), - ]) - ) -} |