Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solution by Anna Kuvarina #15

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"author": "Mate Academy",
"license": "GPL-3.0",
"dependencies": {
"classnames": "^2.2.6",
"prop-types": "^15.7.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
Expand Down
235 changes: 168 additions & 67 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,176 @@
import React from 'react';
import getTodos from './api/todos';
import TodoApp from './TodoApp';
import TodoList from './TodoList';
import TodosFilter from './TodosFilter';

function App() {
return (
<section className="todoapp">
<header className="header">
<h1>todos</h1>
class App extends React.Component {
state = {
todos: [],
visibleTodos: [],
};

<input
className="new-todo"
placeholder="What needs to be done?"
/>
</header>

<section className="main" style={{ display: 'block' }}>
<input type="checkbox" id="toggle-all" className="toggle-all" />
<label htmlFor="toggle-all">Mark all as complete</label>

<ul className="todo-list">
<li className="">
<div className="view">
<input type="checkbox" className="toggle" id="todo-1" />
<label htmlFor="todo-1">sdfsdfsdf</label>
<button type="button" className="destroy" />
</div>
</li>

<li className="">
<div className="view">
<input type="checkbox" className="toggle" id="todo-2" />
<label htmlFor="todo-2">sakgjdfgkhjasgdhjfhs</label>
<button type="button" className="destroy" />
</div>
</li>

<li className="">
<div className="view">
<input type="checkbox" className="toggle" id="todo-3" />
<label htmlFor="todo-3">sddfgdfgdf</label>
<button type="button" className="destroy" />
</div>
</li>
</ul>
</section>
componentDidMount() {
this.setState({
todos: getTodos,
visibleTodos: getTodos,
});
}

addTodo = (title) => {
this.setState(prevState => {
const newTodos = [
...prevState.todos,
{
title,
id: prevState.todos.length + 1,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

тобто в тебе можуть todo з однакоми id? Якщо я видаляю першу тудушку то в нової доданої буде такий же id як і в передостанньої тудушки. Пофікси це

completed: false,
},
];

return {
visibleTodos: newTodos,
todos: newTodos,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Дійсно треба 2 копії зберігати? Може є спосіб як працювати тільки з одним масивом в один момент часу, а не тримати в пам'яті два ідентичні масиви?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можеш не міняти, але на майбутнє думай про ефективне використання пам'яті

}
});
};

handlerChangeCompleted = (id) => {
this.setState(prevState => {
const newTodos = prevState.todos.map((todo) => {
if (todo.id === id) {
return {
...todo,
completed: !todo.completed,
};
}

return todo;
});

return {
visibleTodos: newTodos,
todos: newTodos,
}
});
};

handleChangeCompletedAll = () => {
this.setState(prevState => {
if (prevState.visibleTodos.every(todo => todo.completed === false)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

every(todo => !todo.completed)

|| prevState.visibleTodos.every(todo => todo.completed === true)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

every(todo => todo.completed)

const changeAllTodos = prevState.visibleTodos.map(todo => ({
...todo,
completed: !todo.completed,
}));

return {
visibleTodos: changeAllTodos,
todos: changeAllTodos,
};
} else {
const changeSomeTodos = prevState.visibleTodos.map(todo => ({
...todo,
completed: true,
}));

return {
visibleTodos: changeSomeTodos,
todos: changeSomeTodos,
};
}

<footer className="footer" style={{ display: 'block' }}>
<span className="todo-count">
3 items left
</span>

<ul className="filters">
<li>
<a href="#/" className="selected">All</a>
</li>

<li>
<a href="#/active">Active</a>
</li>

<li>
<a href="#/completed">Completed</a>
</li>
</ul>

<button
type="button"
className="clear-completed"
style={{ display: 'block' }}
});
};

handleRemoveTodo = (id) => {
this.setState(prevState => {
const newTodos = prevState.visibleTodos.filter(todo => (
todo.id !== id
));
return {
visibleTodos: newTodos,
todos: newTodos,
}
});
};

handlerFilter = (filterField) => {
this.setState(state => {
switch (filterField) {
case 'all':
return {
visibleTodos: state.todos,
};
case 'active':
return {
visibleTodos: state.todos.filter(todo => (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

state.todos.filter(todo => !todo.completed)

todo.completed === false
)),
};
case 'completed':
return {
visibleTodos: state.todos.filter(todo => (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

state.todos.filter(todo => todo.completed)

todo.completed === true
)),
};
}
});
};

handlerClearCompleted = () => {
this.setState(prevState => {
const newTodos = prevState.visibleTodos.filter(todo => (
todo.completed === false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

visibleTodos.filter(todo => !todo.completed)

));
return {
visibleTodos: newTodos,
todos: newTodos,
}
});
};

render() {
const { visibleTodos } = this.state;

return (
<section className="todoapp">
<header className="header">
<h1>todos</h1>
<TodoApp addTodo={this.addTodo} />
</header>

<TodoList
todos={visibleTodos}
changeCompleted={this.handlerChangeCompleted}
changeCompletedAll={this.handleChangeCompletedAll}
removeTodo={this.handleRemoveTodo}
/>
</footer>
</section>
);

<footer className="footer" style={{ display: 'block' }}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

по-хорошому Footer це окремий компонент

<span className="todo-count">
{`${visibleTodos
.filter(todo => !todo.completed)
.length} items left`
}
</span>

<TodosFilter
handlerFilter={this.handlerFilter}
/>

<button
type="button"
className="clear-completed"
style={{ display: 'block' }}
onClick={this.handlerClearCompleted}
>
Clear completed
</button>
</footer>
</section>
);
}
}

export default App;
50 changes: 50 additions & 0 deletions src/TodoApp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import propTypes from 'prop-types';

class TodoApp extends React.Component {
state = {
title: '',
};

onChangeInput = (event) => {
const { value } = event.target;

this.setState({ title: value });
};

onCLickEnter = (event) => {
const { title } = this.state;
if (event.keyCode === 13) {
event.preventDefault();

if (!title || title === ' ') {
return;
}

this.props.addTodo(title);
this.setState({ title: '' });
}
};

render() {
const { title } = this.state;

return (
<input
type="text"
name="title"
onChange={this.onChangeInput}
className="new-todo"
value={title}
placeholder="What needs to be done?"
onKeyUp={this.onCLickEnter}
/>
);
}
}

TodoApp.propTypes = {
addTodo: propTypes.func.isRequired,
};

export default TodoApp;
65 changes: 65 additions & 0 deletions src/TodoList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from 'react';
import propTypes from 'prop-types';
import classnames from 'classnames';
import './styles/todoList.css';

const TodoList = ({ todos, changeCompleted, changeCompletedAll, removeTodo}) => (
<section className="main" style={{ display: 'block' }}>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

перенеси display: block в класс main в css файл

<input
type="checkbox"
id="toggle-all"
className="toggle-all"
onChange={() => changeCompletedAll()}
/>
<label
htmlFor="toggle-all"
>
Mark all as complete
</label>

<ul className="todo-list">
{
todos.map(todo => {
const classes = classnames ({
'todo-active': todo.completed === false,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'todo-active': !todo.completed

'todo-completed': todo.completed === true,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'todo-completed': todo.completed

});

return (
<li className={classes} key={todo.id}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

а ось це вже окремий компонент Todo

<div className="view">
<input
type="checkbox"
name="completed"
className="toggle"
id={`todo-${todo.id}`}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

префикс todo не делает id более уникальным

checked={todo.completed}
onChange={() => changeCompleted(todo.id)}
/>
<label
htmlFor={`todo-${todo.id}`}
className={classes}
>
{ todo.title }
</label>
<button
type="button"
className="destroy"
onClick={() => removeTodo(todo.id)}
/>
</div>
</li>
)
})
}
</ul>
</section>
);

TodoList.propTypes = {
todos: propTypes.arrayOf().isRequired,
changeCompleted: propTypes.func,
changeCompletedAll: propTypes.func,
};

export default TodoList;
Loading