-
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 #789
Develop #789
Conversation
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.
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.
Good job, but there is quite a bit of work to be done.
Also, pay attention to the previous comment about the visual component of the application.
src/components/NewTodo/NewTodo.tsx
Outdated
className="todoapp__new-todo" | ||
placeholder="What needs to be done?" | ||
value={newTodoTitle} | ||
onChange={(event) => setNewTodoTitle(event.target.value)} |
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.
onChange={(event) => setNewTodoTitle(event.target.value)} | |
onChange={({ target }) => setNewTodoTitle(target.value)} |
src/components/TodoApp/TodoApp.tsx
Outdated
const [filterKey, setFilterKey] = useState<FilterKey>(FilterKey.All); | ||
const [tempTodo, setTempTodo] = useState<Todo | null>(null); | ||
|
||
const areAllTodosCompleted = todos.every(({ completed }) => completed); |
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.
I know that "are" would be lexically correct, but in programming it is customary to use "is" in all cases :)
src/components/TodoApp/TodoApp.tsx
Outdated
{!!todos.length && ( | ||
<footer className="todoapp__footer" data-cy="Footer"> | ||
<span className="todo-count" data-cy="TodosCounter"> | ||
{`${activeTodos.length} items left`} |
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.
If there is one item, there should not be a plural in the text.
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.
<div | ||
data-cy="ErrorNotification" | ||
className={ | ||
classNames('notification is-danger is-light has-text-weight-normal', { |
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.
classNames('notification is-danger is-light has-text-weight-normal', { | |
classNames('notification', 'is-danger', 'is-light', 'has-text-weight-normal', { |
src/components/TodoItem/TodoItem.tsx
Outdated
const { title, completed, id } = todo; | ||
const [isBeingEdited, setIsBeingEdited] = useState(false); | ||
const [newTitle, setNewTitle] = useState(title); | ||
const editedInput = useRef<HTMLInputElement | null>(null); |
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.
const editedInput = useRef<HTMLInputElement | null>(null); | |
const editedInputRef = useRef<HTMLInputElement | null>(null); |
src/components/TodoItem/TodoItem.tsx
Outdated
ref={editedInput} | ||
onChange={handleChangeOfTitle} | ||
onKeyUp={handleKeyUp} | ||
onBlur={() => handleNewTitleSubmit()} |
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.
onBlur={() => handleNewTitleSubmit()} | |
onBlur={handleNewTitleSubmit} |
src/components/TodoItem/TodoItem.tsx
Outdated
className={classNames('modal overlay', { | ||
'is-active': todo.id === 0 || todoIdsWithLoader.includes(id), | ||
})} |
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.
className={classNames('modal overlay', { | |
'is-active': todo.id === 0 || todoIdsWithLoader.includes(id), | |
})} | |
className={classNames('modal', 'overlay', { | |
'is-active': !todo.id || todoIdsWithLoader.includes(id), | |
})} |
src/components/NewTodo/NewTodo.tsx
Outdated
event.preventDefault(); | ||
|
||
if (!newTodoTitle.trim()) { | ||
onNewError('Title should not be empty'); |
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.
It would be good to put error texts in a separate constant.
src/components/TodoApp/TodoApp.tsx
Outdated
todosToUpdate.forEach(todo => { | ||
updateTodo(todo.id, { completed: !todo.completed }) | ||
.then(() => { | ||
const todosCopy = [...todos]; | ||
const searchedTodo = todos.find( | ||
({ id }) => todo.id === id, | ||
) as Todo; | ||
|
||
searchedTodo.completed = !searchedTodo.completed; | ||
|
||
setTodos(todosCopy); | ||
}) | ||
.catch(() => onNewError(ErrorMessage.UnableUpdate)) | ||
.finally(() => setTodoIdsWithLoader( | ||
prevTodoIds => prevTodoIds.filter((todoId) => todoId !== todo.id), | ||
)); | ||
}); |
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.
Let's use Promise.all
for updating todos
src/components/TodoApp/TodoApp.tsx
Outdated
deleteTodo(todo.id) | ||
.then(() => { | ||
setTodos(prevTodos => prevTodos.filter(({ id }) => id !== todo.id)); | ||
}) | ||
.catch(() => onNewError(ErrorMessage.UnableDelete)) | ||
.finally(() => setTodoIdsWithLoader( | ||
prevTodoIds => prevTodoIds.filter((id) => todo.id !== id), | ||
)); |
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.
Also, try to use Promise.all
src/components/TodoItem/TodoItem.tsx
Outdated
<label | ||
className="todo__status-label" | ||
> |
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.
<label | |
className="todo__status-label" | |
> | |
<label className="todo__status-label"> |
src/components/TodoApp/TodoApp.tsx
Outdated
import { ErrorContext } from '../ErrorContextProvider/ErrorContextProvider'; | ||
import { ErrorMessage } from '../../types/ErrorMessage'; | ||
|
||
function getFilteredTodos(key: FilterKey, todos: Todo[]) { |
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.
I would move this to separate file as a helper function
src/components/TodoApp/TodoApp.tsx
Outdated
/> | ||
|
||
{!!todos.length && ( | ||
<footer className="todoapp__footer" data-cy="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.
I would move footer to separate component
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.
Good work 🚀
Approved, but left a few suggestions, take a look.
return client.delete(`/todos/${todoId}`); | ||
}; | ||
|
||
export const updateTodo = (todoId: number, changes: object) => { |
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.
changes
have to have another type instead of an object, as we update a todo in this case, and not every object suits.
You can use some of the utility types, for example, Partial
.
https://www.typescriptlang.org/docs/handbook/utility-types.html
export const ErrorContext = React.createContext({ | ||
errorMessage: ErrorMessage.None, | ||
setErrorMessage: () => {}, | ||
onNewError: () => {}, | ||
} as ErrorContextProps); |
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.
export const ErrorContext = React.createContext({ | |
errorMessage: ErrorMessage.None, | |
setErrorMessage: () => {}, | |
onNewError: () => {}, | |
} as ErrorContextProps); | |
export const ErrorContext = React.createContext<ErrorContextProps>({ | |
errorMessage: ErrorMessage.None, | |
setErrorMessage: () => {}, | |
onNewError: () => {}, | |
}); |
Don't use as
, createContext
accepts generic
<header className="todoapp__header"> | ||
{!!todos.length && ( | ||
<button | ||
type="button" | ||
data-cy="ToggleAllButton" | ||
className={classNames('todoapp__toggle-all', { | ||
active: isAllTodosCompleted, | ||
})} | ||
aria-label="toggle_all_todos" | ||
onClick={handleAllTodosToggle} | ||
/> | ||
)} | ||
|
||
<NewTodo | ||
setTempTodo={setTempTodo} | ||
tempTodo={tempTodo} | ||
/> | ||
</header> |
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.
You can create a Header
component
const todosCopy = [...todos]; | ||
const searchedTodo = todos.find( | ||
({ id: todoId }) => todoId === id, | ||
) as Todo; | ||
|
||
searchedTodo.completed = !event.target.checked; | ||
|
||
setTodos(todosCopy); |
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.
const todosCopy = [...todos]; | |
const searchedTodo = todos.find( | |
({ id: todoId }) => todoId === id, | |
) as Todo; | |
searchedTodo.completed = !event.target.checked; | |
setTodos(todosCopy); | |
setTodos(prevTodos => ( | |
prevTodos.map(todo => todoId === todo.id ? updatedTodo : todo) | |
)); |
Use map
instead of find
.
DEMO LINK