/ common / components / TXMetaDataPanel / TXMetaDataPanel.tsx
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);