Summary
TeamSearchField keeps its real selection in parent state (teamsData) while leaving the MUI Autocomplete uncontrolled, and then relies on the Autocomplete's internal value for filterSelectedOptions. The two disagree, so the filtering is partial and does not survive a refetch.
Not a regression - it is the shape the component is left in after #1780 removed a value={inputValue} prop that bound a string to an object-valued Autocomplete. That prop was a type error masked by a file-level @ts-nocheck; removing the suppression forced it out and switched the component from (broken) controlled to uncontrolled, which is what made filterSelectedOptions start working at all. Keeping the now-live filter was a deliberate call - it restores what the author evidently intended and the UX is better. This issue is about finishing the job properly.
The mismatch
Three facts that do not compose:
- The Autocomplete is single-select and uncontrolled. There is no
multiple and no value. MUI's internal value is therefore the last selected option, not the selection set.
- The real selection set lives in the parent, as
teamsData, appended by handleAdd and rendered as Chips outside the Autocomplete.
filterSelectedOptions filters against fact 1, not fact 2. So at most one team - whichever was picked most recently - is hidden from the dropdown. Every other already-selected team stays listed.
On top of that, isOptionEqualToValue={(option, value) => option === value} is reference equality, and options is replaced wholesale on every fetchSuggestions(...) call (onInputChange, and the useEffect on mount / orgID change). After any refetch the retained value is no longer reference-equal to the new option objects, so even that single team reappears.
Net: the filter applies to one team, sometimes, until the next keystroke. What actually prevents a duplicate selection is the explicit guard in handleAdd, which sets the "Team Already Selected" error.
Why fix it
The component currently works by accident on two levels - correctness is carried by the handleAdd duplicate guard, while the visible filtering is incidental. Anyone who later needs to control the field programmatically (clear it after a successful invite, preselect teams when editing) will reach for value and land straight back on the bug that @ts-nocheck was hiding.
Suggested resolution
Either of these, not both:
- Derive the filter from the real selection. Drop
filterSelectedOptions and filter options against teamsData directly, so every selected team is hidden, deterministically, regardless of refetches. Smallest change, keeps the component uncontrolled.
- Make it properly controlled. Give the Autocomplete a correctly-typed object value (or
multiple with value={teamsData}), which makes filterSelectedOptions mean what it says and makes programmatic control possible.
In either case replace the reference comparator with an id comparison - (option, value) => option.id === value.id - since options identities are not stable across fetches.
Worth checking InviteUserModal's sibling pickers for the same pattern while in here.
Summary
TeamSearchFieldkeeps its real selection in parent state (teamsData) while leaving the MUIAutocompleteuncontrolled, and then relies on the Autocomplete's internal value forfilterSelectedOptions. The two disagree, so the filtering is partial and does not survive a refetch.Not a regression - it is the shape the component is left in after #1780 removed a
value={inputValue}prop that bound a string to an object-valued Autocomplete. That prop was a type error masked by a file-level@ts-nocheck; removing the suppression forced it out and switched the component from (broken) controlled to uncontrolled, which is what madefilterSelectedOptionsstart working at all. Keeping the now-live filter was a deliberate call - it restores what the author evidently intended and the UX is better. This issue is about finishing the job properly.The mismatch
Three facts that do not compose:
multipleand novalue. MUI's internal value is therefore the last selected option, not the selection set.teamsData, appended byhandleAddand rendered as Chips outside the Autocomplete.filterSelectedOptionsfilters against fact 1, not fact 2. So at most one team - whichever was picked most recently - is hidden from the dropdown. Every other already-selected team stays listed.On top of that,
isOptionEqualToValue={(option, value) => option === value}is reference equality, andoptionsis replaced wholesale on everyfetchSuggestions(...)call (onInputChange, and theuseEffecton mount /orgIDchange). After any refetch the retained value is no longer reference-equal to the new option objects, so even that single team reappears.Net: the filter applies to one team, sometimes, until the next keystroke. What actually prevents a duplicate selection is the explicit guard in
handleAdd, which sets the "Team Already Selected" error.Why fix it
The component currently works by accident on two levels - correctness is carried by the
handleAddduplicate guard, while the visible filtering is incidental. Anyone who later needs to control the field programmatically (clear it after a successful invite, preselect teams when editing) will reach forvalueand land straight back on the bug that@ts-nocheckwas hiding.Suggested resolution
Either of these, not both:
filterSelectedOptionsand filteroptionsagainstteamsDatadirectly, so every selected team is hidden, deterministically, regardless of refetches. Smallest change, keeps the component uncontrolled.multiplewithvalue={teamsData}), which makesfilterSelectedOptionsmean what it says and makes programmatic control possible.In either case replace the reference comparator with an id comparison -
(option, value) => option.id === value.id- sinceoptionsidentities are not stable across fetches.Worth checking
InviteUserModal's sibling pickers for the same pattern while in here.