From ea9d51e427b8e607e612a01629bebf153e516ad9 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Fri, 22 Jun 2018 23:52:45 -0700 Subject: Refactor and redesign confirm transaction views --- ui/app/actions.js | 70 ++-- ui/app/app.js | 7 +- ui/app/components/button/button.component.js | 21 +- .../confirm-detail-row.component.js | 52 +++ .../confirm-detail-row/index.js | 1 + .../confirm-detail-row/index.scss | 43 +++ .../confirm-page-container-content.component.js | 100 ++++++ .../confirm-page-container-error.component.js | 20 ++ .../confirm-page-container-error/index.js | 1 + .../confirm-page-container-error/index.scss | 17 + .../confirm-page-container-summary.component.js | 56 +++ .../confirm-page-container-summary/index.js | 1 + .../confirm-page-container-summary/index.scss | 54 +++ .../confirm-page-container-warning.component.js | 22 ++ .../confirm-page-container-warning/index.js | 1 + .../confirm-page-container-warning/index.scss | 18 + .../confirm-page-container-content/index.js | 4 + .../confirm-page-container-content/index.scss | 66 ++++ .../confirm-page-container-header.component.js | 63 ++++ .../confirm-page-container-header/index.js | 1 + .../confirm-page-container-header/index.scss | 27 ++ .../confirm-page-container.component.js | 116 +++++++ ui/app/components/confirm-page-container/index.js | 8 + .../components/confirm-page-container/index.scss | 5 + .../dropdowns/components/network-dropdown-icon.js | 3 + ui/app/components/index.scss | 10 + ui/app/components/input-number.js | 14 +- .../customize-gas/customize-gas.component.js | 140 ++++++++ .../customize-gas/customize-gas.container.js | 22 ++ .../modals/customize-gas/customize-gas.util.js | 34 ++ ui/app/components/modals/customize-gas/index.js | 1 + ui/app/components/modals/customize-gas/index.scss | 110 ++++++ ui/app/components/modals/index.scss | 2 + ui/app/components/modals/modal.js | 28 +- ui/app/components/network-display.js | 56 --- ui/app/components/network-display/index.js | 2 + ui/app/components/network-display/index.scss | 54 +++ .../network-display/network-display.component.js | 69 ++++ .../network-display/network-display.container.js | 11 + ui/app/components/page-container/index.js | 3 + ui/app/components/page-container/index.scss | 186 ++++++++++ .../page-container-footer.component.js | 10 +- .../page-container-header.component.js | 35 -- .../page-container-header.component.js | 33 +- .../confirm-approve/confirm-approve.component.js | 30 ++ .../confirm-approve/confirm-approve.container.js | 28 ++ ui/app/components/pages/confirm-approve/index.js | 1 + .../confirm-deploy-contract.component.js | 64 ++++ .../confirm-deploy-contract.container.js | 12 + .../pages/confirm-deploy-contract/index.js | 1 + .../confirm-send-ether.component.js | 31 ++ .../confirm-send-ether.container.js | 37 ++ .../components/pages/confirm-send-ether/index.js | 1 + .../confirm-send-token.component.js | 39 +++ .../confirm-send-token.container.js | 72 ++++ .../components/pages/confirm-send-token/index.js | 1 + .../components/pages/confirm-send-token/index.scss | 19 + .../confirm-transaction-base.component.js | 382 +++++++++++++++++++++ .../confirm-transaction-base.container.js | 95 +++++ .../pages/confirm-transaction-base/index.js | 1 + .../confirm-transaction-switch.component.js | 71 ++++ .../confirm-transaction-switch.constants.js | 2 + .../confirm-transaction-switch.container.js | 11 + .../confirm-transaction-switch.util.js | 12 + .../pages/confirm-transaction-switch/index.js | 2 + .../confirm-transaction.component.js | 59 ++++ .../confirm-transaction.container.js | 19 + .../components/pages/confirm-transaction/index.js | 2 + ui/app/components/pages/home.js | 94 ----- ui/app/components/pages/index.scss | 2 + .../send_/send-footer/send-footer.component.js | 6 +- .../send_/send-footer/send-footer.container.js | 2 +- ui/app/components/send_/send.utils.js | 8 +- ui/app/components/sender-to-recipient.js | 72 ---- ui/app/components/sender-to-recipient/index.js | 1 + ui/app/components/sender-to-recipient/index.scss | 74 ++++ .../sender-to-recipient.component.js | 117 +++++++ ui/app/components/tabs/index.js | 3 + ui/app/components/tabs/index.scss | 11 + ui/app/components/tabs/tab/index.js | 2 + ui/app/components/tabs/tab/index.scss | 15 + ui/app/components/tabs/tab/tab.component.js | 31 ++ ui/app/components/tabs/tabs.component.js | 63 ++++ ui/app/components/tooltip-v2.js | 4 +- ui/app/conversion-util.js | 2 + ui/app/css/itcss/components/buttons.scss | 25 +- ui/app/css/itcss/components/index.scss | 2 - ui/app/css/itcss/components/network.scss | 12 - .../css/itcss/components/sender-to-recipient.scss | 58 ---- ui/app/css/itcss/generic/index.scss | 189 ---------- ui/app/css/itcss/settings/variables.scss | 1 + ui/app/css/itcss/tools/utilities.scss | 2 +- ui/app/ducks/confirm-transaction.duck.js | 319 +++++++++++++++++ ui/app/helpers/confirm-transaction/util.js | 101 ++++++ ui/app/reducers.js | 3 + ui/app/routes.js | 20 +- ui/app/selectors.js | 13 + ui/app/selectors/confirm-transaction.js | 65 ++++ 98 files changed, 3308 insertions(+), 598 deletions(-) create mode 100644 ui/app/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js create mode 100644 ui/app/components/confirm-page-container/confirm-detail-row/index.js create mode 100644 ui/app/components/confirm-page-container/confirm-detail-row/index.scss create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/confirm-page-container-error.component.js create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.js create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.scss create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/index.js create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/index.scss create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/index.js create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/index.scss create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-content/index.js create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-content/index.scss create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-header/confirm-page-container-header.component.js create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-header/index.js create mode 100644 ui/app/components/confirm-page-container/confirm-page-container-header/index.scss create mode 100644 ui/app/components/confirm-page-container/confirm-page-container.component.js create mode 100644 ui/app/components/confirm-page-container/index.js create mode 100644 ui/app/components/confirm-page-container/index.scss create mode 100644 ui/app/components/modals/customize-gas/customize-gas.component.js create mode 100644 ui/app/components/modals/customize-gas/customize-gas.container.js create mode 100644 ui/app/components/modals/customize-gas/customize-gas.util.js create mode 100644 ui/app/components/modals/customize-gas/index.js create mode 100644 ui/app/components/modals/customize-gas/index.scss delete mode 100644 ui/app/components/network-display.js create mode 100644 ui/app/components/network-display/index.js create mode 100644 ui/app/components/network-display/index.scss create mode 100644 ui/app/components/network-display/network-display.component.js create mode 100644 ui/app/components/network-display/network-display.container.js create mode 100644 ui/app/components/page-container/index.scss delete mode 100644 ui/app/components/page-container/page-container-header.component.js create mode 100644 ui/app/components/pages/confirm-approve/confirm-approve.component.js create mode 100644 ui/app/components/pages/confirm-approve/confirm-approve.container.js create mode 100644 ui/app/components/pages/confirm-approve/index.js create mode 100644 ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.component.js create mode 100644 ui/app/components/pages/confirm-deploy-contract/confirm-deploy-contract.container.js create mode 100644 ui/app/components/pages/confirm-deploy-contract/index.js create mode 100644 ui/app/components/pages/confirm-send-ether/confirm-send-ether.component.js create mode 100644 ui/app/components/pages/confirm-send-ether/confirm-send-ether.container.js create mode 100644 ui/app/components/pages/confirm-send-ether/index.js create mode 100644 ui/app/components/pages/confirm-send-token/confirm-send-token.component.js create mode 100644 ui/app/components/pages/confirm-send-token/confirm-send-token.container.js create mode 100644 ui/app/components/pages/confirm-send-token/index.js create mode 100644 ui/app/components/pages/confirm-send-token/index.scss create mode 100644 ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js create mode 100644 ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.container.js create mode 100644 ui/app/components/pages/confirm-transaction-base/index.js create mode 100644 ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.component.js create mode 100644 ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.constants.js create mode 100644 ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.container.js create mode 100644 ui/app/components/pages/confirm-transaction-switch/confirm-transaction-switch.util.js create mode 100644 ui/app/components/pages/confirm-transaction-switch/index.js create mode 100644 ui/app/components/pages/confirm-transaction/confirm-transaction.component.js create mode 100644 ui/app/components/pages/confirm-transaction/confirm-transaction.container.js create mode 100644 ui/app/components/pages/confirm-transaction/index.js delete mode 100644 ui/app/components/sender-to-recipient.js create mode 100644 ui/app/components/sender-to-recipient/index.js create mode 100644 ui/app/components/sender-to-recipient/index.scss create mode 100644 ui/app/components/sender-to-recipient/sender-to-recipient.component.js create mode 100644 ui/app/components/tabs/index.js create mode 100644 ui/app/components/tabs/index.scss create mode 100644 ui/app/components/tabs/tab/index.js create mode 100644 ui/app/components/tabs/tab/index.scss create mode 100644 ui/app/components/tabs/tab/tab.component.js create mode 100644 ui/app/components/tabs/tabs.component.js delete mode 100644 ui/app/css/itcss/components/sender-to-recipient.scss create mode 100644 ui/app/ducks/confirm-transaction.duck.js create mode 100644 ui/app/helpers/confirm-transaction/util.js create mode 100644 ui/app/selectors/confirm-transaction.js (limited to 'ui/app') diff --git a/ui/app/actions.js b/ui/app/actions.js index ad890f565..1fb49c920 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -704,11 +704,10 @@ function signTypedMsg (msgData) { function signTx (txData) { return (dispatch) => { - dispatch(actions.showLoadingIndication()) global.ethQuery.sendTransaction(txData, (err, data) => { - dispatch(actions.hideLoadingIndication()) - if (err) return dispatch(actions.displayWarning(err.message)) - dispatch(actions.hideWarning()) + if (err) { + return dispatch(actions.displayWarning(err.message)) + } }) dispatch(actions.showConfTxPage({})) } @@ -910,29 +909,41 @@ function signTokenTx (tokenAddress, toAddress, amount, txData) { function updateTransaction (txData) { log.info('actions: updateTx: ' + JSON.stringify(txData)) - return (dispatch) => { + return dispatch => { log.debug(`actions calling background.updateTx`) - background.updateTransaction(txData, (err) => { - dispatch(actions.hideLoadingIndication()) - dispatch(actions.updateTransactionParams(txData.id, txData.txParams)) - if (err) { - dispatch(actions.txError(err)) - dispatch(actions.goHome()) - return log.error(err.message) - } - dispatch(actions.showConfTxPage({ id: txData.id })) + dispatch(actions.showLoadingIndication()) + + return new Promise((resolve, reject) => { + background.updateTransaction(txData, (err) => { + dispatch(actions.updateTransactionParams(txData.id, txData.txParams)) + if (err) { + dispatch(actions.txError(err)) + dispatch(actions.goHome()) + log.error(err.message) + return reject(err) + } + + resolve(txData) + }) }) + .then(() => updateMetamaskStateFromBackground()) + .then(newState => dispatch(actions.updateMetamaskState(newState))) + .then(() => { + dispatch(actions.showConfTxPage({ id: txData.id })) + dispatch(actions.hideLoadingIndication()) + return txData + }) } } function updateAndApproveTx (txData) { log.info('actions: updateAndApproveTx: ' + JSON.stringify(txData)) - return (dispatch) => { + return dispatch => { log.debug(`actions calling background.updateAndApproveTx`) + dispatch(actions.showLoadingIndication()) return new Promise((resolve, reject) => { background.updateAndApproveTransaction(txData, err => { - dispatch(actions.hideLoadingIndication()) dispatch(actions.updateTransactionParams(txData.id, txData.txParams)) dispatch(actions.clearSend()) @@ -943,10 +954,17 @@ function updateAndApproveTx (txData) { reject(err) } - dispatch(actions.completedTx(txData.id)) resolve(txData) }) }) + .then(() => updateMetamaskStateFromBackground()) + .then(newState => dispatch(actions.updateMetamaskState(newState))) + .then(() => { + dispatch(actions.clearSend()) + dispatch(actions.completedTx(txData.id)) + dispatch(actions.hideLoadingIndication()) + return txData + }) } } @@ -1038,13 +1056,25 @@ function cancelTypedMsg (msgData) { function cancelTx (txData) { return dispatch => { log.debug(`background.cancelTransaction`) + dispatch(actions.showLoadingIndication()) + return new Promise((resolve, reject) => { - background.cancelTransaction(txData.id, () => { + background.cancelTransaction(txData.id, err => { + if (err) { + return reject(err) + } + + resolve() + }) + }) + .then(() => updateMetamaskStateFromBackground()) + .then(newState => dispatch(actions.updateMetamaskState(newState))) + .then(() => { dispatch(actions.clearSend()) dispatch(actions.completedTx(txData.id)) - resolve(txData) + dispatch(actions.hideLoadingIndication()) + return txData }) - }) } } diff --git a/ui/app/app.js b/ui/app/app.js index 670b7e2d0..4e600fe26 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -12,7 +12,7 @@ const log = require('loglevel') const InitializeScreen = require('../../mascara/src/app/first-time').default // accounts const SendTransactionScreen = require('./components/send_/send.container') -const ConfirmTxScreen = require('./conf-tx') +const ConfirmTransaction = require('./components/pages/confirm-transaction') // slideout menu const WalletView = require('./components/wallet-view') @@ -76,7 +76,10 @@ class App extends Component { h(Authenticated, { path: REVEAL_SEED_ROUTE, exact, component: RevealSeedConfirmation }), h(Authenticated, { path: SETTINGS_ROUTE, component: Settings }), h(Authenticated, { path: NOTICE_ROUTE, exact, component: NoticeScreen }), - h(Authenticated, { path: `${CONFIRM_TRANSACTION_ROUTE}/:id?`, component: ConfirmTxScreen }), + h(Authenticated, { + path: `${CONFIRM_TRANSACTION_ROUTE}/:id?`, + component: ConfirmTransaction, + }), h(Authenticated, { path: SEND_ROUTE, exact, component: SendTransactionScreen }), h(Authenticated, { path: ADD_TOKEN_ROUTE, exact, component: AddTokenPage }), h(Authenticated, { path: CONFIRM_ADD_TOKEN_ROUTE, exact, component: ConfirmAddTokenPage }), diff --git a/ui/app/components/button/button.component.js b/ui/app/components/button/button.component.js index e8e798445..1e0ef1b64 100644 --- a/ui/app/components/button/button.component.js +++ b/ui/app/components/button/button.component.js @@ -5,15 +5,24 @@ import classnames from 'classnames' const CLASSNAME_DEFAULT = 'btn-default' const CLASSNAME_PRIMARY = 'btn-primary' const CLASSNAME_SECONDARY = 'btn-secondary' +const CLASSNAME_CONFIRM = 'btn-confirm' const CLASSNAME_LARGE = 'btn--large' const typeHash = { default: CLASSNAME_DEFAULT, primary: CLASSNAME_PRIMARY, secondary: CLASSNAME_SECONDARY, + confirm: CLASSNAME_CONFIRM, } -class Button extends Component { +export default class Button extends Component { + static propTypes = { + type: PropTypes.string, + large: PropTypes.bool, + className: PropTypes.string, + children: PropTypes.string, + } + render () { const { type, large, className, ...buttonProps } = this.props @@ -31,13 +40,3 @@ class Button extends Component { ) } } - -Button.propTypes = { - type: PropTypes.string, - large: PropTypes.bool, - className: PropTypes.string, - children: PropTypes.string, -} - -export default Button - diff --git a/ui/app/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js b/ui/app/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js new file mode 100644 index 000000000..631cf5803 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-detail-row/confirm-detail-row.component.js @@ -0,0 +1,52 @@ +import React from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' + +const ConfirmDetailRow = props => { + const { + label, + fiatFee, + ethFee, + onHeaderClick, + fiatFeeColor, + headerText, + headerTextClassName, + } = props + + return ( +
+
+ { label } +
+
+
onHeaderClick && onHeaderClick()} + > + { headerText } +
+
+ { fiatFee } +
+
+ { `\u2666 ${ethFee}` } +
+
+
+ ) +} + +ConfirmDetailRow.propTypes = { + label: PropTypes.string, + fiatFee: PropTypes.string, + ethFee: PropTypes.string, + fiatFeeColor: PropTypes.string, + onHeaderClick: PropTypes.func, + headerText: PropTypes.string, + headerTextClassName: PropTypes.string, +} + +export default ConfirmDetailRow diff --git a/ui/app/components/confirm-page-container/confirm-detail-row/index.js b/ui/app/components/confirm-page-container/confirm-detail-row/index.js new file mode 100644 index 000000000..056afff04 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-detail-row/index.js @@ -0,0 +1 @@ +export { default } from './confirm-detail-row.component' diff --git a/ui/app/components/confirm-page-container/confirm-detail-row/index.scss b/ui/app/components/confirm-page-container/confirm-detail-row/index.scss new file mode 100644 index 000000000..84d0d56ed --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-detail-row/index.scss @@ -0,0 +1,43 @@ +.confirm-detail-row { + padding: 14px 0; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + + &__label { + font-size: .75rem; + font-weight: 500; + color: $scorpion; + text-transform: uppercase; + } + + &__details { + flex: 1; + text-align: end; + } + + &__fiat { + font-size: 1.5rem; + } + + &__eth { + color: $oslo-gray; + } + + &__header-text { + font-size: .75rem; + text-transform: uppercase; + margin-bottom: 6px; + color: $scorpion; + + &--edit { + color: $curious-blue; + cursor: pointer; + } + + &--total { + font-size: .625rem; + } + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js new file mode 100644 index 000000000..7c7550170 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js @@ -0,0 +1,100 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' +import { Tabs, Tab } from '../../tabs' +import { + ConfirmPageContainerSummary, + ConfirmPageContainerError, + ConfirmPageContainerWarning, +} from './' + +export default class ConfirmPageContainerContent extends Component { + static propTypes = { + action: PropTypes.string, + title: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + titleComponent: PropTypes.func, + subtitle: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + hideSubtitle: PropTypes.bool, + errorMessage: PropTypes.string, + summaryComponent: PropTypes.node, + detailsComponent: PropTypes.node, + dataComponent: PropTypes.node, + identiconAddress: PropTypes.string, + nonce: PropTypes.string, + warning: PropTypes.string, + } + + renderContent () { + const { detailsComponent, dataComponent } = this.props + + if (detailsComponent && dataComponent) { + return this.renderTabs() + } else { + return detailsComponent || dataComponent + } + } + + renderTabs () { + const { detailsComponent, dataComponent } = this.props + + return ( + + + { detailsComponent } + + + { dataComponent } + + + ) + } + + render () { + const { + action, + title, + subtitle, + hideSubtitle, + errorMessage, + identiconAddress, + nonce, + summaryComponent, + detailsComponent, + dataComponent, + warning, + } = this.props + + return ( +
+ { + warning && ( + + ) + } + { + summaryComponent || ( + + ) + } + { this.renderContent() } + { + errorMessage && ( +
+ +
+ ) + } +
+ ) + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/confirm-page-container-error.component.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/confirm-page-container-error.component.js new file mode 100644 index 000000000..dc5b9b935 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/confirm-page-container-error.component.js @@ -0,0 +1,20 @@ +import React from 'react' +import PropTypes from 'prop-types' + +const ConfirmPageContainerError = props => { + return ( +
+ + { `ALERT: ${props.error}` } +
+ ) +} + +ConfirmPageContainerError.propTypes = { + error: PropTypes.string, +} + +export default ConfirmPageContainerError diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.js new file mode 100644 index 000000000..4ac95d0e3 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.js @@ -0,0 +1 @@ +export { default } from './confirm-page-container-error.component' diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.scss b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.scss new file mode 100644 index 000000000..e99b0f631 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-error/index.scss @@ -0,0 +1,17 @@ +.confirm-page-container-error { + height: 32px; + border: 1px solid $monzo; + color: $monzo; + background: lighten($monzo, 56%); + border-radius: 4px; + font-size: .75rem; + display: flex; + justify-content: flex-start; + align-items: center; + padding-left: 16px; + + &__icon { + margin-right: 8px; + flex: 0 0 auto; + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js new file mode 100644 index 000000000..3b1ee62c5 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js @@ -0,0 +1,56 @@ +import React from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' +import Identicon from '../../../identicon' + +const ConfirmPageContainerSummary = props => { + const { action, title, subtitle, hideSubtitle, className, identiconAddress, nonce } = props + + return ( +
+
+
+ { action } +
+ { + nonce && ( +
+ { `#${nonce}` } +
+ ) + } +
+
+ { + identiconAddress && ( + + ) + } +
+ { title } +
+
+ { + hideSubtitle ||
+ { subtitle } +
+ } +
+ ) +} + +ConfirmPageContainerSummary.propTypes = { + action: PropTypes.string, + title: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + subtitle: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + hideSubtitle: PropTypes.bool, + className: PropTypes.string, + identiconAddress: PropTypes.string, + nonce: PropTypes.string, +} + +export default ConfirmPageContainerSummary diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/index.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/index.js new file mode 100644 index 000000000..ed1b28cf2 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/index.js @@ -0,0 +1 @@ +export { default } from './confirm-page-container-summary.component' diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/index.scss b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/index.scss new file mode 100644 index 000000000..7f0f5d37a --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/index.scss @@ -0,0 +1,54 @@ +.confirm-page-container-summary { + padding: 16px 24px 0; + background-color: #f9fafa; + height: 133px; + box-sizing: border-box; + + &__action-row { + display: flex; + justify-content: space-between; + } + + &__action { + text-transform: uppercase; + color: $oslo-gray; + font-size: .75rem; + padding: 3px 8px; + border: 1px solid $oslo-gray; + border-radius: 4px; + display: inline-block; + } + + &__nonce { + color: $oslo-gray; + } + + &__title { + padding: 4px 0; + display: flex; + align-items: center; + } + + &__identicon { + flex: 0 0 auto; + margin-right: 8px; + } + + &__title-text { + font-size: 2.25rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &__subtitle { + color: $oslo-gray; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &--border { + border-bottom: 1px solid $geyser; + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js new file mode 100644 index 000000000..79901c8fc --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js @@ -0,0 +1,22 @@ +import React from 'react' +import PropTypes from 'prop-types' + +const ConfirmPageContainerWarning = props => { + return ( +
+ +
+ { props.warning } +
+
+ ) +} + +ConfirmPageContainerWarning.propTypes = { + warning: PropTypes.string, +} + +export default ConfirmPageContainerWarning diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/index.js b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/index.js new file mode 100644 index 000000000..6e48bd144 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/index.js @@ -0,0 +1 @@ +export { default } from './confirm-page-container-warning.component' diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/index.scss b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/index.scss new file mode 100644 index 000000000..189a5c5c6 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/index.scss @@ -0,0 +1,18 @@ +.confirm-page-container-warning { + background-color: #fffcdb; + display: flex; + justify-content: center; + align-items: center; + border-bottom: 1px solid $geyser; + padding: 12px 24px; + + &__icon { + flex: 0 0 auto; + margin-right: 16px; + } + + &__warning { + font-size: .75rem; + color: $oslo-gray; + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/index.js b/ui/app/components/confirm-page-container/confirm-page-container-content/index.js new file mode 100644 index 000000000..1469dd438 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/index.js @@ -0,0 +1,4 @@ +export { default } from './confirm-page-container-content.component' +export { default as ConfirmPageContainerSummary } from './confirm-page-container-summary' +export { default as ConfirmPageContainerError } from './confirm-page-container-error' +export { default as ConfirmPageContainerWarning } from './confirm-page-container-warning' diff --git a/ui/app/components/confirm-page-container/confirm-page-container-content/index.scss b/ui/app/components/confirm-page-container/confirm-page-container-content/index.scss new file mode 100644 index 000000000..39797a43f --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-content/index.scss @@ -0,0 +1,66 @@ +@import './confirm-page-container-error/index'; + +@import './confirm-page-container-warning/index'; + +@import './confirm-page-container-summary/index'; + +.confirm-page-container-content { + overflow-y: auto; + flex: 1; + + &__error-container { + padding: 0 16px 16px 16px; + } + + &__details { + box-sizing: border-box; + padding: 0 24px; + } + + &__data { + padding: 16px; + color: $oslo-gray; + } + + &__data-box { + background-color: #f9fafa; + padding: 12px; + font-size: .75rem; + margin-bottom: 16px; + word-wrap: break-word; + max-height: 200px; + overflow-y: auto; + + &-label { + text-transform: uppercase; + padding: 8px 0 12px; + font-size: 12px; + } + } + + &__data-field { + display: flex; + flex-direction: row; + + &-label { + font-weight: 500; + padding-right: 16px; + } + + &:not(:last-child) { + margin-bottom: 5px; + } + } + + &__gas-fee { + border-bottom: 1px solid $geyser; + } + + &__function-type { + font-size: .875rem; + font-weight: 500; + text-transform: capitalize; + color: $black; + padding-left: 5px; + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container-header/confirm-page-container-header.component.js b/ui/app/components/confirm-page-container/confirm-page-container-header/confirm-page-container-header.component.js new file mode 100644 index 000000000..e6fe8f82c --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-header/confirm-page-container-header.component.js @@ -0,0 +1,63 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { + ENVIRONMENT_TYPE_POPUP, + ENVIRONMENT_TYPE_NOTIFICATION, +} from '../../../../../app/scripts/lib/enums' +import NetworkDisplay from '../../network-display' + +export default class ConfirmPageContainer extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + showEdit: PropTypes.bool, + onEdit: PropTypes.func, + children: PropTypes.node, + } + + renderTop () { + const { onEdit, showEdit } = this.props + const windowType = window.METAMASK_UI_TYPE + const isFullScreen = windowType !== ENVIRONMENT_TYPE_NOTIFICATION && + windowType !== ENVIRONMENT_TYPE_POPUP + + if (!showEdit && isFullScreen) { + return null + } + + return ( +
+
+ + onEdit()} + > + { this.context.t('edit') } + +
+ { !isFullScreen && } +
+ ) + } + + render () { + const { children } = this.props + + return ( +
+ { this.renderTop() } + { children } +
+ ) + } +} diff --git a/ui/app/components/confirm-page-container/confirm-page-container-header/index.js b/ui/app/components/confirm-page-container/confirm-page-container-header/index.js new file mode 100644 index 000000000..71feb6931 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-header/index.js @@ -0,0 +1 @@ +export { default } from './confirm-page-container-header.component' 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 new file mode 100644 index 000000000..43e1e4427 --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container-header/index.scss @@ -0,0 +1,27 @@ +.confirm-page-container-header { + display: flex; + flex-direction: column; + flex: 0 0 auto; + + &__row { + display: flex; + justify-content: space-between; + border-bottom: 1px solid $geyser; + padding: 13px 13px 13px 24px; + flex: 0 0 auto; + } + + &__back-button-container { + display: flex; + justify-content: center; + align-items: center; + } + + &__back-button { + color: #2f9ae0; + font-size: 1rem; + cursor: pointer; + font-weight: 400; + padding-left: 5px; + } +} 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 new file mode 100644 index 000000000..d5247f83b --- /dev/null +++ b/ui/app/components/confirm-page-container/confirm-page-container.component.js @@ -0,0 +1,116 @@ +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 './' + +export default class ConfirmPageContainer extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + showEdit: PropTypes.bool, + onEdit: PropTypes.func, + // Sender to Recipient + fromName: PropTypes.string, + fromAddress: PropTypes.string, + toName: PropTypes.string, + toAddress: PropTypes.string, + + valid: PropTypes.bool, + errorMessage: PropTypes.string, + // Header + action: PropTypes.string, + title: PropTypes.string, + titleComponent: PropTypes.func, + subtitle: PropTypes.string, + hideSubtitle: PropTypes.bool, + // Content + summaryComponent: PropTypes.node, + contentComponent: PropTypes.node, + fiatTransactionAmount: PropTypes.string, + fiatTransactionFee: PropTypes.string, + fiatTransactionTotal: PropTypes.string, + ethTransactionAmount: PropTypes.string, + ethTransactionFee: PropTypes.string, + ethTransactionTotal: PropTypes.string, + onEditGas: PropTypes.func, + detailsComponent: PropTypes.node, + dataComponent: PropTypes.node, + identiconAddress: PropTypes.string, + nonce: PropTypes.string, + warning: PropTypes.string, + // Footer + onCancel: PropTypes.func, + onSubmit: PropTypes.func, + } + + render () { + const { + showEdit, + onEdit, + fromName, + fromAddress, + toName, + toAddress, + valid, + errorMessage, + contentComponent, + action, + title, + titleComponent, + subtitle, + hideSubtitle, + summaryComponent, + detailsComponent, + dataComponent, + onCancel, + onSubmit, + identiconAddress, + nonce, + warning, + } = this.props + + return ( +
+ onEdit()} + > + + + { + contentComponent || ( + + ) + } + onCancel()} + onSubmit={() => onSubmit()} + submitText={this.context.t('confirm')} + submitButtonType="confirm" + disabled={!valid} + /> +
+ ) + } +} diff --git a/ui/app/components/confirm-page-container/index.js b/ui/app/components/confirm-page-container/index.js new file mode 100644 index 000000000..ee88aa5d3 --- /dev/null +++ b/ui/app/components/confirm-page-container/index.js @@ -0,0 +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 ConfirmPageContainerContent, + ConfirmPageContainerSummary, + ConfirmPageContainerError, +} from './confirm-page-container-content' diff --git a/ui/app/components/confirm-page-container/index.scss b/ui/app/components/confirm-page-container/index.scss new file mode 100644 index 000000000..af7a5b555 --- /dev/null +++ b/ui/app/components/confirm-page-container/index.scss @@ -0,0 +1,5 @@ +@import './confirm-page-container-content/index'; + +@import './confirm-page-container-header/index'; + +@import './confirm-detail-row/index'; diff --git a/ui/app/components/dropdowns/components/network-dropdown-icon.js b/ui/app/components/dropdowns/components/network-dropdown-icon.js index 7e94e0af5..a45da4c10 100644 --- a/ui/app/components/dropdowns/components/network-dropdown-icon.js +++ b/ui/app/components/dropdowns/components/network-dropdown-icon.js @@ -15,6 +15,7 @@ NetworkDropdownIcon.prototype.render = function () { backgroundColor, isSelected, innerBorder = 'none', + diameter = '12', } = this.props return h(`.menu-icon-circle${isSelected ? '--active' : ''}`, {}, @@ -22,6 +23,8 @@ NetworkDropdownIcon.prototype.render = function () { style: { background: backgroundColor, border: innerBorder, + height: `${diameter}px`, + width: `${diameter}px`, }, }) ) diff --git a/ui/app/components/index.scss b/ui/app/components/index.scss index 351640f6e..32f0e90e4 100644 --- a/ui/app/components/index.scss +++ b/ui/app/components/index.scss @@ -4,6 +4,16 @@ @import './info-box/index'; +@import './network-display/index'; + +@import './confirm-page-container/index'; + +@import './page-container/index'; + @import './pages/index'; @import './modals/index'; + +@import './sender-to-recipient/index'; + +@import './tabs/index'; diff --git a/ui/app/components/input-number.js b/ui/app/components/input-number.js index 59c6842ef..01f751b69 100644 --- a/ui/app/components/input-number.js +++ b/ui/app/components/input-number.js @@ -2,10 +2,8 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const { - addCurrencies, conversionGTE, conversionLTE, - subtractCurrencies, } = require('../conversion-util') module.exports = InputNumber @@ -51,7 +49,11 @@ InputNumber.prototype.setValue = function (newValue) { } InputNumber.prototype.render = function () { +<<<<<<< HEAD const { unitLabel, step = 1, placeholder, value } = this.props +======= + const { unitLabel, step = 1, placeholder, value = 0, min = -1, max = Infinity } = this.props +>>>>>>> Refactor and redesign confirm transaction views return h('div.customize-gas-input-wrapper', {}, [ h('input', { @@ -67,11 +69,19 @@ InputNumber.prototype.render = function () { h('span.gas-tooltip-input-detail', {}, [unitLabel]), h('div.gas-tooltip-input-arrows', {}, [ h('i.fa.fa-angle-up', { +<<<<<<< HEAD onClick: () => this.setValue(addCurrencies(value, step, { toNumericBase: 'dec' })), }), h('i.fa.fa-angle-down', { style: { cursor: 'pointer' }, onClick: () => this.setValue(subtractCurrencies(value, step, { toNumericBase: 'dec' })), +======= + onClick: () => this.setValue(Math.min(+value + step, max)), + }), + h('i.fa.fa-angle-down', { + style: { cursor: 'pointer' }, + onClick: () => this.setValue(Math.max(+value - step, min)), +>>>>>>> Refactor and redesign confirm transaction views }), ]), ]) diff --git a/ui/app/components/modals/customize-gas/customize-gas.component.js b/ui/app/components/modals/customize-gas/customize-gas.component.js new file mode 100644 index 000000000..cfaafd2b9 --- /dev/null +++ b/ui/app/components/modals/customize-gas/customize-gas.component.js @@ -0,0 +1,140 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import GasModalCard from '../../customize-gas-modal/gas-modal-card' +import { MIN_GAS_PRICE_GWEI } from '../../send_/send.constants' + +import { + getDecimalGasLimit, + getDecimalGasPrice, + getPrefixedHexGasLimit, + getPrefixedHexGasPrice, +} from './customize-gas.util' + +export default class CustomizeGas extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + txData: PropTypes.object.isRequired, + hideModal: PropTypes.func, + validate: PropTypes.func, + onSubmit: PropTypes.func, + } + + state = { + gasPrice: 0, + gasLimit: 0, + originalGasPrice: 0, + originalGasLimit: 0, + } + + componentDidMount () { + const { txData = {} } = this.props + const { txParams: { gas: hexGasLimit, gasPrice: hexGasPrice } = {} } = txData + + const gasLimit = getDecimalGasLimit(hexGasLimit) + const gasPrice = getDecimalGasPrice(hexGasPrice) + + this.setState({ + gasPrice, + gasLimit, + originalGasPrice: gasPrice, + originalGasLimit: gasLimit, + }) + } + + handleRevert () { + const { originalGasPrice, originalGasLimit } = this.state + + this.setState({ + gasPrice: originalGasPrice, + gasLimit: originalGasLimit, + }) + } + + handleSave () { + const { onSubmit, hideModal } = this.props + const { gasLimit, gasPrice } = this.state + const prefixedHexGasPrice = getPrefixedHexGasPrice(gasPrice) + const prefixedHexGasLimit = getPrefixedHexGasLimit(gasLimit) + + Promise.resolve(onSubmit({ gasPrice: prefixedHexGasPrice, gasLimit: prefixedHexGasLimit })) + .then(() => hideModal()) + } + + validate () { + const { gasLimit, gasPrice } = this.state + return this.props.validate({ + gasPrice: getPrefixedHexGasPrice(gasPrice), + gasLimit: getPrefixedHexGasLimit(gasLimit), + }) + } + + render () { + const { t } = this.context + const { hideModal } = this.props + const { gasPrice, gasLimit } = this.state + const { valid, errorMessage } = this.validate() + + return ( +
+
+
+
+ { this.context.t('customGas') } +
+
hideModal()} + /> +
+
+ this.setState({ gasPrice: value })} + title={t('gasPrice')} + copy={t('gasPriceCalculation')} + /> + this.setState({ gasLimit: value })} + title={t('gasLimit')} + copy={t('gasLimitCalculation')} + /> +
+
+ { !valid &&
{ errorMessage }
} +
this.handleRevert()} + > + { t('revert') } +
+
+ + +
+
+
+
+ ) + } +} diff --git a/ui/app/components/modals/customize-gas/customize-gas.container.js b/ui/app/components/modals/customize-gas/customize-gas.container.js new file mode 100644 index 000000000..46a799795 --- /dev/null +++ b/ui/app/components/modals/customize-gas/customize-gas.container.js @@ -0,0 +1,22 @@ +import { connect } from 'react-redux' +import CustomizeGas from './customize-gas.component' +import { hideModal } from '../../../actions' + +const mapStateToProps = state => { + const { appState: { modal: { modalState: { props } } } } = state + const { txData, onSubmit, validate } = props + + return { + txData, + onSubmit, + validate, + } +} + +const mapDispatchToProps = dispatch => { + return { + hideModal: () => dispatch(hideModal()), + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(CustomizeGas) diff --git a/ui/app/components/modals/customize-gas/customize-gas.util.js b/ui/app/components/modals/customize-gas/customize-gas.util.js new file mode 100644 index 000000000..6ba4a7705 --- /dev/null +++ b/ui/app/components/modals/customize-gas/customize-gas.util.js @@ -0,0 +1,34 @@ +import ethUtil from 'ethereumjs-util' +import { conversionUtil } from '../../../conversion-util' + +export function getDecimalGasLimit (hexGasLimit) { + return conversionUtil(hexGasLimit, { + fromNumericBase: 'hex', + toNumericBase: 'dec', + }) +} + +export function getDecimalGasPrice (hexGasPrice) { + return conversionUtil(hexGasPrice, { + fromNumericBase: 'hex', + toNumericBase: 'dec', + fromDenomination: 'WEI', + toDenomination: 'GWEI', + }) +} + +export function getPrefixedHexGasLimit (gasLimit) { + return ethUtil.addHexPrefix(conversionUtil(gasLimit, { + fromNumericBase: 'dec', + toNumericBase: 'hex', + })) +} + +export function getPrefixedHexGasPrice (gasPrice) { + return ethUtil.addHexPrefix(conversionUtil(gasPrice, { + fromNumericBase: 'dec', + toNumericBase: 'hex', + fromDenomination: 'GWEI', + toDenomination: 'WEI', + })) +} diff --git a/ui/app/components/modals/customize-gas/index.js b/ui/app/components/modals/customize-gas/index.js new file mode 100644 index 000000000..3a0ab7edc --- /dev/null +++ b/ui/app/components/modals/customize-gas/index.js @@ -0,0 +1 @@ +export { default } from './customize-gas.container' diff --git a/ui/app/components/modals/customize-gas/index.scss b/ui/app/components/modals/customize-gas/index.scss new file mode 100644 index 000000000..e10452691 --- /dev/null +++ b/ui/app/components/modals/customize-gas/index.scss @@ -0,0 +1,110 @@ +.customize-gas { + border: 1px solid #D8D8D8; + border-radius: 4px; + background-color: #FFFFFF; + box-shadow: 0 2px 4px 0 rgba(0,0,0,0.14); + font-family: Roboto; + display: flex; + flex-flow: column; + + @media screen and (max-width: $break-small) { + width: 100vw; + height: 100vh; + } + + &__header { + height: 52px; + border-bottom: 1px solid $alto; + display: flex; + align-items: center; + justify-content: space-between; + font-size: 22px; + + @media screen and (max-width: $break-small) { + flex: 0 0 auto; + } + } + + &__title { + margin-left: 19.25px; + } + + &__close::after { + content: '\00D7'; + font-size: 1.8em; + color: $dusty-gray; + font-family: sans-serif; + cursor: pointer; + margin-right: 19.25px; + } + + &__content { + display: flex; + flex-flow: column nowrap; + height: 100%; + } + + &__body { + display: flex; + margin-bottom: 24px; + + @media screen and (max-width: $break-small) { + flex-flow: column; + flex: 1 1 auto; + } + } + + &__footer { + height: 75px; + border-top: 1px solid $alto; + display: flex; + align-items: center; + justify-content: space-between; + font-size: 22px; + position: relative; + + @media screen and (max-width: $break-small) { + flex: 0 0 auto; + } + } + + &__buttons { + display: flex; + justify-content: space-between; + margin-right: 21.25px; + } + + &__revert, &__cancel, &__save, &__save__error { + display: flex; + justify-content: center; + align-items: center; + padding: 0 3px; + cursor: pointer; + } + + &__revert { + color: $silver-chalice; + font-size: 16px; + margin-left: 21.25px; + } + + &__cancel, &__save, &__save__error { + width: 85.74px; + min-width: initial; + } + + &__save__error { + opacity: 0.5; + cursor: auto; + } + + &__error-message { + display: block; + position: absolute; + top: 4px; + right: 4px; + font-size: 12px; + line-height: 12px; + color: $red; + } +} diff --git a/ui/app/components/modals/index.scss b/ui/app/components/modals/index.scss index ad6fe16d3..160911c10 100644 --- a/ui/app/components/modals/index.scss +++ b/ui/app/components/modals/index.scss @@ -1,3 +1,5 @@ +@import './customize-gas/index'; + .modal-container { width: 100%; height: 100%; diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js index 85e85597a..973438b6b 100644 --- a/ui/app/components/modals/modal.js +++ b/ui/app/components/modals/modal.js @@ -24,6 +24,8 @@ const TransactionConfirmed = require('./transaction-confirmed') const WelcomeBeta = require('./welcome-beta') const Notification = require('./notification') +import ConfirmCustomizeGasModal from './customize-gas' + const modalContainerBaseStyle = { transform: 'translate3d(-50%, 0, 0px)', border: '1px solid #CCCFD1', @@ -267,7 +269,31 @@ const MODALS = { CUSTOMIZE_GAS: { contents: [ - h(CustomizeGasModal, {}, []), + h(CustomizeGasModal), + ], + mobileModalStyle: { + width: '100vw', + height: '100vh', + top: '0', + transform: 'none', + left: '0', + right: '0', + margin: '0 auto', + }, + laptopModalStyle: { + width: '720px', + height: '377px', + top: '80px', + transform: 'none', + left: '0', + right: '0', + margin: '0 auto', + }, + }, + + CONFIRM_CUSTOMIZE_GAS: { + contents: [ + h(ConfirmCustomizeGasModal), ], mobileModalStyle: { width: '100vw', diff --git a/ui/app/components/network-display.js b/ui/app/components/network-display.js deleted file mode 100644 index 59719d9a4..000000000 --- a/ui/app/components/network-display.js +++ /dev/null @@ -1,56 +0,0 @@ -const { Component } = require('react') -const h = require('react-hyperscript') -const PropTypes = require('prop-types') -const connect = require('react-redux').connect -const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon') - -const networkToColorHash = { - 1: '#038789', - 3: '#e91550', - 42: '#690496', - 4: '#ebb33f', -} - -class NetworkDisplay extends Component { - renderNetworkIcon () { - const { network } = this.props - const networkColor = networkToColorHash[network] - - return networkColor - ? h(NetworkDropdownIcon, { backgroundColor: networkColor }) - : h('i.fa.fa-question-circle.fa-med', { - style: { - margin: '0 4px', - color: 'rgb(125, 128, 130)', - }, - }) - } - - render () { - const { provider: { type } } = this.props - return h('.network-display__container', [ - this.renderNetworkIcon(), - h('.network-name', this.context.t(type)), - ]) - } -} - -NetworkDisplay.propTypes = { - network: PropTypes.string, - provider: PropTypes.object, - t: PropTypes.func, -} - -const mapStateToProps = ({ metamask: { network, provider } }) => { - return { - network, - provider, - } -} - -NetworkDisplay.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect(mapStateToProps)(NetworkDisplay) - diff --git a/ui/app/components/network-display/index.js b/ui/app/components/network-display/index.js new file mode 100644 index 000000000..f6878ae5b --- /dev/null +++ b/ui/app/components/network-display/index.js @@ -0,0 +1,2 @@ +import NetworkDisplay from './network-display.container' +module.exports = NetworkDisplay diff --git a/ui/app/components/network-display/index.scss b/ui/app/components/network-display/index.scss new file mode 100644 index 000000000..3bce81aaa --- /dev/null +++ b/ui/app/components/network-display/index.scss @@ -0,0 +1,54 @@ +.network-display { + &__container { + 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; + + &--mainnet { + background-color: lighten($blue-lagoon, 45%); + } + + &--ropsten { + background-color: lighten($crimson, 45%); + } + + &--kovan { + background-color: lighten($purple, 45%); + } + + &--rinkeby { + background-color: lighten($tulip-tree, 45%); + } + } + + &__name { + font-size: .875rem; + padding-left: 5px; + } + + &__icon { + height: 10px; + width: 10px; + border-radius: 10px; + + &--mainnet { + background-color: $blue-lagoon; + } + + &--ropsten { + background-color: $crimson; + } + + &--kovan { + background-color: $purple; + } + + &--rinkeby { + background-color: $tulip-tree; + } + } +} diff --git a/ui/app/components/network-display/network-display.component.js b/ui/app/components/network-display/network-display.component.js new file mode 100644 index 000000000..38626af20 --- /dev/null +++ b/ui/app/components/network-display/network-display.component.js @@ -0,0 +1,69 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import classnames from 'classnames' +import { + MAINNET_CODE, + ROPSTEN_CODE, + RINKEYBY_CODE, + KOVAN_CODE, +} from '../../../../app/scripts/controllers/network/enums' + +const networkToClassHash = { + [MAINNET_CODE]: 'mainnet', + [ROPSTEN_CODE]: 'ropsten', + [RINKEYBY_CODE]: 'rinkeby', + [KOVAN_CODE]: 'kovan', +} + +export default class NetworkDisplay extends Component { + static propTypes = { + network: PropTypes.string, + provider: PropTypes.object, + } + + static contextTypes = { + t: PropTypes.func, + } + + renderNetworkIcon () { + const { network } = this.props + const networkClass = networkToClassHash[network] + + return networkClass + ?
+ :
+ } + + render () { + const { network, provider: { type } } = this.props + const networkClass = networkToClassHash[network] + + return ( +
+ { + networkClass + ?
+ :
+ } +
+ { this.context.t(type) } +
+
+ ) + } +} diff --git a/ui/app/components/network-display/network-display.container.js b/ui/app/components/network-display/network-display.container.js new file mode 100644 index 000000000..99a14fff4 --- /dev/null +++ b/ui/app/components/network-display/network-display.container.js @@ -0,0 +1,11 @@ +import { connect } from 'react-redux' +import NetworkDisplay from './network-display.component' + +const mapStateToProps = ({ metamask: { network, provider } }) => { + return { + network, + provider, + } +} + +export default connect(mapStateToProps)(NetworkDisplay) diff --git a/ui/app/components/page-container/index.js b/ui/app/components/page-container/index.js index 415870b37..913b8c9c6 100644 --- a/ui/app/components/page-container/index.js +++ b/ui/app/components/page-container/index.js @@ -1 +1,4 @@ +import PageContainerHeader from './page-container-header' +import PageContainerFooter from './page-container-footer' export { default } from './page-container.component' +export { PageContainerHeader, PageContainerFooter } diff --git a/ui/app/components/page-container/index.scss b/ui/app/components/page-container/index.scss new file mode 100644 index 000000000..06c3ef709 --- /dev/null +++ b/ui/app/components/page-container/index.scss @@ -0,0 +1,186 @@ +.page-container { + width: 408px; + background-color: $white; + box-shadow: 0 0 7px 0 rgba(0, 0, 0, .08); + z-index: 25; + display: flex; + flex-flow: column; + border-radius: 8px; + + &__header { + display: flex; + flex-flow: column; + border-bottom: 1px solid $geyser; + padding: 16px; + flex: 0 0 auto; + position: relative; + + &--no-padding-bottom { + padding-bottom: 0; + } + } + + &__header-close { + color: $tundora; + position: absolute; + top: 16px; + right: 16px; + cursor: pointer; + overflow: hidden; + + &::after { + content: '\00D7'; + font-size: 40px; + line-height: 20px; + } + } + + &__header-row { + padding-bottom: 10px; + display: flex; + justify-content: space-between; + } + + &__footer { + display: flex; + flex-flow: row; + justify-content: center; + border-top: 1px solid $geyser; + padding: 16px; + flex: 0 0 auto; + + .btn-default, + .btn-confirm { + font-size: 1rem; + } + } + + &__footer-button { + height: 55px; + font-size: 1rem; + text-transform: uppercase; + margin-right: 16px; + + &:last-of-type { + margin-right: 0; + } + } + + &__back-button { + color: #2f9ae0; + font-size: 1rem; + cursor: pointer; + font-weight: 400; + } + + &__title { + color: $black; + font-size: 2rem; + font-weight: 500; + line-height: 2rem; + } + + &__subtitle { + padding-top: .5rem; + line-height: initial; + font-size: .9rem; + color: $gray; + } + + &__tabs { + display: flex; + margin-top: 16px; + } + + &__tab { + min-width: 5rem; + padding: 8px; + color: $dusty-gray; + font-family: Roboto; + font-size: 1rem; + text-align: center; + cursor: pointer; + border-bottom: none; + margin-right: 16px; + + &:last-of-type { + margin-right: 0; + } + + &--selected { + color: $curious-blue; + border-bottom: 3px solid $curious-blue; + } + } + + &--full-width { + width: 100% !important; + } + + &--full-height { + height: 100% !important; + max-height: initial !important; + min-height: initial !important; + } + + &__content { + overflow-y: auto; + flex: 1; + } + + &__warning-container { + background: $linen; + padding: 20px; + display: flex; + align-items: start; + } + + &__warning-message { + padding-left: 15px; + } + + &__warning-title { + font-weight: 500; + } + + &__warning-icon { + padding-top: 5px; + } +} + +@media screen and (max-width: 250px) { + .page-container { + &__footer { + flex-flow: column-reverse; + } + + &__footer-button { + width: 100%; + margin-bottom: 1rem; + margin-right: 0; + + &:first-of-type { + margin-bottom: 0; + } + } + } +} + +@media screen and (max-width: 575px) { + .page-container { + height: 100%; + width: 100%; + overflow-y: auto; + background-color: $white; + border-radius: 0; + flex: 1; + } +} + +@media screen and (min-width: 576px) { + .page-container { + max-height: 82vh; + min-height: 570px; + flex: 0 0 auto; + } +} diff --git a/ui/app/components/page-container/page-container-footer/page-container-footer.component.js b/ui/app/components/page-container/page-container-footer/page-container-footer.component.js index 0458ae78a..3d15df294 100644 --- a/ui/app/components/page-container/page-container-footer/page-container-footer.component.js +++ b/ui/app/components/page-container/page-container-footer/page-container-footer.component.js @@ -10,6 +10,7 @@ export default class PageContainerFooter extends Component { onSubmit: PropTypes.func, submitText: PropTypes.string, disabled: PropTypes.bool, + submitButtonType: PropTypes.string, } static contextTypes = { @@ -23,6 +24,7 @@ export default class PageContainerFooter extends Component { onSubmit, submitText, disabled, + submitButtonType, } = this.props return ( @@ -30,16 +32,16 @@ export default class PageContainerFooter extends Component {