From 342dc95410b10f042b3f8ee4135f5fef1fd6fe93 Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Thu, 2 Aug 2018 13:32:22 -0230 Subject: Adds the content of the advanced tab - w/o chart or dynamic content - to gas customize modal. --- .../advanced-tab-content.component.js | 105 ++++++++++++++++++++ .../advanced-tab-content/index.js | 1 + .../advanced-tab-content/index.scss | 109 +++++++++++++++++++++ .../advanced-tab-content/time-remaining/index.js | 1 + .../advanced-tab-content/time-remaining/index.scss | 13 +++ .../time-remaining/time-remaining.component.js | 33 +++++++ .../time-remaining/time-remaining.utils.js | 11 +++ .../gas-modal-page-container.component.js | 40 ++++++-- .../gas-modal-page-container.container.js | 19 +++- .../gas-modal-page-container/index.scss | 8 ++ .../gas-slider/gas-slider.component.js | 48 +++++++++ .../gas-customization/gas-slider/index.js | 1 + .../gas-customization/gas-slider/index.scss | 54 ++++++++++ ui/app/components/gas-customization/index.scss | 3 + ui/app/components/index.scss | 8 +- ui/app/css/itcss/components/gas-slider.scss | 51 ---------- ui/app/css/itcss/settings/variables.scss | 1 + ui/app/ducks/custom-gas.js | 67 +++++++++++++ ui/app/reducers.js | 3 + ui/app/selectors/custom-gas.js | 19 ++++ 20 files changed, 532 insertions(+), 63 deletions(-) create mode 100644 ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js create mode 100644 ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/index.js create mode 100644 ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/index.scss create mode 100644 ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.js create mode 100644 ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.scss create mode 100644 ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.component.js create mode 100644 ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.utils.js create mode 100644 ui/app/components/gas-customization/gas-slider/gas-slider.component.js create mode 100644 ui/app/components/gas-customization/gas-slider/index.js create mode 100644 ui/app/components/gas-customization/gas-slider/index.scss create mode 100644 ui/app/components/gas-customization/index.scss create mode 100644 ui/app/ducks/custom-gas.js create mode 100644 ui/app/selectors/custom-gas.js (limited to 'ui') diff --git a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js new file mode 100644 index 000000000..7ddf13e51 --- /dev/null +++ b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js @@ -0,0 +1,105 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { + MIN_GAS_PRICE_DEC, + MIN_GAS_LIMIT_DEC, +} from '../../../send/send.constants' +import GasSlider from '../../gas-slider' +import TimeRemaining from './time-remaining' + +export default class AdvancedTabContent extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + updateCustomGasPrice: PropTypes.func, + updateCustomGasLimit: PropTypes.func, + customGasPrice: PropTypes.number, + customGasLimit: PropTypes.number, + millisecondsRemaining: PropTypes.number, + } + + gasInput (value, onChange, min, precision, showGWEI) { + return ( +
+ onChange(Number(event.target.value))} + /> + {showGWEI + ? GWEI + : null} +
+ ) + } + + infoButton (onClick) { + return + } + + render () { + const { + updateCustomGasPrice, + updateCustomGasLimit, + millisecondsRemaining, + customGasPrice, + customGasLimit, + } = this.props + + return ( +
+
+
+ New Transaction Fee + ~Transaction Time +
+
+
+ $0.30 +
+ +
+
+
+ Live Transaction Fee Predictions +
+
+
+ { + updateCustomGasPrice(Number(value)) + }} + lowLabel={'Cheaper'} + highLabel={'Faster'} + value={customGasPrice} + step={0.1} + max={200} + min={0} + coloredStart={{}} + /> +
+
+
+
+ Gas Price + { this.infoButton(() => {}) } +
+ { this.gasInput(customGasPrice, updateCustomGasPrice, MIN_GAS_PRICE_DEC, 9, true) } +
+
+
+ Gas Limit + { this.infoButton(() => {}) } +
+ { this.gasInput(customGasLimit, updateCustomGasLimit, MIN_GAS_LIMIT_DEC, 0) } +
+
+
+ ) + } +} diff --git a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/index.js b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/index.js new file mode 100644 index 000000000..492037f25 --- /dev/null +++ b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/index.js @@ -0,0 +1 @@ +export { default } from './advanced-tab-content.component' diff --git a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/index.scss b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/index.scss new file mode 100644 index 000000000..5dc30e061 --- /dev/null +++ b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/index.scss @@ -0,0 +1,109 @@ +@import './time-remaining/index'; + +.advanced-tab { + display: flex; + flex-flow: column; + border-bottom: 1px solid $alto; + + &__transaction-data-summary, + &__fee-chart-title, + &__gas-edit-row { + padding-left: 24px; + padding-right: 24px; + } + + &__transaction-data-summary { + display: flex; + flex-flow: column; + color: $mid-gray; + margin-top: 12px; + + &__titles, + &__container { + display: flex; + flex-flow: row; + justify-content: space-between; + font-size: 12px; + } + + &__container { + font-size: 26px; + margin-top: 6px; + } + } + + &__fee-chart-title { + font-size: 14px; + color: $scorpion; + margin-top: 22px; + } + + &__fee-chart { + padding-left: 10px; + margin-top: 24px; + height: 134px; + } + + &__slider-container { + padding-left: 27px; + padding-right: 27px; + } + + &__gas-edit-rows { + margin-top: 44px; + height: 87px; + display: flex; + flex-flow: column; + justify-content: space-between; + } + + &__gas-edit-row { + display: flex; + flex-flow: row; + justify-content: space-between; + + &__label { + color: $mid-gray; + font-size: 16px; + + .info-circle { + color: $silver; + margin-left: 10px; + } + } + + + &__input-wrapper { + position: relative; + } + + &__input { + border: 1px solid $dusty-gray; + border-radius: 4px; + color: $mid-gray; + font-size: 16px; + height: 37px; + width: 163px; + padding: 8px 10px 10px 10px; + } + + input[type="number"]::-webkit-inner-spin-button { + -webkit-appearance: none; + -moz-appearance: none; + display: none; + } + + input[type="number"]:hover::-webkit-inner-spin-button { + -webkit-appearance: none; + -moz-appearance: none; + display: none; + } + + &__gwei-symbol { + position: absolute; + top: 8px; + right: 10px; + color: $dusty-gray; + } + } +} \ No newline at end of file diff --git a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.js b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.js new file mode 100644 index 000000000..61b681e1a --- /dev/null +++ b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.js @@ -0,0 +1 @@ +export { default } from './time-remaining.component' diff --git a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.scss b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.scss new file mode 100644 index 000000000..01bb06268 --- /dev/null +++ b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/index.scss @@ -0,0 +1,13 @@ +.time-remaining { + .minutes-num, .seconds-num { + font-size: 26px; + } + + .seconds-num { + margin-left: 7px; + } + + .minutes-label, .seconds-label { + font-size: 14px; + } +} \ No newline at end of file diff --git a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.component.js b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.component.js new file mode 100644 index 000000000..826d41f9c --- /dev/null +++ b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.component.js @@ -0,0 +1,33 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { getTimeBreakdown } from './time-remaining.utils' + +export default class TimeRemaining extends Component { + static contextTypes = { + t: PropTypes.func, + } + + static propTypes = { + milliseconds: PropTypes.number, + } + + render () { + const { + milliseconds, + } = this.props + + const { + minutes, + seconds, + } = getTimeBreakdown(milliseconds) + + return ( +
+ {minutes} + {this.context.t('minutesShorthand')} + {seconds} + {this.context.t('secondsShorthand')} +
+ ) + } +} diff --git a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.utils.js b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.utils.js new file mode 100644 index 000000000..cf43e0acb --- /dev/null +++ b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/time-remaining/time-remaining.utils.js @@ -0,0 +1,11 @@ +function getTimeBreakdown (milliseconds) { + return { + hours: Math.floor(milliseconds / 3600000), + minutes: Math.floor((milliseconds % 3600000) / 60000), + seconds: Math.floor((milliseconds % 60000) / 1000), + } +} + +module.exports = { + getTimeBreakdown, +} diff --git a/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js b/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js index 697594ec9..1d7a9d986 100644 --- a/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js +++ b/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js @@ -2,6 +2,7 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import PageContainer from '../../page-container' import { Tabs, Tab } from '../../tabs' +import AdvancedTabContent from './advanced-tab-content' export default class GasModalPageContainer extends Component { static contextTypes = { @@ -10,6 +11,10 @@ export default class GasModalPageContainer extends Component { static propTypes = { hideModal: PropTypes.func, + updateCustomGasPrice: PropTypes.func, + updateCustomGasLimit: PropTypes.func, + customGasPrice: PropTypes.number, + customGasLimit: PropTypes.number, } state = {} @@ -20,9 +25,22 @@ export default class GasModalPageContainer extends Component { ) } - renderAdvancedTabContent () { + renderAdvancedTabContent = () => { + const { + updateCustomGasPrice, + updateCustomGasLimit, + customGasPrice, + customGasLimit, + } = this.props + return ( -
+ ) } @@ -68,14 +86,16 @@ export default class GasModalPageContainer extends Component { const { hideModal } = this.props return ( - hideModal()} - onClose={() => hideModal()} - /> +
+ hideModal()} + onClose={() => hideModal()} + /> +
) } } diff --git a/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js b/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js index 71c700507..f7ac91a38 100644 --- a/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js +++ b/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js @@ -1,11 +1,28 @@ import { connect } from 'react-redux' import GasModalPageContainer from './gas-modal-page-container.component' import { hideModal } from '../../../actions' +import { + setCustomGasPrice, + setCustomGasLimit, +} from '../../../ducks/custom-gas' +import { + getCustomGasPrice, + getCustomGasLimit, +} from '../../../selectors/custom-gas' + +const mapStateToProps = state => { + return { + customGasPrice: getCustomGasPrice(state), + customGasLimit: getCustomGasLimit(state), + } +} const mapDispatchToProps = dispatch => { return { hideModal: () => dispatch(hideModal()), + updateCustomGasPrice: (newPrice) => dispatch(setCustomGasPrice(newPrice)), + updateCustomGasLimit: (newLimit) => dispatch(setCustomGasLimit(newLimit)), } } -export default connect(null, mapDispatchToProps)(GasModalPageContainer) +export default connect(mapStateToProps, mapDispatchToProps)(GasModalPageContainer) diff --git a/ui/app/components/gas-customization/gas-modal-page-container/index.scss b/ui/app/components/gas-customization/gas-modal-page-container/index.scss index a6609a385..027165b48 100644 --- a/ui/app/components/gas-customization/gas-modal-page-container/index.scss +++ b/ui/app/components/gas-customization/gas-modal-page-container/index.scss @@ -1,3 +1,11 @@ +@import './advanced-tab-content/index'; + +.gas-modal-page-container { + .page-container { + width: 391px; + } +} + .gas-modal-content { &__basic-tab { height: 219px; diff --git a/ui/app/components/gas-customization/gas-slider/gas-slider.component.js b/ui/app/components/gas-customization/gas-slider/gas-slider.component.js new file mode 100644 index 000000000..5836e7dfc --- /dev/null +++ b/ui/app/components/gas-customization/gas-slider/gas-slider.component.js @@ -0,0 +1,48 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' + +export default class AdvancedTabContent extends Component { + static propTypes = { + onChange: PropTypes.func, + lowLabel: PropTypes.string, + highLabel: PropTypes.string, + value: PropTypes.number, + step: PropTypes.number, + max: PropTypes.number, + min: PropTypes.number, + } + + render () { + const { + onChange, + lowLabel, + highLabel, + value, + step, + max, + min, + } = this.props + + return ( +
+ onChange(event.target.value)} + /> +
+
+
+
+ {lowLabel} + {highLabel} +
+
+ ) + } +} diff --git a/ui/app/components/gas-customization/gas-slider/index.js b/ui/app/components/gas-customization/gas-slider/index.js new file mode 100644 index 000000000..f1752c93f --- /dev/null +++ b/ui/app/components/gas-customization/gas-slider/index.js @@ -0,0 +1 @@ +export { default } from './gas-slider.component' diff --git a/ui/app/components/gas-customization/gas-slider/index.scss b/ui/app/components/gas-customization/gas-slider/index.scss new file mode 100644 index 000000000..e6c734367 --- /dev/null +++ b/ui/app/components/gas-customization/gas-slider/index.scss @@ -0,0 +1,54 @@ +.gas-slider { + position: relative; + width: 322px; + + &__input { + width: 322px; + margin-left: -2px; + z-index: 2; + } + + input[type=range] { + -webkit-appearance: none !important; + } + + input[type=range]::-webkit-slider-thumb { + -webkit-appearance: none !important; + height: 34px; + width: 34px; + background-color: $curious-blue; + box-shadow: 0 2px 4px 0 rgba(0,0,0,0.08); + border-radius: 50%; + position: relative; + z-index: 10; + } + + &__bar { + height: 6px; + width: 322px; + background: $alto; + display: flex; + justify-content: space-between; + position: absolute; + top: 16px; + z-index: 0; + border-radius: 4px; + } + + &__colored { + height: 6px; + border-radius: 4px; + margin-left: 102px; + width: 322px; + z-index: 1; + background-color: $blizzard-blue; + } + + &__labels { + display: flex; + justify-content: space-between; + font-size: 12px; + margin-top: -6px; + color: $mid-gray; + } +} \ No newline at end of file diff --git a/ui/app/components/gas-customization/index.scss b/ui/app/components/gas-customization/index.scss new file mode 100644 index 000000000..91ca5004e --- /dev/null +++ b/ui/app/components/gas-customization/index.scss @@ -0,0 +1,3 @@ +@import './gas-slider/index'; + +@import './gas-modal-page-container/index'; diff --git a/ui/app/components/index.scss b/ui/app/components/index.scss index 48c6496d9..156b1b9f6 100644 --- a/ui/app/components/index.scss +++ b/ui/app/components/index.scss @@ -64,4 +64,10 @@ @import './unit-input/index'; -@import './gas-customization/gas-modal-page-container/index' +@import './gas-customization/gas-modal-page-container/index'; + +@import './gas-customization/gas-modal-page-container/index'; + +@import './gas-customization/gas-modal-page-container/index'; + +@import './gas-customization/index'; diff --git a/ui/app/css/itcss/components/gas-slider.scss b/ui/app/css/itcss/components/gas-slider.scss index c27a560bd..e69de29bb 100644 --- a/ui/app/css/itcss/components/gas-slider.scss +++ b/ui/app/css/itcss/components/gas-slider.scss @@ -1,51 +0,0 @@ -.gas-slider { - position: relative; - width: 313px; - - &__input { - width: 317px; - margin-left: -2px; - z-index: 2; - } - - input[type=range] { - -webkit-appearance: none !important; - } - - input[type=range]::-webkit-slider-thumb { - -webkit-appearance: none !important; - height: 26px; - width: 26px; - border: 2px solid #B8B8B8; - background-color: #FFFFFF; - box-shadow: 0 2px 4px 0 rgba(0,0,0,0.08); - border-radius: 50%; - position: relative; - z-index: 10; - } - - &__bar { - height: 6px; - width: 313px; - background: $alto; - display: flex; - justify-content: space-between; - position: absolute; - top: 11px; - z-index: 0; - } - - &__low, &__high { - height: 6px; - width: 49px; - z-index: 1; - } - - &__low { - background-color: $crimson; - } - - &__high { - background-color: $caribbean-green; - } -} \ No newline at end of file diff --git a/ui/app/css/itcss/settings/variables.scss b/ui/app/css/itcss/settings/variables.scss index 6c2b82f39..1c95f06a0 100644 --- a/ui/app/css/itcss/settings/variables.scss +++ b/ui/app/css/itcss/settings/variables.scss @@ -57,6 +57,7 @@ $ecstasy: #f7861c; $linen: #fdf4f4; $oslo-gray: #8C8E94; $polar: #fafcfe; +$blizzard-blue: #bfdef3; /* Z-Indicies diff --git a/ui/app/ducks/custom-gas.js b/ui/app/ducks/custom-gas.js new file mode 100644 index 000000000..f1f483e93 --- /dev/null +++ b/ui/app/ducks/custom-gas.js @@ -0,0 +1,67 @@ +import extend from 'xtend' + +// Actions +const SET_CUSTOM_GAS_PRICE = 'metamask/custom-gas/SET_CUSTOM_GAS_PRICE' +const SET_CUSTOM_GAS_LIMIT = 'metamask/custom-gas/SET_CUSTOM_GAS_LIMIT' +const SET_CUSTOM_GAS_ERRORS = 'metamask/custom-gas/SET_CUSTOM_GAS_ERRORS' +const RESET_CUSTOM_GAS_STATE = 'metamask/custom-gas/RESET_CUSTOM_GAS_STATE' + +// TODO: determine if this approach to initState is consistent with conventional ducks pattern +const initState = { + price: 0, + limit: 21000, + errors: {}, +} + +// Reducer +export default function reducer ({ customGas: customGasState = initState }, action = {}) { + const newState = extend({}, customGasState) + + switch (action.type) { + case SET_CUSTOM_GAS_PRICE: + return extend(newState, { + price: action.value, + }) + case SET_CUSTOM_GAS_LIMIT: + return extend(newState, { + limit: action.value, + }) + case SET_CUSTOM_GAS_ERRORS: + return extend(newState, { + errors: { + ...newState.errors, + ...action.value, + }, + }) + case RESET_CUSTOM_GAS_STATE: + return extend({}, initState) + default: + return newState + } +} + +// Action Creators +export function setCustomGasPrice (newPrice) { + return { + type: SET_CUSTOM_GAS_PRICE, + value: newPrice, + } +} + +export function setCustomGasLimit (newLimit) { + return { + type: SET_CUSTOM_GAS_LIMIT, + value: newLimit, + } +} + +export function setCustomGasErrors (newErrors) { + return { + type: SET_CUSTOM_GAS_ERRORS, + value: newErrors, + } +} + +export function resetCustomGasState () { + return { type: RESET_CUSTOM_GAS_STATE } +} diff --git a/ui/app/reducers.js b/ui/app/reducers.js index e1a982f93..7234c3c02 100644 --- a/ui/app/reducers.js +++ b/ui/app/reducers.js @@ -10,6 +10,7 @@ const reduceApp = require('./reducers/app') const reduceLocale = require('./reducers/locale') const reduceSend = require('./ducks/send.duck').default import reduceConfirmTransaction from './ducks/confirm-transaction.duck' +import reduceCustomGas from './ducks/custom-gas' window.METAMASK_CACHED_LOG_STATE = null @@ -49,6 +50,8 @@ function rootReducer (state, action) { state.confirmTransaction = reduceConfirmTransaction(state, action) + state.customGas = reduceCustomGas(state, action) + window.METAMASK_CACHED_LOG_STATE = state return state } diff --git a/ui/app/selectors/custom-gas.js b/ui/app/selectors/custom-gas.js new file mode 100644 index 000000000..97280190f --- /dev/null +++ b/ui/app/selectors/custom-gas.js @@ -0,0 +1,19 @@ +const selectors = { + getCustomGasPrice, + getCustomGasLimit, + getCustomGasErrors, +} + +module.exports = selectors + +function getCustomGasPrice (state) { + return state.customGas.price +} + +function getCustomGasLimit (state) { + return state.customGas.limit +} + +function getCustomGasErrors (state) { + return state.customGas.errors +} -- cgit