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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# React ToDo App
- Replace `<your_account>` with your Github username in the [DEMO LINK](https://<your_account>.github.io/react_todo-app/)
- Replace `<your_account>` with your Github username in the [DEMO LINK](https://alenaloik.github.io/react_todo-app/)
- Follow the [React task guideline](https://github.com/mate-academy/react_task-guideline#react-tasks-guideline)

## Description
Expand Down
199 changes: 129 additions & 70 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,85 +1,144 @@
import React from 'react';
import React, { Component } from 'react';
import { TodoList } from './components/TodoList/TodoList';
import NewTodo from './components/NewTodo/NewTodo';
import { TodosFilter } from './components/TodosFilter/TodosFilter';

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

<input
className="new-todo"
placeholder="What needs to be done?"
/>
</header>
addTodo = (todo) => {
this.setState(prevState => ({
todos: [...prevState.todos, todo],
}));
}

<section className="main">
<input type="checkbox" id="toggle-all" className="toggle-all" />
<label htmlFor="toggle-all">Mark all as complete</label>
updateTodosToShow = (todoToShow) => {
this.setState({ showParam: todoToShow });
}

<ul className="todo-list">
<li>
<div className="view">
<input type="checkbox" className="toggle" id="todo-1" />
<label htmlFor="todo-1">asdfghj</label>
<button type="button" className="destroy" />
</div>
<input type="text" className="edit" />
</li>
handleRemuve = (id) => {
Copy link

Choose a reason for hiding this comment

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

Suggested change
handleRemuve = (id) => {
handleRemove = (id) => {

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

<li className="completed">
<div className="view">
<input type="checkbox" className="toggle" id="todo-2" />
<label htmlFor="todo-2">qwertyuio</label>
<button type="button" className="destroy" />
</div>
<input type="text" className="edit" />
</li>
handleRemuveCompleted = () => {
Copy link

Choose a reason for hiding this comment

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

Suggested change
handleRemuveCompleted = () => {
handleRemoveCompleted = () => {

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

<li className="editing">
<div className="view">
<input type="checkbox" className="toggle" id="todo-3" />
<label htmlFor="todo-3">zxcvbnm</label>
<button type="button" className="destroy" />
</div>
<input type="text" className="edit" />
</li>
toggleComplete = (id) => {
this.setState(prevState => ({
todos: prevState.todos.map((todo) => {
if (todo.id === id) {
return {
...todo,
completed: !todo.completed,
};
}

<li>
<div className="view">
<input type="checkbox" className="toggle" id="todo-4" />
<label htmlFor="todo-4">1234567890</label>
<button type="button" className="destroy" />
</div>
<input type="text" className="edit" />
</li>
</ul>
</section>
return todo;
}),
}));
}

<footer className="footer">
<span className="todo-count">
3 items left
</span>
toggleCompleteAll = () => {
if (this.state.todos.every(todo => (todo.completed))) {
this.setState(prevState => ({
todos: prevState.todos.map(todo => ({
...todo,
completed: false,
})),
}));
} else {
this.setState(prevState => ({
todos: prevState.todos.map(todo => ({
...todo,
completed: true,
})),
}));
}
}

<ul className="filters">
<li>
<a href="#/" className="selected">All</a>
</li>
render() {
let todoView = [];
const itemLeft = this.state.todos.filter(todo => (
!todo.completed)).length;

<li>
<a href="#/active">Active</a>
</li>
switch (this.state.showParam) {
case 'active':
todoView = [...this.state.todos].filter(todo => (
!todo.completed
));
break;
case 'completed':
todoView = [...this.state.todos].filter(todo => (
todo.completed
));
break;
default:
todoView = [...this.state.todos];
}
Comment on lines +76 to +89
Copy link

Choose a reason for hiding this comment

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

не роби це в рендері, винеси це в функцію getTodos(status)


<li>
<a href="#/completed">Completed</a>
</li>
</ul>
return (
<section className="todoapp">
<header className="header">
<h1>todos</h1>
<NewTodo addTodo={this.addTodo} />
</header>
Comment on lines +93 to +96
Copy link

Choose a reason for hiding this comment

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

це окремий компонент

Copy link
Owner Author

@AlenaLoik AlenaLoik May 12, 2020

Choose a reason for hiding this comment

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

То ж там одна стрічка і компонент, хіба так обов'язково робити з цього ще один компонент???

{(this.state.todos.length)
Copy link

Choose a reason for hiding this comment

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

деструктуровуй стейт

? (
<>
<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>
Comment on lines +101 to +108
Copy link

Choose a reason for hiding this comment

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

це в компонент Header

Copy link
Owner Author

Choose a reason for hiding this comment

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

Це відноситься до main

<TodoList
todos={todoView}
remuve={this.handleRemuve}
toggleComplete={this.toggleComplete}
/>
</section>

<button type="button" className="clear-completed">
Clear completed
</button>
</footer>
</section>
);
<footer className="footer">
<span className="todo-count">
{itemLeft}
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>
Comment on lines +116 to +136
Copy link

Choose a reason for hiding this comment

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

це окремий компонент, Footer

</>
) : ''}
</section>
);
}
}

export default App;
Empty file.
49 changes: 49 additions & 0 deletions src/components/NewTodo/NewTodo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React, { Component } from 'react';
import './NewTodo.css';
import PropTypes from 'prop-types';

class NewTodo extends Component {
state = {
content: '',
id: 1,
Copy link

Choose a reason for hiding this comment

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

чому 1? а якщо одразу є якісь завдання?

completed: false,
}

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

handleSubmit = (e) => {
e.preventDefault();

if (this.state.content) {
this.props.addTodo(this.state);
Copy link

Choose a reason for hiding this comment

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

не передавай весь стан, передавай готове todo наверх. addTodo має приймати todo, а не весь стан

Copy link
Owner Author

Choose a reason for hiding this comment

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

Але якщо я хочу щоб даний компонент відповідав повністю за створення нової todo, а зверху addTodo лише додавав її в список зі всіма готовими параметрами. Чи це погана практика???

Copy link
Owner Author

Choose a reason for hiding this comment

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

Якщо в стейті потрібно зберігати як можна менше, тоді я перенесу id & complited у функцію що передає todo. Так добре добре буде?


this.setState(prevState => ({
content: '',
id: prevState.id + 1,
Copy link

Choose a reason for hiding this comment

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

окей, тут добре)

}));
}
}

render() {
return (
<form onSubmit={this.handleSubmit}>
<input
onChange={this.handleChange}
value={this.state.content}
className="new-todo"
placeholder="What needs to be done?"
/>
</form>
);
}
}

export default NewTodo;

NewTodo.propTypes = {
addTodo: PropTypes.func.isRequired,
};
Empty file.
43 changes: 43 additions & 0 deletions src/components/TodoList/TodoList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React 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" />
Comment on lines +8 to +27
Copy link

Choose a reason for hiding this comment

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

Todo компонент, розбивай логіку на дрібніші компоненти

</li>
))}
</ul>
);

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

export const TodosFilter = ({ updateTodosToShow }) => (
<ul className="filters">
<li>
<a
href="#/"
onClick={() => (updateTodosToShow('all'))}
>
All
</a>
</li>
<li>
<a
href="#/active"
onClick={() => (updateTodosToShow('active'))}
>
Active
</a>
</li>
<li>
<a
href="#/completed"
onClick={() => (updateTodosToShow('completed'))}
>
Completed
</a>
</li>
Comment on lines +7 to +30
Copy link

Choose a reason for hiding this comment

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

все чим ці три фільтри відрізняються це один рядок. Ти можеш створити комонент Filter який буде приймати цей рядок і підставляти в потрібне місце, а потім через map зробити собі 3 фільтри. Коду менше буде

</ul>
);

TodosFilter.propTypes = {
updateTodosToShow: PropTypes.func.isRequired,
};
2 changes: 1 addition & 1 deletion src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ body {
transition: color 0.4s;
}

.todo-list li.completed label {
.todo-list li .completed label {
color: #d9d9d9;
text-decoration: line-through;
}
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ import App from './App';

ReactDOM.render(
<App />,
document.getElementById('root')
document.getElementById('root'),
);