diff --git a/mascara/src/ui.js b/mascara/src/ui.js index f9e7670ea..7c06b3299 100644 --- a/mascara/src/ui.js +++ b/mascara/src/ui.js @@ -1,7 +1,7 @@ const injectCss = require('inject-css') const SwController = require('sw-controller') const SwStream = require('sw-stream') -const MetaMaskUiCss = require('../../ui/css') +const MetaMaskUiCss = require('../../old-ui/css') const MetamascaraPlatform = require('../../app/scripts/platforms/window') const startPopup = require('../../app/scripts/popup-core') diff --git a/ui/app/components/balance-component.js b/ui/app/components/balance-component.js deleted file mode 100644 index 801521da5..000000000 --- a/ui/app/components/balance-component.js +++ /dev/null @@ -1,109 +0,0 @@ -const Component = require('react').Component -const connect = require('react-redux').connect -const h = require('react-hyperscript') -const inherits = require('util').inherits -const TokenBalance = require('./token-balance') -const Identicon = require('./identicon') -import UserPreferencedCurrencyDisplay from './user-preferenced-currency-display' -import { PRIMARY, SECONDARY } from '../constants/common' -const { getAssetImages, conversionRateSelector, getCurrentCurrency, getMetaMaskAccounts } = require('../selectors') - -const { formatBalance } = require('../util') - -module.exports = connect(mapStateToProps)(BalanceComponent) - -function mapStateToProps (state) { - const accounts = getMetaMaskAccounts(state) - const network = state.metamask.network - const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0] - const account = accounts[selectedAddress] - - return { - account, - network, - conversionRate: conversionRateSelector(state), - currentCurrency: getCurrentCurrency(state), - assetImages: getAssetImages(state), - } -} - -inherits(BalanceComponent, Component) -function BalanceComponent () { - Component.call(this) -} - -BalanceComponent.prototype.render = function () { - const props = this.props - const { token, network, assetImages } = props - const address = token && token.address - const image = assetImages && address ? assetImages[token.address] : undefined - - return h('div.balance-container', {}, [ - - // TODO: balance icon needs to be passed in - // h('img.balance-icon', { - // src: '../images/eth_logo.svg', - // style: {}, - // }), - h(Identicon, { - diameter: 50, - address, - network, - image, - }), - - token ? this.renderTokenBalance() : this.renderBalance(), - ]) -} - -BalanceComponent.prototype.renderTokenBalance = function () { - const { token } = this.props - - return h('div.flex-column.balance-display', [ - h('div.token-amount', [ h(TokenBalance, { token }) ]), - ]) -} - -BalanceComponent.prototype.renderBalance = function () { - const props = this.props - const { account } = props - const balanceValue = account && account.balance - const needsParse = 'needsParse' in props ? props.needsParse : true - const formattedBalance = balanceValue ? formatBalance(balanceValue, 6, needsParse) : '...' - const showFiat = 'showFiat' in props ? props.showFiat : true - - if (formattedBalance === 'None' || formattedBalance === '...') { - return h('div.flex-column.balance-display', {}, [ - h('div.token-amount', { - style: {}, - }, formattedBalance), - ]) - } - - return h('div.flex-column.balance-display', {}, [ - h('div.token-amount', {}, h(UserPreferencedCurrencyDisplay, { - value: balanceValue, - type: PRIMARY, - ethNumberOfDecimals: 3, - })), - - showFiat && h(UserPreferencedCurrencyDisplay, { - value: balanceValue, - type: SECONDARY, - ethNumberOfDecimals: 3, - }), - ]) -} - -BalanceComponent.prototype.getFiatDisplayNumber = function (formattedBalance, conversionRate) { - if (formattedBalance === 'None') return formattedBalance - if (conversionRate === 0) return 'N/A' - - const splitBalance = formattedBalance.split(' ') - - const convertedNumber = (Number(splitBalance[0]) * conversionRate) - const wholePart = Math.floor(convertedNumber) - const decimalPart = convertedNumber - wholePart - - return wholePart + Number(decimalPart.toPrecision(2)) -} diff --git a/ui/app/components/pages/add-token/add-token.component.js b/ui/app/components/pages/add-token/add-token.component.js deleted file mode 100644 index 3612e676c..000000000 --- a/ui/app/components/pages/add-token/add-token.component.js +++ /dev/null @@ -1,319 +0,0 @@ -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 ( -
- this.handleCustomAddressChange(e.target.value)} - error={customAddressError} - fullWidth - margin="normal" - /> - this.handleCustomSymbolChange(e.target.value)} - error={customSymbolError} - fullWidth - margin="normal" - disabled={autoFilled} - /> - this.handleCustomDecimalsChange(e.target.value)} - error={customDecimalsError} - fullWidth - margin="normal" - disabled={autoFilled} - /> -
- ) - } - - renderSearchToken () { - const { tokenSelectorError, selectedTokens, searchResults } = this.state - - return ( -
- this.setState({ searchResults: results })} - error={tokenSelectorError} - /> -
- this.handleToggleToken(token)} - /> -
-
- ) - } - - renderTabs () { - return ( - - - { this.renderSearchToken() } - - - { this.renderCustomTokenForm() } - - - ) - } - - render () { - const { history, clearPendingTokens } = this.props - - return ( - this.handleNext()} - disabled={this.hasError() || !this.hasSelected()} - onCancel={() => { - clearPendingTokens() - history.push(DEFAULT_ROUTE) - }} - /> - ) - } -} - -export default AddToken diff --git a/ui/app/components/pages/add-token/add-token.container.js b/ui/app/components/pages/add-token/add-token.container.js deleted file mode 100644 index 87671b156..000000000 --- a/ui/app/components/pages/add-token/add-token.container.js +++ /dev/null @@ -1,22 +0,0 @@ -import { connect } from 'react-redux' -import AddToken from './add-token.component' - -const { setPendingTokens, clearPendingTokens } = 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()), - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(AddToken) diff --git a/ui/app/components/pages/add-token/index.js b/ui/app/components/pages/add-token/index.js deleted file mode 100644 index 3666cae82..000000000 --- a/ui/app/components/pages/add-token/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import AddToken from './add-token.container' -module.exports = AddToken diff --git a/ui/app/components/pages/add-token/index.scss b/ui/app/components/pages/add-token/index.scss deleted file mode 100644 index 39e86b97b..000000000 --- a/ui/app/components/pages/add-token/index.scss +++ /dev/null @@ -1,25 +0,0 @@ -@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; - } -} diff --git a/ui/app/components/pages/add-token/token-list/index.js b/ui/app/components/pages/add-token/token-list/index.js deleted file mode 100644 index 21dd5ac72..000000000 --- a/ui/app/components/pages/add-token/token-list/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import TokenList from './token-list.container' -module.exports = TokenList diff --git a/ui/app/components/pages/add-token/token-list/index.scss b/ui/app/components/pages/add-token/token-list/index.scss deleted file mode 100644 index e32739d59..000000000 --- a/ui/app/components/pages/add-token/token-list/index.scss +++ /dev/null @@ -1,65 +0,0 @@ -@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; - } -} diff --git a/ui/app/components/pages/add-token/token-list/token-list-placeholder/index.js b/ui/app/components/pages/add-token/token-list/token-list-placeholder/index.js deleted file mode 100644 index b82f45e93..000000000 --- a/ui/app/components/pages/add-token/token-list/token-list-placeholder/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import TokenListPlaceholder from './token-list-placeholder.component' -module.exports = TokenListPlaceholder diff --git a/ui/app/components/pages/add-token/token-list/token-list-placeholder/index.scss b/ui/app/components/pages/add-token/token-list/token-list-placeholder/index.scss deleted file mode 100644 index cc495dfb0..000000000 --- a/ui/app/components/pages/add-token/token-list/token-list-placeholder/index.scss +++ /dev/null @@ -1,23 +0,0 @@ -.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; - } -} diff --git a/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js b/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js deleted file mode 100644 index 20f550927..000000000 --- a/ui/app/components/pages/add-token/token-list/token-list-placeholder/token-list-placeholder.component.js +++ /dev/null @@ -1,27 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' - -export default class TokenListPlaceholder extends Component { - static contextTypes = { - t: PropTypes.func, - } - - render () { - return ( -
- -
- { this.context.t('addAcquiredTokens') } -
- - { this.context.t('learnMore') } - -
- ) - } -} diff --git a/ui/app/components/pages/add-token/token-list/token-list.component.js b/ui/app/components/pages/add-token/token-list/token-list.component.js deleted file mode 100644 index 724a68d6e..000000000 --- a/ui/app/components/pages/add-token/token-list/token-list.component.js +++ /dev/null @@ -1,60 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import classnames from 'classnames' -import { checkExistingAddresses } from '../util' -import TokenListPlaceholder from './token-list-placeholder' - -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 - ? - : ( -
-
- { this.context.t('searchResults') } -
-
- { - Array(6).fill(undefined) - .map((_, i) => { - const { logo, symbol, name, address } = results[i] || {} - const tokenAlreadyAdded = checkExistingAddresses(address, tokens) - - return Boolean(logo || symbol || name) && ( -
!tokenAlreadyAdded && onToggleToken(results[i])} - key={i} - > -
-
-
- { `${name} (${symbol})` } -
-
- ) - }) - } -
-
- ) - } -} diff --git a/ui/app/components/pages/add-token/token-list/token-list.container.js b/ui/app/components/pages/add-token/token-list/token-list.container.js deleted file mode 100644 index cd7b07a37..000000000 --- a/ui/app/components/pages/add-token/token-list/token-list.container.js +++ /dev/null @@ -1,11 +0,0 @@ -import { connect } from 'react-redux' -import TokenList from './token-list.component' - -const mapStateToProps = ({ metamask }) => { - const { tokens } = metamask - return { - tokens, - } -} - -export default connect(mapStateToProps)(TokenList) diff --git a/ui/app/components/pages/add-token/token-search/index.js b/ui/app/components/pages/add-token/token-search/index.js deleted file mode 100644 index acaa6b084..000000000 --- a/ui/app/components/pages/add-token/token-search/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import TokenSearch from './token-search.component' -module.exports = TokenSearch diff --git a/ui/app/components/pages/add-token/token-search/token-search.component.js b/ui/app/components/pages/add-token/token-search/token-search.component.js deleted file mode 100644 index 036b2db1e..000000000 --- a/ui/app/components/pages/add-token/token-search/token-search.component.js +++ /dev/null @@ -1,85 +0,0 @@ -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 ( - - - - ) - } - - render () { - const { error } = this.props - const { searchQuery } = this.state - - return ( - this.handleSearch(e.target.value)} - error={error} - fullWidth - startAdornment={this.renderAdornment()} - /> - ) - } -} diff --git a/ui/app/components/pages/add-token/util.js b/ui/app/components/pages/add-token/util.js deleted file mode 100644 index 579c56cc0..000000000 --- a/ui/app/components/pages/add-token/util.js +++ /dev/null @@ -1,13 +0,0 @@ -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) -} diff --git a/ui/app/components/pages/authenticated.js b/ui/app/components/pages/authenticated.js deleted file mode 100644 index 1f6b0be49..000000000 --- a/ui/app/components/pages/authenticated.js +++ /dev/null @@ -1,34 +0,0 @@ -const { connect } = require('react-redux') -const PropTypes = require('prop-types') -const { Redirect } = require('react-router-dom') -const h = require('react-hyperscript') -const MetamaskRoute = require('./metamask-route') -const { UNLOCK_ROUTE, INITIALIZE_ROUTE } = require('../../routes') - -const Authenticated = props => { - const { isUnlocked, isInitialized } = props - - switch (true) { - case isUnlocked && isInitialized: - return h(MetamaskRoute, { ...props }) - case !isInitialized: - return h(Redirect, { to: { pathname: INITIALIZE_ROUTE } }) - default: - return h(Redirect, { to: { pathname: UNLOCK_ROUTE } }) - } -} - -Authenticated.propTypes = { - isUnlocked: PropTypes.bool, - isInitialized: PropTypes.bool, -} - -const mapStateToProps = state => { - const { metamask: { isUnlocked, isInitialized } } = state - return { - isUnlocked, - isInitialized, - } -} - -module.exports = connect(mapStateToProps)(Authenticated) diff --git a/ui/app/components/pages/initialized.js b/ui/app/components/pages/initialized.js deleted file mode 100644 index 3adf67b28..000000000 --- a/ui/app/components/pages/initialized.js +++ /dev/null @@ -1,25 +0,0 @@ -const { connect } = require('react-redux') -const PropTypes = require('prop-types') -const { Redirect } = require('react-router-dom') -const h = require('react-hyperscript') -const { INITIALIZE_ROUTE } = require('../../routes') -const MetamaskRoute = require('./metamask-route') - -const Initialized = props => { - return props.isInitialized - ? h(MetamaskRoute, { ...props }) - : h(Redirect, { to: { pathname: INITIALIZE_ROUTE } }) -} - -Initialized.propTypes = { - isInitialized: PropTypes.bool, -} - -const mapStateToProps = state => { - const { metamask: { isInitialized } } = state - return { - isInitialized, - } -} - -module.exports = connect(mapStateToProps)(Initialized) diff --git a/ui/app/components/pages/metamask-route.js b/ui/app/components/pages/metamask-route.js deleted file mode 100644 index 23c5b5199..000000000 --- a/ui/app/components/pages/metamask-route.js +++ /dev/null @@ -1,28 +0,0 @@ -const { connect } = require('react-redux') -const PropTypes = require('prop-types') -const { Route } = require('react-router-dom') -const h = require('react-hyperscript') - -const MetamaskRoute = ({ component, mascaraComponent, isMascara, ...props }) => { - return ( - h(Route, { - ...props, - component: isMascara && mascaraComponent ? mascaraComponent : component, - }) - ) -} - -MetamaskRoute.propTypes = { - component: PropTypes.func, - mascaraComponent: PropTypes.func, - isMascara: PropTypes.bool, -} - -const mapStateToProps = state => { - const { metamask: { isMascara } } = state - return { - isMascara, - } -} - -module.exports = connect(mapStateToProps)(MetamaskRoute) diff --git a/ui/app/components/pages/notice.js b/ui/app/components/pages/notice.js deleted file mode 100644 index a9077b98b..000000000 --- a/ui/app/components/pages/notice.js +++ /dev/null @@ -1,203 +0,0 @@ -const { Component } = require('react') -const h = require('react-hyperscript') -const { connect } = require('react-redux') -const PropTypes = require('prop-types') -const ReactMarkdown = require('react-markdown') -const linker = require('extension-link-enabler') -const generateLostAccountsNotice = require('../../../lib/lost-accounts-notice') -const findDOMNode = require('react-dom').findDOMNode -const actions = require('../../actions') -const { DEFAULT_ROUTE } = require('../../routes') - -class Notice extends Component { - constructor (props) { - super(props) - - this.state = { - disclaimerDisabled: true, - } - } - - componentWillMount () { - if (!this.props.notice) { - this.props.history.push(DEFAULT_ROUTE) - } - } - - componentDidMount () { - // eslint-disable-next-line react/no-find-dom-node - var node = findDOMNode(this) - linker.setupListener(node) - if (document.getElementsByClassName('notice-box')[0].clientHeight < 310) { - this.setState({ disclaimerDisabled: false }) - } - } - - componentWillReceiveProps (nextProps) { - if (!nextProps.notice) { - this.props.history.push(DEFAULT_ROUTE) - } - } - - componentWillUnmount () { - // eslint-disable-next-line react/no-find-dom-node - var node = findDOMNode(this) - linker.teardownListener(node) - } - - handleAccept () { - this.setState({ disclaimerDisabled: true }) - this.props.onConfirm() - } - - render () { - const { notice = {} } = this.props - const { title, date, body } = notice - const { disclaimerDisabled } = this.state - - return ( - h('.flex-column.flex-center.flex-grow', { - style: { - width: '100%', - }, - }, [ - h('h3.flex-center.text-transform-uppercase.terms-header', { - style: { - background: '#EBEBEB', - color: '#AEAEAE', - width: '100%', - fontSize: '20px', - textAlign: 'center', - padding: 6, - }, - }, [ - title, - ]), - - h('h5.flex-center.text-transform-uppercase.terms-header', { - style: { - background: '#EBEBEB', - color: '#AEAEAE', - marginBottom: 24, - width: '100%', - fontSize: '20px', - textAlign: 'center', - padding: 6, - }, - }, [ - date, - ]), - - h('style', ` - - .markdown { - overflow-x: hidden; - } - - .markdown h1, .markdown h2, .markdown h3 { - margin: 10px 0; - font-weight: bold; - } - - .markdown strong { - font-weight: bold; - } - .markdown em { - font-style: italic; - } - - .markdown p { - margin: 10px 0; - } - - .markdown a { - color: #df6b0e; - } - - `), - - h('div.markdown', { - onScroll: (e) => { - var object = e.currentTarget - if (object.offsetHeight + object.scrollTop + 100 >= object.scrollHeight) { - this.setState({ disclaimerDisabled: false }) - } - }, - style: { - background: 'rgb(235, 235, 235)', - height: '310px', - padding: '6px', - width: '90%', - overflowY: 'scroll', - scroll: 'auto', - }, - }, [ - h(ReactMarkdown, { - className: 'notice-box', - source: body, - skipHtml: true, - }), - ]), - - h('button.primary', { - disabled: disclaimerDisabled, - onClick: () => this.handleAccept(), - style: { - marginTop: '18px', - }, - }, 'Accept'), - ]) - ) - } - -} - -const mapStateToProps = state => { - const { metamask } = state - const { noActiveNotices, nextUnreadNotice, lostAccounts } = metamask - - return { - noActiveNotices, - nextUnreadNotice, - lostAccounts, - } -} - -Notice.propTypes = { - notice: PropTypes.object, - onConfirm: PropTypes.func, - history: PropTypes.object, -} - -const mapDispatchToProps = dispatch => { - return { - markNoticeRead: nextUnreadNotice => dispatch(actions.markNoticeRead(nextUnreadNotice)), - markAccountsFound: () => dispatch(actions.markAccountsFound()), - } -} - -const mergeProps = (stateProps, dispatchProps, ownProps) => { - const { noActiveNotices, nextUnreadNotice, lostAccounts } = stateProps - const { markNoticeRead, markAccountsFound } = dispatchProps - - let notice - let onConfirm - - if (!noActiveNotices) { - notice = nextUnreadNotice - onConfirm = () => markNoticeRead(nextUnreadNotice) - } else if (lostAccounts && lostAccounts.length > 0) { - notice = generateLostAccountsNotice(lostAccounts) - onConfirm = () => markAccountsFound() - } - - return { - ...stateProps, - ...dispatchProps, - ...ownProps, - notice, - onConfirm, - } -} - -module.exports = connect(mapStateToProps, mapDispatchToProps, mergeProps)(Notice) diff --git a/ui/app/components/token-balance/index.js b/ui/app/components/token-balance/index.js deleted file mode 100644 index f7da15cf8..000000000 --- a/ui/app/components/token-balance/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './token-balance.container' diff --git a/ui/app/components/token-balance/token-balance.component.js b/ui/app/components/token-balance/token-balance.component.js deleted file mode 100644 index 2b4f73980..000000000 --- a/ui/app/components/token-balance/token-balance.component.js +++ /dev/null @@ -1,23 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import classnames from 'classnames' - -export default class TokenBalance extends PureComponent { - static propTypes = { - string: PropTypes.string, - symbol: PropTypes.string, - error: PropTypes.string, - className: PropTypes.string, - withSymbol: PropTypes.bool, - } - - render () { - const { className, string, withSymbol, symbol } = this.props - - return ( -
- { string + (withSymbol ? ` ${symbol}` : '') } -
- ) - } -} diff --git a/ui/app/components/token-balance/token-balance.container.js b/ui/app/components/token-balance/token-balance.container.js deleted file mode 100644 index adc001f83..000000000 --- a/ui/app/components/token-balance/token-balance.container.js +++ /dev/null @@ -1,16 +0,0 @@ -import { connect } from 'react-redux' -import { compose } from 'recompose' -import withTokenTracker from '../../higher-order-components/with-token-tracker' -import TokenBalance from './token-balance.component' -import selectors from '../../selectors' - -const mapStateToProps = state => { - return { - userAddress: selectors.getSelectedAddress(state), - } -} - -export default compose( - connect(mapStateToProps), - withTokenTracker -)(TokenBalance) diff --git a/ui/app/components/token-cell.js b/ui/app/components/token-cell.js new file mode 100644 index 000000000..edf8b2661 --- /dev/null +++ b/ui/app/components/token-cell.js @@ -0,0 +1,160 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits +const connect = require('react-redux').connect +const Identicon = require('./identicon') +const ethNetProps = require('eth-net-props') +const selectors = require('../selectors') +const actions = require('../actions') +const { conversionUtil, multiplyCurrencies } = require('../conversion-util') + +const TokenMenuDropdown = require('./dropdowns/token-menu-dropdown.js') + +function mapStateToProps (state) { + return { + network: state.metamask.network, + currentCurrency: state.metamask.currentCurrency, + selectedTokenAddress: state.metamask.selectedTokenAddress, + userAddress: selectors.getSelectedAddress(state), + contractExchangeRates: state.metamask.contractExchangeRates, + conversionRate: state.metamask.conversionRate, + sidebarOpen: state.appState.sidebar.isOpen, + } +} + +function mapDispatchToProps (dispatch) { + return { + setSelectedToken: address => dispatch(actions.setSelectedToken(address)), + hideSidebar: () => dispatch(actions.hideSidebar()), + } +} + +module.exports = connect(mapStateToProps, mapDispatchToProps)(TokenCell) + +inherits(TokenCell, Component) +function TokenCell () { + Component.call(this) + + this.state = { + tokenMenuOpen: false, + } +} + +TokenCell.prototype.render = function () { + const { tokenMenuOpen } = this.state + const props = this.props + const { + address, + symbol, + string, + network, + setSelectedToken, + selectedTokenAddress, + contractExchangeRates, + conversionRate, + hideSidebar, + sidebarOpen, + currentCurrency, + // userAddress, + image, + } = props + let currentTokenToFiatRate + let currentTokenInFiat + let formattedFiat = '' + + if (contractExchangeRates[address]) { + currentTokenToFiatRate = multiplyCurrencies( + contractExchangeRates[address], + conversionRate + ) + currentTokenInFiat = conversionUtil(string, { + fromNumericBase: 'dec', + fromCurrency: symbol, + toCurrency: currentCurrency.toUpperCase(), + numberOfDecimals: 2, + conversionRate: currentTokenToFiatRate, + }) + formattedFiat = currentTokenInFiat.toString() === '0' + ? '' + : `${currentTokenInFiat} ${currentCurrency.toUpperCase()}` + } + + const showFiat = Boolean(currentTokenInFiat) && currentCurrency.toUpperCase() !== symbol + + return ( + h('div.token-list-item', { + className: `token-list-item ${selectedTokenAddress === address ? 'token-list-item--active' : ''}`, + // style: { cursor: network === '1' ? 'pointer' : 'default' }, + // onClick: this.view.bind(this, address, userAddress, network), + onClick: () => { + setSelectedToken(address) + selectedTokenAddress !== address && sidebarOpen && hideSidebar() + }, + }, [ + + h(Identicon, { + className: 'token-list-item__identicon', + diameter: 50, + address, + network, + image, + }), + + h('div.token-list-item__balance-ellipsis', null, [ + h('div.token-list-item__balance-wrapper', null, [ + h('div.token-list-item__token-balance', `${string || 0}`), + h('div.token-list-item__token-symbol', symbol), + showFiat && h('div.token-list-item__fiat-amount', { + style: {}, + }, formattedFiat), + ]), + + h('i.fa.fa-ellipsis-h.fa-lg.token-list-item__ellipsis.cursor-pointer', { + onClick: (e) => { + e.stopPropagation() + this.setState({ tokenMenuOpen: true }) + }, + }), + + ]), + + + tokenMenuOpen && h(TokenMenuDropdown, { + onClose: () => this.setState({ tokenMenuOpen: false }), + token: { symbol, address }, + }), + + /* + h('button', { + onClick: this.send.bind(this, address), + }, 'SEND'), + */ + + ]) + ) +} + +TokenCell.prototype.send = function (address, event) { + event.preventDefault() + event.stopPropagation() + const url = tokenFactoryFor(address) + if (url) { + navigateTo(url) + } +} + +TokenCell.prototype.view = function (address, userAddress, network, event) { + const url = ethNetProps.explorerLinks.getExplorerTokenLinkFor(address, userAddress, network) + if (url) { + navigateTo(url) + } +} + +function navigateTo (url) { + global.platform.openWindow({ url }) +} + +function tokenFactoryFor (tokenAddress) { + return `https://tokenfactory.surge.sh/#/token/${tokenAddress}` +} + diff --git a/ui/app/components/token-currency-display/index.js b/ui/app/components/token-currency-display/index.js deleted file mode 100644 index 6065cae1f..000000000 --- a/ui/app/components/token-currency-display/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './token-currency-display.component' diff --git a/ui/app/components/token-currency-display/token-currency-display.component.js b/ui/app/components/token-currency-display/token-currency-display.component.js deleted file mode 100644 index 4bb09a4b6..000000000 --- a/ui/app/components/token-currency-display/token-currency-display.component.js +++ /dev/null @@ -1,54 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import CurrencyDisplay from '../currency-display/currency-display.component' -import { getTokenData } from '../../helpers/transactions.util' -import { getTokenValue, calcTokenAmount } from '../../token-util' - -export default class TokenCurrencyDisplay extends PureComponent { - static propTypes = { - transactionData: PropTypes.string, - token: PropTypes.object, - } - - state = { - displayValue: '', - } - - componentDidMount () { - this.setDisplayValue() - } - - componentDidUpdate (prevProps) { - const { transactionData } = this.props - const { transactionData: prevTransactionData } = prevProps - - if (transactionData !== prevTransactionData) { - this.setDisplayValue() - } - } - - setDisplayValue () { - const { transactionData: data, token } = this.props - const { decimals = '', symbol = '' } = token - const tokenData = getTokenData(data) - - let displayValue - - if (tokenData.params && tokenData.params.length) { - const tokenValue = getTokenValue(tokenData.params) - const tokenAmount = calcTokenAmount(tokenValue, decimals) - displayValue = `${tokenAmount} ${symbol}` - } - - this.setState({ displayValue }) - } - - render () { - return ( - - ) - } -}