aboutsummaryrefslogblamecommitdiffstats
path: root/mascara/src/app/first-time/import-account-screen.js
blob: 555a26386deb3c4f66f7497a419d6cebbce86e02 (plain) (tree)
1
2
3
4
5
6

                                        
                                   
                                   
                                            
                                                                        







                                                                                  
                                                      






                                                                             







                                            










                                                
                                           
                                         







                                                            


                                                         










                                            


                                                         



                                                                    

                                                                                    



                                                              

                                                                                    



                     
                       



                                                                   
                                                                                                                


      


                                             














                                                                            
                                                                   














                                                                                                       
                                                                                




            

                                           









                                        


                                           
 
                               

                                                                    



















                                                          



                                                               














                                                                                                                                                                                       
                                     











                                                                     

                                                                                     

                      
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import classnames from 'classnames'
import LoadingScreen from './loading-screen'
import {importNewAccount, hideWarning} from '../../../../ui/app/actions'

const Input = ({ label, placeholder, onChange, errorMessage, type = 'text' }) => (
  <div className="import-account__input-wrapper">
    <div className="import-account__input-label">{label}</div>
    <input
      type={type}
      placeholder={placeholder}
      className={classnames('first-time-flow__input import-account__input', {
        'first-time-flow__input--error': errorMessage,
      })}
      onChange={onChange}
    />
    <div className="import-account__input-error-message">{errorMessage}</div>
  </div>
)

Input.prototype.propTypes = {
  label: PropTypes.string.isRequired,
  placeholder: PropTypes.string.isRequired,
  type: PropTypes.string.isRequired,
  errorMessage: PropTypes.string.isRequired,
  onChange: PropTypes.func.isRequired,
}

class ImportAccountScreen extends Component {
  static OPTIONS = {
    PRIVATE_KEY: 'private_key',
    JSON_FILE: 'json_file',
  };

  static propTypes = {
    warning: PropTypes.string,
    back: PropTypes.func.isRequired,
    next: PropTypes.func.isRequired,
    importNewAccount: PropTypes.func.isRequired,
    hideWarning: PropTypes.func.isRequired,
    isLoading: PropTypes.bool.isRequired,
  };

  state = {
    selectedOption: ImportAccountScreen.OPTIONS.PRIVATE_KEY,
    privateKey: '',
    jsonFile: {},
  }

  isValid () {
    const { OPTIONS } = ImportAccountScreen
    const { privateKey, jsonFile, password } = this.state

    switch (this.state.selectedOption) {
      case OPTIONS.JSON_FILE:
        return Boolean(jsonFile && password)
      case OPTIONS.PRIVATE_KEY:
      default:
        return Boolean(privateKey)
    }
  }

  onClick = () => {
    const { OPTIONS } = ImportAccountScreen
    const { importNewAccount, next } = this.props
    const { privateKey, jsonFile, password } = this.state

    switch (this.state.selectedOption) {
      case OPTIONS.JSON_FILE:
        return importNewAccount('JSON File', [ jsonFile, password ])
          // JS runtime requires caught rejections but failures are handled by Redux
          .catch()
          .then(next)
      case OPTIONS.PRIVATE_KEY:
      default:
        return importNewAccount('Private Key', [ privateKey ])
          // JS runtime requires caught rejections but failures are handled by Redux
          .catch()
          .then(next)
    }
  }

  renderPrivateKey () {
    return Input({
      label: 'Add Private Key String',
      placeholder: 'Enter private key',
      onChange: e => this.setState({ privateKey: e.target.value }),
      errorMessage: this.props.warning && 'Something went wrong. Please make sure your private key is correct.',
    })
  }

  renderJsonFile () {
    const { jsonFile: { name } } = this.state
    const { warning } = this.props

    return (
      <div className="">
        <div className="import-account__input-wrapper">
          <div className="import-account__input-label">Upload File</div>
          <div className="import-account__file-picker-wrapper">
            <input
              type="file"
              id="file"
              className="import-account__file-input"
              onChange={e => this.setState({ jsonFile: e.target.files[0] })}
            />
            <label
              htmlFor="file"
              className={classnames('import-account__file-input-label', {
                'import-account__file-input-label--error': warning,
              })}
            >
              Choose File
            </label>
            <div className="import-account__file-name">{name}</div>
          </div>
          <div className="import-account__input-error-message">
            {warning && 'Something went wrong. Please make sure your JSON file is properly formatted.'}
          </div>
        </div>
        {Input({
          label: 'Enter Password',
          placeholder: 'Enter Password',
          type: 'password',
          onChange: e => this.setState({ password: e.target.value }),
          errorMessage: warning && 'Please make sure your password is correct.',
        })}
      </div>
    )
  }

  renderContent () {
    const { OPTIONS } = ImportAccountScreen

    switch (this.state.selectedOption) {
      case OPTIONS.JSON_FILE:
        return this.renderJsonFile()
      case OPTIONS.PRIVATE_KEY:
      default:
        return this.renderPrivateKey()
    }
  }

  render () {
    const { OPTIONS } = ImportAccountScreen
    const { selectedOption } = this.state

    return this.props.isLoading
      ? <LoadingScreen loadingMessage="Creating your new account" />
      : (
        <div className="import-account">
          <a
            className="import-account__back-button"
            onClick={e => {
              e.preventDefault()
              this.props.back()
            }}
            href="#"
          >
            {`< Back`}
          </a>
          <div className="import-account__title">
            Import an Account
          </div>
          <div className="import-account__selector-label">
            How would you like to import your account?
          </div>
          <select
            className="import-account__dropdown"
            value={selectedOption}
            onChange={e => {
              this.setState({ selectedOption: e.target.value })
              this.props.hideWarning()
            }}
          >
            <option value={OPTIONS.PRIVATE_KEY}>Private Key</option>
            <option value={OPTIONS.JSON_FILE}>JSON File</option>
          </select>
          {this.renderContent()}
          <button
            className="first-time-flow__button"
            disabled={!this.isValid()}
            onClick={this.onClick}
          >
            Import
          </button>
          <a
            href="https://github.com/MetaMask/faq/blob/master/README.md#q-i-cant-use-the-import-feature-for-uploading-a-json-file-the-window-keeps-closing-when-i-try-to-select-a-file"
            className="first-time-flow__link import-account__faq-link"
            rel="noopener noreferrer"
            target="_blank"
          >
            File import not working?
          </a>
        </div>
      )
  }
}

export default connect(
  ({ appState: { isLoading, warning } }) => ({ isLoading, warning }),
  dispatch => ({
    importNewAccount: (strategy, args) => dispatch(importNewAccount(strategy, args)),
    hideWarning: () => dispatch(hideWarning()),
  })
)(ImportAccountScreen)