From 2a359a689c23b07776a584bf207b820163c84727 Mon Sep 17 00:00:00 2001 From: JoonPyungKim Date: Fri, 25 Sep 2020 20:02:40 +0900 Subject: [PATCH] finished --- src/App.js | 13 ++-- src/components/Todo/Todo.js | 7 +- src/components/TodoDetail/TodoDetail.js | 1 - src/containers/TodoList/NewTodo/NewTodo.js | 27 ++++--- .../TodoList/RealDetail/RealDetail.js | 29 +++++++- src/containers/TodoList/TodoList.js | 58 ++++++++------- src/index.js | 22 +++++- src/store/actions/actionsTypes.js | 5 ++ src/store/actions/index.js | 1 + src/store/actions/todo.js | 73 +++++++++++++++++++ src/store/reducers/todo.js | 44 +++++++++++ 11 files changed, 229 insertions(+), 51 deletions(-) create mode 100644 src/store/actions/actionsTypes.js create mode 100644 src/store/actions/index.js create mode 100644 src/store/actions/todo.js create mode 100644 src/store/reducers/todo.js diff --git a/src/App.js b/src/App.js index 610cd4b..860c57f 100644 --- a/src/App.js +++ b/src/App.js @@ -1,15 +1,16 @@ import React from 'react'; import './App.css'; - 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'; -function App() { +import { ConnectedRouter } from 'connected-react-router'; + +function App(props) { return ( - +
} /> @@ -19,8 +20,8 @@ function App() {

Not Found

} />
-
+ ); } - -export default App; + +export default App; \ No newline at end of file diff --git a/src/components/Todo/Todo.js b/src/components/Todo/Todo.js index 9c80927..df9a51d 100644 --- a/src/components/Todo/Todo.js +++ b/src/components/Todo/Todo.js @@ -7,11 +7,12 @@ const Todo = (props) => { return (
+ className={`text ${props.done && 'done'}`} onClick={props.clickDetail}> {props.title}
- {props.done &&
} + {props.done && (
)} + +
); }; diff --git a/src/components/TodoDetail/TodoDetail.js b/src/components/TodoDetail/TodoDetail.js index 00a18b1..601659b 100644 --- a/src/components/TodoDetail/TodoDetail.js +++ b/src/components/TodoDetail/TodoDetail.js @@ -1,4 +1,3 @@ -import React from 'react'; import './TodoDetail.css'; diff --git a/src/containers/TodoList/NewTodo/NewTodo.js b/src/containers/TodoList/NewTodo/NewTodo.js index 59e7930..22e2ce1 100644 --- a/src/containers/TodoList/NewTodo/NewTodo.js +++ b/src/containers/TodoList/NewTodo/NewTodo.js @@ -1,7 +1,11 @@ -import React, { Component } from 'react'; +//import React, { Component } from 'react'; +import { connect } from 'react-redux'; import { Redirect } from 'react-router-dom'; +import * as actionTypes from '../../../store/actions/actionTypes'; +import * as actionCreators from '../../../store/actions/index'; + import './NewTodo.css'; class NewTodo extends Component { @@ -12,12 +16,9 @@ class NewTodo extends Component { } 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() { @@ -36,7 +37,7 @@ class NewTodo extends Component { > @@ -45,4 +46,12 @@ 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..095b5ce 100644 --- a/src/containers/TodoList/RealDetail/RealDetail.js +++ b/src/containers/TodoList/RealDetail/RealDetail.js @@ -1,9 +1,20 @@ import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import * as actionTypes from '../../../store/actions/actionTypes'; import './RealDetail.css'; +import * as actionCreators from '../../../store/actions/index'; class RealDetail extends Component { + componentDidMount() { + this.props.onGetTodo(parseInt(this.props.match.params.id)); + } render() { + let content = '', title = ''; + if(this.props.selectedTodo){ + title = this.props.selectedTodo.title; + content = this.props.selectedTodo.content; + } return (
@@ -11,6 +22,7 @@ class RealDetail extends Component { Name:
+ {title}
@@ -18,6 +30,7 @@ class RealDetail extends Component { Content:
+ {content}
@@ -25,4 +38,18 @@ class RealDetail extends Component { } }; -export default RealDetail; \ No newline at end of file +export default RealDetail; +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..af8332b 100644 --- a/src/containers/TodoList/TodoList.js +++ b/src/containers/TodoList/TodoList.js @@ -1,49 +1,36 @@ -import React, { Component } from 'react'; - -import Todo from '../../components/Todo/Todo'; -import TodoDetail from '../../components/TodoDetail/TodoDetail'; +import './TodoList.css'; -import { NavLink } from 'react-router-dom'; +import { withRouter } from 'react-router'; +import { connect } from 'react-redux'; -import './TodoList.css'; +import * as actionTypes from '../../store/actions/actionTypes'; +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 (
@@ -59,4 +46,21 @@ class TodoList extends Component { } } -export default TodoList; \ No newline at end of file +const mapStateToProps = state => { + return { + storedTodos: state.td.todos, + selectedTodo : state.td.selectedTodo + }; +}; + +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..90b2cbb 100644 --- a/src/index.js +++ b/src/index.js @@ -1,10 +1,24 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import './index.css'; import App from './App'; import * as serviceWorker from './serviceWorker'; -ReactDOM.render(, document.getElementById('root')); +import {Provider} from 'react-redux'; +import {combineReducers, createStore} from 'redux'; +import { connectRouter, routerMiddleware } from 'connected-react-router' ; +import { createBrowserHistory } from 'history' ; +import { applyMiddleware } from 'redux'; + + +import thunk from 'redux-thunk'; +import todoReducer from './store/reducers/todo'; +const history = createBrowserHistory(); +const rootReducer = combineReducers({ + td: todoReducer, router: connectRouter(history) +}); + +const store = createStore(rootReducer, applyMiddleware(thunk, routerMiddleware(history))); + + + ,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/actionsTypes.js b/src/store/actions/actionsTypes.js new file mode 100644 index 0000000..8b4377d --- /dev/null +++ b/src/store/actions/actionsTypes.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..d8bfb16 --- /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..3fd98d5 --- /dev/null +++ b/src/store/actions/todo.js @@ -0,0 +1,73 @@ +import * as actionTypes from './actionTypes'; +import { push } from 'connected-react-router'; +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))) + .then(() => 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)); + }); + }; + }; + +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)); + }); + }; + }; diff --git a/src/store/reducers/todo.js b/src/store/reducers/todo.js new file mode 100644 index 0000000..001eaa1 --- /dev/null +++ b/src/store/reducers/todo.js @@ -0,0 +1,44 @@ +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; \ No newline at end of file