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

Develop #1060

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open

Develop #1060

wants to merge 38 commits into from

Conversation

przwojwwp
Copy link

Copy link

@Zibi95 Zibi95 left a comment

Choose a reason for hiding this comment

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

Hey. Good job. There are some things that has to be fixed. Also i have left some comments to improve the code.

  • Todo App content div is smaller than its supposed to be. Look how input is overflowing.
Screenshot 2024-10-07 at 08 40 14
  • The 'Toggle All' button should function by toggling all active to-dos to the completed state. When all to-dos are already completed, it should toggle them back to the active state.
    image

It looks like some tests didn't pass. Did the tests pass locally?

Comment on lines 6 to 7
const incompleteTodos = todos.filter(todo => todo.completed === false).length;
const isEveryIncompleted = todos.every(todo => !todo.completed);
Copy link

Choose a reason for hiding this comment

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

Think about caching results of these calculations.

export const Footer = () => {
const { todos, filter, setFilter, deleteMultipleTodos } = useTodoContext();

const incompleteTodos = todos.filter(todo => todo.completed === false).length;
Copy link

Choose a reason for hiding this comment

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

This variable name suggests that it holds all the incomplete to-dos themselves, not just the count of them.

Comment on lines 20 to 45
<a
href="#/"
className={`filter__link ${filter === 'All' ? 'selected' : ''}`}
data-cy="FilterLinkAll"
onClick={() => setFilter('All')}
>
All
</a>

<a
href="#/active"
className={`filter__link ${filter === 'Active' ? 'selected' : ''}`}
data-cy="FilterLinkActive"
onClick={() => setFilter('Active')}
>
Active
</a>

<a
href="#/completed"
className={`filter__link ${filter === 'Completed' ? 'selected' : ''}`}
data-cy="FilterLinkCompleted"
onClick={() => setFilter('Completed')}
>
Completed
</a>
Copy link

Choose a reason for hiding this comment

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

There is duplication in setting filters for different views (All, Active, Completed). This can be refactored to reduce redundancy.

Comment on lines 19 to 25
if (editingTodoId !== null) {
if (editingTitle.trim() === '') {
deleteTodo(editingTodoId);
} else {
updateTodoTitle(editingTodoId, editingTitle);
}
}
Copy link

Choose a reason for hiding this comment

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

The form submission logic could be refactored to avoid deeply nested if conditions.

Suggested change
if (editingTodoId !== null) {
if (editingTitle.trim() === '') {
deleteTodo(editingTodoId);
} else {
updateTodoTitle(editingTodoId, editingTitle);
}
}
if (editingTodoId === null) {
return
}
if (editingTitle.trim() === '') {
deleteTodo(editingTodoId);
} else {
updateTodoTitle(editingTodoId, editingTitle);
}

Comment on lines 29 to 31
if (headerInputRef.current) {
headerInputRef.current.focus();
}
Copy link

Choose a reason for hiding this comment

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

Create a utility function that enables triggering focus on headerInputRef.

return (
<section className="todoapp__main" data-cy="TodoList">
{/* This is a completed todo */}
{filteredTodos.map(todo => (
Copy link

Choose a reason for hiding this comment

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

Remember about destructure syntax.

Comment on lines 39 to 64
useEffect(() => {
if (editingTodoId !== null && renameInputRef.current) {
renameInputRef.current.focus();
}

const handleClickOutsideForm = (event: MouseEvent) => {
if (
editingTodoId !== null &&
renameInputRef.current &&
!renameInputRef.current.contains(event.target as Node)
) {
if (editingTitle.trim() === '') {
deleteTodo(editingTodoId);
} else {
updateTodoTitle(editingTodoId, editingTitle);
}

setEditingTodoId(null);

setTimeout(() => {
if (headerInputRef.current) {
headerInputRef.current.focus();
}
}, 0);
}
};
Copy link

Choose a reason for hiding this comment

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

You don't need this logic. You can just simply listen for onBlur event on the input

Comment on lines 66 to 81
const handlePressEscape = (event: KeyboardEvent) => {
if (event.key === 'Escape' && editingTodoId !== null) {
setEditingTodoId(null);
}
};

if (editingTodoId !== null) {
document.addEventListener('mousedown', handleClickOutsideForm);
document.addEventListener('keyup', handlePressEscape);
}

return () => {
document.removeEventListener('mousedown', handleClickOutsideForm);
document.removeEventListener('keyup', handlePressEscape);
};
});
Copy link

Choose a reason for hiding this comment

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

Add the onKeyUp event to the input. You don't need to listen for the event if it's not necessary.

Copy link

Choose a reason for hiding this comment

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

I suggest creating a TodoItem component. This way, you can colocate the logic and state within that component.

Copy link

Choose a reason for hiding this comment

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

Think about optimizing it a bit. Use useMemo and useCallback.

@przwojwwp przwojwwp requested a review from Zibi95 October 8, 2024 08:08
Copy link

@Zibi95 Zibi95 left a comment

Choose a reason for hiding this comment

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

Good job! There are still some things that you should change.

<a
key={key}
href={href}
className={`filter__link ${filter === currentFilter ? 'selected' : ''}`}
Copy link

Choose a reason for hiding this comment

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

Remember that you have installed lib to handle this.

Copy link
Author

Choose a reason for hiding this comment

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

What lib?

Copy link

Choose a reason for hiding this comment

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

classnames

Comment on lines 53 to 57
useEffect(() => {
if (editingTodoId !== null && renameInputRef.current) {
renameInputRef.current.focus();
}
});
Copy link

Choose a reason for hiding this comment

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

It's unnecessary to run on every change. Use a dependency array.

Comment on lines 6 to 44
const [editingTodoId, setEditingTodoId] = useState<number | null>(null);
const [editingTitle, setEditingTitle] = useState('');
const renameInputRef = useRef<HTMLInputElement | null>(null);
const checkboxRef = useRef<HTMLInputElement | null>(null);
const { toggleTodoStatus, updateTodoTitle, deleteTodo, filteredTodos } =
useTodoContext();

const handleSubmit = useCallback(
(event: React.FormEvent) => {
event.preventDefault();

if (editingTodoId === null) {
return;
}

if (editingTitle.trim() === '') {
deleteTodo(editingTodoId);
} else {
updateTodoTitle(editingTodoId, editingTitle);
}

setEditingTodoId(null);
},
[deleteTodo, editingTitle, editingTodoId, updateTodoTitle],
);

const handleDoubleClick = useCallback((id: number, currentTitle: string) => {
setEditingTodoId(id);
setEditingTitle(currentTitle);
}, []);

const handleOnBlur = useCallback(
(event: React.FormEvent) => {
handleSubmit(event);
},
[handleSubmit],
);

const handleKeyUp = useCallback(
Copy link

Choose a reason for hiding this comment

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

You've created the TodoItem component, but the logic for editing hasn't been moved there yet. You can move the rename input state and also the editingTodoId. This way, you don't need to track which todo is being edited by its ID; you can simply use a state like isEdited

Comment on lines 119 to 131
const value = {
todos,
addTodo,
toggleTodoStatus,
toggleMultipleTodosStatus,
updateTodoTitle,
deleteTodo,
headerInputRef,
filter,
setFilter,
filteredTodos,
deleteMultipleTodos,
};
Copy link

Choose a reason for hiding this comment

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

This one also need to be wrapped in memo. This object is recreated on every rerender.

Comment on lines 119 to 131
const value = {
todos,
addTodo,
toggleTodoStatus,
toggleMultipleTodosStatus,
updateTodoTitle,
deleteTodo,
headerInputRef,
filter,
setFilter,
filteredTodos,
deleteMultipleTodos,
};
Copy link

Choose a reason for hiding this comment

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

@przwojwwp przwojwwp requested a review from Zibi95 October 10, 2024 10:47
Copy link

@natalia-klonowska natalia-klonowska left a comment

Choose a reason for hiding this comment

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

update your demo as your last deployment was 4 days ago and doesn't include all the fixes you've made

@przwojwwp
Copy link
Author

localy all tests passed

Copy link

@Zibi95 Zibi95 left a comment

Choose a reason for hiding this comment

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

Good job!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants