Skip to content

solution#1295

Open
danf4691 wants to merge 11 commits intomate-academy:masterfrom
danf4691:develop
Open

solution#1295
danf4691 wants to merge 11 commits intomate-academy:masterfrom
danf4691:develop

Conversation

@danf4691
Copy link
Copy Markdown

@danf4691 danf4691 commented Apr 6, 2026

Copy link
Copy Markdown

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Choose a reason for hiding this comment

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

Review Summary

This is a strong effort, and the core functionality of the ToDo app is working correctly. However, a few changes are needed to meet all the project's technical requirements before this can be approved. Please address the following points:

  • Component Structure: The logic for rendering a single todo item should be extracted from Section.tsx into its own reusable TodoItem component. This is a key requirement for code modularity. [CHECKLIST ITEM #3]
  • Use of classnames library: The project checklist requires using the classnames library for conditionally applying CSS classes instead of template literals. Please refactor this in Header.tsx, Footer.tsx, and Section.tsx. [CHECKLIST ITEM #7]
  • Constants for Filters: Avoid using hardcoded strings like 'all', 'active', and 'completed' for filtering. These should be defined as constants and imported where needed to prevent typos and improve maintainability. [CHECKLIST ITEM #10]
  • Correct Event Handler: The requirement for canceling an edit is to use the onKeyUp event for the 'Escape' key, but onKeyDown is currently used in Section.tsx.

Once these checklist items are addressed, your solution will be in great shape!


✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨

Important

Fix the issues, commit the changes, and then re-request my review using the Re-request review button2 in the Reviewers tab.

Tip

If you have any comments about this review, please leave a message in the Add a comment section below and mention me with the @mateacademy-ai-mentor tag3.
I will read your message during my next review of your pull request. Please do not reply directly to my comments, as that feature is not supported yet.

Caution

Do not close the pull request until the review is complete. Closing it early can lead to unexpected behavior and disrupt the review process.

Footnotes

  1. Rate AI review example

  2. Re-request AI review example

  3. Add AI review comments example

{todos.length > 0 && (
<button
type="button"
className={`todoapp__toggle-all ${todos.every(todo => todo.completed) ? 'active' : ''}`}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This violates checklist item #7: 'Use classnames lib for calculated classes'. While using a template literal works, the project requirements specifically ask for the classnames library to handle conditional classes. It helps keep the JSX cleaner, especially with more complex logic.

<nav className="filter" data-cy="Filter">
<a
href="#/"
className={`filter__link${filter === 'all' ? ' selected' : ''}`}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

While this works, checklist item #7 requires using the classnames library for dynamically applying classes. This would make the class string construction cleaner, especially with multiple conditional classes. This comment applies to all three filter links.

href="#/"
className={`filter__link${filter === 'all' ? ' selected' : ''}`}
data-cy="FilterLinkAll"
onClick={e => handleFilterChange(e, 'all')}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

According to checklist item #10, it's best to avoid using 'magic strings' like 'all'. You should define these filter types as constants in a separate file or at the top level and import them where needed. This prevents typos and makes the code easier to maintain. This applies to 'active' and 'completed' filters as well.

Comment on lines +47 to +119
{filteredTodos.map(todo => (
<div
key={todo.id}
data-cy="Todo"
className={`todo ${todo.completed ? 'completed' : ''}`}
>
<label className="todo__status-label">
<input
data-cy="TodoStatus"
type="checkbox"
className="todo__status"
aria-label="Mark todo"
checked={todo.completed}
onChange={() => {
updateMark(todo.id, !todo.completed);
}}
/>
</label>

{editingId === todo.id ? (
<input
data-cy="TodoTitleField"
type="text"
className="todo__title-field"
value={editingTitle}
autoFocus
onChange={e => setEditingTitle(e.target.value)}
onBlur={() => {
const trimmed = editingTitle.trim();

if (trimmed) {
updateOnBlur(todo.id, trimmed);
} else {
deleteTodo(todo.id);
}

setEditingId(null);
}}
onKeyDown={e => {
if (e.key === 'Enter') {
(e.target as HTMLInputElement).blur();
} else if (e.key === 'Escape') {
setEditingId(null);
}
}}
/>
) : (
<span
data-cy="TodoTitle"
className="todo__title"
onDoubleClick={() => {
setEditingId(todo.id);
setEditingTitle(todo.title);
}}
>
{todo.title}
</span>
)}

{editingId !== todo.id && (
<button
type="button"
className="todo__remove"
data-cy="TodoDelete"
onClick={() => {
deleteTodo(todo.id);
}}
>
×
</button>
)}
</div>
))}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This violates Task Checklist item #3: 'Code should be split into small, reusable components if it possible (Filter, TodoList, Todo, NewTodo)'. The logic for rendering and managing a single todo item is quite complex and should be extracted into a separate TodoItem component. This would make the Section component (acting as a TodoList) cleaner and the TodoItem logic more reusable.

<div
key={todo.id}
data-cy="Todo"
className={`todo ${todo.completed ? 'completed' : ''}`}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This violates Basic React Checklist item #7: 'Use classnames lib for calculated classes.' The classnames library should be used here to conditionally apply the completed class instead of a template literal.


setEditingId(null);
}}
onKeyDown={e => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The task description requires using onKeyUp to handle the 'Escape' key press for canceling edits. You are using onKeyDown.

Comment on lines +12 to +21
switch (filter) {
case 'all':
return todos;
case 'active':
return todos.filter(todo => !todo.completed);
case 'completed':
return todos.filter(todo => todo.completed);
default:
return 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.

This violates checklist item #10: 'Do not rely on the unknown string, make constants for this.' You should define filter values as constants (e.g., in an object or enum) and use them here and in the Footer component to avoid potential typos and improve code maintainability.

src/App.tsx Outdated
Comment on lines +27 to +28
const [editingId, setEditingId] = React.useState<number | null>(null);
const [editingTitle, setEditingTitle] = React.useState<string>('');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Managing the state for editing a single todo item (editingId, editingTitle) at this top-level component is inefficient. Every keystroke during an edit will cause the entire App component and all its children to re-render. This state should be moved down into the component responsible for rendering the individual todo item (which is currently Section, but would ideally be a TodoItem component).


return saved ? JSON.parse(saved) : [];
});
const [filter, setFilter] = React.useState<Filter>('all');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This violates checklist item #10, which advises against using 'magic strings'. You should initialize the filter state with a constant (e.g., FILTERS.all) instead of the hardcoded string 'all'. This improves code maintainability and prevents potential typos.

Copy link
Copy Markdown

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Choose a reason for hiding this comment

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

Review Summary

Great job on the progress so far! You've successfully implemented many of the previous suggestions, like using the classnames library and filter constants.

However, a few changes are needed before this can be approved. The tests are currently failing because of a build error. To fix this, you need to add the .tsx extension to your local component imports, for example: import { useTodos } from './TodoContext.tsx';.

The most critical architectural issue is that the logic for a single todo item still resides within src/components/Section.tsx. This must be extracted into its own reusable TodoItem.tsx component, as this is a core requirement of the task [CHECKLIST ITEM #3].

Additionally, please address two smaller points for better code quality:

  • The component src/components/NewTodo.tsx should be renamed to something more descriptive like TodoEditForm.tsx, as it's used for editing.
  • The method for generating IDs with +new Date() can create duplicates. Please use a more robust method like an internal counter to ensure uniqueness [CHECKLIST ITEM #4].

You're very close to finishing! Address these points, and your solution will be in great shape.


✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨

Important

Fix the issues, commit the changes, and then re-request my review using the Re-request review button2 in the Reviewers tab.

Tip

If you have any comments about this review, please leave a message in the Add a comment section below and mention me with the @mateacademy-ai-mentor tag3.
I will read your message during my next review of your pull request. Please do not reply directly to my comments, as that feature is not supported yet.

Caution

Do not close the pull request until the review is complete. Closing it early can lead to unexpected behavior and disrupt the review process.

Footnotes

  1. Rate AI review example

  2. Re-request AI review example

  3. Add AI review comments example

case FILTER_ALL:
return todos;
case FILTER_ACTIVE:
return todos.filter(todo => !todo.completed);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Using +new Date() for IDs can lead to duplicates if todos are created very quickly. Checklist item #4 suggests using an internal counter to guarantee unique IDs. This would be a more robust approach.

FILTER_ALL,
FILTER_ACTIVE,
FILTER_COMPLETED,
} from './types/Filter';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The name NewTodo is misleading, as this component is used for editing an existing todo, not creating a new one. To improve clarity and align with checklist item #4 ('A variable name should describe what is stored in it'), consider renaming it to something like TodoEditForm.

}

const newTodo: Todo = {
id: +new Date(),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Using +new Date() for IDs can lead to duplicates if multiple todos are created in quick succession (within the same millisecond). This violates checklist item #4, which states that IDs should be unique. A more reliable approach, as suggested in the checklist, would be to use an internal counter.

todo: Todo;
};

export const NewTodo: React.FC<Props> = ({ todo }) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The component name NewTodo is a bit misleading, as this component is used for editing an existing todo, not creating a new one. According to the checklist, NewTodo is intended for creating new todos. A name like TodoEditForm or EditingTodo would better describe this component's function and avoid confusion.

Comment on lines +27 to +61
<div
key={todo.id}
data-cy="Todo"
className={classNames('todo', { completed: todo.completed })}
>
<label className="todo__status-label">
<input
data-cy="TodoStatus"
type="checkbox"
className="todo__status"
aria-label="Mark todo"
checked={todo.completed}
onChange={() => {
updateMark(todo.id, !todo.completed);
}}
/>
</label>

{editingId === todo.id ? (
<NewTodo todo={todo} />
) : (
<span
data-cy="TodoTitle"
className="todo__title"
onDoubleClick={() => {
setEditingId(todo.id);
setEditingTitle(todo.title);
}}
>
{todo.title}
</span>
)}

{editingId !== todo.id && <RemoveTodo todo={todo} />}
</div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This block of code, which renders a single todo item, should be extracted into a separate, reusable component (e.g., TodoItem.tsx). This was a high-priority requirement from the previous review and is essential for meeting the task's component structure guidelines. Keeping this logic inside the Section component's map function violates checklist item #3: 'Code should be split into small, reusable components if it possible (Filter, TodoList, Todo, NewTodo)'.

Copy link
Copy Markdown

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Choose a reason for hiding this comment

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

Review Summary

I am approving your solution as an educational override to help you move forward, as you've done a fantastic job implementing the core features and refactoring the components!

To ensure your future projects build successfully, please focus on a few key areas. The main issue causing the build to fail is that all local imports are missing their file extensions (e.g., .tsx, .ts). For example, import App from './App' should be import App from './App.tsx'. Also, remember to use consistent PascalCase naming for components and files, like renaming the NewTodo component to TodoEditForm and the todoContext.tsx file to TodoContext.tsx.

You've handled the complex state management and componentization very well. Keep up the great work!


✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨

Important

Fix the issues, commit the changes, and then re-request my review using the Re-request review button2 in the Reviewers tab.

Tip

If you have any comments about this review, please leave a message in the Add a comment section below and mention me with the @mateacademy-ai-mentor tag3.
I will read your message during my next review of your pull request. Please do not reply directly to my comments, as that feature is not supported yet.

Caution

Do not close the pull request until the review is complete. Closing it early can lead to unexpected behavior and disrupt the review process.

Footnotes

  1. Rate AI review example

  2. Re-request AI review example

  3. Add AI review comments example

Comment on lines +11 to +14
import { Header } from './components/Header';
import { Section } from './components/Section';
import { Footer } from './components/Footer';
import { TodoContext } from './components/TodoContext';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

As requested in the previous review, please add the .tsx extension to your local component imports. This is important for the build process to work correctly. For example, import { Header } from './components/Header.tsx';.

FILTER_ACTIVE,
FILTER_COMPLETED,
} from './types/Filter';
// eslint-disable-next-line import/extensions
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The component name NewTodo is confusing here because this component is used for editing existing todos, not creating new ones. It should be renamed to TodoEditForm to match the filename and its purpose. This was also mentioned in the previous review.

return todos.filter(todo => todo.completed);
default:
return 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.

The key prop should only be passed to components inside an array from the parent component, not on elements inside the component itself. The key is already correctly applied in Section.tsx where you map over the todos. This key prop is redundant and should be removed.

@@ -1,156 +1,44 @@
/* eslint-disable jsx-a11y/control-has-associated-label */
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

As a convention, component and context filenames in React should use PascalCase. Please rename this file to TodoContext.tsx.

Comment on lines +8 to +9
} from '../types/Filter';
import { TodoContext } from './TodoContext';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

As mentioned in the previous review, please add file extensions to all local imports. For example, from '../types/Filter' should be from '../types/Filter.ts', and from './TodoContext' should be from './TodoContext.tsx'. This is a critical fix for the build process to work correctly.

Comment on lines +2 to +3
import { Filter, FILTER_ALL } from '../types/Filter';
import { Todo } from '../types/Todo';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

As requested in the previous review, it's critical to add file extensions to all local imports. This is necessary for the build process to work correctly. Please update these paths to ../types/Filter.ts and ../types/Todo.ts.

@@ -3,7 +3,12 @@ import { createRoot } from 'react-dom/client';
import './styles/index.scss';

import { App } from './App';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

As mentioned in previous reviews, please add the .tsx file extension to your local component imports. This should be ./App.tsx.

import './styles/index.scss';

import { App } from './App';
import { TodoProvider } from './components/TodoContext';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This import has two issues. First, the filename is todoContext.tsx (lowercase 't'), but you're importing from TodoContext (PascalCase). File paths are case-sensitive. Second, you must include the .tsx extension for local imports. The file should also be renamed to TodoContext.tsx to follow React conventions.


&__new-todo {
width: 100%;
width: 85%;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Using a percentage width like 85% can cause layout inconsistencies, as it will likely leave a gap on the right side of the input field, which does not match the demo's appearance. A more robust solution is to set width: 100% and add box-sizing: border-box;. This will ensure the input field correctly spans the full width of its container while respecting its padding.


&__title-field {
width: 100%;
width: 93.8%;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Using a fixed percentage like 93.8% can be brittle and might not adapt well if the parent container's padding or other properties change. A more robust approach is to set width: 100% and box-sizing: border-box;. This will ensure the input field fills its container while its padding and border are contained within that width.

@danf4691
Copy link
Copy Markdown
Author

danf4691 commented Apr 6, 2026

You said in the previous review you would aprouve my solution. Can you please do It @mateacademy-ai-mentor

@danf4691
Copy link
Copy Markdown
Author

danf4691 commented Apr 6, 2026

I tried everything I could for the tests, they were all passing on my end. They were passing here too before I did the first request from mateacademy-ai-mentor

Copy link
Copy Markdown

@IanLuan IanLuan left a comment

Choose a reason for hiding this comment

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

The tests are failing because a filename case mismatch is blocking the build. The file is named todoContext.tsx (lowercase "t"), but in index.tsx, it is being imported as ./components/TodoContext. Please ensure the filename and the import statement are consistent and push the fix so the tests can pass.

@danf4691 danf4691 requested a review from IanLuan April 9, 2026 18:16
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