diff --git a/package.json b/package.json
index 4488cb3..5684e00 100644
--- a/package.json
+++ b/package.json
@@ -2,12 +2,18 @@
"name": "swppfront",
"version": "0.1.0",
"private": true,
+ "proxy": "http://localhost:8000",
"dependencies": {
+ "axios": "^0.19.0",
+ "connected-react-router": "^6.5.2",
"react": "^16.9.0",
"react-dom": "^16.9.0",
+ "react-redux": "^7.1.1",
"react-router": "^5.0.1",
"react-router-dom": "^5.0.1",
- "react-scripts": "3.1.1"
+ "react-scripts": "3.1.1",
+ "redux": "^4.0.4",
+ "redux-thunk": "^2.3.0"
},
"scripts": {
"start": "react-scripts start",
diff --git a/redux-basics.js b/redux-basics.js
new file mode 100644
index 0000000..bbb1bc3
--- /dev/null
+++ b/redux-basics.js
@@ -0,0 +1,23 @@
+const redux = require('redux');
+const createStore = redux.createStore;
+
+const initialState = { number: 0 };
+const reducer = (state = initialState, action) => {
+ if (action.type == 'ADD') {
+ return ({ ...state, number: state.number + 1 });
+ } else if (action.type == 'ADD_VALUE') {
+ return ({ ...state, number: state.number + action.value });
+ } else {
+ return state;
+ }
+}
+
+const store = createStore(reducer);
+console.log(store.getState());
+
+store.subscribe(() => {
+ console.log('[Subscription]', store.getState());
+});
+
+store.dispatch({ type: 'ADD' });
+store.dispatch({ type: 'ADD_VALUE', value: 5 });
\ No newline at end of file
diff --git a/src/App.js b/src/App.js
index 610cd4b..a6e850e 100644
--- a/src/App.js
+++ b/src/App.js
@@ -5,11 +5,12 @@ import TodoList from './containers/TodoList/TodoList';
import RealDetail from './containers/TodoList/RealDetail/RealDetail';
import NewTodo from './containers/TodoList/NewTodo/NewTodo';
-import { BrowserRouter, Route, Redirect, Switch } from 'react-router-dom';
+import { Route, Redirect, Switch } from 'react-router-dom';
+import { ConnectedRouter } from 'connected-react-router';
-function App() {
+function App(props) {
return (
-
+
} />
@@ -19,7 +20,7 @@ function App() {
Not Found
} />
-
+
);
}
diff --git a/src/components/Todo/Todo.js b/src/components/Todo/Todo.js
index 9c80927..d1adba6 100644
--- a/src/components/Todo/Todo.js
+++ b/src/components/Todo/Todo.js
@@ -8,10 +8,12 @@ const Todo = (props) => {
+ onClick={props.clickDetail}>
{props.title}
{props.done &&
✓
}
+
+
);
};
diff --git a/src/containers/TodoList/NewTodo/NewTodo.js b/src/containers/TodoList/NewTodo/NewTodo.js
index 59e7930..536cd50 100644
--- a/src/containers/TodoList/NewTodo/NewTodo.js
+++ b/src/containers/TodoList/NewTodo/NewTodo.js
@@ -1,30 +1,22 @@
import React, { Component } from 'react';
-import { Redirect } from 'react-router-dom';
import './NewTodo.css';
+import { connect } from 'react-redux';
+import * as actionCreators from '../../../store/actions/index';
+
class NewTodo extends Component {
state = {
title: '',
content: '',
- submitted: false
}
postTodoHandler = () => {
- const data =
- { title: this.state.title, content: this.state.content }
- alert('submitted' + data.title);
- // this.props.history.push('/todos');
- this.props.history.goBack();
- this.setState({ submitted: true });
+ this.props.onStoreTodo(this.state.title, this.state.content);
}
render() {
- let redirect = null;
- if (this.state.submitted) {
- redirect =
- }
return (
Add a New Todo!
@@ -36,7 +28,7 @@ class NewTodo extends Component {
>
@@ -45,4 +37,11 @@ class NewTodo extends Component {
}
}
-export default NewTodo;
\ No newline at end of file
+const mapDispatchToProps = dispatch => {
+ return {
+ onStoreTodo: (title, content) =>
+ dispatch(actionCreators.postTodo({ title: title, content: content })),
+ }
+};
+
+export default connect(null, mapDispatchToProps)(NewTodo);
\ No newline at end of file
diff --git a/src/containers/TodoList/RealDetail/RealDetail.js b/src/containers/TodoList/RealDetail/RealDetail.js
index 89500a3..a9d888e 100644
--- a/src/containers/TodoList/RealDetail/RealDetail.js
+++ b/src/containers/TodoList/RealDetail/RealDetail.js
@@ -2,8 +2,22 @@ import React, { Component } from 'react';
import './RealDetail.css';
+import { connect } from 'react-redux';
+import * as actionCreators from '../../../store/actions/index';
+
class RealDetail extends Component {
+
+ componentDidMount() {
+ this.props.onGetTodo(this.props.match.params.id);
+ }
+
render() {
+ let title = '';
+ let content = '';
+ if (this.props.selectedTodo) {
+ title = this.props.selectedTodo.title;
+ content = this.props.selectedTodo.content;
+ }
return (
@@ -11,6 +25,7 @@ class RealDetail extends Component {
Name:
+ {title}
@@ -18,6 +33,7 @@ class RealDetail extends Component {
Content:
+ {content}
@@ -25,4 +41,17 @@ class RealDetail extends Component {
}
};
-export default RealDetail;
\ No newline at end of file
+const mapStateToProps = state => {
+ return {
+ selectedTodo: state.td.selectedTodo,
+ };
+};
+
+const mapDispatchToProps = dispatch => {
+ return {
+ onGetTodo: id =>
+ dispatch(actionCreators.getTodo(id)),
+ }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(RealDetail);
\ No newline at end of file
diff --git a/src/containers/TodoList/TodoList.js b/src/containers/TodoList/TodoList.js
index 6cb72c1..e53fae3 100644
--- a/src/containers/TodoList/TodoList.js
+++ b/src/containers/TodoList/TodoList.js
@@ -1,62 +1,66 @@
import React, { Component } from 'react';
import Todo from '../../components/Todo/Todo';
-import TodoDetail from '../../components/TodoDetail/TodoDetail';
import { NavLink } from 'react-router-dom';
import './TodoList.css';
+import { connect } from 'react-redux';
+import { withRouter } from 'react-router';
+
+import * as actionCreators from '../../store/actions/index';
+
class TodoList extends Component {
- state = {
- todos: [
- { id: 1, title: 'SWPP', content: 'take swpp class', done: true },
- { id: 2, title: 'Movie', content: 'watch movie', done: false },
- { id: 3, title: 'Dinner', content: 'eat dinner', done: false }
- ],
- selectedTodo: null,
+ componentDidMount() {
+ this.props.onGetAll();
}
clickTodoHandler = (td) => {
- if (this.state.selectedTodo === td) {
- this.setState({ ...this.state, selectedTodo: null });
- } else {
- this.setState({ ...this.state, selectedTodo: td });
- }
+ this.props.history.push('/todos/' + td.id);
}
render() {
- const todos = this.state.todos.map(td => {
+ const todos = this.props.storedTodos.map(td => {
return (
this.clickTodoHandler(td)}
+ clickDetail={() => this.clickTodoHandler(td)}
+ clickDone={() => this.props.onToggleTodo(td.id)}
+ clickDelete={() => this.props.onDeleteTodo(td.id)}
/>
);
});
- let todo = null;
- if (this.state.selectedTodo) {
- todo =
- }
return (
{this.props.title}
-
- {todos}
-
- {todo}
+ {todos}
New Todo
)
}
}
-export default TodoList;
\ No newline at end of file
+const mapStateToProps = state => {
+ return {
+ storedTodos: state.td.todos,
+ };
+}
+
+const mapDispatchToProps = dispatch => {
+ return {
+ onToggleTodo: (id) =>
+ dispatch(actionCreators.toggleTodo(id)),
+ onDeleteTodo: (id) =>
+ dispatch(actionCreators.deleteTodo(id)),
+ onGetAll: () =>
+ dispatch(actionCreators.getTodos())
+ }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(withRouter(TodoList));
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 87d1be5..4a5b06c 100644
--- a/src/index.js
+++ b/src/index.js
@@ -4,7 +4,43 @@ import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
-ReactDOM.render(, document.getElementById('root'));
+import { Provider } from 'react-redux';
+
+import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
+import thunk from 'redux-thunk';
+
+import { connectRouter, routerMiddleware } from 'connected-react-router';
+import { createBrowserHistory } from 'history';
+
+import todoReducer from './store/reducers/todo';
+
+const history = createBrowserHistory();
+const rootReducer = combineReducers({
+ td: todoReducer,
+ router: connectRouter(history),
+});
+
+const logger = store => {
+ return next => {
+ return action => {
+ console.log('[Middleware] Dispatching', action);
+ const result = next(action);
+ console.log('[Middleware] Next State', store.getState());
+ return result;
+ };
+ };
+};
+
+const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
+const store = createStore(rootReducer,
+ composeEnhancers(
+ applyMiddleware(logger, thunk, routerMiddleware(history))));
+
+ReactDOM.render(
+
+
+ ,
+ document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
diff --git a/src/store/actions/actionTypes.js b/src/store/actions/actionTypes.js
new file mode 100644
index 0000000..eef36b5
--- /dev/null
+++ b/src/store/actions/actionTypes.js
@@ -0,0 +1,5 @@
+export const GET_ALL = 'GET_ALL';
+export const ADD_TODO = 'ADD_TODO';
+export const GET_TODO = 'GET_TODO';
+export const TOGGLE_DONE = 'TOGGLE_DONE';
+export const DELETE_TODO = 'DELETE_TODO';
\ No newline at end of file
diff --git a/src/store/actions/index.js b/src/store/actions/index.js
new file mode 100644
index 0000000..bd04f97
--- /dev/null
+++ b/src/store/actions/index.js
@@ -0,0 +1,7 @@
+export {
+ getTodos,
+ postTodo,
+ deleteTodo,
+ toggleTodo,
+ getTodo
+} from './todo';
\ No newline at end of file
diff --git a/src/store/actions/todo.js b/src/store/actions/todo.js
new file mode 100644
index 0000000..191fb88
--- /dev/null
+++ b/src/store/actions/todo.js
@@ -0,0 +1,75 @@
+import * as actionTypes from './actionTypes';
+import axios from 'axios';
+
+import { push } from 'connected-react-router';
+
+export const getTodos_ = (todos) => {
+ return { type: actionTypes.GET_ALL, todos: todos };
+};
+
+export const getTodos = () => {
+ return dispatch => {
+ return axios.get('/api/todo')
+ .then(res => dispatch(getTodos_(res.data)));
+ };
+};
+
+export const getTodo_ = (todo) => {
+ return { type: actionTypes.GET_TODO, target: todo };
+};
+
+export const getTodo = (id) => {
+ return dispatch => {
+ return axios.get('/api/todo/' + id)
+ .then(res => {
+ dispatch(getTodo_(res.data))
+ });
+ };
+};
+
+export const postTodo_ = (td) => {
+ return {
+ type: actionTypes.ADD_TODO,
+ id: td.id,
+ title: td.title,
+ content: td.content,
+ };
+};
+
+export const postTodo = (td) => {
+ return (dispatch) => {
+ return axios.post('/api/todo/', td)
+ .then(res => {
+ dispatch(postTodo_(res.data));
+ dispatch(push('/todos/'));
+ });
+ };
+};
+
+export const deleteTodo_ = (id) => {
+ return {
+ type: actionTypes.DELETE_TODO,
+ targetID: id
+ };
+};
+
+export const deleteTodo = (id) => {
+ return dispatch => {
+ return axios.delete('/api/todo/' + id)
+ .then(res => dispatch(deleteTodo_(id)));
+ };
+};
+
+export const toggleTodo_ = (id) => {
+ return {
+ type: actionTypes.TOGGLE_DONE,
+ targetID: id
+ };
+};
+
+export const toggleTodo = (id) => {
+ return dispatch => {
+ return axios.put('/api/todo/' + id)
+ .then(res => dispatch(toggleTodo_(id)));
+ };
+};
diff --git a/src/store/reducers/todo.js b/src/store/reducers/todo.js
new file mode 100644
index 0000000..9c048d5
--- /dev/null
+++ b/src/store/reducers/todo.js
@@ -0,0 +1,43 @@
+import * as actionTypes from '../actions/actionTypes';
+
+const initialState = {
+ todos: [
+ ],
+ selectedTodo: null,
+};
+
+const reducer = (state = initialState, action) => {
+ switch (action.type) {
+ case actionTypes.ADD_TODO:
+ const newTodo = {
+ id: action.id,
+ title: action.title,
+ content: action.content,
+ done: action.done,
+ };
+ return { ...state, todos: state.todos.concat(newTodo) };
+ case actionTypes.DELETE_TODO:
+ const deletedTodos = state.todos.filter((todo) => {
+ return todo.id !== action.targetID;
+ });
+ return { ...state, todos: deletedTodos };
+ case actionTypes.TOGGLE_DONE:
+ const modified = state.todos.map((todo) => {
+ if (todo.id === action.targetID) {
+ return { ...todo, done: !todo.done };
+ } else {
+ return { ...todo };
+ }
+ });
+ return { ...state, todos: modified };
+ case actionTypes.GET_TODO:
+ return { ...state, selectedTodo: action.target };
+ case actionTypes.GET_ALL:
+ return { ...state, todos: action.todos };
+ default:
+ break;
+ }
+ return state;
+};
+
+export default reducer;
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 54cccc1..5c8ca6c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -770,6 +770,13 @@
dependencies:
regenerator-runtime "^0.13.2"
+"@babel/runtime@^7.5.5":
+ version "7.6.2"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.2.tgz#c3d6e41b304ef10dcf13777a33e7694ec4a9a6dd"
+ integrity sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg==
+ dependencies:
+ regenerator-runtime "^0.13.2"
+
"@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237"
@@ -1748,6 +1755,14 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
+axios@^0.19.0:
+ version "0.19.0"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8"
+ integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==
+ dependencies:
+ follow-redirects "1.5.10"
+ is-buffer "^2.0.2"
+
axobject-query@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9"
@@ -2551,6 +2566,15 @@ connect-history-api-fallback@^1.3.0:
resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc"
integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==
+connected-react-router@^6.5.2:
+ version "6.5.2"
+ resolved "https://registry.yarnpkg.com/connected-react-router/-/connected-react-router-6.5.2.tgz#422af70f86cb276681e20ab4295cf27dd9b6c7e3"
+ integrity sha512-qzsLPZCofSI80fwy+HgxtEgSGS4ndYUUZAWaw1dqaOGPLKX/FVwIOEb7q+hjHdnZ4v5pKZcNv5GG4urjujIoyA==
+ dependencies:
+ immutable "^3.8.1"
+ prop-types "^15.7.2"
+ seamless-immutable "^7.1.3"
+
console-browserify@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
@@ -2977,6 +3001,13 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.
dependencies:
ms "2.0.0"
+debug@=3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
+ integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
+ dependencies:
+ ms "2.0.0"
+
debug@^3.2.5, debug@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
@@ -3998,6 +4029,13 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
+follow-redirects@1.5.10:
+ version "1.5.10"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
+ integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
+ dependencies:
+ debug "=3.1.0"
+
follow-redirects@^1.0.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76"
@@ -4422,7 +4460,7 @@ hmac-drbg@^1.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
-hoist-non-react-statics@^3.1.0:
+hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b"
integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==
@@ -4641,6 +4679,11 @@ immer@1.10.0:
resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d"
integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==
+immutable@^3.8.1:
+ version "3.8.2"
+ resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3"
+ integrity sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=
+
import-cwd@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
@@ -4841,6 +4884,11 @@ is-buffer@^1.0.2, is-buffer@^1.1.5:
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
+is-buffer@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725"
+ integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==
+
is-callable@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
@@ -7939,11 +7987,23 @@ react-error-overlay@^6.0.1:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.1.tgz#b8d3cf9bb991c02883225c48044cb3ee20413e0f"
integrity sha512-V9yoTr6MeZXPPd4nV/05eCBvGH9cGzc52FN8fs0O0TVQ3HYYf1n7EgZVtHbldRq5xU9zEzoXIITjYNIfxDDdUw==
-react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4:
+react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.9.0:
version "16.9.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.9.0.tgz#21ca9561399aad0ff1a7701c01683e8ca981edcb"
integrity sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==
+react-redux@^7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.1.1.tgz#ce6eee1b734a7a76e0788b3309bf78ff6b34fa0a"
+ integrity sha512-QsW0vcmVVdNQzEkrgzh2W3Ksvr8cqpAv5FhEk7tNEft+5pp7rXxAudTz3VOPawRkLIepItpkEIyLcN/VVXzjTg==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+ hoist-non-react-statics "^3.3.0"
+ invariant "^2.2.4"
+ loose-envify "^1.4.0"
+ prop-types "^15.7.2"
+ react-is "^16.9.0"
+
react-router-dom@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.0.1.tgz#ee66f4a5d18b6089c361958e443489d6bab714be"
@@ -8122,6 +8182,19 @@ recursive-readdir@2.2.2:
dependencies:
minimatch "3.0.4"
+redux-thunk@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
+ integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
+
+redux@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.4.tgz#4ee1aeb164b63d6a1bcc57ae4aa0b6e6fa7a3796"
+ integrity sha512-vKv4WdiJxOWKxK0yRoaK3Y4pxxB0ilzVx6dszU2W8wLxlb2yikRph4iV/ymtdJ6ZxpBLFbyrxklnT5yBbQSl3Q==
+ dependencies:
+ loose-envify "^1.4.0"
+ symbol-observable "^1.2.0"
+
regenerate-unicode-properties@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e"
@@ -8516,6 +8589,11 @@ schema-utils@^2.0.0, schema-utils@^2.0.1:
ajv "^6.1.0"
ajv-keywords "^3.1.0"
+seamless-immutable@^7.1.3:
+ version "7.1.4"
+ resolved "https://registry.yarnpkg.com/seamless-immutable/-/seamless-immutable-7.1.4.tgz#6e9536def083ddc4dea0207d722e0e80d0f372f8"
+ integrity sha512-XiUO1QP4ki4E2PHegiGAlu6r82o5A+6tRh7IkGGTVg/h+UoeX4nFBeCGPOhb4CYjvkqsfm/TUtvOMYC1xmV30A==
+
select-hose@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
@@ -9115,6 +9193,11 @@ svgo@^1.0.0, svgo@^1.2.2:
unquote "~1.1.1"
util.promisify "~1.0.0"
+symbol-observable@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
+ integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
+
symbol-tree@^3.2.2:
version "3.2.4"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"