fix(workorders): Site dialog sends only complete contacts without site ids to the work order

The Site dialog loads extra contacts from the site record with their site
contact ids so the site request can update rows in place. buildSiteDialogPatch
copied those rows verbatim into the work-order patch, so onSave received
siteContactId (and half-filled rows) even though the type documents that the
id is never sent on work-order patches. The wire serializer already stripped
both, but the patch handed to the board did not.

Run the patch's extra contacts through normalizeAdditionalContacts, the same
helper the work-order serializer uses, so the patch carries only complete
name/phone/notes rows. An emptied list still clears the work order's copy.
The site request keeps its ids because it is built from the form fields.
This commit is contained in:
Alexandre Brandizzi 2026-09-25 19:04:32 -03:00
parent 414e584b36
commit b55938104a
3 changed files with 61 additions and 2 deletions

View file

@ -1,5 +1,6 @@
import { extractLocationLabel } from "@/app/(protected)/workorders/_components/list/table/cells/site-dialog-helpers"; import { extractLocationLabel } from "@/app/(protected)/workorders/_components/list/table/cells/site-dialog-helpers";
import type { SitePatch } from "@/app/(protected)/workorders/_components/list/table/cells/site-dialog-types"; import type { SitePatch } from "@/app/(protected)/workorders/_components/list/table/cells/site-dialog-types";
import { normalizeAdditionalContacts } from "@/domain/work-orders/mappers/additional-contacts-mapper";
import { resolveSiteCode } from "@/domain/work-orders/mappers/work-order-board-mapper"; import { resolveSiteCode } from "@/domain/work-orders/mappers/work-order-board-mapper";
import type { WorkOrderAdditionalContact } from "@/domain/work-orders/types/work-order-additional-contact"; import type { WorkOrderAdditionalContact } from "@/domain/work-orders/types/work-order-additional-contact";
import type { LocationOption } from "@/domain/work-orders/types/work-order"; import type { LocationOption } from "@/domain/work-orders/types/work-order";
@ -41,7 +42,8 @@ export function buildSiteDialogPatch({
// Following the site record, the dialog's extra contacts are the site's: copy them only when edited. // Following the site record, the dialog's extra contacts are the site's: copy them only when edited.
const sendContacts = followsSiteRecord ? contactsDirty : contactsDirty || baselineHadContacts; const sendContacts = followsSiteRecord ? contactsDirty : contactsDirty || baselineHadContacts;
if (sendContacts) { if (sendContacts) {
patch.additionalContacts = extraContacts; // The work order keeps only complete name/phone rows; site contact ids stay on the site request.
patch.additionalContacts = normalizeAdditionalContacts(extraContacts) ?? [];
} }
return patch; return patch;
} }

View file

@ -0,0 +1,57 @@
import { describe, expect, it } from "vitest";
import { buildSiteDialogPatch } from "@/app/(protected)/workorders/_components/list/table/cells/build-site-dialog-patch";
const base = {
code: "S-100",
locId: "1",
selected: undefined,
pocName: "Jane",
pocPhone: "(421) 433-1111",
pocNotes: "",
contactsDirty: true,
baselineHadContacts: true,
followsSiteRecord: true,
};
describe("buildSiteDialogPatch", () => {
it("copies site-loaded extra contacts to the work order without their site contact ids", () => {
const patch = buildSiteDialogPatch({
...base,
extraContacts: [{ name: "Bob", phone: "(421) 433-7777", siteContactId: 32 }],
});
expect(patch.additionalContacts).toEqual([{ name: "Bob", phone: "(421) 433-7777" }]);
});
it("drops half-filled and empty extra contacts from the work-order patch", () => {
const patch = buildSiteDialogPatch({
...base,
extraContacts: [
{ name: "Bob", phone: "(421) 433-7777", notes: "Night shift", siteContactId: 32 },
{ name: "Half", phone: "", siteContactId: 33 },
{ name: "", phone: "(421) 433-0000" },
{ name: "", phone: "" },
],
});
expect(patch.additionalContacts).toEqual([
{ name: "Bob", phone: "(421) 433-7777", notes: "Night shift" },
]);
});
it("still clears the work order's copy when every extra contact was removed", () => {
const patch = buildSiteDialogPatch({ ...base, extraContacts: [] });
expect(patch.additionalContacts).toEqual([]);
});
it("leaves additional contacts off the patch when they were not edited", () => {
const patch = buildSiteDialogPatch({
...base,
contactsDirty: false,
extraContacts: [{ name: "Bob", phone: "(421) 433-7777", siteContactId: 32 }],
});
expect(patch).not.toHaveProperty("additionalContacts");
});
});

View file

@ -195,7 +195,7 @@ describe("Work order Site dialog edits the site record", () => {
pocName: "Jane", pocName: "Jane",
pocPhone: "(421) 433-9999", pocPhone: "(421) 433-9999",
pocNotes: "", pocNotes: "",
additionalContacts: [{ name: "Bob", phone: "(421) 433-7777", siteContactId: 32 }], additionalContacts: [{ name: "Bob", phone: "(421) 433-7777" }],
}), }),
); );
expect(onOpenChange).toHaveBeenCalledWith(false); expect(onOpenChange).toHaveBeenCalledWith(false);