2019-01-07 10:43:51 -08:00
|
|
|
import React, { Component } from 'react'
|
2019-01-17 07:35:48 -08:00
|
|
|
import ReactDOM from 'react-dom'
|
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-15 10:56:10 -08:00
|
|
|
import { ButtonConfirm } from './components/ButtonConfirm'
|
|
|
|
import { CreateKeysAddressNote } from './components/CreateKeysAddressNote'
|
|
|
|
import { FormAutocomplete } from './components/FormAutocomplete'
|
|
|
|
import { FormInput } from './components/FormInput'
|
|
|
|
import { FormRadioButton } from './components/FormRadioButton'
|
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'
|
2019-01-15 10:56:10 -08:00
|
|
|
import { geocodeByAddress } from 'react-places-autocomplete'
|
2019-01-07 10:43:51 -08:00
|
|
|
import { messages } from './utils/messages'
|
2019-01-17 05:41:04 -08:00
|
|
|
|
2019-01-07 10:43:51 -08:00
|
|
|
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: '',
|
2019-01-17 05:41:04 -08:00
|
|
|
isCompany: Number(this.props.web3Config.netId) === helpers.netIdByName(constants.branches.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-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() {
|
2019-01-16 12:34:52 -08:00
|
|
|
this.isValidVotingKey = await this.getKeysManager().isVotingActive(this.getVotingKey())
|
|
|
|
if (!this.isValidVotingKey) {
|
2019-01-17 07:35:48 -08:00
|
|
|
this.setState({ loading: false })
|
2019-01-16 12:34:52 -08: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() {
|
2019-01-16 12:34:52 -08:00
|
|
|
this.setState({ loading: true })
|
|
|
|
const isFormValid = this.checkValidation()
|
2018-07-11 08:50:14 -07:00
|
|
|
if (isFormValid) {
|
2019-01-16 12:34:52 -08:00
|
|
|
const votingKey = this.getVotingKey()
|
|
|
|
const isValid = await this.getKeysManager().isVotingActive(votingKey)
|
|
|
|
|
|
|
|
if (isValid) {
|
|
|
|
await this.sendTxToContract()
|
|
|
|
} else {
|
|
|
|
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
|
2019-01-17 07:35:48 -08:00
|
|
|
|
2018-07-11 08:50:14 -07:00
|
|
|
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 })
|
2019-01-17 07:35:48 -08:00
|
|
|
|
|
|
|
let 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() {
|
2019-01-15 10:56:10 -08:00
|
|
|
const netId = Number(this.props.web3Config.netId)
|
|
|
|
const { isCompany } = this.state.form
|
|
|
|
const { networkBranch } = this.props
|
2019-01-17 05:41:04 -08:00
|
|
|
const hideNote = netId !== helpers.netIdByName(constants.branches.CORE)
|
|
|
|
const isDaiNetwork = netId === helpers.netIdByName(constants.branches.DAI)
|
2019-01-17 07:35:48 -08:00
|
|
|
const inputProps = {
|
|
|
|
id: 'address',
|
|
|
|
onChange: this.onChangeAutoComplete,
|
|
|
|
value: this.state.form.fullAddress
|
|
|
|
}
|
2017-12-11 17:35:57 -08:00
|
|
|
const AutocompleteItem = ({ formattedSuggestion }) => (
|
2019-01-15 10:56:10 -08:00
|
|
|
<div className="vld-App_FormAutocompleteItem">
|
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
|
|
|
|
2019-01-17 07:35:48 -08:00
|
|
|
if (this.state.loading) {
|
|
|
|
return ReactDOM.createPortal(
|
|
|
|
<Loading networkBranch={networkBranch} />,
|
|
|
|
document.getElementById('loadingContainer')
|
|
|
|
)
|
2018-01-31 13:24:52 -08:00
|
|
|
}
|
2018-12-11 03:25:28 -08:00
|
|
|
|
2019-01-17 07:35:48 -08:00
|
|
|
return this.isValidVotingKey ? (
|
2019-01-15 10:56:10 -08:00
|
|
|
<div className="vld-App">
|
|
|
|
<MainTitle text={constants.navigationData[1].title} />
|
2019-01-29 06:23:41 -08:00
|
|
|
{isDaiNetwork ? (
|
|
|
|
<div className="vld-App_RadioButtons">
|
|
|
|
<FormRadioButton
|
|
|
|
checked={isCompany}
|
|
|
|
id="isCompany"
|
|
|
|
name="isCompanyRadio"
|
|
|
|
networkBranch={networkBranch}
|
|
|
|
onChange={this.onChangeFormField}
|
|
|
|
text="I'm a company"
|
|
|
|
/>
|
|
|
|
<FormRadioButton
|
|
|
|
checked={!isCompany}
|
|
|
|
id="isNotary"
|
|
|
|
name="isCompanyRadio"
|
|
|
|
networkBranch={networkBranch}
|
|
|
|
onChange={this.onChangeFormField}
|
|
|
|
text="I'm a notary"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
) : null}
|
2019-01-15 10:56:10 -08:00
|
|
|
<form className="vld-App_Form">
|
|
|
|
<FormInput
|
|
|
|
id="firstName"
|
|
|
|
onChange={this.onChangeFormField}
|
|
|
|
title={isCompany ? 'Full name' : 'First name'}
|
|
|
|
value={this.state.form.firstName}
|
|
|
|
/>
|
2019-01-29 06:23:41 -08:00
|
|
|
{isCompany ? (
|
|
|
|
<FormInput
|
|
|
|
id="contactEmail"
|
|
|
|
onChange={this.onChangeFormField}
|
|
|
|
title="Contact E-mail"
|
|
|
|
type="email"
|
|
|
|
value={this.state.form.contactEmail}
|
|
|
|
/>
|
|
|
|
) : null}
|
|
|
|
{isCompany ? null : (
|
|
|
|
<FormInput
|
|
|
|
id="lastName"
|
|
|
|
onChange={this.onChangeFormField}
|
|
|
|
title="Last name"
|
|
|
|
value={this.state.form.lastName}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
{isCompany ? null : (
|
|
|
|
<FormInput
|
|
|
|
id="licenseId"
|
|
|
|
onChange={this.onChangeFormField}
|
|
|
|
title="License id"
|
|
|
|
value={this.state.form.licenseId}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
{isCompany ? null : (
|
|
|
|
<FormInput
|
|
|
|
id="expirationDate"
|
|
|
|
onChange={this.onChangeFormField}
|
|
|
|
title="License expiration"
|
|
|
|
type="date"
|
|
|
|
value={this.state.form.expirationDate}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
{isCompany ? null : (
|
|
|
|
<FormAutocomplete
|
|
|
|
autocompleteItem={AutocompleteItem}
|
|
|
|
id="address"
|
|
|
|
inputProps={inputProps}
|
|
|
|
onSelect={this.onSelect}
|
|
|
|
title="Address"
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
{isCompany ? null : (
|
|
|
|
<FormInput id="us_state" onChange={this.onChangeFormField} title="State" value={this.state.form.us_state} />
|
|
|
|
)}
|
|
|
|
{isCompany ? null : (
|
|
|
|
<FormInput
|
|
|
|
id="postal_code"
|
|
|
|
onChange={this.onChangeFormField}
|
|
|
|
title="Zip code"
|
|
|
|
value={this.state.form.postal_code}
|
|
|
|
/>
|
|
|
|
)}
|
2018-01-31 13:24:52 -08:00
|
|
|
</form>
|
2019-01-15 10:56:10 -08:00
|
|
|
<ButtonConfirm
|
|
|
|
networkBranch={networkBranch}
|
|
|
|
text={` ${this.state.hasData ? 'Update' : 'Set'} Metadata`}
|
|
|
|
onClick={this.onClick}
|
|
|
|
/>
|
|
|
|
{hideNote ? null : <CreateKeysAddressNote networkBranch={networkBranch} />}
|
2017-12-11 17:35:57 -08:00
|
|
|
</div>
|
2019-01-17 07:35:48 -08:00
|
|
|
) : (
|
|
|
|
<div className="vld-App">
|
|
|
|
<MainTitle text={constants.navigationData[1].title} />
|
|
|
|
<p>Invalid voting key</p>
|
|
|
|
</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
|