Skip to content

fix: company-input-v2 — explicit selection only, no clear icon, "Use "<typed>"" row#289

Open
JpMaxMan wants to merge 2 commits into
mainfrom
feature/company-input-v2-freetext-use-option
Open

fix: company-input-v2 — explicit selection only, no clear icon, "Use "<typed>"" row#289
JpMaxMan wants to merge 2 commits into
mainfrom
feature/company-input-v2-freetext-use-option

Conversation

@JpMaxMan

@JpMaxMan JpMaxMan commented Jul 13, 2026

Copy link
Copy Markdown

The bug

CompanyInputV2 used MUI's autoSelect, which commits the currently highlighted option on blur. Users would mouse over a suggestion, then tab away intending to keep their typed text — and the moused-over company got saved instead (wrong company populated).

Changes (src/components/inputs/company-input-v2.js)

  • Remove autoSelect — selection is now explicit (click / Enter) only. This is the root-cause fix.
  • New onBlur — tab/click-away commits exactly what was typed: resolved to an existing company only on an exact (case-insensitive) name match, otherwise a free-text { id: 0, name }. Never commits a merely-highlighted option.
  • disableClearable — removes the MUI clear (x) icon (the field commits free text, so an explicit clear affordance isn't wanted; delete the text to empty).
  • Use "<typed>" rowfilterOptions appends a synthetic option so users can explicitly commit their typed text; skipped when it already matches a listed company. Commits a clean { id: 0, name } (display-only marker stripped). renderOption shows the Use "…" label; getOptionLabel still returns the plain name.
  • Predictive typeahead unchanged (freeSolo + server-side queryRegistrationCompanies).

⚠️ Shared-component behavior change

This affects all CompanyInputV2 consumers, not just the requesting screen: no more clear (x) icon, and blur no longer auto-selects a highlighted option (it keeps the typed text). Both are intentional — flagging for reviewers.

Note: the Formik variant CompanyInputMUI (mui/formik-inputs/company-input-mui.js) is a separate implementation and is not touched here; if a Formik form needs the same behavior we'll do it in a follow-up.

Tests

+5 tests; the file's suite is 25/25 green:

  • blur keeps the typed text and never commits a highlighted option (pins the bug);
  • blur resolves an exact case-insensitive match to the canonical company;
  • clear icon never renders, even with a real selected value;
  • Use "…" row commits clean free text; no redundant Use row on an exact match.

Verified by running jest directly (node_modules/.bin/jest) — CI's Node 18 avoids a local node-sass/Node-25 build issue unrelated to this change. package.json version intentionally not bumped (done separately at release).

Summary by CodeRabbit

  • New Features

    • Added a “Use ‘…’” option to allow committing company names that aren’t in the suggestions.
    • Typed company names are now matched to existing companies case-insensitively.
    • Blurring the field can commit an unmatched entry as free text.
  • Bug Fixes

    • Prevented accidental commits of highlighted suggestions when leaving the field.
    • Removed the clear icon from the company input.
    • Prevented the free-text “Use ‘…’” option from appearing when the typed value already matches a suggestion.

…"<typed>"" row

Root cause of the wrong-company bug: `autoSelect` committed the currently
*highlighted* option on blur, so merely mousing over a suggestion and then
tabbing away silently populated the wrong company.

- Remove `autoSelect`. Selection is now explicit (click / Enter) only.
- New onBlur: tab/click-away commits exactly what was typed — resolved to an
  existing company only on an exact (case-insensitive) name match, else a
  free-text { id: 0, name }. Never commits a merely-highlighted option.
- `disableClearable`: remove the MUI clear (x) icon; the field commits free
  text, so an explicit clear affordance isn't wanted (delete text to empty).
- Append a synthetic 'Use "<typed>"' row so users can explicitly commit their
  text; skipped when it already matches a listed company. Commits a clean
  { id: 0, name }, dropping the display-only marker.
- Predictive typeahead unchanged (freeSolo + server-side queryRegistrationCompanies).

Tests: +5 (blur keeps typed text / never a highlighted option; clear icon never
renders even with a real value; "Use" row commits clean free text; no redundant
"Use" row on exact match). 25/25 green.
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8d2a6245-286d-42c8-8771-9e8f96d5a2b3

📥 Commits

Reviewing files that changed from the base of the PR and between 294bc61 and 1bc112a.

📒 Files selected for processing (2)
  • src/components/inputs/__tests__/company-input-v2.test.js
  • src/components/inputs/company-input-v2.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/inputs/company-input-v2.js

📝 Walkthrough

Walkthrough

CompanyInputV2 commits typed text on blur, resolves case-insensitive company matches, supports explicit Use "<typed>" free-text options, disables the clear icon, and adds integration coverage for these behaviors.

Changes

CompanyInputV2 selection behavior

Layer / File(s) Summary
Selection and blur normalization
src/components/inputs/company-input-v2.js, src/components/inputs/__tests__/company-input-v2.test.js
Blur commits matching companies or { id: 0, name } free-text entries, while onChange normalizes string and synthetic free-text selections.
Synthetic free-text option UI
src/components/inputs/company-input-v2.js, src/components/inputs/__tests__/company-input-v2.test.js
Autocomplete adds and labels Use "<typed>" rows, disables the clear icon, and tests matching-option suppression and free-text selection.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: gcutrini, smarcet

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main changes: explicit selection, removal of the clear icon, and the new Use "" row.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/company-input-v2-freetext-use-option

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/inputs/company-input-v2.js`:
- Around line 113-139: Update the onBlur handler to clear the committed company
when the trimmed inputValue is empty, by calling fireChange with null or the
component’s established clear value. Preserve the existing exact-match and
free-text behavior for non-empty input, avoid duplicate changes when already
cleared, and add a regression test covering delete-all-text followed by blur.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ecfeb9fa-e11a-4a27-bcea-861a0f48f74e

📥 Commits

Reviewing files that changed from the base of the PR and between 5688cf7 and 294bc61.

📒 Files selected for processing (2)
  • src/components/inputs/__tests__/company-input-v2.test.js
  • src/components/inputs/company-input-v2.js

Comment on lines 113 to +139
freeSolo
// No clear (x) icon: the field commits free text, so an explicit clear
// affordance isn't wanted; users empty it by deleting the text.
disableClearable
includeInputInList
filterSelectedOptions
value={normalizedValue}
onBlur={() => { if (onBlur) onBlur(name) }}
// NOTE: `autoSelect` is intentionally NOT set. With it, blurring the field
// committed the currently *highlighted* option — so merely mousing over a
// suggestion and then tabbing away silently populated the wrong company.
// Selection is now explicit (click / Enter) only; see onBlur for the
// "keep what was typed" fallback.
onBlur={() => {
// On blur with no explicit selection, take the typed text as-is:
// resolve to an existing company only on an exact (case-insensitive)
// name match, otherwise commit it as a free-text { id: 0, name }. Never
// commit a merely-highlighted option. Skip when the text already matches
// the committed value (e.g. right after an explicit selection).
const typed = inputValue.trim();
const currentName = isCompanyObject(normalizedValue)
? normalizedValue.name
: (typeof normalizedValue === "string" ? normalizedValue : "");
if (typed && typed.toLowerCase() !== currentName.trim().toLowerCase()) {
fireChange(findExistingByName(options, typed) || { id: 0, name: typed });
}
if (onBlur) onBlur(name);
}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Allow blur-to-empty to clear the selected company

When the user deletes all text and blurs, typed === "" skips fireChange, so the previously selected company stays committed while the field appears empty. With disableClearable, there’s no other UI path to clear the selection. Send null (or the component’s clear value) when the trimmed input is empty, and add a regression test for delete-all-text-then-blur.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/inputs/company-input-v2.js` around lines 113 - 139, Update the
onBlur handler to clear the committed company when the trimmed inputValue is
empty, by calling fireChange with null or the component’s established clear
value. Preserve the existing exact-match and free-text behavior for non-empty
input, avoid duplicate changes when already cleared, and add a regression test
covering delete-all-text followed by blur.

…241)

