Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add togglable advanced gas controls on send and confirm screens #6112

Merged
merged 9 commits into from
Feb 6, 2019
12 changes: 12 additions & 0 deletions app/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,9 @@
"gasLimitCalculation": {
"message": "We calculate the suggested gas limit based on network success rates."
},
"gasLimitInfoModalContent": {
"message": "Gas limit is the maximum amount of units of gas you are willing to spend."
},
"gasLimitRequired": {
"message": "Gas Limit Required"
},
Expand All @@ -547,6 +550,9 @@
"gasPriceExtremelyLow": {
"message": "Gas Price Extremely Low"
},
"gasPriceInfoModalContent": {
"message": "Gas price specifies the amount of Ether you are willing to pay for each unit of gas."
},
"gasPriceNoDenom": {
"message": "Gas Price"
},
Expand Down Expand Up @@ -1210,6 +1216,12 @@
"shapeshiftBuy": {
"message": "Buy with Shapeshift"
},
"showAdvancedGasInline": {
"message": "Advanced gas controls"
},
"showAdvancedGasInlineDescription": {
"message": "Select this to show gas price and limit controls directly on the send and confirm screens."
},
"showPrivateKeys": {
"message": "Show Private Keys"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,8 @@
font-size: .625rem;
}
}

.advanced-gas-inputs__gas-edit-rows {
margin-bottom: 16px;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@

&__gas-fee {
border-bottom: 1px solid $geyser;

.advanced-gas-inputs__gas-edit-rows {
margin-bottom: 16px;
}
}

&__function-type {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import React, { Component } from 'react'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this code is somewhat of a subset of code already in metamask-extension/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js

I will probably remove corresponding code from that component in a future task

import PropTypes from 'prop-types'
import classnames from 'classnames'
import debounce from 'lodash.debounce'

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,
insufficientBalance: PropTypes.bool,
customPriceIsSafe: PropTypes.bool,
isSpeedUp: PropTypes.bool,
showGasPriceInfoModal: PropTypes.func,
showGasLimitInfoModal: PropTypes.func,
}

debouncedGasLimitReset = debounce((dVal) => {
if (dVal < 21000) {
this.props.updateCustomGasLimit(21000)
}
}, 1000, { trailing: true })

onChangeGasLimit = (val) => {
this.props.updateCustomGasLimit(val)
this.debouncedGasLimitReset(val)
}

gasInputError ({ labelKey, insufficientBalance, customPriceIsSafe, isSpeedUp, value }) {
const { t } = this.context
let errorText
let errorType
let isInError = true


if (insufficientBalance) {
errorText = t('insufficientBalance')
errorType = 'error'
} else if (labelKey === 'gasPrice' && isSpeedUp && value === 0) {
errorText = t('zeroGasPriceOnSpeedUpError')
errorType = 'error'
} else if (labelKey === 'gasPrice' && !customPriceIsSafe) {
errorText = t('gasPriceExtremelyLow')
errorType = 'warning'
} else {
isInError = false
}

return {
isInError,
errorText,
errorType,
}
}

gasInput ({ labelKey, value, onChange, insufficientBalance, showGWEI, customPriceIsSafe, isSpeedUp }) {
const {
isInError,
errorText,
errorType,
} = this.gasInputError({ labelKey, insufficientBalance, customPriceIsSafe, isSpeedUp, value })

return (
<div className="advanced-gas-inputs__gas-edit-row__input-wrapper">
<input
className={classnames('advanced-gas-inputs__gas-edit-row__input', {
'advanced-gas-inputs__gas-edit-row__input--error': isInError && errorType === 'error',
'advanced-gas-inputs__gas-edit-row__input--warning': isInError && errorType === 'warning',
})}
type="number"
value={value}
onChange={event => onChange(Number(event.target.value))}
/>
<div className={classnames('advanced-gas-inputs__gas-edit-row__input-arrows', {
'advanced-gas-inputs__gas-edit-row__input--error': isInError && errorType === 'error',
'advanced-gas-inputs__gas-edit-row__input--warning': isInError && errorType === 'warning',
})}>
<div className="advanced-gas-inputs__gas-edit-row__input-arrows__i-wrap" onClick={() => onChange(value + 1)}><i className="fa fa-sm fa-angle-up" /></div>
<div className="advanced-gas-inputs__gas-edit-row__input-arrows__i-wrap" onClick={() => onChange(value - 1)}><i className="fa fa-sm fa-angle-down" /></div>
</div>
{ isInError
? <div className={`advanced-gas-inputs__gas-edit-row__${errorType}-text`}>
{ errorText }
</div>
: null }
</div>
)
}

infoButton (onClick) {
return <i className="fa fa-info-circle" onClick={onClick} />
}

renderGasEditRow (gasInputArgs) {
return (
<div className="advanced-gas-inputs__gas-edit-row">
<div className="advanced-gas-inputs__gas-edit-row__label">
{ this.context.t(gasInputArgs.labelKey) }
{ this.infoButton(() => gasInputArgs.infoOnClick()) }
</div>
{ this.gasInput(gasInputArgs) }
</div>
)
}

render () {
const {
customGasPrice,
updateCustomGasPrice,
customGasLimit,
insufficientBalance,
customPriceIsSafe,
isSpeedUp,
showGasPriceInfoModal,
showGasLimitInfoModal,
} = this.props

return (
<div className="advanced-gas-inputs__gas-edit-rows">
{ this.renderGasEditRow({
labelKey: 'gasPrice',
value: customGasPrice,
onChange: updateCustomGasPrice,
insufficientBalance,
customPriceIsSafe,
showGWEI: true,
isSpeedUp,
infoOnClick: showGasPriceInfoModal,
}) }
{ this.renderGasEditRow({
labelKey: 'gasLimit',
value: customGasLimit,
onChange: this.onChangeGasLimit,
insufficientBalance,
customPriceIsSafe,
infoOnClick: showGasLimitInfoModal,
}) }
</div>
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { connect } from 'react-redux'
import { showModal } from '../../../actions'
import AdvancedGasInputs from './advanced-gas-inputs.component'

const mapDispatchToProps = dispatch => {
return {
showGasPriceInfoModal: modalName => dispatch(showModal({ name: 'GAS_PRICE_INFO_MODAL' })),
showGasLimitInfoModal: modalName => dispatch(showModal({ name: 'GAS_LIMIT_INFO_MODAL' })),
}
}

export default connect(null, mapDispatchToProps)(AdvancedGasInputs)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './advanced-gas-inputs.container'
133 changes: 133 additions & 0 deletions ui/app/components/gas-customization/advanced-gas-inputs/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
.advanced-gas-inputs {
&__gas-edit-rows {
display: flex;
flex-flow: row;
justify-content: space-between;
}

&__gas-edit-row {
display: flex;
flex-flow: column;
width: 47.5%;

&__label {
color: #313B5E;
font-size: 12px;
display: flex;
justify-content: space-between;
align-items: center;

@media screen and (max-width: 576px) {
font-size: 10px;
}

.fa-info-circle {
color: $silver;
margin-left: 10px;
cursor: pointer;
}

.fa-info-circle:hover {
color: $mid-gray;
}
}

&__error-text {
font-size: 12px;
color: red;
}

&__warning-text {
font-size: 12px;
color: orange;
}

&__input-wrapper {
position: relative;
}

&__input {
border: 1px solid $dusty-gray;
border-radius: 4px;
color: $mid-gray;
font-size: 16px;
height: 24px;
width: 100%;
padding-left: 8px;
padding-top: 2px;
margin-top: 7px;
}

&__input--error {
border: 1px solid $red;
}

&__input--warning {
border: 1px solid $orange;
}

&__input-arrows {
position: absolute;
top: 7px;
right: 0px;
width: 17px;
height: 24px;
border: 1px solid #dadada;
border-top-right-radius: 4px;
display: flex;
flex-direction: column;
color: #9b9b9b;
font-size: .8em;
border-bottom-right-radius: 4px;
cursor: pointer;

&__i-wrap {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
cursor: pointer;
}

&__i-wrap:hover {
background: #4EADE7;
color: $white;
}

i:hover {
background: #4EADE7;
}

i {
font-size: 10px;
}
}

&__input-arrows--error {
border: 1px solid $red;
}

&__input-arrows--warning {
border: 1px solid $orange;
}

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;
}
}
}
2 changes: 2 additions & 0 deletions ui/app/components/gas-customization/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
@import './gas-modal-page-container/index';

@import './gas-price-chart/index';

@import './advanced-gas-inputs/index';
34 changes: 34 additions & 0 deletions ui/app/components/modals/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,40 @@ const MODALS = {
},
},

GAS_PRICE_INFO_MODAL: {
contents: [
h(NotifcationModal, {
header: 'gasPriceNoDenom',
message: 'gasPriceInfoModalContent',
}),
],
mobileModalStyle: {
width: '95%',
top: getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP ? '52vh' : '36.5vh',
},
laptopModalStyle: {
width: '449px',
top: 'calc(33% + 45px)',
},
},

GAS_LIMIT_INFO_MODAL: {
contents: [
h(NotifcationModal, {
header: 'gasLimit',
message: 'gasLimitInfoModalContent',
}),
],
mobileModalStyle: {
width: '95%',
top: getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP ? '52vh' : '36.5vh',
},
laptopModalStyle: {
width: '449px',
top: 'calc(33% + 45px)',
},
},

CONFIRM_RESET_ACCOUNT: {
contents: h(ConfirmResetAccount),
mobileModalStyle: {
Expand Down
Loading