diff --git a/package.json b/package.json
index 4488cb3..0e289d2 100644
--- a/package.json
+++ b/package.json
@@ -1,13 +1,18 @@
{
- "name": "swppfront",
+ "name": "todo",
"version": "0.1.0",
"private": true,
+ "proxy": "http://localhost:8000",
"dependencies": {
+ "axios": "^0.20.0",
"react": "^16.9.0",
"react-dom": "^16.9.0",
+ "react-redux": "^7.2.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.5",
+ "redux-thunk": "^2.3.0"
},
"scripts": {
"start": "react-scripts start",
diff --git a/src/components/Todo/Todo.js b/src/components/Todo/Todo.js
index 9c80927..95d8fcd 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..7c30bf2 100644
--- a/src/containers/TodoList/NewTodo/NewTodo.js
+++ b/src/containers/TodoList/NewTodo/NewTodo.js
@@ -4,6 +4,19 @@ import { Redirect } from 'react-router-dom';
import './NewTodo.css';
+import { connect } from 'react-redux';
+import * as actionTypes from '../../../store/actions/actionTypes';
+import * as actionCreators from '../../../store/actions/index';
+
+const mapDispatchToProps = dispatch => {
+ return {
+ onStoreTodo: (title, content) =>
+ dispatch(actionCreators.postTodo({title: title, content: content}))
+// dispatch({ type: actionTypes.ADD_TODO, title: title, content: content })
+// };
+ }
+};
+
class NewTodo extends Component {
state = {
title: '',
@@ -12,12 +25,16 @@ class NewTodo extends Component {
}
postTodoHandler = () => {
+ this.props.onStoreTodo(this.state.title, this.state.content);
+ //this.setState({ submitted: true });
+
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 });
+
}
render() {
@@ -36,7 +53,7 @@ class NewTodo extends Component {
>
@@ -45,4 +62,4 @@ class NewTodo extends Component {
}
}
-export default NewTodo;
\ No newline at end of file
+export default connect(null, mapDispatchToProps)(NewTodo);
diff --git a/src/containers/TodoList/RealDetail/RealDetail.js b/src/containers/TodoList/RealDetail/RealDetail.js
index 89500a3..bb48eb2 100644
--- a/src/containers/TodoList/RealDetail/RealDetail.js
+++ b/src/containers/TodoList/RealDetail/RealDetail.js
@@ -1,23 +1,35 @@
import React, { Component } from 'react';
import './RealDetail.css';
+import * as actionTypes from '../../../store/actions/actionTypes';
+import { connect } from 'react-redux';
+
+import * as actionCreators from '../../../store/actions/index';
class RealDetail extends Component {
+ componentDidMount() {
+ this.props.onGetTodo(parseInt(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 (
Name:
-
@@ -25,4 +37,16 @@ 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..3ee4b14 100644
--- a/src/containers/TodoList/TodoList.js
+++ b/src/containers/TodoList/TodoList.js
@@ -7,7 +7,22 @@ import { NavLink } from 'react-router-dom';
import './TodoList.css';
+import { connect } from 'react-redux';
+
+import * as actionTypes from '../../store/actions/actionTypes';
+
+import { withRouter } from 'react-router';
+import axios from 'axios';
+import * as actionCreators from '../../store/actions/index';
+
+const mapStateToProps = state => {
+ return {
+ storedTodos: state.td.todos
+ };
+};
+
class TodoList extends Component {
+
state = {
todos: [
{ id: 1, title: 'SWPP', content: 'take swpp class', done: true },
@@ -15,24 +30,26 @@ class TodoList extends Component {
{ 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)}
/>
);
});
@@ -59,4 +76,14 @@ class TodoList extends Component {
}
}
-export default TodoList;
\ No newline at end of file
+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));
diff --git a/src/index.js b/src/index.js
index 87d1be5..0f5c540 100644
--- a/src/index.js
+++ b/src/index.js
@@ -4,7 +4,21 @@ import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
-ReactDOM.render(, document.getElementById('root'));
+import { Provider } from 'react-redux';
+import { createStore, applyMiddleware, combineReducers } from 'redux';
+
+import todoReducer from './store/reducers/todo';
+import thunk from 'redux-thunk';
+
+const rootReducer = combineReducers({
+ td: todoReducer,
+});
+
+const store = createStore(rootReducer, applyMiddleware(thunk));
+//const store = createStore(rootReducer,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
+
+
+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/actionCreators/action b/src/store/actionCreators/action
new file mode 100644
index 0000000..e69de29
diff --git a/src/store/actions/actionTypes.js b/src/store/actions/actionTypes.js
new file mode 100644
index 0000000..8b4377d
--- /dev/null
+++ b/src/store/actions/actionTypes.js
@@ -0,0 +1,5 @@
+export const GET_ALL = 'GET_ALL';
+export const GET_TODO = 'GET_TODO';
+export const TOGGLE_DONE = 'TOGGLE_DONE';
+export const DELETE_TODO = 'DELETE_TODO';
+export const ADD_TODO = 'ADD_TODO';
diff --git a/src/store/actions/index.js b/src/store/actions/index.js
new file mode 100644
index 0000000..f75610a
--- /dev/null
+++ b/src/store/actions/index.js
@@ -0,0 +1 @@
+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..275e3db
--- /dev/null
+++ b/src/store/actions/todo.js
@@ -0,0 +1,75 @@
+import * as actionTypes from './actionTypes';
+import axios from 'axios';
+
+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 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));
+ })
+ }
+}
+
+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));
+ })
+ }
+}
+
+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));
+ })
+ }
+}
\ No newline at end of file
diff --git a/src/store/reducers/todo.js b/src/store/reducers/todo.js
new file mode 100644
index 0000000..c7899c1
--- /dev/null
+++ b/src/store/reducers/todo.js
@@ -0,0 +1,41 @@
+import * as actionTypes from '../actions/actionTypes';
+const initialState = {
+ 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
+};
+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, newTodo]};
+ case actionTypes.DELETE_TODO:
+ const deleted = state.todos.filter(todo => {
+ return todo.id !== action.targetID;
+ });
+ return { ...state, todos: deleted};
+ 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;