Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 61 additions & 39 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import { TodoList } from './components/TodoList/TodoList';
import NewTodo from './components/NewTodo/NewTodo';
import { TodosFilter } from './components/TodosFilter/TodosFilter';
import TodoList from './components/TodoList/TodoList';
import { Footer } from './components/Footer/Footer';
import { Header } from './components/Header/Header';

class App extends Component {
state = {
Expand All @@ -19,15 +19,44 @@ class App extends Component {
this.setState({ showParam: todoToShow });
}

handleRemuve = (id) => {
handleRemove = (id) => {
this.setState(prevState => ({
todos: prevState.todos.filter(todo => (
todo.id !== id
)),
}));
}

handleRemuveCompleted = () => {
handleDobleClick = ({ id }) => {
this.setState(prevState => ({
todos: prevState.todos.map(todo => (
(todo.id !== id) ? ({
...todo, editing: false,
}) : ({
...todo, editing: true,
})
)),
}));
}

editTodo = (content) => {
if (content) {
this.setState(prevState => ({
todos: prevState.todos.map(todo => (
(todo.editing) ? ({
...todo, content,
}) : todo)),
}));
} else {
this.setState(prevState => ({
todos: prevState.todos.filter(todo => (
!todo.editing
)),
}));
}
}

handleRemoveCompleted = () => {
this.setState(prevState => ({
todos: prevState.todos.filter(todo => (
!todo.completed
Expand Down Expand Up @@ -68,70 +97,63 @@ class App extends Component {
}
}

render() {
getTodos = (status) => {
let todoView = [];
const { todos } = this.state;

switch (this.state.showParam) {
switch (status) {
case 'active':
todoView = [...this.state.todos].filter(todo => (
todoView = todos.filter(todo => (
!todo.completed
));
break;
case 'completed':
todoView = [...this.state.todos].filter(todo => (
todoView = todos.filter(todo => (
todo.completed
));
break;
default:
todoView = [...this.state.todos];
todoView = todos;
}

return todoView;
}

render() {
const { todos, showParam } = this.state;
const todoView = this.getTodos(showParam);
const itemLeft = todos.filter(todo => (
!todo.completed)).length;

return (
<section className="todoapp">
<header className="header">
<h1>todos</h1>
<NewTodo addTodo={this.addTodo} />
</header>
{(this.state.todos.length)
<Header addTodo={this.addTodo} />
{(todos.length)
? (
<>
<section className="main">
<input
onClick={this.toggleCompleteAll}
checked={!itemLeft}
type="checkbox"
id="toggle-all"
className="toggle-all"
/>
<label htmlFor="toggle-all">Mark all as complete</label>
<TodoList
todos={todoView}
remuve={this.handleRemuve}
remove={this.handleRemove}
toggleComplete={this.toggleComplete}
handleDobleClick={this.handleDobleClick}
editTodo={this.editTodo}
/>
</section>

<footer className="footer">
<span className="todo-count">
{this.state.todos.filter(todo => (
!todo.completed)).length}
item left
</span>
<TodosFilter updateTodosToShow={this.updateTodosToShow} />
{
(this.state.todos.filter(todo => (
todo.completed)).length)
? (
<button
onClick={this.handleRemuveCompleted}
type="button"
className="clear-completed"
>
Clear completed
</button>
)
: ('')
}
</footer>
<Footer
itemLeft={itemLeft}
todos={todos}
updateTodosToShow={this.updateTodosToShow}
handleRemoveCompleted={this.handleRemoveCompleted}
/>
</>
) : ''}
</section>
Expand Down
Empty file.
46 changes: 46 additions & 0 deletions src/components/Footer/Footer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import './Footer.css';
import PropTypes from 'prop-types';
import { TodosFilter } from '../TodosFilter/TodosFilter';

export const Footer = ({
todos,
updateTodosToShow,
handleRemoveCompleted,
itemLeft,
}) => (
<footer className="footer">
<span className="todo-count">
{itemLeft}
{' '}
item left
</span>
<TodosFilter updateTodosToShow={updateTodosToShow} />
{
(todos.filter(todo => (todo.completed)).length)
? (
<button
onClick={handleRemoveCompleted}
type="button"
className="clear-completed"
>
Clear completed
</button>
)
: ('')
}
</footer>
);

Footer.propTypes = {
todos: PropTypes.arrayOf(
PropTypes.shape({
content: PropTypes.string.isRequired,
id: PropTypes.number.isRequired,
completed: PropTypes.bool.isRequired,
}),
).isRequired,
updateTodosToShow: PropTypes.func.isRequired,
handleRemoveCompleted: PropTypes.func.isRequired,
itemLeft: PropTypes.number.isRequired,
};
Empty file.
15 changes: 15 additions & 0 deletions src/components/Header/Header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import './Header.css';
import PropTypes from 'prop-types';
import NewTodo from '../NewTodo/NewTodo';

export const Header = ({ addTodo }) => (
<header className="header">
<h1>todos</h1>
<NewTodo addTodo={addTodo} />
</header>
);

Header.propTypes = {
addTodo: PropTypes.func.isRequired,
};
13 changes: 8 additions & 5 deletions src/components/NewTodo/NewTodo.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import PropTypes from 'prop-types';
class NewTodo extends Component {
state = {
content: '',
id: 1,
completed: false,
}

handleChange = (event) => {
Expand All @@ -17,13 +15,18 @@ class NewTodo extends Component {

handleSubmit = (e) => {
e.preventDefault();
const { content } = this.state;
const id = +Date.now();
const completed = false;
const todo = {
content, id, completed,
};

if (this.state.content) {
this.props.addTodo(this.state);
if (content) {
this.props.addTodo(todo);

this.setState(prevState => ({
content: '',
id: prevState.id + 1,
}));
}
}
Expand Down
121 changes: 91 additions & 30 deletions src/components/TodoList/TodoList.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,93 @@
import React from 'react';
import React, { Component } from 'react';
import PropTypes from 'prop-types';

export const TodoList = ({ todos, remuve, toggleComplete }) => (
<ul className="todo-list">
{todos.map(todo => (
<li key={todo.id}>
<div className={todo.completed ? 'completed' : 'view'}>
<input
checked={todo.completed}
onClick={() => {
toggleComplete(todo.id);
}}
type="checkbox"
className="toggle"
id={`todo-${todo.id}`}
/>
<label htmlFor={`todo-${todo.id}`}>{todo.content}</label>
<button
onClick={() => {
remuve(todo.id);
}}
type="button"
className="destroy"
/>
</div>
<input type="text" className="edit" />
</li>
))}
</ul>
);
class TodoList extends Component {
state = {
content: '',
submitEditing: true,
}

handleChange = (event) => {
this.setState({
content: event.target.value.trim(),
});
}

handleSubmit = (e) => {
e.preventDefault();
this.props.editTodo(this.state.content);
this.setState({
submitEditing: false,
});
}

handleEdit = (todo) => {
this.props.handleDobleClick(todo);
this.setState(() => ({
content: todo.content,
submitEditing: true,
}));
}

render() {
return (
<ul className="todo-list">
{this.props.todos.map(todo => (
<li
key={todo.id}
className={(todo.editing && this.state.submitEditing)
? 'editing' : ''}
>
<form onSubmit={this.handleSubmit}>
<div className={todo.completed ? 'completed' : 'view'}>
<input
onClick={() => {
this.props.toggleComplete(todo.id);
}}
checked={todo.completed}
type="checkbox"
className="toggle"
id={`todo-${todo.id}`}
/>
<label
htmlFor={`edit-${todo.id}`}
onDoubleClick={() => {
this.handleEdit(todo);
}}
>
{todo.content}
</label>
<button
onClick={() => {
this.props.remove(todo.id);
}}
type="button"
className="destroy"
/>
</div>
<input
type="text"
className="edit"
id={`edit-${todo.id}`}
value={this.state.content}
onChange={this.handleChange}
onKeyUp={(e) => {
if (e.key === 'Escape') {
this.setState({ submitEditing: false });
}
}
}
/>
</form>
</li>
))
}
</ul>
);
}
}

export default TodoList;

TodoList.propTypes = {
todos: PropTypes.arrayOf(
Expand All @@ -38,6 +97,8 @@ TodoList.propTypes = {
completed: PropTypes.bool.isRequired,
}),
).isRequired,
remuve: PropTypes.func.isRequired,
remove: PropTypes.func.isRequired,
toggleComplete: PropTypes.func.isRequired,
handleDobleClick: PropTypes.func.isRequired,
editTodo: PropTypes.func.isRequired,
};
Loading