Skip to content

The solution.#1121

Open
1umamaster wants to merge 3 commits intomate-academy:masterfrom
1umamaster:develop
Open

The solution.#1121
1umamaster wants to merge 3 commits intomate-academy:masterfrom
1umamaster:develop

Conversation

@1umamaster
Copy link
Copy Markdown

No description provided.

Copilot AI review requested due to automatic review settings February 15, 2026 22:34
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 requesting changes because a few checklist-required behaviors are still not correctly implemented and will likely break the tests. In src/components/Autocomplete.tsx, the debounced updater is recreated on every render and the delay prop has no default of 300ms; you should set delay = 300 in the props destructuring and create a stable debounced function via useMemo/useRef, then call .cancel() in a cleanup effect. Also in Autocomplete, the filter currently runs even when the user types only spaces, and it always re-filters even when the text hasn’t actually changed; please trim() the incoming query, skip filtering when query.trim() === '', and add an early return when the trimmed query is equal to the previous currentQuery (do the comparison before calling setCurrentQuery). In src/App.tsx, the heading uses data-cy="title" but the requirements specify data-qa attributes for tests, so update it (and any similar usage) to data-qa="title" so the test suite can locate the element. These changes are all tied to explicit task description and checklist items, so they need to be addressed before the solution can be considered complete. Once you’ve fixed these, the overall structure of your Autocomplete and App components looks solid and should satisfy the remaining requirements.


