diff --git a/package.json b/package.json index bec6788..2e6fc48 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "dependencies": { "firebase": "^4.1.1", "immutable": "^3.8.1", + "material-components-web": "^0.13.0", "prop-types": "^15.5.10", "react": "^15.5.4", "react-dom": "^15.5.4", @@ -14,6 +15,7 @@ "react-router-redux": "^5.0.0-alpha.5", "redux": "^3.6.0", "redux-devtools-extension": "^2.13.2", + "redux-saga": "^0.15.3", "uuid": "^3.0.1" }, "devDependencies": { diff --git a/public/index.html b/public/index.html index 7bee027..0b8a0cc 100644 --- a/public/index.html +++ b/public/index.html @@ -19,6 +19,8 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> + + React App diff --git a/src/App.js b/src/App.js index fe13990..7f3f4ff 100644 --- a/src/App.js +++ b/src/App.js @@ -1,30 +1,38 @@ +import 'api/config/firebase'; import React, { Component } from 'react'; import { createStore, combineReducers, applyMiddleware } from 'redux'; import { Provider } from 'react-redux'; import createHistory from 'history/createBrowserHistory'; -import { Route, withRouter } from 'react-router-dom'; +import { Route } from 'react-router-dom'; import { composeWithDevTools } from 'redux-devtools-extension'; import { ConnectedRouter, routerReducer, routerMiddleware } from 'react-router-redux'; +import createSagaMiddleware from 'redux-saga'; import uuid from 'uuid'; import './App.css'; -import Login from 'components/auth/container'; -import Home from 'components/home/container'; +import Login from 'components/auth'; +import Home from 'components/home'; +import Beers from 'components/beer'; -import middleware from 'api/middlewares/middleware.js'; +import sagas from 'api/sagas'; import reducers from 'api/reducers'; + +import { actions as authActions } from 'api/actions/auth'; + window.uuid = uuid; class App extends Component { + componentWillMount() { + const sagaMiddleware = createSagaMiddleware(); const composeEnhancers = composeWithDevTools({}); this.history = createHistory(); const routerReduxMiddleware = routerMiddleware(this.history); const middlewares = [ - middleware, + sagaMiddleware, routerReduxMiddleware, ]; this.store = createStore( @@ -34,6 +42,7 @@ class App extends Component { }), composeEnhancers(applyMiddleware(...middlewares)) ); + sagaMiddleware.run(sagas); } componentDidMount() { @@ -42,7 +51,7 @@ class App extends Component { onAuthStateChanged = (payload) => { const action = { - type: 'logged', + type: authActions.logged, payload, }; this.store.dispatch(action); @@ -55,6 +64,7 @@ class App extends Component {
+
diff --git a/src/api/actions/auth.js b/src/api/actions/auth.js index b5a2755..f16cfc7 100644 --- a/src/api/actions/auth.js +++ b/src/api/actions/auth.js @@ -3,23 +3,26 @@ import { push } from 'react-router-redux'; export const actions = { login: 'BREWERY_AUTH_LOGIN', logged: 'BREWERY_AUTH_LOGGED', -} + logout: 'BREWERY_AUTH_LOGOUT', +}; export const mapStateToProps = ({ user }) => ({ user }); -export const mapDispatchToProps = (dispatch) => { +export const mapDispatchToProps = dispatch => { return { - redirectToHome: (uid) => { + redirectToHome: uid => { if (uid) { dispatch(push('/')); } }, - redirectToLogin: (uid) => { + redirectToLogin: uid => { if (!uid) { dispatch(push('/login')); } }, - onLogin: () => dispatch({ type: 'login' }) + + onLogin: () => dispatch({ type: actions.login }), + onLogout: () => dispatch({ type: actions.logout }), }; }; diff --git a/src/api/actions/beer.js b/src/api/actions/beer.js new file mode 100644 index 0000000..f522f27 --- /dev/null +++ b/src/api/actions/beer.js @@ -0,0 +1,55 @@ +export const actions = { + add: 'BEER_LIST_ADD', + edit: 'BEER_LIST_EDIT', + update: 'BEER_LIST_UPDATE', + remove: 'BEER_LIST_REMOVE', + request: 'BEER_LIST_REQUEST', + requestSuccess: 'BEER_LIST_REQUEST_SUCCESS', +}; + +export const mapStateToProps = ({ beerList, beerEdit }) => ({ beerList, beerEdit }); + +export const mapDispatchToProps = dispatch => { + return { + + request: (payload1, payload2) => dispatch({ + type: actions.request, + payload1, + payload2, + }), + + requestSuccess: payload => dispatch({ + type: actions.requestSuccess, + payload, + }), + + add: (payload1, payload2) => dispatch({ + type: actions.add, + payload1, + payload2, + }), + + remove: (payload, payload1, payload2) => dispatch({ + type: actions.remove, + payload, + payload1, + payload2, + }), + + update: (payload, payload1, payload2) => dispatch({ + type: actions.update, + payload, + payload1, + payload2, + }), + + edit: (payload, payload1, payload2) => dispatch({ + type: actions.edit, + payload, + payload1, + payload2, + }), + }; +}; + +export default {}; diff --git a/src/api/actions/brewery.js b/src/api/actions/brewery.js index 59676e6..4bab37c 100644 --- a/src/api/actions/brewery.js +++ b/src/api/actions/brewery.js @@ -1,25 +1,37 @@ -import { push } from 'react-router-redux'; - export const actions = { add: 'BREWERY_LIST_ADD', edit: 'BREWERY_LIST_EDIT', - request:'BREWERY_LIST_REQUEST', + update: 'BREWERY_LIST_UPDATE', + remove: 'BREWERY_LIST_REMOVE', + request: 'BREWERY_LIST_REQUEST', requestSuccess: 'BREWERY_LIST_REQUEST_SUCCESS', -} +}; -export const mapStateToProps = ({ list }) => ({ list }); +export const mapStateToProps = ({ list, breweryEdit, user }) => ({ list, breweryEdit, user }); -export const mapDispatchToProps = (dispatch) => { +export const mapDispatchToProps = dispatch => { return { request: () => dispatch({ type: actions.request }), requestSuccess: payload => dispatch({ type: actions.requestSuccess, - payload + payload, }), + add: () => dispatch({ type: actions.add }), + + remove: payload => dispatch({ + type: actions.remove, + payload, + }), + + update: payload => dispatch({ + type: actions.update, + payload + }), + edit: payload => dispatch({ type: actions.edit, - payload + payload, }), }; }; diff --git a/src/api/config/firebase.js b/src/api/config/firebase.js new file mode 100644 index 0000000..6ee2b89 --- /dev/null +++ b/src/api/config/firebase.js @@ -0,0 +1,13 @@ +import firebase from 'firebase'; + +const config = { + apiKey: "AIzaSyBp4WfcFIutxqzrGbCxcro9YxRUhHgoWe4", + authDomain: "feedback-4a295.firebaseapp.com", + databaseURL: "https://feedback-4a295.firebaseio.com", + projectId: "feedback-4a295", + storageBucket: "feedback-4a295.appspot.com", + messagingSenderId: "952975869388" +}; +firebase.initializeApp(config); + +window.firebase = firebase; diff --git a/src/api/middlewares/middleware.js b/src/api/middlewares/middleware.js deleted file mode 100644 index 92d6356..0000000 --- a/src/api/middlewares/middleware.js +++ /dev/null @@ -1,75 +0,0 @@ -import uuid from 'uuid'; -import firebase from 'firebase'; -import { actions } from 'api/actions/auth'; - -const config = { - apiKey: "AIzaSyDGYMxpnYaAJYyquEUM6Y__yQjhPP_skx0", - authDomain: "feedback-140018.firebaseapp.com", - databaseURL: "https://feedback-140018.firebaseio.com", - projectId: "feedback-140018", - storageBucket: "feedback-140018.appspot.com", - messagingSenderId: "71457068040" -}; -firebase.initializeApp(config); -window.firebase = firebase; - -const addFirebaseUser = (user, store) => { - const { displayName, photoURL, email, uid } = user; - const ref = firebase.database().ref(`/users/${uid}`); - ref.update({ - displayName, - photoURL, - email, - }).then(() => { - store.dispatch({ - type: actions.logged, - payload: user, - }) - }); - } - -function middleware(store) { - return dispatch => { - return action => { - - if (action.type === 'BREWERY_LIST_EDIT') { - const { uid } = action.payload; - const ref = firebase.database().ref(`/breweries/${uid}`); - ref.update(action.payload); - } - - if (action.type === 'BREWERY_LIST_ADD') { - const uid = uuid(); - const ref = firebase.database().ref(`/breweries/${uid}`); - ref.update({ - uid, - name: '', - brewery: '', - }) - } - - if (action.type === 'BREWERY_LIST_REQUEST') { - const ref = firebase.database().ref(`/breweries`); - ref.on('value', data => { - store.dispatch({ - type: 'BREWERY_LIST_REQUEST_SUCCESS', - payload: data.val(), - }); - }); - } - - - if (action.type === actions.login) { - const authProvider = new firebase.auth.GoogleAuthProvider(); - firebase.auth() - .signInWithPopup(authProvider) - .then((payload) => { - addFirebaseUser(payload.user, store); - }); - } - return dispatch(action); - } - } -} - -export default middleware; diff --git a/src/api/reducers/index.js b/src/api/reducers/index.js index ffa8dad..e79a6c2 100644 --- a/src/api/reducers/index.js +++ b/src/api/reducers/index.js @@ -1,20 +1,54 @@ import { fromJS } from 'immutable'; +import { actions as breweryActions } from 'api/actions/brewery'; +import { actions as beerActions } from 'api/actions/beer'; +import { actions as authActions } from 'api/actions/auth'; -function listReducer(list = fromJS({}), action) { - if (action.type === 'BREWERY_LIST_REQUEST_SUCCESS') { +//User related +function userReducer(user = {}, action){ + if(action.type === authActions.logged){ + return action.payload || {}; + } + return user; +} +//User related + + +//Brewery related +function listReducer(list = fromJS({}), action){ + if(action.type === breweryActions.requestSuccess){ return fromJS(action.payload); } return list; } +function breweryEdit(brewery = fromJS({}), action) { + if (action.type === breweryActions.edit) { + return action.payload; + } + return brewery; +} +//Brewery related + -function userReducer(user = {}, action) { - if (action.type === 'logged') { +//Beer related +function beerListReducer(beerList = fromJS({}), action){ + if(action.type === beerActions.requestSuccess){ + return fromJS(action.payload) || fromJS({}); + } + return beerList; +} +function beerEdit(beer = fromJS({}), action) { + if (action.type === beerActions.edit) { return action.payload; } - return user; + return beer; } +//Beer related + -export default { +export default{ user: userReducer, list: listReducer, -}; + beerList: beerListReducer, + breweryEdit: breweryEdit, + beerEdit: beerEdit, +} diff --git a/src/api/sagas/beer/watchAddBeer.js b/src/api/sagas/beer/watchAddBeer.js new file mode 100644 index 0000000..1c2c14c --- /dev/null +++ b/src/api/sagas/beer/watchAddBeer.js @@ -0,0 +1,20 @@ +import { takeLatest, put } from 'redux-saga/effects'; +import { actions } from 'api/actions/beer'; +import uuid from 'uuid'; + +function* addSuccessfull({ payload1, payload2 }) { + const uid = uuid(); + const ref = yield window.firebase.database().ref( + `users/${payload1}/breweries/${payload2}/${uid}` + ); + yield ref.update({ uid, name: '', premium: false }); + yield put({ + type: actions.request, + payload1, + payload2, + }); +} + +export default function* watchAddBrewery() { + yield takeLatest(actions.add, addSuccessfull); +} diff --git a/src/api/sagas/beer/watchBeers.js b/src/api/sagas/beer/watchBeers.js new file mode 100644 index 0000000..6fd7a9a --- /dev/null +++ b/src/api/sagas/beer/watchBeers.js @@ -0,0 +1,29 @@ +import { takeLatest, call, put } from 'redux-saga/effects'; +import { actions } from 'api/actions/beer'; + +const fetchBreweries = (ref) => { + return new Promise((resolve, reject) => { + ref.on('value', data => { + resolve(data.val()) + }); + }); +} + +function* requestSuccessfull({ payload1, payload2 }) { + console.log(`/users/${payload1}/breweries/${payload2}/`); + try { + const ref = yield window.firebase.database().ref( + `/users/${payload1}/breweries/${payload2}/` + ); + yield ref.update({}); + + const payload = yield call(fetchBreweries, ref); + yield put({ type: actions.requestSuccess, payload }); + } catch(error) { + console.log("ERRAO DA PORRA", error); + } +} + +export default function* watchBreweries() { + yield takeLatest(actions.request, requestSuccessfull); +} diff --git a/src/api/sagas/beer/watchEditBeer.js b/src/api/sagas/beer/watchEditBeer.js new file mode 100644 index 0000000..06a545e --- /dev/null +++ b/src/api/sagas/beer/watchEditBeer.js @@ -0,0 +1,25 @@ +import { takeLatest, put } from 'redux-saga/effects'; +import { fromJS } from 'immutable'; +import { actions } from 'api/actions/beer'; + +function* editSuccessfull({ payload, payload1, payload2 }) { + const ref = yield window.firebase.database().ref( + `users/${payload1}/breweries/${payload2}/${payload.get('uid')}` + ); + yield ref.update(payload.toJS()); + yield put({ + type: actions.edit, + payload: fromJS({}), + payload1, + payload2, + }); + yield put({ + type: actions.request, + payload1, + payload2, + }); +} + +export default function* watchEditBrewery() { + yield takeLatest(actions.update, editSuccessfull); +} diff --git a/src/api/sagas/beer/watchRemoveBeer.js b/src/api/sagas/beer/watchRemoveBeer.js new file mode 100644 index 0000000..1173908 --- /dev/null +++ b/src/api/sagas/beer/watchRemoveBeer.js @@ -0,0 +1,18 @@ +import { takeLatest, put } from 'redux-saga/effects'; +import { actions } from 'api/actions/beer'; + +function* removeSuccessfull({ payload: uid, payload1, payload2 }) { + const ref = yield window.firebase.database().ref( + `/users/${payload1}/breweries/${payload2}/${uid}` + ); + yield ref.remove(); + yield put({ + type: actions.request, + payload1, + payload2, + }); +} + +export default function* watchRemoveBrewery() { + yield takeLatest(actions.remove, removeSuccessfull); +} diff --git a/src/api/sagas/brewery/watchAddBrewery.js b/src/api/sagas/brewery/watchAddBrewery.js new file mode 100644 index 0000000..7737c04 --- /dev/null +++ b/src/api/sagas/brewery/watchAddBrewery.js @@ -0,0 +1,14 @@ +import { takeLatest, put } from 'redux-saga/effects'; +import { actions } from 'api/actions/brewery'; +import uuid from 'uuid'; + +function* addSuccessfull() { + const uid = uuid(); + const ref = yield window.firebase.database().ref(`/breweries/${uid}`); + yield ref.update({ uid, name: '' }); + yield put({ type: actions.request }); +} + +export default function* watchAddBrewery() { + yield takeLatest(actions.add, addSuccessfull); +} diff --git a/src/api/sagas/brewery/watchBreweries.js b/src/api/sagas/brewery/watchBreweries.js new file mode 100644 index 0000000..d2d25f9 --- /dev/null +++ b/src/api/sagas/brewery/watchBreweries.js @@ -0,0 +1,24 @@ +import { takeLatest, call, put } from 'redux-saga/effects'; +import { actions } from 'api/actions/brewery'; + +const fetchBreweries = (ref) => { + return new Promise((resolve, reject) => { + ref.on('value', data => { + resolve(data.val()) + }); + }); +} + +function* requestSuccessfull() { + try { + const ref = yield window.firebase.database().ref(`/breweries`); + const payload = yield call(fetchBreweries, ref); + yield put({ type: actions.requestSuccess, payload }); + } catch(error) { + console.log("ERRAO DA PORRA", error); + } +} + +export default function* watchBreweries() { + yield takeLatest(actions.request, requestSuccessfull); +} diff --git a/src/api/sagas/brewery/watchEditBrewery.js b/src/api/sagas/brewery/watchEditBrewery.js new file mode 100644 index 0000000..c8cc32d --- /dev/null +++ b/src/api/sagas/brewery/watchEditBrewery.js @@ -0,0 +1,14 @@ +import { takeLatest, put } from 'redux-saga/effects'; +import { fromJS } from 'immutable'; +import { actions } from 'api/actions/brewery'; + +function* editSuccessfull({ payload }) { + const ref = yield window.firebase.database().ref(`/breweries/${payload.get('uid')}`); + yield ref.update(payload.toJS()); + yield put({ type: actions.edit, payload: fromJS({}) }); + yield put({ type: actions.request }); +} + +export default function* watchEditBrewery() { + yield takeLatest(actions.update, editSuccessfull); +} diff --git a/src/api/sagas/brewery/watchRemoveBrewery.js b/src/api/sagas/brewery/watchRemoveBrewery.js new file mode 100644 index 0000000..e392be3 --- /dev/null +++ b/src/api/sagas/brewery/watchRemoveBrewery.js @@ -0,0 +1,14 @@ +import { takeLatest, put } from 'redux-saga/effects'; +import { actions } from 'api/actions/brewery'; + +function* removeSuccessfull({ payload: uid }) { + const ref = yield window.firebase.database().ref(`/breweries/${uid}`); + yield ref.remove(); + yield put({ + type: actions.request + }); +} + +export default function* watchRemoveBrewery() { + yield takeLatest(actions.remove, removeSuccessfull); +} diff --git a/src/api/sagas/index.js b/src/api/sagas/index.js new file mode 100644 index 0000000..9192d0b --- /dev/null +++ b/src/api/sagas/index.js @@ -0,0 +1,31 @@ +import { fork } from 'redux-saga/effects'; + +import watchBreweries from 'api/sagas/brewery/watchBreweries'; +import watchRemoveBrewery from 'api/sagas/brewery/watchRemoveBrewery'; +import watchAddBrewery from 'api/sagas/brewery/watchAddBrewery'; +import watchEditBrewery from 'api/sagas/brewery/watchEditBrewery'; + +import watchBeers from 'api/sagas/beer/watchBeers'; +import watchRemoveBeer from 'api/sagas/beer/watchRemoveBeer'; +import watchAddBeer from 'api/sagas/beer/watchAddBeer'; +import watchEditBeer from 'api/sagas/beer/watchEditBeer'; + +import watchLogin from 'api/sagas/login/watchLogin'; +import watchLogout from 'api/sagas/login/watchLogout'; + +function* rootSaga() { + yield fork(watchBreweries); + yield fork(watchAddBrewery); + yield fork(watchEditBrewery); + yield fork(watchRemoveBrewery); + + yield fork(watchBeers); + yield fork(watchAddBeer); + yield fork(watchRemoveBeer); + yield fork(watchEditBeer); + + yield fork(watchLogin); + yield fork(watchLogout); +} + +export default rootSaga; diff --git a/src/api/sagas/login/watchLogin.js b/src/api/sagas/login/watchLogin.js new file mode 100644 index 0000000..711be3c --- /dev/null +++ b/src/api/sagas/login/watchLogin.js @@ -0,0 +1,14 @@ +import { takeLatest } from 'redux-saga/effects'; +import { actions as authActions } from 'api/actions/auth'; + +function* prepareLogin() { + const authProvider = new window.firebase.auth.GoogleAuthProvider(); + const { user: payload } = yield window.firebase.auth().signInWithPopup(authProvider); + const { displayName, photoURL, email, uid } = payload; + const ref = yield window.firebase.database().ref(`/users/${uid}`); + yield ref.update({ displayName, photoURL, email }); +} + +export default function* watchLogin() { + yield takeLatest(authActions.login, prepareLogin); +} diff --git a/src/api/sagas/login/watchLogout.js b/src/api/sagas/login/watchLogout.js new file mode 100644 index 0000000..a97f65f --- /dev/null +++ b/src/api/sagas/login/watchLogout.js @@ -0,0 +1,12 @@ +import { takeLatest, put } from 'redux-saga/effects'; +import { push } from 'react-router-redux'; +import { actions as authActions } from 'api/actions/auth'; + +function* prepareLogout() { + yield window.firebase.auth().signOut(); + yield put(push('/login')); +} + +export default function* watchLogout() { + yield takeLatest(authActions.logout, prepareLogout); +} diff --git a/src/components/auth/container.js b/src/components/auth/index.js similarity index 100% rename from src/components/auth/container.js rename to src/components/auth/index.js diff --git a/src/components/beer/beer.js b/src/components/beer/beer.js new file mode 100644 index 0000000..c977bfe --- /dev/null +++ b/src/components/beer/beer.js @@ -0,0 +1,57 @@ +import React from 'react'; + +const Beer = ({ beer, edit, remove, update, userId, breweryId }) => { + + const removeBeer = () => { + remove(beer.get('uid'), userId, breweryId); + } + + const updateBeer = () => { + update(beer, userId, breweryId); + } + + const onChange = ({ target: { value, dataset } }) => { + edit( + beer.set(dataset['key'], value), + userId, + breweryId, + ); + } + + const onCheck = ({ target: { checked, dataset } }) => { + edit( + beer.set(dataset['key'], checked) + ); + } + + return ( +
  • +
    + + +
    +
    + + +
    +
    + + +
    +
  • + ); + +} + +export default Beer; diff --git a/src/components/beer/beerShow.js b/src/components/beer/beerShow.js new file mode 100644 index 0000000..e982260 --- /dev/null +++ b/src/components/beer/beerShow.js @@ -0,0 +1,34 @@ +import React from 'react'; + +const Beer = ({ beer, edit, remove, userId, breweryId }) => { + + const removeBeer = () => { + remove(beer.get('uid'), userId, breweryId); + } + + const onClick = () => edit(beer, userId, breweryId); + + const premium = beer.get('premium') ? +
    Especial
    : null; + + return ( +
  • +
    +
    Beer:
    +
    + {beer.get('name')} +
    +
    +
    + {premium} +
    +
    + + +
    +
  • + ); + +} + +export default Beer; diff --git a/src/components/beer/index.js b/src/components/beer/index.js new file mode 100644 index 0000000..0d4e5e3 --- /dev/null +++ b/src/components/beer/index.js @@ -0,0 +1,5 @@ +import { connect } from 'react-redux'; +import { mapStateToProps, mapDispatchToProps } from 'api/actions/beer'; +import List from 'components/beer/list'; + +export default connect(mapStateToProps, mapDispatchToProps)(List); diff --git a/src/components/beer/list.js b/src/components/beer/list.js new file mode 100644 index 0000000..fac6387 --- /dev/null +++ b/src/components/beer/list.js @@ -0,0 +1,72 @@ +import React, { Component } from 'react'; +import Beer from 'components/beer/beer'; +import BeerShow from 'components/beer/beerShow'; + +class List extends Component{ + + componentWillMount() { + this.props.request(this.props.match.params.uid, this.props.match.params.id); + } + + add = () => { + this.props.add(this.props.match.params.uid, this.props.match.params.id); + } + + mappingBeers = () => { + const { beerList, beerEdit, edit, remove, update } = this.props; + const breweryId = this.props.match.params.id; + const userId = this.props.match.params.uid; + + return beerList.map(beer => ( + (beerEdit.get('uid') === beer.get('uid')) ? + : + + )).toList().toJS(); + } + + // + // findBrewery = (breweryId) => { + // const { beerList } = this.props; + // return beerList.toList().toJS().find( + // brew => { + // return brew.uid === breweryId; + // } + // ); + // } + + render() { + const breweryId = this.props.match.params.id; + const userId = this.props.match.params.uid; + //const brewery = this.findBrewery(breweryId); + + const beers = this.mappingBeers(); + console.log() + return ( +
    +
      +

      user id: {userId}

      +

      brewery id: {breweryId}

      + {beers} +
    + +
    + ); + } +} + +export default List; diff --git a/src/components/brewery/beer.js b/src/components/brewery/beer.js deleted file mode 100644 index 891e916..0000000 --- a/src/components/brewery/beer.js +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; - -const Beer = ({ beer, edit }) => { - - const { uid, name, brewery } = beer.toJS(); - - const remove = () => { - // dispatch({ - // type: 'remove', - // payload: uid, - // }) - } - - const onChange = ({ target: { value, dataset } }) => { - edit({ - uid, - [dataset['key']]: value - }); - } - - return ( -
    -
    - - -
    -
    - - -
    -
    - -
    -
    - ); - -} - -export default Beer; diff --git a/src/components/brewery/brewery.js b/src/components/brewery/brewery.js new file mode 100644 index 0000000..7db9ea6 --- /dev/null +++ b/src/components/brewery/brewery.js @@ -0,0 +1,45 @@ +import React from 'react'; + +const Brewery = ({ brewery, edit, remove, update }) => { + + const removeBrewery = () => { + remove(brewery.get('uid')); + } + + const updateBrewery = () => { + update(brewery); + } + + const onChange = ({ target: { value, dataset } }) => { + edit( + brewery.set(dataset['key'], value) + ); + } + + const onCheck = ({ target: { checked, dataset } }) => { + edit( + brewery.set(dataset['key'], checked) + ); + } + + return ( +
  • +
    + + +
    +
    + + +
    +
  • + ); + +} + +export default Brewery; diff --git a/src/components/brewery/breweryShow.js b/src/components/brewery/breweryShow.js new file mode 100644 index 0000000..e1a6a1c --- /dev/null +++ b/src/components/brewery/breweryShow.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { Link } from 'react-router-dom' + +const Brewery = ({ brewery, edit, remove, user }) => { + const removeBrewery = () => remove(brewery.get('uid')); + const onClick = () => edit(brewery); + // + // const premium = brewery.get('premium') ? + //
    Especial
    : null; + + return ( +
  • +
    +
    Brewery:
    + + {brewery.get('name')} + +
    +
    + + +
    +
  • + ); + +} + +export default Brewery; diff --git a/src/components/brewery/index.js b/src/components/brewery/index.js new file mode 100644 index 0000000..8a34fb5 --- /dev/null +++ b/src/components/brewery/index.js @@ -0,0 +1,5 @@ +import { connect } from 'react-redux'; +import { mapStateToProps, mapDispatchToProps } from 'api/actions/brewery'; +import List from 'components/brewery/list'; + +export default connect(mapStateToProps, mapDispatchToProps)(List); diff --git a/src/components/brewery/list.js b/src/components/brewery/list.js index c240da1..d6e2f04 100644 --- a/src/components/brewery/list.js +++ b/src/components/brewery/list.js @@ -1,8 +1,6 @@ import React, { Component } from 'react'; -import uuid from 'uuid'; -import { connect } from 'react-redux'; -import { mapStateToProps, mapDispatchToProps } from 'api/actions/brewery'; -import Beer from 'components/brewery/beer'; +import Brewery from 'components/brewery/brewery'; +import BreweryShow from 'components/brewery/breweryShow'; class List extends Component { @@ -14,25 +12,38 @@ class List extends Component { this.props.request(); } - render() { - const { list, edit } = this.props; - const beers = list.map(beer => ( - { + const { list, breweryEdit, edit, remove, update, user } = this.props; + return list.map(brewery => ( + (breweryEdit.get('uid') === brewery.get('uid')) ? + : + - )); + )).toList().toJS(); + } + render() { + const brewery = this.mappingBreweries(); return ( -
    -
    {beers}
    +
    +
      + {brewery} +
    ); } } -export default connect( - mapStateToProps, mapDispatchToProps -)(List); +export default List; diff --git a/src/components/home/home.js b/src/components/home/home.js index 76e9c2f..c8d4784 100644 --- a/src/components/home/home.js +++ b/src/components/home/home.js @@ -1,11 +1,11 @@ import React from 'react'; -import Toolbar from 'components/home/toolbar'; -import Brewery from 'components/brewery/list'; +import Toolbar from 'components/home/toolbar/index.js'; +import Brewery from 'components/brewery'; class Home extends React.Component { render() { return ( -
    +
    diff --git a/src/components/home/container.js b/src/components/home/index.js similarity index 51% rename from src/components/home/container.js rename to src/components/home/index.js index 30d4d36..3be467a 100644 --- a/src/components/home/container.js +++ b/src/components/home/index.js @@ -4,18 +4,18 @@ import { connect } from 'react-redux'; import { mapStateToProps, mapDispatchToProps } from 'api/actions/auth'; import Home from 'components/home/home'; -class Container extends React.Component { +class Container extends React.Component{ - componentWillMount() { - const { user, redirectToLogin } = this.props; - redirectToLogin(user.uid); - } + componentWillMount(){ + const { user, redirectToLogin } = this.props; + redirectToLogin(user.uid); + } - render() { - return - } + render(){ + return + } } export default withRouter( - connect(mapStateToProps, mapDispatchToProps)(Container) + connect(mapStateToProps, mapDispatchToProps)(Container) ); diff --git a/src/components/home/toolbar.js b/src/components/home/toolbar.js deleted file mode 100644 index 36fd310..0000000 --- a/src/components/home/toolbar.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; - -const Toolbar = ({ count, user: { uid } }) => ( -
    - { - uid ? `Count: ${count}`: '' - } -
    -); - -export default connect(state => { - return { - count: 0, - // state.list.reduce( - // (count, item) => { - // if (item.premium) { - // return count + 1; - // } - // return count; - // }, - // 0 - // ), - user: state.user, - } -})(Toolbar); diff --git a/src/components/home/toolbar/index.js b/src/components/home/toolbar/index.js new file mode 100644 index 0000000..5312677 --- /dev/null +++ b/src/components/home/toolbar/index.js @@ -0,0 +1,20 @@ +import { connect } from 'react-redux'; +import Toolbar from 'components/home/toolbar/toolbar'; +import { mapDispatchToProps } from 'api/actions/auth'; + +function mapStateToProps(state){ + return { + count: state.list.reduce( + (count, item) => { + if (item.premium) { + return count + 1; + } + return count; + }, + 0 + ), + user: state.user, + } +}; + +export default connect(mapStateToProps, mapDispatchToProps)(Toolbar); diff --git a/src/components/home/toolbar/toolbar.js b/src/components/home/toolbar/toolbar.js new file mode 100644 index 0000000..09f9479 --- /dev/null +++ b/src/components/home/toolbar/toolbar.js @@ -0,0 +1,27 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const Toolbar = ({ count, user: { uid }, onLogout }) => ( +
    +
    +
    +
    + { + uid ? `Count: ${count}`: '' + } +
    +
    +
    + exit_to_app +
    +
    +
    +); + +Toolbar.propTypes = { + onLogout: PropTypes.func.isRequired, + count: PropTypes.number.isRequired, + user: PropTypes.object.isRequired, +} + +export default Toolbar; diff --git a/src/css/brewery.css b/src/css/brewery.css new file mode 100644 index 0000000..ca8ee95 --- /dev/null +++ b/src/css/brewery.css @@ -0,0 +1,4 @@ +.Brewery { + position: absolute; + top: 64px; +} diff --git a/src/index.js b/src/index.js index 53c7688..4594cd8 100644 --- a/src/index.js +++ b/src/index.js @@ -2,7 +2,9 @@ import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import registerServiceWorker from './registerServiceWorker'; +import 'material-components-web/dist/material-components-web.css'; import './index.css'; +import './css/brewery.css'; ReactDOM.render(, document.getElementById('root')); registerServiceWorker(); diff --git a/src/milflux/connect.js b/src/milflux/connect.js deleted file mode 100644 index cf473bf..0000000 --- a/src/milflux/connect.js +++ /dev/null @@ -1,38 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; - -class Wrapper extends Component { - - static contextTypes = { - state: PropTypes.object, - dispatch: PropTypes.func, - } - - render() { - const { state, dispatch } = this.context; - const { component, defaultProps, mapping } = this.props; - - const mapped = (mapping) ? mapping(state) : {}; - const props = { - ...mapped, - dispatch, - ...defaultProps, - }; - return React.createElement( - component, - props - ); - } -} - -const connect = (component, mapping) => { - return (props) => ( - - ); -} - -export default connect; diff --git a/src/milflux/store.js b/src/milflux/store.js deleted file mode 100644 index b0133c5..0000000 --- a/src/milflux/store.js +++ /dev/null @@ -1,142 +0,0 @@ -import React from 'react'; -import uuid from 'uuid'; -import PropTypes from 'prop-types'; -import firebase from 'firebase'; - -class Store extends React.Component { - - static childContextTypes = { - state: PropTypes.object, - dispatch: PropTypes.func, - } - - state = { - list: [], - user: {}, - } - - getChildContext() { - return { - state: this.state, - dispatch: this.dispatch, - }; - } - - dispatch = action => { - - if (action.type === 'load') { - this.load(action.payload); - } - - if (action.type === 'add') { - this.add(); - } - - if (action.type === 'remove') { - this.remove(action.payload); - } - - if (action.type === 'edit') { - this.edit(action.payload); - } - - if (action.type === 'login') { - this.login(); - } - - } - - componentWillMount() { - const config = { - apiKey: "AIzaSyDGYMxpnYaAJYyquEUM6Y__yQjhPP_skx0", - authDomain: "feedback-140018.firebaseapp.com", - databaseURL: "https://feedback-140018.firebaseio.com", - projectId: "feedback-140018", - storageBucket: "feedback-140018.appspot.com", - messagingSenderId: "71457068040" - }; - firebase.initializeApp(config); - window.firebase = firebase; - } - - login = () => { - const authProvider = new firebase.auth.GoogleAuthProvider(); - firebase.auth() - .signInWithPopup(authProvider) - .then((payload) => { - this.addFirebaseUser(payload.user); - }); - } - - addFirebaseUser = user => { - const { displayName, photoURL, email, uid } = user; - const ref = firebase.database().ref(`/users/${uid}`); - ref.update({ - displayName, - photoURL, - email, - list: this.state.list, - }).then(() => { - this.setState({ - ...this.state, - user, - }) - }); - }; - - load = (list) => { - this.setState({ - ...this.state, - list, - }); - } - - remove = (uid) => { - this.setState({ - ...this.state, - list: this.state.list.reduce( - (newList, item) => { - if (item.uid !== uid) { - newList.push(item); - } - return newList; - }, - [] - ), - }); - } - - add = () => { - const newList = this.state.list; - newList.push({ name: '', uid: uuid() }); - this.setState({ - ...this.state, - list: newList, - }); - } - - edit = ({ target: { dataset, name, value } }) => { - const { list } = this.state; - this.setState({ - ...this.state, - list: list.map(item => { - if (item.uid === name) { - item.premium = (value === 'Baden'); - if (dataset['name'] === 'brewery') { - item.brewery = value; - } - if (dataset['name'] === 'name') { - item.name = value; - } - } - return item; - }), - }); - } - - render () { - return this.props.children; - } -} - -export default Store; diff --git a/yarn.lock b/yarn.lock index 7a3e786..613a71c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,247 @@ # yarn lockfile v1 +"@material/animation@^0.2.2", "@material/animation@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@material/animation/-/animation-0.2.3.tgz#25f24962cd649e76459a16ab234b7846a7a7f419" + +"@material/auto-init@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@material/auto-init/-/auto-init-0.1.2.tgz#a6d5f88efff08c087e53f55c2cdfbb22ce6f4901" + +"@material/base@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@material/base/-/base-0.2.0.tgz#685e2c344aa037e42be7978e1f365ff183b9f3a1" + +"@material/button@^0.3.7": + version "0.3.7" + resolved "https://registry.yarnpkg.com/@material/button/-/button-0.3.7.tgz#3912791322f7f7129a5a2239c3098e8b10a4ceb8" + dependencies: + "@material/animation" "^0.2.3" + "@material/elevation" "^0.1.8" + "@material/ripple" "^0.6.2" + "@material/theme" "^0.1.5" + "@material/typography" "^0.2.2" + +"@material/card@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@material/card/-/card-0.2.3.tgz#15524aeafe22d5911d8836f8d3013ded828751f0" + dependencies: + "@material/elevation" "^0.1.8" + "@material/rtl" "^0.1.5" + "@material/theme" "^0.1.5" + "@material/typography" "^0.2.2" + +"@material/checkbox@^0.3.6": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@material/checkbox/-/checkbox-0.3.6.tgz#4f38b8f4a1f444bc7b86b7f5abfb3ecb0a23e44c" + dependencies: + "@material/animation" "^0.2.3" + "@material/base" "^0.2.0" + "@material/ripple" "^0.6.2" + "@material/rtl" "^0.1.5" + "@material/theme" "^0.1.5" + +"@material/dialog@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@material/dialog/-/dialog-0.3.1.tgz#dd81736fba86f61ef73c9dd3bac6982c4d3f1e4f" + dependencies: + "@material/animation" "^0.2.3" + "@material/base" "^0.2.0" + "@material/elevation" "^0.1.8" + "@material/ripple" "^0.6.2" + "@material/rtl" "^0.1.5" + "@material/theme" "^0.1.5" + "@material/typography" "^0.1.1" + focus-trap "^2.3.0" + +"@material/drawer@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@material/drawer/-/drawer-0.5.0.tgz#1aea6d15e9d2bc9a7cdda97cccede1a0ef9fbed8" + dependencies: + "@material/animation" "^0.2.3" + "@material/base" "^0.2.0" + "@material/elevation" "^0.1.8" + "@material/rtl" "^0.1.5" + "@material/theme" "^0.1.5" + "@material/typography" "^0.2.2" + +"@material/elevation@^0.1.8": + version "0.1.8" + resolved "https://registry.yarnpkg.com/@material/elevation/-/elevation-0.1.8.tgz#57a1f3541a330d035633db7f5db82c462d0ccad0" + dependencies: + "@material/animation" "^0.2.3" + +"@material/fab@^0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@material/fab/-/fab-0.3.9.tgz#4817c768ed55654f5fcedc477b2b285ce8facd02" + dependencies: + "@material/animation" "^0.2.3" + "@material/elevation" "^0.1.8" + "@material/ripple" "^0.6.2" + "@material/theme" "^0.1.5" + +"@material/form-field@^0.2.7": + version "0.2.7" + resolved "https://registry.yarnpkg.com/@material/form-field/-/form-field-0.2.7.tgz#034f7d8e4217240a52c2869edcacf24306551891" + dependencies: + "@material/base" "^0.2.0" + "@material/rtl" "^0.1.5" + "@material/theme" "^0.1.5" + "@material/typography" "^0.2.2" + +"@material/grid-list@^0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@material/grid-list/-/grid-list-0.2.4.tgz#c8bb519788773d0d14bef463c26b103a3e46f34f" + dependencies: + "@material/base" "^0.2.0" + "@material/rtl" "^0.1.5" + "@material/theme" "^0.1.5" + "@material/typography" "^0.2.2" + +"@material/icon-toggle@^0.1.12": + version "0.1.12" + resolved "https://registry.yarnpkg.com/@material/icon-toggle/-/icon-toggle-0.1.12.tgz#e7076cd0f7071fbcd2060fe3d4e774ecbba01d9c" + dependencies: + "@material/animation" "^0.2.3" + "@material/base" "^0.2.0" + "@material/ripple" "^0.6.2" + "@material/theme" "^0.1.5" + +"@material/layout-grid@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@material/layout-grid/-/layout-grid-0.2.0.tgz#5e84735747219649099b3bced4788d3487812ff9" + +"@material/linear-progress@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@material/linear-progress/-/linear-progress-0.1.2.tgz#6ccb0ee9cd2305b7245f4ebd189e58a311ce630b" + dependencies: + "@material/animation" "^0.2.3" + "@material/base" "^0.2.0" + "@material/theme" "^0.1.5" + +"@material/list@^0.2.10": + version "0.2.10" + resolved "https://registry.yarnpkg.com/@material/list/-/list-0.2.10.tgz#ba27cf9b14b321a8428818a44f736f28453700de" + dependencies: + "@material/ripple" "^0.6.2" + "@material/rtl" "^0.1.5" + "@material/theme" "^0.1.5" + "@material/typography" "^0.2.2" + +"@material/menu@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@material/menu/-/menu-0.3.0.tgz#49f32c384987e02e4c9a0d19105e27613bf4332f" + dependencies: + "@material/animation" "^0.2.3" + "@material/base" "^0.2.0" + "@material/elevation" "^0.1.8" + "@material/theme" "^0.1.5" + "@material/typography" "^0.2.2" + +"@material/radio@^0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@material/radio/-/radio-0.2.5.tgz#fc9fe47f222e519ce6916c8fe19c7d62ea9dcbea" + dependencies: + "@material/animation" "^0.2.3" + "@material/base" "^0.2.0" + "@material/ripple" "^0.6.2" + "@material/theme" "^0.1.5" + +"@material/ripple@^0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@material/ripple/-/ripple-0.6.2.tgz#a8556db7c141d35f5582c5990be8690bef9dee59" + dependencies: + "@material/base" "^0.2.0" + "@material/theme" "^0.1.5" + +"@material/rtl@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@material/rtl/-/rtl-0.1.5.tgz#062b88eac42e925d5b052e04925121505e62ff44" + +"@material/select@^0.3.8": + version "0.3.8" + resolved "https://registry.yarnpkg.com/@material/select/-/select-0.3.8.tgz#0607af02703ca3693f6a10238a8c9aea48cb4cb4" + dependencies: + "@material/animation" "^0.2.3" + "@material/base" "^0.2.0" + "@material/list" "^0.2.10" + "@material/menu" "^0.3.0" + "@material/rtl" "^0.1.5" + "@material/theme" "^0.1.5" + "@material/typography" "^0.2.2" + +"@material/slider@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@material/slider/-/slider-0.1.0.tgz#dd1df402ca2072c5a8f336ab050453e840e2b21a" + dependencies: + "@material/animation" "^0.2.2" + "@material/base" "^0.2.0" + "@material/rtl" "^0.1.5" + "@material/theme" "^0.1.5" + +"@material/snackbar@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@material/snackbar/-/snackbar-0.2.1.tgz#cafe6c3090364e19ab8911c1405205aeb1528e62" + dependencies: + "@material/animation" "^0.2.3" + "@material/base" "^0.2.0" + "@material/button" "^0.3.7" + "@material/rtl" "^0.1.5" + "@material/theme" "^0.1.5" + "@material/typography" "^0.2.2" + +"@material/switch@^0.1.8": + version "0.1.8" + resolved "https://registry.yarnpkg.com/@material/switch/-/switch-0.1.8.tgz#e36c01a6a59959f2ac43e361bc1bf65a2efb445c" + dependencies: + "@material/animation" "^0.2.3" + "@material/elevation" "^0.1.8" + "@material/theme" "^0.1.5" + +"@material/tabs@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@material/tabs/-/tabs-0.2.1.tgz#b11e148f00301732f90df9845e839fae1bea2c59" + dependencies: + "@material/animation" "^0.2.3" + "@material/base" "^0.2.0" + "@material/ripple" "^0.6.2" + "@material/rtl" "^0.1.5" + "@material/theme" "^0.1.5" + "@material/typography" "^0.2.2" + +"@material/textfield@^0.2.11": + version "0.2.11" + resolved "https://registry.yarnpkg.com/@material/textfield/-/textfield-0.2.11.tgz#21cf12115dbb39bae9f618de12b4c90cdab7ff54" + dependencies: + "@material/animation" "^0.2.3" + "@material/base" "^0.2.0" + "@material/rtl" "^0.1.5" + "@material/theme" "^0.1.5" + "@material/typography" "^0.2.2" + +"@material/theme@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@material/theme/-/theme-0.1.5.tgz#5c7bd9a1974d8c1c0eacf037e0235aad9c5cb699" + +"@material/toolbar@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@material/toolbar/-/toolbar-0.4.0.tgz#b6e3764b2d81adecb74c708ed378be33c5f9ed23" + dependencies: + "@material/base" "^0.2.0" + "@material/elevation" "^0.1.8" + "@material/rtl" "^0.1.5" + "@material/theme" "^0.1.5" + "@material/typography" "^0.2.2" + +"@material/typography@^0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@material/typography/-/typography-0.1.1.tgz#fb2e3437bd3284d39e9fb91485767ade6b2bd0c1" + +"@material/typography@^0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@material/typography/-/typography-0.2.2.tgz#dc5f0763ad7d6e5ad5c86c394b360f2b4cf30bb2" + "@timer/detect-port@1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@timer/detect-port/-/detect-port-1.1.3.tgz#1383abd67f9a5d683df5276f8a92d60bdf9abb90" @@ -9,10 +250,6 @@ address "^1.0.1" debug "^2.6.0" -D@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/D/-/D-0.0.1.tgz#292f54dbd43f36e4853f6a09e77617c23c46228b" - abab@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d" @@ -2494,6 +2731,12 @@ flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" +focus-trap@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-2.3.0.tgz#07c91964867d346315f4f5f8df88bf96455316e2" + dependencies: + tabbable "^1.0.3" + for-in@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -3867,6 +4110,39 @@ map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" +material-components-web@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/material-components-web/-/material-components-web-0.13.0.tgz#e18a2a510e07be102ca89c3b389746fe3e024dab" + dependencies: + "@material/animation" "^0.2.3" + "@material/auto-init" "^0.1.2" + "@material/base" "^0.2.0" + "@material/button" "^0.3.7" + "@material/card" "^0.2.3" + "@material/checkbox" "^0.3.6" + "@material/dialog" "^0.3.1" + "@material/drawer" "^0.5.0" + "@material/elevation" "^0.1.8" + "@material/fab" "^0.3.9" + "@material/form-field" "^0.2.7" + "@material/grid-list" "^0.2.4" + "@material/icon-toggle" "^0.1.12" + "@material/layout-grid" "^0.2.0" + "@material/linear-progress" "^0.1.2" + "@material/list" "^0.2.10" + "@material/menu" "^0.3.0" + "@material/radio" "^0.2.5" + "@material/ripple" "^0.6.2" + "@material/select" "^0.3.8" + "@material/slider" "^0.1.0" + "@material/snackbar" "^0.2.1" + "@material/switch" "^0.1.8" + "@material/tabs" "^0.2.1" + "@material/textfield" "^0.2.11" + "@material/theme" "^0.1.5" + "@material/toolbar" "^0.4.0" + "@material/typography" "^0.2.2" + math-expression-evaluator@^1.2.14: version "1.2.17" resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac" @@ -5112,6 +5388,10 @@ redux-devtools-extension@^2.13.2: version "2.13.2" resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.2.tgz#e0f9a8e8dfca7c17be92c7124958a3b94eb2911d" +redux-saga@^0.15.3: + version "0.15.3" + resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-0.15.3.tgz#be2b86b4ad46bf0d84fcfcb0ca96cfc33db91acb" + redux@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/redux/-/redux-3.6.0.tgz#887c2b3d0b9bd86eca2be70571c27654c19e188d" @@ -5764,6 +6044,10 @@ symbol-tree@^3.2.1: version "3.2.2" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" +tabbable@^1.0.3: + version "1.0.6" + resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-1.0.6.tgz#7c26a87ea6f4a25edf5edb619745a0ae740724fc" + table@^3.7.8: version "3.8.3" resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f"