fix(workorders): Site dialog hides per-contact notes when it edits the site record

Site contacts carry only a name and a phone (LocationContact, and the
Sites page contact rows), so PATCH contact-info has nowhere to put an
additional contact's note. The Notes box on each additional contact card
let a dispatcher type one under copy saying contacts are saved to the
site record, but the note only reached this work order's copy and no
other work order at the site ever saw it.

The additional-contact Notes box is now hidden while the dialog edits the
site record. It stays where contacts are saved to the work order only:
inline create, the wizard, and an existing work order whose site record
failed to load.
This commit is contained in:
Alexandre Brandizzi 2026-09-25 19:36:09 -03:00
parent f36a07c99c
commit 53dcb6af9e
3 changed files with 42 additions and 8 deletions

View file

@ -54,6 +54,8 @@ export function SiteDialogPocSection({
onPocNotesChange={onPocNotesChange}
onAdditionalContactsChange={onAdditionalContactsChange}
helperText={helperText(editsSiteRecord, siteRecordUnavailable)}
// Site contacts carry only a name and phone, so a per-contact note could never reach the site.
additionalContactNotes={!editsSiteRecord || siteRecordUnavailable}
/>
);
}

View file

@ -26,6 +26,8 @@ type PocContactFieldsProps = {
showPrimaryErrors?: boolean;
/** Labels the primary name/phone inputs with a persistent required asterisk. */
primaryRequired?: boolean;
/** Offers a Notes box on each additional contact; off where contacts save without per-contact notes. */
additionalContactNotes?: boolean;
};
function extraNameMissing(contact: WorkOrderAdditionalContact): boolean {
@ -49,11 +51,13 @@ function updateContactAt(
function AdditionalPocCard({
contact,
index,
showNotes,
onChange,
onRemove,
}: {
contact: WorkOrderAdditionalContact;
index: number;
showNotes: boolean;
onChange: (patch: Partial<WorkOrderAdditionalContact>) => void;
onRemove: () => void;
}) {
@ -115,14 +119,16 @@ function AdditionalPocCard({
</Text>
</div>
</div>
<textarea
value={contact.notes ?? ""}
onChange={(event) => onChange({ notes: event.target.value })}
placeholder="Notes…"
rows={2}
className={`${DLG_INPUT_CLS} resize-none`}
style={{ ...DLG_INPUT_STYLE, fontFamily: "inherit" }}
/>
{showNotes && (
<textarea
value={contact.notes ?? ""}
onChange={(event) => onChange({ notes: event.target.value })}
placeholder="Notes…"
rows={2}
className={`${DLG_INPUT_CLS} resize-none`}
style={{ ...DLG_INPUT_STYLE, fontFamily: "inherit" }}
/>
)}
</div>
);
}
@ -139,6 +145,7 @@ export function PocContactFields({
helperText,
showPrimaryErrors = false,
primaryRequired = false,
additionalContactNotes = true,
}: PocContactFieldsProps) {
const fieldId = useId();
const nameMissing = showPrimaryErrors && !pocName.trim();
@ -214,6 +221,7 @@ export function PocContactFields({
key={`additional-poc-${index}`}
contact={contact}
index={index}
showNotes={additionalContactNotes}
onChange={(patch) =>
onAdditionalContactsChange(updateContactAt(additionalContacts, index, patch))
}

View file

@ -95,6 +95,26 @@ describe("Work order Site dialog edits the site record", () => {
expect(screen.queryByText(SITE_UNAVAILABLE_COPY)).not.toBeInTheDocument();
});
it("offers no per-contact notes on additional contacts, since site contacts cannot store them", async () => {
renderDialog();
await screen.findByDisplayValue("Bob");
// Only the site notes box: Bob's card has none.
expect(screen.getAllByPlaceholderText("Notes…")).toHaveLength(1);
fireEvent.click(screen.getByRole("button", { name: /add point of contact/i }));
expect(screen.getAllByPlaceholderText("POC name")).toHaveLength(3);
expect(screen.getAllByPlaceholderText("Notes…")).toHaveLength(1);
});
it("keeps per-contact notes when the site record is unavailable and Save writes the work order only", async () => {
getById.mockRejectedValue(new Error("Network error"));
renderDialog();
await screen.findByText(SITE_UNAVAILABLE_COPY);
fireEvent.click(screen.getByRole("button", { name: /add point of contact/i }));
expect(screen.getAllByPlaceholderText("Notes…")).toHaveLength(2);
});
it("locks the contact fields until the site loads, so typed input is never replaced", async () => {
let resolveSite: (site: Location) => void = () => {};
getById.mockReturnValue(
@ -299,6 +319,10 @@ describe("Work order Site dialog edits the site record", () => {
await waitFor(() => expect(getById).toHaveBeenCalled());
fireEvent.change(primaryField("Notes…"), { target: { value: "Bring ladder" } });
// Work-order-only contacts keep their own notes.
fireEvent.click(screen.getByRole("button", { name: /add point of contact/i }));
expect(screen.getAllByPlaceholderText("Notes…")).toHaveLength(2);
fireEvent.click(screen.getByRole("button", { name: /remove point of contact 2/i }));
fireEvent.click(saveButton());
await waitFor(() => expect(onSave).toHaveBeenCalledTimes(1));