Skip to content

885: fix, adds autocomplete operator edit in AgentOrganisationDetails - #912

Open
DarrellRoberts wants to merge 5 commits into
developfrom
darrell/fix/operator-agent-org-details
Open

885: fix, adds autocomplete operator edit in AgentOrganisationDetails#912
DarrellRoberts wants to merge 5 commits into
developfrom
darrell/fix/operator-agent-org-details

Conversation

@DarrellRoberts

Copy link
Copy Markdown
Collaborator

Description

On edit for agent profile for OrganisationDetails this allows a new autocomplete EditableField to field operator.

Related Issues

Closes #885

Changes

  • Adds new EditableField type: autocomplete

Screenshots / Demos

Aufzeichnung.2026-08-07.232740.mp4

Checklist

  • WITHIN THE SCOPE OF AN ISSUE; No unnecessary files included
  • Tests added/updated
  • Documentation updated
  • CI passes


export type StatusValue = AgentEngagementStatusType | AgentVolunteerSearchType | AgentTrustType;

// @ts-expect-error - TODO: Add INCONTACT and TRIED_TO_CONTACT types

@DarrellRoberts DarrellRoberts Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

will implement when I do to Issue 796


type IconComponent = React.ComponentType<{ size?: number; color?: string }>;

// @ts-expect-error - TODO: Add INCONTACT and TRIED_TO_CONTACT types

@DarrellRoberts DarrellRoberts Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

will implement when I do to Issue 796

[AgentEngagementStatus.INACTIVE]: t("dashboard.agentProfile.status.engagement.inactive"),
});
export const createEngagementStatusLabelMap = (t: TFunction): Record<AgentEngagementStatus, string> =>
// @ts-expect-error TODO - Add INCONTACT and TRIED_TO_CONTACT types

@DarrellRoberts DarrellRoberts Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

will implement when I do to Issue 796

Comment thread package.json
@DarrellRoberts DarrellRoberts self-assigned this Aug 9, 2026
@nadavosa

Copy link
Copy Markdown
Collaborator

Review

Overview: adds a new autocomplete EditableField type and wires it up so the agent's "operator" (Träger) field on OrganisationDetails is picked from a live list of organizations (useGetOrganization) instead of free text.

Potential regression: strict operator validation could block unrelated edits on existing agents

operator: z
  .string()
  .min(1, required)
  .refine((val) => validOperators.includes(val), {
    message: t(`${i18nPrefix}.operatorInvalid`),
  }),

This requires the operator to exactly match an entry in the current organizations list. Any existing agent whose stored operator isn't in that list (a legacy free-text value, a renamed/removed organization, or simply no operator ever set) will now show a validation error on this field as soon as the section is opened for editing — before the user touches anything — which (via isValid) would block saving any other change in this section until they pick a new value from the dropdown. Given the PR is scoped as "add autocomplete for editing operator," blocking unrelated edits on agents with an out-of-list operator seems like a wider blast radius than intended. Worth confirming this is the desired behavior, or relaxing the refine to only apply when the user actually changes the field.

That's compounded by this change:

- operator: details?.operator || agent.operator || "",
+ operator: details?.operator,

This drops both the agent.operator fallback and the || "" default. If details?.operator is undefined, the field's initial value is undefined (a) risking a React uncontrolled→controlled warning on the controlled EditableField, and (b) if agent.operator was carrying a legacy value not present on details, that value no longer shows at all — and per the above, an empty operator also now fails .min(1) immediately.

UX: autocomplete updates the real value on every keystroke, not just on selection

onChange={(e) => {
  const v = e.target.value as T;
  setLocalValue(v);
  setValue(v);   // fires react-hook-form's onChange immediately
  setOpen(true);
}}

Since setValue (== field.onChange) runs on every keystroke rather than only when an option is picked from the dropdown, the "Ungültiger Träger" error will flash on while the user is still typing, before they've had a chance to select anything. Also, the placeholder text ("Type the first three letters of the operator") implies a prefix match, but displayOperators does a case-sensitive op.includes(value) — a substring match anywhere in the name, not anchored to the start, and won't match if the user's casing differs from the stored title.

Scope: two unrelated @ts-expect-error suppressions

// @ts-expect-error TODO - Add INCONTACT and TRIED_TO_CONTACT types

appears in ProfileHeader/agent/constants.ts and Dashboard/common/statusMaps.ts, unrelated to the operator-autocomplete feature. This traces to the need4deed-sdk bump in this PR (0.0.139 → 0.0.141), which added AgentEngagementStatusType.INCONTACT/TRIED_TO_CONTACT (per fe#796) and broke these previously-exhaustive Record<AgentEngagementStatus, string> maps. Suppressing rather than fixing means any agent whose engagement status is actually INCONTACT/TRIED_TO_CONTACT will render with an undefined label/color/icon wherever these maps are used — worth either implementing the two new statuses here, or referencing #796 explicitly in the TODO so it's tracked rather than silently swept under the rug.

Test coverage

Checklist is fully unchecked (scope/tests/docs/CI) and no tests were added for the new validation or the autocomplete field type.

@need4deed

Copy link
Copy Markdown
Contributor

@DarrellRoberts does this bot review make sense?

@DarrellRoberts

Copy link
Copy Markdown
Collaborator Author

thanks @nadavosa , I've pushed my changes.

@need4deed in response to the bot comments:

Exact match

This requires the operator to exactly match an entry in the current organizations list. Any existing agent whose stored operator isn't in that list (a legacy free-text value, a renamed/removed organization, or simply no operator ever set) will now show a validation error on this field as soon as the section is opened for editing — before the user touches anything — which (via isValid) would block saving any other change in this section until they pick a new value from the dropdown. Given the PR is scoped as "add autocomplete for editing operator," blocking unrelated edits on agents with an out-of-list operator seems like a wider blast radius than intended. Worth confirming this is the desired behavior, or relaxing the refine to only apply when the user actually changes the field.

This is intentional. It's so a user is forced to submit a confirmed Operator value rather than a random string like "aus" as opposed to ausbildung-ota.de

image image

Error showing whilst user typing

Since setValue (== field.onChange) runs on every keystroke rather than only when an option is picked from the dropdown, the "Ungültiger Träger" error will flash on while the user is still typing, before they've had a chance to select anything.

I added a bit more UX along with a hint so that if the value is less than 3 characters, we flag it (otherwise the list won't show), and then if it's 3 or more characters but the user hasn't selected from the list, it will still show an error.
This relates to my first point where we don't want it to be valid if the user just leaves the field as "aus" .
Essentially making it as idiot proof as possible.

image

Uncontrolled component

This drops both the agent.operator fallback and the || "" default. If details?.operator is undefined, the field's initial value is undefined (a) risking a React uncontrolled→controlled warning on the controlled EditableField, and (b) if agent.operator was carrying a legacy value not present on details, that value no longer shows at all — and per the above, an empty operator also now fails .min(1) immediately.

This is a fair point and have reverted the change

Also, the placeholder text ("Type the first three letters of the operator") implies a prefix match, but displayOperators does a case-sensitive op.includes(value) — a substring match anywhere in the name, not anchored to the start, and won't match if the user's casing differs from the stored title.

Another fair point, have made check lowercase

Scope: two unrelated @ts-expect-error suppressions

The updated sdk causes linting errors. I'm actually working in parallel on this issue hence why I commented above.
I will submit a seperate PR today which will add the missing values in regards to Issue 796

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.

NGO profile organisaional details section bugs

3 participants