Conversation
mateacademy-ai-mentor
left a comment
There was a problem hiding this comment.
Review Summary
Great job implementing the core functionality for adding and displaying todos! The form validation logic is also working well. However, there are a few critical issues that need to be addressed before this can be approved.
Here are the main points to work on:
- Data Structure & Logic: The
Todointerface insrc/services/todo.tsis missing the requireduserobject. This has led to the data preparation logic being placed inTodoList.tsx. Please update theTodotype and move the user-finding logic intoApp.tsxto align with the project's architecture guidelines [CHECKLIST ITEM #5]. - Runtime Safety: In
TodoList.tsx, using the non-null assertion operator (!) is unsafe and could crash the app if a user isn't found. You should add a check to ensure the user exists before rendering [CHECKLIST ITEM #4]. - ID Generation Bug: The logic for creating a new todo ID in
App.tsxisgetNextId(todos) + 1. SincegetNextIdalready returns the correct next ID, you are adding 1 twice and skipping IDs. Please use the value fromgetNextId(todos)directly. - Missing Requirements: The form in
App.tsxis missing the required<label>elements for accessibility, and the email link inUserInfo.tsxneeds themailto:prefix to function correctly.
Once these issues are resolved, 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
src/components/UserInfo/UserInfo.tsx
Outdated
|
|
||
| export const UserInfo = ({ user }: Props) => { | ||
| return ( | ||
| <a className="UserInfo" href={user.email}> |
There was a problem hiding this comment.
The href attribute for an email link should start with mailto:. Without this prefix, clicking the link won't open the user's default email client.
| type Props = { | ||
| todo: Todo; | ||
| user: User; | ||
| }; |
There was a problem hiding this comment.
This component's props signature (todo and user as separate props) indicates that the logic for associating a user with a todo is happening outside the root App component. This violates checklist item #5: 'Prepare data in one place (App component) and pass it to child components'.
The App component should be responsible for creating a complete data object for each todo, including its user. This component should then receive a single prop (e.g., todoWithUser) that contains all the necessary information, simplifying the data flow.
src/components/TodoList/TodoList.tsx
Outdated
| const findUserById = (usersArr: User[], id: number): User | undefined => { | ||
| return usersArr.find(user => user.id === id); | ||
| }; |
There was a problem hiding this comment.
This violates checklist item #5: 'Prepare data in one place (App component) and pass it to child components. Don't use import keyword in non-root components'. The logic to find the user associated with a todo should be handled in the App component. The App should prepare an array of 'todos with users' and pass that down to TodoList, making this component purely for presentation.
src/components/TodoList/TodoList.tsx
Outdated
| return ( | ||
| <section className="TodoList"> | ||
| {todos.map(todo => { | ||
| const user: User = findUserById(users, todo.userId)!; |
There was a problem hiding this comment.
Using the non-null assertion operator ! is unsafe here. If findUserById returns undefined (for example, if a todo has a userId that doesn't exist in the users array), the application will crash. This violates checklist item #4. You should add a check to ensure user exists before rendering the TodoInfo component.
src/components/TodoList/TodoList.tsx
Outdated
| const user: User = findUserById(users, todo.userId)!; | ||
|
|
||
| return ( | ||
| <TodoInfo key={todo.id} user={user} todo={todo} data-id={todo.id} /> |
There was a problem hiding this comment.
The data-id prop is redundant here. The requirement is for the rendered HTML element to have the data-id attribute. Your TodoInfo component already correctly sets this attribute on its root <article> element. You can safely remove this prop from the TodoInfo invocation.
src/App.tsx
Outdated
| return Math.max(...arr.map(t => t.id)) + 1; | ||
| }; | ||
|
|
||
| const selectedUser = users.find(u => u.id === Number(selectUser)); |
There was a problem hiding this comment.
This violates checklist item #1: 'Don't use one-letter variable naming'. Please use a more descriptive name, for example, user.
src/App.tsx
Outdated
| } | ||
|
|
||
| const newTodo: Todo = { | ||
| id: getNextId(todos) + 1, |
There was a problem hiding this comment.
The logic for generating the new id is incorrect. The getNextId function already calculates the next available ID by finding the maximum ID and adding 1. By adding 1 again here, you are skipping an ID every time a new todo is created. You should just use the value returned from getNextId(todos) directly.
src/App.tsx
Outdated
| <div className="field"> | ||
| <input type="text" data-cy="titleInput" /> | ||
| <span className="error">Please enter a title</span> | ||
| <input |
There was a problem hiding this comment.
The task requires adding labels where they are needed for form fields. This input is missing a corresponding <label> element for accessibility. Consider adding one. Also, a placeholder attribute could improve user experience.
src/App.tsx
Outdated
|
|
||
| <div className="field"> | ||
| <select data-cy="userSelect"> | ||
| <select |
There was a problem hiding this comment.
The task requires adding labels where they are needed for form fields. This select element is missing a corresponding <label> element for better accessibility and user guidance.
| export interface Todo { | ||
| id: number; | ||
| title: string; | ||
| completed?: boolean; | ||
| userId: User['id']; | ||
| } |
There was a problem hiding this comment.
The task description states: "each TODO item must have the following fields: ... and a user object containing: id, name, username, email". This interface is missing the user property.
Adding an optional user property here (e.g., user?: User;) would align this type with the requirements. It would also enable you to prepare the data correctly in the App component by combining todos and users in one place, which is a requirement from checklist item #5.
…ng requirements malto:
mateacademy-ai-mentor
left a comment
There was a problem hiding this comment.
Review Summary
Great work on refactoring the data handling! Moving the logic to the App component has really improved the structure. I am requesting a few changes to address some critical issues before this can be approved.
First, the form in App.tsx is missing <label> elements for the input and select fields. This is a key accessibility requirement from the task description that needs to be added.
Second, the use of the non-null assertion operator (!) in App.tsx when matching todos to users is unsafe and could cause the app to crash if a user isn't found. Please handle this case more safely, for example, by filtering out todos that don't have a matching user.
Once these two points are fixed, 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
| type Props = { | ||
| todo: Todo; | ||
| user: User; | ||
| }; |
There was a problem hiding this comment.
The user prop is redundant here because the user object is already a property of the todo object. To make the component's API cleaner, you can simplify the props to only accept the todo object.
For example:
// Props would be just:
type Props = {
todo: Todo;
};
// Then, inside the component, you'd use `todo.user`:
export const TodoInfo = ({ todo }: Props) => {
// ...
return (
// ...
<UserInfo user={todo.user} />
// ...
);
};| import { useState } from 'react'; | ||
|
|
||
| export const App = () => { | ||
| const users: User[] = [...usersFromServer]; |
There was a problem hiding this comment.
This creates an unnecessary copy of the usersFromServer array. Since you are not mutating this array, you can directly assign it. This violates checklist item #3: 'If you are using a non-mutating array method, you don't need to create a copy of the array'.
src/App.tsx
Outdated
| const [todos, setTodos] = useState<Todo[]>(() => | ||
| todosFromServer.map(t => ({ | ||
| ...t, | ||
| user: users.find(u => u.id === t.userId)!, |
There was a problem hiding this comment.
Using the non-null assertion operator (!) here is unsafe. If a todo from the server has a userId that doesn't exist in usersFromServer, the application will crash. It's better to handle this possibility, for example, by filtering out any todos that don't have a matching user.
src/App.tsx
Outdated
| title: title, | ||
| completed: false, | ||
| userId: selectedUser!.id, | ||
| user: findUserById(users, selectedUser!.id)!, |
There was a problem hiding this comment.
This line re-finds the user, but you already have the complete user object stored in the selectedUser constant. You can simplify this and avoid repeating logic by using user: selectedUser!. This aligns with checklist item #2: 'Don't repeat yourself'.
| <h1>Add todo form</h1> | ||
|
|
||
| <form action="/api/todos" method="POST"> | ||
| <form action="/api/todos" method="POST" onSubmit={handleSubmit}> |
There was a problem hiding this comment.
The form is missing <label> elements for the title input and user select, which is a requirement from the task description (add labels and placeholders where they are needed). Labels are important for accessibility. Each form control should have an associated <label>. This was also pointed out in the previous review.
| // const findUserById = (usersArr: User[], id: number): User | undefined => { | ||
| // return usersArr.find(user => user.id === id); | ||
| // }; | ||
|
|
||
| // const todosWithUsers = todos.filter(todo => | ||
| // users.some(u => u.id === todo.userId), | ||
| // ); |
There was a problem hiding this comment.
It's good practice to remove commented-out code that is no longer needed. This improves the readability and maintainability of the component.
| key={todo.id} | ||
| user={todo.user} | ||
| todo={todo} | ||
| data-id={todo.id} |
There was a problem hiding this comment.
The data-id attribute is already being set within the TodoInfo component itself (using the id from the todo object). Passing it as a prop here is unnecessary because the TodoInfo component doesn't expect or use a data-id prop. You can safely remove this line.
mateacademy-ai-mentor
left a comment
There was a problem hiding this comment.
Review Summary
Great job on this task and for addressing the previous feedback! I am approving this solution as an educational override to help you move forward, but there are a couple of important points to review that are causing the component tests to fail.
The main issue is in src/components/TodoList/TodoList.tsx, where you're passing an unnecessary data-id prop to the TodoInfo component. This component already sets its own data-id internally, and removing this prop from the parent will fix the failing tests. For even cleaner code, I also suggest removing the redundant user prop from TodoInfo (since it's already in the todo object) and using more descriptive variable names like todo instead of t in App.tsx [CHECKLIST ITEM #1].
You've made great progress, keep up the excellent work!
✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨
Footnotes
| key={todo.id} | ||
| user={todo.user} | ||
| todo={todo} | ||
| data-id={todo.id} |
There was a problem hiding this comment.
This data-id prop is not needed here. The TodoInfo component already receives the entire todo object and is responsible for setting its own data-id attribute internally. Passing props that a component doesn't expect can lead to confusion.
| import { useState } from 'react'; | ||
|
|
||
| export const App = () => { | ||
| const users: User[] = [...usersFromServer]; |
There was a problem hiding this comment.
This copy of usersFromServer is not needed. Since the original array isn't being modified, you can assign it directly. This relates to checklist item #3 about avoiding unnecessary copies.
| const users: User[] = [...usersFromServer]; | ||
| const [todos, setTodos] = useState<Todo[]>(() => | ||
| todosFromServer | ||
| .map(t => { |
There was a problem hiding this comment.
This violates checklist item #1: 'Don't use one-letter variable naming.' Please use a more descriptive name like todo instead of t. This also applies to other single-letter variables in your array methods in this file.
|
|
||
| type Props = { | ||
| todo: Todo; | ||
| user: User; |
There was a problem hiding this comment.
The user prop is redundant because the todo object already contains the full user object. You can simplify this component by removing this prop and using todo.user directly when passing it to the UserInfo component.
<your_account>with your Github username in the DEMO LINK and add it to the PR description.