OasisDEX/oasis-react

View on GitHub
src/containers/OasisTokenUnwrapForm.jsx

Summary

Maintainability
C
1 day
Test Coverage
F
56%
import React, { PureComponent } from "react";
import { PropTypes } from "prop-types";

import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import { Field, reduxForm } from "redux-form/immutable";
import wrapUnwrap from "../store/selectors/wrapUnwrap";
import web3 from "../bootstrap/web3";
import wrapUnwrapReducer from "../store/reducers/wrapUnwrap";
import OasisButton from "../components/OasisButton";
import tableStyles from "../styles/modules/_table.scss";
import styles from "./OasisTokenUnwrapForm.scss";
import widgetStyles from "./OasisWidgetFrame.scss";
import CSSModules from "react-css-modules";
import OasisTransactionStatusWrapperInfoBox from "./OasisTransactionStatusInfoBox";
import { AMOUNT_DECIMALS, formatAmount } from "../utils/tokens/pair";
import MaskedTokenAmountInput from "../components/MaskedTokenAmountInput";
import platform from "../store/selectors/platform";
import { SETMAXBTN_HIDE_DELAY_MS, TOKEN_WRAPPED_ETH, TOKEN_WRAPPED_GNT } from '../constants';
import isNumericAndGreaterThanZero from "../utils/numbers/isNumericAndGreaterThanZero";
import OasisInsufficientAmountOfToken from "../components/OasisInsufficientAmountOfToken";

const propTypes = PropTypes && {
  actions: PropTypes.object.isRequired,
  activeUnwrappedTokenBalance: PropTypes.string,
  onFormChange: PropTypes.func,
  wrappedToken: PropTypes.oneOf([
    TOKEN_WRAPPED_ETH,
    TOKEN_WRAPPED_GNT
  ])
};

const inputStyle = { textAlign: "right", width: "100%" };

