-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 4c4c721
Showing
29 changed files
with
1,442 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"presets": ["es2015", "react"], | ||
"env": { | ||
"development": { | ||
"presets": ["react-hmre"] | ||
} | ||
} | ||
} |
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 * as types from '../constants/ActionTypes' | ||
|
||
export function addTodo(text) { | ||
return { type: types.ADD_TODO, text } | ||
} | ||
|
||
export function deleteTodo(id) { | ||
return { type: types.DELETE_TODO, id } | ||
} | ||
|
||
export function editTodo(id, text) { | ||
return { type: types.EDIT_TODO, id, text } | ||
} | ||
|
||
export function completeTodo(id) { | ||
return { type: types.COMPLETE_TODO, id } | ||
} | ||
|
||
export function completeAll() { | ||
return { type: types.COMPLETE_ALL } | ||
} | ||
|
||
export function clearCompleted() { | ||
return { type: types.CLEAR_COMPLETED } | ||
} |
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,73 @@ | ||
import React, { PropTypes, Component } from 'react' | ||
import classnames from 'classnames' | ||
import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from '../constants/TodoFilters' | ||
|
||
const FILTER_TITLES = { | ||
[SHOW_ALL]: 'All', | ||
[SHOW_ACTIVE]: 'Active', | ||
[SHOW_COMPLETED]: 'Completed' | ||
} | ||
|
||
class Footer extends Component { | ||
renderTodoCount() { | ||
const { activeCount } = this.props | ||
const itemWord = activeCount === 1 ? 'item' : 'items' | ||
|
||
return ( | ||
<span className="todo-count"> | ||
<strong>{activeCount || 'No'}</strong> {itemWord} left | ||
</span> | ||
) | ||
} | ||
|
||
renderFilterLink(filter) { | ||
const title = FILTER_TITLES[filter] | ||
const { filter: selectedFilter, onShow } = this.props | ||
|
||
return ( | ||
<a className={classnames({ selected: filter === selectedFilter })} | ||
style={{ cursor: 'pointer' }} | ||
onClick={() => onShow(filter)}> | ||
{title} | ||
</a> | ||
) | ||
} | ||
|
||
renderClearButton() { | ||
const { completedCount, onClearCompleted } = this.props | ||
if (completedCount > 0) { | ||
return ( | ||
<button className="clear-completed" | ||
onClick={onClearCompleted} > | ||
Clear completed | ||
</button> | ||
) | ||
} | ||
} | ||
|
||
render() { | ||
return ( | ||
<footer className="footer"> | ||
{this.renderTodoCount()} | ||
<ul className="filters"> | ||
{[ SHOW_ALL, SHOW_ACTIVE, SHOW_COMPLETED ].map(filter => | ||
<li key={filter}> | ||
{this.renderFilterLink(filter)} | ||
</li> | ||
)} | ||
</ul> | ||
{this.renderClearButton()} | ||
</footer> | ||
) | ||
} | ||
} | ||
|
||
Footer.propTypes = { | ||
completedCount: PropTypes.number.isRequired, | ||
activeCount: PropTypes.number.isRequired, | ||
filter: PropTypes.string.isRequired, | ||
onClearCompleted: PropTypes.func.isRequired, | ||
onShow: PropTypes.func.isRequired | ||
} | ||
|
||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import React, { PropTypes, Component } from 'react' | ||
import TodoTextInput from './TodoTextInput' | ||
|
||
class Header extends Component { | ||
handleSave(text) { | ||
if (text.length !== 0) { | ||
this.props.addTodo(text) | ||
} | ||
} | ||
|
||
render() { | ||
return ( | ||
<header className="header"> | ||
<h1>todos</h1> | ||
<TodoTextInput newTodo | ||
onSave={this.handleSave.bind(this)} | ||
placeholder="What needs to be done?" /> | ||
</header> | ||
) | ||
} | ||
} | ||
|
||
Header.propTypes = { | ||
addTodo: PropTypes.func.isRequired | ||
} | ||
|
||
export default Header; |
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,83 @@ | ||
import React, { Component, PropTypes } from 'react' | ||
import TodoItem from './TodoItem' | ||
import Footer from './Footer' | ||
import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from '../constants/TodoFilters' | ||
|
||
const TODO_FILTERS = { | ||
[SHOW_ALL]: () => true, | ||
[SHOW_ACTIVE]: todo => !todo.completed, | ||
[SHOW_COMPLETED]: todo => todo.completed | ||
} | ||
|
||
class MainSection extends Component { | ||
constructor(props, context) { | ||
super(props, context) | ||
this.state = { filter: SHOW_ALL } | ||
} | ||
|
||
handleClearCompleted() { | ||
this.props.actions.clearCompleted() | ||
} | ||
|
||
handleShow(filter) { | ||
this.setState({ filter }) | ||
} | ||
|
||
renderToggleAll(completedCount) { | ||
const { todos, actions } = this.props | ||
if (todos.length > 0) { | ||
return ( | ||
<input className="toggle-all" | ||
type="checkbox" | ||
checked={completedCount === todos.length} | ||
onChange={actions.completeAll} /> | ||
) | ||
} | ||
} | ||
|
||
renderFooter(completedCount) { | ||
const { todos } = this.props | ||
const { filter } = this.state | ||
const activeCount = todos.length - completedCount | ||
|
||
if (todos.length) { | ||
return ( | ||
<Footer completedCount={completedCount} | ||
activeCount={activeCount} | ||
filter={filter} | ||
onClearCompleted={this.handleClearCompleted.bind(this)} | ||
onShow={this.handleShow.bind(this)} /> | ||
) | ||
} | ||
} | ||
|
||
render() { | ||
const { todos, actions } = this.props | ||
const { filter } = this.state | ||
|
||
const filteredTodos = todos.filter(TODO_FILTERS[filter]) | ||
const completedCount = todos.reduce((count, todo) => | ||
todo.completed ? count + 1 : count, | ||
0 | ||
) | ||
|
||
return ( | ||
<section className="main"> | ||
{this.renderToggleAll(completedCount)} | ||
<ul className="todo-list"> | ||
{filteredTodos.map(todo => | ||
<TodoItem key={todo.id} todo={todo} {...actions} /> | ||
)} | ||
</ul> | ||
{this.renderFooter(completedCount)} | ||
</section> | ||
) | ||
} | ||
} | ||
|
||
MainSection.propTypes = { | ||
todos: PropTypes.array.isRequired, | ||
actions: PropTypes.object.isRequired | ||
} | ||
|
||
export default MainSection |
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,70 @@ | ||
import React, { Component, PropTypes } from 'react' | ||
import classnames from 'classnames' | ||
import TodoTextInput from './TodoTextInput' | ||
|
||
class TodoItem extends Component { | ||
constructor(props, context) { | ||
super(props, context) | ||
this.state = { | ||
editing: false | ||
} | ||
} | ||
|
||
handleDoubleClick() { | ||
this.setState({ editing: true }) | ||
} | ||
|
||
handleSave(id, text) { | ||
if (text.length === 0) { | ||
this.props.deleteTodo(id) | ||
} else { | ||
this.props.editTodo(id, text) | ||
} | ||
this.setState({ editing: false }) | ||
} | ||
|
||
render() { | ||
const { todo, completeTodo, deleteTodo } = this.props | ||
|
||
let element | ||
if (this.state.editing) { | ||
element = ( | ||
<TodoTextInput text={todo.text} | ||
editing={this.state.editing} | ||
onSave={(text) => this.handleSave(todo.id, text)} /> | ||
) | ||
} else { | ||
element = ( | ||
<div className="view"> | ||
<input className="toggle" | ||
type="checkbox" | ||
checked={todo.completed} | ||
onChange={() => completeTodo(todo.id)} /> | ||
<label onDoubleClick={this.handleDoubleClick.bind(this)}> | ||
{todo.text} | ||
</label> | ||
<button className="destroy" | ||
onClick={() => deleteTodo(todo.id)} /> | ||
</div> | ||
) | ||
} | ||
|
||
return ( | ||
<li className={classnames({ | ||
completed: todo.completed, | ||
editing: this.state.editing | ||
})}> | ||
{element} | ||
</li> | ||
) | ||
} | ||
} | ||
|
||
TodoItem.propTypes = { | ||
todo: PropTypes.object.isRequired, | ||
editTodo: PropTypes.func.isRequired, | ||
deleteTodo: PropTypes.func.isRequired, | ||
completeTodo: PropTypes.func.isRequired | ||
} | ||
|
||
export default TodoItem |
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,58 @@ | ||
import React, { Component, PropTypes } from 'react' | ||
import classnames from 'classnames' | ||
|
||
class TodoTextInput extends Component { | ||
constructor(props, context) { | ||
super(props, context) | ||
this.state = { | ||
text: this.props.text || '' | ||
} | ||
} | ||
|
||
handleSubmit(e) { | ||
const text = e.target.value.trim() | ||
if (e.which === 13) { | ||
this.props.onSave(text) | ||
if (this.props.newTodo) { | ||
this.setState({ text: '' }) | ||
} | ||
} | ||
} | ||
|
||
handleChange(e) { | ||
this.setState({ text: e.target.value }) | ||
} | ||
|
||
handleBlur(e) { | ||
if (!this.props.newTodo) { | ||
this.props.onSave(e.target.value) | ||
} | ||
} | ||
|
||
render() { | ||
return ( | ||
<input className={ | ||
classnames({ | ||
edit: this.props.editing, | ||
'new-todo': this.props.newTodo | ||
})} | ||
type="text" | ||
placeholder={this.props.placeholder} | ||
autoFocus="true" | ||
value={this.state.text} | ||
onBlur={this.handleBlur.bind(this)} | ||
onChange={this.handleChange.bind(this)} | ||
onKeyDown={this.handleSubmit.bind(this)} /> | ||
) | ||
} | ||
} | ||
|
||
TodoTextInput.propTypes = { | ||
onSave: PropTypes.func.isRequired, | ||
text: PropTypes.string, | ||
placeholder: PropTypes.string, | ||
editing: PropTypes.bool, | ||
newTodo: PropTypes.bool | ||
} | ||
|
||
export default TodoTextInput |
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,13 @@ | ||
import React from 'react'; | ||
import Header from '../header'; | ||
import {storiesOf, action} from 'react-storybook'; | ||
|
||
storiesOf('Header', module) | ||
.add('default view', () => { | ||
return ( | ||
<div className="todoapp"> | ||
<Header addTodo={action('Add Todo')}/> | ||
</div> | ||
); | ||
}) | ||
.add('nothing', () => (<p>Hello Man</p>)) |
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 @@ | ||
import './header' |
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,6 @@ | ||
export const ADD_TODO = 'ADD_TODO' | ||
export const DELETE_TODO = 'DELETE_TODO' | ||
export const EDIT_TODO = 'EDIT_TODO' | ||
export const COMPLETE_TODO = 'COMPLETE_TODO' | ||
export const COMPLETE_ALL = 'COMPLETE_ALL' | ||
export const CLEAR_COMPLETED = 'CLEAR_COMPLETED' |
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,3 @@ | ||
export const SHOW_ALL = 'show_all' | ||
export const SHOW_COMPLETED = 'show_completed' | ||
export const SHOW_ACTIVE = 'show_active' |
Oops, something went wrong.