-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Develop #708
base: master
Are you sure you want to change the base?
Develop #708
Changes from 4 commits
67075bd
a04699d
0f96ab1
cd36639
24654eb
18bc34d
4c14365
a52d504
66c5340
999790f
4a270f1
00a1b2d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,24 +1,203 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/* eslint-disable max-len */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/* eslint-disable jsx-a11y/control-has-associated-label */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import React from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import React, { useEffect, useMemo, useState } from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { UserWarning } from './UserWarning'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { TodoList } from './Components/ToDoList'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { Notification } from './Components/errorNotification'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { client } from './utils/fetchClient'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { Error } from './types/Error'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const USER_ID = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { FilterType, Todo } from './types/Todo'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { getTodos, deleteTodo } from './api/todos'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { Footer } from './Components/Footer'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const USER_ID = 6340; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export const App: React.FC = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [todos, setTodos] = useState<Todo[]>([]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [filterBy, setFilterBy] = useState<FilterType>(FilterType.ALL); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [error, setError] = useState<Error>(Error.NONE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [inputQuery, setInputQuery] = useState(''); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [isLoading, setIsLoading] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
loadTodosData(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, []); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const loadTodosData = async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError(Error.NONE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const todosFromServer = await getTodos(USER_ID); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setTodos(todosFromServer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError(Error.LOAD); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const addNewTodo = async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!inputQuery.trim()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError(Error.NONE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError(Error.NONE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setIsLoading(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const newTodo = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
userId: USER_ID, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
title: inputQuery.trim(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
completed: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const response = await client.post<Todo>('/todos', newTodo); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
better to keep such functions in separated |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setTodos([...todos, response]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setInputQuery(''); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError(Error.ADD); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} finally { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setIsLoading(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const deleteTodoItem = async (todoId: number) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError(Error.NONE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await deleteTodo(todoId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setTodos(todos.filter(todo => todo.id !== todoId)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError(Error.DELETE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const handleFormSubmit = (e: React.FormEvent) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
e.preventDefault(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
addNewTodo(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const handleTodoDelete = (todoId: number) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
deleteTodoItem(todoId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setInputQuery(e.target.value); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const handleToggleAll = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const areAllCompleted = todos.every(todo => todo.completed); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const updatedTodos = todos.map(todo => ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
...todo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
completed: !areAllCompleted, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
})); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setTodos(updatedTodos); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const visibleTodos = useMemo(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return todos.filter((todo) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
switch (filterBy) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
case FilterType.ACTIVE: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return !todo.completed; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
case FilterType.COMPLETED: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return todo.completed; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
default: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to filter in case FilterType is All
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, [filterBy, todos]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!USER_ID) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return <UserWarning />; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const updateTodoItem = async (todoId: number, updatedTodo: Todo) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError(Error.NONE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await client.patch<Todo>(`/todos/${todoId}`, updatedTodo); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setTodos(prevTodos => prevTodos.map( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
todo => (todo.id === todoId ? updatedTodo : todo), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError(Error.UPDATE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const deleteAllCompletedTodos = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const completedTodos = todos.filter((todo) => todo.completed); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const deletePromises = completedTodos.map((todo) => deleteTodo(todo.id)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Promise.all(deletePromises) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.then(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setTodos((prevTodos) => prevTodos.filter((todo) => !todo.completed)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.catch(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError(Error.DELETE); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<section className="section container"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<p className="title is-4"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Copy all you need from the prev task: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<br /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<a href="https://github.com/mate-academy/react_todo-app-add-and-delete#react-todo-app-add-and-delete">React Todo App - Add and Delete</a> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</p> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<p className="subtitle">Styles are already copied</p> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</section> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="todoapp"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<h1 className="todoapp__title">todos</h1> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="todoapp__content"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<header className="todoapp__header"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type="button" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
className="todoapp__toggle-all active" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onClick={handleToggleAll} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<form onSubmit={handleFormSubmit}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<input | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type="text" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
className="todoapp__new-todo" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
placeholder="What needs to be done?" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
value={inputQuery} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onChange={handleInputChange} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</form> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</header> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{todos.length > 0 && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<TodoList | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
todos={visibleTodos} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onDelete={handleTodoDelete} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onUpdate={updateTodoItem} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Footer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
filterBy={filterBy} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setFilterBy={setFilterBy} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
todos={visibleTodos} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onDelete={deleteAllCompletedTodos} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{isLoading && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="loader-overlay"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="loader" /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{error && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Notification | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
error={error} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onErrorChange={setError} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import classNames from 'classnames'; | ||
import React from 'react'; | ||
import { Todo, FilterType } from '../types/Todo'; | ||
|
||
type Props = { | ||
filterBy: FilterType, | ||
setFilterBy: (value: FilterType) => void, | ||
todos: Todo[], | ||
onDelete: (id: number) => void, | ||
}; | ||
|
||
const filterOptions = Object.values(FilterType); | ||
|
||
export const Footer: React.FC<Props> = React.memo(({ | ||
filterBy, | ||
setFilterBy, | ||
todos, | ||
onDelete, | ||
}) => { | ||
const itemsLeftLength = todos.filter((todo) => !todo.completed).length; | ||
|
||
const deleteAllCompletedTodos = async () => { | ||
const completedTodoIds = todos.filter(todo => todo.completed); | ||
const idCompletesTodoId = completedTodoIds.map(todo => todo.id); | ||
|
||
await Promise.all(idCompletesTodoId.map(id => onDelete(id))); | ||
}; | ||
|
||
return ( | ||
<footer className="todoapp__footer"> | ||
<span className="todo-count"> | ||
{`${itemsLeftLength} items left`} | ||
</span> | ||
|
||
<nav className="filter"> | ||
{filterOptions.map((option) => { | ||
return ( | ||
<a | ||
key={option} | ||
href={`#/${option}`} | ||
className={classNames( | ||
'filter__link', | ||
{ selected: filterBy === option }, | ||
)} | ||
onClick={() => setFilterBy(option)} | ||
> | ||
{option} | ||
</a> | ||
); | ||
})} | ||
</nav> | ||
|
||
<button | ||
type="button" | ||
className="todoapp__clear-completed" | ||
onClick={deleteAllCompletedTodos} | ||
> | ||
Clear completed | ||
</button> | ||
</footer> | ||
); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commit all files and push them