1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-27 04:46:10 +01:00
metamask-extension/ui/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js
Dan J Miller 09512c7148
Improvements for multi-layer fee UX (#13547)
* Show fiat on confirm screen on multilayer-fee network

* Disable gas editing on optimism

* Fix send max mode on optimism

* Represent layer 2 gas fee as a single value

* Hide gas fee edit UI on optimism

* Improvement multilayer-fee-message styling

* Lint fix

* Fix locales

* Remove unnecessary code change

Co-authored-by: David Walsh <davidwalsh83@gmail.com>
2022-03-29 16:51:45 -02:30

276 lines
7.9 KiB
JavaScript

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { debounce } from 'lodash';
import Tooltip from '../../../ui/tooltip';
export default class AdvancedGasInputs extends Component {
static contextTypes = {
t: PropTypes.func,
};
static propTypes = {
updateCustomGasPrice: PropTypes.func,
updateCustomGasLimit: PropTypes.func,
customGasPrice: PropTypes.number.isRequired,
customGasLimit: PropTypes.number.isRequired,
insufficientBalance: PropTypes.bool,
customPriceIsSafe: PropTypes.bool,
isSpeedUp: PropTypes.bool,
customGasLimitMessage: PropTypes.string,
minimumGasLimit: PropTypes.number,
customPriceIsExcessive: PropTypes.bool,
networkSupportsSettingGasFees: PropTypes.bool,
};
static defaultProps = {
customPriceIsExcessive: false,
networkSupportsSettingGasFees: true,
};
constructor(props) {
super(props);
this.state = {
gasPrice: this.props.customGasPrice,
gasLimit: this.props.customGasLimit,
};
this.changeGasPrice = debounce(this.changeGasPrice, 500);
this.changeGasLimit = debounce(this.changeGasLimit, 500);
}
componentDidUpdate(prevProps) {
const {
customGasPrice: prevCustomGasPrice,
customGasLimit: prevCustomGasLimit,
} = prevProps;
const { customGasPrice, customGasLimit } = this.props;
const { gasPrice, gasLimit } = this.state;
if (customGasPrice !== prevCustomGasPrice && customGasPrice !== gasPrice) {
this.setState({ gasPrice: customGasPrice });
}
if (customGasLimit !== prevCustomGasLimit && customGasLimit !== gasLimit) {
this.setState({ gasLimit: customGasLimit });
}
}
onChangeGasLimit = (e) => {
this.setState({ gasLimit: e.target.value });
this.changeGasLimit({ target: { value: e.target.value } });
};
changeGasLimit = (e) => {
this.props.updateCustomGasLimit(Number(e.target.value));
};
onChangeGasPrice = (e) => {
this.setState({ gasPrice: e.target.value });
this.changeGasPrice({ target: { value: e.target.value } });
};
changeGasPrice = (e) => {
this.props.updateCustomGasPrice(Number(e.target.value));
};
gasPriceError({
insufficientBalance,
customPriceIsSafe,
isSpeedUp,
gasPrice,
customPriceIsExcessive,
}) {
const { t } = this.context;
if (insufficientBalance) {
return {
errorText: t('insufficientBalance'),
errorType: 'error',
};
} else if (isSpeedUp && gasPrice === 0) {
return {
errorText: t('zeroGasPriceOnSpeedUpError'),
errorType: 'error',
};
} else if (!customPriceIsSafe) {
return {
errorText: t('gasPriceExtremelyLow'),
errorType: 'warning',
};
} else if (customPriceIsExcessive) {
return {
errorText: t('gasPriceExcessiveInput'),
errorType: 'error',
};
}
return {};
}
gasLimitError({ insufficientBalance, gasLimit, minimumGasLimit }) {
const { t } = this.context;
if (insufficientBalance) {
return {
errorText: t('insufficientBalance'),
errorType: 'error',
};
} else if (gasLimit < minimumGasLimit) {
return {
errorText: t('gasLimitTooLowWithDynamicFee', [minimumGasLimit]),
errorType: 'error',
};
}
return {};
}
renderGasInput({
value,
onChange,
errorComponent,
errorType,
label,
testId,
customMessageComponent,
tooltipTitle,
disabled,
}) {
return (
<div className="advanced-gas-inputs__gas-edit-row">
<div className="advanced-gas-inputs__gas-edit-row__label">
{label}
<Tooltip title={tooltipTitle} position="top" arrow>
<i className="fa fa-info-circle" />
</Tooltip>
</div>
<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':
errorType === 'error',
'advanced-gas-inputs__gas-edit-row__input--warning':
errorType === 'warning',
})}
type="number"
min="0"
value={value}
onChange={onChange}
disabled={disabled}
data-testid={testId}
/>
<div
className={classnames(
'advanced-gas-inputs__gas-edit-row__input-arrows',
{
'advanced-gas-inputs__gas-edit-row__input--error':
errorType === 'error',
'advanced-gas-inputs__gas-edit-row__input--warning':
errorType === 'warning',
'advanced-gas-inputs__gas-edit-row__input-arrows--hidden': disabled,
},
)}
>
<div
className="advanced-gas-inputs__gas-edit-row__input-arrows__i-wrap"
onClick={() =>
!disabled && onChange({ target: { value: value + 1 } })
}
>
<i className="fa fa-sm fa-angle-up" />
</div>
<div
className="advanced-gas-inputs__gas-edit-row__input-arrows__i-wrap"
onClick={() =>
!disabled &&
onChange({ target: { value: Math.max(value - 1, 0) } })
}
>
<i className="fa fa-sm fa-angle-down" />
</div>
</div>
{errorComponent || customMessageComponent}
</div>
</div>
);
}
render() {
const {
insufficientBalance,
customPriceIsSafe,
isSpeedUp,
customGasLimitMessage,
minimumGasLimit,
customPriceIsExcessive,
networkSupportsSettingGasFees,
} = this.props;
const { gasPrice, gasLimit } = this.state;
if (!networkSupportsSettingGasFees) {
return null;
}
const {
errorText: gasPriceErrorText,
errorType: gasPriceErrorType,
} = this.gasPriceError({
insufficientBalance,
customPriceIsSafe,
isSpeedUp,
gasPrice,
customPriceIsExcessive,
});
const gasPriceErrorComponent = gasPriceErrorType ? (
<div
className={`advanced-gas-inputs__gas-edit-row__${gasPriceErrorType}-text`}
>
{gasPriceErrorText}
</div>
) : null;
const {
errorText: gasLimitErrorText,
errorType: gasLimitErrorType,
} = this.gasLimitError({ insufficientBalance, gasLimit, minimumGasLimit });
const gasLimitErrorComponent = gasLimitErrorType ? (
<div
className={`advanced-gas-inputs__gas-edit-row__${gasLimitErrorType}-text`}
>
{gasLimitErrorText}
</div>
) : null;
const gasLimitCustomMessageComponent = customGasLimitMessage ? (
<div className="advanced-gas-inputs__gas-edit-row__custom-text">
{customGasLimitMessage}
</div>
) : null;
return (
<div className="advanced-gas-inputs__gas-edit-rows">
{this.renderGasInput({
label: this.context.t('gasPrice'),
testId: 'gas-price',
tooltipTitle: this.context.t('gasPriceInfoTooltipContent'),
value: this.state.gasPrice,
onChange: this.onChangeGasPrice,
errorComponent: gasPriceErrorComponent,
errorType: gasPriceErrorType,
disabled: !networkSupportsSettingGasFees,
})}
{this.renderGasInput({
label: this.context.t('gasLimit'),
testId: 'gas-limit',
tooltipTitle: this.context.t('gasLimitInfoTooltipContent'),
value: this.state.gasLimit,
onChange: this.onChangeGasLimit,
errorComponent: gasLimitErrorComponent,
customMessageComponent: gasLimitCustomMessageComponent,
errorType: gasLimitErrorType,
disabled: !networkSupportsSettingGasFees,
})}
</div>
);
}
}