diff options
author | Thomas Huang <tmashuang@users.noreply.github.com> | 2018-11-23 03:06:46 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-23 03:06:46 +0800 |
commit | be3619cd802536894097d81e7f31d38b0c2b3e9f (patch) | |
tree | 2591ff5a9fe64f2dbd9fa089f5c51e8d0141be24 /ui/app | |
parent | 337a4e1b4ea7a560d773bc262b2adffd1617a39b (diff) | |
parent | 804b273cec61246f0d23efd461ccd2cc5c64bf22 (diff) | |
download | tangerine-wallet-browser-be3619cd802536894097d81e7f31d38b0c2b3e9f.tar tangerine-wallet-browser-be3619cd802536894097d81e7f31d38b0c2b3e9f.tar.gz tangerine-wallet-browser-be3619cd802536894097d81e7f31d38b0c2b3e9f.tar.bz2 tangerine-wallet-browser-be3619cd802536894097d81e7f31d38b0c2b3e9f.tar.lz tangerine-wallet-browser-be3619cd802536894097d81e7f31d38b0c2b3e9f.tar.xz tangerine-wallet-browser-be3619cd802536894097d81e7f31d38b0c2b3e9f.tar.zst tangerine-wallet-browser-be3619cd802536894097d81e7f31d38b0c2b3e9f.zip |
Merge pull request #5793 from MetaMask/develop
Bring master up to date with develop
Diffstat (limited to 'ui/app')
82 files changed, 982 insertions, 218 deletions
diff --git a/ui/app/actions.js b/ui/app/actions.js index a8b9189e9..e3cf57c9e 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -325,6 +325,9 @@ var actions = { clearPendingTokens, createCancelTransaction, + approveProviderRequest, + rejectProviderRequest, + clearApprovedOrigins, } module.exports = actions @@ -992,7 +995,7 @@ function updateSendTokenBalance ({ .then(usersToken => { if (usersToken) { const newTokenBalance = calcTokenBalance({ selectedToken, usersToken }) - dispatch(setSendTokenBalance(newTokenBalance.toString(10))) + dispatch(setSendTokenBalance(newTokenBalance)) } }) .catch(err => { @@ -2484,3 +2487,21 @@ function setPendingTokens (pendingTokens) { payload: tokens, } } + +function approveProviderRequest (origin) { + return (dispatch) => { + background.approveProviderRequest(origin) + } +} + +function rejectProviderRequest (origin) { + return (dispatch) => { + background.rejectProviderRequest(origin) + } +} + +function clearApprovedOrigins () { + return (dispatch) => { + background.clearApprovedOrigins() + } +} diff --git a/ui/app/components/app-header/app-header.component.js b/ui/app/components/app-header/app-header.component.js index c82dc1de9..83ec4809d 100644 --- a/ui/app/components/app-header/app-header.component.js +++ b/ui/app/components/app-header/app-header.component.js @@ -108,7 +108,7 @@ export default class AppHeader extends PureComponent { > <img className="app-header__metafox-logo app-header__metafox-logo--horizontal" - src="/images/logo/metamask-logo-horizontal-beta.svg" + src="/images/logo/metamask-logo-horizontal.svg" height={30} /> <img diff --git a/ui/app/components/balance-component.js b/ui/app/components/balance-component.js index 0f8514c81..4e2769ee8 100644 --- a/ui/app/components/balance-component.js +++ b/ui/app/components/balance-component.js @@ -86,13 +86,13 @@ BalanceComponent.prototype.renderBalance = function () { className: 'token-amount', value: balanceValue, type: PRIMARY, - ethNumberOfDecimals: 3, + ethNumberOfDecimals: 4, }), showFiat && h(UserPreferencedCurrencyDisplay, { value: balanceValue, type: SECONDARY, - ethNumberOfDecimals: 3, + ethNumberOfDecimals: 4, }), ]) } diff --git a/ui/app/components/confirm-page-container/confirm-page-container-header/index.scss b/ui/app/components/confirm-page-container/confirm-page-container-header/index.scss index 43e1e4427..be77edbdf 100644 --- a/ui/app/components/confirm-page-container/confirm-page-container-header/index.scss +++ b/ui/app/components/confirm-page-container/confirm-page-container-header/index.scss @@ -7,7 +7,7 @@ display: flex; justify-content: space-between; border-bottom: 1px solid $geyser; - padding: 13px 13px 13px 24px; + padding: 4px 13px 4px 13px; flex: 0 0 auto; } diff --git a/ui/app/components/confirm-page-container/confirm-page-container-navigation/confirm-page-container-navigation.component.js b/ui/app/components/confirm-page-container/confirm-page-container-navigation/confirm-page-container-navigation.component.js new file mode 100755 index 000000000..8327f997b --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-navigation/confirm-page-container-navigation.component.js @@ -0,0 +1,69 @@ +import React from 'react' +import PropTypes from 'prop-types' + +const ConfirmPageContainerNavigation = props => { + const { onNextTx, totalTx, positionOfCurrentTx, nextTxId, prevTxId, showNavigation, firstTx, lastTx, ofText, requestsWaitingText } = props + + return ( + <div className="confirm-page-container-navigation" + style={{ + display: showNavigation ? 'flex' : 'none', + }} + > + <div className="confirm-page-container-navigation__container" + style={{ + visibility: prevTxId ? 'initial' : 'hidden', + }}> + <div + className="confirm-page-container-navigation__arrow" + onClick={() => onNextTx(firstTx)}> + <img src="/images/double-arrow.svg" /> + </div> + <div + className="confirm-page-container-navigation__arrow" + onClick={() => onNextTx(prevTxId)}> + <img src="/images/single-arrow.svg" /> + </div> + </div> + <div className="confirm-page-container-navigation__textcontainer"> + <div className="confirm-page-container-navigation__navtext"> + {positionOfCurrentTx} {ofText} {totalTx} + </div> + <div className="confirm-page-container-navigation__longtext"> + {requestsWaitingText} + </div> + </div> + <div + className="confirm-page-container-navigation__container" + style={{ + visibility: nextTxId ? 'initial' : 'hidden', + }}> + <div + className="confirm-page-container-navigation__arrow" + onClick={() => onNextTx(nextTxId)}> + <img className="confirm-page-container-navigation__imageflip" src="/images/single-arrow.svg" /> + </div> + <div + className="confirm-page-container-navigation__arrow" + onClick={() => onNextTx(lastTx)}> + <img className="confirm-page-container-navigation__imageflip" src="/images/double-arrow.svg" /> + </div> + </div> + </div> + ) +} + +ConfirmPageContainerNavigation.propTypes = { + totalTx: PropTypes.number, + positionOfCurrentTx: PropTypes.number, + onNextTx: PropTypes.func, + nextTxId: PropTypes.string, + prevTxId: PropTypes.string, + showNavigation: PropTypes.bool, + firstTx: PropTypes.string, + lastTx: PropTypes.string, + ofText: PropTypes.string, + requestsWaitingText: PropTypes.string, +} + +export default ConfirmPageContainerNavigation diff --git a/ui/app/components/confirm-page-container/confirm-page-container-navigation/index.js b/ui/app/components/confirm-page-container/confirm-page-container-navigation/index.js new file mode 100755 index 000000000..d97c1b447 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-navigation/index.js @@ -0,0 +1 @@ +export { default } from './confirm-page-container-navigation.component' diff --git a/ui/app/components/confirm-page-container/confirm-page-container-navigation/index.scss b/ui/app/components/confirm-page-container/confirm-page-container-navigation/index.scss new file mode 100755 index 000000000..0cf184c60 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-navigation/index.scss @@ -0,0 +1,54 @@ +.confirm-page-container-navigation { + display: flex; + justify-content: space-between; + font: inherit; + padding: 4px 10px 4px 10px; + border-bottom: 1px solid $geyser; + flex: 0 0 auto; + + &__container { + display: flex; + } + + &__arrow { + cursor: pointer; + display: flex; + padding-left: 5px; + padding-right: 5px; + } + + &__arrow:hover { + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + transform: scale(1.1); + } + + &__arrow:active { + -webkit-transform: scale(0.95); + -moz-transform: scale(0.95); + -o-transform: scale(0.95); + transform: scale(0.95); + } + + &__textcontainer { + text-align: center; + } + + &__navtext { + font-size: 9px; + font-weight: bold; + } + + &__longtext { + color: $oslo-gray; + font-size: 8px; + } + + &__imageflip { + -webkit-transform: scaleX(-1); + -moz-transform: scaleX(-1); + -o-transform: scaleX(-1); + transform: scaleX(-1); + } +}
\ No newline at end of file diff --git a/ui/app/components/confirm-page-container/confirm-page-container.component.js b/ui/app/components/confirm-page-container/confirm-page-container.component.js index 8b2e47cbb..10edf3b16 100644 --- a/ui/app/components/confirm-page-container/confirm-page-container.component.js +++ b/ui/app/components/confirm-page-container/confirm-page-container.component.js @@ -2,7 +2,7 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import SenderToRecipient from '../sender-to-recipient' import { PageContainerFooter } from '../page-container' -import { ConfirmPageContainerHeader, ConfirmPageContainerContent } from './' +import { ConfirmPageContainerHeader, ConfirmPageContainerContent, ConfirmPageContainerNavigation } from './' export default class ConfirmPageContainer extends Component { static contextTypes = { @@ -43,6 +43,17 @@ export default class ConfirmPageContainer extends Component { summaryComponent: PropTypes.node, warning: PropTypes.string, unapprovedTxCount: PropTypes.number, + // Navigation + totalTx: PropTypes.number, + positionOfCurrentTx: PropTypes.number, + nextTxId: PropTypes.string, + prevTxId: PropTypes.string, + showNavigation: PropTypes.bool, + onNextTx: PropTypes.func, + firstTx: PropTypes.string, + lastTx: PropTypes.string, + ofText: PropTypes.string, + requestsWaitingText: PropTypes.string, // Footer onCancelAll: PropTypes.func, onCancel: PropTypes.func, @@ -79,11 +90,33 @@ export default class ConfirmPageContainer extends Component { unapprovedTxCount, assetImage, warning, + totalTx, + positionOfCurrentTx, + nextTxId, + prevTxId, + showNavigation, + onNextTx, + firstTx, + lastTx, + ofText, + requestsWaitingText, } = this.props const renderAssetImage = contentComponent || (!contentComponent && !identiconAddress) return ( <div className="page-container"> + <ConfirmPageContainerNavigation + totalTx={totalTx} + positionOfCurrentTx={positionOfCurrentTx} + nextTxId={nextTxId} + prevTxId={prevTxId} + showNavigation={showNavigation} + onNextTx={(txId) => onNextTx(txId)} + firstTx={firstTx} + lastTx={lastTx} + ofText={ofText} + requestsWaitingText={requestsWaitingText} + /> <ConfirmPageContainerHeader showEdit={showEdit} onEdit={() => onEdit()} diff --git a/ui/app/components/confirm-page-container/index.js b/ui/app/components/confirm-page-container/index.js index ee88aa5d3..28b17614e 100644 --- a/ui/app/components/confirm-page-container/index.js +++ b/ui/app/components/confirm-page-container/index.js @@ -1,6 +1,8 @@ export { default } from './confirm-page-container.component' export { default as ConfirmPageContainerHeader } from './confirm-page-container-header' export { default as ConfirmDetailRow } from './confirm-detail-row' +export { default as ConfirmPageContainerNavigation } from './confirm-page-container-navigation' + export { default as ConfirmPageContainerContent, ConfirmPageContainerSummary, diff --git a/ui/app/components/confirm-page-container/index.scss b/ui/app/components/confirm-page-container/index.scss index af7a5b555..d41cd4423 100644 --- a/ui/app/components/confirm-page-container/index.scss +++ b/ui/app/components/confirm-page-container/index.scss @@ -3,3 +3,5 @@ @import './confirm-page-container-header/index'; @import './confirm-detail-row/index'; + +@import './confirm-page-container-navigation/index';
\ No newline at end of file diff --git a/ui/app/components/currency-display/currency-display.container.js b/ui/app/components/currency-display/currency-display.container.js index 6ddf07172..e581f8a5e 100644 --- a/ui/app/components/currency-display/currency-display.container.js +++ b/ui/app/components/currency-display/currency-display.container.js @@ -20,15 +20,24 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { currency, denomination, hideLabel, + displayValue: propsDisplayValue, + suffix: propsSuffix, ...restOwnProps } = ownProps const toCurrency = currency || currentCurrency - const convertedValue = getValueFromWeiHex({ - value, fromCurrency: nativeCurrency, toCurrency, conversionRate, numberOfDecimals, toDenomination: denomination, - }) - const displayValue = formatCurrency(convertedValue, toCurrency) - const suffix = hideLabel ? undefined : toCurrency.toUpperCase() + + const displayValue = propsDisplayValue || formatCurrency( + getValueFromWeiHex({ + value, + fromCurrency: nativeCurrency, + toCurrency, conversionRate, + numberOfDecimals, + toDenomination: denomination, + }), + toCurrency + ) + const suffix = propsSuffix || (hideLabel ? undefined : toCurrency.toUpperCase()) return { ...restStateProps, diff --git a/ui/app/components/currency-display/tests/currency-display.container.test.js b/ui/app/components/currency-display/tests/currency-display.container.test.js index 0c886af50..9888c366e 100644 --- a/ui/app/components/currency-display/tests/currency-display.container.test.js +++ b/ui/app/components/currency-display/tests/currency-display.container.test.js @@ -131,7 +131,7 @@ describe('CurrencyDisplay container', () => { }, result: { nativeCurrency: 'ETH', - displayValue: '1e-9', + displayValue: '0.000000001', suffix: undefined, }, }, diff --git a/ui/app/components/index.scss b/ui/app/components/index.scss index 72de6cb93..f901aed7d 100644 --- a/ui/app/components/index.scss +++ b/ui/app/components/index.scss @@ -32,12 +32,16 @@ @import './pages/index'; +@import './provider-page-container/index'; + @import './selected-account/index'; @import './sender-to-recipient/index'; @import './tabs/index'; +@import './token-balance/index'; + @import './transaction-activity-log/index'; @import './transaction-breakdown/index'; diff --git a/ui/app/components/menu-bar/menu-bar.component.js b/ui/app/components/menu-bar/menu-bar.component.js index 7460e8dd5..e64809f3f 100644 --- a/ui/app/components/menu-bar/menu-bar.component.js +++ b/ui/app/components/menu-bar/menu-bar.component.js @@ -52,7 +52,7 @@ export default class MenuBar extends PureComponent { { accountDetailsMenuOpen && ( <AccountDetailsDropdown - className="menu-bar__account-details-dropdown" + className="menu-bar__account-details-dropdown" onClose={() => this.setState({ accountDetailsMenuOpen: false })} /> ) diff --git a/ui/app/components/modals/clear-approved-origins/clear-approved-origins.component.js b/ui/app/components/modals/clear-approved-origins/clear-approved-origins.component.js new file mode 100644 index 000000000..ceaa20a95 --- /dev/null +++ b/ui/app/components/modals/clear-approved-origins/clear-approved-origins.component.js @@ -0,0 +1,39 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import Modal, { ModalContent } from '../../modal' + +export default class ClearApprovedOrigins extends PureComponent { + static propTypes = { + hideModal: PropTypes.func.isRequired, + clearApprovedOrigins: PropTypes.func.isRequired, + } + + static contextTypes = { + t: PropTypes.func, + } + + handleClear = () => { + const { clearApprovedOrigins, hideModal } = this.props + clearApprovedOrigins() + hideModal() + } + + render () { + const { t } = this.context + + return ( + <Modal + onSubmit={this.handleClear} + onCancel={() => this.props.hideModal()} + submitText={t('ok')} + cancelText={t('nevermind')} + submitType="secondary" + > + <ModalContent + title={t('clearApprovalData')} + description={t('confirmClear')} + /> + </Modal> + ) + } +} diff --git a/ui/app/components/modals/clear-approved-origins/clear-approved-origins.container.js b/ui/app/components/modals/clear-approved-origins/clear-approved-origins.container.js new file mode 100644 index 000000000..3a801a062 --- /dev/null +++ b/ui/app/components/modals/clear-approved-origins/clear-approved-origins.container.js @@ -0,0 +1,16 @@ +import { connect } from 'react-redux' +import { compose } from 'recompose' +import withModalProps from '../../../higher-order-components/with-modal-props' +import ClearApprovedOriginsComponent from './clear-approved-origins.component' +import { clearApprovedOrigins } from '../../../actions' + +const mapDispatchToProps = dispatch => { + return { + clearApprovedOrigins: () => dispatch(clearApprovedOrigins()), + } +} + +export default compose( + withModalProps, + connect(null, mapDispatchToProps) +)(ClearApprovedOriginsComponent) diff --git a/ui/app/components/modals/clear-approved-origins/index.js b/ui/app/components/modals/clear-approved-origins/index.js new file mode 100644 index 000000000..b3e321995 --- /dev/null +++ b/ui/app/components/modals/clear-approved-origins/index.js @@ -0,0 +1 @@ +export { default } from './clear-approved-origins.container' diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js index 338229a28..5aff4f5e1 100644 --- a/ui/app/components/modals/modal.js +++ b/ui/app/components/modals/modal.js @@ -28,6 +28,7 @@ import ConfirmCustomizeGasModal from './customize-gas' import CancelTransaction from './cancel-transaction' import WelcomeBeta from './welcome-beta' import RejectTransactions from './reject-transactions' +import ClearApprovedOrigins from './clear-approved-origins' const modalContainerBaseStyle = { transform: 'translate3d(-50%, 0, 0px)', @@ -212,6 +213,19 @@ const MODALS = { }, }, + CLEAR_APPROVED_ORIGINS: { + contents: h(ClearApprovedOrigins), + mobileModalStyle: { + ...modalContainerMobileStyle, + }, + laptopModalStyle: { + ...modalContainerLaptopStyle, + }, + contentStyle: { + borderRadius: '8px', + }, + }, + OLD_UI_NOTIFICATION_MODAL: { contents: [ h(NotifcationModal, { diff --git a/ui/app/components/network-display/index.scss b/ui/app/components/network-display/index.scss index 2085cff67..e9f2f2057 100644 --- a/ui/app/components/network-display/index.scss +++ b/ui/app/components/network-display/index.scss @@ -3,11 +3,14 @@ display: flex; align-items: center; justify-content: flex-start; - background-color: lighten(rgb(125, 128, 130), 45%); padding: 0 10px; border-radius: 4px; height: 25px; + &--colored { + background-color: lighten(rgb(125, 128, 130), 45%); + } + &--mainnet { background-color: lighten($blue-lagoon, 68%); } diff --git a/ui/app/components/network-display/network-display.component.js b/ui/app/components/network-display/network-display.component.js index 82f9ff9c3..22d617099 100644 --- a/ui/app/components/network-display/network-display.component.js +++ b/ui/app/components/network-display/network-display.component.js @@ -16,7 +16,12 @@ const networkToClassHash = { } export default class NetworkDisplay extends Component { + static defaultProps = { + colored: true, + } + static propTypes = { + colored: PropTypes.bool, network: PropTypes.string, provider: PropTypes.object, } @@ -41,14 +46,16 @@ export default class NetworkDisplay extends Component { } render () { - const { network, provider: { type, nickname } } = this.props + const { colored, network, provider: { type, nickname } } = this.props const networkClass = networkToClassHash[network] return ( - <div className={classnames( - 'network-display__container', - networkClass && ('network-display__container--' + networkClass) - )}> + <div + className={classnames('network-display__container', { + 'network-display__container--colored': colored, + ['network-display__container--' + networkClass]: colored && networkClass, + })} + > { networkClass ? <div className={`network-display__icon network-display__icon--${networkClass}`} /> diff --git a/ui/app/components/page-container/index.scss b/ui/app/components/page-container/index.scss index 6742e3082..ba1215e84 100644 --- a/ui/app/components/page-container/index.scss +++ b/ui/app/components/page-container/index.scss @@ -101,6 +101,7 @@ font-size: 2rem; font-weight: 500; line-height: 2rem; + margin-right: 1.5rem; } &__subtitle { 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 index 7d01aaffb..e3abde233 100644 --- 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 @@ -1,8 +1,9 @@ +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 } from '../../../routes' +import { DEFAULT_ROUTE, CONFIRM_TRANSACTION_ROUTE } from '../../../routes' import { INSUFFICIENT_FUNDS_ERROR_KEY, TRANSACTION_ERROR_KEY, @@ -55,6 +56,7 @@ export default class ConfirmTransactionBase extends Component { transactionStatus: PropTypes.string, txData: PropTypes.object, unapprovedTxCount: PropTypes.number, + currentNetworkUnapprovedTxs: PropTypes.object, // Component props action: PropTypes.string, contentComponent: PropTypes.node, @@ -238,7 +240,7 @@ export default class ConfirmTransactionBase extends Component { ) } <div className="confirm-page-container-content__data-box-label"> - {`${t('hexData')}:`} + {`${t('hexData')}: ${ethUtil.toBuffer(data).length} bytes`} </div> <div className="confirm-page-container-content__data-box"> { data } @@ -293,22 +295,35 @@ export default class ConfirmTransactionBase extends Component { return } - this.setState({ submitting: true, submitError: null }) - - 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 }) - }) - } + this.setState({ + submitting: true, + submitError: null, + }, () => { + 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 () { @@ -348,6 +363,32 @@ export default class ConfirmTransactionBase extends Component { ) } + 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'), + } + } + render () { const { isTxReprice, @@ -376,6 +417,7 @@ export default class ConfirmTransactionBase extends Component { const { name } = methodData const { valid, errorKey } = this.getErrorKey() + const { totalTx, positionOfCurrentTx, nextTxId, prevTxId, showNavigation, firstTx, lastTx, ofText, requestsWaitingText } = this.getNavigateTxData() return ( <ConfirmPageContainer @@ -401,6 +443,16 @@ export default class ConfirmTransactionBase extends Component { 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()} 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 index c366d5137..45bf62fb9 100644 --- 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 @@ -73,9 +73,9 @@ const mapStateToProps = (state, props) => { const currentNetworkUnapprovedTxs = R.filter( ({ metamaskNetworkId }) => metamaskNetworkId === network, - valuesFor(unapprovedTxs), + unapprovedTxs, ) - const unapprovedTxCount = currentNetworkUnapprovedTxs.length + const unapprovedTxCount = valuesFor(currentNetworkUnapprovedTxs).length return { balance, @@ -104,6 +104,7 @@ const mapStateToProps = (state, props) => { assetImage, unapprovedTxs, unapprovedTxCount, + currentNetworkUnapprovedTxs, } } 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 index 2c44b6094..76782cf6a 100644 --- 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 @@ -32,21 +32,15 @@ export default class ConfirmTransactionSwitch extends Component { txData, methodData: { name }, fetchingData, - isEtherTransaction, } = this.props const { id, txParams: { data } = {} } = txData - if (isConfirmDeployContract(txData)) { - const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_DEPLOY_CONTRACT_PATH}` - return <Redirect to={{ pathname }} /> - } - if (fetchingData) { return <Loading /> } - if (isEtherTransaction) { - const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_SEND_ETHER_PATH}` + if (isConfirmDeployContract(txData)) { + const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_DEPLOY_CONTRACT_PATH}` return <Redirect to={{ pathname }} /> } 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 index 2767b2e1f..c63de234a 100644 --- a/ui/app/components/pages/create-account/connect-hardware/account-list.js +++ b/ui/app/components/pages/create-account/connect-hardware/account-list.js @@ -152,7 +152,7 @@ class AccountList extends Component { }, [this.context.t('cancel')]), h(Button, { - type: 'primary', + type: 'confirm', large: true, className: 'new-account-connect-form__button unlock', disabled, 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 index d3abf3119..49a5610c1 100644 --- a/ui/app/components/pages/create-account/connect-hardware/connect-screen.js +++ b/ui/app/components/pages/create-account/connect-hardware/connect-screen.js @@ -45,11 +45,13 @@ class ConnectScreen extends Component { this.renderConnectToLedgerButton(), this.renderConnectToTrezorButton(), ]), - h( - `button.hw-connect__connect-btn${!this.state.selectedDevice ? '.disabled' : ''}`, - { onClick: this.connect }, - this.context.t('connect') - ), + h(Button, { + type: 'confirm', + large: true, + className: 'hw-connect__connect-btn', + onClick: this.connect, + disabled: !this.state.selectedDevice, + }, this.context.t('connect')), ]) ) } @@ -67,9 +69,7 @@ class ConnectScreen extends Component { onClick: () => global.platform.openWindow({ url: 'https://google.com/chrome', }), - }, - this.context.t('downloadGoogleChrome') - ), + }, this.context.t('downloadGoogleChrome')), ]) ) } diff --git a/ui/app/components/pages/create-account/connect-hardware/index.js b/ui/app/components/pages/create-account/connect-hardware/index.js index 547df5223..4fe25f629 100644 --- a/ui/app/components/pages/create-account/connect-hardware/index.js +++ b/ui/app/components/pages/create-account/connect-hardware/index.js @@ -50,9 +50,8 @@ class ConnectHardwareForm extends Component { } connectToHardwareWallet = (device) => { - // None of the hardware wallets are supported - // At least for now - if (getPlatform() === PLATFORM_FIREFOX) { + // Ledger hardware wallets are not supported on firefox + if (getPlatform() === PLATFORM_FIREFOX && device === 'ledger') { this.setState({ browserSupported: false, error: null}) return null } @@ -126,7 +125,7 @@ class ConnectHardwareForm extends Component { .catch(e => { if (e === 'Window blocked') { this.setState({ browserSupported: false, error: null}) - } else if (e !== 'Window closed') { + } else if (e !== 'Window closed' && e !== 'Popup closed') { this.setState({ error: e.toString() }) } }) diff --git a/ui/app/components/pages/home/home.component.js b/ui/app/components/pages/home/home.component.js index d3c71c4f6..b9ec3c258 100644 --- a/ui/app/components/pages/home/home.component.js +++ b/ui/app/components/pages/home/home.component.js @@ -4,6 +4,8 @@ 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_BACKUP_PHRASE_ROUTE, RESTORE_VAULT_ROUTE, @@ -21,6 +23,7 @@ export default class Home extends PureComponent { seedWords: PropTypes.string, suggestedTokens: PropTypes.object, unconfirmedTransactionsCount: PropTypes.number, + providerRequests: PropTypes.array, } componentDidMount () { @@ -46,6 +49,7 @@ export default class Home extends PureComponent { lostAccounts, forgottenPassword, seedWords, + providerRequests, } = this.props // notices @@ -62,6 +66,12 @@ export default class Home extends PureComponent { 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"> diff --git a/ui/app/components/pages/home/home.container.js b/ui/app/components/pages/home/home.container.js index 58001df6b..bb8cf5e81 100644 --- a/ui/app/components/pages/home/home.container.js +++ b/ui/app/components/pages/home/home.container.js @@ -11,6 +11,7 @@ const mapStateToProps = state => { lostAccounts, seedWords, suggestedTokens, + providerRequests, } = metamask const { forgottenPassword } = appState @@ -21,6 +22,7 @@ const mapStateToProps = state => { seedWords, suggestedTokens, unconfirmedTransactionsCount: unconfirmedTransactionsCountSelector(state), + providerRequests, } } diff --git a/ui/app/components/pages/provider-approval/index.js b/ui/app/components/pages/provider-approval/index.js new file mode 100644 index 000000000..4162f3155 --- /dev/null +++ b/ui/app/components/pages/provider-approval/index.js @@ -0,0 +1 @@ +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 new file mode 100644 index 000000000..da98bc3fc --- /dev/null +++ b/ui/app/components/pages/provider-approval/provider-approval.component.js @@ -0,0 +1,28 @@ +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} + 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 new file mode 100644 index 000000000..b223244a1 --- /dev/null +++ b/ui/app/components/pages/provider-approval/provider-approval.container.js @@ -0,0 +1,12 @@ +import { connect } from 'react-redux' +import ProviderApproval from './provider-approval.component' +import { approveProviderRequest, rejectProviderRequest } from '../../../actions' + +function mapDispatchToProps (dispatch) { + return { + approveProviderRequest: origin => dispatch(approveProviderRequest(origin)), + rejectProviderRequest: origin => dispatch(rejectProviderRequest(origin)), + } +} + +export default connect(null, mapDispatchToProps)(ProviderApproval) 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 index cd81491a8..a0a8ed47e 100644 --- a/ui/app/components/pages/settings/settings-tab/settings-tab.component.js +++ b/ui/app/components/pages/settings/settings-tab/settings-tab.component.js @@ -39,12 +39,15 @@ export default class SettingsTab extends PureComponent { 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, @@ -276,6 +279,36 @@ export default class SettingsTab extends PureComponent { ) } + 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 @@ -461,6 +494,32 @@ export default class SettingsTab extends PureComponent { ) } + 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> + ) + } + render () { const { warning, isMascara } = this.props @@ -475,8 +534,10 @@ export default class SettingsTab extends PureComponent { { this.renderSeedWords() } { !isMascara && this.renderOldUI() } { this.renderResetAccount() } - { this.renderBlockieOptIn() } + { this.renderClearApproval() } + { this.renderPrivacyOptIn() } { this.renderHexDataOptIn() } + { this.renderBlockieOptIn() } </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 index f4110207e..b6c33a5b2 100644 --- a/ui/app/components/pages/settings/settings-tab/settings-tab.container.js +++ b/ui/app/components/pages/settings/settings-tab/settings-tab.container.js @@ -22,7 +22,10 @@ const mapStateToProps = state => { conversionDate, nativeCurrency, useBlockie, - featureFlags: { sendHexData } = {}, + featureFlags: { + sendHexData, + privacyMode, + } = {}, provider = {}, isMascara, currentLocale, @@ -38,6 +41,7 @@ const mapStateToProps = state => { nativeCurrency, useBlockie, sendHexData, + privacyMode, provider, useNativeCurrencyAsPrimaryCurrency, } @@ -55,10 +59,12 @@ const mapDispatchToProps = dispatch => { return dispatch(setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')) }, setHexDataFeatureFlag: shouldShow => dispatch(setFeatureFlag('sendHexData', shouldShow)), + setPrivacyMode: enabled => dispatch(setFeatureFlag('privacyMode', enabled)), showResetAccountConfirmationModal: () => dispatch(showModal({ name: 'CONFIRM_RESET_ACCOUNT' })), setUseNativeCurrencyAsPrimaryCurrencyPreference: value => { return dispatch(setUseNativeCurrencyAsPrimaryCurrencyPreference(value)) }, + showClearApprovalModal: () => dispatch(showModal({ name: 'CLEAR_APPROVED_ORIGINS' })), } } diff --git a/ui/app/components/provider-page-container/index.js b/ui/app/components/provider-page-container/index.js new file mode 100644 index 000000000..927c35940 --- /dev/null +++ b/ui/app/components/provider-page-container/index.js @@ -0,0 +1,3 @@ +export {default} from './provider-page-container.component' +export {default as ProviderPageContainerContent} from './provider-page-container-content' +export {default as ProviderPageContainerHeader} from './provider-page-container-header' diff --git a/ui/app/components/provider-page-container/index.scss b/ui/app/components/provider-page-container/index.scss new file mode 100644 index 000000000..8d35ac179 --- /dev/null +++ b/ui/app/components/provider-page-container/index.scss @@ -0,0 +1,121 @@ +.provider-approval-container { + display: flex; + + &__header { + display: flex; + flex-direction: column; + align-items: flex-end; + border-bottom: 1px solid $geyser; + padding: 9px; + } + + &__content { + display: flex; + overflow-y: auto; + flex: 1; + flex-direction: column; + justify-content: space-between; + color: #7C808E; + + h1, h2 { + color: #4A4A4A; + display: flex; + justify-content: center; + text-align: center; + } + + h2 { + font-size: 16px; + line-height: 18px; + padding: 20px; + } + + h1 { + font-size: 22px; + line-height: 26px; + padding: 20px; + } + + p { + padding: 0 40px; + text-align: center; + font-size: 12px; + line-height: 18px; + } + + a, a:hover { + color: $dodger-blue; + } + + .provider-approval-visual { + display: flex; + flex-direction: row; + justify-content: space-evenly; + position: relative; + margin: 0 32px; + + section { + display: flex; + flex-direction: column; + align-items: center; + flex: 1; + } + + h1 { + font-size: 14px; + line-height: 18px; + padding: 8px 0 0; + } + + h2 { + font-size: 10px; + line-height: 14px; + padding: 0; + color: #A2A4AC; + } + + &__check { + width: 40px; + height: 40px; + background: white url("/images/provider-approval-check.svg") no-repeat; + margin-top: 14px; + } + + &__identicon { + width: 64px; + height: 64px; + + &--default { + background-color: #777A87; + color: white; + width: 64px; + height: 64px; + border-radius: 32px; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + } + } + + &:before { + border-top: 2px dashed #CDD1E4; + content: ""; + margin: 0 auto; + position: absolute; + top: 32px; + left: 0; + bottom: 0; + right: 0; + width: 65%; + z-index: -1; + } + } + + .secure-badge { + display: flex; + justify-content: center; + padding: 25px; + } + } +} diff --git a/ui/app/components/provider-page-container/provider-page-container-content/index.js b/ui/app/components/provider-page-container/provider-page-container-content/index.js new file mode 100644 index 000000000..73e491adc --- /dev/null +++ b/ui/app/components/provider-page-container/provider-page-container-content/index.js @@ -0,0 +1 @@ +export {default} from './provider-page-container-content.container' diff --git a/ui/app/components/provider-page-container/provider-page-container-content/provider-page-container-content.component.js b/ui/app/components/provider-page-container/provider-page-container-content/provider-page-container-content.component.js new file mode 100644 index 000000000..268db613f --- /dev/null +++ b/ui/app/components/provider-page-container/provider-page-container-content/provider-page-container-content.component.js @@ -0,0 +1,77 @@ +import PropTypes from 'prop-types' +import React, {PureComponent} from 'react' +import Identicon from '../../identicon' + +export default class ProviderPageContainerContent extends PureComponent { + static propTypes = { + origin: PropTypes.string.isRequired, + selectedIdentity: PropTypes.string.isRequired, + siteImage: PropTypes.string, + siteTitle: PropTypes.string.isRequired, + } + + static contextTypes = { + t: PropTypes.func, + }; + + renderConnectVisual = () => { + const { origin, selectedIdentity, siteImage, siteTitle } = this.props + + return ( + <div className="provider-approval-visual"> + <section> + {siteImage ? ( + <img + className="provider-approval-visual__identicon" + src={siteImage} + /> + ) : ( + <i className="provider-approval-visual__identicon--default"> + {siteTitle.charAt(0).toUpperCase()} + </i> + )} + <h1>{siteTitle}</h1> + <h2>{origin}</h2> + </section> + <span className="provider-approval-visual__check" /> + <section> + <Identicon + className="provider-approval-visual__identicon" + address={selectedIdentity.address} + diameter={64} + /> + <h1>{selectedIdentity.name}</h1> + </section> + </div> + ) + } + + render () { + const { siteTitle } = this.props + const { t } = this.context + + return ( + <div className="provider-approval-container__content"> + <section> + <h2>{t('connectRequest')}</h2> + {this.renderConnectVisual()} + <h1>{t('providerRequest', [siteTitle])}</h1> + <p> + {t('providerRequestInfo')} + <br/> + <a + href="https://medium.com/metamask/introducing-privacy-mode-42549d4870fa" + target="_blank" + rel="noopener noreferrer" + > + {t('learnMore')}. + </a> + </p> + </section> + <section className="secure-badge"> + <img src="/images/mm-secure.svg" /> + </section> + </div> + ) + } +} diff --git a/ui/app/components/provider-page-container/provider-page-container-content/provider-page-container-content.container.js b/ui/app/components/provider-page-container/provider-page-container-content/provider-page-container-content.container.js new file mode 100644 index 000000000..3ea1ce20e --- /dev/null +++ b/ui/app/components/provider-page-container/provider-page-container-content/provider-page-container-content.container.js @@ -0,0 +1,11 @@ +import { connect } from 'react-redux' +import ProviderPageContainerContent from './provider-page-container-content.component' +import { getSelectedIdentity } from '../../../selectors' + +const mapStateToProps = (state) => { + return { + selectedIdentity: getSelectedIdentity(state), + } +} + +export default connect(mapStateToProps)(ProviderPageContainerContent) diff --git a/ui/app/components/provider-page-container/provider-page-container-header/index.js b/ui/app/components/provider-page-container/provider-page-container-header/index.js new file mode 100644 index 000000000..430627d3a --- /dev/null +++ b/ui/app/components/provider-page-container/provider-page-container-header/index.js @@ -0,0 +1 @@ +export {default} from './provider-page-container-header.component' diff --git a/ui/app/components/provider-page-container/provider-page-container-header/provider-page-container-header.component.js b/ui/app/components/provider-page-container/provider-page-container-header/provider-page-container-header.component.js new file mode 100644 index 000000000..41bf6c3dd --- /dev/null +++ b/ui/app/components/provider-page-container/provider-page-container-header/provider-page-container-header.component.js @@ -0,0 +1,12 @@ +import React, {PureComponent} from 'react' +import NetworkDisplay from '../../network-display' + +export default class ProviderPageContainerHeader extends PureComponent { + render () { + return ( + <div className="provider-approval-container__header"> + <NetworkDisplay colored={false} /> + </div> + ) + } +} diff --git a/ui/app/components/provider-page-container/provider-page-container.component.js b/ui/app/components/provider-page-container/provider-page-container.component.js new file mode 100644 index 000000000..902733616 --- /dev/null +++ b/ui/app/components/provider-page-container/provider-page-container.component.js @@ -0,0 +1,50 @@ +import PropTypes from 'prop-types' +import React, {PureComponent} from 'react' +import { ProviderPageContainerContent, ProviderPageContainerHeader } from './' +import { PageContainerFooter } from '../page-container' + +export default class ProviderPageContainer extends PureComponent { + static propTypes = { + approveProviderRequest: PropTypes.func.isRequired, + origin: PropTypes.string.isRequired, + rejectProviderRequest: PropTypes.func.isRequired, + siteImage: PropTypes.string, + siteTitle: PropTypes.string.isRequired, + }; + + static contextTypes = { + t: PropTypes.func, + }; + + onCancel = () => { + const { origin, rejectProviderRequest } = this.props + rejectProviderRequest(origin) + } + + onSubmit = () => { + const { approveProviderRequest, origin } = this.props + approveProviderRequest(origin) + } + + render () { + const {origin, siteImage, siteTitle} = this.props + + return ( + <div className="page-container provider-approval-container"> + <ProviderPageContainerHeader /> + <ProviderPageContainerContent + origin={origin} + siteImage={siteImage} + siteTitle={siteTitle} + /> + <PageContainerFooter + onCancel={() => this.onCancel()} + cancelText={this.context.t('cancel')} + onSubmit={() => this.onSubmit()} + submitText={this.context.t('connect')} + submitButtonType="confirm" + /> + </div> + ) + } +} diff --git a/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js b/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js index ceb620941..80518977e 100644 --- a/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js +++ b/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js @@ -11,11 +11,11 @@ export default class AmountMaxButton extends Component { setAmountToMax: PropTypes.func, setMaxModeTo: PropTypes.func, tokenBalance: PropTypes.string, - }; + } static contextTypes = { t: PropTypes.func, - }; + } setMaxAmount () { const { diff --git a/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js b/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js index b490a7fd7..27181d2f5 100644 --- a/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js +++ b/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js @@ -5,16 +5,23 @@ const { const ethUtil = require('ethereumjs-util') function calcMaxAmount ({ balance, gasTotal, selectedToken, tokenBalance }) { - const { decimals } = selectedToken || {} - const multiplier = Math.pow(10, Number(decimals || 0)) + const { decimals } = selectedToken || {} + const multiplier = Math.pow(10, Number(decimals || 0)) - return selectedToken - ? multiplyCurrencies(tokenBalance, multiplier, {toNumericBase: 'hex'}) - : subtractCurrencies( - ethUtil.addHexPrefix(balance), - ethUtil.addHexPrefix(gasTotal), - { toNumericBase: 'hex' } - ) + return selectedToken + ? multiplyCurrencies( + tokenBalance, + multiplier, + { + toNumericBase: 'hex', + multiplicandBase: 16, + } + ) + : subtractCurrencies( + ethUtil.addHexPrefix(balance), + ethUtil.addHexPrefix(gasTotal), + { toNumericBase: 'hex' } + ) } module.exports = { diff --git a/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js b/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js index 816df6a12..1ee858f67 100644 --- a/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js +++ b/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js @@ -19,7 +19,7 @@ describe('amount-max-button utils', () => { selectedToken: { decimals: 10, }, - tokenBalance: 100, + tokenBalance: '64', }), 'e8d4a51000') }) }) diff --git a/ui/app/components/send/send-content/send-amount-row/send-amount-row.component.js b/ui/app/components/send/send-content/send-amount-row/send-amount-row.component.js index 0268376bf..4df1e0ffa 100644 --- a/ui/app/components/send/send-content/send-amount-row/send-amount-row.component.js +++ b/ui/app/components/send/send-content/send-amount-row/send-amount-row.component.js @@ -26,11 +26,11 @@ export default class SendAmountRow extends Component { updateSendAmount: PropTypes.func, updateSendAmountError: PropTypes.func, updateGas: PropTypes.func, - }; + } static contextTypes = { t: PropTypes.func, - }; + } validateAmount (amount) { const { @@ -58,7 +58,6 @@ export default class SendAmountRow extends Component { if (selectedToken) { updateGasFeeError({ - amount, amountConversionRate, balance, conversionRate, diff --git a/ui/app/components/send/send-content/send-amount-row/send-amount-row.container.js b/ui/app/components/send/send-content/send-amount-row/send-amount-row.container.js index 3504d1b73..2b6fe0f6c 100644 --- a/ui/app/components/send/send-content/send-amount-row/send-amount-row.container.js +++ b/ui/app/components/send/send-content/send-amount-row/send-amount-row.container.js @@ -45,10 +45,10 @@ function mapDispatchToProps (dispatch) { setMaxModeTo: bool => dispatch(setMaxModeTo(bool)), updateSendAmount: newAmount => dispatch(updateSendAmount(newAmount)), updateGasFeeError: (amountDataObject) => { - dispatch(updateSendErrors(getGasFeeErrorObject(amountDataObject))) + dispatch(updateSendErrors(getGasFeeErrorObject(amountDataObject))) }, updateSendAmountError: (amountDataObject) => { - dispatch(updateSendErrors(getAmountErrorObject(amountDataObject))) + dispatch(updateSendErrors(getAmountErrorObject(amountDataObject))) }, } } diff --git a/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js b/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js index 56e80cb83..14a71129f 100644 --- a/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js +++ b/ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js @@ -82,7 +82,6 @@ describe('SendAmountRow Component', function () { assert.deepEqual( propsMethodSpies.updateGasFeeError.getCall(0).args, [{ - amount: 'someAmount', amountConversionRate: 'mockAmountConversionRate', balance: 'mockBalance', conversionRate: 7, diff --git a/ui/app/components/send/send-content/send-from-row/from-dropdown/from-dropdown.component.js b/ui/app/components/send/send-content/send-from-row/from-dropdown/from-dropdown.component.js index 4f43a9d61..d512f7d0b 100644 --- a/ui/app/components/send/send-content/send-from-row/from-dropdown/from-dropdown.component.js +++ b/ui/app/components/send/send-content/send-from-row/from-dropdown/from-dropdown.component.js @@ -12,11 +12,11 @@ export default class FromDropdown extends Component { onSelect: PropTypes.func, openDropdown: PropTypes.func, selectedAccount: PropTypes.object, - }; + } static contextTypes = { t: PropTypes.func, - }; + } render () { const { diff --git a/ui/app/components/send/send-content/send-from-row/send-from-row.component.js b/ui/app/components/send/send-content/send-from-row/send-from-row.component.js index 3e0e0de22..b6de9d222 100644 --- a/ui/app/components/send/send-content/send-from-row/send-from-row.component.js +++ b/ui/app/components/send/send-content/send-from-row/send-from-row.component.js @@ -15,11 +15,11 @@ export default class SendFromRow extends Component { tokenContract: PropTypes.object, updateSendFrom: PropTypes.func, setSendTokenBalance: PropTypes.func, - }; + } static contextTypes = { t: PropTypes.func, - }; + } async handleFromChange (newFrom) { const { @@ -32,6 +32,7 @@ export default class SendFromRow extends Component { const usersToken = await tokenContract.balanceOf(newFrom.address) setSendTokenBalance(usersToken) } + updateSendFrom(newFrom) } diff --git a/ui/app/components/send/send-content/send-from-row/send-from-row.container.js b/ui/app/components/send/send-content/send-from-row/send-from-row.container.js index 33cb63b43..7008bbea4 100644 --- a/ui/app/components/send/send-content/send-from-row/send-from-row.container.js +++ b/ui/app/components/send/send-content/send-from-row/send-from-row.container.js @@ -10,8 +10,8 @@ import { } from './send-from-row.selectors.js' import { calcTokenBalance } from '../../send.utils.js' import { - updateSendFrom, - setSendTokenBalance, + updateSendFrom, + setSendTokenBalance, } from '../../../../actions' import { closeFromDropdown, @@ -37,10 +37,10 @@ function mapDispatchToProps (dispatch) { openFromDropdown: () => dispatch(openFromDropdown()), updateSendFrom: newFrom => dispatch(updateSendFrom(newFrom)), setSendTokenBalance: (usersToken, selectedToken) => { - if (!usersToken) return + if (!usersToken) return - const tokenBalance = calcTokenBalance({ usersToken, selectedToken }) - dispatch(setSendTokenBalance(tokenBalance)) + const tokenBalance = calcTokenBalance({ usersToken, selectedToken }) + dispatch(setSendTokenBalance(tokenBalance)) }, } } diff --git a/ui/app/components/send/send-content/send-gas-row/send-gas-row.component.js b/ui/app/components/send/send-content/send-gas-row/send-gas-row.component.js index 91b58cfd0..6ad4499ff 100644 --- a/ui/app/components/send/send-content/send-gas-row/send-gas-row.component.js +++ b/ui/app/components/send/send-content/send-gas-row/send-gas-row.component.js @@ -12,11 +12,11 @@ export default class SendGasRow extends Component { gasLoadingError: PropTypes.bool, gasTotal: PropTypes.string, showCustomizeGasModal: PropTypes.func, - }; + } static contextTypes = { t: PropTypes.func, - }; + } render () { const { diff --git a/ui/app/components/send/send-content/send-gas-row/send-gas-row.container.js b/ui/app/components/send/send-content/send-gas-row/send-gas-row.container.js index 8f8e3e4dd..e44fe4ef1 100644 --- a/ui/app/components/send/send-content/send-gas-row/send-gas-row.container.js +++ b/ui/app/components/send/send-content/send-gas-row/send-gas-row.container.js @@ -1,8 +1,8 @@ import { connect } from 'react-redux' import { - getConversionRate, - getCurrentCurrency, - getGasTotal, + getConversionRate, + getCurrentCurrency, + getGasTotal, } from '../../send.selectors.js' import { getGasLoadingError, gasFeeIsInError } from './send-gas-row.selectors.js' import { showModal } from '../../../../actions' diff --git a/ui/app/components/send/send-content/send-to-row/send-to-row.component.js b/ui/app/components/send/send-content/send-to-row/send-to-row.component.js index 17c75c817..ce5325314 100644 --- a/ui/app/components/send/send-content/send-to-row/send-to-row.component.js +++ b/ui/app/components/send/send-content/send-to-row/send-to-row.component.js @@ -19,11 +19,11 @@ export default class SendToRow extends Component { updateSendTo: PropTypes.func, updateSendToError: PropTypes.func, scanQrCode: PropTypes.func, - }; + } static contextTypes = { t: PropTypes.func, - }; + } handleToChange (to, nickname = '', toError) { const { hasHexData, updateSendTo, updateSendToError, updateGas } = this.props diff --git a/ui/app/components/send/send-footer/send-footer.component.js b/ui/app/components/send/send-footer/send-footer.component.js index 230bf450f..b78b56373 100644 --- a/ui/app/components/send/send-footer/send-footer.component.js +++ b/ui/app/components/send/send-footer/send-footer.component.js @@ -26,11 +26,11 @@ export default class SendFooter extends Component { tokenBalance: PropTypes.string, unapprovedTxs: PropTypes.object, update: PropTypes.func, - }; + } static contextTypes = { t: PropTypes.func, - }; + } onCancel () { this.props.clearSend() diff --git a/ui/app/components/send/send.component.js b/ui/app/components/send/send.component.js index fb7beca16..a27401f30 100644 --- a/ui/app/components/send/send.component.js +++ b/ui/app/components/send/send.component.js @@ -41,11 +41,11 @@ export default class SendTransactionScreen extends PersistentForm { scanQrCode: PropTypes.func, qrCodeDetected: PropTypes.func, qrCodeData: PropTypes.object, - }; + } static contextTypes = { t: PropTypes.func, - }; + } componentWillReceiveProps (nextProps) { if (nextProps.qrCodeData) { @@ -138,14 +138,12 @@ export default class SendTransactionScreen extends PersistentForm { }) const gasFeeErrorObject = selectedToken ? getGasFeeErrorObject({ - amount, amountConversionRate, balance, conversionRate, gasTotal, primaryCurrency, selectedToken, - tokenBalance, }) : { gasFee: null } updateSendErrors(Object.assign(amountErrorObject, gasFeeErrorObject)) diff --git a/ui/app/components/send/send.utils.js b/ui/app/components/send/send.utils.js index eb1667c63..b2ac41e9c 100644 --- a/ui/app/components/send/send.utils.js +++ b/ui/app/components/send/send.utils.js @@ -89,11 +89,10 @@ function isTokenBalanceSufficient ({ const tokenBalanceIsSufficient = conversionGTE( { value: tokenBalance, - fromNumericBase: 'dec', + fromNumericBase: 'hex', }, { value: calcTokenAmount(amountInDec, decimals), - fromNumericBase: 'dec', }, ) @@ -151,7 +150,6 @@ function getAmountErrorObject ({ } function getGasFeeErrorObject ({ - amount, amountConversionRate, balance, conversionRate, @@ -180,7 +178,7 @@ function getGasFeeErrorObject ({ function calcTokenBalance ({ selectedToken, usersToken }) { const { decimals } = selectedToken || {} - return calcTokenAmount(usersToken.balance.toString(), decimals) + '' + return calcTokenAmount(usersToken.balance.toString(), decimals).toString(16) } function doesAmountErrorRequireUpdate ({ diff --git a/ui/app/components/send/tests/send-component.test.js b/ui/app/components/send/tests/send-component.test.js index f4943e707..bd136a0b8 100644 --- a/ui/app/components/send/tests/send-component.test.js +++ b/ui/app/components/send/tests/send-component.test.js @@ -158,14 +158,12 @@ describe('Send Component', function () { assert.deepEqual( utilsMethodStubs.getGasFeeErrorObject.getCall(0).args[0], { - amount: 'mockAmount', amountConversionRate: 'mockAmountConversionRate', balance: 'mockBalance', conversionRate: 10, gasTotal: 'mockGasTotal', primaryCurrency: 'mockPrimaryCurrency', selectedToken: 'mockSelectedToken', - tokenBalance: 'mockTokenBalance', } ) }) diff --git a/ui/app/components/send/tests/send-utils.test.js b/ui/app/components/send/tests/send-utils.test.js index b72d87eee..f31e1221b 100644 --- a/ui/app/components/send/tests/send-utils.test.js +++ b/ui/app/components/send/tests/send-utils.test.js @@ -285,11 +285,10 @@ describe('send utils', () => { [ { value: 123, - fromNumericBase: 'dec', + fromNumericBase: 'hex', }, { value: 'calc:1610', - fromNumericBase: 'dec', }, ] ) diff --git a/ui/app/components/token-balance/index.scss b/ui/app/components/token-balance/index.scss new file mode 100644 index 000000000..2ff6dfbc8 --- /dev/null +++ b/ui/app/components/token-balance/index.scss @@ -0,0 +1,14 @@ +.token-balance-component { + display: flex; + align-items: center; + + &__text { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &__suffix { + padding-left: 4px; + } +} diff --git a/ui/app/components/token-balance/token-balance.component.js b/ui/app/components/token-balance/token-balance.component.js index 2b4f73980..af1a32578 100644 --- a/ui/app/components/token-balance/token-balance.component.js +++ b/ui/app/components/token-balance/token-balance.component.js @@ -1,6 +1,6 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' -import classnames from 'classnames' +import CurrencyDisplay from '../currency-display' export default class TokenBalance extends PureComponent { static propTypes = { @@ -12,12 +12,14 @@ export default class TokenBalance extends PureComponent { } render () { - const { className, string, withSymbol, symbol } = this.props + const { className, string, symbol } = this.props return ( - <div className={classnames('hide-text-overflow', className)}> - { string + (withSymbol ? ` ${symbol}` : '') } - </div> + <CurrencyDisplay + className={className} + displayValue={string} + suffix={symbol} + /> ) } } diff --git a/ui/app/components/token-currency-display/token-currency-display.component.js b/ui/app/components/token-currency-display/token-currency-display.component.js index 4bb09a4b6..6e9a65300 100644 --- a/ui/app/components/token-currency-display/token-currency-display.component.js +++ b/ui/app/components/token-currency-display/token-currency-display.component.js @@ -1,6 +1,6 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' -import CurrencyDisplay from '../currency-display/currency-display.component' +import CurrencyDisplay from '../currency-display' import { getTokenData } from '../../helpers/transactions.util' import { getTokenValue, calcTokenAmount } from '../../token-util' @@ -12,6 +12,7 @@ export default class TokenCurrencyDisplay extends PureComponent { state = { displayValue: '', + suffix: '', } componentDidMount () { @@ -29,25 +30,27 @@ export default class TokenCurrencyDisplay extends PureComponent { setDisplayValue () { const { transactionData: data, token } = this.props - const { decimals = '', symbol = '' } = token + const { decimals = '', symbol: suffix = '' } = token const tokenData = getTokenData(data) let displayValue if (tokenData.params && tokenData.params.length) { const tokenValue = getTokenValue(tokenData.params) - const tokenAmount = calcTokenAmount(tokenValue, decimals) - displayValue = `${tokenAmount} ${symbol}` + displayValue = calcTokenAmount(tokenValue, decimals).toString() } - this.setState({ displayValue }) + this.setState({ displayValue, suffix }) } render () { + const { displayValue, suffix } = this.state + return ( <CurrencyDisplay {...this.props} - displayValue={this.state.displayValue} + displayValue={displayValue} + suffix={suffix} /> ) } diff --git a/ui/app/components/token-input/token-input.component.js b/ui/app/components/token-input/token-input.component.js index d1388945b..10fa1151e 100644 --- a/ui/app/components/token-input/token-input.component.js +++ b/ui/app/components/token-input/token-input.component.js @@ -32,7 +32,7 @@ export default class TokenInput extends PureComponent { super(props) const { value: hexValue } = props - const decimalValue = hexValue ? this.getDecimalValue(props) : 0 + const decimalValue = hexValue ? this.getValue(props) : 0 this.state = { decimalValue, @@ -46,12 +46,12 @@ export default class TokenInput extends PureComponent { const { hexValue: stateHexValue } = this.state if (prevPropsHexValue !== propsHexValue && propsHexValue !== stateHexValue) { - const decimalValue = this.getDecimalValue(this.props) + const decimalValue = this.getValue(this.props) this.setState({ hexValue: propsHexValue, decimalValue }) } } - getDecimalValue (props) { + getValue (props) { const { value: hexValue, selectedToken: { decimals, symbol } = {} } = props const multiplier = Math.pow(10, Number(decimals || 0)) @@ -63,7 +63,7 @@ export default class TokenInput extends PureComponent { invertConversionRate: true, }) - return Number(decimalValueString) || 0 + return Number(decimalValueString) ? decimalValueString : '' } handleChange = decimalValue => { diff --git a/ui/app/components/transaction-list-item/index.scss b/ui/app/components/transaction-list-item/index.scss index ac0e7beeb..449974734 100644 --- a/ui/app/components/transaction-list-item/index.scss +++ b/ui/app/components/transaction-list-item/index.scss @@ -80,6 +80,8 @@ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + min-width: 0; + max-width: 100%; &--primary { text-align: end; diff --git a/ui/app/components/transaction-status/tests/transaction-status.component.test.js b/ui/app/components/transaction-status/tests/transaction-status.component.test.js new file mode 100644 index 000000000..9e3bffe4f --- /dev/null +++ b/ui/app/components/transaction-status/tests/transaction-status.component.test.js @@ -0,0 +1,35 @@ +import React from 'react' +import assert from 'assert' +import { mount } from 'enzyme' +import TransactionStatus from '../transaction-status.component' +import Tooltip from '../../tooltip-v2' + +describe('TransactionStatus Component', () => { + it('should render APPROVED properly', () => { + const wrapper = mount( + <TransactionStatus + statusKey="approved" + title="test-title" + />, + { context: { t: str => str.toUpperCase() } } + ) + + assert.ok(wrapper) + const tooltipProps = wrapper.find(Tooltip).props() + assert.equal(tooltipProps.children, 'APPROVED') + assert.equal(tooltipProps.title, 'test-title') + }) + + it('should render SUBMITTED properly', () => { + const wrapper = mount( + <TransactionStatus + statusKey="submitted" + />, + { context: { t: str => str.toUpperCase() } } + ) + + assert.ok(wrapper) + const tooltipProps = wrapper.find(Tooltip).props() + assert.equal(tooltipProps.children, 'PENDING') + }) +}) diff --git a/ui/app/components/transaction-status/transaction-status.component.js b/ui/app/components/transaction-status/transaction-status.component.js index c22baf18a..0d47d7868 100644 --- a/ui/app/components/transaction-status/transaction-status.component.js +++ b/ui/app/components/transaction-status/transaction-status.component.js @@ -25,7 +25,6 @@ const statusToClassNameHash = { } const statusToTextHash = { - [APPROVED_STATUS]: 'pending', [SUBMITTED_STATUS]: 'pending', } diff --git a/ui/app/components/transaction-view-balance/index.scss b/ui/app/components/transaction-view-balance/index.scss index 659f896ff..43e87459b 100644 --- a/ui/app/components/transaction-view-balance/index.scss +++ b/ui/app/components/transaction-view-balance/index.scss @@ -6,6 +6,12 @@ height: 54px; min-width: 0; + @media screen and (max-width: $break-small) { + flex-direction: column; + height: initial; + width: 100%; + } + &__balance { margin: 0 12px; display: flex; @@ -15,17 +21,8 @@ @media screen and (max-width: $break-small) { align-items: center; margin: 16px 0; - } - } - - &__token-balance { - margin-left: 12px; - font-size: 1.5rem; - - @media screen and (max-width: $break-small) { - margin: 12px 0; - margin-left: 0; - font-size: 1.75rem; + padding: 0 16px; + max-width: 100%; } } @@ -34,6 +31,7 @@ @media screen and (max-width: $break-small) { font-size: 1.75rem; + width: 100%; } } @@ -51,6 +49,7 @@ @media screen and (max-width: $break-small) { flex-direction: column; + width: 100%; } } @@ -71,9 +70,4 @@ margin-right: 12px; } } - - @media screen and (max-width: $break-small) { - flex-direction: column; - height: initial - } } diff --git a/ui/app/components/transaction-view-balance/transaction-view-balance.component.js b/ui/app/components/transaction-view-balance/transaction-view-balance.component.js index 273845c47..a24b97478 100644 --- a/ui/app/components/transaction-view-balance/transaction-view-balance.component.js +++ b/ui/app/components/transaction-view-balance/transaction-view-balance.component.js @@ -26,24 +26,26 @@ export default class TransactionViewBalance extends PureComponent { return selectedToken ? ( - <TokenBalance - token={selectedToken} - withSymbol - className="transaction-view-balance__token-balance" - /> + <div className="transaction-view-balance__balance"> + <TokenBalance + token={selectedToken} + withSymbol + className="transaction-view-balance__primary-balance" + /> + </div> ) : ( <div className="transaction-view-balance__balance"> <UserPreferencedCurrencyDisplay className="transaction-view-balance__primary-balance" value={balance} type={PRIMARY} - ethNumberOfDecimals={3} + ethNumberOfDecimals={4} /> <UserPreferencedCurrencyDisplay className="transaction-view-balance__secondary-balance" value={balance} type={SECONDARY} - ethNumberOfDecimals={3} + ethNumberOfDecimals={4} /> </div> ) diff --git a/ui/app/components/unit-input/index.scss b/ui/app/components/unit-input/index.scss index 28c5bf6f0..7995696aa 100644 --- a/ui/app/components/unit-input/index.scss +++ b/ui/app/components/unit-input/index.scss @@ -38,6 +38,10 @@ align-items: center; } + &__suffix { + margin-left: 3px; + } + &--error { border-color: $red; } diff --git a/ui/app/components/unit-input/unit-input.component.js b/ui/app/components/unit-input/unit-input.component.js index f1ebf4d77..0c6b21797 100644 --- a/ui/app/components/unit-input/unit-input.component.js +++ b/ui/app/components/unit-input/unit-input.component.js @@ -66,7 +66,7 @@ export default class UnitInput extends PureComponent { const valueString = String(value) const valueLength = valueString.length || 1 const decimalPointDeficit = valueString.match(/\./) ? -0.5 : 0 - return (valueLength + decimalPointDeficit + 0.75) + 'ch' + return (valueLength + decimalPointDeficit + 0.5) + 'ch' } render () { diff --git a/ui/app/conversion-util.js b/ui/app/conversion-util.js index f271b5683..8cc531773 100644 --- a/ui/app/conversion-util.js +++ b/ui/app/conversion-util.js @@ -62,7 +62,7 @@ const toSpecifiedDenomination = { } const baseChange = { hex: n => n.toString(16), - dec: n => Number(n).toString(10), + dec: n => (new BigNumber(n)).toString(10), BN: n => new BN(n.toString(16)), } diff --git a/ui/app/css/itcss/components/new-account.scss b/ui/app/css/itcss/components/new-account.scss index e4c7a4e0d..7bfa2d443 100644 --- a/ui/app/css/itcss/components/new-account.scss +++ b/ui/app/css/itcss/components/new-account.scss @@ -3,6 +3,7 @@ background-color: #FFFFFF; box-shadow: 0 0 7px 0 rgba(0,0,0,0.08); z-index: 25; + height: 100%; &__header { display: flex; @@ -186,22 +187,8 @@ } &__connect-btn { - background-color: #259De5; - color: #fff; - border: none; width: 315px; - min-height: 54px; - font-weight: 300; - font-size: 14px; - margin-bottom: 20px; - margin-top: 20px; - border-radius: 5px; - display: flex; - flex: 1; - margin-left: 20px; - margin-right: 20px; - justify-content: center; - text-transform: uppercase; + margin: 20px; } &__connect-btn.disabled { @@ -449,6 +436,7 @@ margin-top: 10px; &__button { + background: #fff; height: 19px; display: flex; color: #33a4e7; @@ -489,29 +477,8 @@ justify-content: space-between; } - &__button { - width: 150px; - min-width: initial; - } - - .btn-primary { - background-color: #259DE5; - color: #FFFFFF; - border: none; - width: 100%; - min-height: 54px; - font-weight: 300; - font-size: 14px; - margin-bottom: 20px - } - - &__button.unlock { - width: 50%; - } - - &__button.btn-primary--disabled { - cursor: not-allowed; - opacity: .5; + &__button:not(:last-child) { + margin-right: 16px; } } diff --git a/ui/app/css/itcss/components/pages/index.scss b/ui/app/css/itcss/components/pages/index.scss index 709f8baf6..45e47f447 100644 --- a/ui/app/css/itcss/components/pages/index.scss +++ b/ui/app/css/itcss/components/pages/index.scss @@ -1 +1,3 @@ @import './reveal-seed.scss'; + +@import './provider-approval.scss'; diff --git a/ui/app/css/itcss/components/pages/provider-approval.scss b/ui/app/css/itcss/components/pages/provider-approval.scss new file mode 100644 index 000000000..f172165ab --- /dev/null +++ b/ui/app/css/itcss/components/pages/provider-approval.scss @@ -0,0 +1,11 @@ +.provider_approval_content { + height: auto; + overflow: auto; + padding: 16px; +} + +.provider_approval_origin { + font-weight: 999; + margin-top: 16px; + word-wrap: break-word; +} diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss index a57653b45..c791a24c7 100644 --- a/ui/app/css/itcss/components/send.scss +++ b/ui/app/css/itcss/components/send.scss @@ -552,6 +552,7 @@ &__form-field { flex: 1 1 auto; + min-width: 0; .currency-display { color: $tundora; @@ -580,6 +581,7 @@ line-height: 22px; width: 88px; font-weight: 400; + flex: 0 0 auto; } &__from-dropdown { diff --git a/ui/app/ducks/confirm-transaction.duck.js b/ui/app/ducks/confirm-transaction.duck.js index 275eb1551..e228d2d39 100644 --- a/ui/app/ducks/confirm-transaction.duck.js +++ b/ui/app/ducks/confirm-transaction.duck.js @@ -370,11 +370,16 @@ export function setTransactionToConfirm (transactionId) { dispatch(setFetchingData(true)) const methodData = await getMethodData(data) dispatch(updateMethodData(methodData)) + } catch (error) { + dispatch(updateMethodData({})) + dispatch(setFetchingData(false)) + } + + try { const toSmartContract = await isSmartContractAddress(to) dispatch(updateToSmartContract(toSmartContract)) dispatch(setFetchingData(false)) } catch (error) { - dispatch(updateMethodData({})) dispatch(setFetchingData(false)) } diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index 22fa53098..302d1627a 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -33,7 +33,7 @@ function reduceMetamask (state, action) { gasLimit: null, gasPrice: null, gasTotal: null, - tokenBalance: null, + tokenBalance: '0x0', from: '', to: '', amount: '0x0', @@ -74,6 +74,7 @@ function reduceMetamask (state, action) { case actions.CLEAR_NOTICES: return extend(metamaskState, { noActiveNotices: true, + nextUnreadNotice: undefined, }) case actions.UPDATE_METAMASK_STATE: @@ -294,8 +295,10 @@ function reduceMetamask (state, action) { amount: '0x0', memo: '', errors: {}, + maxModeOn: false, editingTransactionId: null, forceGasMin: null, + toNickname: '', }, }) @@ -333,9 +336,9 @@ function reduceMetamask (state, action) { }) case actions.SET_USE_BLOCKIE: - return extend(metamaskState, { - useBlockie: action.value, - }) + return extend(metamaskState, { + useBlockie: action.value, + }) case actions.UPDATE_FEATURE_FLAGS: return extend(metamaskState, { diff --git a/ui/app/select-app.js b/ui/app/select-app.js index f2e8e8d10..f5f9e33ab 100644 --- a/ui/app/select-app.js +++ b/ui/app/select-app.js @@ -5,17 +5,14 @@ const h = require('react-hyperscript') const { HashRouter } = require('react-router-dom') const App = require('./app') const OldApp = require('../../old-ui/app/app') -const { autoAddToBetaUI } = require('./selectors') +const { getShouldUseNewUi } = require('./selectors') const { setFeatureFlag } = require('./actions') const I18nProvider = require('./i18n-provider') function mapStateToProps (state) { return { - betaUI: state.metamask.featureFlags.betaUI, - autoAdd: autoAddToBetaUI(state), - isUnlocked: state.metamask.isUnlocked, isMascara: state.metamask.isMascara, - firstTime: Object.keys(state.metamask.identities).length === 0, + shouldUseNewUi: getShouldUseNewUi(state), } } @@ -56,17 +53,13 @@ SelectedApp.prototype.componentWillReceiveProps = function (nextProps) { } SelectedApp.prototype.render = function () { - // Code commented out until we begin auto adding users to NewUI - // const { betaUI, isMascara, firstTime } = this.props - // const Selected = betaUI || isMascara || firstTime ? App : OldApp - - const { betaUI, isMascara } = this.props - - return betaUI || isMascara - ? h(HashRouter, { - hashType: 'noslash', - }, [ - h(I18nProvider, [ h(App) ]), - ]) - : h(OldApp) + const { shouldUseNewUi } = this.props + const newUi = h(HashRouter, { + hashType: 'noslash', + }, [ + h(I18nProvider, [ + h(App), + ]), + ]) + return shouldUseNewUi ? newUi : h(OldApp) } diff --git a/ui/app/selectors.js b/ui/app/selectors.js index 7209f19d1..b518527c9 100644 --- a/ui/app/selectors.js +++ b/ui/app/selectors.js @@ -31,6 +31,7 @@ const selectors = { getSelectedTokenToFiatRate, getSelectedTokenContract, autoAddToBetaUI, + getShouldUseNewUi, getSendMaxModeState, getCurrentViewContext, getTotalUnapprovedCount, @@ -185,6 +186,13 @@ function autoAddToBetaUI (state) { return userIsNotInBeta && userPassesThreshold } +function getShouldUseNewUi (state) { + const isAlreadyUsingBetaUi = state.metamask.featureFlags.betaUI + const isMascara = state.metamask.isMascara + const isFreshInstall = Object.keys(state.metamask.identities).length === 0 + return isAlreadyUsingBetaUi || isMascara || isFreshInstall +} + function getCurrentViewContext (state) { const { currentView = {} } = state.appState return currentView.context diff --git a/ui/app/selectors/confirm-transaction.js b/ui/app/selectors/confirm-transaction.js index 90924c036..23ef26d95 100644 --- a/ui/app/selectors/confirm-transaction.js +++ b/ui/app/selectors/confirm-transaction.js @@ -137,11 +137,12 @@ export const tokenAmountAndToAddressSelector = createSelector( const valueParam = params.find(param => param.name === TOKEN_PARAM_VALUE) toAddress = toParam ? toParam.value : params[0].value const value = valueParam ? Number(valueParam.value) : Number(params[1].value) - tokenAmount = roundExponential(value) if (tokenDecimals) { - tokenAmount = calcTokenAmount(value, tokenDecimals) + tokenAmount = calcTokenAmount(value, tokenDecimals).toNumber() } + + tokenAmount = roundExponential(tokenAmount) } return { @@ -163,7 +164,7 @@ export const approveTokenAmountAndToAddressSelector = createSelector( const value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value) if (tokenDecimals) { - tokenAmount = calcTokenAmount(value, tokenDecimals) + tokenAmount = calcTokenAmount(value, tokenDecimals).toNumber() } tokenAmount = roundExponential(tokenAmount) @@ -188,7 +189,7 @@ export const sendTokenTokenAmountAndToAddressSelector = createSelector( let value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value) if (tokenDecimals) { - value = calcTokenAmount(value, tokenDecimals) + value = calcTokenAmount(value, tokenDecimals).toNumber() } tokenAmount = roundExponential(value) diff --git a/ui/app/token-util.js b/ui/app/token-util.js index 6e4992763..35a19a69f 100644 --- a/ui/app/token-util.js +++ b/ui/app/token-util.js @@ -109,7 +109,7 @@ export function tokenInfoGetter () { export function calcTokenAmount (value, decimals) { const multiplier = Math.pow(10, Number(decimals || 0)) - return new BigNumber(String(value)).div(multiplier).toNumber() + return new BigNumber(String(value)).div(multiplier) } export function getTokenValue (tokenParams = []) { diff --git a/ui/app/welcome-screen.js b/ui/app/welcome-screen.js index 63512cd50..146661eb3 100644 --- a/ui/app/welcome-screen.js +++ b/ui/app/welcome-screen.js @@ -50,7 +50,7 @@ class WelcomeScreen extends Component { height: '225', }), - h('div.welcome-screen__info__header', this.context.t('welcomeBeta')), + h('div.welcome-screen__info__header', this.context.t('welcome')), h('div.welcome-screen__info__copy', this.context.t('metamaskDescription')), |