✨ 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 +12 to +21
export const Autocomplete: React.FC<Props> = ({
people,
onSelected,
delay,
}) => {
const [shownPeople, setShownPeople] = useState([...people]);
const [focused, setFocused] = useState(false);
const [currentQuery, setCurrentQuery] = useState('');

const shownPeopleUpdater = debounce(setShownPeople, delay);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Two related problems around the debounced updater:

  1. The delay prop has no default value. The task requires a default delay of 300ms (the delay should be customizable via props, default 300ms) — set delay = 300 in the destructuring.
  2. The debounced function is created inline on every render (debounce(setShownPeople, delay)), so debouncing won't work correctly across renders. Create a stable debounced function (use useMemo or useRef) and cancel it on unmount (e.g. call .cancel() in cleanup).

These relate to the requirement that suggestions appear after some delay (debounce) and that the delay has a default value. See description for the requirement.

Comment on lines +28 to +39
const handleFilter = (query: string) => {
const queryLow = query.toLowerCase();

setCurrentQuery(query);
onSelected(null);

shownPeopleUpdater(
[...people].filter(person =>
person.name.toLowerCase().includes(queryLow),
),
);
};
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 code calls the filtering logic even when the user types only spaces. That violates the checklist item: "- make sure that filter won't be called if user enred spaces only;". You should trim() the incoming query and avoid calling the filter/updater when query.trim() === '' (or treat it as empty and show all people without doing the filtering call). See checklist.

Comment on lines +28 to +39
const handleFilter = (query: string) => {
const queryLow = query.toLowerCase();

setCurrentQuery(query);
onSelected(null);

shownPeopleUpdater(
[...people].filter(person =>
person.name.toLowerCase().includes(queryLow),
),
);
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

There is no guard to avoid re-filtering when the text hasn't changed. The function sets setCurrentQuery(query) and then always schedules the filter/update. To satisfy the requirement "don't run filtering again if the text has not changed", compare the incoming query with the previous currentQuery (the value from state) and return early when they are equal (after trimming as above). Also ensure the comparison happens before updating state so you can detect unchanged text correctly.

src/App.tsx Outdated
Comment on lines +14 to +19
<h1 className="title" data-cy="title">
{`${currentPerson.name} (${currentPerson.born} - ${currentPerson.died})`}
</h1>
) : (
<h1 className="title" data-cy="title">
No selected person
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 the checklist/description item: "Don't remove the data-qa attributes. It is required for tests." The h1 uses data-cy="title" instead of a data-qa attribute — please add/replace with data-qa="title" so tests can locate the title element. You have this at both title occurrences (lines below).

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request implements an Autocomplete component with debounced search functionality for displaying and filtering people from a data source. The component allows users to search through a list of people with a customizable debounce delay, select a person to display their details in the app title, and see appropriate feedback when no matches are found.

Changes:

  • Created new Autocomplete component with debounced filtering, focus management, and person selection
  • Updated App component to integrate the Autocomplete and display selected person details
  • Updated @mate-academy/scripts dependency from version 1.8.5 to 2.1.3

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 10 comments.

File Description
src/components/Autocomplete.tsx New component implementing autocomplete dropdown with debounced search, conditional rendering of suggestions/no-results message, and event handling for focus/blur/selection
src/App.tsx Integrated Autocomplete component, added state management for selected person, and updated title rendering to show selected person or default message
package.json Updated @mate-academy/scripts dependency to version 2.1.3
package-lock.json Lock file updates corresponding to the dependency version change

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

onSelected,
delay,
}) => {
const [shownPeople, setShownPeople] = useState([...people]);
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

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

The shownPeople state is initialized with the people prop but won't update if the people prop changes after the initial render. If the people array can change during the component's lifetime, consider using useEffect to sync the state, or derive the filtered people directly from props and the current query instead of using state.

Copilot uses AI. Check for mistakes.
import classNames from 'classnames';
import debounce from 'lodash.debounce';
import { Person } from '../types/Person';
import { useState } from 'react';
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

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

Missing React import. The component uses React.FC but React is not imported. This will cause a runtime error. Add import React from 'react'; at the top of the file, or change line 4 to import React, { useState } from 'react';.

Suggested change
import { useState } from 'react';
import React, { useState } from 'react';

Copilot uses AI. Check for mistakes.
onSelected,
delay,
}) => {
const [shownPeople, setShownPeople] = useState([...people]);
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

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

Unnecessary array spreading. The initial state can be set directly to people instead of [...people]. This shallow copy doesn't provide any benefit here and adds unnecessary overhead.

Suggested change
const [shownPeople, setShownPeople] = useState([...people]);
const [shownPeople, setShownPeople] = useState(people);

Copilot uses AI. Check for mistakes.
onSelected(null);

shownPeopleUpdater(
[...people].filter(person =>
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

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

Unnecessary array spreading before filtering. The [...people] creates a shallow copy that is immediately filtered, which is redundant. The filter method already returns a new array, so you can change this to people.filter(person => ...) directly.

Suggested change
[...people].filter(person =>
people.filter(person =>

Copilot uses AI. Check for mistakes.
Comment on lines +90 to +96
className="
notification
is-danger
is-light
mt-3
is-align-self-flex-start
"
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

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

Unusual className formatting with line breaks and indentation. This should be formatted on a single line or use an array approach for better readability. Consider changing to: className="notification is-danger is-light mt-3 is-align-self-flex-start"

Suggested change
className="
notification
is-danger
is-light
mt-3
is-align-self-flex-start
"
className="notification is-danger is-light mt-3 is-align-self-flex-start"

Copilot uses AI. Check for mistakes.
Comment on lines +70 to +80
<a
onMouseDown={() => {
handleSelect(person);
}}
className={classNames({
'has-text-link': person.sex === 'm',
'has-text-danger': person.sex === 'f',
})}
>
{person.name}
</a>
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

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

Anchor tag without href attribute used as a clickable element. This creates accessibility issues as screen readers and keyboard navigation expect anchor tags to have href attributes. Consider using a button element instead, or add href="#" with proper event handling (e.preventDefault), or add role="button" and tabIndex={0} for proper accessibility.

Copilot uses AI. Check for mistakes.
export const Autocomplete: React.FC<Props> = ({
people,
onSelected,
delay,
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

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

The delay prop can be undefined, but lodash.debounce will treat undefined as 0ms delay, effectively removing the debounce behavior. According to the README, the default value should be 300ms. Add a default parameter value: change line 15 to delay = 300, to ensure proper debounce behavior when the prop is not provided.

Suggested change
delay,
delay = 300,

Copilot uses AI. Check for mistakes.
const [focused, setFocused] = useState(false);
const [currentQuery, setCurrentQuery] = useState('');

const shownPeopleUpdater = debounce(setShownPeople, delay);
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

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

Debounce function is recreated on every render, which can lead to memory leaks and unexpected behavior. The debounce instance should be created once and cleaned up properly. Consider using useMemo to memoize the debounced function, or better yet, use useCallback with the debounced function and clean it up in a useEffect cleanup function.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +39
const handleFilter = (query: string) => {
const queryLow = query.toLowerCase();

setCurrentQuery(query);
onSelected(null);

shownPeopleUpdater(
[...people].filter(person =>
person.name.toLowerCase().includes(queryLow),
),
);
};
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

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

According to the checklist, the filter should not be called if the user enters spaces only. Currently, entering only spaces will trigger filtering. Add a check to trim the query and return early if it's empty or contains only whitespace, e.g., if (!query.trim()) { ... }

Copilot uses AI. Check for mistakes.

interface Props {
people: Person[];
onSelected: (person: Person | null) => void;
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

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

The prop name onSelected doesn't follow React naming conventions for event handler props. According to common React conventions, event handler props should be named with 'on' followed by the verb in base form (e.g., onSelect, onChange, onClick), not past tense. Consider renaming to onSelect for consistency with React conventions.

Copilot uses AI. Check for mistakes.
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 requesting changes because there are still a few critical behaviors and test-related requirements that are not met.

Critical issues that must be fixed (blockers):

  1. In src/components/Autocomplete.tsx, handleInputChange still ends up calling the debounced filter when the user types only spaces, violating the requirement to not run filtering for spaces-only input [CHECKLIST ITEM #1]. Trim the value first (const trimmed = value.trim()), and if trimmed === '', skip calling the debounced function and instead reset shownPeople appropriately (e.g., to the full people list or empty depending on your intended UX).
  2. The same handler always calls debouncedFilter(...) even when the trimmed text has not changed from the previous trimmed query, which contradicts the requirement not to re-filter when the text is unchanged after a pause. Store the previous trimmed query in a useRef or via existing state, compare trimmed to that previous value, and if they are equal, return early without calling the debounced filter.
  3. Both src/components/Autocomplete.tsx and src/App.tsx use data-cy attributes (e.g., on the input, suggestions list, suggestion items, “no suggestions” message, and the title), but the tests and task explicitly require data-qa attributes. Replace all relevant data-cy="..." with data-qa="..." so the test suite can find the elements.

As minor improvements, make sure the ordering in handleInputChange is: trim → compare with previous → decide whether to call debouncedFilter(trimmed) or reset shownPeople → then update state, which keeps behavior clear and efficient. Overall your structure, debouncing setup, and selection handling look solid; once these filtering and data-qa issues are corrected, the solution should fully meet the task requirements.


✨ 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 +51 to +57
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;

setCurrentQuery(value);
onSelected(null);

debouncedFilter(value);
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 #1: "make sure that filter won't be called if user enred spaces only;" Currently the debounced filter is still invoked from handleInputChange even if the input contains only spaces. Move the trim() and early-empty check before calling the debounced function (or skip calling it when value.trim() === '') so the filter isn't called for spaces-only input.

Comment on lines +51 to +57
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;

setCurrentQuery(value);
onSelected(null);

debouncedFilter(value);
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 does not satisfy the requirement: "don't run filtering again if the text has not changed (a pause in typing happened when the text was the same as before)". The code always calls debouncedFilter(value) on every change event, so a pause with the same text will re-trigger filtering. Compare the incoming trimmed query with the previous trimmed query (store the previous in a ref or use currentQuery) and skip calling the debounced filter when they are equal to avoid unnecessary re-filtering.

Comment on lines +73 to +106
data-cy="search-input"
value={currentQuery}
onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)}
onChange={handleInputChange}
/>
</div>

{focused && shownPeople.length > 0 && (
<div className="dropdown-menu" role="menu" data-cy="suggestions-list">
<div className="dropdown-content">
{shownPeople.map(person => (
<a
onMouseDown={() => handleSelect(person)}
key={person.slug}
className={classNames('dropdown-item', {
'has-text-link': person.sex === 'm',
'has-text-danger': person.sex === 'f',
})}
data-cy="suggestion-item"
style={{ cursor: 'pointer' }}
>
{person.name}
</a>
))}
</div>
</div>
)}

{focused && shownPeople.length === 0 && currentQuery !== '' && (
<div
className="notification is-danger is-light mt-3"
role="alert"
data-cy="no-suggestions-message"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Tests and the task description require data-qa attributes: "Don't remove the data-qa attributes. It is required for tests." This file uses data-cy on the input, suggestions list, suggestion items and the no-suggestions message. Replace these data-cy attributes with data-qa so the test suite can locate elements.

Comment on lines +51 to +57
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;

setCurrentQuery(value);
onSelected(null);

debouncedFilter(value);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor correctness hint: you trim query inside the debounced callback (good), but to fully satisfy both the spaces-only and unchanged-text requirements, perform const trimmed = value.trim() in handleInputChange, compare to previous trimmed query and only call debouncedFilter(trimmed) when needed (or skip calling and directly set shownPeople to people for empty trimmed). This prevents calling the debounced filter unnecessarily and ensures correct behavior for spaces-only input.

src/App.tsx Outdated
<p className="has-text-danger">No matching suggestions</p>
</div>
{currentPerson ? (
<h1 className="title" data-cy="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.

This uses data-cy="title". The task description requires data-qa attributes for tests: "Don't remove the data-qa attributes. It is required for tests." Please change to data-qa="title" so the test suite can locate the element.

src/App.tsx Outdated
{`${currentPerson.name} (${currentPerson.born} - ${currentPerson.died})`}
</h1>
) : (
<h1 className="title" data-cy="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.

This uses data-cy="title" in the "No selected person" branch. As above, change to data-qa="title" to satisfy the requirement: "Don't remove the data-qa attributes. It is required for tests."

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 so you can keep progressing while you refine the remaining behaviors. You did a solid job wiring up the Autocomplete with Bulma, using a debounced filter with a configurable delay, handling selection updates, and correctly rendering the title and data-qa="title" in App.tsx. The main behavior gaps are in src/components/Autocomplete.tsx: your input handler still calls the debounced filter even when the user types only spaces, which conflicts with [CHECKLIST ITEM #1] that requires not calling the filter at all for spaces-only input. To fix this, compute const trimmed = value.trim() first, and if trimmed === '' just reset shownPeople (or keep people) and do not call the debounced function. You should also compare this trimmed value with the previously trimmed query (stored in a useRef or state), return early if they’re equal to avoid re-filtering, and only then update state (setCurrentQuery and onSelected(null)) and decide whether to call the debounced filter using the trimmed string. Once you adjust the ordering and trimming logic in the input-change handler, your implementation will better match the behavioral requirements and should be more robust in tests. Overall, you’re very close—your structure and main logic are good, and these refinements will strengthen your understanding of controlled inputs and debounced search flows.


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

Footnotes

  1. Rate AI review example

setCurrentQuery(value);
onSelected(null);

debouncedFilter(value);
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 still violates checklist item #1 exactly: "make sure that filter won't be called if user enred spaces only;" (from checklist). You call debouncedFilter(value) here even when value may be spaces-only. Although the debounced filter trims internally, the requirement is to avoid calling the filter at all for spaces-only input. Trim the input first and, if the trimmed string is empty, reset shownPeople (or keep people) and do not invoke the debounced function.

Comment on lines +51 to +64
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;

if (value.toLowerCase().trim() === currentQuery.toLowerCase().trim()) {
setCurrentQuery(value);

return;
}

setCurrentQuery(value);
onSelected(null);

debouncedFilter(value);
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reorder the input-change logic to: 1) compute const trimmed = value.trim(), 2) compare trimmed with the previous trimmed query (use a ref or stored trimmed value) and return early if equal so you don't re-run filtering, 3) decide whether to call the debounced filter (pass the trimmed string) or reset shownPeople when trimmed is empty, and only then 4) update state (setCurrentQuery and onSelected(null)). Right now the handler sets state and calls debouncedFilter with the untrimmed value, and it can call the debounced filter for spaces-only — adjust ordering and pass trimmed query to satisfy the requirements.

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