export class OasisTokenUnwrapFormWrapper extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      showMaxButton: false,
      txStatus: undefined,
      txStartTimestamp: undefined
    };

    this.componentIsUnmounted = false;
    this.currentSetMaxTimeout = null;

    this.validate = this.validate.bind(this);
    this.setUnwrapMax = this.setUnwrapMax.bind(this);
    this.onSetMaxFocus = this.onSetMaxFocus.bind(this);
    this.onSetMaxBlur = this.onSetMaxBlur.bind(this);
    this.onTotalFieldSectionFocus = this.onTotalFieldSectionFocus.bind(this);
    this.onTotalFieldSectionBlur = this.onTotalFieldSectionBlur.bind(this);
    this.onFormChange = this.onFormChange.bind(this);
    this.transactionInfoBlock = this.transactionInfoBlock.bind(this);
  }

  validate(value) {
    const { activeWrappedTokenBalance } = this.props;
    if (!value || value == 0) {
      return "VALIDATE_ERROR/VALUE_IS_REQUIRED";
    } else if (web3.fromWei(activeWrappedTokenBalance).lt(value)) {
      return "VALIDATE_ERROR/WRAP_AMOUNT_GREATER_THAN_TOKEN_BALANCE";
    }
  }

  setUnwrapMax() {
    this.props.actions.setUnwrapMax();
    this.onFormChange();
  }

  transactionInfoBlock() {
    const { unwrapTokenAmount, wrappedToken } = this.props;
    return (
      <div>
        Unwrap{" "}
        <b>
          {formatAmount(unwrapTokenAmount, false, null, AMOUNT_DECIMALS)}{" "}
          {wrappedToken}
        </b>
      </div>
    );
  }

  renderTransactionStatus() {
    const {
      txType,
      transactionState: { txStatus, txStartTimestamp }
    } = this.props;
    return (
      <OasisTransactionStatusWrapperInfoBox
        txStatus={txStatus}
        infoText={this.transactionInfoBlock}
        localStatus={txStatus}
        txTimestamp={txStartTimestamp}
        txType={txType}
      />
    );
  }

  renderInsufficientBalanceWarning() {
    const {
      activeWrappedTokenBalance,
      unwrapTokenAmount,
      wrappedToken,
      transactionState: { txStatus }
    } = this.props;
    return !txStatus ? (
      <div>
        {isNumericAndGreaterThanZero(unwrapTokenAmount) &&
          web3.fromWei(activeWrappedTokenBalance).lt(unwrapTokenAmount) && (
            <OasisInsufficientAmountOfToken tokenName={wrappedToken} noBorder />
          )}
      </div>
    ) : null;
  }


  onFormChange() {
    const { onFormChange } = this.props;
    onFormChange && onFormChange();
  }
  render() {
    const {
      valid,
      handleSubmit,
      initialized,
      wrappedToken,
      disabled,
      globalFormLock,
      unwrapTokenAmount,
      activeWrappedTokenBalance
    } = this.props;

    return (
      <form onChange={this.onFormChange} onSubmit={handleSubmit}>
        <table className={`${tableStyles.table} ${styles.form}`}>
          <tbody>
            <tr>
              <th>Amount</th>
              <td className={tableStyles.withInput}>
                <div className={tableStyles.inputGroup}>
                  {this.state.showMaxButton && (
                    <OasisButton
                      type="button"
                      size="xs"
                      className={tableStyles.inputBtn}
                      onClick={this.setUnwrapMax}
                      onFocus={this.onSetMaxFocus}
                      onBlur={this.onSetMaxBlur}
                      disabled={
                        disabled ||
                        globalFormLock ||
                        !isNumericAndGreaterThanZero(activeWrappedTokenBalance)
                      }
                    >
                      <span style={{ fontSize: "10px" }}>unwrap max</span>
                    </OasisButton>
                  )}
                  <div
                    className={tableStyles.inputGroupEventHandlerChild}
                    onFocus={this.onTotalFieldSectionFocus}
                    onBlur={this.onTotalFieldSectionBlur}
                  >
                    <Field
                      style={inputStyle}
                      required
                      validate={this.validate}
                      autoComplete="off"
                      name="amount"
                      component={MaskedTokenAmountInput}
                      placeholder={0}
                      type="text"
                      disabled={disabled || globalFormLock}
                    />
                  </div>
                </div>
              </td>
              <td className={tableStyles.currency}>{wrappedToken}</td>
            </tr>
          </tbody>
        </table>
        <div>{this.renderTransactionStatus()}</div>
        <div className={styles.footer}>
          <div>
            {this.renderInsufficientBalanceWarning()}
          </div>
          <OasisButton
            type="submit"
            disabled={
              !valid ||
              disabled ||
              globalFormLock ||
              initialized ||
              !isNumericAndGreaterThanZero(unwrapTokenAmount)
            }
            className={styles.footerBtn}
          >
            Unwrap
          </OasisButton>
        </div>
      </form>
    );
  }

  onSetMaxFocus() {
    clearTimeout(this.currentSetMaxTimeout);
  }

  onSetMaxBlur() {
    this.setState({ showMaxButton: false });
  }

  onTotalFieldSectionFocus() {
    if (this.componentIsUnmounted === false) {
      this.setState({ showMaxButton: true });
    }
  }

  onTotalFieldSectionBlur() {
    if (this.componentIsUnmounted === false) {
      this.currentSetMaxTimeout = setTimeout(
        () => this.setState({ showMaxButton: false }),
        SETMAXBTN_HIDE_DELAY_MS
      );
    }
  }

  componentWillUnmount() {
    this.componentIsUnmounted = true;
  }
}

export function mapStateToProps(state, { form }) {
  return {
    activeWrappedTokenBalance: wrapUnwrap.activeWrappedTokenBalance(
      state,
      true
    ),
    unwrapTokenAmount: wrapUnwrap.unwrapTokenAmount(state, form),
    globalFormLock: platform.globalFormLock(state)
  };
}
export function mapDispatchToProps(dispatch) {
  const actions = {
    setUnwrapMax: wrapUnwrapReducer.actions.setUnwrapMax
  };
  return { actions: bindActionCreators(actions, dispatch) };
}

OasisTokenUnwrapFormWrapper.propTypes = propTypes;
OasisTokenUnwrapFormWrapper.displayName = "OasisTokenUnwrapForm";
export default connect(mapStateToProps, mapDispatchToProps)(
  reduxForm({})(
    CSSModules(
      OasisTokenUnwrapFormWrapper,
      { tableStyles, styles, widgetStyles },
      { allowMultiple: true }
    )
  )
);