Skip to content

add task solution - #1332

Open
nkoropka wants to merge 3 commits into
mate-academy:masterfrom
nkoropka:develop
Open

add task solution#1332
nkoropka wants to merge 3 commits into
mate-academy:masterfrom
nkoropka:develop

Conversation

@nkoropka

Copy link
Copy Markdown

@Zoolgrand Zoolgrand left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Great job overall! I've found a couple of improvements you can add to your code — we need to refactor those two components and remove the code comments across the app.

Comment thread src/components/TodoItem.tsx Outdated
Comment on lines +18 to +82
const [isEditing, setIsEditing] = useState(false);
const [editingTitle, setEditingTitle] = useState(todo.title);

const isCancelledRef = useRef(false);

const handleSave = (event?: React.FormEvent) => {
if (event) {
event.preventDefault();
}

if (isCancelledRef.current || !isEditing) {
return;
}

setIsEditing(false);

const trimmedTitle = editingTitle.trim();

if (!trimmedTitle) {
onDelete(todo.id);

return;
}

if (trimmedTitle !== todo.title) {
dispatch({
type: 'RENAME',
payload: { id: todo.id, title: trimmedTitle },
});
}

onFocusNewTodo?.();
};

const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.key === 'Escape') {
isCancelledRef.current = true;
setEditingTitle(todo.title);

setIsEditing(false);
onFocusNewTodo?.();
}
};

const handleBlur = () => {
if (!isEditing) {
return;
}

if (isEditing && editingTitle !== todo.title) {
handleSave();
} else {
setIsEditing(false);
}
};

const handleDoubleClick = () => {
setIsEditing(true);
setEditingTitle(todo.title);
isCancelledRef.current = false;
};

useEffect(() => {
setEditingTitle(todo.title);
}, [todo.title]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Could you extract this logic into custom hook useTodoItem?

Comment thread src/components/TodoItem.tsx Outdated
value={editingTitle}
onChange={e => setEditingTitle(e.target.value)}
onBlur={handleBlur}
onKeyDown={handleKeyDown}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Please use onKeyUp to match the specification

Comment thread src/App.tsx Outdated
Comment on lines +16 to +18
useEffect(() => {
newTodoInputRef.current?.focus();
}, []);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

You already have autofocus on your input

Comment thread src/App.tsx Outdated
Comment on lines +11 to +45
const [title, setTitle] = useState('');
const [filter, setFilter] = useState<FilteredStatus>('all');

const newTodoInputRef = useRef<HTMLInputElement>(null);

useEffect(() => {
newTodoInputRef.current?.focus();
}, []);

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

const trimmedTitle = title.trim();

if (!trimmedTitle) {
return;
}

dispatch({ type: 'ADD', payload: trimmedTitle });

setTitle('');
};

const handleDeleteTodo = (todoId: number) => {
dispatch({ type: 'DELETE', payload: todoId });
newTodoInputRef.current?.focus();
};

const hasCompletedTodos = todos.some(t => t.completed);

const activeTodosCount = todos.filter(t => !t.completed).length;

const focusNewTodoInput = () => {
newTodoInputRef.current?.focus();
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Extract this logic into custom hook UseTodo

Comment thread src/App.tsx Outdated
Comment on lines +73 to +80
onClick={() => {
const areAllCompleted = todos.every(t => t.completed);

dispatch({
type: 'TOGGLE_ALL',
payload: !areAllCompleted,
});
}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Extract this into function

Comment thread src/App.tsx Outdated
Comment on lines +158 to +161
onClick={() => {
dispatch({ type: 'CLEAR' });
newTodoInputRef.current?.focus();
}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Here is smaller example but we can still extract this into function

Comment thread src/App.tsx Outdated
))}
</section>

{/* Hide the footer if there are no todos */}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Clear the comments

Comment thread src/components/TodoItem.tsx Outdated
onFocusNewTodo?.();
};

const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

rename this to handle keyUp event as requires specification

@nkoropka
nkoropka requested a review from Zoolgrand July 29, 2026 13:27

@2pasha 2pasha left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

good job! 👏

take a look on comments below ⬇️

Comment thread src/components/TodoItem.tsx Outdated
onChange={e => setEditingTitle(e.target.value)}
onBlur={handleBlur}
onKeyDown={handleKeyDown}
onKeyDown={handleKeyUp}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

should be

onKeyUp={handleKeyUp}

Comment thread src/hooks/useTodoItem.ts Outdated
Comment on lines +65 to +75
// const handleBlur = () => {
// if (!isEditing) {
// return;
// }

// if (isEditing && editingTitle !== todo.title) {
// handleSave();
// } else {
// setIsEditing(false);
// }
// };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

remove unused code

Comment thread src/App.tsx Outdated
Comment on lines +78 to +109
<a
href="#/"
className={classNames('filter__link', {
selected: filter === 'all',
})}
data-cy="FilterLinkAll"
onClick={() => setFilter('all')}
>
All
</a>

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

<a
href="#/completed"
className={classNames('filter__link', {
selected: filter === 'completed',
})}
data-cy="FilterLinkCompleted"
onClick={() => setFilter('completed')}
>
Completed
</a>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

you may add all your filter values to kind of array and map through it to avoid code duplication

@nkoropka
nkoropka requested a review from 2pasha July 30, 2026 09:41

@Zoolgrand Zoolgrand left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Good job.
Approved

There is still some comments in your code (search for {/ in code) could you remove this as well?

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