diff options
Merge branch 'develop' into clearNotices
Diffstat (limited to 'ui/app/components/pages')
129 files changed, 0 insertions, 9357 deletions
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 198889cf2..000000000 --- a/ui/app/components/pages/add-token/add-token.component.js +++ /dev/null @@ -1,335 +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, - forceEditSymbol: false, - } - } - - 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 >= 12) { - customSymbolError = this.context.t('symbolBetweenZeroTwelve') - } - - 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, - forceEditSymbol, - } = this.state - - return ( - <div className="add-token__custom-token-form"> - <TextField - id="custom-address" - label={this.context.t('tokenContractAddress')} - type="text" - value={customAddress} - onChange={e => this.handleCustomAddressChange(e.target.value)} - error={customAddressError} - fullWidth - margin="normal" - /> - <TextField - id="custom-symbol" - label={( - <div className="add-token__custom-symbol__label-wrapper"> - <span className="add-token__custom-symbol__label"> - {this.context.t('tokenSymbol')} - </span> - {(autoFilled && !forceEditSymbol) && ( - <div - className="add-token__custom-symbol__edit" - onClick={() => this.setState({ forceEditSymbol: true })} - > - {this.context.t('edit')} - </div> - )} - </div> - )} - type="text" - value={customSymbol} - onChange={e => this.handleCustomSymbolChange(e.target.value)} - error={customSymbolError} - fullWidth - margin="normal" - disabled={autoFilled && !forceEditSymbol} - /> - <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> - ) - } - - renderTabs () { - return ( - <Tabs> - <Tab name={this.context.t('search')}> - { this.renderSearchToken() } - </Tab> - <Tab name={this.context.t('customToken')}> - { this.renderCustomTokenForm() } - </Tab> - </Tabs> - ) - } - - render () { - const { history, clearPendingTokens } = this.props - - return ( - <PageContainer - title={this.context.t('addTokens')} - tabsComponent={this.renderTabs()} - onSubmit={() => 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 1690c7654..000000000 --- a/ui/app/components/pages/add-token/index.scss +++ /dev/null @@ -1,45 +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; - } - - &__custom-symbol { - - &__label-wrapper { - display: flex; - flex-flow: row nowrap; - } - - &__label { - flex: 0 0 auto; - } - - &__edit { - flex: 1 1 auto; - text-align: right; - color: $curious-blue; - padding-right: 4px; - cursor: pointer; - } - } -} 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 ( - <div className="token-list-placeholder"> - <img src="images/tokensearch.svg" /> - <div className="token-list-placeholder__text"> - { this.context.t('addAcquiredTokens') } - </div> - <a - className="token-list-placeholder__link" - href="https://metamask.zendesk.com/hc/en-us/articles/360015489031" - target="_blank" - rel="noopener noreferrer" - > - { this.context.t('learnMore') } - </a> - </div> - ) - } -} 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 - ? <TokenListPlaceholder /> - : ( - <div className="token-list"> - <div className="token-list__title"> - { 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) - - return Boolean(logo || symbol || name) && ( - <div - className={classnames('token-list__token', { - 'token-list__token--selected': selectedTokens[address], - 'token-list__token--disabled': tokenAlreadyAdded, - })} - onClick={() => !tokenAlreadyAdded && onToggleToken(results[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> - ) - }) - } - </div> - </div> - ) - } -} 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 ( - <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={this.context.t('searchTokens')} - type="text" - value={searchQuery} - onChange={e => 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/confirm-add-suggested-token/confirm-add-suggested-token.component.js b/ui/app/components/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js deleted file mode 100644 index ee5d6fa64..000000000 --- a/ui/app/components/pages/confirm-add-suggested-token/confirm-add-suggested-token.component.js +++ /dev/null @@ -1,122 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import { DEFAULT_ROUTE } from '../../../routes' -import Button from '../../button' -import Identicon from '../../../components/identicon' -import TokenBalance from '../../token-balance' - -export default class ConfirmAddSuggestedToken extends Component { - static contextTypes = { - t: PropTypes.func, - } - - static propTypes = { - history: PropTypes.object, - clearPendingTokens: PropTypes.func, - addToken: PropTypes.func, - pendingTokens: PropTypes.object, - removeSuggestedTokens: PropTypes.func, - } - - componentDidMount () { - const { pendingTokens = {}, history } = this.props - - if (Object.keys(pendingTokens).length === 0) { - history.push(DEFAULT_ROUTE) - } - } - - getTokenName (name, symbol) { - return typeof name === 'undefined' - ? symbol - : `${name} (${symbol})` - } - - render () { - const { addToken, pendingTokens, removeSuggestedTokens, history } = this.props - const pendingTokenKey = Object.keys(pendingTokens)[0] - const pendingToken = pendingTokens[pendingTokenKey] - - return ( - <div className="page-container"> - <div className="page-container__header"> - <div className="page-container__title"> - { this.context.t('addSuggestedTokens') } - </div> - <div className="page-container__subtitle"> - { this.context.t('likeToAddTokens') } - </div> - </div> - <div className="page-container__content"> - <div className="confirm-add-token"> - <div className="confirm-add-token__header"> - <div className="confirm-add-token__token"> - { this.context.t('token') } - </div> - <div className="confirm-add-token__balance"> - { this.context.t('balance') } - </div> - </div> - <div className="confirm-add-token__token-list"> - { - Object.entries(pendingTokens) - .map(([ address, token ]) => { - const { name, symbol, image } = 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} - image={image} - /> - <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"> - <header> - <Button - type="default" - large - className="page-container__footer-button" - onClick={() => { - removeSuggestedTokens() - .then(() => history.push(DEFAULT_ROUTE)) - }} - > - { this.context.t('cancel') } - </Button> - <Button - type="primary" - large - className="page-container__footer-button" - onClick={() => { - addToken(pendingToken) - .then(() => removeSuggestedTokens()) - .then(() => history.push(DEFAULT_ROUTE)) - }} - > - { this.context.t('addToken') } - </Button> - </header> - </div> - </div> - ) - } -} diff --git a/ui/app/components/pages/confirm-add-suggested-token/confirm-add-suggested-token.container.js b/ui/app/components/pages/confirm-add-suggested-token/confirm-add-suggested-token.container.js deleted file mode 100644 index 1f2737e52..000000000 --- a/ui/app/components/pages/confirm-add-suggested-token/confirm-add-suggested-token.container.js +++ /dev/null @@ -1,29 +0,0 @@ -import { connect } from 'react-redux' -import { compose } from 'recompose' -import ConfirmAddSuggestedToken from './confirm-add-suggested-token.component' -import { withRouter } from 'react-router-dom' - -const extend = require('xtend') - -const { addToken, removeSuggestedTokens } = require('../../../actions') - -const mapStateToProps = ({ metamask }) => { - const { pendingTokens, suggestedTokens } = metamask - const params = extend(pendingTokens, suggestedTokens) - - return { - pendingTokens: params, - } -} - -const mapDispatchToProps = dispatch => { - return { - addToken: ({address, symbol, decimals, image}) => dispatch(addToken(address, symbol, decimals, image)), - removeSuggestedTokens: () => dispatch(removeSuggestedTokens()), - } -} - -export default compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(ConfirmAddSuggestedToken) diff --git a/ui/app/components/pages/confirm-add-suggested-token/index.js b/ui/app/components/pages/confirm-add-suggested-token/index.js deleted file mode 100644 index 2ca56b43c..000000000 --- a/ui/app/components/pages/confirm-add-suggested-token/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import ConfirmAddSuggestedToken from './confirm-add-suggested-token.container' -module.exports = ConfirmAddSuggestedToken diff --git a/ui/app/components/pages/confirm-add-token/confirm-add-token.component.js b/ui/app/components/pages/confirm-add-token/confirm-add-token.component.js deleted file mode 100644 index d3fec79d7..000000000 --- a/ui/app/components/pages/confirm-add-token/confirm-add-token.component.js +++ /dev/null @@ -1,117 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import { DEFAULT_ROUTE, ADD_TOKEN_ROUTE } from '../../../routes' -import Button from '../../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, - } - - componentDidMount () { - const { pendingTokens = {}, history } = this.props - - if (Object.keys(pendingTokens).length === 0) { - history.push(DEFAULT_ROUTE) - } - } - - getTokenName (name, symbol) { - return typeof name === 'undefined' - ? symbol - : `${name} (${symbol})` - } - - render () { - const { history, addTokens, clearPendingTokens, pendingTokens } = this.props - - return ( - <div className="page-container"> - <div className="page-container__header"> - <div className="page-container__title"> - { this.context.t('addTokens') } - </div> - <div className="page-container__subtitle"> - { this.context.t('likeToAddTokens') } - </div> - </div> - <div className="page-container__content"> - <div className="confirm-add-token"> - <div className="confirm-add-token__header"> - <div className="confirm-add-token__token"> - { this.context.t('token') } - </div> - <div className="confirm-add-token__balance"> - { this.context.t('balance') } - </div> - </div> - <div className="confirm-add-token__token-list"> - { - 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"> - <header> - <Button - type="default" - large - className="page-container__footer-button" - onClick={() => history.push(ADD_TOKEN_ROUTE)} - > - { this.context.t('back') } - </Button> - <Button - type="primary" - large - className="page-container__footer-button" - onClick={() => { - addTokens(pendingTokens) - .then(() => { - clearPendingTokens() - history.push(DEFAULT_ROUTE) - }) - }} - > - { this.context.t('addTokens') } - </Button> - </header> - </div> - </div> - ) - } -} diff --git a/ui/app/components/pages/confirm-add-token/confirm-add-token.container.js b/ui/app/components/pages/confirm-add-token/confirm-add-token.container.js deleted file mode 100644 index 0190024d9..000000000 --- a/ui/app/components/pages/confirm-add-token/confirm-add-token.container.js +++ /dev/null @@ -1,20 +0,0 @@ -import { connect } from 'react-redux' -import ConfirmAddToken from './confirm-add-token.component' - -const { addTokens, clearPendingTokens } = require('../../../actions') - -const mapStateToProps = ({ metamask }) => { - const { pendingTokens } = metamask - return { - pendingTokens, - } -} - -const mapDispatchToProps = dispatch => { - return { - addTokens: tokens => dispatch(addTokens(tokens)), - clearPendingTokens: () => dispatch(clearPendingTokens()), - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(ConfirmAddToken) diff --git a/ui/app/components/pages/confirm-add-token/index.js b/ui/app/components/pages/confirm-add-token/index.js deleted file mode 100644 index b7decabec..000000000 --- a/ui/app/components/pages/confirm-add-token/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import ConfirmAddToken from './confirm-add-token.container' -module.exports = ConfirmAddToken diff --git a/ui/app/components/pages/confirm-add-token/index.scss b/ui/app/components/pages/confirm-add-token/index.scss deleted file mode 100644 index 66146cf78..000000000 --- a/ui/app/components/pages/confirm-add-token/index.scss +++ /dev/null @@ -1,69 +0,0 @@ -.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; - } -} diff --git a/ui/app/components/pages/confirm-approve/confirm-approve.component.js b/ui/app/components/pages/confirm-approve/confirm-approve.component.js deleted file mode 100644 index b71eaa1d4..000000000 --- a/ui/app/components/pages/confirm-approve/confirm-approve.component.js +++ /dev/null @@ -1,21 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import ConfirmTokenTransactionBase from '../confirm-token-transaction-base' - -export default class ConfirmApprove extends Component { - static propTypes = { - tokenAmount: PropTypes.number, - tokenSymbol: PropTypes.string, - } - - render () { - const { tokenAmount, tokenSymbol } = this.props - - return ( - <ConfirmTokenTransactionBase - tokenAmount={tokenAmount} - warning={`By approving this action, you grant permission for this contract to spend up to ${tokenAmount} of your ${tokenSymbol}.`} - /> - ) - } -} diff --git a/ui/app/components/pages/confirm-approve/confirm-approve.container.js b/ui/app/components/pages/confirm-approve/confirm-approve.container.js deleted file mode 100644 index 4ef9f4ced..000000000 --- a/ui/app/components/pages/confirm-approve/confirm-approve.container.js +++ /dev/null @@ -1,15 +0,0 @@ -import { connect } from 'react-redux' -import ConfirmApprove from './confirm-approve.component' -import { approveTokenAmountAndToAddressSelector } from '../../../selectors/confirm-transaction' - -const mapStateToProps = state => { - const { confirmTransaction: { tokenProps: { tokenSymbol } = {} } } = state - const { tokenAmount } = approveTokenAmountAndToAddressSelector(state) - - return { - tokenAmount, - tokenSymbol, - } -} - -export default connect(mapStateToProps)(ConfirmApprove) diff --git a/ui/app/components/pages/confirm-approve/index.js b/ui/app/components/pages/confirm-approve/index.js deleted file mode 100644 index 791297be7..000000000 --- a/ui/app/components/pages/confirm-approve/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './confirm-approve.container' diff --git a/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.component.js b/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.component.js deleted file mode 100644 index 9bc0daab9..000000000 --- a/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.component.js +++ /dev/null @@ -1,64 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import ethUtil from 'ethereumjs-util' -import ConfirmTransactionBase from '../confirm-transaction-base' - -export default class ConfirmDeployContract extends Component { - static contextTypes = { - t: PropTypes.func, - } - - static propTypes = { - txData: PropTypes.object, - } - - renderData () { - const { t } = this.context - const { - txData: { - origin, - txParams: { - data, - } = {}, - } = {}, - } = this.props - - return ( - <div className="confirm-page-container-content__data"> - <div className="confirm-page-container-content__data-box"> - <div className="confirm-page-container-content__data-field"> - <div className="confirm-page-container-content__data-field-label"> - { `${t('origin')}:` } - </div> - <div> - { origin } - </div> - </div> - <div className="confirm-page-container-content__data-field"> - <div className="confirm-page-container-content__data-field-label"> - { `${t('bytes')}:` } - </div> - <div> - { ethUtil.toBuffer(data).length } - </div> - </div> - </div> - <div className="confirm-page-container-content__data-box-label"> - { `${t('hexData')}:` } - </div> - <div className="confirm-page-container-content__data-box"> - { data } - </div> - </div> - ) - } - - render () { - return ( - <ConfirmTransactionBase - action={this.context.t('contractDeployment')} - dataComponent={this.renderData()} - /> - ) - } -} diff --git a/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.container.js b/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.container.js deleted file mode 100644 index 336ee83ea..000000000 --- a/ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.container.js +++ /dev/null @@ -1,12 +0,0 @@ -import { connect } from 'react-redux' -import ConfirmDeployContract from './confirm-deploy-contract.component' - -const mapStateToProps = state => { - const { confirmTransaction: { txData } = {} } = state - - return { - txData, - } -} - -export default connect(mapStateToProps)(ConfirmDeployContract) diff --git a/ui/app/components/pages/confirm-deploy-contract/index.js b/ui/app/components/pages/confirm-deploy-contract/index.js deleted file mode 100644 index c4fb01b52..000000000 --- a/ui/app/components/pages/confirm-deploy-contract/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './confirm-deploy-contract.container' diff --git a/ui/app/components/pages/confirm-send-ether/confirm-send-ether.component.js b/ui/app/components/pages/confirm-send-ether/confirm-send-ether.component.js deleted file mode 100644 index 442a478b8..000000000 --- a/ui/app/components/pages/confirm-send-ether/confirm-send-ether.component.js +++ /dev/null @@ -1,39 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import ConfirmTransactionBase from '../confirm-transaction-base' -import { SEND_ROUTE } from '../../../routes' - -export default class ConfirmSendEther extends Component { - static contextTypes = { - t: PropTypes.func, - } - - static propTypes = { - editTransaction: PropTypes.func, - history: PropTypes.object, - txParams: PropTypes.object, - } - - handleEdit ({ txData }) { - const { editTransaction, history } = this.props - editTransaction(txData) - history.push(SEND_ROUTE) - } - - shouldHideData () { - const { txParams = {} } = this.props - return !txParams.data - } - - render () { - const hideData = this.shouldHideData() - - return ( - <ConfirmTransactionBase - action={this.context.t('confirm')} - hideData={hideData} - onEdit={confirmTransactionData => this.handleEdit(confirmTransactionData)} - /> - ) - } -} diff --git a/ui/app/components/pages/confirm-send-ether/confirm-send-ether.container.js b/ui/app/components/pages/confirm-send-ether/confirm-send-ether.container.js deleted file mode 100644 index e48ef54a8..000000000 --- a/ui/app/components/pages/confirm-send-ether/confirm-send-ether.container.js +++ /dev/null @@ -1,45 +0,0 @@ -import { connect } from 'react-redux' -import { compose } from 'recompose' -import { withRouter } from 'react-router-dom' -import { updateSend } from '../../../actions' -import { clearConfirmTransaction } from '../../../ducks/confirm-transaction.duck' -import ConfirmSendEther from './confirm-send-ether.component' - -const mapStateToProps = state => { - const { confirmTransaction: { txData: { txParams } = {} } } = state - - return { - txParams, - } -} - -const mapDispatchToProps = dispatch => { - return { - editTransaction: txData => { - const { id, txParams } = txData - const { - gas: gasLimit, - gasPrice, - to, - value: amount, - } = txParams - - dispatch(updateSend({ - gasLimit, - gasPrice, - gasTotal: null, - to, - amount, - errors: { to: null, amount: null }, - editingTransactionId: id && id.toString(), - })) - - dispatch(clearConfirmTransaction()) - }, - } -} - -export default compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(ConfirmSendEther) diff --git a/ui/app/components/pages/confirm-send-ether/index.js b/ui/app/components/pages/confirm-send-ether/index.js deleted file mode 100644 index 2d5767c39..000000000 --- a/ui/app/components/pages/confirm-send-ether/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './confirm-send-ether.container' diff --git a/ui/app/components/pages/confirm-send-token/confirm-send-token.component.js b/ui/app/components/pages/confirm-send-token/confirm-send-token.component.js deleted file mode 100644 index cb39e3d7b..000000000 --- a/ui/app/components/pages/confirm-send-token/confirm-send-token.component.js +++ /dev/null @@ -1,29 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import ConfirmTokenTransactionBase from '../confirm-token-transaction-base' -import { SEND_ROUTE } from '../../../routes' - -export default class ConfirmSendToken extends Component { - static propTypes = { - history: PropTypes.object, - editTransaction: PropTypes.func, - tokenAmount: PropTypes.number, - } - - handleEdit (confirmTransactionData) { - const { editTransaction, history } = this.props - editTransaction(confirmTransactionData) - history.push(SEND_ROUTE) - } - - render () { - const { tokenAmount } = this.props - - return ( - <ConfirmTokenTransactionBase - onEdit={confirmTransactionData => this.handleEdit(confirmTransactionData)} - tokenAmount={tokenAmount} - /> - ) - } -} diff --git a/ui/app/components/pages/confirm-send-token/confirm-send-token.container.js b/ui/app/components/pages/confirm-send-token/confirm-send-token.container.js deleted file mode 100644 index d60911e59..000000000 --- a/ui/app/components/pages/confirm-send-token/confirm-send-token.container.js +++ /dev/null @@ -1,52 +0,0 @@ -import { connect } from 'react-redux' -import { compose } from 'recompose' -import { withRouter } from 'react-router-dom' -import ConfirmSendToken from './confirm-send-token.component' -import { clearConfirmTransaction } from '../../../ducks/confirm-transaction.duck' -import { setSelectedToken, updateSend, showSendTokenPage } from '../../../actions' -import { conversionUtil } from '../../../conversion-util' -import { sendTokenTokenAmountAndToAddressSelector } from '../../../selectors/confirm-transaction' - -const mapStateToProps = state => { - const { tokenAmount } = sendTokenTokenAmountAndToAddressSelector(state) - - return { - tokenAmount, - } -} - -const mapDispatchToProps = dispatch => { - return { - editTransaction: ({ txData, tokenData, tokenProps }) => { - const { txParams: { to: tokenAddress, gas: gasLimit, gasPrice } = {}, id } = txData - const { params = [] } = tokenData - const { value: to } = params[0] || {} - const { value: tokenAmountInDec } = params[1] || {} - const tokenAmountInHex = conversionUtil(tokenAmountInDec, { - fromNumericBase: 'dec', - toNumericBase: 'hex', - }) - dispatch(setSelectedToken(tokenAddress)) - dispatch(updateSend({ - gasLimit, - gasPrice, - gasTotal: null, - to, - amount: tokenAmountInHex, - errors: { to: null, amount: null }, - editingTransactionId: id && id.toString(), - token: { - ...tokenProps, - address: tokenAddress, - }, - })) - dispatch(clearConfirmTransaction()) - dispatch(showSendTokenPage()) - }, - } -} - -export default compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(ConfirmSendToken) diff --git a/ui/app/components/pages/confirm-send-token/index.js b/ui/app/components/pages/confirm-send-token/index.js deleted file mode 100644 index 409b6ef3d..000000000 --- a/ui/app/components/pages/confirm-send-token/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './confirm-send-token.container' diff --git a/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js b/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js deleted file mode 100644 index 7f1fb4e49..000000000 --- a/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.component.js +++ /dev/null @@ -1,119 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import ConfirmTransactionBase from '../confirm-transaction-base' -import UserPreferencedCurrencyDisplay from '../../user-preferenced-currency-display' -import { - formatCurrency, - convertTokenToFiat, - addFiat, - roundExponential, -} from '../../../helpers/confirm-transaction/util' -import { getWeiHexFromDecimalValue } from '../../../helpers/conversions.util' -import { ETH, PRIMARY } from '../../../constants/common' - -export default class ConfirmTokenTransactionBase extends Component { - static contextTypes = { - t: PropTypes.func, - } - - static propTypes = { - tokenAddress: PropTypes.string, - toAddress: PropTypes.string, - tokenAmount: PropTypes.number, - tokenSymbol: PropTypes.string, - fiatTransactionTotal: PropTypes.string, - ethTransactionTotal: PropTypes.string, - contractExchangeRate: PropTypes.number, - conversionRate: PropTypes.number, - currentCurrency: PropTypes.string, - } - - getFiatTransactionAmount () { - const { tokenAmount, currentCurrency, conversionRate, contractExchangeRate } = this.props - - return convertTokenToFiat({ - value: tokenAmount, - toCurrency: currentCurrency, - conversionRate, - contractExchangeRate, - }) - } - - renderSubtitleComponent () { - const { contractExchangeRate, tokenAmount } = this.props - - const decimalEthValue = (tokenAmount * contractExchangeRate) || 0 - const hexWeiValue = getWeiHexFromDecimalValue({ - value: decimalEthValue, - fromCurrency: ETH, - fromDenomination: ETH, - }) - - return typeof contractExchangeRate === 'undefined' - ? ( - <span> - { this.context.t('noConversionRateAvailable') } - </span> - ) : ( - <UserPreferencedCurrencyDisplay - value={hexWeiValue} - type={PRIMARY} - showEthLogo - hideLabel - /> - ) - } - - renderPrimaryTotalTextOverride () { - const { tokenAmount, tokenSymbol, ethTransactionTotal } = this.props - const tokensText = `${tokenAmount} ${tokenSymbol}` - - return ( - <div> - <span>{ `${tokensText} + ` }</span> - <img - src="/images/eth.svg" - height="18" - /> - <span>{ ethTransactionTotal }</span> - </div> - ) - } - - getSecondaryTotalTextOverride () { - const { fiatTransactionTotal, currentCurrency, contractExchangeRate } = this.props - - if (typeof contractExchangeRate === 'undefined') { - return formatCurrency(fiatTransactionTotal, currentCurrency) - } else { - const fiatTransactionAmount = this.getFiatTransactionAmount() - const fiatTotal = addFiat(fiatTransactionAmount, fiatTransactionTotal) - const roundedFiatTotal = roundExponential(fiatTotal) - return formatCurrency(roundedFiatTotal, currentCurrency) - } - } - - render () { - const { - toAddress, - tokenAddress, - tokenSymbol, - tokenAmount, - ...restProps - } = this.props - - const tokensText = `${tokenAmount} ${tokenSymbol}` - - return ( - <ConfirmTransactionBase - toAddress={toAddress} - identiconAddress={tokenAddress} - title={tokensText} - subtitleComponent={this.renderSubtitleComponent()} - primaryTotalTextOverride={this.renderPrimaryTotalTextOverride()} - secondaryTotalTextOverride={this.getSecondaryTotalTextOverride()} - {...restProps} - /> - ) - } -} diff --git a/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js b/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js deleted file mode 100644 index be38acdb0..000000000 --- a/ui/app/components/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js +++ /dev/null @@ -1,34 +0,0 @@ -import { connect } from 'react-redux' -import ConfirmTokenTransactionBase from './confirm-token-transaction-base.component' -import { - tokenAmountAndToAddressSelector, - contractExchangeRateSelector, -} from '../../../selectors/confirm-transaction' - -const mapStateToProps = (state, ownProps) => { - const { tokenAmount: ownTokenAmount } = ownProps - const { confirmTransaction, metamask: { currentCurrency, conversionRate } } = state - const { - txData: { txParams: { to: tokenAddress } = {} } = {}, - tokenProps: { tokenSymbol } = {}, - fiatTransactionTotal, - ethTransactionTotal, - } = confirmTransaction - - const { tokenAmount, toAddress } = tokenAmountAndToAddressSelector(state) - const contractExchangeRate = contractExchangeRateSelector(state) - - return { - toAddress, - tokenAddress, - tokenAmount: typeof ownTokenAmount !== 'undefined' ? ownTokenAmount : tokenAmount, - tokenSymbol, - currentCurrency, - conversionRate, - contractExchangeRate, - fiatTransactionTotal, - ethTransactionTotal, - } -} - -export default connect(mapStateToProps)(ConfirmTokenTransactionBase) diff --git a/ui/app/components/pages/confirm-token-transaction-base/index.js b/ui/app/components/pages/confirm-token-transaction-base/index.js deleted file mode 100644 index e15c5d56b..000000000 --- a/ui/app/components/pages/confirm-token-transaction-base/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from './confirm-token-transaction-base.container' -export { default as ConfirmTokenTransactionBase } from './confirm-token-transaction-base.component' diff --git a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js deleted file mode 100644 index 8b101b1ba..000000000 --- a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js +++ /dev/null @@ -1,574 +0,0 @@ -import ethUtil from 'ethereumjs-util' -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import ConfirmPageContainer, { ConfirmDetailRow } from '../../confirm-page-container' -import { isBalanceSufficient } from '../../send/send.utils' -import { DEFAULT_ROUTE, CONFIRM_TRANSACTION_ROUTE } from '../../../routes' -import { - INSUFFICIENT_FUNDS_ERROR_KEY, - TRANSACTION_ERROR_KEY, -} from '../../../constants/error-keys' -import { CONFIRMED_STATUS, DROPPED_STATUS } from '../../../constants/transactions' -import UserPreferencedCurrencyDisplay from '../../user-preferenced-currency-display' -import { PRIMARY, SECONDARY } from '../../../constants/common' -import AdvancedGasInputs from '../../gas-customization/advanced-gas-inputs' - -export default class ConfirmTransactionBase extends Component { - static contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, - } - - static propTypes = { - // react-router props - match: PropTypes.object, - history: PropTypes.object, - // Redux props - balance: PropTypes.string, - cancelTransaction: PropTypes.func, - cancelAllTransactions: PropTypes.func, - clearConfirmTransaction: PropTypes.func, - clearSend: PropTypes.func, - conversionRate: PropTypes.number, - currentCurrency: PropTypes.string, - editTransaction: PropTypes.func, - ethTransactionAmount: PropTypes.string, - ethTransactionFee: PropTypes.string, - ethTransactionTotal: PropTypes.string, - fiatTransactionAmount: PropTypes.string, - fiatTransactionFee: PropTypes.string, - fiatTransactionTotal: PropTypes.string, - fromAddress: PropTypes.string, - fromName: PropTypes.string, - hexTransactionAmount: PropTypes.string, - hexTransactionFee: PropTypes.string, - hexTransactionTotal: PropTypes.string, - isTxReprice: PropTypes.bool, - methodData: PropTypes.object, - nonce: PropTypes.string, - assetImage: PropTypes.string, - sendTransaction: PropTypes.func, - showCustomizeGasModal: PropTypes.func, - showTransactionConfirmedModal: PropTypes.func, - showRejectTransactionsConfirmationModal: PropTypes.func, - toAddress: PropTypes.string, - tokenData: PropTypes.object, - tokenProps: PropTypes.object, - toName: PropTypes.string, - transactionStatus: PropTypes.string, - txData: PropTypes.object, - unapprovedTxCount: PropTypes.number, - currentNetworkUnapprovedTxs: PropTypes.object, - updateGasAndCalculate: PropTypes.func, - customGas: PropTypes.object, - // Component props - action: PropTypes.string, - contentComponent: PropTypes.node, - dataComponent: PropTypes.node, - detailsComponent: PropTypes.node, - errorKey: PropTypes.string, - errorMessage: PropTypes.string, - primaryTotalTextOverride: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), - secondaryTotalTextOverride: PropTypes.string, - hideData: PropTypes.bool, - hideDetails: PropTypes.bool, - hideSubtitle: PropTypes.bool, - identiconAddress: PropTypes.string, - onCancel: PropTypes.func, - onEdit: PropTypes.func, - onEditGas: PropTypes.func, - onSubmit: PropTypes.func, - setMetaMetricsSendCount: PropTypes.func, - metaMetricsSendCount: PropTypes.number, - subtitle: PropTypes.string, - subtitleComponent: PropTypes.node, - summaryComponent: PropTypes.node, - title: PropTypes.string, - titleComponent: PropTypes.node, - valid: PropTypes.bool, - warning: PropTypes.string, - advancedInlineGasShown: PropTypes.bool, - insufficientBalance: PropTypes.bool, - hideFiatConversion: PropTypes.bool, - } - - state = { - submitting: false, - submitError: null, - } - - componentDidUpdate () { - const { - transactionStatus, - showTransactionConfirmedModal, - history, - clearConfirmTransaction, - } = this.props - - if (transactionStatus === DROPPED_STATUS || transactionStatus === CONFIRMED_STATUS) { - showTransactionConfirmedModal({ - onSubmit: () => { - clearConfirmTransaction() - history.push(DEFAULT_ROUTE) - }, - }) - - return - } - } - - getErrorKey () { - const { - balance, - conversionRate, - hexTransactionFee, - txData: { - simulationFails, - txParams: { - value: amount, - } = {}, - } = {}, - } = this.props - - const insufficientBalance = balance && !isBalanceSufficient({ - amount, - gasTotal: hexTransactionFee || '0x0', - balance, - conversionRate, - }) - - if (insufficientBalance) { - return { - valid: false, - errorKey: INSUFFICIENT_FUNDS_ERROR_KEY, - } - } - - if (simulationFails) { - return { - valid: true, - errorKey: simulationFails.errorKey ? simulationFails.errorKey : TRANSACTION_ERROR_KEY, - } - } - - return { - valid: true, - } - } - - handleEditGas () { - const { onEditGas, showCustomizeGasModal, action, txData: { origin }, methodData = {} } = this.props - - this.context.metricsEvent({ - eventOpts: { - category: 'Transactions', - action: 'Confirm Screen', - name: 'User clicks "Edit" on gas', - }, - customVariables: { - recipientKnown: null, - functionType: action || getMethodName(methodData.name) || this.context.t('contractInteraction'), - origin, - }, - }) - - if (onEditGas) { - onEditGas() - } else { - showCustomizeGasModal() - } - } - - renderDetails () { - const { - detailsComponent, - primaryTotalTextOverride, - secondaryTotalTextOverride, - hexTransactionFee, - hexTransactionTotal, - hideDetails, - advancedInlineGasShown, - customGas, - insufficientBalance, - updateGasAndCalculate, - hideFiatConversion, - } = this.props - - if (hideDetails) { - return null - } - - return ( - detailsComponent || ( - <div className="confirm-page-container-content__details"> - <div className="confirm-page-container-content__gas-fee"> - <ConfirmDetailRow - label="Gas Fee" - value={hexTransactionFee} - headerText="Edit" - headerTextClassName="confirm-detail-row__header-text--edit" - onHeaderClick={() => this.handleEditGas()} - secondaryText={hideFiatConversion ? this.context.t('noConversionRateAvailable') : ''} - /> - {advancedInlineGasShown - ? <AdvancedGasInputs - updateCustomGasPrice={newGasPrice => updateGasAndCalculate({ ...customGas, gasPrice: newGasPrice })} - updateCustomGasLimit={newGasLimit => updateGasAndCalculate({ ...customGas, gasLimit: newGasLimit })} - customGasPrice={customGas.gasPrice} - customGasLimit={customGas.gasLimit} - insufficientBalance={insufficientBalance} - customPriceIsSafe={true} - isSpeedUp={false} - /> - : null - } - </div> - <div> - <ConfirmDetailRow - label="Total" - value={hexTransactionTotal} - primaryText={primaryTotalTextOverride} - secondaryText={hideFiatConversion ? this.context.t('noConversionRateAvailable') : secondaryTotalTextOverride} - headerText="Amount + Gas Fee" - headerTextClassName="confirm-detail-row__header-text--total" - primaryValueTextColor="#2f9ae0" - /> - </div> - </div> - ) - ) - } - - renderData () { - const { t } = this.context - const { - txData: { - txParams: { - data, - } = {}, - } = {}, - methodData: { - name, - params, - } = {}, - hideData, - dataComponent, - } = this.props - - if (hideData) { - return null - } - - return dataComponent || ( - <div className="confirm-page-container-content__data"> - <div className="confirm-page-container-content__data-box-label"> - {`${t('functionType')}:`} - <span className="confirm-page-container-content__function-type"> - { name || t('notFound') } - </span> - </div> - { - params && ( - <div className="confirm-page-container-content__data-box"> - <div className="confirm-page-container-content__data-field-label"> - { `${t('parameters')}:` } - </div> - <div> - <pre>{ JSON.stringify(params, null, 2) }</pre> - </div> - </div> - ) - } - <div className="confirm-page-container-content__data-box-label"> - {`${t('hexData')}: ${ethUtil.toBuffer(data).length} bytes`} - </div> - <div className="confirm-page-container-content__data-box"> - { data } - </div> - </div> - ) - } - - handleEdit () { - const { txData, tokenData, tokenProps, onEdit, action, txData: { origin }, methodData = {} } = this.props - - this.context.metricsEvent({ - eventOpts: { - category: 'Transactions', - action: 'Confirm Screen', - name: 'Edit Transaction', - }, - customVariables: { - recipientKnown: null, - functionType: action || getMethodName(methodData.name) || this.context.t('contractInteraction'), - origin, - }, - }) - - onEdit({ txData, tokenData, tokenProps }) - } - - handleCancelAll () { - const { - cancelAllTransactions, - clearConfirmTransaction, - history, - showRejectTransactionsConfirmationModal, - unapprovedTxCount, - } = this.props - - showRejectTransactionsConfirmationModal({ - unapprovedTxCount, - async onSubmit () { - await cancelAllTransactions() - clearConfirmTransaction() - history.push(DEFAULT_ROUTE) - }, - }) - } - - handleCancel () { - const { metricsEvent } = this.context - const { onCancel, txData, cancelTransaction, history, clearConfirmTransaction, action, txData: { origin }, methodData = {} } = this.props - - if (onCancel) { - metricsEvent({ - eventOpts: { - category: 'Transactions', - action: 'Confirm Screen', - name: 'Cancel', - }, - customVariables: { - recipientKnown: null, - functionType: action || getMethodName(methodData.name) || this.context.t('contractInteraction'), - origin, - }, - }) - onCancel(txData) - } else { - cancelTransaction(txData) - .then(() => { - clearConfirmTransaction() - history.push(DEFAULT_ROUTE) - }) - } - } - - handleSubmit () { - const { metricsEvent } = this.context - const { txData: { origin }, sendTransaction, clearConfirmTransaction, txData, history, onSubmit, action, metaMetricsSendCount = 0, setMetaMetricsSendCount, methodData = {} } = this.props - const { submitting } = this.state - - if (submitting) { - return - } - - this.setState({ - submitting: true, - submitError: null, - }, () => { - metricsEvent({ - eventOpts: { - category: 'Transactions', - action: 'Confirm Screen', - name: 'Transaction Completed', - }, - customVariables: { - recipientKnown: null, - functionType: action || getMethodName(methodData.name) || this.context.t('contractInteraction'), - origin, - }, - }) - - setMetaMetricsSendCount(metaMetricsSendCount + 1) - .then(() => { - if (onSubmit) { - Promise.resolve(onSubmit(txData)) - .then(() => { - this.setState({ - submitting: false, - }) - }) - } else { - sendTransaction(txData) - .then(() => { - clearConfirmTransaction() - this.setState({ - submitting: false, - }, () => { - history.push(DEFAULT_ROUTE) - }) - }) - .catch(error => { - this.setState({ - submitting: false, - submitError: error.message, - }) - }) - } - }) - }) - } - - renderTitleComponent () { - const { title, titleComponent, hexTransactionAmount } = this.props - - // Title string passed in by props takes priority - if (title) { - return null - } - - return titleComponent || ( - <UserPreferencedCurrencyDisplay - value={hexTransactionAmount} - type={PRIMARY} - showEthLogo - ethLogoHeight="26" - hideLabel - /> - ) - } - - renderSubtitleComponent () { - const { subtitle, subtitleComponent, hexTransactionAmount } = this.props - - // Subtitle string passed in by props takes priority - if (subtitle) { - return null - } - - return subtitleComponent || ( - <UserPreferencedCurrencyDisplay - value={hexTransactionAmount} - type={SECONDARY} - showEthLogo - hideLabel - /> - ) - } - - handleNextTx (txId) { - const { history, clearConfirmTransaction } = this.props - if (txId) { - clearConfirmTransaction() - history.push(`${CONFIRM_TRANSACTION_ROUTE}/${txId}`) - } - } - - getNavigateTxData () { - const { currentNetworkUnapprovedTxs, txData: { id } = {} } = this.props - const enumUnapprovedTxs = Object.keys(currentNetworkUnapprovedTxs).reverse() - const currentPosition = enumUnapprovedTxs.indexOf(id.toString()) - - return { - totalTx: enumUnapprovedTxs.length, - positionOfCurrentTx: currentPosition + 1, - nextTxId: enumUnapprovedTxs[currentPosition + 1], - prevTxId: enumUnapprovedTxs[currentPosition - 1], - showNavigation: enumUnapprovedTxs.length > 1, - firstTx: enumUnapprovedTxs[0], - lastTx: enumUnapprovedTxs[enumUnapprovedTxs.length - 1], - ofText: this.context.t('ofTextNofM'), - requestsWaitingText: this.context.t('requestsAwaitingAcknowledgement'), - } - } - - componentDidMount () { - const { txData: { origin } = {} } = this.props - const { metricsEvent } = this.context - metricsEvent({ - eventOpts: { - category: 'Transactions', - action: 'Confirm Screen', - name: 'Confirm: Started', - }, - customVariables: { - origin, - }, - }) - } - - render () { - const { - isTxReprice, - fromName, - fromAddress, - toName, - toAddress, - methodData, - valid: propsValid = true, - errorMessage, - errorKey: propsErrorKey, - action, - title, - subtitle, - hideSubtitle, - identiconAddress, - summaryComponent, - contentComponent, - onEdit, - nonce, - assetImage, - warning, - unapprovedTxCount, - } = this.props - const { submitting, submitError } = this.state - - const { name } = methodData - const { valid, errorKey } = this.getErrorKey() - const { totalTx, positionOfCurrentTx, nextTxId, prevTxId, showNavigation, firstTx, lastTx, ofText, requestsWaitingText } = this.getNavigateTxData() - - return ( - <ConfirmPageContainer - fromName={fromName} - fromAddress={fromAddress} - toName={toName} - toAddress={toAddress} - showEdit={onEdit && !isTxReprice} - action={action || getMethodName(name) || this.context.t('contractInteraction')} - title={title} - titleComponent={this.renderTitleComponent()} - subtitle={subtitle} - subtitleComponent={this.renderSubtitleComponent()} - hideSubtitle={hideSubtitle} - summaryComponent={summaryComponent} - detailsComponent={this.renderDetails()} - dataComponent={this.renderData()} - contentComponent={contentComponent} - nonce={nonce} - unapprovedTxCount={unapprovedTxCount} - assetImage={assetImage} - identiconAddress={identiconAddress} - errorMessage={errorMessage || submitError} - errorKey={propsErrorKey || errorKey} - warning={warning} - totalTx={totalTx} - positionOfCurrentTx={positionOfCurrentTx} - nextTxId={nextTxId} - prevTxId={prevTxId} - showNavigation={showNavigation} - onNextTx={(txId) => this.handleNextTx(txId)} - firstTx={firstTx} - lastTx={lastTx} - ofText={ofText} - requestsWaitingText={requestsWaitingText} - disabled={!propsValid || !valid || submitting} - onEdit={() => this.handleEdit()} - onCancelAll={() => this.handleCancelAll()} - onCancel={() => this.handleCancel()} - onSubmit={() => this.handleSubmit()} - /> - ) - } -} - -export function getMethodName (camelCase) { - if (!camelCase || typeof camelCase !== 'string') { - return '' - } - - return camelCase - .replace(/([a-z])([A-Z])/g, '$1 $2') - .replace(/([A-Z])([a-z])/g, ' $1$2') - .replace(/ +/g, ' ') -} diff --git a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js deleted file mode 100644 index 22f509905..000000000 --- a/ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js +++ /dev/null @@ -1,242 +0,0 @@ -import { connect } from 'react-redux' -import { compose } from 'recompose' -import { withRouter } from 'react-router-dom' -import R from 'ramda' -import contractMap from 'eth-contract-metadata' -import ConfirmTransactionBase from './confirm-transaction-base.component' -import { - clearConfirmTransaction, - updateGasAndCalculate, -} from '../../../ducks/confirm-transaction.duck' -import { clearSend, cancelTx, cancelTxs, updateAndApproveTx, showModal, setMetaMetricsSendCount } from '../../../actions' -import { - INSUFFICIENT_FUNDS_ERROR_KEY, - GAS_LIMIT_TOO_LOW_ERROR_KEY, -} from '../../../constants/error-keys' -import { getHexGasTotal } from '../../../helpers/confirm-transaction/util' -import { isBalanceSufficient, calcGasTotal } from '../../send/send.utils' -import { conversionGreaterThan } from '../../../conversion-util' -import { MIN_GAS_LIMIT_DEC } from '../../send/send.constants' -import { checksumAddress, addressSlicer, valuesFor } from '../../../util' -import {getMetaMaskAccounts, getAdvancedInlineGasShown, preferencesSelector, getIsMainnet} from '../../../selectors' - -const casedContractMap = Object.keys(contractMap).reduce((acc, base) => { - return { - ...acc, - [base.toLowerCase()]: contractMap[base], - } -}, {}) - -const mapStateToProps = (state, props) => { - const { toAddress: propsToAddress } = props - const { showFiatInTestnets } = preferencesSelector(state) - const isMainnet = getIsMainnet(state) - const { confirmTransaction, metamask, gas } = state - const { - ethTransactionAmount, - ethTransactionFee, - ethTransactionTotal, - fiatTransactionAmount, - fiatTransactionFee, - fiatTransactionTotal, - hexTransactionAmount, - hexTransactionFee, - hexTransactionTotal, - tokenData, - methodData, - txData, - tokenProps, - nonce, - } = confirmTransaction - const { txParams = {}, lastGasPrice, id: transactionId } = txData - const { - from: fromAddress, - to: txParamsToAddress, - gasPrice, - gas: gasLimit, - value: amount, - } = txParams - const accounts = getMetaMaskAccounts(state) - const { - conversionRate, - identities, - currentCurrency, - selectedAddress, - selectedAddressTxList, - assetImages, - network, - unapprovedTxs, - metaMetricsSendCount, - } = metamask - const assetImage = assetImages[txParamsToAddress] - - const { - customGasLimit, - customGasPrice, - } = gas - - const { balance } = accounts[selectedAddress] - const { name: fromName } = identities[selectedAddress] - const toAddress = propsToAddress || txParamsToAddress - const toName = identities[toAddress] - ? identities[toAddress].name - : ( - casedContractMap[toAddress] - ? casedContractMap[toAddress].name - : addressSlicer(checksumAddress(toAddress)) - ) - - const isTxReprice = Boolean(lastGasPrice) - - const transaction = R.find(({ id }) => id === transactionId)(selectedAddressTxList) - const transactionStatus = transaction ? transaction.status : '' - - const currentNetworkUnapprovedTxs = R.filter( - ({ metamaskNetworkId }) => metamaskNetworkId === network, - unapprovedTxs, - ) - const unapprovedTxCount = valuesFor(currentNetworkUnapprovedTxs).length - - const insufficientBalance = !isBalanceSufficient({ - amount, - gasTotal: calcGasTotal(gasLimit, gasPrice), - balance, - conversionRate, - }) - - return { - balance, - fromAddress, - fromName, - toAddress, - toName, - ethTransactionAmount, - ethTransactionFee, - ethTransactionTotal, - fiatTransactionAmount, - fiatTransactionFee, - fiatTransactionTotal, - hexTransactionAmount, - hexTransactionFee, - hexTransactionTotal, - txData, - tokenData, - methodData, - tokenProps, - isTxReprice, - currentCurrency, - conversionRate, - transactionStatus, - nonce, - assetImage, - unapprovedTxs, - unapprovedTxCount, - currentNetworkUnapprovedTxs, - customGas: { - gasLimit: customGasLimit || gasLimit, - gasPrice: customGasPrice || gasPrice, - }, - advancedInlineGasShown: getAdvancedInlineGasShown(state), - insufficientBalance, - hideSubtitle: (!isMainnet && !showFiatInTestnets), - hideFiatConversion: (!isMainnet && !showFiatInTestnets), - metaMetricsSendCount, - } -} - -const mapDispatchToProps = dispatch => { - return { - clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), - clearSend: () => dispatch(clearSend()), - showTransactionConfirmedModal: ({ onSubmit }) => { - return dispatch(showModal({ name: 'TRANSACTION_CONFIRMED', onSubmit })) - }, - showCustomizeGasModal: ({ txData, onSubmit, validate }) => { - return dispatch(showModal({ name: 'CUSTOMIZE_GAS', txData, onSubmit, validate })) - }, - updateGasAndCalculate: ({ gasLimit, gasPrice }) => { - return dispatch(updateGasAndCalculate({ gasLimit, gasPrice })) - }, - showRejectTransactionsConfirmationModal: ({ onSubmit, unapprovedTxCount }) => { - return dispatch(showModal({ name: 'REJECT_TRANSACTIONS', onSubmit, unapprovedTxCount })) - }, - cancelTransaction: ({ id }) => dispatch(cancelTx({ id })), - cancelAllTransactions: (txList) => dispatch(cancelTxs(txList)), - sendTransaction: txData => dispatch(updateAndApproveTx(txData)), - setMetaMetricsSendCount: val => dispatch(setMetaMetricsSendCount(val)), - } -} - -const getValidateEditGas = ({ balance, conversionRate, txData }) => { - const { txParams: { value: amount } = {} } = txData - - return ({ gasLimit, gasPrice }) => { - const gasTotal = getHexGasTotal({ gasLimit, gasPrice }) - const hasSufficientBalance = isBalanceSufficient({ - amount, - gasTotal, - balance, - conversionRate, - }) - - if (!hasSufficientBalance) { - return { - valid: false, - errorKey: INSUFFICIENT_FUNDS_ERROR_KEY, - } - } - - const gasLimitTooLow = gasLimit && conversionGreaterThan( - { - value: MIN_GAS_LIMIT_DEC, - fromNumericBase: 'dec', - conversionRate, - }, - { - value: gasLimit, - fromNumericBase: 'hex', - }, - ) - - if (gasLimitTooLow) { - return { - valid: false, - errorKey: GAS_LIMIT_TOO_LOW_ERROR_KEY, - } - } - - return { - valid: true, - } - } -} - -const mergeProps = (stateProps, dispatchProps, ownProps) => { - const { balance, conversionRate, txData, unapprovedTxs } = stateProps - const { - cancelAllTransactions: dispatchCancelAllTransactions, - showCustomizeGasModal: dispatchShowCustomizeGasModal, - updateGasAndCalculate: dispatchUpdateGasAndCalculate, - ...otherDispatchProps - } = dispatchProps - - const validateEditGas = getValidateEditGas({ balance, conversionRate, txData }) - - return { - ...stateProps, - ...otherDispatchProps, - ...ownProps, - showCustomizeGasModal: () => dispatchShowCustomizeGasModal({ - txData, - onSubmit: customGas => dispatchUpdateGasAndCalculate(customGas), - validate: validateEditGas, - }), - cancelAllTransactions: () => dispatchCancelAllTransactions(valuesFor(unapprovedTxs)), - updateGasAndCalculate: dispatchUpdateGasAndCalculate, - } -} - -export default compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps, mergeProps) -)(ConfirmTransactionBase) diff --git a/ui/app/components/pages/confirm-transaction-base/index.js b/ui/app/components/pages/confirm-transaction-base/index.js deleted file mode 100644 index 9996e9aeb..000000000 --- a/ui/app/components/pages/confirm-transaction-base/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './confirm-transaction-base.container' diff --git a/ui/app/components/pages/confirm-transaction-base/tests/confirm-transaction-base.component.test.js b/ui/app/components/pages/confirm-transaction-base/tests/confirm-transaction-base.component.test.js deleted file mode 100644 index 8ca7ca4e7..000000000 --- a/ui/app/components/pages/confirm-transaction-base/tests/confirm-transaction-base.component.test.js +++ /dev/null @@ -1,14 +0,0 @@ -import assert from 'assert' -import { getMethodName } from '../confirm-transaction-base.component' - -describe('ConfirmTransactionBase Component', () => { - describe('getMethodName', () => { - it('should get correct method names', () => { - assert.equal(getMethodName(undefined), '') - assert.equal(getMethodName({}), '') - assert.equal(getMethodName('confirm'), 'confirm') - assert.equal(getMethodName('balanceOf'), 'balance Of') - assert.equal(getMethodName('ethToTokenSwapInput'), 'eth To Token Swap Input') - }) - }) -}) diff --git a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js deleted file mode 100644 index cf79b94bc..000000000 --- a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js +++ /dev/null @@ -1,92 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import { Redirect } from 'react-router-dom' -import Loading from '../../loading-screen' -import { - CONFIRM_TRANSACTION_ROUTE, - CONFIRM_DEPLOY_CONTRACT_PATH, - CONFIRM_SEND_ETHER_PATH, - CONFIRM_SEND_TOKEN_PATH, - CONFIRM_APPROVE_PATH, - CONFIRM_TRANSFER_FROM_PATH, - CONFIRM_TOKEN_METHOD_PATH, - SIGNATURE_REQUEST_PATH, -} from '../../../routes' -import { isConfirmDeployContract } from '../../../helpers/transactions.util' -import { - TOKEN_METHOD_TRANSFER, - TOKEN_METHOD_APPROVE, - TOKEN_METHOD_TRANSFER_FROM, -} from '../../../constants/transactions' - -export default class ConfirmTransactionSwitch extends Component { - static propTypes = { - txData: PropTypes.object, - methodData: PropTypes.object, - fetchingData: PropTypes.bool, - isEtherTransaction: PropTypes.bool, - } - - redirectToTransaction () { - const { - txData, - methodData: { name }, - fetchingData, - isEtherTransaction, - } = this.props - const { id, txParams: { data } = {} } = txData - - if (fetchingData) { - return <Loading /> - } - - if (isConfirmDeployContract(txData)) { - const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_DEPLOY_CONTRACT_PATH}` - return <Redirect to={{ pathname }} /> - } - - if (isEtherTransaction) { - const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_SEND_ETHER_PATH}` - return <Redirect to={{ pathname }} /> - } - - if (data) { - const methodName = name && name.toLowerCase() - - switch (methodName) { - case TOKEN_METHOD_TRANSFER: { - const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_SEND_TOKEN_PATH}` - return <Redirect to={{ pathname }} /> - } - case TOKEN_METHOD_APPROVE: { - const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_APPROVE_PATH}` - return <Redirect to={{ pathname }} /> - } - case TOKEN_METHOD_TRANSFER_FROM: { - const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_TRANSFER_FROM_PATH}` - return <Redirect to={{ pathname }} /> - } - default: { - const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_TOKEN_METHOD_PATH}` - return <Redirect to={{ pathname }} /> - } - } - } - - const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_SEND_ETHER_PATH}` - return <Redirect to={{ pathname }} /> - } - - render () { - const { txData } = this.props - - if (txData.txParams) { - return this.redirectToTransaction() - } else if (txData.msgParams) { - const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${txData.id}${SIGNATURE_REQUEST_PATH}` - return <Redirect to={{ pathname }} /> - } - - return <Loading /> - } -} diff --git a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.container.js b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.container.js deleted file mode 100644 index 7f2c36af2..000000000 --- a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.container.js +++ /dev/null @@ -1,22 +0,0 @@ -import { connect } from 'react-redux' -import ConfirmTransactionSwitch from './confirm-transaction-switch.component' - -const mapStateToProps = state => { - const { - confirmTransaction: { - txData, - methodData, - fetchingData, - toSmartContract, - }, - } = state - - return { - txData, - methodData, - fetchingData, - isEtherTransaction: !toSmartContract, - } -} - -export default connect(mapStateToProps)(ConfirmTransactionSwitch) diff --git a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.util.js b/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.util.js deleted file mode 100644 index 536aa5212..000000000 --- a/ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.util.js +++ /dev/null @@ -1,4 +0,0 @@ -export function isConfirmDeployContract (txData = {}) { - const { txParams = {} } = txData - return !txParams.to -} diff --git a/ui/app/components/pages/confirm-transaction-switch/index.js b/ui/app/components/pages/confirm-transaction-switch/index.js deleted file mode 100644 index c288acb1a..000000000 --- a/ui/app/components/pages/confirm-transaction-switch/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import ConfirmTransactionSwitch from './confirm-transaction-switch.container' -module.exports = ConfirmTransactionSwitch diff --git a/ui/app/components/pages/confirm-transaction/confirm-transaction.component.js b/ui/app/components/pages/confirm-transaction/confirm-transaction.component.js deleted file mode 100644 index 2e460f377..000000000 --- a/ui/app/components/pages/confirm-transaction/confirm-transaction.component.js +++ /dev/null @@ -1,160 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import { Switch, Route } from 'react-router-dom' -import Loading from '../../loading-screen' -import ConfirmTransactionSwitch from '../confirm-transaction-switch' -import ConfirmTransactionBase from '../confirm-transaction-base' -import ConfirmSendEther from '../confirm-send-ether' -import ConfirmSendToken from '../confirm-send-token' -import ConfirmDeployContract from '../confirm-deploy-contract' -import ConfirmApprove from '../confirm-approve' -import ConfirmTokenTransactionBase from '../confirm-token-transaction-base' -import ConfTx from '../../../conf-tx' -import { - DEFAULT_ROUTE, - CONFIRM_TRANSACTION_ROUTE, - CONFIRM_DEPLOY_CONTRACT_PATH, - CONFIRM_SEND_ETHER_PATH, - CONFIRM_SEND_TOKEN_PATH, - CONFIRM_APPROVE_PATH, - CONFIRM_TRANSFER_FROM_PATH, - CONFIRM_TOKEN_METHOD_PATH, - SIGNATURE_REQUEST_PATH, -} from '../../../routes' - -export default class ConfirmTransaction extends Component { - static propTypes = { - history: PropTypes.object.isRequired, - totalUnapprovedCount: PropTypes.number.isRequired, - match: PropTypes.object, - send: PropTypes.object, - unconfirmedTransactions: PropTypes.array, - setTransactionToConfirm: PropTypes.func, - confirmTransaction: PropTypes.object, - clearConfirmTransaction: PropTypes.func, - fetchBasicGasAndTimeEstimates: PropTypes.func, - } - - getParamsTransactionId () { - const { match: { params: { id } = {} } } = this.props - return id || null - } - - componentDidMount () { - const { - totalUnapprovedCount = 0, - send = {}, - history, - confirmTransaction: { txData: { id: transactionId } = {} }, - fetchBasicGasAndTimeEstimates, - } = this.props - - if (!totalUnapprovedCount && !send.to) { - history.replace(DEFAULT_ROUTE) - return - } - - if (!transactionId) { - fetchBasicGasAndTimeEstimates() - this.setTransactionToConfirm() - } - } - - componentDidUpdate () { - const { - setTransactionToConfirm, - confirmTransaction: { txData: { id: transactionId } = {} }, - clearConfirmTransaction, - } = this.props - const paramsTransactionId = this.getParamsTransactionId() - - if (paramsTransactionId && transactionId && paramsTransactionId !== transactionId + '') { - clearConfirmTransaction() - setTransactionToConfirm(paramsTransactionId) - return - } - - if (!transactionId) { - this.setTransactionToConfirm() - } - } - - setTransactionToConfirm () { - const { - history, - unconfirmedTransactions, - setTransactionToConfirm, - } = this.props - const paramsTransactionId = this.getParamsTransactionId() - - if (paramsTransactionId) { - // Check to make sure params ID is valid - const tx = unconfirmedTransactions.find(({ id }) => id + '' === paramsTransactionId) - - if (!tx) { - history.replace(DEFAULT_ROUTE) - } else { - setTransactionToConfirm(paramsTransactionId) - } - } else if (unconfirmedTransactions.length) { - const totalUnconfirmed = unconfirmedTransactions.length - const transaction = unconfirmedTransactions[totalUnconfirmed - 1] - const { id: transactionId, loadingDefaults } = transaction - - if (!loadingDefaults) { - setTransactionToConfirm(transactionId) - } - } - } - - render () { - const { confirmTransaction: { txData: { id } } = {} } = this.props - const paramsTransactionId = this.getParamsTransactionId() - - // Show routes when state.confirmTransaction has been set and when either the ID in the params - // isn't specified or is specified and matches the ID in state.confirmTransaction in order to - // support URLs of /confirm-transaction or /confirm-transaction/<transactionId> - return id && (!paramsTransactionId || paramsTransactionId === id + '') - ? ( - <Switch> - <Route - exact - path={`${CONFIRM_TRANSACTION_ROUTE}/:id?${CONFIRM_DEPLOY_CONTRACT_PATH}`} - component={ConfirmDeployContract} - /> - <Route - exact - path={`${CONFIRM_TRANSACTION_ROUTE}/:id?${CONFIRM_TOKEN_METHOD_PATH}`} - component={ConfirmTransactionBase} - /> - <Route - exact - path={`${CONFIRM_TRANSACTION_ROUTE}/:id?${CONFIRM_SEND_ETHER_PATH}`} - component={ConfirmSendEther} - /> - <Route - exact - path={`${CONFIRM_TRANSACTION_ROUTE}/:id?${CONFIRM_SEND_TOKEN_PATH}`} - component={ConfirmSendToken} - /> - <Route - exact - path={`${CONFIRM_TRANSACTION_ROUTE}/:id?${CONFIRM_APPROVE_PATH}`} - component={ConfirmApprove} - /> - <Route - exact - path={`${CONFIRM_TRANSACTION_ROUTE}/:id?${CONFIRM_TRANSFER_FROM_PATH}`} - component={ConfirmTokenTransactionBase} - /> - <Route - exact - path={`${CONFIRM_TRANSACTION_ROUTE}/:id?${SIGNATURE_REQUEST_PATH}`} - component={ConfTx} - /> - <Route path="*" component={ConfirmTransactionSwitch} /> - </Switch> - ) - : <Loading /> - } -} diff --git a/ui/app/components/pages/confirm-transaction/confirm-transaction.container.js b/ui/app/components/pages/confirm-transaction/confirm-transaction.container.js deleted file mode 100644 index 46342dc76..000000000 --- a/ui/app/components/pages/confirm-transaction/confirm-transaction.container.js +++ /dev/null @@ -1,37 +0,0 @@ -import { connect } from 'react-redux' -import { compose } from 'recompose' -import { withRouter } from 'react-router-dom' -import { - setTransactionToConfirm, - clearConfirmTransaction, -} from '../../../ducks/confirm-transaction.duck' -import { - fetchBasicGasAndTimeEstimates, -} from '../../../ducks/gas.duck' -import ConfirmTransaction from './confirm-transaction.component' -import { getTotalUnapprovedCount } from '../../../selectors' -import { unconfirmedTransactionsListSelector } from '../../../selectors/confirm-transaction' - -const mapStateToProps = state => { - const { metamask: { send }, confirmTransaction } = state - - return { - totalUnapprovedCount: getTotalUnapprovedCount(state), - send, - confirmTransaction, - unconfirmedTransactions: unconfirmedTransactionsListSelector(state), - } -} - -const mapDispatchToProps = dispatch => { - return { - setTransactionToConfirm: transactionId => dispatch(setTransactionToConfirm(transactionId)), - clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), - fetchBasicGasAndTimeEstimates: () => dispatch(fetchBasicGasAndTimeEstimates()), - } -} - -export default compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps), -)(ConfirmTransaction) diff --git a/ui/app/components/pages/confirm-transaction/index.js b/ui/app/components/pages/confirm-transaction/index.js deleted file mode 100644 index 4bf42d85c..000000000 --- a/ui/app/components/pages/confirm-transaction/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import ConfirmTransaction from './confirm-transaction.container' -module.exports = ConfirmTransaction diff --git a/ui/app/components/pages/create-account/connect-hardware/account-list.js b/ui/app/components/pages/create-account/connect-hardware/account-list.js deleted file mode 100644 index c63de234a..000000000 --- a/ui/app/components/pages/create-account/connect-hardware/account-list.js +++ /dev/null @@ -1,205 +0,0 @@ -const { Component } = require('react') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const genAccountLink = require('../../../../../lib/account-link.js') -const Select = require('react-select').default -import Button from '../../../button' - -class AccountList extends Component { - constructor (props, context) { - super(props) - } - - getHdPaths () { - return [ - { - label: `Ledger Live`, - value: `m/44'/60'/0'/0/0`, - }, - { - label: `Legacy (MEW / MyCrypto)`, - value: `m/44'/60'/0'`, - }, - ] - } - - goToNextPage = () => { - // If we have < 5 accounts, it's restricted by BIP-44 - if (this.props.accounts.length === 5) { - this.props.getPage(this.props.device, 1, this.props.selectedPath) - } else { - this.props.onAccountRestriction() - } - } - - goToPreviousPage = () => { - this.props.getPage(this.props.device, -1, this.props.selectedPath) - } - - renderHdPathSelector () { - const { onPathChange, selectedPath } = this.props - - const options = this.getHdPaths() - return h('div', [ - h('h3.hw-connect__hdPath__title', {}, this.context.t('selectHdPath')), - h('p.hw-connect__msg', {}, this.context.t('selectPathHelp')), - h('div.hw-connect__hdPath', [ - h(Select, { - className: 'hw-connect__hdPath__select', - name: 'hd-path-select', - clearable: false, - value: selectedPath, - options, - onChange: (opt) => { - onPathChange(opt.value) - }, - }), - ]), - ]) - } - - capitalizeDevice (device) { - return device.slice(0, 1).toUpperCase() + device.slice(1) - } - - renderHeader () { - const { device } = this.props - return ( - h('div.hw-connect', [ - - h('h3.hw-connect__unlock-title', {}, `${this.context.t('unlock')} ${this.capitalizeDevice(device)}`), - - device.toLowerCase() === 'ledger' ? this.renderHdPathSelector() : null, - - h('h3.hw-connect__hdPath__title', {}, this.context.t('selectAnAccount')), - h('p.hw-connect__msg', {}, this.context.t('selectAnAccountHelp')), - ]) - ) - } - - renderAccounts () { - return h('div.hw-account-list', [ - this.props.accounts.map((a, i) => { - - return h('div.hw-account-list__item', { key: a.address }, [ - h('div.hw-account-list__item__radio', [ - h('input', { - type: 'radio', - name: 'selectedAccount', - id: `address-${i}`, - value: a.index, - onChange: (e) => this.props.onAccountChange(e.target.value), - checked: this.props.selectedAccount === a.index.toString(), - }), - h( - 'label.hw-account-list__item__label', - { - htmlFor: `address-${i}`, - }, - [ - h('span.hw-account-list__item__index', a.index + 1), - `${a.address.slice(0, 4)}...${a.address.slice(-4)}`, - h('span.hw-account-list__item__balance', `${a.balance}`), - ]), - ]), - h( - 'a.hw-account-list__item__link', - { - href: genAccountLink(a.address, this.props.network), - target: '_blank', - title: this.context.t('etherscanView'), - }, - h('img', { src: 'images/popout.svg' }) - ), - ]) - }), - ]) - } - - renderPagination () { - return h('div.hw-list-pagination', [ - h( - 'button.hw-list-pagination__button', - { - onClick: this.goToPreviousPage, - }, - `< ${this.context.t('prev')}` - ), - - h( - 'button.hw-list-pagination__button', - { - onClick: this.goToNextPage, - }, - `${this.context.t('next')} >` - ), - ]) - } - - renderButtons () { - const disabled = this.props.selectedAccount === null - const buttonProps = {} - if (disabled) { - buttonProps.disabled = true - } - - return h('div.new-account-connect-form__buttons', {}, [ - h(Button, { - type: 'default', - large: true, - className: 'new-account-connect-form__button', - onClick: this.props.onCancel.bind(this), - }, [this.context.t('cancel')]), - - h(Button, { - type: 'confirm', - large: true, - className: 'new-account-connect-form__button unlock', - disabled, - onClick: this.props.onUnlockAccount.bind(this, this.props.device), - }, [this.context.t('unlock')]), - ]) - } - - renderForgetDevice () { - return h('div.hw-forget-device-container', {}, [ - h('a', { - onClick: this.props.onForgetDevice.bind(this, this.props.device), - }, this.context.t('forgetDevice')), - ]) - } - - render () { - return h('div.new-account-connect-form.account-list', {}, [ - this.renderHeader(), - this.renderAccounts(), - this.renderPagination(), - this.renderButtons(), - this.renderForgetDevice(), - ]) - } - -} - - -AccountList.propTypes = { - onPathChange: PropTypes.func.isRequired, - selectedPath: PropTypes.string.isRequired, - device: PropTypes.string.isRequired, - accounts: PropTypes.array.isRequired, - onAccountChange: PropTypes.func.isRequired, - onForgetDevice: PropTypes.func.isRequired, - getPage: PropTypes.func.isRequired, - network: PropTypes.string, - selectedAccount: PropTypes.string, - history: PropTypes.object, - onUnlockAccount: PropTypes.func, - onCancel: PropTypes.func, - onAccountRestriction: PropTypes.func, -} - -AccountList.contextTypes = { - t: PropTypes.func, -} - -module.exports = AccountList diff --git a/ui/app/components/pages/create-account/connect-hardware/connect-screen.js b/ui/app/components/pages/create-account/connect-hardware/connect-screen.js deleted file mode 100644 index 49a5610c1..000000000 --- a/ui/app/components/pages/create-account/connect-hardware/connect-screen.js +++ /dev/null @@ -1,197 +0,0 @@ -const { Component } = require('react') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -import Button from '../../../button' - -class ConnectScreen extends Component { - constructor (props, context) { - super(props) - this.state = { - selectedDevice: null, - } - } - - connect = () => { - if (this.state.selectedDevice) { - this.props.connectToHardwareWallet(this.state.selectedDevice) - } - return null - } - - renderConnectToTrezorButton () { - return h( - `button.hw-connect__btn${this.state.selectedDevice === 'trezor' ? '.selected' : ''}`, - { onClick: _ => this.setState({selectedDevice: 'trezor'}) }, - h('img.hw-connect__btn__img', { - src: 'images/trezor-logo.svg', - }) - ) - } - - renderConnectToLedgerButton () { - return h( - `button.hw-connect__btn${this.state.selectedDevice === 'ledger' ? '.selected' : ''}`, - { onClick: _ => this.setState({selectedDevice: 'ledger'}) }, - h('img.hw-connect__btn__img', { - src: 'images/ledger-logo.svg', - }) - ) - } - - renderButtons () { - return ( - h('div', {}, [ - h('div.hw-connect__btn-wrapper', {}, [ - this.renderConnectToLedgerButton(), - this.renderConnectToTrezorButton(), - ]), - h(Button, { - type: 'confirm', - large: true, - className: 'hw-connect__connect-btn', - onClick: this.connect, - disabled: !this.state.selectedDevice, - }, this.context.t('connect')), - ]) - ) - } - - renderUnsupportedBrowser () { - return ( - h('div.new-account-connect-form.unsupported-browser', {}, [ - h('div.hw-connect', [ - h('h3.hw-connect__title', {}, this.context.t('browserNotSupported')), - h('p.hw-connect__msg', {}, this.context.t('chromeRequiredForHardwareWallets')), - ]), - h(Button, { - type: 'primary', - large: true, - onClick: () => global.platform.openWindow({ - url: 'https://google.com/chrome', - }), - }, this.context.t('downloadGoogleChrome')), - ]) - ) - } - - renderHeader () { - return ( - h('div.hw-connect__header', {}, [ - h('h3.hw-connect__header__title', {}, this.context.t(`hardwareWallets`)), - h('p.hw-connect__header__msg', {}, this.context.t(`hardwareWalletsMsg`)), - ]) - ) - } - - getAffiliateLinks () { - const links = { - trezor: `<a class='hw-connect__get-hw__link' href='https://shop.trezor.io/?a=metamask' target='_blank'>Trezor</a>`, - ledger: `<a class='hw-connect__get-hw__link' href='https://www.ledger.com/products/ledger-nano-s?r=17c4991a03fa&tracker=MY_TRACKER' target='_blank'>Ledger</a>`, - } - - const text = this.context.t('orderOneHere') - const response = text.replace('Trezor', links.trezor).replace('Ledger', links.ledger) - - return h('div.hw-connect__get-hw__msg', { dangerouslySetInnerHTML: {__html: response }}) - } - - renderTrezorAffiliateLink () { - return h('div.hw-connect__get-hw', {}, [ - h('p.hw-connect__get-hw__msg', {}, this.context.t(`dontHaveAHardwareWallet`)), - this.getAffiliateLinks(), - ]) - } - - - scrollToTutorial = (e) => { - if (this.referenceNode) this.referenceNode.scrollIntoView({behavior: 'smooth'}) - } - - renderLearnMore () { - return ( - h('p.hw-connect__learn-more', { - onClick: this.scrollToTutorial, - }, [ - this.context.t('learnMore'), - h('img.hw-connect__learn-more__arrow', { src: 'images/caret-right.svg'}), - ]) - ) - } - - renderTutorialSteps () { - const steps = [ - { - asset: 'hardware-wallet-step-1', - dimensions: {width: '225px', height: '75px'}, - }, - { - asset: 'hardware-wallet-step-2', - dimensions: {width: '300px', height: '100px'}, - }, - { - asset: 'hardware-wallet-step-3', - dimensions: {width: '120px', height: '90px'}, - }, - ] - - return h('.hw-tutorial', { - ref: node => { this.referenceNode = node }, - }, - steps.map((step, i) => ( - h('div.hw-connect', {}, [ - h('h3.hw-connect__title', {}, this.context.t(`step${i + 1}HardwareWallet`)), - h('p.hw-connect__msg', {}, this.context.t(`step${i + 1}HardwareWalletMsg`)), - h('img.hw-connect__step-asset', { src: `images/${step.asset}.svg`, ...step.dimensions }), - ]) - )) - ) - } - - renderFooter () { - return ( - h('div.hw-connect__footer', {}, [ - h('h3.hw-connect__footer__title', {}, this.context.t(`readyToConnect`)), - this.renderButtons(), - h('p.hw-connect__footer__msg', {}, [ - this.context.t(`havingTroubleConnecting`), - h('a.hw-connect__footer__link', { - href: 'https://support.metamask.io/', - target: '_blank', - }, this.context.t('getHelp')), - ]), - ]) - ) - } - - renderConnectScreen () { - return ( - h('div.new-account-connect-form', {}, [ - this.renderHeader(), - this.renderButtons(), - this.renderTrezorAffiliateLink(), - this.renderLearnMore(), - this.renderTutorialSteps(), - this.renderFooter(), - ]) - ) - } - - render () { - if (this.props.browserSupported) { - return this.renderConnectScreen() - } - return this.renderUnsupportedBrowser() - } -} - -ConnectScreen.propTypes = { - connectToHardwareWallet: PropTypes.func.isRequired, - browserSupported: PropTypes.bool.isRequired, -} - -ConnectScreen.contextTypes = { - t: PropTypes.func, -} - -module.exports = ConnectScreen - diff --git a/ui/app/components/pages/create-account/connect-hardware/index.js b/ui/app/components/pages/create-account/connect-hardware/index.js deleted file mode 100644 index 712cc5cbb..000000000 --- a/ui/app/components/pages/create-account/connect-hardware/index.js +++ /dev/null @@ -1,293 +0,0 @@ -const { Component } = require('react') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const connect = require('react-redux').connect -const actions = require('../../../../actions') -const { getMetaMaskAccounts } = require('../../../../selectors') -const ConnectScreen = require('./connect-screen') -const AccountList = require('./account-list') -const { DEFAULT_ROUTE } = require('../../../../routes') -const { formatBalance } = require('../../../../util') -const { getPlatform } = require('../../../../../../app/scripts/lib/util') -const { PLATFORM_FIREFOX } = require('../../../../../../app/scripts/lib/enums') - -class ConnectHardwareForm extends Component { - constructor (props, context) { - super(props) - this.state = { - error: null, - selectedAccount: null, - accounts: [], - browserSupported: true, - unlocked: false, - device: null, - } - } - - componentWillReceiveProps (nextProps) { - const { accounts } = nextProps - const newAccounts = this.state.accounts.map(a => { - const normalizedAddress = a.address.toLowerCase() - const balanceValue = accounts[normalizedAddress] && accounts[normalizedAddress].balance || null - a.balance = balanceValue ? formatBalance(balanceValue, 6) : '...' - return a - }) - this.setState({accounts: newAccounts}) - } - - - componentDidMount () { - this.checkIfUnlocked() - } - - async checkIfUnlocked () { - ['trezor', 'ledger'].forEach(async device => { - const unlocked = await this.props.checkHardwareStatus(device, this.props.defaultHdPaths[device]) - if (unlocked) { - this.setState({unlocked: true}) - this.getPage(device, 0, this.props.defaultHdPaths[device]) - } - }) - } - - connectToHardwareWallet = (device) => { - // Ledger hardware wallets are not supported on firefox - if (getPlatform() === PLATFORM_FIREFOX && device === 'ledger') { - this.setState({ browserSupported: false, error: null}) - return null - } - - if (this.state.accounts.length) { - return null - } - - // Default values - this.getPage(device, 0, this.props.defaultHdPaths[device]) - } - - onPathChange = (path) => { - this.props.setHardwareWalletDefaultHdPath({device: this.state.device, path}) - this.getPage(this.state.device, 0, path) - } - - onAccountChange = (account) => { - this.setState({selectedAccount: account.toString(), error: null}) - } - - onAccountRestriction = () => { - this.setState({error: this.context.t('ledgerAccountRestriction') }) - } - - showTemporaryAlert () { - this.props.showAlert(this.context.t('hardwareWalletConnected')) - // Autohide the alert after 5 seconds - setTimeout(_ => { - this.props.hideAlert() - }, 5000) - } - - getPage = (device, page, hdPath) => { - this.props - .connectHardware(device, page, hdPath) - .then(accounts => { - if (accounts.length) { - - // If we just loaded the accounts for the first time - // (device previously locked) show the global alert - if (this.state.accounts.length === 0 && !this.state.unlocked) { - this.showTemporaryAlert() - } - - const newState = { unlocked: true, device, error: null } - // Default to the first account - if (this.state.selectedAccount === null) { - accounts.forEach((a, i) => { - if (a.address.toLowerCase() === this.props.address) { - newState.selectedAccount = a.index.toString() - } - }) - // If the page doesn't contain the selected account, let's deselect it - } else if (!accounts.filter(a => a.index.toString() === this.state.selectedAccount).length) { - newState.selectedAccount = null - } - - - // Map accounts with balances - newState.accounts = accounts.map(account => { - const normalizedAddress = account.address.toLowerCase() - const balanceValue = this.props.accounts[normalizedAddress] && this.props.accounts[normalizedAddress].balance || null - account.balance = balanceValue ? formatBalance(balanceValue, 6) : '...' - return account - }) - - this.setState(newState) - } - }) - .catch(e => { - if (e === 'Window blocked') { - this.setState({ browserSupported: false, error: null}) - } else if (e !== 'Window closed' && e !== 'Popup closed') { - this.setState({ error: e.toString() }) - } - }) - } - - onForgetDevice = (device) => { - this.props.forgetDevice(device) - .then(_ => { - this.setState({ - error: null, - selectedAccount: null, - accounts: [], - unlocked: false, - }) - }).catch(e => { - this.setState({ error: e.toString() }) - }) - } - - onUnlockAccount = (device) => { - - if (this.state.selectedAccount === null) { - this.setState({ error: this.context.t('accountSelectionRequired') }) - } - - this.props.unlockHardwareWalletAccount(this.state.selectedAccount, device) - .then(_ => { - this.context.metricsEvent({ - eventOpts: { - category: 'Accounts', - action: 'Connected Hardware Wallet', - name: 'Connected Account with: ' + device, - }, - }) - this.props.history.push(DEFAULT_ROUTE) - }).catch(e => { - this.context.metricsEvent({ - eventOpts: { - category: 'Accounts', - action: 'Connected Hardware Wallet', - name: 'Error connecting hardware wallet', - }, - customVariables: { - error: e.toString(), - }, - }) - this.setState({ error: e.toString() }) - }) - } - - onCancel = () => { - this.props.history.push(DEFAULT_ROUTE) - } - - renderError () { - return this.state.error - ? h('span.error', { style: { margin: '20px 20px 10px', display: 'block', textAlign: 'center' } }, this.state.error) - : null - } - - renderContent () { - if (!this.state.accounts.length) { - return h(ConnectScreen, { - connectToHardwareWallet: this.connectToHardwareWallet, - browserSupported: this.state.browserSupported, - }) - } - - return h(AccountList, { - onPathChange: this.onPathChange, - selectedPath: this.props.defaultHdPaths[this.state.device], - device: this.state.device, - accounts: this.state.accounts, - selectedAccount: this.state.selectedAccount, - onAccountChange: this.onAccountChange, - network: this.props.network, - getPage: this.getPage, - history: this.props.history, - onUnlockAccount: this.onUnlockAccount, - onForgetDevice: this.onForgetDevice, - onCancel: this.onCancel, - onAccountRestriction: this.onAccountRestriction, - }) - } - - render () { - return h('div', [ - this.renderError(), - this.renderContent(), - ]) - } -} - -ConnectHardwareForm.propTypes = { - hideModal: PropTypes.func, - showImportPage: PropTypes.func, - showConnectPage: PropTypes.func, - connectHardware: PropTypes.func, - checkHardwareStatus: PropTypes.func, - forgetDevice: PropTypes.func, - showAlert: PropTypes.func, - hideAlert: PropTypes.func, - unlockHardwareWalletAccount: PropTypes.func, - setHardwareWalletDefaultHdPath: PropTypes.func, - numberOfExistingAccounts: PropTypes.number, - history: PropTypes.object, - t: PropTypes.func, - network: PropTypes.string, - accounts: PropTypes.object, - address: PropTypes.string, - defaultHdPaths: PropTypes.object, -} - -const mapStateToProps = state => { - const { - metamask: { network, selectedAddress, identities = {} }, - } = state - const accounts = getMetaMaskAccounts(state) - const numberOfExistingAccounts = Object.keys(identities).length - const { - appState: { defaultHdPaths }, - } = state - - return { - network, - accounts, - address: selectedAddress, - numberOfExistingAccounts, - defaultHdPaths, - } -} - -const mapDispatchToProps = dispatch => { - return { - setHardwareWalletDefaultHdPath: ({device, path}) => { - return dispatch(actions.setHardwareWalletDefaultHdPath({device, path})) - }, - connectHardware: (deviceName, page, hdPath) => { - return dispatch(actions.connectHardware(deviceName, page, hdPath)) - }, - checkHardwareStatus: (deviceName, hdPath) => { - return dispatch(actions.checkHardwareStatus(deviceName, hdPath)) - }, - forgetDevice: (deviceName) => { - return dispatch(actions.forgetDevice(deviceName)) - }, - unlockHardwareWalletAccount: (index, deviceName, hdPath) => { - return dispatch(actions.unlockHardwareWalletAccount(index, deviceName, hdPath)) - }, - showImportPage: () => dispatch(actions.showImportPage()), - showConnectPage: () => dispatch(actions.showConnectPage()), - showAlert: (msg) => dispatch(actions.showAlert(msg)), - hideAlert: () => dispatch(actions.hideAlert()), - } -} - -ConnectHardwareForm.contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, -} - -module.exports = connect(mapStateToProps, mapDispatchToProps)( - ConnectHardwareForm -) diff --git a/ui/app/components/pages/create-account/import-account/index.js b/ui/app/components/pages/create-account/import-account/index.js deleted file mode 100644 index 48d8f8838..000000000 --- a/ui/app/components/pages/create-account/import-account/index.js +++ /dev/null @@ -1,96 +0,0 @@ -const inherits = require('util').inherits -const Component = require('react').Component -const h = require('react-hyperscript') -const PropTypes = require('prop-types') -const connect = require('react-redux').connect -import Select from 'react-select' - -// Subviews -const JsonImportView = require('./json.js') -const PrivateKeyImportView = require('./private-key.js') - - -AccountImportSubview.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect()(AccountImportSubview) - - -inherits(AccountImportSubview, Component) -function AccountImportSubview () { - Component.call(this) -} - -AccountImportSubview.prototype.getMenuItemTexts = function () { - return [ - this.context.t('privateKey'), - this.context.t('jsonFile'), - ] -} - -AccountImportSubview.prototype.render = function () { - const state = this.state || {} - const menuItems = this.getMenuItemTexts() - const { type } = state - - return ( - h('div.new-account-import-form', [ - - h('.new-account-import-disclaimer', [ - h('span', this.context.t('importAccountMsg')), - h('span', { - style: { - cursor: 'pointer', - textDecoration: 'underline', - }, - onClick: () => { - global.platform.openWindow({ - url: 'https://metamask.zendesk.com/hc/en-us/articles/360015289932', - }) - }, - }, this.context.t('here')), - ]), - - h('div.new-account-import-form__select-section', [ - - h('div.new-account-import-form__select-label', this.context.t('selectType')), - - h(Select, { - className: 'new-account-import-form__select', - name: 'import-type-select', - clearable: false, - value: type || menuItems[0], - options: menuItems.map((type) => { - return { - value: type, - label: type, - } - }), - onChange: (opt) => { - this.setState({ type: opt.value }) - }, - }), - - ]), - - this.renderImportView(), - ]) - ) -} - -AccountImportSubview.prototype.renderImportView = function () { - const state = this.state || {} - const { type } = state - const menuItems = this.getMenuItemTexts() - const current = type || menuItems[0] - - switch (current) { - case this.context.t('privateKey'): - return h(PrivateKeyImportView) - case this.context.t('jsonFile'): - return h(JsonImportView) - default: - return h(JsonImportView) - } -} diff --git a/ui/app/components/pages/create-account/import-account/json.js b/ui/app/components/pages/create-account/import-account/json.js deleted file mode 100644 index 9aeea5579..000000000 --- a/ui/app/components/pages/create-account/import-account/json.js +++ /dev/null @@ -1,170 +0,0 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const { withRouter } = require('react-router-dom') -const { compose } = require('recompose') -const connect = require('react-redux').connect -const actions = require('../../../../actions') -const FileInput = require('react-simple-file-input').default -const { DEFAULT_ROUTE } = require('../../../../routes') -const { getMetaMaskAccounts } = require('../../../../selectors') -const HELP_LINK = 'https://support.metamask.io/kb/article/7-importing-accounts' -import Button from '../../../button' - -class JsonImportSubview extends Component { - constructor (props) { - super(props) - - this.state = { - file: null, - fileContents: '', - } - } - - render () { - const { error } = this.props - - return ( - h('div.new-account-import-form__json', [ - - h('p', this.context.t('usedByClients')), - h('a.warning', { - href: HELP_LINK, - target: '_blank', - }, this.context.t('fileImportFail')), - - h(FileInput, { - readAs: 'text', - onLoad: this.onLoad.bind(this), - style: { - margin: '20px 0px 12px 34%', - fontSize: '15px', - display: 'flex', - justifyContent: 'center', - }, - }), - - h('input.new-account-import-form__input-password', { - type: 'password', - placeholder: this.context.t('enterPassword'), - id: 'json-password-box', - onKeyPress: this.createKeyringOnEnter.bind(this), - }), - - h('div.new-account-create-form__buttons', {}, [ - - h(Button, { - type: 'default', - large: true, - className: 'new-account-create-form__button', - onClick: () => this.props.history.push(DEFAULT_ROUTE), - }, [this.context.t('cancel')]), - - h(Button, { - type: 'primary', - large: true, - className: 'new-account-create-form__button', - onClick: () => this.createNewKeychain(), - }, [this.context.t('import')]), - - ]), - - error ? h('span.error', error) : null, - ]) - ) - } - - onLoad (event, file) { - this.setState({file: file, fileContents: event.target.result}) - } - - createKeyringOnEnter (event) { - if (event.key === 'Enter') { - event.preventDefault() - this.createNewKeychain() - } - } - - createNewKeychain () { - const { firstAddress, displayWarning, importNewJsonAccount, setSelectedAddress, history } = this.props - const state = this.state - - if (!state) { - const message = this.context.t('validFileImport') - return displayWarning(message) - } - - const { fileContents } = state - - if (!fileContents) { - const message = this.context.t('needImportFile') - return displayWarning(message) - } - - const passwordInput = document.getElementById('json-password-box') - const password = passwordInput.value - - importNewJsonAccount([ fileContents, password ]) - .then(({ selectedAddress }) => { - if (selectedAddress) { - history.push(DEFAULT_ROUTE) - this.context.metricsEvent({ - eventOpts: { - category: 'Accounts', - action: 'Import Account', - name: 'Imported Account with JSON', - }, - }) - displayWarning(null) - } else { - displayWarning('Error importing account.') - this.context.metricsEvent({ - eventOpts: { - category: 'Accounts', - action: 'Import Account', - name: 'Error importing JSON', - }, - }) - setSelectedAddress(firstAddress) - } - }) - .catch(err => err && displayWarning(err.message || err)) - } -} - -JsonImportSubview.propTypes = { - error: PropTypes.string, - goHome: PropTypes.func, - displayWarning: PropTypes.func, - firstAddress: PropTypes.string, - importNewJsonAccount: PropTypes.func, - history: PropTypes.object, - setSelectedAddress: PropTypes.func, - t: PropTypes.func, -} - -const mapStateToProps = state => { - return { - error: state.appState.warning, - firstAddress: Object.keys(getMetaMaskAccounts(state))[0], - } -} - -const mapDispatchToProps = dispatch => { - return { - goHome: () => dispatch(actions.goHome()), - displayWarning: warning => dispatch(actions.displayWarning(warning)), - importNewJsonAccount: options => dispatch(actions.importNewAccount('JSON File', options)), - setSelectedAddress: (address) => dispatch(actions.setSelectedAddress(address)), - } -} - -JsonImportSubview.contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, -} - -module.exports = compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(JsonImportSubview) diff --git a/ui/app/components/pages/create-account/import-account/private-key.js b/ui/app/components/pages/create-account/import-account/private-key.js deleted file mode 100644 index 4ba31806f..000000000 --- a/ui/app/components/pages/create-account/import-account/private-key.js +++ /dev/null @@ -1,128 +0,0 @@ -const inherits = require('util').inherits -const Component = require('react').Component -const h = require('react-hyperscript') -const { withRouter } = require('react-router-dom') -const { compose } = require('recompose') -const PropTypes = require('prop-types') -const connect = require('react-redux').connect -const actions = require('../../../../actions') -const { DEFAULT_ROUTE } = require('../../../../routes') -const { getMetaMaskAccounts } = require('../../../../selectors') -import Button from '../../../button' - -PrivateKeyImportView.contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, -} - -module.exports = compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(PrivateKeyImportView) - - -function mapStateToProps (state) { - return { - error: state.appState.warning, - firstAddress: Object.keys(getMetaMaskAccounts(state))[0], - } -} - -function mapDispatchToProps (dispatch) { - return { - importNewAccount: (strategy, [ privateKey ]) => { - return dispatch(actions.importNewAccount(strategy, [ privateKey ])) - }, - displayWarning: (message) => dispatch(actions.displayWarning(message || null)), - setSelectedAddress: (address) => dispatch(actions.setSelectedAddress(address)), - } -} - -inherits(PrivateKeyImportView, Component) -function PrivateKeyImportView () { - this.createKeyringOnEnter = this.createKeyringOnEnter.bind(this) - Component.call(this) -} - -PrivateKeyImportView.prototype.render = function () { - const { error, displayWarning } = this.props - - return ( - h('div.new-account-import-form__private-key', [ - - h('span.new-account-create-form__instruction', this.context.t('pastePrivateKey')), - - h('div.new-account-import-form__private-key-password-container', [ - - h('input.new-account-import-form__input-password', { - type: 'password', - id: 'private-key-box', - onKeyPress: e => this.createKeyringOnEnter(e), - }), - - ]), - - h('div.new-account-import-form__buttons', {}, [ - - h(Button, { - type: 'default', - large: true, - className: 'new-account-create-form__button', - onClick: () => { - displayWarning(null) - this.props.history.push(DEFAULT_ROUTE) - }, - }, [this.context.t('cancel')]), - - h(Button, { - type: 'primary', - large: true, - className: 'new-account-create-form__button', - onClick: () => this.createNewKeychain(), - }, [this.context.t('import')]), - - ]), - - error ? h('span.error', error) : null, - ]) - ) -} - -PrivateKeyImportView.prototype.createKeyringOnEnter = function (event) { - if (event.key === 'Enter') { - event.preventDefault() - this.createNewKeychain() - } -} - -PrivateKeyImportView.prototype.createNewKeychain = function () { - const input = document.getElementById('private-key-box') - const privateKey = input.value - const { importNewAccount, history, displayWarning, setSelectedAddress, firstAddress } = this.props - - importNewAccount('Private Key', [ privateKey ]) - .then(({ selectedAddress }) => { - if (selectedAddress) { - this.context.metricsEvent({ - eventOpts: { - category: 'Accounts', - action: 'Import Account', - name: 'Imported Account with Private Key', - }, - }) - history.push(DEFAULT_ROUTE) - displayWarning(null) - } else { - displayWarning('Error importing account.') - this.context.metricsEvent({ - eventOpts: { - category: 'Accounts', - action: 'Import Account', - name: 'Error importing with Private Key', - }, - }) - setSelectedAddress(firstAddress) - } - }) - .catch(err => err && displayWarning(err.message || err)) -} diff --git a/ui/app/components/pages/create-account/import-account/seed.js b/ui/app/components/pages/create-account/import-account/seed.js deleted file mode 100644 index d98909baa..000000000 --- a/ui/app/components/pages/create-account/import-account/seed.js +++ /dev/null @@ -1,35 +0,0 @@ -const inherits = require('util').inherits -const Component = require('react').Component -const h = require('react-hyperscript') -const PropTypes = require('prop-types') -const connect = require('react-redux').connect - -SeedImportSubview.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect(mapStateToProps)(SeedImportSubview) - - -function mapStateToProps (state) { - return {} -} - -inherits(SeedImportSubview, Component) -function SeedImportSubview () { - Component.call(this) -} - -SeedImportSubview.prototype.render = function () { - return ( - h('div', { - style: { - }, - }, [ - this.context.t('pasteSeed'), - h('textarea'), - h('br'), - h('button', this.context.t('submit')), - ]) - ) -} diff --git a/ui/app/components/pages/create-account/index.js b/ui/app/components/pages/create-account/index.js deleted file mode 100644 index d3de1ea01..000000000 --- a/ui/app/components/pages/create-account/index.js +++ /dev/null @@ -1,113 +0,0 @@ -const Component = require('react').Component -const { Switch, Route, matchPath } = require('react-router-dom') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const connect = require('react-redux').connect -const actions = require('../../../actions') -const { getCurrentViewContext } = require('../../../selectors') -const classnames = require('classnames') -const NewAccountCreateForm = require('./new-account') -const NewAccountImportForm = require('./import-account') -const ConnectHardwareForm = require('./connect-hardware') -const { - NEW_ACCOUNT_ROUTE, - IMPORT_ACCOUNT_ROUTE, - CONNECT_HARDWARE_ROUTE, -} = require('../../../routes') - -class CreateAccountPage extends Component { - renderTabs () { - const { history, location } = this.props - - return h('div.new-account__tabs', [ - h('div.new-account__tabs__tab', { - className: classnames('new-account__tabs__tab', { - 'new-account__tabs__selected': matchPath(location.pathname, { - path: NEW_ACCOUNT_ROUTE, exact: true, - }), - }), - onClick: () => history.push(NEW_ACCOUNT_ROUTE), - }, [ - this.context.t('create'), - ]), - - h('div.new-account__tabs__tab', { - className: classnames('new-account__tabs__tab', { - 'new-account__tabs__selected': matchPath(location.pathname, { - path: IMPORT_ACCOUNT_ROUTE, exact: true, - }), - }), - onClick: () => history.push(IMPORT_ACCOUNT_ROUTE), - }, [ - this.context.t('import'), - ]), - h( - 'div.new-account__tabs__tab', - { - className: classnames('new-account__tabs__tab', { - 'new-account__tabs__selected': matchPath(location.pathname, { - path: CONNECT_HARDWARE_ROUTE, - exact: true, - }), - }), - onClick: () => history.push(CONNECT_HARDWARE_ROUTE), - }, - this.context.t('connect') - ), - ]) - } - - render () { - return h('div.new-account', {}, [ - h('div.new-account__header', [ - h('div.new-account__title', this.context.t('newAccount')), - this.renderTabs(), - ]), - h('div.new-account__form', [ - h(Switch, [ - h(Route, { - exact: true, - path: NEW_ACCOUNT_ROUTE, - component: NewAccountCreateForm, - }), - h(Route, { - exact: true, - path: IMPORT_ACCOUNT_ROUTE, - component: NewAccountImportForm, - }), - h(Route, { - exact: true, - path: CONNECT_HARDWARE_ROUTE, - component: ConnectHardwareForm, - }), - ]), - ]), - ]) - } -} - -CreateAccountPage.propTypes = { - location: PropTypes.object, - history: PropTypes.object, - t: PropTypes.func, -} - -CreateAccountPage.contextTypes = { - t: PropTypes.func, -} - -const mapStateToProps = state => ({ - displayedForm: getCurrentViewContext(state), -}) - -const mapDispatchToProps = dispatch => ({ - displayForm: form => dispatch(actions.setNewAccountForm(form)), - showQrView: (selected, identity) => dispatch(actions.showQrView(selected, identity)), - showExportPrivateKeyModal: () => { - dispatch(actions.showModal({ name: 'EXPORT_PRIVATE_KEY' })) - }, - hideModal: () => dispatch(actions.hideModal()), - setAccountLabel: (address, label) => dispatch(actions.setAccountLabel(address, label)), -}) - -module.exports = connect(mapStateToProps, mapDispatchToProps)(CreateAccountPage) diff --git a/ui/app/components/pages/create-account/new-account.js b/ui/app/components/pages/create-account/new-account.js deleted file mode 100644 index a7595e346..000000000 --- a/ui/app/components/pages/create-account/new-account.js +++ /dev/null @@ -1,130 +0,0 @@ -const { Component } = require('react') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const connect = require('react-redux').connect -const actions = require('../../../actions') -const { DEFAULT_ROUTE } = require('../../../routes') -import Button from '../../button' - -class NewAccountCreateForm extends Component { - constructor (props, context) { - super(props) - - const { numberOfExistingAccounts = 0 } = props - const newAccountNumber = numberOfExistingAccounts + 1 - - this.state = { - newAccountName: '', - defaultAccountName: context.t('newAccountNumberName', [newAccountNumber]), - } - } - - render () { - const { newAccountName, defaultAccountName } = this.state - const { history, createAccount } = this.props - - return h('div.new-account-create-form', [ - - h('div.new-account-create-form__input-label', {}, [ - this.context.t('accountName'), - ]), - - h('div.new-account-create-form__input-wrapper', {}, [ - h('input.new-account-create-form__input', { - value: newAccountName, - placeholder: defaultAccountName, - onChange: event => this.setState({ newAccountName: event.target.value }), - }, []), - ]), - - h('div.new-account-create-form__buttons', {}, [ - - h(Button, { - type: 'default', - large: true, - className: 'new-account-create-form__button', - onClick: () => history.push(DEFAULT_ROUTE), - }, [this.context.t('cancel')]), - - h(Button, { - type: 'primary', - large: true, - className: 'new-account-create-form__button', - onClick: () => { - createAccount(newAccountName || defaultAccountName) - .then(() => { - this.context.metricsEvent({ - eventOpts: { - category: 'Accounts', - action: 'Add New Account', - name: 'Added New Account', - }, - }) - history.push(DEFAULT_ROUTE) - }) - .catch((e) => { - this.context.metricsEvent({ - eventOpts: { - category: 'Accounts', - action: 'Add New Account', - name: 'Error', - }, - customVariables: { - errorMessage: e.message, - }, - }) - }) - }, - }, [this.context.t('create')]), - - ]), - - ]) - } -} - -NewAccountCreateForm.propTypes = { - hideModal: PropTypes.func, - showImportPage: PropTypes.func, - showConnectPage: PropTypes.func, - createAccount: PropTypes.func, - numberOfExistingAccounts: PropTypes.number, - history: PropTypes.object, - t: PropTypes.func, -} - -const mapStateToProps = state => { - const { metamask: { network, selectedAddress, identities = {} } } = state - const numberOfExistingAccounts = Object.keys(identities).length - - return { - network, - address: selectedAddress, - numberOfExistingAccounts, - } -} - -const mapDispatchToProps = dispatch => { - return { - toCoinbase: address => dispatch(actions.buyEth({ network: '1', address, amount: 0 })), - hideModal: () => dispatch(actions.hideModal()), - createAccount: newAccountName => { - return dispatch(actions.addNewAccount()) - .then(newAccountAddress => { - if (newAccountName) { - dispatch(actions.setAccountLabel(newAccountAddress, newAccountName)) - } - }) - }, - showImportPage: () => dispatch(actions.showImportPage()), - showConnectPage: () => dispatch(actions.showConnectPage()), - } -} - -NewAccountCreateForm.contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, -} - -module.exports = connect(mapStateToProps, mapDispatchToProps)(NewAccountCreateForm) - diff --git a/ui/app/components/pages/first-time-flow/create-password/create-password.component.js b/ui/app/components/pages/first-time-flow/create-password/create-password.component.js deleted file mode 100644 index 070361652..000000000 --- a/ui/app/components/pages/first-time-flow/create-password/create-password.component.js +++ /dev/null @@ -1,71 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import { Switch, Route } from 'react-router-dom' -import NewAccount from './new-account' -import ImportWithSeedPhrase from './import-with-seed-phrase' -import { - INITIALIZE_CREATE_PASSWORD_ROUTE, - INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE, - INITIALIZE_SEED_PHRASE_ROUTE, -} from '../../../../routes' - -export default class CreatePassword extends PureComponent { - static propTypes = { - history: PropTypes.object, - isInitialized: PropTypes.bool, - onCreateNewAccount: PropTypes.func, - onCreateNewAccountFromSeed: PropTypes.func, - } - - componentDidMount () { - const { isInitialized, history } = this.props - - if (isInitialized) { - history.push(INITIALIZE_SEED_PHRASE_ROUTE) - } - } - - render () { - const { onCreateNewAccount, onCreateNewAccountFromSeed } = this.props - - return ( - <div className="first-time-flow__wrapper"> - <div className="app-header__logo-container"> - <img - className="app-header__metafox-logo app-header__metafox-logo--horizontal" - src="/images/logo/metamask-logo-horizontal.svg" - height={30} - /> - <img - className="app-header__metafox-logo app-header__metafox-logo--icon" - src="/images/logo/metamask-fox.svg" - height={42} - width={42} - /> - </div> - <Switch> - <Route - exact - path={INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE} - render={props => ( - <ImportWithSeedPhrase - { ...props } - onSubmit={onCreateNewAccountFromSeed} - /> - )} - /> - <Route - exact - path={INITIALIZE_CREATE_PASSWORD_ROUTE} - render={props => ( - <NewAccount - { ...props } - onSubmit={onCreateNewAccount} - /> - )} - /> - </Switch> - </div> - ) - } -} diff --git a/ui/app/components/pages/first-time-flow/create-password/create-password.container.js b/ui/app/components/pages/first-time-flow/create-password/create-password.container.js deleted file mode 100644 index 89106f016..000000000 --- a/ui/app/components/pages/first-time-flow/create-password/create-password.container.js +++ /dev/null @@ -1,12 +0,0 @@ -import { connect } from 'react-redux' -import CreatePassword from './create-password.component' - -const mapStateToProps = state => { - const { metamask: { isInitialized } } = state - - return { - isInitialized, - } -} - -export default connect(mapStateToProps)(CreatePassword) diff --git a/ui/app/components/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js b/ui/app/components/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js deleted file mode 100644 index 4ecaa5895..000000000 --- a/ui/app/components/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js +++ /dev/null @@ -1,256 +0,0 @@ -import {validateMnemonic} from 'bip39' -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import TextField from '../../../../text-field' -import Button from '../../../../button' -import { - INITIALIZE_SELECT_ACTION_ROUTE, - INITIALIZE_END_OF_FLOW_ROUTE, -} from '../../../../../routes' - -export default class ImportWithSeedPhrase extends PureComponent { - static contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, - } - - static propTypes = { - history: PropTypes.object, - onSubmit: PropTypes.func.isRequired, - } - - state = { - seedPhrase: '', - password: '', - confirmPassword: '', - seedPhraseError: '', - passwordError: '', - confirmPasswordError: '', - termsChecked: false, - } - - parseSeedPhrase = (seedPhrase) => { - return seedPhrase - .trim() - .match(/\w+/g) - .join(' ') - } - - handleSeedPhraseChange (seedPhrase) { - let seedPhraseError = '' - - if (seedPhrase) { - const parsedSeedPhrase = this.parseSeedPhrase(seedPhrase) - if (parsedSeedPhrase.split(' ').length !== 12) { - seedPhraseError = this.context.t('seedPhraseReq') - } else if (!validateMnemonic(parsedSeedPhrase)) { - seedPhraseError = this.context.t('invalidSeedPhrase') - } - } - - this.setState({ seedPhrase, seedPhraseError }) - } - - handlePasswordChange (password) { - const { t } = this.context - - this.setState(state => { - const { confirmPassword } = state - let confirmPasswordError = '' - let passwordError = '' - - if (password && password.length < 8) { - passwordError = t('passwordNotLongEnough') - } - - if (confirmPassword && password !== confirmPassword) { - confirmPasswordError = t('passwordsDontMatch') - } - - return { - password, - passwordError, - confirmPasswordError, - } - }) - } - - handleConfirmPasswordChange (confirmPassword) { - const { t } = this.context - - this.setState(state => { - const { password } = state - let confirmPasswordError = '' - - if (password !== confirmPassword) { - confirmPasswordError = t('passwordsDontMatch') - } - - return { - confirmPassword, - confirmPasswordError, - } - }) - } - - handleImport = async event => { - event.preventDefault() - - if (!this.isValid()) { - return - } - - const { password, seedPhrase } = this.state - const { history, onSubmit } = this.props - - try { - await onSubmit(password, this.parseSeedPhrase(seedPhrase)) - this.context.metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Import Seed Phrase', - name: 'Import Complete', - }, - }) - history.push(INITIALIZE_END_OF_FLOW_ROUTE) - } catch (error) { - this.setState({ seedPhraseError: error.message }) - } - } - - isValid () { - const { - seedPhrase, - password, - confirmPassword, - passwordError, - confirmPasswordError, - seedPhraseError, - } = this.state - - if (!password || !confirmPassword || !seedPhrase || password !== confirmPassword) { - return false - } - - if (password.length < 8) { - return false - } - - return !passwordError && !confirmPasswordError && !seedPhraseError - } - - toggleTermsCheck = () => { - this.context.metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Import Seed Phrase', - name: 'Check ToS', - }, - }) - - this.setState((prevState) => ({ - termsChecked: !prevState.termsChecked, - })) - } - - render () { - const { t } = this.context - const { seedPhraseError, passwordError, confirmPasswordError, termsChecked } = this.state - - return ( - <form - className="first-time-flow__form" - onSubmit={this.handleImport} - > - <div className="first-time-flow__create-back"> - <a - onClick={e => { - e.preventDefault() - this.context.metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Import Seed Phrase', - name: 'Go Back from Onboarding Import', - }, - }) - this.props.history.push(INITIALIZE_SELECT_ACTION_ROUTE) - }} - href="#" - > - {`< Back`} - </a> - </div> - <div className="first-time-flow__header"> - { t('importAccountSeedPhrase') } - </div> - <div className="first-time-flow__text-block"> - { t('secretPhrase') } - </div> - <div className="first-time-flow__textarea-wrapper"> - <label>{ t('walletSeed') }</label> - <textarea - className="first-time-flow__textarea" - onChange={e => this.handleSeedPhraseChange(e.target.value)} - value={this.state.seedPhrase} - placeholder={t('seedPhrasePlaceholder')} - /> - </div> - { - seedPhraseError && ( - <span className="error"> - { seedPhraseError } - </span> - ) - } - <TextField - id="password" - label={t('newPassword')} - type="password" - className="first-time-flow__input" - value={this.state.password} - onChange={event => this.handlePasswordChange(event.target.value)} - error={passwordError} - autoComplete="new-password" - margin="normal" - largeLabel - /> - <TextField - id="confirm-password" - label={t('confirmPassword')} - type="password" - className="first-time-flow__input" - value={this.state.confirmPassword} - onChange={event => this.handleConfirmPasswordChange(event.target.value)} - error={confirmPasswordError} - autoComplete="confirm-password" - margin="normal" - largeLabel - /> - <div className="first-time-flow__checkbox-container" onClick={this.toggleTermsCheck}> - <div className="first-time-flow__checkbox"> - {termsChecked ? <i className="fa fa-check fa-2x" /> : null} - </div> - <span className="first-time-flow__checkbox-label"> - I have read and agree to the <a - href="https://metamask.io/terms.html" - target="_blank" - rel="noopener noreferrer" - > - <span className="first-time-flow__link-text"> - { 'Terms of Use' } - </span> - </a> - </span> - </div> - <Button - type="confirm" - className="first-time-flow__button" - disabled={!this.isValid() || !termsChecked} - onClick={this.handleImport} - > - { t('import') } - </Button> - </form> - ) - } -} diff --git a/ui/app/components/pages/first-time-flow/create-password/import-with-seed-phrase/index.js b/ui/app/components/pages/first-time-flow/create-password/import-with-seed-phrase/index.js deleted file mode 100644 index e5ff1fde5..000000000 --- a/ui/app/components/pages/first-time-flow/create-password/import-with-seed-phrase/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './import-with-seed-phrase.component' diff --git a/ui/app/components/pages/first-time-flow/create-password/index.js b/ui/app/components/pages/first-time-flow/create-password/index.js deleted file mode 100644 index 42e7436f9..000000000 --- a/ui/app/components/pages/first-time-flow/create-password/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './create-password.container' diff --git a/ui/app/components/pages/first-time-flow/create-password/new-account/index.js b/ui/app/components/pages/first-time-flow/create-password/new-account/index.js deleted file mode 100644 index 97db39cc3..000000000 --- a/ui/app/components/pages/first-time-flow/create-password/new-account/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './new-account.component' diff --git a/ui/app/components/pages/first-time-flow/create-password/new-account/new-account.component.js b/ui/app/components/pages/first-time-flow/create-password/new-account/new-account.component.js deleted file mode 100644 index 11d10e2d9..000000000 --- a/ui/app/components/pages/first-time-flow/create-password/new-account/new-account.component.js +++ /dev/null @@ -1,225 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import Button from '../../../../button' -import { - INITIALIZE_SEED_PHRASE_ROUTE, - INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE, - INITIALIZE_SELECT_ACTION_ROUTE, -} from '../../../../../routes' -import TextField from '../../../../text-field' - -export default class NewAccount extends PureComponent { - static contextTypes = { - metricsEvent: PropTypes.func, - t: PropTypes.func, - } - - static propTypes = { - onSubmit: PropTypes.func.isRequired, - history: PropTypes.object.isRequired, - } - - state = { - password: '', - confirmPassword: '', - passwordError: '', - confirmPasswordError: '', - termsChecked: false, - } - - isValid () { - const { - password, - confirmPassword, - passwordError, - confirmPasswordError, - } = this.state - - if (!password || !confirmPassword || password !== confirmPassword) { - return false - } - - if (password.length < 8) { - return false - } - - return !passwordError && !confirmPasswordError - } - - handlePasswordChange (password) { - const { t } = this.context - - this.setState(state => { - const { confirmPassword } = state - let passwordError = '' - let confirmPasswordError = '' - - if (password && password.length < 8) { - passwordError = t('passwordNotLongEnough') - } - - if (confirmPassword && password !== confirmPassword) { - confirmPasswordError = t('passwordsDontMatch') - } - - return { - password, - passwordError, - confirmPasswordError, - } - }) - } - - handleConfirmPasswordChange (confirmPassword) { - const { t } = this.context - - this.setState(state => { - const { password } = state - let confirmPasswordError = '' - - if (password !== confirmPassword) { - confirmPasswordError = t('passwordsDontMatch') - } - - return { - confirmPassword, - confirmPasswordError, - } - }) - } - - handleCreate = async event => { - event.preventDefault() - - if (!this.isValid()) { - return - } - - const { password } = this.state - const { onSubmit, history } = this.props - - try { - await onSubmit(password) - - this.context.metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Create Password', - name: 'Submit Password', - }, - }) - - history.push(INITIALIZE_SEED_PHRASE_ROUTE) - } catch (error) { - this.setState({ passwordError: error.message }) - } - } - - handleImportWithSeedPhrase = event => { - const { history } = this.props - - event.preventDefault() - history.push(INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE) - } - - toggleTermsCheck = () => { - this.context.metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Create Password', - name: 'Check ToS', - }, - }) - - this.setState((prevState) => ({ - termsChecked: !prevState.termsChecked, - })) - } - - render () { - const { t } = this.context - const { password, confirmPassword, passwordError, confirmPasswordError, termsChecked } = this.state - - return ( - <div> - <div className="first-time-flow__create-back"> - <a - onClick={e => { - e.preventDefault() - this.context.metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Create Password', - name: 'Go Back from Onboarding Create', - }, - }) - this.props.history.push(INITIALIZE_SELECT_ACTION_ROUTE) - }} - href="#" - > - {`< Back`} - </a> - </div> - <div className="first-time-flow__header"> - { t('createPassword') } - </div> - <form - className="first-time-flow__form" - onSubmit={this.handleCreate} - > - <TextField - id="create-password" - label={t('newPassword')} - type="password" - className="first-time-flow__input" - value={password} - onChange={event => this.handlePasswordChange(event.target.value)} - error={passwordError} - autoFocus - autoComplete="new-password" - margin="normal" - fullWidth - largeLabel - /> - <TextField - id="confirm-password" - label={t('confirmPassword')} - type="password" - className="first-time-flow__input" - value={confirmPassword} - onChange={event => this.handleConfirmPasswordChange(event.target.value)} - error={confirmPasswordError} - autoComplete="confirm-password" - margin="normal" - fullWidth - largeLabel - /> - <div className="first-time-flow__checkbox-container" onClick={this.toggleTermsCheck}> - <div className="first-time-flow__checkbox"> - {termsChecked ? <i className="fa fa-check fa-2x" /> : null} - </div> - <span className="first-time-flow__checkbox-label"> - I have read and agree to the <a - href="https://metamask.io/terms.html" - target="_blank" - rel="noopener noreferrer" - > - <span className="first-time-flow__link-text"> - { 'Terms of Use' } - </span> - </a> - </span> - </div> - <Button - type="confirm" - className="first-time-flow__button" - disabled={!this.isValid() || !termsChecked} - onClick={this.handleCreate} - > - { t('create') } - </Button> - </form> - </div> - ) - } -} diff --git a/ui/app/components/pages/first-time-flow/create-password/unique-image/index.js b/ui/app/components/pages/first-time-flow/create-password/unique-image/index.js deleted file mode 100644 index 0e97bf755..000000000 --- a/ui/app/components/pages/first-time-flow/create-password/unique-image/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './unique-image.container' diff --git a/ui/app/components/pages/first-time-flow/create-password/unique-image/unique-image.component.js b/ui/app/components/pages/first-time-flow/create-password/unique-image/unique-image.component.js deleted file mode 100644 index cbc85c0e4..000000000 --- a/ui/app/components/pages/first-time-flow/create-password/unique-image/unique-image.component.js +++ /dev/null @@ -1,55 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import Button from '../../../../button' -import { INITIALIZE_END_OF_FLOW_ROUTE } from '../../../../../routes' - -export default class UniqueImageScreen extends PureComponent { - static contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, - } - - static propTypes = { - history: PropTypes.object, - } - - render () { - const { t } = this.context - const { history } = this.props - - return ( - <div> - <img - src="/images/sleuth.svg" - height={42} - width={42} - /> - <div className="first-time-flow__header"> - { t('protectYourKeys') } - </div> - <div className="first-time-flow__text-block"> - { t('protectYourKeysMessage1') } - </div> - <div className="first-time-flow__text-block"> - { t('protectYourKeysMessage2') } - </div> - <Button - type="confirm" - className="first-time-flow__button" - onClick={() => { - this.context.metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Agree to Phishing Warning', - name: 'Agree to Phishing Warning', - }, - }) - history.push(INITIALIZE_END_OF_FLOW_ROUTE) - }} - > - { t('next') } - </Button> - </div> - ) - } -} diff --git a/ui/app/components/pages/first-time-flow/create-password/unique-image/unique-image.container.js b/ui/app/components/pages/first-time-flow/create-password/unique-image/unique-image.container.js deleted file mode 100644 index 34874aaec..000000000 --- a/ui/app/components/pages/first-time-flow/create-password/unique-image/unique-image.container.js +++ /dev/null @@ -1,12 +0,0 @@ -import { connect } from 'react-redux' -import UniqueImage from './unique-image.component' - -const mapStateToProps = ({ metamask }) => { - const { selectedAddress } = metamask - - return { - address: selectedAddress, - } -} - -export default connect(mapStateToProps)(UniqueImage) diff --git a/ui/app/components/pages/first-time-flow/end-of-flow/end-of-flow.component.js b/ui/app/components/pages/first-time-flow/end-of-flow/end-of-flow.component.js deleted file mode 100644 index c0e2f59d9..000000000 --- a/ui/app/components/pages/first-time-flow/end-of-flow/end-of-flow.component.js +++ /dev/null @@ -1,93 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import Button from '../../../button' -import { DEFAULT_ROUTE } from '../../../../routes' - -export default class EndOfFlowScreen extends PureComponent { - static contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, - } - - static propTypes = { - history: PropTypes.object, - completeOnboarding: PropTypes.func, - completionMetaMetricsName: PropTypes.string, - } - - render () { - const { t } = this.context - const { history, completeOnboarding, completionMetaMetricsName } = this.props - - return ( - <div className="end-of-flow"> - <div className="app-header__logo-container"> - <img - className="app-header__metafox-logo app-header__metafox-logo--horizontal" - src="/images/logo/metamask-logo-horizontal.svg" - height={30} - /> - <img - className="app-header__metafox-logo app-header__metafox-logo--icon" - src="/images/logo/metamask-fox.svg" - height={42} - width={42} - /> - </div> - <div className="end-of-flow__emoji">🎉</div> - <div className="first-time-flow__header"> - { t('congratulations') } - </div> - <div className="first-time-flow__text-block end-of-flow__text-1"> - { t('endOfFlowMessage1') } - </div> - <div className="first-time-flow__text-block end-of-flow__text-2"> - { t('endOfFlowMessage2') } - </div> - <div className="end-of-flow__text-3"> - { '• ' + t('endOfFlowMessage3') } - </div> - <div className="end-of-flow__text-3"> - { '• ' + t('endOfFlowMessage4') } - </div> - <div className="end-of-flow__text-3"> - { '• ' + t('endOfFlowMessage5') } - </div> - <div className="end-of-flow__text-3"> - { '• ' + t('endOfFlowMessage6') } - </div> - <div className="end-of-flow__text-3"> - { '• ' + t('endOfFlowMessage7') } - </div> - <div className="first-time-flow__text-block end-of-flow__text-4"> - *MetaMask cannot recover your seedphrase. <a - href="https://metamask.zendesk.com/hc/en-us/articles/360015489591-Basic-Safety-Tips" - target="_blank" - rel="noopener noreferrer" - > - <span className="first-time-flow__link-text"> - Learn More - </span> - </a>. - </div> - <Button - type="confirm" - className="first-time-flow__button" - onClick={async () => { - await completeOnboarding() - this.context.metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Onboarding Complete', - name: completionMetaMetricsName, - }, - }) - history.push(DEFAULT_ROUTE) - }} - > - { 'All Done' } - </Button> - </div> - ) - } -} diff --git a/ui/app/components/pages/first-time-flow/end-of-flow/end-of-flow.container.js b/ui/app/components/pages/first-time-flow/end-of-flow/end-of-flow.container.js deleted file mode 100644 index 91ae5a941..000000000 --- a/ui/app/components/pages/first-time-flow/end-of-flow/end-of-flow.container.js +++ /dev/null @@ -1,25 +0,0 @@ -import { connect } from 'react-redux' -import EndOfFlow from './end-of-flow.component' -import { setCompletedOnboarding } from '../../../../actions' - -const firstTimeFlowTypeNameMap = { - create: 'New Wallet Created', - 'import': 'New Wallet Imported', -} - -const mapStateToProps = ({ metamask }) => { - const { firstTimeFlowType } = metamask - - return { - completionMetaMetricsName: firstTimeFlowTypeNameMap[firstTimeFlowType], - } -} - - -const mapDispatchToProps = dispatch => { - return { - completeOnboarding: () => dispatch(setCompletedOnboarding()), - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(EndOfFlow) diff --git a/ui/app/components/pages/first-time-flow/end-of-flow/index.js b/ui/app/components/pages/first-time-flow/end-of-flow/index.js deleted file mode 100644 index b0643d155..000000000 --- a/ui/app/components/pages/first-time-flow/end-of-flow/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './end-of-flow.container' diff --git a/ui/app/components/pages/first-time-flow/end-of-flow/index.scss b/ui/app/components/pages/first-time-flow/end-of-flow/index.scss deleted file mode 100644 index d7eb4513b..000000000 --- a/ui/app/components/pages/first-time-flow/end-of-flow/index.scss +++ /dev/null @@ -1,53 +0,0 @@ -.end-of-flow { - color: black; - font-family: Roboto; - font-style: normal; - - .app-header__logo-container { - width: 742px; - margin-top: 3%; - - @media screen and (max-width: $break-small) { - width: 100%; - } - } - - &__text-1, &__text-3 { - font-weight: normal; - font-size: 16px; - margin-top: 18px; - } - - &__text-2 { - font-weight: bold; - font-size: 16px; - margin-top: 26px; - } - - &__text-3 { - margin-top: 2px; - margin-bottom: 2px; - - @media screen and (max-width: $break-small) { - margin-bottom: 16px; - font-size: .875rem; - } - } - - &__text-4 { - margin-top: 26px; - } - - button { - width: 207px; - } - - &__start-over-button { - width: 744px; - } - - &__emoji { - font-size: 80px; - margin-top: 70px; - } -}
\ No newline at end of file diff --git a/ui/app/components/pages/first-time-flow/first-time-flow-switch/first-time-flow-switch.component.js b/ui/app/components/pages/first-time-flow/first-time-flow-switch/first-time-flow-switch.component.js deleted file mode 100644 index 5c2294393..000000000 --- a/ui/app/components/pages/first-time-flow/first-time-flow-switch/first-time-flow-switch.component.js +++ /dev/null @@ -1,57 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import { Redirect } from 'react-router-dom' -import { - DEFAULT_ROUTE, - LOCK_ROUTE, - INITIALIZE_WELCOME_ROUTE, - INITIALIZE_UNLOCK_ROUTE, - INITIALIZE_SEED_PHRASE_ROUTE, - INITIALIZE_METAMETRICS_OPT_IN_ROUTE, -} from '../../../../routes' - -export default class FirstTimeFlowSwitch extends PureComponent { - static propTypes = { - completedOnboarding: PropTypes.bool, - isInitialized: PropTypes.bool, - isUnlocked: PropTypes.bool, - seedPhrase: PropTypes.string, - optInMetaMetrics: PropTypes.bool, - } - - render () { - const { - completedOnboarding, - isInitialized, - isUnlocked, - seedPhrase, - optInMetaMetrics, - } = this.props - - if (completedOnboarding) { - return <Redirect to={{ pathname: DEFAULT_ROUTE }} /> - } - - if (isUnlocked && !seedPhrase) { - return <Redirect to={{ pathname: LOCK_ROUTE }} /> - } - - if (!isInitialized) { - return <Redirect to={{ pathname: INITIALIZE_WELCOME_ROUTE }} /> - } - - if (!isUnlocked) { - return <Redirect to={{ pathname: INITIALIZE_UNLOCK_ROUTE }} /> - } - - if (seedPhrase) { - return <Redirect to={{ pathname: INITIALIZE_SEED_PHRASE_ROUTE }} /> - } - - if (optInMetaMetrics === null) { - return <Redirect to={{ pathname: INITIALIZE_WELCOME_ROUTE }} /> - } - - return <Redirect to={{ pathname: INITIALIZE_METAMETRICS_OPT_IN_ROUTE }} /> - } -} diff --git a/ui/app/components/pages/first-time-flow/first-time-flow-switch/first-time-flow-switch.container.js b/ui/app/components/pages/first-time-flow/first-time-flow-switch/first-time-flow-switch.container.js deleted file mode 100644 index d68f7a153..000000000 --- a/ui/app/components/pages/first-time-flow/first-time-flow-switch/first-time-flow-switch.container.js +++ /dev/null @@ -1,20 +0,0 @@ -import { connect } from 'react-redux' -import FirstTimeFlowSwitch from './first-time-flow-switch.component' - -const mapStateToProps = ({ metamask }) => { - const { - completedOnboarding, - isInitialized, - isUnlocked, - participateInMetaMetrics: optInMetaMetrics, - } = metamask - - return { - completedOnboarding, - isInitialized, - isUnlocked, - optInMetaMetrics, - } -} - -export default connect(mapStateToProps)(FirstTimeFlowSwitch) diff --git a/ui/app/components/pages/first-time-flow/first-time-flow-switch/index.js b/ui/app/components/pages/first-time-flow/first-time-flow-switch/index.js deleted file mode 100644 index 3647756ef..000000000 --- a/ui/app/components/pages/first-time-flow/first-time-flow-switch/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './first-time-flow-switch.container' diff --git a/ui/app/components/pages/first-time-flow/first-time-flow.component.js b/ui/app/components/pages/first-time-flow/first-time-flow.component.js deleted file mode 100644 index a1f629431..000000000 --- a/ui/app/components/pages/first-time-flow/first-time-flow.component.js +++ /dev/null @@ -1,152 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import { Switch, Route } from 'react-router-dom' -import FirstTimeFlowSwitch from './first-time-flow-switch' -import Welcome from './welcome' -import SelectAction from './select-action' -import EndOfFlow from './end-of-flow' -import Unlock from '../unlock-page' -import CreatePassword from './create-password' -import SeedPhrase from './seed-phrase' -import MetaMetricsOptInScreen from './metametrics-opt-in' -import { - DEFAULT_ROUTE, - INITIALIZE_WELCOME_ROUTE, - INITIALIZE_CREATE_PASSWORD_ROUTE, - INITIALIZE_SEED_PHRASE_ROUTE, - INITIALIZE_UNLOCK_ROUTE, - INITIALIZE_SELECT_ACTION_ROUTE, - INITIALIZE_END_OF_FLOW_ROUTE, - INITIALIZE_METAMETRICS_OPT_IN_ROUTE, -} from '../../../routes' - -export default class FirstTimeFlow extends PureComponent { - static propTypes = { - completedOnboarding: PropTypes.bool, - createNewAccount: PropTypes.func, - createNewAccountFromSeed: PropTypes.func, - history: PropTypes.object, - isInitialized: PropTypes.bool, - isUnlocked: PropTypes.bool, - unlockAccount: PropTypes.func, - nextRoute: PropTypes.func, - } - - state = { - seedPhrase: '', - isImportedKeyring: false, - } - - componentDidMount () { - const { completedOnboarding, history, isInitialized, isUnlocked } = this.props - - if (completedOnboarding) { - history.push(DEFAULT_ROUTE) - return - } - - if (isInitialized && !isUnlocked) { - history.push(INITIALIZE_UNLOCK_ROUTE) - return - } - } - - handleCreateNewAccount = async password => { - const { createNewAccount } = this.props - - try { - const seedPhrase = await createNewAccount(password) - this.setState({ seedPhrase }) - } catch (error) { - throw new Error(error.message) - } - } - - handleImportWithSeedPhrase = async (password, seedPhrase) => { - const { createNewAccountFromSeed } = this.props - - try { - await createNewAccountFromSeed(password, seedPhrase) - this.setState({ isImportedKeyring: true }) - } catch (error) { - throw new Error(error.message) - } - } - - handleUnlock = async password => { - const { unlockAccount, history, nextRoute } = this.props - - try { - const seedPhrase = await unlockAccount(password) - this.setState({ seedPhrase }, () => { - history.push(nextRoute) - }) - } catch (error) { - throw new Error(error.message) - } - } - - render () { - const { seedPhrase, isImportedKeyring } = this.state - - return ( - <div className="first-time-flow"> - <Switch> - <Route - path={INITIALIZE_SEED_PHRASE_ROUTE} - render={props => ( - <SeedPhrase - { ...props } - seedPhrase={seedPhrase} - /> - )} - /> - <Route - path={INITIALIZE_CREATE_PASSWORD_ROUTE} - render={props => ( - <CreatePassword - { ...props } - isImportedKeyring={isImportedKeyring} - onCreateNewAccount={this.handleCreateNewAccount} - onCreateNewAccountFromSeed={this.handleImportWithSeedPhrase} - /> - )} - /> - <Route - path={INITIALIZE_SELECT_ACTION_ROUTE} - component={SelectAction} - /> - <Route - path={INITIALIZE_UNLOCK_ROUTE} - render={props => ( - <Unlock - { ...props } - onSubmit={this.handleUnlock} - /> - )} - /> - <Route - exact - path={INITIALIZE_END_OF_FLOW_ROUTE} - component={EndOfFlow} - /> - <Route - exact - path={INITIALIZE_WELCOME_ROUTE} - component={Welcome} - /> - <Route - exact - path={INITIALIZE_METAMETRICS_OPT_IN_ROUTE} - component={MetaMetricsOptInScreen} - /> - <Route - exact - path="*" - component={FirstTimeFlowSwitch} - /> - </Switch> - </div> - ) - } -} diff --git a/ui/app/components/pages/first-time-flow/first-time-flow.container.js b/ui/app/components/pages/first-time-flow/first-time-flow.container.js deleted file mode 100644 index 293f94c47..000000000 --- a/ui/app/components/pages/first-time-flow/first-time-flow.container.js +++ /dev/null @@ -1,31 +0,0 @@ -import { connect } from 'react-redux' -import FirstTimeFlow from './first-time-flow.component' -import { getFirstTimeFlowTypeRoute } from './first-time-flow.selectors' -import { - createNewVaultAndGetSeedPhrase, - createNewVaultAndRestore, - unlockAndGetSeedPhrase, -} from '../../../actions' - -const mapStateToProps = state => { - const { metamask: { completedOnboarding, isInitialized, isUnlocked } } = state - - return { - completedOnboarding, - isInitialized, - isUnlocked, - nextRoute: getFirstTimeFlowTypeRoute(state), - } -} - -const mapDispatchToProps = dispatch => { - return { - createNewAccount: password => dispatch(createNewVaultAndGetSeedPhrase(password)), - createNewAccountFromSeed: (password, seedPhrase) => { - return dispatch(createNewVaultAndRestore(password, seedPhrase)) - }, - unlockAccount: password => dispatch(unlockAndGetSeedPhrase(password)), - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(FirstTimeFlow) diff --git a/ui/app/components/pages/first-time-flow/first-time-flow.selectors.js b/ui/app/components/pages/first-time-flow/first-time-flow.selectors.js deleted file mode 100644 index 1286afed9..000000000 --- a/ui/app/components/pages/first-time-flow/first-time-flow.selectors.js +++ /dev/null @@ -1,26 +0,0 @@ -import { - INITIALIZE_CREATE_PASSWORD_ROUTE, - INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE, - DEFAULT_ROUTE, -} from '../../../routes' - -const selectors = { - getFirstTimeFlowTypeRoute, -} - -module.exports = selectors - -function getFirstTimeFlowTypeRoute (state) { - const { firstTimeFlowType } = state.metamask - - let nextRoute - if (firstTimeFlowType === 'create') { - nextRoute = INITIALIZE_CREATE_PASSWORD_ROUTE - } else if (firstTimeFlowType === 'import') { - nextRoute = INITIALIZE_IMPORT_WITH_SEED_PHRASE_ROUTE - } else { - nextRoute = DEFAULT_ROUTE - } - - return nextRoute -} diff --git a/ui/app/components/pages/first-time-flow/index.js b/ui/app/components/pages/first-time-flow/index.js deleted file mode 100644 index 5db42437c..000000000 --- a/ui/app/components/pages/first-time-flow/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './first-time-flow.container' diff --git a/ui/app/components/pages/first-time-flow/index.scss b/ui/app/components/pages/first-time-flow/index.scss deleted file mode 100644 index d41748575..000000000 --- a/ui/app/components/pages/first-time-flow/index.scss +++ /dev/null @@ -1,159 +0,0 @@ -@import './welcome/index'; - -@import './select-action/index'; - -@import './seed-phrase/index'; - -@import './end-of-flow/index'; - -@import './metametrics-opt-in/index'; - - -.first-time-flow { - width: 100%; - background-color: $white; - display: flex; - justify-content: center; - - &__wrapper { - @media screen and (min-width: $break-large) { - max-width: 742px; - display: flex; - flex-direction: column; - width: 100%; - margin-top: 2%; - } - - .app-header__metafox-logo { - margin-bottom: 40px; - } - } - - &__form { - display: flex; - flex-direction: column; - } - - &__create-back { - margin-bottom: 16px; - } - - &__header { - font-size: 2.5rem; - margin-bottom: 24px; - color: black; - } - - &__subheader { - margin-bottom: 16px; - } - - &__input { - max-width: 350px; - } - - &__textarea-wrapper { - margin-bottom: 8px; - display: inline-flex; - padding: 0; - position: relative; - min-width: 0; - flex-direction: column; - max-width: 350px; - } - - &__textarea-label { - margin-bottom: 9px; - color: #1B344D; - font-size: 18px; - } - - &__textarea { - font-size: 1rem; - font-family: Roboto; - height: 190px; - border: 1px solid #CDCDCD; - border-radius: 6px; - background-color: #FFFFFF; - padding: 16px; - margin-top: 8px; - } - - &__breadcrumbs { - margin: 36px 0; - } - - &__unique-image { - margin-bottom: 20px; - } - - &__markdown { - border: 1px solid #979797; - border-radius: 8px; - background-color: $white; - height: 200px; - overflow-y: auto; - color: #757575; - font-size: .75rem; - line-height: 15px; - text-align: justify; - margin: 0; - padding: 16px 20px; - height: 30vh; - } - - &__text-block { - margin-bottom: 24px; - color: black; - - @media screen and (max-width: $break-small) { - margin-bottom: 16px; - font-size: .875rem; - } - } - - &__button { - margin: 35px 0 14px; - width: 140px; - height: 44px; - } - - &__checkbox-container { - display: flex; - align-items: center; - margin-top: 24px; - } - - &__checkbox { - background: #FFFFFF; - border: 1px solid #CDCDCD; - box-sizing: border-box; - height: 34px; - width: 34px; - display: flex; - justify-content: center; - align-items: center; - - &:hover { - border: 1.5px solid #2f9ae0; - } - - .fa-check { - color: #2f9ae0 - } - } - - &__checkbox-label { - font-family: Roboto; - font-style: normal; - font-weight: normal; - line-height: normal; - font-size: 18px; - color: #939090; - margin-left: 18px; - } - - &__link-text { - color: $curious-blue; - } -} diff --git a/ui/app/components/pages/first-time-flow/metametrics-opt-in/index.js b/ui/app/components/pages/first-time-flow/metametrics-opt-in/index.js deleted file mode 100644 index 4bc2fc3a7..000000000 --- a/ui/app/components/pages/first-time-flow/metametrics-opt-in/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './metametrics-opt-in.container' diff --git a/ui/app/components/pages/first-time-flow/metametrics-opt-in/index.scss b/ui/app/components/pages/first-time-flow/metametrics-opt-in/index.scss deleted file mode 100644 index 6c2e37785..000000000 --- a/ui/app/components/pages/first-time-flow/metametrics-opt-in/index.scss +++ /dev/null @@ -1,136 +0,0 @@ -.metametrics-opt-in { - position: relative; - width: 100%; - - a { - color: #2f9ae0bf; - } - - &__main { - display: flex; - flex-direction: column; - margin-left: 26.26%; - margin-right: 28%; - color: black; - - @media screen and (max-width: 575px) { - justify-content: center; - margin-left: 2%; - margin-right: 0%; - } - - .app-header__logo-container { - margin-top: 3%; - } - } - - &__title { - position: relative; - margin-top: 20px; - - font-family: Roboto; - font-style: normal; - font-weight: normal; - line-height: normal; - font-size: 42px; - } - - &__body-graphic { - margin-top: 25px; - - .fa-bar-chart { - color: #C4C4C4; - } - } - - &__description { - font-family: Roboto; - font-style: normal; - font-weight: normal; - line-height: 21px; - font-size: 16px; - margin-top: 12px; - } - - &__committments { - display: flex; - flex-direction: column; - } - - &__content { - overflow-y: scroll; - flex: 1; - } - - &__row { - display: flex; - margin-top: 8px; - - .fa-check { - margin-right: 12px; - color: #1ACC56; - } - - .fa-times { - margin-right: 12px; - color: #D0021B; - } - } - - &__bold { - font-weight: bold; - } - - &__break-row { - margin-top: 30px; - } - - &__body { - position: relative; - display: flex; - max-width: 730px; - flex-direction: column; - } - - &__body-text { - max-width: 548px; - margin-left: 16px; - margin-right: 16px; - } - - &__bottom-text { - margin-top: 10px; - color: #9a9a9a; - } - - &__content { - overflow-y: auto; - } - - &__footer { - margin-top: 26px; - - @media screen and (max-width: 575px) { - margin-top: 10px; - justify-content: center; - margin-left: 2%; - max-height: 520px; - } - - .page-container__footer { - border-top: none; - max-width: 535px; - margin-bottom: 15px; - - button { - height: 44px; - min-height: 44px; - margin-right: 16px; - } - - header { - padding: 0px; - } - } - } -}
\ No newline at end of file diff --git a/ui/app/components/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js b/ui/app/components/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js deleted file mode 100644 index 58a03944e..000000000 --- a/ui/app/components/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js +++ /dev/null @@ -1,169 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import PageContainerFooter from '../../../page-container/page-container-footer' - -export default class MetaMetricsOptIn extends Component { - static propTypes = { - history: PropTypes.object, - setParticipateInMetaMetrics: PropTypes.func, - nextRoute: PropTypes.string, - firstTimeSelectionMetaMetricsName: PropTypes.string, - participateInMetaMetrics: PropTypes.bool, - } - - static contextTypes = { - metricsEvent: PropTypes.func, - } - - render () { - const { metricsEvent } = this.context - const { - nextRoute, - history, - setParticipateInMetaMetrics, - firstTimeSelectionMetaMetricsName, - participateInMetaMetrics, - } = this.props - - return ( - <div className="metametrics-opt-in"> - <div className="metametrics-opt-in__main"> - <div className="app-header__logo-container"> - <img - className="app-header__metafox-logo app-header__metafox-logo--horizontal" - src="/images/logo/metamask-logo-horizontal.svg" - height={30} - /> - <img - className="app-header__metafox-logo app-header__metafox-logo--icon" - src="/images/logo/metamask-fox.svg" - height={42} - width={42} - /> - </div> - <div className="metametrics-opt-in__body-graphic"> - <img src="images/metrics-chart.svg" /> - </div> - <div className="metametrics-opt-in__title">Help Us Improve MetaMask</div> - <div className="metametrics-opt-in__body"> - <div className="metametrics-opt-in__description"> - MetaMask would like to gather usage data to better understand how our users interact with the extension. This data - will be used to continually improve the usability and user experience of our product and the Etheruem ecosystem. - </div> - <div className="metametrics-opt-in__description"> - MetaMask will.. - </div> - - <div className="metametrics-opt-in__committments"> - <div className="metametrics-opt-in__row"> - <i className="fa fa-check" /> - <div className="metametrics-opt-in__row-description"> - Always allow you to opt-out via Settings - </div> - </div> - <div className="metametrics-opt-in__row"> - <i className="fa fa-check" /> - <div className="metametrics-opt-in__row-description"> - Send anonymized click & pageview events - </div> - </div> - <div className="metametrics-opt-in__row"> - <i className="fa fa-check" /> - <div className="metametrics-opt-in__row-description"> - Maintain a public aggregate dashboard to educate the community - </div> - </div> - <div className="metametrics-opt-in__row metametrics-opt-in__break-row"> - <i className="fa fa-times" /> - <div className="metametrics-opt-in__row-description"> - <span className="metametrics-opt-in__bold">Never</span> collect keys, addresses, transactions, balances, hashes, or any personal information - </div> - </div> - <div className="metametrics-opt-in__row"> - <i className="fa fa-times" /> - <div className="metametrics-opt-in__row-description"> - <span className="metametrics-opt-in__bold">Never</span> collect your full IP address - </div> - </div> - <div className="metametrics-opt-in__row"> - <i className="fa fa-times" /> - <div className="metametrics-opt-in__row-description"> - <span className="metametrics-opt-in__bold">Never</span> sell data for profit. Ever! - </div> - </div> - </div> - </div> - <div className="metametrics-opt-in__footer"> - <PageContainerFooter - onCancel={() => { - setParticipateInMetaMetrics(false) - .then(() => { - const promise = participateInMetaMetrics !== false - ? metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Metrics Option', - name: 'Metrics Opt Out', - }, - isOptIn: true, - }) - : Promise.resolve() - - promise - .then(() => { - history.push(nextRoute) - }) - }) - }} - cancelText={'No Thanks'} - hideCancel={false} - onSubmit={() => { - setParticipateInMetaMetrics(true) - .then(([participateStatus, metaMetricsId]) => { - const promise = participateInMetaMetrics !== true - ? metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Metrics Option', - name: 'Metrics Opt In', - }, - isOptIn: true, - }) - : Promise.resolve() - - promise - .then(() => { - return metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Import or Create', - name: firstTimeSelectionMetaMetricsName, - }, - isOptIn: true, - metaMetricsId, - }) - }) - .then(() => { - history.push(nextRoute) - }) - }) - }} - submitText={'I agree'} - submitButtonType={'confirm'} - disabled={false} - /> - <div className="metametrics-opt-in__bottom-text"> - This data is aggregated and is therefore anonymous for the purposes of General Data Protection Regulation (EU) 2016/679. For more information in relation to our privacy practices, please see our <a - href="https://metamask.io/privacy.html" - target="_blank" - rel="noopener noreferrer" - > - Privacy Policy here - </a>. - </div> - </div> - </div> - </div> - ) - } -} diff --git a/ui/app/components/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.container.js b/ui/app/components/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.container.js deleted file mode 100644 index b13af8bf6..000000000 --- a/ui/app/components/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.container.js +++ /dev/null @@ -1,27 +0,0 @@ -import { connect } from 'react-redux' -import MetaMetricsOptIn from './metametrics-opt-in.component' -import { setParticipateInMetaMetrics } from '../../../../actions' -import { getFirstTimeFlowTypeRoute } from '../first-time-flow.selectors' - -const firstTimeFlowTypeNameMap = { - create: 'Selected Create New Wallet', - 'import': 'Selected Import Wallet', -} - -const mapStateToProps = (state) => { - const { firstTimeFlowType, participateInMetaMetrics } = state.metamask - - return { - nextRoute: getFirstTimeFlowTypeRoute(state), - firstTimeSelectionMetaMetricsName: firstTimeFlowTypeNameMap[firstTimeFlowType], - participateInMetaMetrics, - } -} - -const mapDispatchToProps = dispatch => { - return { - setParticipateInMetaMetrics: (val) => dispatch(setParticipateInMetaMetrics(val)), - } -} - -export default connect(mapStateToProps, mapDispatchToProps)(MetaMetricsOptIn) diff --git a/ui/app/components/pages/first-time-flow/seed-phrase/confirm-seed-phrase/confirm-seed-phrase.component.js b/ui/app/components/pages/first-time-flow/seed-phrase/confirm-seed-phrase/confirm-seed-phrase.component.js deleted file mode 100644 index bd5ab8a84..000000000 --- a/ui/app/components/pages/first-time-flow/seed-phrase/confirm-seed-phrase/confirm-seed-phrase.component.js +++ /dev/null @@ -1,155 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import classnames from 'classnames' -import shuffle from 'lodash.shuffle' -import Button from '../../../../button' -import { - INITIALIZE_END_OF_FLOW_ROUTE, - INITIALIZE_SEED_PHRASE_ROUTE, -} from '../../../../../routes' -import { exportAsFile } from '../../../../../../app/util' -import { selectSeedWord, deselectSeedWord } from './confirm-seed-phrase.state' - -export default class ConfirmSeedPhrase extends PureComponent { - static contextTypes = { - metricsEvent: PropTypes.func, - t: PropTypes.func, - } - - static defaultProps = { - seedPhrase: '', - } - - static propTypes = { - history: PropTypes.object, - onSubmit: PropTypes.func, - seedPhrase: PropTypes.string, - } - - state = { - selectedSeedWords: [], - shuffledSeedWords: [], - // Hash of shuffledSeedWords index {Number} to selectedSeedWords index {Number} - selectedSeedWordsHash: {}, - } - - componentDidMount () { - const { seedPhrase = '' } = this.props - const shuffledSeedWords = shuffle(seedPhrase.split(' ')) || [] - this.setState({ shuffledSeedWords }) - } - - handleExport = () => { - exportAsFile('MetaMask Secret Backup Phrase', this.props.seedPhrase, 'text/plain') - } - - handleSubmit = async () => { - const { history } = this.props - - if (!this.isValid()) { - return - } - - try { - this.context.metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Seed Phrase Setup', - name: 'Verify Complete', - }, - }) - history.push(INITIALIZE_END_OF_FLOW_ROUTE) - } catch (error) { - console.error(error.message) - } - } - - handleSelectSeedWord = (word, shuffledIndex) => { - this.setState(selectSeedWord(word, shuffledIndex)) - } - - handleDeselectSeedWord = shuffledIndex => { - this.setState(deselectSeedWord(shuffledIndex)) - } - - isValid () { - const { seedPhrase } = this.props - const { selectedSeedWords } = this.state - return seedPhrase === selectedSeedWords.join(' ') - } - - render () { - const { t } = this.context - const { history } = this.props - const { selectedSeedWords, shuffledSeedWords, selectedSeedWordsHash } = this.state - - return ( - <div className="confirm-seed-phrase"> - <div className="confirm-seed-phrase__back-button"> - <a - onClick={e => { - e.preventDefault() - history.push(INITIALIZE_SEED_PHRASE_ROUTE) - }} - href="#" - > - {`< Back`} - </a> - </div> - <div className="first-time-flow__header"> - { t('confirmSecretBackupPhrase') } - </div> - <div className="first-time-flow__text-block"> - { t('selectEachPhrase') } - </div> - <div className="confirm-seed-phrase__selected-seed-words"> - { - selectedSeedWords.map((word, index) => ( - <div - key={index} - className="confirm-seed-phrase__seed-word" - > - { word } - </div> - )) - } - </div> - <div className="confirm-seed-phrase__shuffled-seed-words"> - { - shuffledSeedWords.map((word, index) => { - const isSelected = index in selectedSeedWordsHash - - return ( - <div - key={index} - className={classnames( - 'confirm-seed-phrase__seed-word', - 'confirm-seed-phrase__seed-word--shuffled', - { 'confirm-seed-phrase__seed-word--selected': isSelected } - )} - onClick={() => { - if (!isSelected) { - this.handleSelectSeedWord(word, index) - } else { - this.handleDeselectSeedWord(index) - } - }} - > - { word } - </div> - ) - }) - } - </div> - <Button - type="confirm" - className="first-time-flow__button" - onClick={this.handleSubmit} - disabled={!this.isValid()} - > - { t('confirm') } - </Button> - </div> - ) - } -} diff --git a/ui/app/components/pages/first-time-flow/seed-phrase/confirm-seed-phrase/confirm-seed-phrase.state.js b/ui/app/components/pages/first-time-flow/seed-phrase/confirm-seed-phrase/confirm-seed-phrase.state.js deleted file mode 100644 index f2476fc5c..000000000 --- a/ui/app/components/pages/first-time-flow/seed-phrase/confirm-seed-phrase/confirm-seed-phrase.state.js +++ /dev/null @@ -1,41 +0,0 @@ -export function selectSeedWord (word, shuffledIndex) { - return function update (state) { - const { selectedSeedWords, selectedSeedWordsHash } = state - const nextSelectedIndex = selectedSeedWords.length - - return { - selectedSeedWords: [ ...selectedSeedWords, word ], - selectedSeedWordsHash: { ...selectedSeedWordsHash, [shuffledIndex]: nextSelectedIndex }, - } - } -} - -export function deselectSeedWord (shuffledIndex) { - return function update (state) { - const { - selectedSeedWords: prevSelectedSeedWords, - selectedSeedWordsHash: prevSelectedSeedWordsHash, - } = state - - const selectedSeedWords = [...prevSelectedSeedWords] - const indexToRemove = prevSelectedSeedWordsHash[shuffledIndex] - selectedSeedWords.splice(indexToRemove, 1) - const selectedSeedWordsHash = Object.keys(prevSelectedSeedWordsHash).reduce((acc, index) => { - const output = { ...acc } - const selectedSeedWordIndex = prevSelectedSeedWordsHash[index] - - if (selectedSeedWordIndex < indexToRemove) { - output[index] = selectedSeedWordIndex - } else if (selectedSeedWordIndex > indexToRemove) { - output[index] = selectedSeedWordIndex - 1 - } - - return output - }, {}) - - return { - selectedSeedWords, - selectedSeedWordsHash, - } - } -} diff --git a/ui/app/components/pages/first-time-flow/seed-phrase/confirm-seed-phrase/index.js b/ui/app/components/pages/first-time-flow/seed-phrase/confirm-seed-phrase/index.js deleted file mode 100644 index c7b511503..000000000 --- a/ui/app/components/pages/first-time-flow/seed-phrase/confirm-seed-phrase/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './confirm-seed-phrase.component' diff --git a/ui/app/components/pages/first-time-flow/seed-phrase/confirm-seed-phrase/index.scss b/ui/app/components/pages/first-time-flow/seed-phrase/confirm-seed-phrase/index.scss deleted file mode 100644 index 93137618c..000000000 --- a/ui/app/components/pages/first-time-flow/seed-phrase/confirm-seed-phrase/index.scss +++ /dev/null @@ -1,48 +0,0 @@ -.confirm-seed-phrase { - &__back-button { - margin-bottom: 12px; - } - - &__selected-seed-words { - min-height: 190px; - max-width: 496px; - border: 1px solid #CDCDCD; - border-radius: 6px; - background-color: $white; - margin: 24px 0 36px; - padding: 12px; - } - - &__shuffled-seed-words { - max-width: 496px; - } - - &__seed-word { - display: inline-block; - color: #5B5D67; - background-color: #E7E7E7; - padding: 8px 18px; - min-width: 64px; - margin: 4px; - text-align: center; - - &--selected { - background-color: #85D1CC; - color: $white; - } - - &--shuffled { - cursor: pointer; - margin: 6px; - } - - @media screen and (max-width: 575px) { - font-size: .875rem; - padding: 6px 18px; - } - } - - button { - margin-top: 0xp; - } -} diff --git a/ui/app/components/pages/first-time-flow/seed-phrase/index.js b/ui/app/components/pages/first-time-flow/seed-phrase/index.js deleted file mode 100644 index 185b3f089..000000000 --- a/ui/app/components/pages/first-time-flow/seed-phrase/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './seed-phrase.component' diff --git a/ui/app/components/pages/first-time-flow/seed-phrase/index.scss b/ui/app/components/pages/first-time-flow/seed-phrase/index.scss deleted file mode 100644 index e4fd7be4f..000000000 --- a/ui/app/components/pages/first-time-flow/seed-phrase/index.scss +++ /dev/null @@ -1,40 +0,0 @@ -@import './confirm-seed-phrase/index'; - -@import './reveal-seed-phrase/index'; - -.seed-phrase { - - &__sections { - display: flex; - - @media screen and (min-width: $break-large) { - flex-direction: row; - } - - @media screen and (max-width: $break-small) { - flex-direction: column; - } - } - - &__main { - flex: 3; - min-width: 0; - } - - &__side { - flex: 2; - min-width: 0; - - @media screen and (min-width: $break-large) { - margin-left: 81px; - } - - @media screen and (max-width: $break-small) { - margin-top: 24px; - } - - .first-time-flow__text-block { - color: #5A5A5A; - } - } -} diff --git a/ui/app/components/pages/first-time-flow/seed-phrase/reveal-seed-phrase/index.js b/ui/app/components/pages/first-time-flow/seed-phrase/reveal-seed-phrase/index.js deleted file mode 100644 index 4a1b191b5..000000000 --- a/ui/app/components/pages/first-time-flow/seed-phrase/reveal-seed-phrase/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './reveal-seed-phrase.component' diff --git a/ui/app/components/pages/first-time-flow/seed-phrase/reveal-seed-phrase/index.scss b/ui/app/components/pages/first-time-flow/seed-phrase/reveal-seed-phrase/index.scss deleted file mode 100644 index 8a47447ed..000000000 --- a/ui/app/components/pages/first-time-flow/seed-phrase/reveal-seed-phrase/index.scss +++ /dev/null @@ -1,57 +0,0 @@ -.reveal-seed-phrase { - &__secret { - position: relative; - display: flex; - justify-content: center; - border: 1px solid #CDCDCD; - border-radius: 6px; - background-color: $white; - padding: 18px; - margin-top: 36px; - max-width: 350px; - } - - &__secret-words { - width: 310px; - font-size: 1.25rem; - text-align: center; - - &--hidden { - filter: blur(5px); - } - } - - &__secret-blocker { - position: absolute; - top: 0; - bottom: 0; - height: 100%; - width: 100%; - background-color: rgba(0,0,0,0.6); - display: flex; - flex-flow: column nowrap; - align-items: center; - justify-content: center; - padding: 8px 0 18px; - cursor: pointer; - } - - &__reveal-button { - color: $white; - font-size: .75rem; - font-weight: 500; - text-transform: uppercase; - margin-top: 8px; - text-align: center; - } - - &__export-text { - color: $curious-blue; - cursor: pointer; - font-weight: 500; - } - - button { - margin-top: 0xp; - } -} diff --git a/ui/app/components/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.component.js b/ui/app/components/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.component.js deleted file mode 100644 index cb8a01322..000000000 --- a/ui/app/components/pages/first-time-flow/seed-phrase/reveal-seed-phrase/reveal-seed-phrase.component.js +++ /dev/null @@ -1,143 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import classnames from 'classnames' -import LockIcon from '../../../../lock-icon' -import Button from '../../../../button' -import { INITIALIZE_CONFIRM_SEED_PHRASE_ROUTE } from '../../../../../routes' -import { exportAsFile } from '../../../../../../app/util' - -export default class RevealSeedPhrase extends PureComponent { - static contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, - } - - static propTypes = { - history: PropTypes.object, - seedPhrase: PropTypes.string, - } - - state = { - isShowingSeedPhrase: false, - } - - handleExport = () => { - exportAsFile('MetaMask Secret Backup Phrase', this.props.seedPhrase, 'text/plain') - } - - handleNext = event => { - event.preventDefault() - const { isShowingSeedPhrase } = this.state - const { history } = this.props - - this.context.metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Seed Phrase Setup', - name: 'Advance to Verify', - }, - }) - - if (!isShowingSeedPhrase) { - return - } - - history.push(INITIALIZE_CONFIRM_SEED_PHRASE_ROUTE) - } - - renderSecretWordsContainer () { - const { t } = this.context - const { seedPhrase } = this.props - const { isShowingSeedPhrase } = this.state - - return ( - <div className="reveal-seed-phrase__secret"> - <div className={classnames( - 'reveal-seed-phrase__secret-words', - { 'reveal-seed-phrase__secret-words--hidden': !isShowingSeedPhrase } - )}> - { seedPhrase } - </div> - { - !isShowingSeedPhrase && ( - <div - className="reveal-seed-phrase__secret-blocker" - onClick={() => { - this.context.metricsEvent({ - eventOpts: { - category: 'Onboarding', - action: 'Seed Phrase Setup', - name: 'Revealed Words', - }, - }) - this.setState({ isShowingSeedPhrase: true }) - }} - > - <LockIcon - width="28px" - height="35px" - fill="#FFFFFF" - /> - <div className="reveal-seed-phrase__reveal-button"> - { t('clickToRevealSeed') } - </div> - </div> - ) - } - </div> - ) - } - - render () { - const { t } = this.context - const { isShowingSeedPhrase } = this.state - - return ( - <div className="reveal-seed-phrase"> - <div className="seed-phrase__sections"> - <div className="seed-phrase__main"> - <div className="first-time-flow__header"> - { t('secretBackupPhrase') } - </div> - <div className="first-time-flow__text-block"> - { t('secretBackupPhraseDescription') } - </div> - <div className="first-time-flow__text-block"> - { t('secretBackupPhraseWarning') } - </div> - { this.renderSecretWordsContainer() } - </div> - <div className="seed-phrase__side"> - <div className="first-time-flow__text-block"> - { `${t('tips')}:` } - </div> - <div className="first-time-flow__text-block"> - { t('storePhrase') } - </div> - <div className="first-time-flow__text-block"> - { t('writePhrase') } - </div> - <div className="first-time-flow__text-block"> - { t('memorizePhrase') } - </div> - <div className="first-time-flow__text-block"> - <a - className="reveal-seed-phrase__export-text" - onClick={this.handleExport}> - { t('downloadSecretBackup') } - </a> - </div> - </div> - </div> - <Button - type="confirm" - className="first-time-flow__button" - onClick={this.handleNext} - disabled={!isShowingSeedPhrase} - > - { t('next') } - </Button> - </div> - ) - } -} diff --git a/ui/app/components/pages/first-time-flow/seed-phrase/seed-phrase.component.js b/ui/app/components/pages/first-time-flow/seed-phrase/seed-phrase.component.js deleted file mode 100644 index 9eec89cdd..000000000 --- a/ui/app/components/pages/first-time-flow/seed-phrase/seed-phrase.component.js +++ /dev/null @@ -1,70 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import { Switch, Route } from 'react-router-dom' -import RevealSeedPhrase from './reveal-seed-phrase' -import ConfirmSeedPhrase from './confirm-seed-phrase' -import { - INITIALIZE_SEED_PHRASE_ROUTE, - INITIALIZE_CONFIRM_SEED_PHRASE_ROUTE, - DEFAULT_ROUTE, -} from '../../../../routes' - -export default class SeedPhrase extends PureComponent { - static propTypes = { - address: PropTypes.string, - history: PropTypes.object, - seedPhrase: PropTypes.string, - } - - componentDidMount () { - const { seedPhrase, history } = this.props - - if (!seedPhrase) { - history.push(DEFAULT_ROUTE) - } - } - - render () { - const { seedPhrase } = this.props - - return ( - <div className="first-time-flow__wrapper"> - <div className="app-header__logo-container"> - <img - className="app-header__metafox-logo app-header__metafox-logo--horizontal" - src="/images/logo/metamask-logo-horizontal.svg" - height={30} - /> - <img - className="app-header__metafox-logo app-header__metafox-logo--icon" - src="/images/logo/metamask-fox.svg" - height={42} - width={42} - /> - </div> - <Switch> - <Route - exact - path={INITIALIZE_CONFIRM_SEED_PHRASE_ROUTE} - render={props => ( - <ConfirmSeedPhrase - { ...props } - seedPhrase={seedPhrase} - /> - )} - /> - <Route - exact - path={INITIALIZE_SEED_PHRASE_ROUTE} - render={props => ( - <RevealSeedPhrase - { ...props } - seedPhrase={seedPhrase} - /> - )} - /> - </Switch> - </div> - ) - } -} diff --git a/ui/app/components/pages/first-time-flow/select-action/index.js b/ui/app/components/pages/first-time-flow/select-action/index.js deleted file mode 100644 index 4fbe1823b..000000000 --- a/ui/app/components/pages/first-time-flow/select-action/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './select-action.container' diff --git a/ui/app/components/pages/first-time-flow/select-action/index.scss b/ui/app/components/pages/first-time-flow/select-action/index.scss deleted file mode 100644 index e1b22d05b..000000000 --- a/ui/app/components/pages/first-time-flow/select-action/index.scss +++ /dev/null @@ -1,88 +0,0 @@ -.select-action { - .app-header__logo-container { - width: 742px; - margin-top: 3%; - } - - &__body { - display: flex; - flex-direction: column; - align-items: center; - } - - &__body-header { - font-family: Roboto; - font-style: normal; - font-weight: normal; - line-height: 39px; - font-size: 28px; - text-align: center; - margin-top: 65px; - color: black; - } - - &__select-buttons { - display: flex; - flex-direction: row; - margin-top: 40px; - } - - &__select-button { - display: flex; - flex-direction: column; - align-items: center; - justify-content: space-evenly; - width: 388px; - height: 278px; - - border: 1px solid #D8D8D8; - box-sizing: border-box; - border-radius: 10px; - margin-left: 22px; - - .first-time-flow__button { - max-width: 221px; - height: 44px; - } - } - - &__button-symbol { - color: #C4C4C4; - margin-top: 41px; - } - - &__button-content { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - height: 144px; - } - - &__button-text-big { - font-family: Roboto; - font-style: normal; - font-weight: normal; - line-height: 28px; - font-size: 20px; - color: #000000; - margin-top: 12px; - text-align: center; - } - - &__button-text-small { - font-family: Roboto; - font-style: normal; - font-weight: normal; - line-height: 20px; - font-size: 14px; - color: #7A7A7B; - margin-top: 10px; - text-align: center; - } - - button { - font-weight: 500; - width: 221px; - } -}
\ No newline at end of file diff --git a/ui/app/components/pages/first-time-flow/select-action/select-action.component.js b/ui/app/components/pages/first-time-flow/select-action/select-action.component.js deleted file mode 100644 index b6a6942c3..000000000 --- a/ui/app/components/pages/first-time-flow/select-action/select-action.component.js +++ /dev/null @@ -1,112 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import Button from '../../../button' -import { - INITIALIZE_METAMETRICS_OPT_IN_ROUTE, -} from '../../../../routes' - -export default class SelectAction extends PureComponent { - static propTypes = { - history: PropTypes.object, - isInitialized: PropTypes.bool, - setFirstTimeFlowType: PropTypes.func, - nextRoute: PropTypes.string, - } - - static contextTypes = { - t: PropTypes.func, - } - - componentDidMount () { - const { history, isInitialized, nextRoute } = this.props - - if (isInitialized) { - history.push(nextRoute) - } - } - - handleCreate = () => { - this.props.setFirstTimeFlowType('create') - this.props.history.push(INITIALIZE_METAMETRICS_OPT_IN_ROUTE) - } - - handleImport = () => { - this.props.setFirstTimeFlowType('import') - this.props.history.push(INITIALIZE_METAMETRICS_OPT_IN_ROUTE) - } - - render () { - const { t } = this.context - - return ( - <div className="select-action"> - <div className="app-header__logo-container"> - <img - className="app-header__metafox-logo app-header__metafox-logo--horizontal" - src="/images/logo/metamask-logo-horizontal.svg" - height={30} - /> - <img - className="app-header__metafox-logo app-header__metafox-logo--icon" - src="/images/logo/metamask-fox.svg" - height={42} - width={42} - /> - </div> - - <div className="select-action__wrapper"> - - - <div className="select-action__body"> - <div className="select-action__body-header"> - { t('newToMetaMask') } - </div> - <div className="select-action__select-buttons"> - <div className="select-action__select-button"> - <div className="select-action__button-content"> - <div className="select-action__button-symbol"> - <img src="/images/download-alt.svg" /> - </div> - <div className="select-action__button-text-big"> - { t('noAlreadyHaveSeed') } - </div> - <div className="select-action__button-text-small"> - { t('importYourExisting') } - </div> - </div> - <Button - type="primary" - className="first-time-flow__button" - onClick={this.handleImport} - > - { t('importWallet') } - </Button> - </div> - <div className="select-action__select-button"> - <div className="select-action__button-content"> - <div className="select-action__button-symbol"> - <img src="/images/thin-plus.svg" /> - </div> - <div className="select-action__button-text-big"> - { t('letsGoSetUp') } - </div> - <div className="select-action__button-text-small"> - { t('thisWillCreate') } - </div> - </div> - <Button - type="confirm" - className="first-time-flow__button" - onClick={this.handleCreate} - > - { t('createAWallet') } - </Button> - </div> - </div> - </div> - - </div> - </div> - ) - } -} diff --git a/ui/app/components/pages/first-time-flow/select-action/select-action.container.js b/ui/app/components/pages/first-time-flow/select-action/select-action.container.js deleted file mode 100644 index 42fac7af2..000000000 --- a/ui/app/components/pages/first-time-flow/select-action/select-action.container.js +++ /dev/null @@ -1,23 +0,0 @@ -import { connect } from 'react-redux' -import { withRouter } from 'react-router-dom' -import { compose } from 'recompose' -import { setFirstTimeFlowType } from '../../../../actions' -import { getFirstTimeFlowTypeRoute } from '../first-time-flow.selectors' -import Welcome from './select-action.component' - -const mapStateToProps = (state) => { - return { - nextRoute: getFirstTimeFlowTypeRoute(state), - } -} - -const mapDispatchToProps = dispatch => { - return { - setFirstTimeFlowType: type => dispatch(setFirstTimeFlowType(type)), - } -} - -export default compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(Welcome) diff --git a/ui/app/components/pages/first-time-flow/welcome/index.js b/ui/app/components/pages/first-time-flow/welcome/index.js deleted file mode 100644 index 8abeddaa1..000000000 --- a/ui/app/components/pages/first-time-flow/welcome/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './welcome.container' diff --git a/ui/app/components/pages/first-time-flow/welcome/index.scss b/ui/app/components/pages/first-time-flow/welcome/index.scss deleted file mode 100644 index 3b5071480..000000000 --- a/ui/app/components/pages/first-time-flow/welcome/index.scss +++ /dev/null @@ -1,42 +0,0 @@ -.welcome-page { - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: center; - max-width: 442px; - padding: 0 18px; - color: black; - - &__wrapper { - display: flex; - flex-direction: row; - justify-content: center; - align-items: flex-start; - height: 100%; - margin-top: 110px; - } - - &__header { - font-size: 28px; - margin-bottom: 22px; - margin-top: 50px; - } - - &__description { - text-align: center; - - div { - font-size: 16px; - } - - @media screen and (max-width: 575px) { - font-size: .9rem; - } - } - - .first-time-flow__button { - width: 184px; - font-weight: 500; - margin-top: 44px; - } -} diff --git a/ui/app/components/pages/first-time-flow/welcome/welcome.component.js b/ui/app/components/pages/first-time-flow/welcome/welcome.component.js deleted file mode 100644 index 88cdb936c..000000000 --- a/ui/app/components/pages/first-time-flow/welcome/welcome.component.js +++ /dev/null @@ -1,69 +0,0 @@ -import EventEmitter from 'events' -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import Mascot from '../../../mascot' -import Button from '../../../button' -import { INITIALIZE_CREATE_PASSWORD_ROUTE, INITIALIZE_SELECT_ACTION_ROUTE } from '../../../../routes' - -export default class Welcome extends PureComponent { - static propTypes = { - history: PropTypes.object, - isInitialized: PropTypes.bool, - participateInMetaMetrics: PropTypes.bool, - welcomeScreenSeen: PropTypes.bool, - } - - static contextTypes = { - t: PropTypes.func, - } - - constructor (props) { - super(props) - - this.animationEventEmitter = new EventEmitter() - } - - componentDidMount () { - const { history, participateInMetaMetrics, welcomeScreenSeen } = this.props - - if (welcomeScreenSeen && participateInMetaMetrics !== null) { - history.push(INITIALIZE_CREATE_PASSWORD_ROUTE) - } else if (welcomeScreenSeen) { - history.push(INITIALIZE_SELECT_ACTION_ROUTE) - } - } - - handleContinue = () => { - this.props.history.push(INITIALIZE_SELECT_ACTION_ROUTE) - } - - render () { - const { t } = this.context - - return ( - <div className="welcome-page__wrapper"> - <div className="welcome-page"> - <Mascot - animationEventEmitter={this.animationEventEmitter} - width="125" - height="125" - /> - <div className="welcome-page__header"> - { t('welcome') } - </div> - <div className="welcome-page__description"> - <div>{ t('metamaskDescription') }</div> - <div>{ t('happyToSeeYou') }</div> - </div> - <Button - type="confirm" - className="first-time-flow__button" - onClick={this.handleContinue} - > - { t('getStarted') } - </Button> - </div> - </div> - ) - } -} diff --git a/ui/app/components/pages/first-time-flow/welcome/welcome.container.js b/ui/app/components/pages/first-time-flow/welcome/welcome.container.js deleted file mode 100644 index 47753e16f..000000000 --- a/ui/app/components/pages/first-time-flow/welcome/welcome.container.js +++ /dev/null @@ -1,26 +0,0 @@ -import { connect } from 'react-redux' -import { withRouter } from 'react-router-dom' -import { compose } from 'recompose' -import { closeWelcomeScreen } from '../../../../actions' -import Welcome from './welcome.component' - -const mapStateToProps = ({ metamask }) => { - const { welcomeScreenSeen, isInitialized, participateInMetaMetrics } = metamask - - return { - welcomeScreenSeen, - isInitialized, - participateInMetaMetrics, - } -} - -const mapDispatchToProps = dispatch => { - return { - closeWelcomeScreen: () => dispatch(closeWelcomeScreen()), - } -} - -export default compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(Welcome) diff --git a/ui/app/components/pages/home/home.component.js b/ui/app/components/pages/home/home.component.js deleted file mode 100644 index 953d43aba..000000000 --- a/ui/app/components/pages/home/home.component.js +++ /dev/null @@ -1,77 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import Media from 'react-media' -import { Redirect } from 'react-router-dom' -import WalletView from '../../wallet-view' -import TransactionView from '../../transaction-view' -import ProviderApproval from '../provider-approval' - -import { - INITIALIZE_SEED_PHRASE_ROUTE, - RESTORE_VAULT_ROUTE, - CONFIRM_TRANSACTION_ROUTE, - CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE, -} from '../../../routes' - -export default class Home extends PureComponent { - static propTypes = { - history: PropTypes.object, - forgottenPassword: PropTypes.bool, - seedWords: PropTypes.string, - suggestedTokens: PropTypes.object, - unconfirmedTransactionsCount: PropTypes.number, - providerRequests: PropTypes.array, - } - - componentDidMount () { - const { - history, - suggestedTokens = {}, - unconfirmedTransactionsCount = 0, - } = this.props - - // suggested new tokens - if (Object.keys(suggestedTokens).length > 0) { - history.push(CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE) - } - - if (unconfirmedTransactionsCount > 0) { - history.push(CONFIRM_TRANSACTION_ROUTE) - } - } - - render () { - const { - forgottenPassword, - seedWords, - providerRequests, - } = this.props - - // seed words - if (seedWords) { - return <Redirect to={{ pathname: INITIALIZE_SEED_PHRASE_ROUTE }}/> - } - - if (forgottenPassword) { - return <Redirect to={{ pathname: RESTORE_VAULT_ROUTE }} /> - } - - if (providerRequests && providerRequests.length > 0) { - return ( - <ProviderApproval providerRequest={providerRequests[0]} /> - ) - } - - return ( - <div className="main-container"> - <div className="account-and-transaction-details"> - <Media - query="(min-width: 576px)" - render={() => <WalletView />} - /> - <TransactionView /> - </div> - </div> - ) - } -} diff --git a/ui/app/components/pages/home/home.container.js b/ui/app/components/pages/home/home.container.js deleted file mode 100644 index bb8cf5e81..000000000 --- a/ui/app/components/pages/home/home.container.js +++ /dev/null @@ -1,32 +0,0 @@ -import Home from './home.component' -import { compose } from 'recompose' -import { connect } from 'react-redux' -import { withRouter } from 'react-router-dom' -import { unconfirmedTransactionsCountSelector } from '../../../selectors/confirm-transaction' - -const mapStateToProps = state => { - const { metamask, appState } = state - const { - noActiveNotices, - lostAccounts, - seedWords, - suggestedTokens, - providerRequests, - } = metamask - const { forgottenPassword } = appState - - return { - noActiveNotices, - lostAccounts, - forgottenPassword, - seedWords, - suggestedTokens, - unconfirmedTransactionsCount: unconfirmedTransactionsCountSelector(state), - providerRequests, - } -} - -export default compose( - withRouter, - connect(mapStateToProps) -)(Home) diff --git a/ui/app/components/pages/home/index.js b/ui/app/components/pages/home/index.js deleted file mode 100644 index 4474ba5b8..000000000 --- a/ui/app/components/pages/home/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './home.container' diff --git a/ui/app/components/pages/index.scss b/ui/app/components/pages/index.scss deleted file mode 100644 index 6a0680f32..000000000 --- a/ui/app/components/pages/index.scss +++ /dev/null @@ -1,11 +0,0 @@ -@import './unlock-page/index'; - -@import './add-token/index'; - -@import './confirm-add-token/index'; - -@import './settings/index'; - -@import './first-time-flow/index'; - -@import './keychains/index'; diff --git a/ui/app/components/pages/keychains/index.scss b/ui/app/components/pages/keychains/index.scss deleted file mode 100644 index 868185419..000000000 --- a/ui/app/components/pages/keychains/index.scss +++ /dev/null @@ -1,197 +0,0 @@ -.first-view-main-wrapper { - display: flex; - width: 100%; - height: 100%; - justify-content: center; - padding: 0 10px; -} - -.first-view-main { - display: flex; - flex-direction: row; - justify-content: flex-start; -} - -@media screen and (min-width: 1281px) { - .first-view-main { - width: 62vw; - } -} - -.import-account { - display: flex; - flex-flow: column nowrap; - margin: 60px 0 30px 0; - position: relative; - max-width: initial; -} - -@media only screen and (max-width: 575px) { - .import-account{ - margin: 24px; - display: flex; - flex-flow: column nowrap; - width: calc(100vw - 80px); - } - - .import-account__title { - width: initial !important; - } - - .first-view-main { - height: 100%; - flex-direction: column; - align-items: center; - justify-content: flex-start; - margin-top: 12px; - } - - .first-view-phone-invisible { - display: none; - } - - .first-time-flow__input { - width: 100%; - } - - .import-account__secret-phrase { - width: initial !important; - height: initial !important; - min-height: 190px; - } -} - -.import-account__title { - color: #1B344D; - font-size: 40px; - line-height: 51px; - margin-bottom: 10px; -} - -.import-account__back-button { - margin-bottom: 18px; - color: #22232c; - font-size: 16px; - line-height: 21px; - position: absolute; - top: -25px; -} - -.import-account__secret-phrase { - height: 190px; - width: 495px; - border: 1px solid #CDCDCD; - border-radius: 6px; - background-color: #FFFFFF; - padding: 17px; - font-size: 16px; -} - -.import-account__secret-phrase::placeholder { - color: #9B9B9B; - font-weight: 200; -} - -.import-account__faq-link { - font-size: 18px; - line-height: 23px; - font-family: Roboto; -} - -.import-account__selector-label { - color: #1B344D; - font-size: 16px; -} - -.import-account__dropdown { - width: 325px; - border: 1px solid #CDCDCD; - border-radius: 4px; - background-color: #FFFFFF; - margin-top: 14px; - color: #5B5D67; - font-family: Roboto; - font-size: 18px; - line-height: 23px; - padding: 14px 21px; - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - cursor: pointer; -} - -.import-account__description-text { - color: #757575; - font-size: 18px; - line-height: 23px; - margin-top: 21px; - font-family: Roboto; -} - -.import-account__input-wrapper { - display: flex; - flex-flow: column nowrap; - margin-top: 30px; -} - -.import-account__input-error-message { - margin-top: 10px; - width: 422px; - color: #FF001F; - font-size: 16px; - line-height: 21px; -} - -.import-account__input-label { - margin-bottom: 9px; - color: #1B344D; - font-size: 18px; - line-height: 23px; -} - -.import-account__input-label__disabled { - opacity: 0.5; -} - -.import-account__input { - width: 350px; -} - -@media only screen and (max-width: 575px) { - .import-account__input { - width: 100%; - } -} - -.import-account__file-input { - display: none; -} - -.import-account__file-input-label { - height: 53px; - width: 148px; - border: 1px solid #1B344D; - border-radius: 4px; - color: #1B344D; - font-family: Roboto; - font-size: 18px; - display: flex; - flex-flow: column nowrap; - align-items: center; - justify-content: center; - cursor: pointer; -} - -.import-account__file-picker-wrapper { - display: flex; - flex-flow: row nowrap; - align-items: center; -} - -.import-account__file-name { - color: #000000; - font-family: Roboto; - font-size: 18px; - line-height: 23px; - margin-left: 22px; -} diff --git a/ui/app/components/pages/keychains/restore-vault.js b/ui/app/components/pages/keychains/restore-vault.js deleted file mode 100644 index 73ff5191a..000000000 --- a/ui/app/components/pages/keychains/restore-vault.js +++ /dev/null @@ -1,197 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import {connect} from 'react-redux' -import { - createNewVaultAndRestore, - unMarkPasswordForgotten, -} from '../../../actions' -import { DEFAULT_ROUTE } from '../../../routes' -import TextField from '../../text-field' -import Button from '../../button' - -class RestoreVaultPage extends Component { - static contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, - } - - static propTypes = { - warning: PropTypes.string, - createNewVaultAndRestore: PropTypes.func.isRequired, - leaveImportSeedScreenState: PropTypes.func, - history: PropTypes.object, - isLoading: PropTypes.bool, - }; - - state = { - seedPhrase: '', - password: '', - confirmPassword: '', - seedPhraseError: null, - passwordError: null, - confirmPasswordError: null, - } - - parseSeedPhrase = (seedPhrase) => { - return seedPhrase - .match(/\w+/g) - .join(' ') - } - - handleSeedPhraseChange (seedPhrase) { - let seedPhraseError = null - - if (seedPhrase && this.parseSeedPhrase(seedPhrase).split(' ').length !== 12) { - seedPhraseError = this.context.t('seedPhraseReq') - } - - this.setState({ seedPhrase, seedPhraseError }) - } - - handlePasswordChange (password) { - const { confirmPassword } = this.state - let confirmPasswordError = null - let passwordError = null - - if (password && password.length < 8) { - passwordError = this.context.t('passwordNotLongEnough') - } - - if (confirmPassword && password !== confirmPassword) { - confirmPasswordError = this.context.t('passwordsDontMatch') - } - - this.setState({ password, passwordError, confirmPasswordError }) - } - - handleConfirmPasswordChange (confirmPassword) { - const { password } = this.state - let confirmPasswordError = null - - if (password !== confirmPassword) { - confirmPasswordError = this.context.t('passwordsDontMatch') - } - - this.setState({ confirmPassword, confirmPasswordError }) - } - - onClick = () => { - const { password, seedPhrase } = this.state - const { - createNewVaultAndRestore, - leaveImportSeedScreenState, - history, - } = this.props - - leaveImportSeedScreenState() - createNewVaultAndRestore(password, this.parseSeedPhrase(seedPhrase)) - .then(() => { - this.context.metricsEvent({ - eventOpts: { - category: 'Retention', - action: 'userEntersSeedPhrase', - name: 'onboardingRestoredVault', - }, - }) - history.push(DEFAULT_ROUTE) - }) - } - - hasError () { - const { passwordError, confirmPasswordError, seedPhraseError } = this.state - return passwordError || confirmPasswordError || seedPhraseError - } - - render () { - const { - seedPhrase, - password, - confirmPassword, - seedPhraseError, - passwordError, - confirmPasswordError, - } = this.state - const { t } = this.context - const { isLoading } = this.props - const disabled = !seedPhrase || !password || !confirmPassword || isLoading || this.hasError() - - return ( - <div className="first-view-main-wrapper"> - <div className="first-view-main"> - <div className="import-account"> - <a - className="import-account__back-button" - onClick={e => { - e.preventDefault() - this.props.history.goBack() - }} - href="#" - > - {`< Back`} - </a> - <div className="import-account__title"> - { this.context.t('restoreAccountWithSeed') } - </div> - <div className="import-account__selector-label"> - { this.context.t('secretPhrase') } - </div> - <div className="import-account__input-wrapper"> - <label className="import-account__input-label">Wallet Seed</label> - <textarea - className="import-account__secret-phrase" - onChange={e => this.handleSeedPhraseChange(e.target.value)} - value={this.state.seedPhrase} - placeholder={this.context.t('separateEachWord')} - /> - </div> - <span className="error"> - { seedPhraseError } - </span> - <TextField - id="password" - label={t('newPassword')} - type="password" - className="first-time-flow__input" - value={this.state.password} - onChange={event => this.handlePasswordChange(event.target.value)} - error={passwordError} - autoComplete="new-password" - margin="normal" - largeLabel - /> - <TextField - id="confirm-password" - label={t('confirmPassword')} - type="password" - className="first-time-flow__input" - value={this.state.confirmPassword} - onChange={event => this.handleConfirmPasswordChange(event.target.value)} - error={confirmPasswordError} - autoComplete="confirm-password" - margin="normal" - largeLabel - /> - <Button - type="first-time" - className="first-time-flow__button" - onClick={() => !disabled && this.onClick()} - disabled={disabled} - > - {this.context.t('restore')} - </Button> - </div> - </div> - </div> - ) - } -} - -export default connect( - ({ appState: { warning, isLoading } }) => ({ warning, isLoading }), - dispatch => ({ - leaveImportSeedScreenState: () => { - dispatch(unMarkPasswordForgotten()) - }, - createNewVaultAndRestore: (pw, seed) => dispatch(createNewVaultAndRestore(pw, seed)), - }) -)(RestoreVaultPage) diff --git a/ui/app/components/pages/keychains/reveal-seed.js b/ui/app/components/pages/keychains/reveal-seed.js deleted file mode 100644 index 32557066f..000000000 --- a/ui/app/components/pages/keychains/reveal-seed.js +++ /dev/null @@ -1,177 +0,0 @@ -const { Component } = require('react') -const { connect } = require('react-redux') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const classnames = require('classnames') - -const { requestRevealSeedWords } = require('../../../actions') -const { DEFAULT_ROUTE } = require('../../../routes') -const ExportTextContainer = require('../../export-text-container') - -import Button from '../../button' - -const PASSWORD_PROMPT_SCREEN = 'PASSWORD_PROMPT_SCREEN' -const REVEAL_SEED_SCREEN = 'REVEAL_SEED_SCREEN' - -class RevealSeedPage extends Component { - constructor (props) { - super(props) - - this.state = { - screen: PASSWORD_PROMPT_SCREEN, - password: '', - seedWords: null, - error: null, - } - } - - componentDidMount () { - const passwordBox = document.getElementById('password-box') - if (passwordBox) { - passwordBox.focus() - } - } - - handleSubmit (event) { - event.preventDefault() - this.setState({ seedWords: null, error: null }) - this.props.requestRevealSeedWords(this.state.password) - .then(seedWords => this.setState({ seedWords, screen: REVEAL_SEED_SCREEN })) - .catch(error => this.setState({ error: error.message })) - } - - renderWarning () { - return ( - h('.page-container__warning-container', [ - h('img.page-container__warning-icon', { - src: 'images/warning.svg', - }), - h('.page-container__warning-message', [ - h('.page-container__warning-title', [this.context.t('revealSeedWordsWarningTitle')]), - h('div', [this.context.t('revealSeedWordsWarning')]), - ]), - ]) - ) - } - - renderContent () { - return this.state.screen === PASSWORD_PROMPT_SCREEN - ? this.renderPasswordPromptContent() - : this.renderRevealSeedContent() - } - - renderPasswordPromptContent () { - const { t } = this.context - - return ( - h('form', { - onSubmit: event => this.handleSubmit(event), - }, [ - h('label.input-label', { - htmlFor: 'password-box', - }, t('enterPasswordContinue')), - h('.input-group', [ - h('input.form-control', { - type: 'password', - placeholder: t('password'), - id: 'password-box', - value: this.state.password, - onChange: event => this.setState({ password: event.target.value }), - className: classnames({ 'form-control--error': this.state.error }), - }), - ]), - this.state.error && h('.reveal-seed__error', this.state.error), - ]) - ) - } - - renderRevealSeedContent () { - const { t } = this.context - - return ( - h('div', [ - h('label.reveal-seed__label', t('yourPrivateSeedPhrase')), - h(ExportTextContainer, { - text: this.state.seedWords, - filename: t('metamaskSeedWords'), - }), - ]) - ) - } - - renderFooter () { - return this.state.screen === PASSWORD_PROMPT_SCREEN - ? this.renderPasswordPromptFooter() - : this.renderRevealSeedFooter() - } - - renderPasswordPromptFooter () { - return ( - h('.page-container__footer', [ - h('header', [ - h(Button, { - type: 'default', - large: true, - className: 'page-container__footer-button', - onClick: () => this.props.history.push(DEFAULT_ROUTE), - }, this.context.t('cancel')), - h(Button, { - type: 'primary', - large: true, - className: 'page-container__footer-button', - onClick: event => this.handleSubmit(event), - disabled: this.state.password === '', - }, this.context.t('next')), - ]), - ]) - ) - } - - renderRevealSeedFooter () { - return ( - h('.page-container__footer', [ - h(Button, { - type: 'default', - large: true, - className: 'page-container__footer-button', - onClick: () => this.props.history.push(DEFAULT_ROUTE), - }, this.context.t('close')), - ]) - ) - } - - render () { - return ( - h('.page-container', [ - h('.page-container__header', [ - h('.page-container__title', this.context.t('revealSeedWordsTitle')), - h('.page-container__subtitle', this.context.t('revealSeedWordsDescription')), - ]), - h('.page-container__content', [ - this.renderWarning(), - h('.reveal-seed__content', [ - this.renderContent(), - ]), - ]), - this.renderFooter(), - ]) - ) - } -} - -RevealSeedPage.propTypes = { - requestRevealSeedWords: PropTypes.func, - history: PropTypes.object, -} - -RevealSeedPage.contextTypes = { - t: PropTypes.func, -} - -const mapDispatchToProps = dispatch => { - return { - requestRevealSeedWords: password => dispatch(requestRevealSeedWords(password)), - } -} - -module.exports = connect(null, mapDispatchToProps)(RevealSeedPage) diff --git a/ui/app/components/pages/lock/index.js b/ui/app/components/pages/lock/index.js deleted file mode 100644 index 7bfe2a61f..000000000 --- a/ui/app/components/pages/lock/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './lock.container' diff --git a/ui/app/components/pages/lock/lock.component.js b/ui/app/components/pages/lock/lock.component.js deleted file mode 100644 index 51f8742ed..000000000 --- a/ui/app/components/pages/lock/lock.component.js +++ /dev/null @@ -1,26 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import Loading from '../../loading-screen' -import { DEFAULT_ROUTE } from '../../../routes' - -export default class Lock extends PureComponent { - static propTypes = { - history: PropTypes.object, - isUnlocked: PropTypes.bool, - lockMetamask: PropTypes.func, - } - - componentDidMount () { - const { lockMetamask, isUnlocked, history } = this.props - - if (isUnlocked) { - lockMetamask().then(() => history.push(DEFAULT_ROUTE)) - } else { - history.replace(DEFAULT_ROUTE) - } - } - - render () { - return <Loading /> - } -} diff --git a/ui/app/components/pages/lock/lock.container.js b/ui/app/components/pages/lock/lock.container.js deleted file mode 100644 index 81d89ba21..000000000 --- a/ui/app/components/pages/lock/lock.container.js +++ /dev/null @@ -1,24 +0,0 @@ -import Lock from './lock.component' -import { compose } from 'recompose' -import { connect } from 'react-redux' -import { withRouter } from 'react-router-dom' -import { lockMetamask } from '../../../actions' - -const mapStateToProps = state => { - const { metamask: { isUnlocked } } = state - - return { - isUnlocked, - } -} - -const mapDispatchToProps = dispatch => { - return { - lockMetamask: () => dispatch(lockMetamask()), - } -} - -export default compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(Lock) diff --git a/ui/app/components/pages/mobile-sync/index.js b/ui/app/components/pages/mobile-sync/index.js deleted file mode 100644 index 22a69d092..000000000 --- a/ui/app/components/pages/mobile-sync/index.js +++ /dev/null @@ -1,387 +0,0 @@ -const { Component } = require('react') -const { connect } = require('react-redux') -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const classnames = require('classnames') -const PubNub = require('pubnub') - -const { requestRevealSeedWords, fetchInfoToSync } = require('../../../actions') -const { DEFAULT_ROUTE } = require('../../../routes') -const actions = require('../../../actions') - -const qrCode = require('qrcode-generator') - -import Button from '../../button' -import LoadingScreen from '../../loading-screen' - -const PASSWORD_PROMPT_SCREEN = 'PASSWORD_PROMPT_SCREEN' -const REVEAL_SEED_SCREEN = 'REVEAL_SEED_SCREEN' - -class MobileSyncPage extends Component { - static propTypes = { - history: PropTypes.object, - selectedAddress: PropTypes.string, - displayWarning: PropTypes.func, - fetchInfoToSync: PropTypes.func, - requestRevealSeedWords: PropTypes.func, - } - - constructor (props) { - super(props) - - this.state = { - screen: PASSWORD_PROMPT_SCREEN, - password: '', - seedWords: null, - error: null, - syncing: false, - completed: false, - } - - this.syncing = false - } - - componentDidMount () { - const passwordBox = document.getElementById('password-box') - if (passwordBox) { - passwordBox.focus() - } - } - - handleSubmit (event) { - event.preventDefault() - this.setState({ seedWords: null, error: null }) - this.props.requestRevealSeedWords(this.state.password) - .then(seedWords => { - this.generateCipherKeyAndChannelName() - this.setState({ seedWords, screen: REVEAL_SEED_SCREEN }) - this.initWebsockets() - }) - .catch(error => this.setState({ error: error.message })) - } - - generateCipherKeyAndChannelName () { - this.cipherKey = `${this.props.selectedAddress.substr(-4)}-${PubNub.generateUUID()}` - this.channelName = `mm-${PubNub.generateUUID()}` - } - - initWebsockets () { - this.pubnub = new PubNub({ - subscribeKey: process.env.PUBNUB_SUB_KEY, - publishKey: process.env.PUBNUB_PUB_KEY, - cipherKey: this.cipherKey, - ssl: true, - }) - - this.pubnubListener = this.pubnub.addListener({ - message: (data) => { - const {channel, message} = data - // handle message - if (channel !== this.channelName || !message) { - return false - } - - if (message.event === 'start-sync') { - this.startSyncing() - } else if (message.event === 'end-sync') { - this.disconnectWebsockets() - this.setState({syncing: false, completed: true}) - } - }, - }) - - this.pubnub.subscribe({ - channels: [this.channelName], - withPresence: false, - }) - - } - - disconnectWebsockets () { - if (this.pubnub && this.pubnubListener) { - this.pubnub.disconnect(this.pubnubListener) - } - } - - // Calculating a PubNub Message Payload Size. - calculatePayloadSize (channel, message) { - return encodeURIComponent( - channel + JSON.stringify(message) - ).length + 100 - } - - chunkString (str, size) { - const numChunks = Math.ceil(str.length / size) - const chunks = new Array(numChunks) - for (let i = 0, o = 0; i < numChunks; ++i, o += size) { - chunks[i] = str.substr(o, size) - } - return chunks - } - - notifyError (errorMsg) { - return new Promise((resolve, reject) => { - this.pubnub.publish( - { - message: { - event: 'error-sync', - data: errorMsg, - }, - channel: this.channelName, - sendByPost: false, // true to send via post - storeInHistory: false, - }, - (status, response) => { - if (!status.error) { - resolve() - } else { - reject(response) - } - }) - }) - } - - async startSyncing () { - if (this.syncing) return false - this.syncing = true - this.setState({syncing: true}) - - const { accounts, network, preferences, transactions } = await this.props.fetchInfoToSync() - - const allDataStr = JSON.stringify({ - accounts, - network, - preferences, - transactions, - udata: { - pwd: this.state.password, - seed: this.state.seedWords, - }, - }) - - const chunks = this.chunkString(allDataStr, 17000) - const totalChunks = chunks.length - try { - for (let i = 0; i < totalChunks; i++) { - await this.sendMessage(chunks[i], i + 1, totalChunks) - } - } catch (e) { - this.props.displayWarning('Sync failed :(') - this.setState({syncing: false}) - this.syncing = false - this.notifyError(e.toString()) - } - } - - sendMessage (data, pkg, count) { - return new Promise((resolve, reject) => { - this.pubnub.publish( - { - message: { - event: 'syncing-data', - data, - totalPkg: count, - currentPkg: pkg, - }, - channel: this.channelName, - sendByPost: false, // true to send via post - storeInHistory: false, - }, - (status, response) => { - if (!status.error) { - resolve() - } else { - reject(response) - } - } - ) - }) - } - - - componentWillUnmount () { - this.disconnectWebsockets() - } - - renderWarning (text) { - return ( - h('.page-container__warning-container', [ - h('.page-container__warning-message', [ - h('div', [text]), - ]), - ]) - ) - } - - renderContent () { - const { t } = this.context - - if (this.state.syncing) { - return h(LoadingScreen, {loadingMessage: 'Sync in progress'}) - } - - if (this.state.completed) { - return h('div.reveal-seed__content', {}, - h('label.reveal-seed__label', { - style: { - width: '100%', - textAlign: 'center', - }, - }, t('syncWithMobileComplete')), - ) - } - - return this.state.screen === PASSWORD_PROMPT_SCREEN - ? h('div', {}, [ - this.renderWarning(this.context.t('mobileSyncText')), - h('.reveal-seed__content', [ - this.renderPasswordPromptContent(), - ]), - ]) - : h('div', {}, [ - this.renderWarning(this.context.t('syncWithMobileBeCareful')), - h('.reveal-seed__content', [ this.renderRevealSeedContent() ]), - ]) - } - - renderPasswordPromptContent () { - const { t } = this.context - - return ( - h('form', { - onSubmit: event => this.handleSubmit(event), - }, [ - h('label.input-label', { - htmlFor: 'password-box', - }, t('enterPasswordContinue')), - h('.input-group', [ - h('input.form-control', { - type: 'password', - placeholder: t('password'), - id: 'password-box', - value: this.state.password, - onChange: event => this.setState({ password: event.target.value }), - className: classnames({ 'form-control--error': this.state.error }), - }), - ]), - this.state.error && h('.reveal-seed__error', this.state.error), - ]) - ) - } - - renderRevealSeedContent () { - - const qrImage = qrCode(0, 'M') - qrImage.addData(`metamask-sync:${this.channelName}|@|${this.cipherKey}`) - qrImage.make() - - const { t } = this.context - return ( - h('div', [ - h('label.reveal-seed__label', { - style: { - width: '100%', - textAlign: 'center', - }, - }, t('syncWithMobileScanThisCode')), - h('.div.qr-wrapper', { - style: { - display: 'flex', - justifyContent: 'center', - }, - dangerouslySetInnerHTML: { - __html: qrImage.createTableTag(4), - }, - }), - ]) - ) - } - - renderFooter () { - return this.state.screen === PASSWORD_PROMPT_SCREEN - ? this.renderPasswordPromptFooter() - : this.renderRevealSeedFooter() - } - - renderPasswordPromptFooter () { - return ( - h('div.new-account-import-form__buttons', {style: {padding: 30}}, [ - - h(Button, { - type: 'default', - large: true, - className: 'new-account-create-form__button', - onClick: () => this.props.history.push(DEFAULT_ROUTE), - }, this.context.t('cancel')), - - h(Button, { - type: 'primary', - large: true, - className: 'new-account-create-form__button', - onClick: event => this.handleSubmit(event), - disabled: this.state.password === '', - }, this.context.t('next')), - ]) - ) - } - - renderRevealSeedFooter () { - return ( - h('.page-container__footer', {style: {padding: 30}}, [ - h(Button, { - type: 'default', - large: true, - className: 'page-container__footer-button', - onClick: () => this.props.history.push(DEFAULT_ROUTE), - }, this.context.t('close')), - ]) - ) - } - - render () { - return ( - h('.page-container', [ - h('.page-container__header', [ - h('.page-container__title', this.context.t('syncWithMobileTitle')), - this.state.screen === PASSWORD_PROMPT_SCREEN ? h('.page-container__subtitle', this.context.t('syncWithMobileDesc')) : null, - this.state.screen === PASSWORD_PROMPT_SCREEN ? h('.page-container__subtitle', this.context.t('syncWithMobileDescNewUsers')) : null, - ]), - h('.page-container__content', [ - this.renderContent(), - ]), - this.renderFooter(), - ]) - ) - } -} - -MobileSyncPage.propTypes = { - requestRevealSeedWords: PropTypes.func, - fetchInfoToSync: PropTypes.func, - history: PropTypes.object, -} - -MobileSyncPage.contextTypes = { - t: PropTypes.func, -} - -const mapDispatchToProps = dispatch => { - return { - requestRevealSeedWords: password => dispatch(requestRevealSeedWords(password)), - fetchInfoToSync: () => dispatch(fetchInfoToSync()), - displayWarning: (message) => dispatch(actions.displayWarning(message || null)), - } - -} - -const mapStateToProps = state => { - const { - metamask: { selectedAddress }, - } = state - - return { - selectedAddress, - } -} - -module.exports = connect(mapStateToProps, mapDispatchToProps)(MobileSyncPage) 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/pages/provider-approval/index.js b/ui/app/components/pages/provider-approval/index.js deleted file mode 100644 index 4162f3155..000000000 --- a/ui/app/components/pages/provider-approval/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './provider-approval.container' diff --git a/ui/app/components/pages/provider-approval/provider-approval.component.js b/ui/app/components/pages/provider-approval/provider-approval.component.js deleted file mode 100644 index 11895327a..000000000 --- a/ui/app/components/pages/provider-approval/provider-approval.component.js +++ /dev/null @@ -1,29 +0,0 @@ -import PropTypes from 'prop-types' -import React, { Component } from 'react' -import ProviderPageContainer from '../../provider-page-container' - -export default class ProviderApproval extends Component { - static propTypes = { - approveProviderRequest: PropTypes.func.isRequired, - providerRequest: PropTypes.object.isRequired, - rejectProviderRequest: PropTypes.func.isRequired, - }; - - static contextTypes = { - t: PropTypes.func, - }; - - render () { - const { approveProviderRequest, providerRequest, rejectProviderRequest } = this.props - return ( - <ProviderPageContainer - approveProviderRequest={approveProviderRequest} - origin={providerRequest.origin} - tabID={providerRequest.tabID} - rejectProviderRequest={rejectProviderRequest} - siteImage={providerRequest.siteImage} - siteTitle={providerRequest.siteTitle} - /> - ) - } -} diff --git a/ui/app/components/pages/provider-approval/provider-approval.container.js b/ui/app/components/pages/provider-approval/provider-approval.container.js deleted file mode 100644 index 28e4531a9..000000000 --- a/ui/app/components/pages/provider-approval/provider-approval.container.js +++ /dev/null @@ -1,12 +0,0 @@ -import { connect } from 'react-redux' -import ProviderApproval from './provider-approval.component' -import { approveProviderRequest, rejectProviderRequest } from '../../../actions' - -function mapDispatchToProps (dispatch) { - return { - approveProviderRequest: tabID => dispatch(approveProviderRequest(tabID)), - rejectProviderRequest: tabID => dispatch(rejectProviderRequest(tabID)), - } -} - -export default connect(null, mapDispatchToProps)(ProviderApproval) diff --git a/ui/app/components/pages/settings/index.js b/ui/app/components/pages/settings/index.js deleted file mode 100644 index 44a9ffa63..000000000 --- a/ui/app/components/pages/settings/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './settings.component' diff --git a/ui/app/components/pages/settings/index.scss b/ui/app/components/pages/settings/index.scss deleted file mode 100644 index 138ebcfc5..000000000 --- a/ui/app/components/pages/settings/index.scss +++ /dev/null @@ -1,80 +0,0 @@ -@import './info-tab/index'; - -@import './settings-tab/index'; - -.settings-page { - position: relative; - background: $white; - display: flex; - flex-flow: column nowrap; - - &__header { - padding: 25px 25px 0; - } - - &__close-button::after { - content: '\00D7'; - font-size: 40px; - color: $dusty-gray; - position: absolute; - top: 25px; - right: 30px; - cursor: pointer; - } - - &__content { - padding: 25px; - height: auto; - overflow: auto; - } - - &__content-row { - display: flex; - flex-direction: row; - padding: 10px 0 20px; - - @media screen and (max-width: 575px) { - flex-direction: column; - padding: 10px 0; - } - } - - &__content-item { - flex: 1; - min-width: 0; - display: flex; - flex-direction: column; - padding: 0 5px; - min-height: 71px; - - @media screen and (max-width: 575px) { - height: initial; - padding: 5px 0; - } - - &--without-height { - height: initial; - } - } - - &__content-label { - text-transform: capitalize; - } - - &__content-description { - font-size: 14px; - color: $dusty-gray; - padding-top: 5px; - } - - &__content-item-col { - max-width: 300px; - display: flex; - flex-direction: column; - - @media screen and (max-width: 575px) { - max-width: 100%; - width: 100%; - } - } -} diff --git a/ui/app/components/pages/settings/info-tab/index.js b/ui/app/components/pages/settings/info-tab/index.js deleted file mode 100644 index 7556a258d..000000000 --- a/ui/app/components/pages/settings/info-tab/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './info-tab.component' diff --git a/ui/app/components/pages/settings/info-tab/index.scss b/ui/app/components/pages/settings/info-tab/index.scss deleted file mode 100644 index 43ad6f652..000000000 --- a/ui/app/components/pages/settings/info-tab/index.scss +++ /dev/null @@ -1,56 +0,0 @@ -.info-tab { - &__logo-wrapper { - height: 80px; - margin-bottom: 20px; - } - - &__logo { - max-height: 100%; - max-width: 100%; - } - - &__item { - padding: 10px 0; - } - - &__link-header { - padding-bottom: 15px; - - @media screen and (max-width: 575px) { - padding-bottom: 5px; - } - } - - &__link-item { - padding: 15px 0; - - @media screen and (max-width: 575px) { - padding: 5px 0; - } - } - - &__link-text { - color: $curious-blue; - } - - &__version-number { - padding-top: 5px; - font-size: 13px; - color: $dusty-gray; - } - - &__separator { - margin: 15px 0; - width: 80px; - border-color: $alto; - border: none; - height: 1px; - background-color: $alto; - color: $alto; - } - - &__about { - color: $dusty-gray; - margin-bottom: 15px; - } -} diff --git a/ui/app/components/pages/settings/info-tab/info-tab.component.js b/ui/app/components/pages/settings/info-tab/info-tab.component.js deleted file mode 100644 index 72f7d835e..000000000 --- a/ui/app/components/pages/settings/info-tab/info-tab.component.js +++ /dev/null @@ -1,136 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' - -export default class InfoTab extends PureComponent { - state = { - version: global.platform.getVersion(), - } - - static propTypes = { - tab: PropTypes.string, - metamask: PropTypes.object, - setCurrentCurrency: PropTypes.func, - setRpcTarget: PropTypes.func, - displayWarning: PropTypes.func, - revealSeedConfirmation: PropTypes.func, - warning: PropTypes.string, - location: PropTypes.object, - history: PropTypes.object, - } - - static contextTypes = { - t: PropTypes.func, - } - - renderInfoLinks () { - const { t } = this.context - - return ( - <div className="settings-page__content-item settings-page__content-item--without-height"> - <div className="info-tab__link-header"> - { t('links') } - </div> - <div className="info-tab__link-item"> - <a - href="https://metamask.io/privacy.html" - target="_blank" - rel="noopener noreferrer" - > - <span className="info-tab__link-text"> - { t('privacyMsg') } - </span> - </a> - </div> - <div className="info-tab__link-item"> - <a - href="https://metamask.io/terms.html" - target="_blank" - rel="noopener noreferrer" - > - <span className="info-tab__link-text"> - { t('terms') } - </span> - </a> - </div> - <div className="info-tab__link-item"> - <a - href="https://metamask.io/attributions.html" - target="_blank" - rel="noopener noreferrer" - > - <span className="info-tab__link-text"> - { t('attributions') } - </span> - </a> - </div> - <hr className="info-tab__separator" /> - <div className="info-tab__link-item"> - <a - href="https://support.metamask.io" - target="_blank" - rel="noopener noreferrer" - > - <span className="info-tab__link-text"> - { t('supportCenter') } - </span> - </a> - </div> - <div className="info-tab__link-item"> - <a - href="https://metamask.io/" - target="_blank" - rel="noopener noreferrer" - > - <span className="info-tab__link-text"> - { t('visitWebSite') } - </span> - </a> - </div> - <div className="info-tab__link-item"> - <a - href="mailto:help@metamask.io?subject=Feedback" - target="_blank" - rel="noopener noreferrer" - > - <span className="info-tab__link-text"> - { t('emailUs') } - </span> - </a> - </div> - </div> - ) - } - - render () { - const { t } = this.context - - return ( - <div className="settings-page__content"> - <div className="settings-page__content-row"> - <div className="settings-page__content-item settings-page__content-item--without-height"> - <div className="info-tab__logo-wrapper"> - <img - src="images/info-logo.png" - className="info-tab__logo" - /> - </div> - <div className="info-tab__item"> - <div className="info-tab__version-header"> - { t('metamaskVersion') } - </div> - <div className="info-tab__version-number"> - { this.state.version } - </div> - </div> - <div className="info-tab__item"> - <div className="info-tab__about"> - { t('builtInCalifornia') } - </div> - </div> - </div> - { this.renderInfoLinks() } - </div> - </div> - ) - } -} diff --git a/ui/app/components/pages/settings/settings-tab/index.js b/ui/app/components/pages/settings/settings-tab/index.js deleted file mode 100644 index 9fdaafd3f..000000000 --- a/ui/app/components/pages/settings/settings-tab/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './settings-tab.container' diff --git a/ui/app/components/pages/settings/settings-tab/index.scss b/ui/app/components/pages/settings/settings-tab/index.scss deleted file mode 100644 index ef32b0e4c..000000000 --- a/ui/app/components/pages/settings/settings-tab/index.scss +++ /dev/null @@ -1,69 +0,0 @@ -.settings-tab { - &__error { - padding-bottom: 20px; - text-align: center; - color: $crimson; - } - - &__advanced-link { - color: $curious-blue; - padding-left: 5px; - } - - &__rpc-save-button { - align-self: flex-end; - padding: 5px; - text-transform: uppercase; - color: $dusty-gray; - cursor: pointer; - width: 25%; - min-width: 80px; - height: 33px; - } - - &__button--red { - border-color: lighten($monzo, 10%); - color: $monzo; - - &:active { - background: lighten($monzo, 55%); - border-color: $monzo; - } - - &:hover { - border-color: $monzo; - } - } - - &__button--orange { - border-color: lighten($ecstasy, 20%); - color: $ecstasy; - - &:active { - background: lighten($ecstasy, 40%); - border-color: $ecstasy; - } - - &:hover { - border-color: $ecstasy; - } - } - - &__radio-buttons { - display: flex; - align-items: center; - } - - &__radio-button { - display: flex; - align-items: center; - - &:not(:last-child) { - margin-right: 16px; - } - } - - &__radio-label { - padding-left: 4px; - } -} diff --git a/ui/app/components/pages/settings/settings-tab/settings-tab.component.js b/ui/app/components/pages/settings/settings-tab/settings-tab.component.js deleted file mode 100644 index abddaaee8..000000000 --- a/ui/app/components/pages/settings/settings-tab/settings-tab.component.js +++ /dev/null @@ -1,679 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import infuraCurrencies from '../../../../infura-conversion.json' -import validUrl from 'valid-url' -import { exportAsFile } from '../../../../util' -import SimpleDropdown from '../../../dropdowns/simple-dropdown' -import ToggleButton from 'react-toggle-button' -import { REVEAL_SEED_ROUTE, MOBILE_SYNC_ROUTE } from '../../../../routes' -import locales from '../../../../../../app/_locales/index.json' -import TextField from '../../../text-field' -import Button from '../../../button' - -const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => { - return a.quote.name.toLocaleLowerCase().localeCompare(b.quote.name.toLocaleLowerCase()) -}) - -const infuraCurrencyOptions = sortedCurrencies.map(({ quote: { code, name } }) => { - return { - displayValue: `${code.toUpperCase()} - ${name}`, - key: code, - value: code, - } -}) - -const localeOptions = locales.map(locale => { - return { - displayValue: `${locale.name}`, - key: locale.code, - value: locale.code, - } -}) - -export default class SettingsTab extends PureComponent { - static contextTypes = { - t: PropTypes.func, - metricsEvent: PropTypes.func, - } - - static propTypes = { - metamask: PropTypes.object, - setUseBlockie: PropTypes.func, - setHexDataFeatureFlag: PropTypes.func, - setPrivacyMode: PropTypes.func, - privacyMode: PropTypes.bool, - setCurrentCurrency: PropTypes.func, - setRpcTarget: PropTypes.func, - delRpcTarget: PropTypes.func, - displayWarning: PropTypes.func, - revealSeedConfirmation: PropTypes.func, - setFeatureFlagToBeta: PropTypes.func, - showClearApprovalModal: PropTypes.func, - showResetAccountConfirmationModal: PropTypes.func, - warning: PropTypes.string, - history: PropTypes.object, - updateCurrentLocale: PropTypes.func, - currentLocale: PropTypes.string, - useBlockie: PropTypes.bool, - sendHexData: PropTypes.bool, - currentCurrency: PropTypes.string, - conversionDate: PropTypes.number, - nativeCurrency: PropTypes.string, - useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, - setUseNativeCurrencyAsPrimaryCurrencyPreference: PropTypes.func, - setAdvancedInlineGasFeatureFlag: PropTypes.func, - advancedInlineGas: PropTypes.bool, - mobileSync: PropTypes.bool, - showFiatInTestnets: PropTypes.bool, - setShowFiatConversionOnTestnetsPreference: PropTypes.func.isRequired, - participateInMetaMetrics: PropTypes.bool, - setParticipateInMetaMetrics: PropTypes.func, - } - - state = { - newRpc: '', - chainId: '', - showOptions: false, - ticker: '', - nickname: '', - } - - renderCurrentConversion () { - const { t } = this.context - const { currentCurrency, conversionDate, setCurrentCurrency } = this.props - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ t('currencyConversion') }</span> - <span className="settings-page__content-description"> - { t('updatedWithDate', [Date(conversionDate)]) } - </span> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <SimpleDropdown - placeholder={t('selectCurrency')} - options={infuraCurrencyOptions} - selectedOption={currentCurrency} - onSelect={newCurrency => setCurrentCurrency(newCurrency)} - /> - </div> - </div> - </div> - ) - } - - renderCurrentLocale () { - const { t } = this.context - const { updateCurrentLocale, currentLocale } = this.props - const currentLocaleMeta = locales.find(locale => locale.code === currentLocale) - const currentLocaleName = currentLocaleMeta ? currentLocaleMeta.name : '' - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span className="settings-page__content-label"> - { t('currentLanguage') } - </span> - <span className="settings-page__content-description"> - { currentLocaleName } - </span> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <SimpleDropdown - placeholder={t('selectLocale')} - options={localeOptions} - selectedOption={currentLocale} - onSelect={async newLocale => updateCurrentLocale(newLocale)} - /> - </div> - </div> - </div> - ) - } - - renderNewRpcUrl () { - const { t } = this.context - const { newRpc, chainId, ticker, nickname } = this.state - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ t('newNetwork') }</span> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <TextField - type="text" - id="new-rpc" - placeholder={t('rpcURL')} - value={newRpc} - onChange={e => this.setState({ newRpc: e.target.value })} - onKeyPress={e => { - if (e.key === 'Enter') { - this.validateRpc(newRpc, chainId, ticker, nickname) - } - }} - fullWidth - margin="dense" - /> - <TextField - type="text" - id="chainid" - placeholder={t('optionalChainId')} - value={chainId} - onChange={e => this.setState({ chainId: e.target.value })} - onKeyPress={e => { - if (e.key === 'Enter') { - this.validateRpc(newRpc, chainId, ticker, nickname) - } - }} - style={{ - display: this.state.showOptions ? null : 'none', - }} - fullWidth - margin="dense" - /> - <TextField - type="text" - id="ticker" - placeholder={t('optionalSymbol')} - value={ticker} - onChange={e => this.setState({ ticker: e.target.value })} - onKeyPress={e => { - if (e.key === 'Enter') { - this.validateRpc(newRpc, chainId, ticker, nickname) - } - }} - style={{ - display: this.state.showOptions ? null : 'none', - }} - fullWidth - margin="dense" - /> - <TextField - type="text" - id="nickname" - placeholder={t('optionalNickname')} - value={nickname} - onChange={e => this.setState({ nickname: e.target.value })} - onKeyPress={e => { - if (e.key === 'Enter') { - this.validateRpc(newRpc, chainId, ticker, nickname) - } - }} - style={{ - display: this.state.showOptions ? null : 'none', - }} - fullWidth - margin="dense" - /> - <div className="flex-row flex-align-center space-between"> - <span className="settings-tab__advanced-link" - onClick={e => { - e.preventDefault() - this.setState({ showOptions: !this.state.showOptions }) - }} - > - { t(this.state.showOptions ? 'hideAdvancedOptions' : 'showAdvancedOptions') } - </span> - <button - className="button btn-primary settings-tab__rpc-save-button" - onClick={e => { - e.preventDefault() - this.validateRpc(newRpc, chainId, ticker, nickname) - }} - > - { t('save') } - </button> - </div> - </div> - </div> - </div> - ) - } - - validateRpc (newRpc, chainId, ticker = 'ETH', nickname) { - const { setRpcTarget, displayWarning } = this.props - if (validUrl.isWebUri(newRpc)) { - this.context.metricsEvent({ - eventOpts: { - category: 'Settings', - action: 'Custom RPC', - name: 'Success', - }, - customVariables: { - networkId: newRpc, - chainId, - }, - }) - if (!!chainId && Number.isNaN(parseInt(chainId))) { - return displayWarning(`${this.context.t('invalidInput')} chainId`) - } - - setRpcTarget(newRpc, chainId, ticker, nickname) - } else { - this.context.metricsEvent({ - eventOpts: { - category: 'Settings', - action: 'Custom RPC', - name: 'Error', - }, - customVariables: { - networkId: newRpc, - chainId, - }, - }) - const appendedRpc = `http://${newRpc}` - - if (validUrl.isWebUri(appendedRpc)) { - displayWarning(this.context.t('uriErrorMsg')) - } else { - displayWarning(this.context.t('invalidRPC')) - } - } - } - - renderStateLogs () { - const { t } = this.context - const { displayWarning } = this.props - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ t('stateLogs') }</span> - <span className="settings-page__content-description"> - { t('stateLogsDescription') } - </span> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <Button - type="primary" - large - onClick={() => { - window.logStateString((err, result) => { - if (err) { - displayWarning(t('stateLogError')) - } else { - exportAsFile('MetaMask State Logs.json', result) - } - }) - }} - > - { t('downloadStateLogs') } - </Button> - </div> - </div> - </div> - ) - } - - renderClearApproval () { - const { t } = this.context - const { showClearApprovalModal } = this.props - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ t('approvalData') }</span> - <span className="settings-page__content-description"> - { t('approvalDataDescription') } - </span> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <Button - type="secondary" - large - className="settings-tab__button--orange" - onClick={event => { - event.preventDefault() - showClearApprovalModal() - }} - > - { t('clearApprovalData') } - </Button> - </div> - </div> - </div> - ) - } - - renderSeedWords () { - const { t } = this.context - const { history } = this.props - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ t('revealSeedWords') }</span> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <Button - type="secondary" - large - onClick={event => { - event.preventDefault() - this.context.metricsEvent({ - eventOpts: { - category: 'Settings', - action: 'Reveal Seed Phrase', - name: 'Reveal Seed Phrase', - }, - }) - history.push(REVEAL_SEED_ROUTE) - }} - > - { t('revealSeedWords') } - </Button> - </div> - </div> - </div> - ) - } - - - renderMobileSync () { - const { t } = this.context - const { history, mobileSync } = this.props - - if (!mobileSync) { - return - } - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ t('syncWithMobile') }</span> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <Button - type="primary" - large - onClick={event => { - event.preventDefault() - history.push(MOBILE_SYNC_ROUTE) - }} - > - { t('syncWithMobile') } - </Button> - </div> - </div> - </div> - ) - } - - - renderResetAccount () { - const { t } = this.context - const { showResetAccountConfirmationModal } = this.props - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ t('resetAccount') }</span> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <Button - type="secondary" - large - className="settings-tab__button--orange" - onClick={event => { - event.preventDefault() - this.context.metricsEvent({ - eventOpts: { - category: 'Settings', - action: 'Reset Account', - name: 'Reset Account', - }, - }) - showResetAccountConfirmationModal() - }} - > - { t('resetAccount') } - </Button> - </div> - </div> - </div> - ) - } - - renderBlockieOptIn () { - const { useBlockie, setUseBlockie } = this.props - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ this.context.t('blockiesIdenticon') }</span> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <ToggleButton - value={useBlockie} - onToggle={value => setUseBlockie(!value)} - activeLabel="" - inactiveLabel="" - /> - </div> - </div> - </div> - ) - } - - renderHexDataOptIn () { - const { t } = this.context - const { sendHexData, setHexDataFeatureFlag } = this.props - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ t('showHexData') }</span> - <div className="settings-page__content-description"> - { t('showHexDataDescription') } - </div> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <ToggleButton - value={sendHexData} - onToggle={value => setHexDataFeatureFlag(!value)} - activeLabel="" - inactiveLabel="" - /> - </div> - </div> - </div> - ) - } - - renderAdvancedGasInputInline () { - const { t } = this.context - const { advancedInlineGas, setAdvancedInlineGasFeatureFlag } = this.props - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ t('showAdvancedGasInline') }</span> - <div className="settings-page__content-description"> - { t('showAdvancedGasInlineDescription') } - </div> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <ToggleButton - value={advancedInlineGas} - onToggle={value => setAdvancedInlineGasFeatureFlag(!value)} - activeLabel="" - inactiveLabel="" - /> - </div> - </div> - </div> - ) - } - - renderUsePrimaryCurrencyOptions () { - const { t } = this.context - const { - nativeCurrency, - setUseNativeCurrencyAsPrimaryCurrencyPreference, - useNativeCurrencyAsPrimaryCurrency, - } = this.props - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ t('primaryCurrencySetting') }</span> - <div className="settings-page__content-description"> - { t('primaryCurrencySettingDescription') } - </div> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <div className="settings-tab__radio-buttons"> - <div className="settings-tab__radio-button"> - <input - type="radio" - id="native-primary-currency" - onChange={() => setUseNativeCurrencyAsPrimaryCurrencyPreference(true)} - checked={Boolean(useNativeCurrencyAsPrimaryCurrency)} - /> - <label - htmlFor="native-primary-currency" - className="settings-tab__radio-label" - > - { nativeCurrency } - </label> - </div> - <div className="settings-tab__radio-button"> - <input - type="radio" - id="fiat-primary-currency" - onChange={() => setUseNativeCurrencyAsPrimaryCurrencyPreference(false)} - checked={!useNativeCurrencyAsPrimaryCurrency} - /> - <label - htmlFor="fiat-primary-currency" - className="settings-tab__radio-label" - > - { t('fiat') } - </label> - </div> - </div> - </div> - </div> - </div> - ) - } - - renderShowConversionInTestnets () { - const { t } = this.context - const { - showFiatInTestnets, - setShowFiatConversionOnTestnetsPreference, - } = this.props - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ t('showFiatConversionInTestnets') }</span> - <div className="settings-page__content-description"> - { t('showFiatConversionInTestnetsDescription') } - </div> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <ToggleButton - value={showFiatInTestnets} - onToggle={value => setShowFiatConversionOnTestnetsPreference(!value)} - activeLabel="" - inactiveLabel="" - /> - </div> - </div> - </div> - ) - } - - renderPrivacyOptIn () { - const { t } = this.context - const { privacyMode, setPrivacyMode } = this.props - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ t('privacyMode') }</span> - <div className="settings-page__content-description"> - { t('privacyModeDescription') } - </div> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <ToggleButton - value={privacyMode} - onToggle={value => setPrivacyMode(!value)} - activeLabel="" - inactiveLabel="" - /> - </div> - </div> - </div> - ) - } - - renderMetaMetricsOptIn () { - const { t } = this.context - const { participateInMetaMetrics, setParticipateInMetaMetrics } = this.props - - return ( - <div className="settings-page__content-row"> - <div className="settings-page__content-item"> - <span>{ t('participateInMetaMetrics') }</span> - <div className="settings-page__content-description"> - <span>{ t('participateInMetaMetricsDescription') }</span> - </div> - </div> - <div className="settings-page__content-item"> - <div className="settings-page__content-item-col"> - <ToggleButton - value={participateInMetaMetrics} - onToggle={value => setParticipateInMetaMetrics(!value)} - activeLabel="" - inactiveLabel="" - /> - </div> - </div> - </div> - ) - } - - render () { - const { warning } = this.props - - return ( - <div className="settings-page__content"> - { warning && <div className="settings-tab__error">{ warning }</div> } - { this.renderCurrentConversion() } - { this.renderUsePrimaryCurrencyOptions() } - { this.renderShowConversionInTestnets() } - { this.renderCurrentLocale() } - { this.renderNewRpcUrl() } - { this.renderStateLogs() } - { this.renderSeedWords() } - { this.renderResetAccount() } - { this.renderClearApproval() } - { this.renderPrivacyOptIn() } - { this.renderHexDataOptIn() } - { this.renderAdvancedGasInputInline() } - { this.renderBlockieOptIn() } - { this.renderMobileSync() } - { this.renderMetaMetricsOptIn() } - </div> - ) - } -} diff --git a/ui/app/components/pages/settings/settings-tab/settings-tab.container.js b/ui/app/components/pages/settings/settings-tab/settings-tab.container.js deleted file mode 100644 index 64c256412..000000000 --- a/ui/app/components/pages/settings/settings-tab/settings-tab.container.js +++ /dev/null @@ -1,83 +0,0 @@ -import SettingsTab from './settings-tab.component' -import { compose } from 'recompose' -import { connect } from 'react-redux' -import { withRouter } from 'react-router-dom' -import { - setCurrentCurrency, - updateAndSetCustomRpc, - displayWarning, - revealSeedConfirmation, - setUseBlockie, - updateCurrentLocale, - setFeatureFlag, - showModal, - setUseNativeCurrencyAsPrimaryCurrencyPreference, - setShowFiatConversionOnTestnetsPreference, - setParticipateInMetaMetrics, -} from '../../../../actions' -import { preferencesSelector } from '../../../../selectors' - -const mapStateToProps = state => { - const { appState: { warning }, metamask } = state - const { - currentCurrency, - conversionDate, - nativeCurrency, - useBlockie, - featureFlags: { - sendHexData, - privacyMode, - advancedInlineGas, - mobileSync, - } = {}, - provider = {}, - currentLocale, - participateInMetaMetrics, - } = metamask - const { useNativeCurrencyAsPrimaryCurrency, showFiatInTestnets } = preferencesSelector(state) - - return { - warning, - currentLocale, - currentCurrency, - conversionDate, - nativeCurrency, - useBlockie, - sendHexData, - advancedInlineGas, - privacyMode, - provider, - useNativeCurrencyAsPrimaryCurrency, - mobileSync, - showFiatInTestnets, - participateInMetaMetrics, - } -} - -const mapDispatchToProps = dispatch => { - return { - setCurrentCurrency: currency => dispatch(setCurrentCurrency(currency)), - setRpcTarget: (newRpc, chainId, ticker, nickname) => dispatch(updateAndSetCustomRpc(newRpc, chainId, ticker, nickname)), - displayWarning: warning => dispatch(displayWarning(warning)), - revealSeedConfirmation: () => dispatch(revealSeedConfirmation()), - setUseBlockie: value => dispatch(setUseBlockie(value)), - updateCurrentLocale: key => dispatch(updateCurrentLocale(key)), - setHexDataFeatureFlag: shouldShow => dispatch(setFeatureFlag('sendHexData', shouldShow)), - setAdvancedInlineGasFeatureFlag: shouldShow => dispatch(setFeatureFlag('advancedInlineGas', shouldShow)), - setPrivacyMode: enabled => dispatch(setFeatureFlag('privacyMode', enabled)), - showResetAccountConfirmationModal: () => dispatch(showModal({ name: 'CONFIRM_RESET_ACCOUNT' })), - setUseNativeCurrencyAsPrimaryCurrencyPreference: value => { - return dispatch(setUseNativeCurrencyAsPrimaryCurrencyPreference(value)) - }, - setShowFiatConversionOnTestnetsPreference: value => { - return dispatch(setShowFiatConversionOnTestnetsPreference(value)) - }, - showClearApprovalModal: () => dispatch(showModal({ name: 'CLEAR_APPROVED_ORIGINS' })), - setParticipateInMetaMetrics: (val) => dispatch(setParticipateInMetaMetrics(val)), - } -} - -export default compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(SettingsTab) diff --git a/ui/app/components/pages/settings/settings.component.js b/ui/app/components/pages/settings/settings.component.js deleted file mode 100644 index 94a97bba1..000000000 --- a/ui/app/components/pages/settings/settings.component.js +++ /dev/null @@ -1,54 +0,0 @@ -import React, { PureComponent } from 'react' -import PropTypes from 'prop-types' -import { Switch, Route, matchPath } from 'react-router-dom' -import TabBar from '../../tab-bar' -import SettingsTab from './settings-tab' -import InfoTab from './info-tab' -import { DEFAULT_ROUTE, SETTINGS_ROUTE, INFO_ROUTE } from '../../../routes' - -export default class SettingsPage extends PureComponent { - static propTypes = { - location: PropTypes.object, - history: PropTypes.object, - t: PropTypes.func, - } - - static contextTypes = { - t: PropTypes.func, - } - - render () { - const { history, location } = this.props - - return ( - <div className="main-container settings-page"> - <div className="settings-page__header"> - <div - className="settings-page__close-button" - onClick={() => history.push(DEFAULT_ROUTE)} - /> - <TabBar - tabs={[ - { content: this.context.t('settings'), key: SETTINGS_ROUTE }, - { content: this.context.t('info'), key: INFO_ROUTE }, - ]} - isActive={key => matchPath(location.pathname, { path: key, exact: true })} - onSelect={key => history.push(key)} - /> - </div> - <Switch> - <Route - exact - path={INFO_ROUTE} - component={InfoTab} - /> - <Route - exact - path={SETTINGS_ROUTE} - component={SettingsTab} - /> - </Switch> - </div> - ) - } -} diff --git a/ui/app/components/pages/unlock-page/index.js b/ui/app/components/pages/unlock-page/index.js deleted file mode 100644 index be80cde4f..000000000 --- a/ui/app/components/pages/unlock-page/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import UnlockPage from './unlock-page.container' -module.exports = UnlockPage diff --git a/ui/app/components/pages/unlock-page/index.scss b/ui/app/components/pages/unlock-page/index.scss deleted file mode 100644 index 3d44bd037..000000000 --- a/ui/app/components/pages/unlock-page/index.scss +++ /dev/null @@ -1,51 +0,0 @@ -.unlock-page { - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: center; - width: 357px; - padding: 30px; - font-weight: 400; - color: $silver-chalice; - - &__container { - background: $white; - display: flex; - align-self: stretch; - justify-content: center; - flex: 1 0 auto; - } - - &__mascot-container { - margin-top: 24px; - } - - &__title { - margin-top: 5px; - font-size: 2rem; - font-weight: 800; - color: $tundora; - } - - &__form { - width: 100%; - margin: 56px 0 8px; - } - - &__links { - margin-top: 25px; - width: 100%; - } - - &__link { - cursor: pointer; - - &--import { - color: $ecstasy; - } - - &--use-classic { - margin-top: 10px; - } - } -} diff --git a/ui/app/components/pages/unlock-page/unlock-page.component.js b/ui/app/components/pages/unlock-page/unlock-page.component.js deleted file mode 100644 index cc86d5872..000000000 --- a/ui/app/components/pages/unlock-page/unlock-page.component.js +++ /dev/null @@ -1,191 +0,0 @@ -import React, { Component } from 'react' -import PropTypes from 'prop-types' -import Button from '@material-ui/core/Button' -import TextField from '../../text-field' -import getCaretCoordinates from 'textarea-caret' -import { EventEmitter } from 'events' -import Mascot from '../../mascot' -import { DEFAULT_ROUTE } from '../../../routes' - -export default class UnlockPage extends Component { - static contextTypes = { - metricsEvent: PropTypes.func, - t: PropTypes.func, - } - - static propTypes = { - history: PropTypes.object, - isUnlocked: PropTypes.bool, - onImport: PropTypes.func, - onRestore: PropTypes.func, - onSubmit: PropTypes.func, - forceUpdateMetamaskState: PropTypes.func, - showOptInModal: PropTypes.func, - } - - constructor (props) { - super(props) - - this.state = { - password: '', - error: null, - } - - this.submitting = false - this.animationEventEmitter = new EventEmitter() - } - - componentWillMount () { - const { isUnlocked, history } = this.props - - if (isUnlocked) { - history.push(DEFAULT_ROUTE) - } - } - - handleSubmit = async event => { - event.preventDefault() - event.stopPropagation() - - const { password } = this.state - const { onSubmit, forceUpdateMetamaskState, showOptInModal } = this.props - - if (password === '' || this.submitting) { - return - } - - this.setState({ error: null }) - this.submitting = true - - try { - await onSubmit(password) - const newState = await forceUpdateMetamaskState() - this.context.metricsEvent({ - eventOpts: { - category: 'Navigation', - action: 'Unlock', - name: 'Success', - }, - isNewVisit: true, - }) - - if (newState.participateInMetaMetrics === null || newState.participateInMetaMetrics === undefined) { - showOptInModal() - } - } catch ({ message }) { - if (message === 'Incorrect password') { - const newState = await forceUpdateMetamaskState() - this.context.metricsEvent({ - eventOpts: { - category: 'Navigation', - action: 'Unlock', - name: 'Incorrect Passowrd', - }, - customVariables: { - numberOfTokens: newState.tokens.length, - numberOfAccounts: Object.keys(newState.accounts).length, - }, - }) - } - - this.setState({ error: message }) - this.submitting = false - } - } - - handleInputChange ({ target }) { - this.setState({ password: target.value, error: null }) - - // tell mascot to look at page action - const element = target - const boundingRect = element.getBoundingClientRect() - const coordinates = getCaretCoordinates(element, element.selectionEnd) - this.animationEventEmitter.emit('point', { - x: boundingRect.left + coordinates.left - element.scrollLeft, - y: boundingRect.top + coordinates.top - element.scrollTop, - }) - } - - renderSubmitButton () { - const style = { - backgroundColor: '#f7861c', - color: 'white', - marginTop: '20px', - height: '60px', - fontWeight: '400', - boxShadow: 'none', - borderRadius: '4px', - } - - return ( - <Button - type="submit" - style={style} - disabled={!this.state.password} - fullWidth - variant="raised" - size="large" - onClick={this.handleSubmit} - disableRipple - > - { this.context.t('login') } - </Button> - ) - } - - render () { - const { password, error } = this.state - const { t } = this.context - const { onImport, onRestore } = this.props - - return ( - <div className="unlock-page__container"> - <div className="unlock-page"> - <div className="unlock-page__mascot-container"> - <Mascot - animationEventEmitter={this.animationEventEmitter} - width="120" - height="120" - /> - </div> - <h1 className="unlock-page__title"> - { t('welcomeBack') } - </h1> - <div>{ t('unlockMessage') }</div> - <form - className="unlock-page__form" - onSubmit={this.handleSubmit} - > - <TextField - id="password" - label={t('password')} - type="password" - value={password} - onChange={event => this.handleInputChange(event)} - error={error} - autoFocus - autoComplete="current-password" - material - fullWidth - /> - </form> - { this.renderSubmitButton() } - <div className="unlock-page__links"> - <div - className="unlock-page__link" - onClick={() => onRestore()} - > - { t('restoreFromSeed') } - </div> - <div - className="unlock-page__link unlock-page__link--import" - onClick={() => onImport()} - > - { t('importUsingSeed') } - </div> - </div> - </div> - </div> - ) - } -} diff --git a/ui/app/components/pages/unlock-page/unlock-page.container.js b/ui/app/components/pages/unlock-page/unlock-page.container.js deleted file mode 100644 index fe51c8095..000000000 --- a/ui/app/components/pages/unlock-page/unlock-page.container.js +++ /dev/null @@ -1,64 +0,0 @@ -import { connect } from 'react-redux' -import { withRouter } from 'react-router-dom' -import { compose } from 'recompose' -import { getEnvironmentType } from '../../../../../app/scripts/lib/util' -import { ENVIRONMENT_TYPE_POPUP } from '../../../../../app/scripts/lib/enums' -import { DEFAULT_ROUTE, RESTORE_VAULT_ROUTE } from '../../../routes' -import { - tryUnlockMetamask, - forgotPassword, - markPasswordForgotten, - forceUpdateMetamaskState, - showModal, -} from '../../../actions' -import UnlockPage from './unlock-page.component' - -const mapStateToProps = state => { - const { metamask: { isUnlocked } } = state - return { - isUnlocked, - } -} - -const mapDispatchToProps = dispatch => { - return { - forgotPassword: () => dispatch(forgotPassword()), - tryUnlockMetamask: password => dispatch(tryUnlockMetamask(password)), - markPasswordForgotten: () => dispatch(markPasswordForgotten()), - forceUpdateMetamaskState: () => forceUpdateMetamaskState(dispatch), - showOptInModal: () => dispatch(showModal({ name: 'METAMETRICS_OPT_IN_MODAL' })), - } -} - -const mergeProps = (stateProps, dispatchProps, ownProps) => { - const { markPasswordForgotten, tryUnlockMetamask, ...restDispatchProps } = dispatchProps - const { history, onSubmit: ownPropsSubmit, ...restOwnProps } = ownProps - - const onImport = () => { - markPasswordForgotten() - history.push(RESTORE_VAULT_ROUTE) - - if (getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP) { - global.platform.openExtensionInBrowser() - } - } - - const onSubmit = async password => { - await tryUnlockMetamask(password) - history.push(DEFAULT_ROUTE) - } - - return { - ...stateProps, - ...restDispatchProps, - ...restOwnProps, - onImport, - onRestore: onImport, - onSubmit: ownPropsSubmit || onSubmit, - } -} - -export default compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps, mergeProps) -)(UnlockPage) |