/ common / components / TXMetaDataPanel / components / AdvancedGas.tsx
AdvancedGas.tsx
  1  import React from 'react';
  2  import { connect } from 'react-redux';
  3  
  4  import { EAC_SCHEDULING_CONFIG } from 'libs/scheduling';
  5  import translate, { translateRaw } from 'translations';
  6  import { AppState } from 'features/reducers';
  7  import { TToggleAutoGasLimit, toggleAutoGasLimit, getAutoGasLimitEnabled } from 'features/config';
  8  import { scheduleSelectors } from 'features/schedule';
  9  import { transactionFieldsActions, transactionSelectors } from 'features/transaction';
 10  import { NonceField, GasLimitField, DataField } from 'components';
 11  import { Input } from 'components/ui';
 12  import FeeSummary, { RenderData } from './FeeSummary';
 13  import './AdvancedGas.scss';
 14  
 15  export interface AdvancedOptions {
 16    gasPriceField?: boolean;
 17    gasLimitField?: boolean;
 18    nonceField?: boolean;
 19    dataField?: boolean;
 20    feeSummary?: boolean;
 21  }
 22  
 23  interface OwnProps {
 24    inputGasPrice: transactionFieldsActions.TInputGasPrice;
 25    gasPrice: AppState['transaction']['fields']['gasPrice'];
 26    options?: AdvancedOptions;
 27    scheduling?: boolean;
 28    scheduleGasPrice: AppState['schedule']['scheduleGasPrice'];
 29    timeBounty: AppState['schedule']['timeBounty'];
 30  }
 31  
 32  interface StateProps {
 33    autoGasLimitEnabled: AppState['config']['meta']['autoGasLimit'];
 34    validGasPrice: boolean;
 35  }
 36  
 37  interface DispatchProps {
 38    toggleAutoGasLimit: TToggleAutoGasLimit;
 39  }
 40  
 41  interface State {
 42    options: AdvancedOptions;
 43  }
 44  
 45  type Props = OwnProps & StateProps & DispatchProps;
 46  
 47  class AdvancedGas extends React.Component<Props, State> {
 48    public state = {
 49      options: {
 50        gasPriceField: true,
 51        gasLimitField: true,
 52        nonceField: true,
 53        dataField: true,
 54        feeSummary: true,
 55        ...this.props.options
 56      }
 57    };
 58  
 59    public render() {
 60      const { autoGasLimitEnabled, gasPrice, scheduling, validGasPrice } = this.props;
 61      const { gasPriceField, gasLimitField, nonceField, dataField } = this.state.options;
 62  
 63      return (
 64        <div className="AdvancedGas row form-group">
 65          <div className="AdvancedGas-calculate-limit">
 66            <label className="checkbox">
 67              <input
 68                type="checkbox"
 69                defaultChecked={autoGasLimitEnabled}
 70                onChange={this.handleToggleAutoGasLimit}
 71              />
 72              <span>{translate('TRANS_AUTO_GAS_TOGGLE')}</span>
 73            </label>
 74          </div>
 75  
 76          <div className="AdvancedGas-flex-wrapper flex-wrapper">
 77            {gasPriceField && (
 78              <div className="AdvancedGas-gas-price">
 79                <div className="input-group-wrapper">
 80                  <label className="input-group">
 81                    <div className="input-group-header">
 82                      {translateRaw('OFFLINE_STEP2_LABEL_3')} (gwei)
 83                    </div>
 84                    {/*We leave type as string instead of number, because things such as multiple decimals
 85                    or invalid exponent notation does not fire the onchange handler
 86                    so the component will not display as invalid for such things */}
 87                    <Input
 88                      isValid={validGasPrice}
 89                      placeholder="40"
 90                      value={gasPrice.raw}
 91                      onChange={this.handleGasPriceChange}
 92                    />
 93                  </label>
 94                </div>
 95              </div>
 96            )}
 97  
 98            {gasLimitField && (
 99              <div className="AdvancedGas-gas-limit">
100                <GasLimitField
101                  customLabel={translateRaw('OFFLINE_STEP2_LABEL_4')}
102                  disabled={scheduling}
103                  hideGasCalculationSpinner={scheduling}
104                />
105              </div>
106            )}
107            {nonceField && (
108              <div className="AdvancedGas-nonce">
109                <NonceField alwaysDisplay={true} showInvalidBeforeBlur={true} />
110              </div>
111            )}
112          </div>
113  
114          {!scheduling &&
115            dataField && (
116              <div className="AdvancedGas-data">
117                <DataField />
118              </div>
119            )}
120  
121          {this.renderFee()}
122        </div>
123      );
124    }
125  
126    private renderFee() {
127      const { gasPrice, scheduleGasPrice } = this.props;
128      const { feeSummary } = this.state.options;
129  
130      if (!feeSummary) {
131        return;
132      }
133  
134      return (
135        <div className="AdvancedGas-fee-summary">
136          <FeeSummary
137            gasPrice={gasPrice}
138            scheduleGasPrice={scheduleGasPrice}
139            render={(data: RenderData) => this.printFeeFormula(data)}
140          />
141        </div>
142      );
143    }
144  
145    private printFeeFormula(data: RenderData) {
146      if (this.props.scheduling) {
147        return this.getScheduleFeeFormula(data);
148      }
149  
150      return this.getStandardFeeFormula(data);
151    }
152  
153    private getStandardFeeFormula({ gasPriceWei, gasLimit, fee, usd }: RenderData) {
154      return (
155        <span>
156          {gasPriceWei} * {gasLimit} = {fee} {usd && <span>~= ${usd} USD</span>}
157        </span>
158      );
159    }
160  
161    private getScheduleFeeFormula({ gasPriceWei, scheduleGasLimit, fee, usd }: RenderData) {
162      const { scheduleGasPrice, timeBounty } = this.props;
163  
164      return (
165        <div>
166          {timeBounty && timeBounty.value && timeBounty.value.toString()} + {gasPriceWei} *{' '}
167          {EAC_SCHEDULING_CONFIG.SCHEDULING_GAS_LIMIT.toString()} +{' '}
168          {scheduleGasPrice && scheduleGasPrice.value && scheduleGasPrice.value.toString()} * ({EAC_SCHEDULING_CONFIG.FUTURE_EXECUTION_COST.toString()}{' '}
169          + {scheduleGasLimit}) =&nbsp;{fee}&nbsp;{usd && <span>~=&nbsp;${usd}&nbsp;USD</span>}
170        </div>
171      );
172    }
173  
174    private handleGasPriceChange = (ev: React.FormEvent<HTMLInputElement>) => {
175      const { value } = ev.currentTarget;
176      this.props.inputGasPrice(value);
177    };
178  
179    private handleToggleAutoGasLimit = (_: React.FormEvent<HTMLInputElement>) => {
180      this.props.toggleAutoGasLimit();
181    };
182  }
183  
184  export default connect(
185    (state: AppState) => ({
186      autoGasLimitEnabled: getAutoGasLimitEnabled(state),
187      scheduleGasPrice: scheduleSelectors.getScheduleGasPrice(state),
188      timeBounty: scheduleSelectors.getTimeBounty(state),
189      validGasPrice: transactionSelectors.isValidGasPrice(state)
190    }),
191    { toggleAutoGasLimit }
192  )(AdvancedGas);