aboutsummaryrefslogblamecommitdiffstats
path: root/old-ui/app/components/ens-input.js
blob: 9c46f77d78f1f065bcdd557c15377a9b21959bc1 (plain) (tree)
1
2
3
4
5
6
7
8
9


                                            





                                                                 
                               










                                         
 
                             


                                                              
 





                                                                           
        









































                                                         



































































































                                                                                                
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const debounce = require('debounce')
const copyToClipboard = require('copy-to-clipboard')
const ENS = require('ethjs-ens')
const networkMap = require('ethjs-ens/lib/network-map.json')
const ensRE = /.+\..+$/
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
const log = require('loglevel')


module.exports = EnsInput

inherits(EnsInput, Component)
function EnsInput () {
  Component.call(this)
}

EnsInput.prototype.render = function () {
  const props = this.props

  function onInputChange () {
    const network = this.props.network
    const networkHasEnsSupport = getNetworkEnsSupport(network)
    if (!networkHasEnsSupport) return

    const recipient = document.querySelector('input[name="address"]').value
    if (recipient.match(ensRE) === null) {
      return this.setState({
        loadingEns: false,
        ensResolution: null,
        ensFailure: null,
      })
    }

    this.setState({
      loadingEns: true,
    })
    this.checkName()
  }

  return (
    h('div', {
      style: { width: '100%' },
    }, [
      h('input.large-input', {
        name: props.name,
        placeholder: props.placeholder,
        list: 'addresses',
        onChange: onInputChange.bind(this),
      }),
      // The address book functionality.
      h('datalist#addresses',
        [
          // Corresponds to the addresses owned.
          Object.keys(props.identities).map((key) => {
            const identity = props.identities[key]
            return h('option', {
              value: identity.address,
              label: identity.name,
              key: identity.address,
            })
          }),
          // Corresponds to previously sent-to addresses.
          props.addressBook.map((identity) => {
            return h('option', {
              value: identity.address,
              label: identity.name,
              key: identity.address,
            })
          }),
        ]),
      this.ensIcon(),
    ])
  )
}

EnsInput.prototype.componentDidMount = function () {
  const network = this.props.network
  const networkHasEnsSupport = getNetworkEnsSupport(network)
  this.setState({ ensResolution: ZERO_ADDRESS })

  if (networkHasEnsSupport) {
    const provider = global.ethereumProvider
    this.ens = new ENS({ provider, network })
    this.checkName = debounce(this.lookupEnsName.bind(this), 200)
  }
}

EnsInput.prototype.lookupEnsName = function () {
  const recipient = document.querySelector('input[name="address"]').value
  const { ensResolution } = this.state

  log.info(`ENS attempting to resolve name: ${recipient}`)
  this.ens.lookup(recipient.trim())
  .then((address) => {
    if (address === ZERO_ADDRESS) throw new Error('No address has been set for this name.')
    if (address !== ensResolution) {
      this.setState({
        loadingEns: false,
        ensResolution: address,
        nickname: recipient.trim(),
        hoverText: address + '\nClick to Copy',
        ensFailure: false,
      })
    }
  })
  .catch((reason) => {
    log.error(reason)
    return this.setState({
      loadingEns: false,
      ensResolution: ZERO_ADDRESS,
      ensFailure: true,
      hoverText: reason.message,
    })
  })
}

EnsInput.prototype.componentDidUpdate = function (prevProps, prevState) {
  const state = this.state || {}
  const ensResolution = state.ensResolution
  // If an address is sent without a nickname, meaning not from ENS or from
  // the user's own accounts, a default of a one-space string is used.
  const nickname = state.nickname || ' '
  if (prevState && ensResolution && this.props.onChange &&
      ensResolution !== prevState.ensResolution) {
    this.props.onChange(ensResolution, nickname)
  }
}

EnsInput.prototype.ensIcon = function (recipient) {
  const { hoverText } = this.state || {}
  return h('span', {
    title: hoverText,
    style: {
      position: 'absolute',
      padding: '9px',
      transform: 'translatex(-40px)',
    },
  }, this.ensIconContents(recipient))
}

EnsInput.prototype.ensIconContents = function (recipient) {
  const { loadingEns, ensFailure, ensResolution } = this.state || { ensResolution: ZERO_ADDRESS}

  if (loadingEns) {
    return h('img', {
      src: 'images/loading.svg',
      style: {
        width: '30px',
        height: '30px',
        transform: 'translateY(-6px)',
      },
    })
  }

  if (ensFailure) {
    return h('i.fa.fa-warning.fa-lg.warning')
  }

  if (ensResolution && (ensResolution !== ZERO_ADDRESS)) {
    return h('i.fa.fa-check-circle.fa-lg.cursor-pointer', {
      style: { color: 'green' },
      onClick: (event) => {
        event.preventDefault()
        event.stopPropagation()
        copyToClipboard(ensResolution)
      },
    })
  }
}

function getNetworkEnsSupport (network) {
  return Boolean(networkMap[network])
}