-
Notifications
You must be signed in to change notification settings - Fork 301
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TodoList sample with server side persistence. (#107)
* auto disable ssr based on load * if autossr is needed * making auto ssr an option * remove unused variable * move auto ssr to a module * removing comments * package electrode-auto-ssr * adding hapi as dev dependency * add local package to gulpfile * consistent variable name * missing variable * basic todo app * correctly initialize redux Store * modify default reducer * read file * read todo list from file * add middleware * component changes * update reducers and view * add plugin for updating file * undo debugging changes * fix esLint * error handling * using isomorphic fetch * lint * response status is a number * enable csrf
- Loading branch information
Showing
22 changed files
with
401 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
let nextTodoId = 0; | ||
export const addTodo = (text) => { | ||
return { | ||
type: "ADD_TODO", | ||
id: nextTodoId++, | ||
text | ||
}; | ||
}; | ||
|
||
export const setVisibilityFilter = (filter) => { | ||
return { | ||
type: "SET_VISIBILITY_FILTER", | ||
filter | ||
}; | ||
}; | ||
|
||
export const toggleTodo = (id) => { | ||
return { | ||
type: "TOGGLE_TODO", | ||
id | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import React from "react"; | ||
import FilterLink from "../containers/filter-link"; | ||
|
||
const Footer = () => ( | ||
<div> | ||
<p> | ||
Show: | ||
{" "} | ||
<FilterLink filter="SHOW_ALL"> | ||
All | ||
</FilterLink> | ||
{", "} | ||
<FilterLink filter="SHOW_ACTIVE"> | ||
Active | ||
</FilterLink> | ||
{", "} | ||
<FilterLink filter="SHOW_COMPLETED"> | ||
Completed | ||
</FilterLink> | ||
</p> | ||
<a href="/"> | ||
Home | ||
</a> | ||
</div> | ||
); | ||
|
||
export default Footer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import React, { PropTypes } from "react"; | ||
|
||
const Link = ({ active, children, onClick }) => { | ||
if (active) { | ||
return <span>{children}</span>; | ||
} | ||
|
||
return ( | ||
<a href="#" | ||
onClick={(e) => { | ||
e.preventDefault(); | ||
onClick(); | ||
}} | ||
> | ||
{children} | ||
</a> | ||
); | ||
}; | ||
|
||
Link.propTypes = { | ||
active: PropTypes.bool.isRequired, | ||
children: PropTypes.node.isRequired, | ||
onClick: PropTypes.func.isRequired | ||
}; | ||
|
||
export default Link; |
14 changes: 14 additions & 0 deletions
14
samples/universal-react-node/client/components/todo-app.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import React from "react"; | ||
import Footer from "./footer"; | ||
import AddTodo from "../containers/add-todo"; | ||
import VisibleTodoList from "../containers/visible-todo-list"; | ||
|
||
const TodoApp = () => ( | ||
<div> | ||
<AddTodo /> | ||
<VisibleTodoList /> | ||
<Footer /> | ||
</div> | ||
); | ||
|
||
export default TodoApp; |
25 changes: 25 additions & 0 deletions
25
samples/universal-react-node/client/components/todo-list.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import React, { PropTypes } from "react"; | ||
import Todo from "./todo"; | ||
|
||
const TodoList = ({ todos, onTodoClick }) => ( | ||
<ul> | ||
{todos.map((todo) => | ||
<Todo | ||
key={todo.id} | ||
{...todo} | ||
onClick={() => onTodoClick(todo.id)} | ||
/> | ||
)} | ||
</ul> | ||
); | ||
|
||
TodoList.propTypes = { | ||
todos: PropTypes.arrayOf(PropTypes.shape({ | ||
id: PropTypes.number.isRequired, | ||
completed: PropTypes.bool.isRequired, | ||
text: PropTypes.string.isRequired | ||
}).isRequired).isRequired, | ||
onTodoClick: PropTypes.func.isRequired | ||
}; | ||
|
||
export default TodoList; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import React, { PropTypes } from "react"; | ||
|
||
const Todo = ({ onClick, completed, text }) => ( | ||
<li | ||
onClick={onClick} | ||
style={{ | ||
textDecoration: completed ? "line-through" : "none" | ||
}} | ||
> | ||
{text} | ||
</li> | ||
); | ||
|
||
Todo.propTypes = { | ||
onClick: PropTypes.func.isRequired, | ||
completed: PropTypes.bool.isRequired, | ||
text: PropTypes.string.isRequired | ||
}; | ||
|
||
export default Todo; |
34 changes: 34 additions & 0 deletions
34
samples/universal-react-node/client/containers/add-todo.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import React, {PropTypes} from "react"; | ||
import { connect } from "react-redux"; | ||
import { addTodo } from "../actions"; | ||
|
||
let AddTodo = ({ dispatch }) => { | ||
let input; | ||
|
||
return ( | ||
<div> | ||
<form onSubmit={(e) => { | ||
e.preventDefault(); | ||
if (!input.value.trim()) { | ||
return; | ||
} | ||
dispatch(addTodo(input.value)); | ||
input.value = ""; | ||
}}> | ||
<input ref={(node) => { | ||
input = node; | ||
}} /> | ||
<button type="submit"> | ||
Add Todo | ||
</button> | ||
</form> | ||
</div> | ||
); | ||
}; | ||
|
||
AddTodo.propTypes = { | ||
dispatch: PropTypes.func | ||
}; | ||
AddTodo = connect()(AddTodo); | ||
|
||
export default AddTodo; |
24 changes: 24 additions & 0 deletions
24
samples/universal-react-node/client/containers/filter-link.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { connect } from "react-redux"; | ||
import { setVisibilityFilter } from "../actions"; | ||
import Link from "../components/link"; | ||
|
||
const mapStateToProps = (state, ownProps) => { | ||
return { | ||
active: ownProps.filter === state.visibilityFilter | ||
}; | ||
}; | ||
|
||
const mapDispatchToProps = (dispatch, ownProps) => { | ||
return { | ||
onClick: () => { | ||
dispatch(setVisibilityFilter(ownProps.filter)); | ||
} | ||
}; | ||
}; | ||
|
||
const FilterLink = connect( | ||
mapStateToProps, | ||
mapDispatchToProps | ||
)(Link); | ||
|
||
export default FilterLink; |
37 changes: 37 additions & 0 deletions
37
samples/universal-react-node/client/containers/visible-todo-list.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { connect } from "react-redux"; | ||
import { toggleTodo } from "../actions"; | ||
import TodoList from "../components/todo-list"; | ||
|
||
const getVisibleTodos = (todos, filter) => { | ||
switch (filter) { | ||
case "SHOW_ALL": | ||
return todos; | ||
case "SHOW_COMPLETED": | ||
return todos.filter((t) => t.completed); | ||
case "SHOW_ACTIVE": | ||
return todos.filter((t) => !t.completed); | ||
default: | ||
return todos; | ||
} | ||
}; | ||
|
||
const mapStateToProps = (state) => { | ||
return { | ||
todos: getVisibleTodos(state.todos, state.visibilityFilter) | ||
}; | ||
}; | ||
|
||
const mapDispatchToProps = (dispatch) => { | ||
return { | ||
onTodoClick: (id) => { | ||
dispatch(toggleTodo(id)); | ||
} | ||
}; | ||
}; | ||
|
||
const VisibleTodoList = connect( | ||
mapStateToProps, | ||
mapDispatchToProps | ||
)(TodoList); | ||
|
||
export default VisibleTodoList; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import "es6-promise"; | ||
import "isomorphic-fetch"; | ||
const HTTP_BAD_REQUEST = 400; | ||
const HTTP_OK = 200; | ||
let token; | ||
|
||
const updateStorage = (store) => (next) => (action) => { | ||
const result = next(action); | ||
const completeState = store.getState(); | ||
fetch("/1", {credentials: "same-origin"}) | ||
.then((resp) => { | ||
if (resp.status === HTTP_OK) { | ||
token = resp.headers.get("x-csrf-jwt"); | ||
} else { | ||
throw new Error("token generation failed"); | ||
} | ||
fetch("/updateStorage", { | ||
credentials: "same-origin", | ||
method: "POST", | ||
headers: { | ||
"Accept": "application/json", | ||
"Content-Type": "application/json", | ||
"x-csrf-jwt": token | ||
}, | ||
body: JSON.stringify(completeState) | ||
}) | ||
.then((response) => { | ||
if (response.status >= HTTP_BAD_REQUEST) { | ||
throw new Error("Bad response from server"); | ||
} | ||
return result; | ||
}) | ||
.catch((err) => { | ||
throw new Error("Error Updating Storage", err); | ||
}); | ||
}) | ||
.catch((err) => { | ||
throw new Error("Error Fetching Csrf Token", err); | ||
}); | ||
}; | ||
|
||
export default updateStorage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,9 @@ | ||
const rootReducer = (state) => { | ||
return state || {}; | ||
}; | ||
import todos from "./todos"; | ||
import visibilityFilter from "./visibilityFilter"; | ||
|
||
export default rootReducer; | ||
export default function rootReducer(state = {}, action) { | ||
return { | ||
visibilityFilter: visibilityFilter(state.visibilityFilter, action), | ||
todos: todos(state.todos, action) | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
const todo = (state = {}, action) => { | ||
let currentId; | ||
if (state.length > 0) { | ||
currentId = state[state.length - 1].id; | ||
} | ||
switch (action.type) { | ||
case "ADD_TODO": | ||
return { | ||
id: ++currentId || action.id, | ||
text: action.text, | ||
completed: false | ||
}; | ||
case "TOGGLE_TODO": | ||
if (state.id !== action.id) { | ||
return state; | ||
} | ||
return Object.assign({}, state, { | ||
completed: !state.completed | ||
}); | ||
default: | ||
return state; | ||
} | ||
}; | ||
|
||
const todos = (state = [], action) => { | ||
switch (action.type) { | ||
case "ADD_TODO": | ||
return [ | ||
...state, | ||
todo(state, action) | ||
]; | ||
case "TOGGLE_TODO": | ||
return state.map((t) => | ||
todo(t, action) | ||
); | ||
default: | ||
return state; | ||
} | ||
}; | ||
|
||
export default todos; |
Oops, something went wrong.