Follow-up to removing autoSelect. autoSelect (added in #241) committed the
input's DOM value on blur, which is how it captured iOS-Chrome browser autofill
(autofill writes to the DOM without firing onInputChange). The initial onBlur
here read React input state, which would be stale for autofill and reintroduce
the #241 required-field-validation bug.

- onBlur now reads event.target.value (the DOM value), not React state, so
  typed AND autofilled values propagate on blur — while still committing the
  field text, never a highlighted option (the autoSelect-on-hover bug fix
  stands).
- Test: commits a browser-autofilled value on blur even when onInputChange
  never fired. 26/26 green.

Needs a Chrome-iOS device re-test of the #241 autofill path before merge.
@JpMaxMan

Copy link
Copy Markdown
Author

Re: autoSelect and the #241 autofill fix — addressed in 1bc112a

@gcutrini flagged (via Slack) that autoSelect was added in #241 to fix a real bug: in freeSolo mode MUI only propagates a value on explicit selection, so typing-and-tabbing and browser autofill (iOS Chrome) never reached the parent and required-field validation failed. Correct — and simply removing autoSelect would regress that.

Reconciliation (latest commit): autoSelect stays removed — it's what committed the currently highlighted option on blur, so mousing over a suggestion and tabbing away saved the wrong company. In its place, onBlur now reads the input's DOM value (event.target.value) — the same source autoSelect read internally — and commits it as the field value. So:

Suite: 26/26 (jest run directly; CI Node 18 avoids a local node-sass/Node-25 issue).

⚠️ Merge gate: the autofill test passes in jsdom, but jsdom ≠ iOS Chrome. Reading event.target.value is strictly the more-robust source (it's what autoSelect used), but the real iOS-Chrome autofill path needs a device re-test. @gcutrini — could you verify that path on this branch, since you have the #241 repro? Happy to pair if the behavior differs.

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.

1 participant