2018-07-11 08:50:14 -07:00
|
|
|
import PlacesAutocomplete, { geocodeByAddress } from 'react-places-autocomplete'
|
2019-01-07 10:43:51 -08:00
|
|
|
import React, { Component } from 'react'
|
2018-12-17 04:38:33 -08:00
|
|
|
import emailValidator from 'email-validator'
|
2019-01-07 10:43:51 -08:00
|
|
|
import helpers from './utils/helpers'
|
|
|
|
import moment from 'moment'
|
2019-01-07 12:45:51 -08:00
|
|
|
import { Loading } from './components/Loading'
|
|
|
|
import { MainTitle } from './components/MainTitle'
|
2019-01-07 10:43:51 -08:00
|
|
|
import { constants } from './utils/constants'
|
|
|
|
import { messages } from './utils/messages'
|
|
|
|
|
|
|
|
import './assets/stylesheets/index.css'
|
2017-12-11 17:35:57 -08:00
|
|
|
|
|
|
|
class App extends Component {
|
2018-07-11 08:50:14 -07:00
|
|
|
constructor(props) {
|
|
|
|
super(props)
|
2019-01-07 10:43:51 -08:00
|
|
|
|
2017-12-11 17:35:57 -08:00
|
|
|
this.checkValidation = this.checkValidation.bind(this)
|
2018-07-11 08:50:14 -07:00
|
|
|
this.onClick = this.onClick.bind(this)
|
|
|
|
this.onChangeFormField = this.onChangeFormField.bind(this)
|
|
|
|
this.getKeysManager = this.getKeysManager.bind(this)
|
|
|
|
this.getMetadataContract = this.getMetadataContract.bind(this)
|
|
|
|
this.getVotingKey = this.getVotingKey.bind(this)
|
|
|
|
this.onChangeAutoComplete = address => {
|
|
|
|
const form = this.state.form
|
|
|
|
form.fullAddress = address
|
|
|
|
this.setState({ form })
|
|
|
|
}
|
2017-12-11 17:35:57 -08:00
|
|
|
this.onSelect = this.onSelectAutocomplete.bind(this)
|
|
|
|
this.state = {
|
|
|
|
web3Config: {},
|
|
|
|
form: {
|
|
|
|
fullAddress: '',
|
|
|
|
expirationDate: '',
|
|
|
|
postal_code: '',
|
|
|
|
us_state: '',
|
|
|
|
firstName: '',
|
|
|
|
lastName: '',
|
2018-12-11 03:25:28 -08:00
|
|
|
licenseId: '',
|
|
|
|
contactEmail: '',
|
2018-12-20 08:51:51 -08:00
|
|
|
isCompany: Number(this.props.web3Config.netId) === helpers.netIdByName('dai')
|
2017-12-11 17:35:57 -08:00
|
|
|
},
|
|
|
|
hasData: false
|
|
|
|
}
|
|
|
|
|
2018-07-11 08:50:14 -07:00
|
|
|
this.defaultValues = null
|
|
|
|
this.setMetadata.call(this)
|
2018-01-31 13:24:52 -08:00
|
|
|
|
2018-07-11 08:56:38 -07:00
|
|
|
this.isValidVotingKey = false
|
|
|
|
this.setIsValidVotingKey.call(this)
|
2017-12-11 17:35:57 -08:00
|
|
|
}
|
2018-07-11 08:50:14 -07:00
|
|
|
async setMetadata() {
|
2018-08-07 01:53:06 -07:00
|
|
|
const currentData = await this.getMetadataContract().getValidatorData(this.getMiningKey())
|
2018-12-11 03:25:28 -08:00
|
|
|
const hasData = currentData.createdDate ? true : false
|
2018-07-11 08:50:14 -07:00
|
|
|
this.defaultValues = currentData
|
2018-08-07 01:53:06 -07:00
|
|
|
const pendingChange = await this.getMetadataContract().getPendingChange(this.getMiningKey())
|
2018-07-11 08:50:14 -07:00
|
|
|
if (Number(pendingChange.minThreshold) > 0) {
|
2018-12-11 03:25:28 -08:00
|
|
|
let msg
|
|
|
|
if (pendingChange.isCompany) {
|
|
|
|
msg = `
|
|
|
|
Full name: <b>${pendingChange.firstName}</b> <br/>
|
|
|
|
Contact E-mail: <b>${pendingChange.contactEmail}</b> <br/>
|
|
|
|
`
|
|
|
|
} else {
|
|
|
|
msg = `
|
|
|
|
First Name: <b>${pendingChange.firstName}</b> <br/>
|
|
|
|
Last Name: <b>${pendingChange.lastName}</b> <br/>
|
|
|
|
Full Address: <b>${pendingChange.fullAddress}</b> <br/>
|
|
|
|
Expiration Date: <b>${pendingChange.expirationDate}</b> <br />
|
|
|
|
License ID: <b>${pendingChange.licenseId}</b> <br/>
|
|
|
|
US state: <b>${pendingChange.us_state}</b> <br/>
|
|
|
|
Zip Code: <b>${pendingChange.postal_code}</b> <br/>
|
|
|
|
`
|
|
|
|
}
|
2018-07-11 08:50:14 -07:00
|
|
|
helpers.generateAlert('warning', 'You have pending changes!', msg)
|
2017-12-12 23:27:31 -08:00
|
|
|
}
|
2017-12-11 23:01:59 -08:00
|
|
|
this.setState({
|
|
|
|
form: {
|
2017-12-12 01:25:19 -08:00
|
|
|
fullAddress: currentData.fullAddress,
|
|
|
|
expirationDate: currentData.expirationDate,
|
|
|
|
postal_code: currentData.postal_code,
|
|
|
|
us_state: currentData.us_state,
|
|
|
|
firstName: currentData.firstName,
|
|
|
|
lastName: currentData.lastName,
|
2018-12-11 03:25:28 -08:00
|
|
|
licenseId: currentData.licenseId,
|
|
|
|
contactEmail: currentData.contactEmail,
|
2018-12-20 08:51:51 -08:00
|
|
|
isCompany: hasData ? currentData.isCompany : this.state.form.isCompany
|
2017-12-11 23:01:59 -08:00
|
|
|
},
|
|
|
|
hasData
|
2018-07-11 08:50:14 -07:00
|
|
|
})
|
2017-12-11 23:01:59 -08:00
|
|
|
}
|
2018-07-06 00:05:26 -07:00
|
|
|
async setIsValidVotingKey() {
|
2018-07-11 08:56:38 -07:00
|
|
|
this.isValidVotingKey = await this.getKeysManager().isVotingActive(this.getVotingKey())
|
2018-07-06 00:05:26 -07:00
|
|
|
if (!this.isValidVotingKey) {
|
2018-07-11 08:56:38 -07:00
|
|
|
helpers.generateAlert('warning', 'Warning!', messages.invalidaVotingKey)
|
2018-07-06 00:05:26 -07:00
|
|
|
}
|
|
|
|
}
|
2018-07-11 08:50:14 -07:00
|
|
|
getKeysManager() {
|
|
|
|
return this.props.web3Config.keysManager
|
2017-12-11 23:01:59 -08:00
|
|
|
}
|
2018-07-11 08:50:14 -07:00
|
|
|
getMetadataContract() {
|
|
|
|
return this.props.web3Config.metadataContract
|
2017-12-11 23:01:59 -08:00
|
|
|
}
|
2018-07-11 08:50:14 -07:00
|
|
|
getVotingKey() {
|
|
|
|
return this.props.web3Config.votingKey
|
2017-12-11 23:01:59 -08:00
|
|
|
}
|
2018-08-07 01:53:06 -07:00
|
|
|
getMiningKey() {
|
|
|
|
return this.props.web3Config.miningKey
|
|
|
|
}
|
2017-12-11 17:35:57 -08:00
|
|
|
checkValidation() {
|
2018-12-11 03:25:28 -08:00
|
|
|
if (this.state.form.isCompany) {
|
|
|
|
if (!this.state.form.firstName) {
|
2018-07-11 08:50:14 -07:00
|
|
|
this.setState({ loading: false })
|
2018-12-11 03:25:28 -08:00
|
|
|
helpers.generateAlert('warning', 'Warning!', `Full name cannot be empty`)
|
|
|
|
return false
|
|
|
|
}
|
2018-12-17 04:38:33 -08:00
|
|
|
if (!emailValidator.validate(this.state.form.contactEmail)) {
|
2018-12-11 03:25:28 -08:00
|
|
|
this.setState({ loading: false })
|
2018-12-17 04:38:33 -08:00
|
|
|
helpers.generateAlert('warning', 'Warning!', `Contact E-mail is invalid`)
|
2018-07-11 08:50:14 -07:00
|
|
|
return false
|
2017-12-11 17:35:57 -08:00
|
|
|
}
|
|
|
|
} else {
|
2018-12-11 03:25:28 -08:00
|
|
|
const keys = Object.keys(this.state.form)
|
|
|
|
keys.forEach(key => {
|
|
|
|
if (!this.state.form[key]) {
|
|
|
|
if (key !== 'contactEmail' && key !== 'isCompany') {
|
|
|
|
this.setState({ loading: false })
|
|
|
|
helpers.generateAlert('warning', 'Warning!', `${key} cannot be empty`)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2018-12-17 04:38:33 -08:00
|
|
|
const isAfter = moment(this.state.form.expirationDate).isAfter(moment())
|
|
|
|
if (!isAfter) {
|
|
|
|
this.setState({ loading: false })
|
|
|
|
helpers.generateAlert('warning', 'Warning!', 'Expiration date should be valid')
|
|
|
|
return false
|
|
|
|
}
|
2017-12-11 17:35:57 -08:00
|
|
|
}
|
2018-07-11 08:50:14 -07:00
|
|
|
return true
|
2017-12-11 17:35:57 -08:00
|
|
|
}
|
|
|
|
async onSelectAutocomplete(data) {
|
|
|
|
let place = await geocodeByAddress(data)
|
2018-07-11 08:50:14 -07:00
|
|
|
let address_components = {}
|
2017-12-11 17:35:57 -08:00
|
|
|
for (var i = 0; i < place[0].address_components.length; i++) {
|
2018-07-11 08:50:14 -07:00
|
|
|
var addressType = place[0].address_components[i].types[0]
|
|
|
|
switch (addressType) {
|
|
|
|
case 'postal_code':
|
|
|
|
address_components.postal_code = place[0].address_components[i].short_name
|
|
|
|
break
|
|
|
|
case 'street_number':
|
|
|
|
address_components.street_number = place[0].address_components[i].short_name
|
|
|
|
break
|
|
|
|
case 'route':
|
|
|
|
address_components.route = place[0].address_components[i].short_name
|
|
|
|
break
|
|
|
|
case 'locality':
|
|
|
|
address_components.locality = place[0].address_components[i].short_name
|
|
|
|
break
|
|
|
|
case 'administrative_area_level_1':
|
|
|
|
address_components.administrative_area_level_1 = place[0].address_components[i].short_name
|
|
|
|
break
|
2018-02-26 06:35:10 -08:00
|
|
|
default:
|
2018-07-11 08:50:14 -07:00
|
|
|
break
|
2017-12-11 17:35:57 -08:00
|
|
|
}
|
2018-07-11 08:50:14 -07:00
|
|
|
let form = this.state.form
|
|
|
|
form.fullAddress = `${address_components.street_number} ${address_components.route} ${
|
|
|
|
address_components.locality
|
|
|
|
}`
|
|
|
|
form.us_state = address_components.administrative_area_level_1
|
|
|
|
form.postal_code = address_components.postal_code
|
2017-12-11 17:35:57 -08:00
|
|
|
this.setState({
|
|
|
|
form
|
2018-07-11 08:50:14 -07:00
|
|
|
})
|
2017-12-11 17:35:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
async onClick() {
|
2018-07-11 08:50:14 -07:00
|
|
|
this.setState({ loading: true })
|
|
|
|
const isFormValid = this.checkValidation()
|
|
|
|
if (isFormValid) {
|
|
|
|
const votingKey = this.getVotingKey()
|
|
|
|
const isValid = await this.getKeysManager().isVotingActive(votingKey)
|
|
|
|
if (isValid) {
|
2017-12-12 01:25:19 -08:00
|
|
|
await this.sendTxToContract()
|
|
|
|
} else {
|
2018-07-11 08:50:14 -07:00
|
|
|
this.setState({ loading: false })
|
|
|
|
helpers.generateAlert('warning', 'Warning!', messages.invalidaVotingKey)
|
|
|
|
return
|
2017-12-11 17:35:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-11 08:50:14 -07:00
|
|
|
async sendTxToContract() {
|
|
|
|
this.getMetadataContract()
|
|
|
|
.createMetadata({
|
|
|
|
firstName: this.state.form.firstName,
|
|
|
|
lastName: this.state.form.lastName,
|
|
|
|
licenseId: this.state.form.licenseId,
|
|
|
|
fullAddress: this.state.form.fullAddress,
|
|
|
|
state: this.state.form.us_state,
|
|
|
|
zipcode: this.state.form.postal_code,
|
|
|
|
expirationDate: moment(this.state.form.expirationDate).unix(),
|
2018-12-11 03:25:28 -08:00
|
|
|
contactEmail: this.state.form.contactEmail,
|
|
|
|
isCompany: this.state.form.isCompany,
|
2018-07-11 08:50:14 -07:00
|
|
|
votingKey: this.getVotingKey(),
|
|
|
|
hasData: this.state.hasData
|
|
|
|
})
|
|
|
|
.then(receipt => {
|
|
|
|
this.setState({ loading: false })
|
|
|
|
helpers.generateAlert('success', 'Congratulations!', 'Your metadata was sent!')
|
|
|
|
})
|
|
|
|
.catch(error => {
|
|
|
|
let errDescription
|
|
|
|
if (error.message.includes(constants.userDeniedTransactionPattern))
|
2018-10-15 11:36:13 -07:00
|
|
|
errDescription = `Error: ${constants.userDeniedTransactionPattern}`
|
2018-07-11 08:50:14 -07:00
|
|
|
else errDescription = error.message
|
|
|
|
this.setState({ loading: false })
|
|
|
|
var msg = `
|
2018-12-11 03:25:28 -08:00
|
|
|
Something went wrong!<br/><br/>
|
|
|
|
${errDescription}
|
|
|
|
`
|
2018-07-11 08:50:14 -07:00
|
|
|
helpers.generateAlert('error', 'Error!', msg)
|
|
|
|
})
|
2017-12-11 17:35:57 -08:00
|
|
|
}
|
|
|
|
onChangeFormField(event) {
|
2018-07-11 08:50:14 -07:00
|
|
|
const field = event.target.id
|
|
|
|
let form = this.state.form
|
2018-12-11 03:25:28 -08:00
|
|
|
if (field === 'isNotary') {
|
|
|
|
form.isCompany = false
|
|
|
|
} else if (field === 'isCompany') {
|
|
|
|
form.isCompany = true
|
|
|
|
} else {
|
|
|
|
form[field] = event.target.value
|
|
|
|
}
|
2018-07-11 08:50:14 -07:00
|
|
|
this.setState({ form })
|
2017-12-11 17:35:57 -08:00
|
|
|
}
|
2018-12-11 03:25:28 -08:00
|
|
|
|
2017-12-11 17:35:57 -08:00
|
|
|
render() {
|
2018-12-11 03:25:28 -08:00
|
|
|
const netId = Number(this.props.web3Config.netId)
|
|
|
|
const { isCompany } = this.state.form
|
2018-10-10 08:55:10 -07:00
|
|
|
const classNameHiddenIfNotCoreNetwork = netId !== helpers.netIdByName('core') ? 'display-none' : ''
|
2018-12-11 03:25:28 -08:00
|
|
|
const classNameHiddenIfCompany = isCompany ? 'display-none' : ''
|
|
|
|
const classNameHiddenIfNotary = !isCompany ? 'display-none' : ''
|
2018-09-13 08:39:56 -07:00
|
|
|
|
2018-07-06 00:05:26 -07:00
|
|
|
if (!this.isValidVotingKey) {
|
2018-12-11 05:19:29 -08:00
|
|
|
return null
|
2018-07-06 00:05:26 -07:00
|
|
|
}
|
2018-12-11 03:25:28 -08:00
|
|
|
|
2018-07-11 08:50:14 -07:00
|
|
|
const BtnAction = this.state.hasData ? 'Update' : 'Set'
|
2017-12-11 17:35:57 -08:00
|
|
|
const AutocompleteItem = ({ formattedSuggestion }) => (
|
|
|
|
<div className="custom-container">
|
2018-07-11 08:50:14 -07:00
|
|
|
<strong>{formattedSuggestion.mainText}</strong> <small>{formattedSuggestion.secondaryText}</small>
|
2017-12-11 17:35:57 -08:00
|
|
|
</div>
|
|
|
|
)
|
2018-01-31 13:24:52 -08:00
|
|
|
|
2017-12-11 17:35:57 -08:00
|
|
|
const inputProps = {
|
|
|
|
value: this.state.form.fullAddress,
|
|
|
|
onChange: this.onChangeAutoComplete,
|
|
|
|
id: 'address'
|
2018-01-31 13:24:52 -08:00
|
|
|
}
|
2018-07-11 08:50:14 -07:00
|
|
|
let loader = this.state.loading ? <Loading /> : ''
|
2018-12-11 03:25:28 -08:00
|
|
|
|
|
|
|
const isDaiNetwork = netId === helpers.netIdByName('dai')
|
|
|
|
|
2018-01-31 13:24:52 -08:00
|
|
|
let createKeyBtn = (
|
|
|
|
<div className="create-keys">
|
|
|
|
<form className="create-keys-form">
|
2018-12-11 03:25:28 -08:00
|
|
|
<div className={`create-keys-form-is-company ${!isDaiNetwork ? 'display-none' : ''}`}>
|
|
|
|
<input
|
|
|
|
type="radio"
|
|
|
|
name="isCompanyRadio"
|
|
|
|
id="isNotary"
|
|
|
|
checked={!isCompany}
|
|
|
|
onChange={this.onChangeFormField}
|
|
|
|
/>
|
|
|
|
<label htmlFor="isNotary">I'm a notary</label>
|
|
|
|
<input
|
|
|
|
type="radio"
|
|
|
|
name="isCompanyRadio"
|
|
|
|
id="isCompany"
|
|
|
|
checked={isCompany}
|
|
|
|
onChange={this.onChangeFormField}
|
|
|
|
/>
|
|
|
|
<label htmlFor="isCompany">I'm a company</label>
|
|
|
|
</div>
|
|
|
|
|
2018-01-31 13:24:52 -08:00
|
|
|
<div className="create-keys-form-i">
|
2018-12-11 03:25:28 -08:00
|
|
|
<label htmlFor="firstName">{isCompany ? 'Full name' : 'First name'}</label>
|
2018-07-11 08:50:14 -07:00
|
|
|
<input type="text" id="firstName" value={this.state.form.firstName} onChange={this.onChangeFormField} />
|
2018-09-13 12:11:44 -07:00
|
|
|
</div>
|
2018-12-11 03:25:28 -08:00
|
|
|
<div className={`create-keys-form-i ${classNameHiddenIfNotary}`}>
|
|
|
|
<label htmlFor="contactEmail">Contact E-mail</label>
|
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
id="contactEmail"
|
|
|
|
value={this.state.form.contactEmail}
|
|
|
|
onChange={this.onChangeFormField}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div className={`create-keys-form-i ${classNameHiddenIfCompany}`}>
|
|
|
|
<label htmlFor="lastName">Last name</label>
|
2018-09-13 12:11:44 -07:00
|
|
|
<input type="text" id="lastName" value={this.state.form.lastName} onChange={this.onChangeFormField} />
|
|
|
|
</div>
|
2018-12-11 03:25:28 -08:00
|
|
|
<div className={`create-keys-form-i ${classNameHiddenIfCompany}`}>
|
2018-09-13 12:11:44 -07:00
|
|
|
<label htmlFor="licenseId">License id</label>
|
|
|
|
<input type="text" id="licenseId" value={this.state.form.licenseId} onChange={this.onChangeFormField} />
|
|
|
|
</div>
|
2018-12-11 03:25:28 -08:00
|
|
|
<div className={`create-keys-form-i ${classNameHiddenIfCompany}`}>
|
2018-01-31 13:24:52 -08:00
|
|
|
<label htmlFor="expirationDate">License expiration</label>
|
2018-07-11 08:50:14 -07:00
|
|
|
<input
|
|
|
|
type="date"
|
|
|
|
id="expirationDate"
|
|
|
|
value={this.state.form.expirationDate}
|
|
|
|
onChange={this.onChangeFormField}
|
|
|
|
/>
|
2018-01-31 13:24:52 -08:00
|
|
|
</div>
|
2018-12-11 03:25:28 -08:00
|
|
|
<div className={`create-keys-form-i ${classNameHiddenIfCompany}`}>
|
2018-09-13 12:11:44 -07:00
|
|
|
<label htmlFor="address">Address</label>
|
|
|
|
<PlacesAutocomplete onSelect={this.onSelect} inputProps={inputProps} autocompleteItem={AutocompleteItem} />
|
|
|
|
</div>
|
2018-12-11 03:25:28 -08:00
|
|
|
<div className={`create-keys-form-i ${classNameHiddenIfCompany}`}>
|
2018-07-18 11:17:09 -07:00
|
|
|
<label htmlFor="state">State</label>
|
|
|
|
<input type="text" id="us_state" value={this.state.form.us_state} onChange={this.onChangeFormField} />
|
2018-09-13 12:11:44 -07:00
|
|
|
</div>
|
2018-12-11 03:25:28 -08:00
|
|
|
<div className={`create-keys-form-i ${classNameHiddenIfCompany}`}>
|
2018-09-13 12:11:44 -07:00
|
|
|
<label htmlFor="zip">Zip code</label>
|
|
|
|
<input type="text" id="postal_code" value={this.state.form.postal_code} onChange={this.onChangeFormField} />
|
2018-07-18 11:17:09 -07:00
|
|
|
</div>
|
2018-01-31 13:24:52 -08:00
|
|
|
</form>
|
2018-07-11 08:50:14 -07:00
|
|
|
<button onClick={this.onClick} className="create-keys-button">
|
|
|
|
{BtnAction} Metadata
|
|
|
|
</button>
|
2018-09-13 08:39:56 -07:00
|
|
|
<p className={`create-keys-address-note ${classNameHiddenIfNotCoreNetwork}`}>
|
|
|
|
<i className="create-keys-address-note__icon-info" />
|
|
|
|
The entered address will be displayed as Unconfirmed and will be used if you don't have Registered Address(es)
|
2018-09-14 05:55:37 -07:00
|
|
|
in{' '}
|
2018-09-21 09:33:49 -07:00
|
|
|
<a href="https://popa.poa.network/" target="_blank" rel="noopener noreferrer">
|
2018-09-14 05:55:37 -07:00
|
|
|
PoPA DApp
|
|
|
|
</a>
|
|
|
|
. You have to use PoPA to register and confirm your address(es).
|
2018-09-13 08:39:56 -07:00
|
|
|
</p>
|
2018-07-11 08:50:14 -07:00
|
|
|
</div>
|
|
|
|
)
|
2018-07-18 11:17:09 -07:00
|
|
|
|
2018-07-11 08:50:14 -07:00
|
|
|
let content = createKeyBtn
|
2018-07-18 11:17:09 -07:00
|
|
|
|
2017-12-11 17:35:57 -08:00
|
|
|
return (
|
2019-01-07 12:45:51 -08:00
|
|
|
<div className="vld-App">
|
2017-12-11 17:35:57 -08:00
|
|
|
{loader}
|
2019-01-15 07:44:13 -08:00
|
|
|
<MainTitle text={constants.navigationData[1].title} />
|
2018-01-31 13:24:52 -08:00
|
|
|
{content}
|
2017-12-11 17:35:57 -08:00
|
|
|
</div>
|
2018-07-11 08:50:14 -07:00
|
|
|
)
|
2017-12-11 17:35:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-11 08:50:14 -07:00
|
|
|
export default App
|