Add Drizzle to manage web3 and smart contracts call

This commit is contained in:
Chi Kei Chan 2018-10-10 02:09:26 -07:00
parent e77330ece3
commit bab0217d6c
21 changed files with 855 additions and 291 deletions

@ -7,6 +7,8 @@
"axios": "^0.18.0", "axios": "^0.18.0",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"d3": "^4.13.0", "d3": "^4.13.0",
"drizzle": "^1.2.3",
"drizzle-react": "^1.2.0",
"fuse": "^0.4.0", "fuse": "^0.4.0",
"jazzicon": "^1.5.0", "jazzicon": "^1.5.0",
"node-sass": "^4.9.3", "node-sass": "^4.9.3",
@ -24,6 +26,7 @@
"react-select": "^1.2.1", "react-select": "^1.2.1",
"react-transition-group": "1.x", "react-transition-group": "1.x",
"redux": "^3.7.2", "redux": "^3.7.2",
"redux-saga": "^0.16.2",
"redux-subscriber": "^1.1.0", "redux-subscriber": "^1.1.0",
"redux-thunk": "^2.2.0", "redux-thunk": "^2.2.0",
"ua-parser-js": "^0.7.18", "ua-parser-js": "^0.7.18",

@ -1,5 +1,5 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { connect } from 'react-redux'; import { drizzleConnect } from 'drizzle-react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import './address-input-panel.scss'; import './address-input-panel.scss';
@ -39,4 +39,4 @@ class AddressInputPanel extends Component {
} }
} }
export default connect()(AddressInputPanel); export default drizzleConnect(AddressInputPanel);

