This repository has been archived by the owner on Aug 9, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Todos widget implemented in Redux
- Loading branch information
1 parent
71f404a
commit e914a9c
Showing
9 changed files
with
301 additions
and
0 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
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,24 @@ | ||
// action types | ||
export const ADD_TODO = 'ADD_TODO' | ||
export const COMPLETE_TODO = 'COMPLETE_TODO' | ||
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER' | ||
|
||
// other constants | ||
export const VisibilityFilters = { | ||
SHOW_ALL: 'SHOW_ALL', | ||
SHOW_COMPLETED: 'SHOW_COMPLETED', | ||
SHOW_ACTIVE: 'SHOW_ACTIVE' | ||
} | ||
|
||
// action creators | ||
export function addTodo(text) { | ||
return { type: ADD_TODO, text } | ||
} | ||
|
||
export function completeTodo(index) { | ||
return { type: COMPLETE_TODO, index } | ||
} | ||
|
||
export function setVisibilityFilter(filter) { | ||
return { type: SET_VISIBILITY_FILTER, filter } | ||
} |
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 { combineReducers } from 'redux'; | ||
import { ADD_TODO, COMPLETE_TODO, SET_VISIBILITY_FILTER, VisibilityFilters } | ||
from './actions'; | ||
const { SHOW_ALL } = VisibilityFilters; | ||
|
||
function visibilityFilter(state = SHOW_ALL, action) { | ||
// TODO Switch statements are a no-no | ||
switch (action.type) { | ||
case SET_VISIBILITY_FILTER: | ||
return action.filter; | ||
default: | ||
return state; | ||
} | ||
} | ||
|
||
function todos(state = [], action) { | ||
// TODO Switch statements are a no-no | ||
switch (action.type) { | ||
case ADD_TODO: | ||
return [...state, { | ||
text: action.text, | ||
completed: false | ||
}]; | ||
case COMPLETE_TODO: | ||
return [ | ||
...state.slice(0, action.index), | ||
Object.assign( {}, state[action.index], { | ||
completed: true | ||
}), | ||
...state.slice(action.index + 1) | ||
]; | ||
default: | ||
return state; | ||
} | ||
} | ||
|
||
const todoApp = combineReducers({ | ||
visibilityFilter, | ||
todos | ||
}); | ||
|
||
export default todoApp; |
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 React from 'react' | ||
|
||
export default class AddTodo extends React.Component { | ||
|
||
constructor(props) { | ||
super(props) | ||
this.bindInstanceMethods( "handleClick" ) | ||
} | ||
|
||
bindInstanceMethods( ...methods ) { | ||
methods.forEach( | ||
( method ) => this[ method ] = this[ method ].bind( this ) | ||
) | ||
} | ||
|
||
render() { | ||
return ( | ||
<div> | ||
<input type="text" ref="input" /> | ||
<button onClick={this.handleClick}> | ||
Add | ||
</button> | ||
</div> | ||
) | ||
} | ||
|
||
handleClick( event ) { | ||
let node = React.findDOMNode( this.refs.input ) | ||
let text = node.value.trim() | ||
this.props.onAddClick( text ) | ||
node.value = '' | ||
} | ||
} | ||
|
||
AddTodo.propTypes = { | ||
onAddClick: React.PropTypes.func.isRequired | ||
} |
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,69 @@ | ||
import React from "react" | ||
import { connect } from 'react-redux' | ||
import { addTodo, completeTodo, setVisibilityFilter, VisibilityFilters } | ||
from '../flux/actions' | ||
import AddTodo from './AddTodo.jsx' | ||
import TodoList from './TodoList.jsx' | ||
import Footer from './Footer.jsx' | ||
|
||
class App extends React.Component { | ||
|
||
render() { | ||
// Injected by connect() call: | ||
const { dispatch, visibleTodos, visibilityFilter } = this.props | ||
return ( | ||
<div> | ||
<AddTodo | ||
onAddClick={text => | ||
dispatch( addTodo( text ) ) | ||
} /> | ||
<TodoList | ||
todos={visibleTodos} | ||
onTodoClick={index => { | ||
dispatch( completeTodo( index ) ) | ||
}} /> | ||
<Footer | ||
filter={visibilityFilter} | ||
onFilterChange={nextFilter => | ||
dispatch( setVisibilityFilter( nextFilter ) ) | ||
} /> | ||
</div> | ||
) | ||
} | ||
} | ||
|
||
App.propTypes = { | ||
visibleTodos: React.PropTypes.arrayOf( React.PropTypes.shape({ | ||
text: React.PropTypes.string.isRequired, | ||
completed: React.PropTypes.bool.isRequired | ||
}) ), | ||
visibilityFilter: React.PropTypes.oneOf([ | ||
'SHOW_ALL', | ||
'SHOW_COMPLETED', | ||
'SHOW_ACTIVE' | ||
]).isRequired | ||
} | ||
|
||
function selectTodos(todos, filter) { | ||
// TODO Switch statements are a no-no | ||
switch ( filter ) { | ||
case VisibilityFilters.SHOW_ALL: | ||
return todos | ||
case VisibilityFilters.SHOW_COMPLETED: | ||
return todos.filter( todo => todo.completed ) | ||
case VisibilityFilters.SHOW_ACTIVE: | ||
return todos.filter( todo => !todo.completed ) | ||
} | ||
} | ||
|
||
// Which props do we want to inject, given the global state? | ||
// Note: use https://github.com/faassen/reselect for better performance. | ||
function select(state) { | ||
return { | ||
visibleTodos: selectTodos( state.todos, state.visibilityFilter ), | ||
visibilityFilter: state.visibilityFilter | ||
} | ||
} | ||
|
||
// Wrap the component to inject dispatch and state into it | ||
export default connect( select )( App ) |
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,51 @@ | ||
import React from 'react' | ||
|
||
export default class Footer extends React.Component { | ||
|
||
constructor(props) { | ||
super(props) | ||
} | ||
|
||
render() { | ||
return ( | ||
<p> | ||
Show: | ||
{' '} | ||
{this.renderFilter('SHOW_ALL', 'All')} | ||
{', '} | ||
{this.renderFilter('SHOW_COMPLETED', 'Completed')} | ||
{', '} | ||
{this.renderFilter('SHOW_ACTIVE', 'Active')} | ||
. | ||
</p> | ||
) | ||
} | ||
|
||
renderFilter(filter, name) { | ||
if (filter === this.props.filter) { | ||
return name | ||
} | ||
|
||
return ( | ||
// Please note the currying technique we use below | ||
<a href="#" onClick={ this.handleClick.bind( this, filter ) }> | ||
{name} | ||
</a> | ||
) | ||
} | ||
|
||
handleClick( filter, event ) { | ||
event.preventDefault() | ||
this.props.onFilterChange( filter ) | ||
} | ||
|
||
} | ||
|
||
Footer.propTypes = { | ||
onFilterChange: React.PropTypes.func.isRequired, | ||
filter: React.PropTypes.oneOf([ | ||
'SHOW_ALL', | ||
'SHOW_COMPLETED', | ||
'SHOW_ACTIVE' | ||
]).isRequired | ||
} |
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,33 @@ | ||
import React from "react" | ||
|
||
export default class Todo extends React.Component { | ||
|
||
render() { | ||
let textDecoration, cursor | ||
|
||
if ( this.props.completed ) { | ||
textDecoration = 'line-through' | ||
cursor = 'default' | ||
} else { | ||
textDecoration = 'none' | ||
cursor = 'pointer' | ||
} | ||
|
||
return ( | ||
<li | ||
onClick={this.props.onClick} | ||
style={{ | ||
textDecoration: textDecoration, | ||
cursor: cursor | ||
}}> | ||
{this.props.text} | ||
</li> | ||
); | ||
} | ||
} | ||
|
||
Todo.propTypes = { | ||
onClick: React.PropTypes.func.isRequired, | ||
text: React.PropTypes.string.isRequired, | ||
completed: React.PropTypes.bool.isRequired | ||
}; |
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 React from "react" | ||
import Todo from './Todo.jsx'; | ||
|
||
export default class TodoList extends React.Component { | ||
render() { | ||
return ( | ||
<ul> | ||
{this.props.todos.map( (todo, index) => | ||
<Todo {...todo} | ||
key={index} | ||
onClick={ () => this.props.onTodoClick(index) } /> | ||
)} | ||
</ul> | ||
); | ||
} | ||
} | ||
|
||
TodoList.propTypes = { | ||
onTodoClick: React.PropTypes.func.isRequired, | ||
todos: React.PropTypes.arrayOf( React.PropTypes.shape({ | ||
text: React.PropTypes.string.isRequired, | ||
completed: React.PropTypes.bool.isRequired | ||
}).isRequired ).isRequired | ||
}; |