TXMetaDataPanel.tsx
1 import React from 'react'; 2 import { connect } from 'react-redux'; 3 import BN from 'bn.js'; 4 5 import { translateRaw } from 'translations'; 6 import { NetworkConfig } from 'types/network'; 7 import { Units } from 'libs/units'; 8 import { AppState } from 'features/reducers'; 9 import { getOffline, getNetworkConfig } from 'features/config'; 10 import { 11 transactionFieldsActions, 12 transactionFieldsSelectors, 13 transactionNetworkActions 14 } from 'features/transaction'; 15 import { ratesActions } from 'features/rates'; 16 import AdvancedGas, { AdvancedOptions } from './components/AdvancedGas'; 17 import SimpleGas from './components/SimpleGas'; 18 import './TXMetaDataPanel.scss'; 19 20 type SliderStates = 'simple' | 'advanced'; 21 22 interface StateProps { 23 gasPrice: AppState['transaction']['fields']['gasPrice']; 24 offline: AppState['config']['meta']['offline']; 25 network: NetworkConfig; 26 } 27 28 interface DispatchProps { 29 inputGasPrice: transactionFieldsActions.TInputGasPrice; 30 inputGasPriceIntent: transactionFieldsActions.TInputGasPriceIntent; 31 fetchCCRates: ratesActions.TFetchCCRatesRequested; 32 getNonceRequested: transactionNetworkActions.TGetNonceRequested; 33 resetTransactionRequested: transactionFieldsActions.TResetTransactionRequested; 34 } 35 36 // Set default props for props that can't be truthy or falsy 37 interface DefaultProps { 38 initialState: SliderStates; 39 } 40 41 interface OwnProps { 42 initialState?: SliderStates; 43 disableToggle?: boolean; 44 advancedGasOptions?: AdvancedOptions; 45 className?: string; 46 scheduling?: boolean; 47 } 48 49 type Props = DispatchProps & OwnProps & StateProps; 50 51 interface State { 52 gasPrice: AppState['transaction']['fields']['gasPrice']; 53 sliderState: SliderStates; 54 } 55 56 class TXMetaDataPanel extends React.Component<Props, State> { 57 public static defaultProps: DefaultProps = { 58 initialState: 'simple' 59 }; 60 61 public state: State = { 62 gasPrice: this.props.gasPrice, 63 sliderState: (this.props as DefaultProps).initialState 64 }; 65 66 public componentWillMount() { 67 if (!this.props.offline) { 68 this.props.resetTransactionRequested(); 69 } 70 } 71 72 public componentDidMount() { 73 if (!this.props.offline) { 74 this.props.fetchCCRates([this.props.network.unit]); 75 this.props.getNonceRequested(); 76 } 77 } 78 79 public UNSAFE_componentWillReceiveProps(nextProps: Props) { 80 if ( 81 (this.props.offline && !nextProps.offline) || 82 this.props.network.unit !== nextProps.network.unit 83 ) { 84 this.props.fetchCCRates([this.props.network.unit]); 85 } 86 if (this.props.gasPrice !== nextProps.gasPrice) { 87 this.setState({ gasPrice: nextProps.gasPrice }); 88 } 89 } 90 91 public render() { 92 const { offline, disableToggle, advancedGasOptions, className = '', scheduling } = this.props; 93 const { gasPrice } = this.state; 94 const showAdvanced = this.state.sliderState === 'advanced' || offline; 95 96 return ( 97 <div className={`Gas col-md-12 ${className}`}> 98 <br /> 99 {showAdvanced ? ( 100 <AdvancedGas 101 gasPrice={gasPrice} 102 inputGasPrice={this.props.inputGasPrice} 103 options={advancedGasOptions} 104 scheduling={scheduling} 105 /> 106 ) : ( 107 <SimpleGas 108 gasPrice={gasPrice} 109 inputGasPrice={this.handleGasPriceInput} 110 setGasPrice={this.props.inputGasPrice} 111 /> 112 )} 113 114 {!offline && 115 !disableToggle && ( 116 <div className="help-block"> 117 <a className="Gas-toggle" onClick={this.toggleAdvanced}> 118 {showAdvanced 119 ? `- ${translateRaw('TRANS_SIMPLE')}` 120 : `+ ${translateRaw('TRANS_ADVANCED')}`} 121 </a> 122 </div> 123 )} 124 </div> 125 ); 126 } 127 128 private toggleAdvanced = () => { 129 this.setState({ sliderState: this.state.sliderState === 'advanced' ? 'simple' : 'advanced' }); 130 }; 131 132 private handleGasPriceInput = (raw: string) => { 133 // Realistically, we're not going to end up with a > 32 bit int, so it's 134 // safe to cast to float, multiply by gwei units, then big number, since 135 // some of the inputs may be sub-one float values. 136 const value = new BN(parseFloat(raw) * parseFloat(Units.gwei)); 137 this.setState({ 138 gasPrice: { raw, value } 139 }); 140 this.props.inputGasPriceIntent(raw); 141 }; 142 } 143 144 function mapStateToProps(state: AppState): StateProps { 145 return { 146 gasPrice: transactionFieldsSelectors.getGasPrice(state), 147 offline: getOffline(state), 148 network: getNetworkConfig(state) 149 }; 150 } 151 152 export default connect(mapStateToProps, { 153 inputGasPrice: transactionFieldsActions.inputGasPrice, 154 inputGasPriceIntent: transactionFieldsActions.inputGasPriceIntent, 155 fetchCCRates: ratesActions.fetchCCRatesRequested, 156 getNonceRequested: transactionNetworkActions.getNonceRequested, 157 resetTransactionRequested: transactionFieldsActions.resetTransactionRequested 158 })(TXMetaDataPanel);