Skip to content

Commit

Permalink
Merge pull request #2 from Schwartz10/web3manager
Browse files Browse the repository at this point in the history
Web3Manager
  • Loading branch information
Schwartz10 authored Apr 23, 2018
2 parents de5e5d1 + bb16eaa commit e67d481
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 100 deletions.
42 changes: 8 additions & 34 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,15 @@
import React, { Component } from 'react'
import { connect } from 'react-redux';
import { fetchWeb3 } from './store/web3'
import { fetchContract } from './store/contract'
import { fetchAccounts } from './store/accounts';
import Routes from './components/Routes'
import React from 'react'
import Routes from './components/Routes';

import './css/oswald.css'
import './css/open-sans.css'
import './css/pure-min.css'
import './App.css'

class App extends Component {
componentDidMount = () => this.collectBlockchainInfo();
const App = () => (
<div className="App">
<Routes />
</div>
);

collectBlockchainInfo = async () => {
const { getContract, getAccounts } = this.props;
// Get network provider, web3, and truffle contract instance and store them on state.
const { web3 } = await this.props.getWeb3();
getContract(web3);
getAccounts(web3);
}

render() {
return (
<div className="App">
<Routes />
</div>
);
}
}

function mapDispatchToProps(dispatch){
return {
getWeb3: () => dispatch(fetchWeb3()),
getContract: (web3) => dispatch(fetchContract(web3)),
getAccounts: (web3) => dispatch(fetchAccounts(web3))
}
}

export default connect(null, mapDispatchToProps)(App);
export default App;
8 changes: 6 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import {Provider} from 'react-redux'
import { Provider } from 'react-redux'
import store from './store'
import Web3Manager from './web3/Web3Manager';

ReactDOM.render(
<Provider store={store}>
<App />
<div>
<Web3Manager />
<App />
</div>
</Provider>,
document.getElementById('root')
);
20 changes: 6 additions & 14 deletions src/store/accounts.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,25 @@
/**
* INITIAL STATE
*/
const defaultAccounts = []
const defaultAccount = null;

/**
* ACTION TYPES
*/
const GET_ACCOUNTS = 'GET_ACCOUNTS';
const GET_ACCOUNT = 'GET_ACCOUNTS';

/**
* ACTION CREATORS
*/
const setAccounts = accounts => ({type: GET_ACCOUNTS, accounts})

/**
* THUNK CREATORS
*/
export const fetchAccounts = web3 => {
return dispatch =>
web3.eth.getAccounts((err, accounts) => dispatch(setAccounts(accounts)))
}
export const setAccount = account => ({type: GET_ACCOUNT, account})

/**
* REDUCER
*/
export default function (state = defaultAccounts, action) {
export default function (state = defaultAccount, action) {
switch (action.type) {
case GET_ACCOUNTS:
return action.accounts;
case GET_ACCOUNT:
return action.account;
default:
return state
}
Expand Down
5 changes: 3 additions & 2 deletions src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import thunkMiddleware from 'redux-thunk'
import { composeWithDevTools } from 'redux-devtools-extension'
import web3 from './web3'
import contract from './contract'
import accounts from './accounts'
import account from './accounts'
import network from './network'


export const reducer = combineReducers({ web3, contract, accounts })
export const reducer = combineReducers({ web3, contract, account, network })
const middleware = composeWithDevTools(applyMiddleware(
thunkMiddleware,
createLogger({collapsed: true})
Expand Down
27 changes: 27 additions & 0 deletions src/store/network.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* INITIAL STATE
*/
const defaultNetwork = false;

/**
* ACTION TYPES
*/
const GET_NETWORK = 'GET_NETWORK';

/**
* ACTION CREATORS
*/
// receives true if the user is on a valid network, false if not
export const setValidNetwork = bool => ({type: GET_NETWORK, bool});

/**
* REDUCER
*/
export default function (state = defaultNetwork, action) {
switch (action.type) {
case GET_NETWORK:
return action.bool;
default:
return state
}
}
15 changes: 2 additions & 13 deletions src/store/web3.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import getWeb3 from '../utils/getWeb3'

/**
* INITIAL STATE
*/
const defaultWeb3 = {}
const defaultWeb3 = {};

/**
* ACTION TYPES
Expand All @@ -13,16 +11,7 @@ const GET_WEB3 = 'GET_WEB3';
/**
* ACTION CREATORS
*/
const setWeb3 = web3 => ({type: GET_WEB3, web3})
/**
* THUNK CREATORS
*/

export const fetchWeb3 = () =>
dispatch =>
getWeb3
.then(results => dispatch(setWeb3(results.web3)))
.catch(() => console.log('error fetching web3'))
export const setWeb3 = web3 => ({type: GET_WEB3, web3})

/**
* REDUCER
Expand Down
35 changes: 0 additions & 35 deletions src/utils/getWeb3.js

This file was deleted.

94 changes: 94 additions & 0 deletions src/web3/Web3Manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React from 'react';
import Web3 from 'web3';
import { connect } from 'react-redux';
import { setWeb3 } from '../store/web3';
import { setAccount } from '../store/accounts';
import { setValidNetwork } from '../store/network';

const fetchWeb3 = (localProvider = null) => {
let { web3 } = window;
if (localProvider) {
const provider = new Web3.providers.HttpProvider(localProvider)
web3 = new Web3(provider)
return web3;
}
else if (typeof web3 !== 'undefined') {
// create new web3 instance with currentProvider
web3 = new Web3(web3.currentProvider);
return web3;
}
// if metamask did not inject web3 and we have no localProvider
else {
return null;
}
};

class Web3Manager extends React.Component {
componentDidMount(){
// continuously look for updates to the window's web3 obj
this.intervalId = setInterval(this.collectWeb3Data.bind(this), 500);
}

componentWillUnmount(){
// clears interval in case the component unmounts to avoid memory leaks
clearInterval(this.intervalId);
}

collectWeb3Data() {
// if any localProvider was passed in as prop, we use it to construct the web3 object
const { localProvider, hasWeb3, currentAccount, validNetwork, requiredNetwork,
setWeb3, setAccount, setValidNetwork } = this.props;
const web3 = fetchWeb3(localProvider || null);

/* -- we only dispatch actions if anything important CHANGED -- */

if (web3){
// dispatches an action if a web3 instance was recently created
if (!hasWeb3) setWeb3(web3);

// /* ---------- ensures the user is on the right network ----------- */
const currentNetworkId = Number(web3.version.network);

// if component received a validNetwork prop, we make sure the user is on the valid network
const onCorrectNetwork = requiredNetwork ?
requiredNetwork === currentNetworkId : true;

// valid network refers to the previous bool value kept on redux store
const changedToValidNetwork = onCorrectNetwork && !validNetwork;

if (changedToValidNetwork) setValidNetwork(true);

/* ------------- checks for unlocked account change -------------- */
const [ account ] = web3.eth.accounts;
const recentlyChangedAccount = account && account !== currentAccount;
const recentlyLoggedOut = !account && currentAccount;

// if an important account changed, dispatch the appropriate action
if (recentlyChangedAccount || recentlyLoggedOut) {
setAccount(account);
}
}
}

render(){
// this component does not need to render any JSX
return(null);
}
}

function mapStateToProps(state, props) {
return {
hasWeb3: Object.keys(state.web3).length > 0,
validNetwork: state.network,
currentAccount: state.account
};
}

export default connect(
mapStateToProps,
{
setWeb3,
setAccount,
setValidNetwork
}
)(Web3Manager);

0 comments on commit e67d481

Please sign in to comment.