add gas station component

This commit is contained in:
Jonathan Rainville 2018-08-28 11:16:24 -04:00 committed by Pascal Precht
parent 7080be9fb1
commit 77258f8636
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
5 changed files with 178 additions and 18 deletions

View File

@ -2,7 +2,6 @@ import axios from "axios";
import constants from '../constants'; import constants from '../constants';
function get(path, params, endpoint) { function get(path, params, endpoint) {
console.log('GET ', (endpoint || constants.httpEndpoint) + path);
return axios.get((endpoint || constants.httpEndpoint) + path, params) return axios.get((endpoint || constants.httpEndpoint) + path, params)
.then((response) => { .then((response) => {
return {response, error: null}; return {response, error: null};

View File

@ -12,11 +12,11 @@ import {
class ContractFunction extends Component { class ContractFunction extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { inputs: {} }; this.state = {inputs: {}};
} }
buttonTitle() { buttonTitle() {
const { method } =this.props; const {method} = this.props;
if (method.name === 'constructor') { if (method.name === 'constructor') {
return 'Deploy'; return 'Deploy';
} }
@ -24,7 +24,7 @@ class ContractFunction extends Component {
return (method.mutability === 'view' || method.mutability === 'pure') ? 'Call' : 'Send'; return (method.mutability === 'view' || method.mutability === 'pure') ? 'Call' : 'Send';
} }
inputsAsArray(){ inputsAsArray() {
return this.props.method.inputs return this.props.method.inputs
.map(input => this.state.inputs[input.name]) .map(input => this.state.inputs[input.name])
.filter(value => value); .filter(value => value);
@ -33,7 +33,7 @@ class ContractFunction extends Component {
handleChange(e, name) { handleChange(e, name) {
let newInputs = this.state.inputs; let newInputs = this.state.inputs;
newInputs[name] = e.target.value; newInputs[name] = e.target.value;
this.setState({ inputs: newInputs}); this.setState({inputs: newInputs});
} }
handleCall(e) { handleCall(e) {
@ -63,7 +63,7 @@ class ContractFunction extends Component {
{this.buttonTitle()} {this.buttonTitle()}
</Button> </Button>
</Card.Body> </Card.Body>
<Card.Footer> {this.props.contractFunctions && this.props.contractFunctions.length > 0 && <Card.Footer>
<List> <List>
{this.props.contractFunctions.map(contractFunction => ( {this.props.contractFunctions.map(contractFunction => (
<List.Item key={contractFunction.result}> <List.Item key={contractFunction.result}>
@ -72,7 +72,7 @@ class ContractFunction extends Component {
</List.Item> </List.Item>
))} ))}
</List> </List>
</Card.Footer> </Card.Footer>}
</Card> </Card>
</Grid.Col> </Grid.Col>
</Grid.Row> </Grid.Row>
@ -106,7 +106,7 @@ const ContractFunctions = (props) => {
method={method} method={method}
contractFunctions={filterContractFunctions(props.contractFunctions, contractProfile.name, method.name)} contractFunctions={filterContractFunctions(props.contractFunctions, contractProfile.name, method.name)}
contractProfile={contractProfile} contractProfile={contractProfile}
postContractFunction={props.postContractFunction} />)} postContractFunction={props.postContractFunction}/>)}
</Page.Content> </Page.Content>
); );
}; };

View File

@ -0,0 +1,142 @@
import PropTypes from "prop-types";
import React, {Component} from 'react';
import {Card, Form, Grid, StampCard} from 'tabler-react';
const test = {
"fast": 50.0,
"speed": 0.998437456605574,
"fastest": 400.0,
"avgWait": 1.9,
"fastWait": 0.7,
"blockNum": 6228803,
"safeLowWait": 1.9,
"block_time": 14.326530612244898,
"fastestWait": 0.5,
"safeLow": 24.0,
"average": 24.0
};
const COLORS = {
good: 'green',
medium: 'yellow',
bad: 'red'
};
class GasStation extends Component {
constructor(props) {
super(props);
if (!props.gasStats) {
return console.error('gasStats is a needed Prop for GasStation');
}
this.state = {gasSliderIndex: 0};
this.formattedGasStats = GasStation.formatGasStats(props.gasStats);
}
static formatGasStats(gasStats) {
const {
fast, speed, fastest, avgWait, fastWait, blockNum, safeLowWait,
block_time, fastestWait, safeLow, average
} = gasStats;
return {
average: {price: average, wait: avgWait},
blockTime: block_time,
blockNum,
speed,
gasSteps: [
{price: safeLow, wait: safeLowWait},
{price: fast, wait: fastWait},
{price: fastest, wait: fastestWait}
]
};
}
gasSliderChange(e) {
this.setState({
gasSliderIndex: e.target.value
});
}
static getColorForWait(wait) {
if (wait <= 1) {
return COLORS.good;
}
if (wait <= 3) {
return COLORS.medium;
}
return COLORS.bad;
}
static getColorForPrice(gasPrice) {
if (gasPrice <= 20) {
return COLORS.good;
}
if (gasPrice <= 40) {
return COLORS.medium;
}
return COLORS.bad;
}
render() {
const currentGasStep = this.formattedGasStats.gasSteps[this.state.gasSliderIndex];
return <Grid.Row>
<Grid.Col>
<Card>
<Card.Header>
<Card.Title>Gas Price Estimator</Card.Title>
</Card.Header>
<Card.Body>
<Grid.Row cards={true}>
<Grid.Col lg={6} md={6} sm={12}>
<StampCard icon="sliders" color={GasStation.getColorForPrice(currentGasStep.price)}>
{currentGasStep.price / 10} GWei
</StampCard>
</Grid.Col>
<Grid.Col lg={6} md={6} sm={12}>
<StampCard icon="clock" color={GasStation.getColorForWait(currentGasStep.wait)}>
{currentGasStep.wait} minutes
</StampCard>
</Grid.Col>
</Grid.Row>
<Form.Group>
<Form.Ratio
defaultValue={0}
max={this.formattedGasStats.gasSteps.length - 1}
min={0}
step={1}
value={this.state.gasSliderIndex}
onChange={(e) => this.gasSliderChange(e)}
/>
</Form.Group>
<Grid.Row cards={true}>
<Grid.Col lg={4} md={6} sm={12}>
<StampCard icon="sliders" color="grey">
Average Price: {this.formattedGasStats.average.price / 10} Gwei
</StampCard>
</Grid.Col>
<Grid.Col lg={4} md={6} sm={12}>
<StampCard icon="clock" color="grey">
Average Wait: {this.formattedGasStats.average.wait} min
</StampCard>
</Grid.Col>
<Grid.Col lg={4} md={6} sm={12}>
<StampCard icon="square" color="grey">
Last Block: {this.formattedGasStats.blockNum}
</StampCard>
</Grid.Col>
</Grid.Row>
</Card.Body>
</Card>
</Grid.Col>
</Grid.Row>;
}
}
GasStation.propTypes = {
gasStats: PropTypes.object.isRequired
};
export default GasStation;

View File

@ -3,10 +3,15 @@ import {connect} from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {withRouter} from 'react-router-dom'; import {withRouter} from 'react-router-dom';
import {contractProfile as contractProfileAction, contractDeploy as contractDeployAction, ethGas as ethGasAction} from '../actions'; import {
contractProfile as contractProfileAction,
contractDeploy as contractDeployAction,
ethGas as ethGasAction
} from '../actions';
import ContractFunctions from '../components/ContractFunctions'; import ContractFunctions from '../components/ContractFunctions';
import DataWrapper from "../components/DataWrapper"; import DataWrapper from "../components/DataWrapper";
import {getContractProfile, getContractDeploys} from "../reducers/selectors"; import GasStation from "../components/GasStation";
import {getContractProfile, getContractDeploys, getGasStats} from "../reducers/selectors";
class ContractDeploymentContainer extends Component { class ContractDeploymentContainer extends Component {
componentDidMount() { componentDidMount() {
@ -16,14 +21,23 @@ class ContractDeploymentContainer extends Component {
render() { render() {
return ( return (
<DataWrapper shouldRender={this.props.contractProfile !== undefined } <React.Fragment>
{...this.props} <DataWrapper shouldRender={this.props.contractProfile !== undefined}
render={({contractProfile, contractDeploys, postContractDeploy}) => ( {...this.props}
<ContractFunctions contractProfile={contractProfile} render={({contractProfile, contractDeploys, postContractDeploy}) => (
contractFunctions={contractDeploys} <ContractFunctions contractProfile={contractProfile}
onlyConstructor contractFunctions={contractDeploys}
postContractFunction={postContractDeploy}/> onlyConstructor
)} /> postContractFunction={postContractDeploy}/>
)}/>
<DataWrapper shouldRender={this.props.gasStats !== undefined}
{...this.props}
render={({gasStats}) => (
<GasStation gasStats={gasStats}/>
)}/>
</React.Fragment>
); );
} }
} }
@ -32,6 +46,7 @@ function mapStateToProps(state, props) {
return { return {
contractProfile: getContractProfile(state, props.match.params.contractName), contractProfile: getContractProfile(state, props.match.params.contractName),
contractDeploys: getContractDeploys(state, props.match.params.contractName), contractDeploys: getContractDeploys(state, props.match.params.contractName),
gasStats: getGasStats(state),
error: state.errorMessage, error: state.errorMessage,
loading: state.loading loading: state.loading
}; };

View File

@ -84,6 +84,10 @@ export function getVersions(state) {
return state.entities.versions; return state.entities.versions;
} }
export function getGasStats(state) {
return state.entities.gasStats[state.entities.gasStats.length - 1];
}
export function isWeb3Enabled(state) { export function isWeb3Enabled(state) {
return Boolean(state.entities.versions.find((version) => version.name === 'web3')); return Boolean(state.entities.versions.find((version) => version.name === 'web3'));
} }