@ -1,5 +1,5 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { connect } from 'react-redux'; import { drizzleConnect } from 'drizzle-react'
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { CSSTransitionGroup } from "react-transition-group"; import { CSSTransitionGroup } from "react-transition-group";
import classnames from 'classnames'; import classnames from 'classnames';
@ -32,7 +32,11 @@ class CurrencyInputPanel extends Component {
title: PropTypes.string, title: PropTypes.string,
description: PropTypes.string, description: PropTypes.string,
extraText: PropTypes.string, extraText: PropTypes.string,
web3: PropTypes.object.isRequired, initialized: PropTypes.bool,
};
static contextTypes = {
drizzle: PropTypes.object,
}; };
state = { state = {
@ -44,15 +48,19 @@ class CurrencyInputPanel extends Component {
getBalance() { getBalance() {
const { const {
balance, balance,
web3, initialized,
} = this.props; } = this.props;
const { selectedTokenAddress } = this.state; const { selectedTokenAddress } = this.state;
const { drizzle: { web3 } } = this.context;
if (!selectedTokenAddress) { if (!selectedTokenAddress || !initialized || !web3 || !balance) {
return ''; return '';
} }
if (selectedTokenAddress === 'ETH') {
return `Balance: ${web3.utils.fromWei(balance, 'ether')}`;
}
const bn = balance[selectedTokenAddress]; const bn = balance[selectedTokenAddress];
if (!bn) { if (!bn) {
@ -147,8 +155,6 @@ class CurrencyInputPanel extends Component {
const { const {
title, title,
description, description,
balance,
web3,
} = this.props; } = this.props;
const { selectedTokenAddress } = this.state; const { selectedTokenAddress } = this.state;
@ -201,13 +207,22 @@ class CurrencyInputPanel extends Component {
} }
} }
export default connect( export default drizzleConnect(
state => ({ CurrencyInputPanel,
tokenAddresses: state.web3.tokenAddresses, state => {
balance: state.web3.balance, const {
web3: state.web3.web3, drizzleStatus: { initialized },
}), accounts,
accountBalances,
} = state;
return {
tokenAddresses: state.addresses.tokenAddresses,
initialized,
balance: accountBalances[accounts[0]] || null,
};
},
dispatch => ({ dispatch => ({
updateField: (name, value) => dispatch(updateField({ name, value })), updateField: (name, value) => dispatch(updateField({ name, value })),
}) }),
)(CurrencyInputPanel); );

@ -3,7 +3,7 @@ import React, { Component }from 'react';
import SelectToken from './SelectToken'; import SelectToken from './SelectToken';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { setInteractionState, setExchangeType } from '../ducks/web3'; import { setInteractionState, setExchangeType } from '../ducks/addresses';
import { setExchangeInputValue, setExchangeOutputValue, setExchangeRate, setExchangeFee, setInputToken, setOutputToken, setInputBalance, setOutputBalance, setAllowanceApprovalState } from '../ducks/exchange'; import { setExchangeInputValue, setExchangeOutputValue, setExchangeRate, setExchangeFee, setInputToken, setOutputToken, setInputBalance, setOutputBalance, setAllowanceApprovalState } from '../ducks/exchange';
class Exchange extends Component { class Exchange extends Component {

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { drizzleConnect } from 'drizzle-react'
import classnames from 'classnames'; import classnames from 'classnames';
import UAParser from 'ua-parser-js'; import UAParser from 'ua-parser-js';
import Logo from '../Logo'; import Logo from '../Logo';
@ -57,7 +57,9 @@ function Header (props) {
})} })}
> >
<div>No Ethereum wallet found</div> <div>No Ethereum wallet found</div>
<div className="header__dialog__description">Please visit us from a web3-enabled mobile browser, such as Trust Wallet and Cipher Browser.</div> <div className="header__dialog__description">
Please visit us from a web3-enabled mobile browser, such as Trust Wallet and Cipher Browser.
</div>
<div className="header__download"> <div className="header__download">
<img src={CipherLogo} onClick={() => window.open(getCipherLink(), '_blank')} /> <img src={CipherLogo} onClick={() => window.open(getCipherLink(), '_blank')} />
<img src={TrustLogo} onClick={() => window.open(getTrustLink(), '_blank')} /> <img src={TrustLogo} onClick={() => window.open(getTrustLink(), '_blank')} />
@ -72,7 +74,7 @@ function Header (props) {
<div className="header__center-group"> <div className="header__center-group">
<span className="header__title">Uniswap</span> <span className="header__title">Uniswap</span>
</div> </div>
<Web3Status address="0xcf1de0b4d1e492080336909f70413a5f4e7eec62" isConnected /> <Web3Status isConnected />
</div> </div>
<NavigationTabs <NavigationTabs
className={classnames('header__navigation', { className={classnames('header__navigation', {
@ -84,15 +86,15 @@ function Header (props) {
} }
Header.propTypes = { Header.propTypes = {
web3: PropTypes.object.isRequired,
currentAddress: PropTypes.string, currentAddress: PropTypes.string,
isConnected: PropTypes.bool.isRequired, isConnected: PropTypes.bool.isRequired,
}; };
export default connect( export default drizzleConnect(
Header,
state => ({ state => ({
web3: state.web3.web3, // web3: console.log(state) || state.web3,
currentAddress: state.web3.currentAddress, currentAddress: state.accounts[0],
isConnected: !!(state.web3.web3 && state.web3.currentAddress), isConnected: !!(state.drizzleStatus.initialized && state.accounts[0]),
}), }),
)(Header) );

@ -2,7 +2,7 @@ import React, { Component }from 'react';
import { bindActionCreators } from 'redux' import { bindActionCreators } from 'redux'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { subscribe } from 'redux-subscriber'; import { subscribe } from 'redux-subscriber';
import { setWeb3ConnectionStatus, setInteractionState, setNetworkMessage, metamaskLocked } from '../ducks/web3'; import { setWeb3ConnectionStatus, setInteractionState, setNetworkMessage, metamaskLocked } from '../ducks/addresses';
class NetworkStatus extends Component { class NetworkStatus extends Component {
componentDidMount(){ componentDidMount(){

@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { bindActionCreators } from 'redux' import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { setBlockTimestamp, setInteractionState } from '../ducks/web3'; import { setBlockTimestamp, setInteractionState } from '../ducks/addresses';
import { setExchangeInputValue, setExchangeOutputValue } from '../ducks/exchange'; import { setExchangeInputValue, setExchangeOutputValue } from '../ducks/exchange';
class Purchase extends Component { class Purchase extends Component {

@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { bindActionCreators } from 'redux' import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { setBlockTimestamp, setInteractionState } from '../ducks/web3'; import { setBlockTimestamp, setInteractionState } from '../ducks/addresses';
import { setExchangeInputValue, setExchangeOutputValue } from '../ducks/exchange'; import { setExchangeInputValue, setExchangeOutputValue } from '../ducks/exchange';
class Purchase extends Component { class Purchase extends Component {

@ -1,65 +0,0 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { updateBalance } from '../../ducks/web3';
class Watcher extends Component {
state = {
watchlist: {},
};
componentWillMount() {
this.startWatching();
}
componentWillUnmount() {
}
add(address) {
const { watchlist } = this.state;
this.setState({
...watchlist,
[address]: true,
});
}
remove(address) {
const { watchlist } = this.state;
this.setState({
...watchlist,
[address]: false,
});
}
startWatching() {
if (this.interval) {
clearInterval(this.interval);
return;
}
this.interval = setInterval(() => {
this.props.updateBalance();
Object.keys(this.state.watchlist).forEach(address => {
});
}, 15000);
}
stopWatching() {
if (this.interval) {
clearInterval(this.interval);
}
}
render() {
return <noscript />;
}
}
export default connect(
null,
dispatch => ({
updateBalance: () => dispatch(updateBalance()),
}),
)(Watcher);

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { drizzleConnect } from 'drizzle-react'
import classnames from 'classnames'; import classnames from 'classnames';
import Web3 from 'web3'; import Web3 from 'web3';
import Jazzicon from 'jazzicon'; import Jazzicon from 'jazzicon';
@ -26,6 +26,7 @@ function Web3Status(props) {
return; return;
} }
el.innerHTML = '';
el.appendChild(Jazzicon(18, parseInt(address.slice(2), 16))); el.appendChild(Jazzicon(18, parseInt(address.slice(2), 16)));
}} }}
/> />
@ -41,7 +42,7 @@ function getText(text) {
return 'Disconnected'; return 'Disconnected';
} }
const address = Web3.utils.toChecksumAddress(text) const address = Web3.utils.toChecksumAddress(text);
return `${address.substring(0, 6)}...${address.substring(38)}`; return `${address.substring(0, 6)}...${address.substring(38)}`;
} }
@ -56,9 +57,10 @@ Web3Status.defaultProps = {
address: 'Disconnected', address: 'Disconnected',
}; };
export default connect( export default drizzleConnect(
({ web3: { web3, currentAddress } }) => ({ Web3Status,
address: currentAddress, state => ({
isConnected: !!(web3 && currentAddress), address: state.accounts[0],
isConnected: !!(state.drizzleStatus.initialized && state.accounts[0]),
}) })
)(Web3Status); );

28
src/ducks/addresses.js Normal file

@ -0,0 +1,28 @@
const initialState = {
currentAddress: '',
balance: {},
exchangeAddresses: {
addresses: [
['BAT','0x80f5C1beA2Ea4a9C21E4c6D7831ae2Dbce45674d'],
['DAI','0x9eb0461bcc20229bE61319372cCA84d782823FCb'],
['MKR','0x4c86a3b3cf926de3644f60658071ca604949609f'],
['OMG','0x1033f09e293200de63AF16041e83000aFBBfF5c0'],
['ZRX','0x42E109452F4055c82a513A527690F2D73251367e']
]
},
tokenAddresses: {
addresses: [
['BAT','0xDA5B056Cfb861282B4b59d29c9B395bcC238D29B'],
['DAI','0x2448eE2641d78CC42D7AD76498917359D961A783'],
['MKR','0xf9ba5210f91d0474bd1e1dcdaec4c58e359aad85'],
['OMG','0x879884c3C46A24f56089f3bBbe4d5e38dB5788C0'],
['ZRX','0xF22e3F33768354c9805d046af3C0926f27741B43']
]
},
};
export default (state = initialState, { type }) => {
switch (type) {
default: return state;
}
}

@ -1,15 +1,16 @@
import { combineReducers } from 'redux'; import { combineReducers } from 'redux';
// import global from './global-reducer'; import { drizzleReducers } from 'drizzle'
import web3 from './web3'; import addresses from './addresses';
import exchangeContracts from './exchange-contract'; import exchangeContracts from './exchange-contract';
import tokenContracts from './token-contract'; import tokenContracts from './token-contract';
import exchange from './exchange'; import exchange from './exchange';
import swap from './swap'; import swap from './swap';
export default combineReducers({ export default combineReducers({
web3, addresses,
exchangeContracts, exchangeContracts,
tokenContracts, tokenContracts,
exchange, exchange,
swap, swap,
...drizzleReducers,
}); });

@ -1,104 +0,0 @@
import Web3 from "web3";
const INITIALIZE = 'app/web3/initialize';
const UPDATE_CURRENT_ADDRESS = 'app/web3/updateCurrentAddress';
const UPDATE_BALANCE = 'app/web3/updateBalance';
const initialState = {
web3: {},
currentAddress: '',
balance: {},
exchangeAddresses: {
addresses: [
['BAT','0x80f5C1beA2Ea4a9C21E4c6D7831ae2Dbce45674d'],
['DAI','0x9eb0461bcc20229bE61319372cCA84d782823FCb'],
['MKR','0x4c86a3b3cf926de3644f60658071ca604949609f'],
['OMG','0x1033f09e293200de63AF16041e83000aFBBfF5c0'],
['ZRX','0x42E109452F4055c82a513A527690F2D73251367e']
]
},
tokenAddresses: {
addresses: [
['BAT','0xDA5B056Cfb861282B4b59d29c9B395bcC238D29B'],
['DAI','0x2448eE2641d78CC42D7AD76498917359D961A783'],
['MKR','0xf9ba5210f91d0474bd1e1dcdaec4c58e359aad85'],
['OMG','0x879884c3C46A24f56089f3bBbe4d5e38dB5788C0'],
['ZRX','0xF22e3F33768354c9805d046af3C0926f27741B43']
]
},
};
export const initialize = () => dispatch => {
if (typeof window.web3 !== 'undefined') {
const web3 = new Web3(window.web3.currentProvider);
dispatch({
type: INITIALIZE,
payload: web3,
});
dispatch(updateCurrentAddress());
setInterval(() => dispatch(updateBalance()), 15000)
}
};
export const updateCurrentAddress = () => (dispatch, getState) => {
const { web3: { web3 } } = getState();
if (!web3) {
return;
}
web3.eth.getAccounts((err, accounts) => {
if (err) {
return;
}
dispatch({
type: UPDATE_CURRENT_ADDRESS,
payload: accounts[0],
});
dispatch(updateBalance());
});
};
export const updateBalance = () => (dispatch, getState) => {
const { web3: { web3, currentAddress } } = getState();
if (!web3 || !currentAddress) {
return;
}
web3.eth.getBalance(currentAddress, (e, data) => {
if (e) {
return;
}
dispatch({
type: UPDATE_BALANCE,
payload: {
address: 'ETH',
balance: data,
}
});
});
};
export default (state = initialState, { type, payload }) => {
switch (type) {
case INITIALIZE:
return { ...state, web3: payload };
case UPDATE_CURRENT_ADDRESS:
return { ...state, currentAddress: payload };
case UPDATE_BALANCE:
return {
...state,
balance: {
...state.balance,
[payload.address]: payload.balance,
},
};
default: return state;
}
}

@ -1,20 +1,23 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import Web3 from 'web3'; import { DrizzleProvider } from 'drizzle-react';
import App from './pages/App'; import App from './pages/App';
import { Provider } from 'react-redux';
import store from './store'; import store from './store';
import './index.scss'; import './index.scss';
import registerServiceWorker from './registerServiceWorker'; import registerServiceWorker from './registerServiceWorker';
window.addEventListener('load', function() { window.addEventListener('load', function() {
ReactDOM.render( ReactDOM.render(
<Provider store={store}> <DrizzleProvider options={{
contracts: [],
events: [],
polls: { accounts: 3000, blocks: 3000 },
}} store={store}>
<App /> <App />
</Provider> </DrizzleProvider>
, document.getElementById('root') , document.getElementById('root')
); );

@ -1,9 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { connect } from 'react-redux'; import { drizzleConnect } from 'drizzle-react'
import { BrowserRouter, Switch, Route } from 'react-router-dom'; import { BrowserRouter, Switch, Route } from 'react-router-dom';
import { AnimatedSwitch } from 'react-router-transition'; import { AnimatedSwitch } from 'react-router-transition';
import { initialize } from '../ducks/web3'
import Watcher from '../components/Watcher';
import Swap from './Swap'; import Swap from './Swap';
import Send from './Send'; import Send from './Send';
import Pool from './Pool'; import Pool from './Pool';
@ -11,35 +9,32 @@ import Pool from './Pool';
import './App.scss'; import './App.scss';
class App extends Component { class App extends Component {
componentWillMount() {
this.props.initializeWeb3();
}
render() { render() {
if (!this.props.initialized) {
return <noscript />;
}
return ( return (
<div style={{ width: '100%', height: '100%' }}> <BrowserRouter>
<Watcher /> <AnimatedSwitch
<BrowserRouter> atEnter={{ opacity: 0 }}
<AnimatedSwitch atLeave={{ opacity: 0 }}
atEnter={{ opacity: 0 }} atActive={{ opacity: 1 }}
atLeave={{ opacity: 0 }} className="app__switch-wrapper"
atActive={{ opacity: 1 }} >
className="app__switch-wrapper" <Route exact path="/swap" component={Swap} />
> <Route exact path="/send" component={Send} />
<Route exact path="/swap" component={Swap} /> <Route exact path="/pool" component={Pool} />
<Route exact path="/send" component={Send} /> <Route component={Swap} />
<Route exact path="/pool" component={Pool} /> </AnimatedSwitch>
<Route component={Swap} /> </BrowserRouter>
</AnimatedSwitch>
</BrowserRouter>
</div>
); );
} }
} }
export default connect( export default drizzleConnect(
null, App,
dispatch => ({ state => ({
initializeWeb3: () => dispatch(initialize()), initialized: state.drizzleStatus.initialized,
}) }),
)(App); );

@ -1,5 +1,5 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { connect } from 'react-redux'; import { drizzleConnect } from 'drizzle-react';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from "classnames"; import classnames from "classnames";
@ -20,7 +20,6 @@ class Pool extends Component {
// Injected by React Router Dom // Injected by React Router Dom
push: PropTypes.func.isRequired, push: PropTypes.func.isRequired,
pathname: PropTypes.string.isRequired, pathname: PropTypes.string.isRequired,
web3: PropTypes.object.isRequired,
currentAddress: PropTypes.string, currentAddress: PropTypes.string,
isConnected: PropTypes.bool.isRequired, isConnected: PropTypes.bool.isRequired,
}; };
@ -84,13 +83,13 @@ class Pool extends Component {
} }
export default withRouter( export default withRouter(
connect( drizzleConnect(
Pool,
(state, ownProps) => ({ (state, ownProps) => ({
push: ownProps.history.push, push: ownProps.history.push,
pathname: ownProps.location.pathname, pathname: ownProps.location.pathname,
web3: state.web3.web3, currentAddress: state.accounts[0],
currentAddress: state.web3.currentAddress, isConnected: !!(state.drizzleStatus.initialized && state.accounts[0]),
isConnected: !!(state.web3.web3 && state.web3.currentAddress),
}), }),
)(Pool) ),
); );

@ -1,5 +1,5 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { connect } from 'react-redux'; import { drizzleConnect } from 'drizzle-react';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
@ -16,7 +16,6 @@ class Send extends Component {
// Injected by React Router Dom // Injected by React Router Dom
push: PropTypes.func.isRequired, push: PropTypes.func.isRequired,
pathname: PropTypes.string.isRequired, pathname: PropTypes.string.isRequired,
web3: PropTypes.object.isRequired,
currentAddress: PropTypes.string, currentAddress: PropTypes.string,
isConnected: PropTypes.bool.isRequired, isConnected: PropTypes.bool.isRequired,
}; };
@ -75,13 +74,13 @@ class Send extends Component {
} }
export default withRouter( export default withRouter(
connect( drizzleConnect(
Send,
(state, ownProps) => ({ (state, ownProps) => ({
push: ownProps.history.push, push: ownProps.history.push,
pathname: ownProps.location.pathname, pathname: ownProps.location.pathname,
web3: state.web3.web3, currentAddress: state.accounts[0],
currentAddress: state.web3.currentAddress, isConnected: !!(state.drizzleStatus.initialized && state.accounts[0]),
isConnected: !!(state.web3.web3 && state.web3.currentAddress),
}), }),
)(Send) ),
); );

@ -1,5 +1,5 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { connect } from 'react-redux'; import { drizzleConnect } from 'drizzle-react';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
@ -15,7 +15,6 @@ class Swap extends Component {
// Injected by React Router Dom // Injected by React Router Dom
push: PropTypes.func.isRequired, push: PropTypes.func.isRequired,
pathname: PropTypes.string.isRequired, pathname: PropTypes.string.isRequired,
web3: PropTypes.object.isRequired,
currentAddress: PropTypes.string, currentAddress: PropTypes.string,
isConnected: PropTypes.bool.isRequired, isConnected: PropTypes.bool.isRequired,
}; };
@ -67,13 +66,13 @@ class Swap extends Component {
} }
export default withRouter( export default withRouter(
connect( drizzleConnect(
Swap,
(state, ownProps) => ({ (state, ownProps) => ({
push: ownProps.history.push, push: ownProps.history.push,
pathname: ownProps.location.pathname, pathname: ownProps.location.pathname,
web3: state.web3.web3, currentAddress: state.accounts[0],
currentAddress: state.web3.currentAddress, isConnected: !!(state.drizzleStatus.initialized && state.accounts[0]),
isConnected: !!(state.web3.web3 && state.web3.currentAddress),
}), }),
)(Swap) ),
); );

@ -1,6 +1,7 @@
import { generateContractsInitialState } from 'drizzle'
export default { export default {
web3: { addresses: {
web3: {},
exchangeAddresses: { exchangeAddresses: {
addresses: [ addresses: [
['BAT','0x80f5C1beA2Ea4a9C21E4c6D7831ae2Dbce45674d'], ['BAT','0x80f5C1beA2Ea4a9C21E4c6D7831ae2Dbce45674d'],
@ -20,6 +21,7 @@ export default {
] ]
} }
}, },
contracts: generateContractsInitialState({ contracts: [], events: [], polls: [] }),
exchangeContracts: {}, exchangeContracts: {},
tokenContracts: {}, tokenContracts: {},
exchange: { exchange: {

@ -1,20 +1,32 @@
import { applyMiddleware, compose, createStore } from 'redux'; import { applyMiddleware, compose, createStore } from 'redux';
import reducer from '../ducks';
import thunk from 'redux-thunk' import thunk from 'redux-thunk'
import initSubscriber from 'redux-subscriber';
import initialState from './initial-state'; import initialState from './initial-state';
import reducer from '../ducks';
import createSagaMiddleware from 'redux-saga';
import { all, fork } from 'redux-saga/effects'
import { drizzleSagas } from 'drizzle'
const middleware = [thunk]; function* root() {
yield all(
drizzleSagas.map(saga => fork(saga))
)
}
const sagaMiddleware = createSagaMiddleware();
const middleware = [thunk, sagaMiddleware];
const enhancers = []; const enhancers = [];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore( const store = createStore(
reducer, reducer,
initialState, initialState,
composeEnhancers(applyMiddleware(...middleware), ...enhancers) composeEnhancers(
applyMiddleware(...middleware),
...enhancers,
)
); );
// redux-subscribe solution attempt
// eslint-disable-next-line no-unused-vars sagaMiddleware.run(root);
const subscribe = initSubscriber(store);
export default store; export default store;

709
yarn.lock

File diff suppressed because it is too large Load Diff