Skip to content
This repository was archived by the owner on Mar 11, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
"ganache:deploy": "lerna run ganache:deploy --stream",
"serve:ui": "lerna run serve:ui --parallel --stream",
"webpack-reports": "lerna run webpack-report --parallel --stream",
"lint": "eslint 'packages/*/src/**/*.js'",
"lint:fix": "eslint 'packages/*/src/**/*.js' --fix",
"test": "lerna run test --parallel --stream",
"test:store": "lerna run test --stream --scope @drizzle/store",
"test:store:verbose": "lerna run test --stream --scope @drizzle/store -- --verbose",
Expand Down
41 changes: 24 additions & 17 deletions packages/react-components/src/AccountData.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { drizzleConnect } from "@drizzle/react-plugin";
import React, { Component } from "react";
import PropTypes from "prop-types";
import Loading from "./Loading.js";

class AccountData extends Component {
constructor(props) {
Expand All @@ -10,48 +11,54 @@ class AccountData extends Component {
}

precisionRound(number, precision) {
var factor = Math.pow(10, precision);
const factor = Math.pow(10, precision);
return Math.round(number * factor) / factor;
}

render() {
const {
accounts,
accountIndex,
accountBalances,
precision,
render,
} = this.props;

// No accounts found.
if (Object.keys(this.props.accounts).length === 0) {
return <span>Initializing...</span>;
if (Object.keys(accounts).length === 0) {
return <Loading>Initializing...</Loading>;
}

// Get account address and balance.
const address = this.props.accounts[this.props.accountIndex];
var balance = this.props.accountBalances[address];
const address = accounts[accountIndex];
const units = this.props.units
? this.props.units.charAt(0).toUpperCase() + this.props.units.slice(1)
: "Wei";

let balance = accountBalances[address];

// Convert to given units.
if (this.props.units && typeof balance !== "undefined") {
balance = this.context.drizzle.web3.utils.fromWei(
balance,
this.props.units,
);
if (units && typeof balance !== "undefined") {
balance = this.context.drizzle.web3.utils.fromWei(balance, units);
}

// Adjust to given precision.
if (this.props.precision) {
balance = this.precisionRound(balance, this.props.precision);
if (precision) {
balance = this.precisionRound(balance, precision);
}

if (this.props.render) {
return this.props.render({
if (render) {
return render({
address,
balance,
units,
});
}

return (
<div>
<h4>{address}</h4>
<p>
<div role="status" aria-live="polite">
<h4 aria-label={`${units} Address: ${address}`}>{address}</h4>
<p aria-label={`${units} Balance: ${balance}`}>
{balance} {units}
</p>
</div>
Expand Down
51 changes: 28 additions & 23 deletions packages/react-components/src/ContractData.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { drizzleConnect } from "@drizzle/react-plugin";
import React, { Component } from "react";
import PropTypes from "prop-types";
import Loading from "./Loading.js";

class ContractData extends Component {
constructor(props, context) {
super(props);

// Fetch initial value from chain and return cache key for reactive updates.
var methodArgs = this.props.methodArgs ? this.props.methodArgs : [];
const methodArgs = this.props.methodArgs ? this.props.methodArgs : [];

this.contracts = context.drizzle.contracts;
this.state = {
Expand Down Expand Up @@ -37,48 +38,52 @@ class ContractData extends Component {
}

render() {
const { dataKey } = this.state;
const {
contract,
contracts,
hideIndicator,
method,
render,
toAscii,
toUtf8,
} = this.props;

// Contract is not yet intialized.
if (!this.props.contracts[this.props.contract].initialized) {
return <span>Initializing...</span>;
if (!contracts[contract].initialized) {
return <Loading>Initializing...</Loading>;
}

// If the cache key we received earlier isn't in the store yet; the initial value is still being fetched.
if (
!(
this.state.dataKey in
this.props.contracts[this.props.contract][this.props.method]
)
) {
return <span>Fetching...</span>;
if (!(dataKey in contracts[contract][method])) {
return <Loading>Fetching...</Loading>;
}

// Show a loading spinner for future updates.
var pendingSpinner = this.props.contracts[this.props.contract].synced
? ""
: " 🔄";
let pendingSpinner = !contracts[contract].synced && (
<Loading aria-label="Loading">{" 🔄"}</Loading>
);

// Optionally hide loading spinner (EX: ERC20 token symbol).
if (this.props.hideIndicator) {
pendingSpinner = "";
if (hideIndicator) {
pendingSpinner = null;
}

var displayData = this.props.contracts[this.props.contract][
this.props.method
][this.state.dataKey].value;
let displayData = contracts[contract][method][dataKey].value;

// Optionally convert to UTF8
if (this.props.toUtf8) {
if (toUtf8) {
displayData = this.context.drizzle.web3.utils.hexToUtf8(displayData);
}

// Optionally convert to Ascii
if (this.props.toAscii) {
if (toAscii) {
displayData = this.context.drizzle.web3.utils.hexToAscii(displayData);
}

// If a render prop is given, have displayData rendered from that component
if (this.props.render) {
return this.props.render(displayData);
if (render) {
return render(displayData);
}

// If return value is an array
Expand All @@ -97,7 +102,7 @@ class ContractData extends Component {

// If retun value is an object
if (typeof displayData === "object") {
var i = 0;
let i = 0;
const displayObjectProps = [];

Object.keys(displayData).forEach(key => {
Expand Down
80 changes: 46 additions & 34 deletions packages/react-components/src/ContractForm.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { drizzleConnect } from "@drizzle/react-plugin";
import React, { Component } from "react";
import React, { Component, Fragment } from "react";
import PropTypes from "prop-types";

const translateType = type => {
Expand All @@ -24,19 +24,20 @@ class ContractForm extends Component {

this.contracts = context.drizzle.contracts;
this.utils = context.drizzle.web3.utils;
this.inputs = [];

// Get the contract ABI
const abi = this.contracts[this.props.contract].abi;
const { contract, method } = this.props;
const initialState = {};

this.inputs = [];
var initialState = {};
// Get the contract ABI
const abi = this.contracts[contract].abi;

// Iterate over abi for correct function.
for (var i = 0; i < abi.length; i++) {
if (abi[i].name === this.props.method) {
for (let i = 0; i < abi.length; i++) {
if (abi[i].name === method) {
this.inputs = abi[i].inputs;

for (var j = 0; j < this.inputs.length; j++) {
for (let j = 0; j < this.inputs.length; j++) {
initialState[this.inputs[j].name] = "";
}

Expand All @@ -50,35 +51,42 @@ class ContractForm extends Component {
handleSubmit(event) {
event.preventDefault();

const { contract, method, sendArgs } = this.props;
const convertedInputs = this.inputs.map(input => {
if (input.type === "bytes32") {
return this.utils.toHex(this.state[input.name]);
}
return this.state[input.name];
});

if (this.props.sendArgs) {
return this.contracts[this.props.contract].methods[
this.props.method
].cacheSend(...convertedInputs, this.props.sendArgs);
if (sendArgs) {
return this.contracts[contract].methods[method].cacheSend(
...convertedInputs,
sendArgs,
);
}

return this.contracts[this.props.contract].methods[
this.props.method
].cacheSend(...convertedInputs);
return this.contracts[contract].methods[method].cacheSend(
...convertedInputs,
);
}

handleInputChange(event) {
const value =
event.target.type === 'checkbox'
? event.target.checked
: event.target.value;
this.setState({ [event.target.name]: value });
const { checked, name, type } = event.target;
const value = type === "checkbox" ? checked : event.target.value;
this.setState({ [name]: value });
}

render() {
if (this.props.render) {
return this.props.render({
const { labels, render } = this.props;
const visibilityHidden = {
visibility: "hidden",
display: "inline-block",
width: 0,
};

if (render) {
return render({
inputs: this.inputs,
inputTypes: this.inputs.map(input => translateType(input.type)),
state: this.state,
Expand All @@ -93,20 +101,24 @@ class ContractForm extends Component {
onSubmit={this.handleSubmit}
>
{this.inputs.map((input, index) => {
var inputType = translateType(input.type);
var inputLabel = this.props.labels
? this.props.labels[index]
: input.name;
// check if input type is struct and if so loop out struct fields as well

const inputType = translateType(input.type);
const inputLabel = labels ? labels[index] : input.name;

return (
<input
key={input.name}
type={inputType}
name={input.name}
value={this.state[input.name]}
placeholder={inputLabel}
onChange={this.handleInputChange}
/>
<Fragment key={input.name}>
<label htmlFor={input.name} style={visibilityHidden}>
{inputLabel}
</label>
<input
type={inputType}
name={input.name}
value={this.state[input.name]}
placeholder={inputLabel}
onChange={this.handleInputChange}
/>
</Fragment>
);
})}
<button
Expand Down
14 changes: 14 additions & 0 deletions packages/react-components/src/Loading.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";
import PropTypes from "prop-types";

const Loading = ({ children, ...props }) => (
<span role="alert" aria-busy="true" aria-live="polite" {...props}>
{children}
</span>
);

Loading.propTypes = {
children: PropTypes.node.isRequired,
};

export default Loading;
Loading