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}) = {fee} {usd && <span>~= ${usd} 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);