Skip to content

Commit e196214

Browse files
Add Todo functionality in Frontend react-redux part
1 parent 1274790 commit e196214

File tree

14 files changed

+297
-46
lines changed

14 files changed

+297
-46
lines changed

express-server/app.js

+4
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@ import bodyParser from 'body-parser';
55
import logger from 'morgan';
66
import mongoose from 'mongoose';
77
import SourceMapSupport from 'source-map-support';
8+
import bb from 'express-busboy';
89

910
// import routes
1011
import todoRoutes from './routes/todo.server.route';
1112

1213
// define our app using express
1314
const app = express();
1415

16+
// express-busboy to parse multipart/form-data
17+
bb.extend(app);
18+
1519
// allow-cors
1620
app.use(function(req,res,next){
1721
res.header("Access-Control-Allow-Origin", "*");

express-server/controllers/todo.server.controller.js

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const getTodos = (req,res) => {
1515
}
1616

1717
export const addTodo = (req,res) => {
18+
console.log(req.body);
1819
const newTodo = new Todo(req.body);
1920
newTodo.save((err,todo) => {
2021
if(err){

express-server/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"babel-preset-es2015-node6": "^0.4.0",
2727
"babel-register": "^6.26.0",
2828
"body-parser": "^1.17.2",
29+
"express-busboy": "^6.0.1",
2930
"mongoose": "^4.11.7",
3031
"morgan": "^1.8.2",
3132
"source-map-support": "^0.4.16"

react-redux-client/src/actions/appActions.js

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// ./react-redux-client/src/actions/appActions.js
22

3-
const apiUrl = "/api/";
4-
53
export const toggleAddTodo = () => {
64
return {
75
type: 'TOGGLE_ADD_TODO'

react-redux-client/src/actions/todoActions.js

+107-10
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,48 @@ export const toggleAddBook = () => {
88
}
99
}
1010

11-
export const addTodo = (todo) => {
11+
export const addNewTodo = (todo) => {console.log(todo)
12+
return (dispatch) => {
13+
dispatch(addNewTodoRequest(todo));
14+
return fetch(apiUrl, {
15+
method:'post',
16+
// headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
17+
body: todo,
18+
}).then(response => {
19+
if(response.ok){
20+
response.json().then(data => {console.log(data.todo);
21+
dispatch(addNewTodoRequestSuccess(data.todo, data.message))
22+
})
23+
}
24+
else{
25+
response.json().then(error => {
26+
dispatch(addNewTodoRequestFailed(error))
27+
})
28+
}
29+
})
30+
}
31+
}
1232

33+
export const addNewTodoRequest = (todo) => {
34+
return {
35+
type: 'ADD_NEW_TODO_REQUEST',
36+
todo
37+
}
38+
}
39+
40+
export const addNewTodoRequestSuccess = (todo,message) => {
41+
return {
42+
type: 'ADD_NEW_TODO_REQUEST_SUCCESS',
43+
todo:todo,
44+
message:message
45+
}
46+
}
47+
48+
export const addNewTodoRequestFailed = (error) => {
49+
return {
50+
type: 'ADD_NEW_TODO_REQUEST_FAILED',
51+
error
52+
}
1353
}
1454

1555
export const deleteTodo = (todo) => {
@@ -29,15 +69,20 @@ export const fetchTodos = () => {
2969
dispatch(fetchTodosRequest());
3070
// Returns a promise
3171
return fetch(apiUrl)
32-
.then(response => response.json())
33-
.then(data =>
34-
// dispatch another action
35-
// to consume data
36-
dispatch(fetchTodosSuccess(data.todos,data.message))
37-
)
38-
.then(error => {
39-
throw(error);
72+
.then(response => {
73+
if(response.ok){
74+
response.json().then(data => {
75+
dispatch(fetchTodosSuccess(data.todos,data.message));
76+
})
77+
}
78+
else{
79+
response.json().then(error => {
80+
dispatch(fetchTodosFailed(error));
81+
})
82+
}
4083
})
84+
85+
4186
}
4287
}
4388

@@ -56,4 +101,56 @@ export const fetchTodosSuccess = (todos,message) => {
56101
message: message,
57102
receivedAt: Date.now
58103
}
59-
};
104+
}
105+
106+
export const fetchTodosFailed = (error) => {
107+
return {
108+
type:'FETCH_TODOS_FAILED',
109+
error
110+
}
111+
}
112+
113+
export const fetchTodoById = (todoId) => {
114+
return (dispatch) => {
115+
dispatch(fetchTodoRequest());
116+
// Returns a promise
117+
return fetch(apiUrl + todoId)
118+
.then(response => {console.log(response)
119+
if(response.ok){
120+
response.json().then(data => {
121+
dispatch(fetchTodoSuccess(data.todo[0], data.message));
122+
})
123+
}
124+
else{
125+
response.json().then(error => {
126+
dispatch(fetchTodoFailed(error));
127+
})
128+
}
129+
})
130+
131+
}
132+
}
133+
134+
export const fetchTodoRequest = () => {
135+
return {
136+
type:'FETCH_TODO_REQUEST'
137+
}
138+
}
139+
140+
141+
//Sync action
142+
export const fetchTodoSuccess = (todo,message) => {
143+
return {
144+
type: 'FETCH_TODO_SUCCESS',
145+
todo: todo,
146+
message: message,
147+
receivedAt: Date.now
148+
}
149+
}
150+
151+
export const fetchTodoFailed = (error) => {
152+
return {
153+
type:'FETCH_TODO_FAILED',
154+
error
155+
}
156+
}

react-redux-client/src/components/App.css

+1-20
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,4 @@
22
text-align: center;
33
}
44

5-
.App-logo {
6-
animation: App-logo-spin infinite 20s linear;
7-
height: 80px;
8-
}
9-
10-
.App-header {
11-
background-color: #222;
12-
height: 150px;
13-
padding: 20px;
14-
color: white;
15-
}
16-
17-
.App-intro {
18-
font-size: large;
19-
}
20-
21-
@keyframes App-logo-spin {
22-
from { transform: rotate(0deg); }
23-
to { transform: rotate(360deg); }
24-
}
5+
.centerAlign{text-align: center;vertical-align: middle;}

react-redux-client/src/components/App.js

+25
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,41 @@ import React from 'react';
33
import { Navbar,Nav,NavItem,MenuItem } from 'react-bootstrap';
44
import { LinkContainer } from 'react-router-bootstrap';
55
import './App.css';
6+
import TodoForm from './TodoForm';
67

78
export default class App extends React.Component {
89
constructor(props){
910
super(props);
1011
this.toggleAddTodo = this.toggleAddTodo.bind(this);
12+
this.addTodo = this.addTodo.bind(this);
1113
}
1214

1315
toggleAddTodo(e){
1416
e.preventDefault();
1517
this.props.mappedToggleAddTodo();
1618
}
1719

20+
addTodo(e){
21+
e.preventDefault();
22+
const form = document.getElementById('addTodoForm');
23+
if(form.todoText.value !== "" && form.todoDesc.value !== ""){
24+
const data = new FormData();
25+
data.append('todoText', form.todoText.value);
26+
data.append('todoDesc', form.todoDesc.value);
27+
// const data = {
28+
// todoText: form.todoText.value,
29+
// todoDesc: form.todoDesc.value
30+
// }
31+
this.props.mappedAddTodo(data);
32+
form.reset();
33+
}
34+
else{
35+
return ;
36+
}
37+
}
38+
1839
render(){
40+
const appState = this.props.mappedAppState;
1941
return(
2042
<div>
2143
<Navbar inverse collapseOnSelect className="customNav">
@@ -39,6 +61,9 @@ export default class App extends React.Component {
3961
</Navbar.Collapse>
4062
</Navbar>
4163
<div className="container">
64+
{appState.showAddTodo &&
65+
<TodoForm addTodo={this.addTodo} />
66+
}
4267
{ /* Each Smaller Components */}
4368
{this.props.children}
4469
</div>

react-redux-client/src/components/Todo.js

+15-4
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,26 @@
22
import React from 'react';
33

44
export default class Todo extends React.Component {
5-
5+
componentDidMount(){
6+
this.props.mappedfetchTodoById(this.props.params.id);
7+
}
68

79
render(){
8-
const todo = this.props.mappedTodoState.todo;
10+
const todoState = this.props.mappedTodoState;
911
return(
1012
<div className="todoDetail">
1113
<h2>Todo Detail</h2>
12-
<h3>{todo.todoText}</h3>
13-
<p>{todo.todoDesc}</p>
14+
{!todoState.todo && todoState.isFetching &&
15+
<div>
16+
<p>Loading todo....</p>
17+
</div>
18+
}
19+
{todoState.todo && !todoState.isFetching &&
20+
<div>
21+
<h3>{todoState.todo.todoText}</h3>
22+
<p>{todoState.todo.todoDesc}</p>
23+
</div>
24+
}
1425
</div>
1526
);
1627
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// ./react-redux-client/src/components/TodoForm.js
2+
import React from 'react';
3+
import { FormGroup,ControlLabel,FormControl,Button } from 'react-bootstrap';
4+
5+
const TodoForm = (props) => {
6+
return (
7+
<form className="form form-horizontal" id="addTodoForm" onSubmit={props.addTodo}>
8+
<div className="row">
9+
<h3 className="centerAlign">Add Your Todo</h3>
10+
<div className="col-md-12">
11+
<FormGroup>
12+
<ControlLabel>Todo: </ControlLabel>
13+
<FormControl
14+
type="text" placeholder="Enter todo"
15+
name="todoText"
16+
/>
17+
</FormGroup>
18+
</div>
19+
<div className="col-md-12">
20+
<FormGroup>
21+
<ControlLabel>Description: </ControlLabel>
22+
<FormControl
23+
componentClass="textarea" placeholder="Enter description"
24+
name="todoDesc"
25+
/>
26+
</FormGroup>
27+
</div>
28+
</div>
29+
<FormGroup>
30+
<Button type="submit" bsStyle="success" bsSize="large" block>Submit</Button>
31+
</FormGroup>
32+
</form>
33+
);
34+
}
35+
36+
export default TodoForm;

react-redux-client/src/components/Todos.js

+13-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export default class Todos extends React.Component {
1212
this.props.fetchTodos();
1313
}
1414

15+
1516
showEditModal(bookToEdit){
1617
//this.props.mappedshowEditModal(todoToEdit);
1718
}
@@ -29,18 +30,24 @@ export default class Todos extends React.Component {
2930
}
3031

3132
render(){
32-
const todos = this.props.mappedTodoState.todos;
33+
const todoState = this.props.mappedTodoState;
34+
const todos = todoState.todos;
3335
return(
3436
<div className="col-md-12">
35-
<h3>Todos</h3>
36-
37+
<h3 className="centerAlign">Todos</h3>
38+
{!todos && todoState.isFetching &&
39+
<p>Loading todos....</p>
40+
}
41+
{todos.length <= 0 && !todoState.isFetching &&
42+
<p>No Todos Available. Add A Todo to List here.</p>
43+
}
44+
{todos && todos.length > 0 && !todoState.isFetching &&
3745
<table className="table booksTable">
3846
<thead>
3947
<tr><th>Todo</th><th className="textCenter">Edit</th><th className="textCenter">Delete</th><th className="textCenter">View</th></tr>
4048
</thead>
4149
<tbody>
42-
{todos &&
43-
todos.map((todo,i) => <tr key={i}>
50+
{todos.map((todo,i) => <tr key={i}>
4451
<td>{todo.todoText}</td>
4552
<td className="textCenter"><Button onClick={() => this.showEditModal(todo)} bsStyle="info" bsSize="xsmall"><Glyphicon glyph="pencil" /></Button></td>
4653
<td className="textCenter"><Button onClick={() => this.showDeleteModal(todo)} bsStyle="danger" bsSize="xsmall"><Glyphicon glyph="trash" /></Button></td>
@@ -49,6 +56,7 @@ export default class Todos extends React.Component {
4956
}
5057
</tbody>
5158
</table>
59+
}
5260
</div>
5361
);
5462
}

react-redux-client/src/containers/App.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { connect } from 'react-redux';
33
import * as appActions from '../actions/appActions';
44
import App from '../components/App';
5+
import * as todoActions from '../actions/todoActions';
56

67
// map state from store to props
78
const mapStateToProps = (state) => {
@@ -15,7 +16,8 @@ const mapStateToProps = (state) => {
1516
const mapDispatchToProps = (dispatch) => {
1617
return {
1718
//you can now say this.props.mappedAppActions
18-
mappedToggleAddTodo: () => dispatch(appActions.toggleAddTodo())
19+
mappedToggleAddTodo: () => dispatch(appActions.toggleAddTodo()),
20+
mappedAddTodo: todo => dispatch(todoActions.addNewTodo(todo))
1921
}
2022
}
2123

react-redux-client/src/containers/Todo.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const mapStateToProps = (state) => {
1515
const mapDispatchToProps = (dispatch) => {
1616
return {
1717
//you can now say this.props.mappedAppActions
18-
18+
mappedfetchTodoById: todoId => dispatch(todoActions.fetchTodoById(todoId))
1919
}
2020
}
2121

0 commit comments

Comments
 (0)