2017-10-16 21:01:28 -07:00
|
|
|
import React, { Component } from 'react';
|
|
|
|
import translate from 'translations';
|
2018-02-06 20:28:28 -08:00
|
|
|
import { NetworkContract, donationAddressMap } from 'config';
|
2017-10-16 21:01:28 -07:00
|
|
|
import { getNetworkContracts } from 'selectors/config';
|
|
|
|
import { connect } from 'react-redux';
|
|
|
|
import { AppState } from 'reducers';
|
|
|
|
import { isValidETHAddress, isValidAbiJson } from 'libs/validators';
|
|
|
|
import classnames from 'classnames';
|
2018-01-23 16:33:11 -08:00
|
|
|
import Select from 'react-select';
|
2017-10-16 21:01:28 -07:00
|
|
|
|
2018-01-23 16:33:11 -08:00
|
|
|
interface ContractOption {
|
|
|
|
name: string;
|
|
|
|
value: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface StateProps {
|
2017-10-16 21:01:28 -07:00
|
|
|
contracts: NetworkContract[];
|
2018-01-23 16:33:11 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
interface OwnProps {
|
|
|
|
accessContract(contractAbi: string, address: string): (ev) => void;
|
2017-10-16 21:01:28 -07:00
|
|
|
resetState(): void;
|
|
|
|
}
|
|
|
|
|
2018-01-23 16:33:11 -08:00
|
|
|
type Props = OwnProps & StateProps;
|
|
|
|
|
2017-10-16 21:01:28 -07:00
|
|
|
interface State {
|
|
|
|
address: string;
|
|
|
|
abiJson: string;
|
2018-01-23 16:33:11 -08:00
|
|
|
contract: ContractOption | null;
|
|
|
|
contractPlaceholder: string;
|
2017-10-16 21:01:28 -07:00
|
|
|
}
|
|
|
|
|
2018-01-23 16:33:11 -08:00
|
|
|
const abiJsonPlaceholder = [
|
|
|
|
{
|
|
|
|
type: 'constructor',
|
|
|
|
inputs: [{ name: 'param1', type: 'uint256', indexed: true }],
|
|
|
|
name: 'Event'
|
|
|
|
},
|
|
|
|
{ type: 'function', inputs: [{ name: 'a', type: 'uint256' }], name: 'foo', outputs: [] }
|
|
|
|
];
|
|
|
|
|
2017-10-16 21:01:28 -07:00
|
|
|
class InteractForm extends Component<Props, State> {
|
2018-01-23 16:33:11 -08:00
|
|
|
private abiJsonPlaceholder = JSON.stringify(abiJsonPlaceholder, null, 0);
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
address: '',
|
|
|
|
abiJson: '',
|
|
|
|
contract: null,
|
|
|
|
contractPlaceholder: this.isContractsValid()
|
|
|
|
? 'Please select a contract...'
|
|
|
|
: 'No contracts available'
|
|
|
|
};
|
|
|
|
}
|
2017-10-16 21:01:28 -07:00
|
|
|
|
2018-01-23 16:33:11 -08:00
|
|
|
public isContractsValid = () => {
|
|
|
|
const { contracts } = this.props;
|
|
|
|
return contracts && contracts.length;
|
|
|
|
};
|
2017-10-16 21:01:28 -07:00
|
|
|
|
|
|
|
public render() {
|
|
|
|
const { contracts, accessContract } = this.props;
|
2018-01-23 16:33:11 -08:00
|
|
|
const { address, abiJson, contract } = this.state;
|
2017-10-16 21:01:28 -07:00
|
|
|
const validEthAddress = isValidETHAddress(address);
|
|
|
|
const validAbiJson = isValidAbiJson(abiJson);
|
|
|
|
const showContractAccessButton = validEthAddress && validAbiJson;
|
2018-01-23 16:33:11 -08:00
|
|
|
let contractOptions: ContractOption[] = [];
|
|
|
|
|
|
|
|
if (this.isContractsValid()) {
|
|
|
|
contractOptions = contracts.map(con => {
|
|
|
|
const addr = con.address ? `(${con.address.substr(0, 10)}...)` : '';
|
|
|
|
return {
|
|
|
|
name: `${con.name} ${addr}`,
|
|
|
|
value: this.makeContractValue(con)
|
|
|
|
};
|
|
|
|
});
|
2017-10-16 21:01:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Use common components for address, abi json
|
|
|
|
return (
|
|
|
|
<div className="InteractForm">
|
2017-12-05 11:51:21 -08:00
|
|
|
<div className="InteractForm-address row">
|
|
|
|
<label className="InteractForm-address-field form-group col-sm-6">
|
2017-10-16 21:01:28 -07:00
|
|
|
<h4>{translate('CONTRACT_Title')}</h4>
|
|
|
|
<input
|
2018-02-06 20:28:28 -08:00
|
|
|
placeholder={`ensdomain.eth or ${donationAddressMap.ETH}`}
|
2017-10-16 21:01:28 -07:00
|
|
|
name="contract_address"
|
|
|
|
autoComplete="off"
|
|
|
|
value={address}
|
2017-12-05 11:51:21 -08:00
|
|
|
className={classnames('InteractForm-address-field-input', 'form-control', {
|
|
|
|
'is-invalid': !validEthAddress
|
|
|
|
})}
|
2017-10-16 21:01:28 -07:00
|
|
|
onChange={this.handleInput('address')}
|
|
|
|
/>
|
|
|
|
</label>
|
|
|
|
|
2017-12-05 11:51:21 -08:00
|
|
|
<label className="InteractForm-address-contract form-group col-sm-6">
|
2017-10-16 21:01:28 -07:00
|
|
|
<h4>{translate('CONTRACT_Title_2')}</h4>
|
2018-01-23 16:33:11 -08:00
|
|
|
<Select
|
|
|
|
name="interactContract"
|
|
|
|
className={`${!contract ? 'is-invalid' : ''}`}
|
|
|
|
value={contract as any}
|
|
|
|
placeholder={this.state.contractPlaceholder}
|
2017-10-16 21:01:28 -07:00
|
|
|
onChange={this.handleSelectContract}
|
2018-01-23 16:33:11 -08:00
|
|
|
options={contractOptions}
|
|
|
|
clearable={false}
|
|
|
|
searchable={false}
|
|
|
|
labelKey="name"
|
|
|
|
/>
|
2017-10-16 21:01:28 -07:00
|
|
|
</label>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className="InteractForm-interface">
|
|
|
|
<label className="InteractForm-interface-field form-group">
|
2017-12-05 11:51:21 -08:00
|
|
|
<h4 className="InteractForm-interface-field-label">{translate('CONTRACT_Json')}</h4>
|
2017-10-16 21:01:28 -07:00
|
|
|
<textarea
|
|
|
|
placeholder={this.abiJsonPlaceholder}
|
|
|
|
name="abiJson"
|
2017-12-05 11:51:21 -08:00
|
|
|
className={classnames('InteractForm-interface-field-input', 'form-control', {
|
|
|
|
'is-invalid': !validAbiJson
|
|
|
|
})}
|
2017-10-16 21:01:28 -07:00
|
|
|
onChange={this.handleInput('abiJson')}
|
|
|
|
value={abiJson}
|
|
|
|
rows={6}
|
|
|
|
/>
|
|
|
|
</label>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<button
|
|
|
|
className="InteractForm-submit btn btn-primary"
|
|
|
|
disabled={!showContractAccessButton}
|
2017-10-23 19:59:18 -07:00
|
|
|
onClick={accessContract(abiJson, address)}
|
2017-10-16 21:01:28 -07:00
|
|
|
>
|
|
|
|
{translate('x_Access')}
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-01-10 22:47:48 -08:00
|
|
|
private handleInput = name => (ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
2017-10-16 21:01:28 -07:00
|
|
|
this.props.resetState();
|
2018-01-10 22:47:48 -08:00
|
|
|
this.setState({ [name]: ev.currentTarget.value });
|
2017-10-16 21:01:28 -07:00
|
|
|
};
|
|
|
|
|
2018-01-23 16:33:11 -08:00
|
|
|
private handleSelectContract = (contract: ContractOption) => {
|
2017-10-16 21:01:28 -07:00
|
|
|
this.props.resetState();
|
2018-01-23 16:33:11 -08:00
|
|
|
const fullContract = this.props.contracts.find(currContract => {
|
|
|
|
return this.makeContractValue(currContract) === contract.value;
|
2017-10-16 21:01:28 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
this.setState({
|
2018-01-23 16:33:11 -08:00
|
|
|
address: fullContract && fullContract.address ? fullContract.address : '',
|
|
|
|
abiJson: fullContract && fullContract.abi ? fullContract.abi : '',
|
|
|
|
contract
|
2017-10-16 21:01:28 -07:00
|
|
|
});
|
|
|
|
};
|
2018-01-10 22:47:48 -08:00
|
|
|
|
|
|
|
private makeContractValue(contract: NetworkContract) {
|
|
|
|
return `${contract.name}:${contract.address}`;
|
|
|
|
}
|
2017-10-16 21:01:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const mapStateToProps = (state: AppState) => ({
|
2018-01-23 16:33:11 -08:00
|
|
|
contracts: getNetworkContracts(state) || []
|
2017-10-16 21:01:28 -07:00
|
|
|
});
|
|
|
|
|
2018-01-23 16:33:11 -08:00
|
|
|
export default connect<StateProps, {}>(mapStateToProps)(InteractForm);
|