From c0e484275dbcc512ef36715aad403f144e4710b4 Mon Sep 17 00:00:00 2001 From: Alexandre Brandizzi Date: Fri, 25 Sep 2026 13:39:25 -0300 Subject: [PATCH] fix(workorders): say Site dialog saves to the work order only when the site did not load When the site detail request fails, or the user types before it loads, the dialog falls back to saving this work order only and never calls updateContactInfo. The POC helper text still said contacts and notes were saved to the site record, so a dispatcher could believe every work order at the site now had the new contact. The helper text now follows the site-record sync state and says the change applies to this work order only whenever that fallback is active, including after a later refetch succeeds. --- .../table/cells/site-dialog-poc-section.tsx | 18 +++++++++++++----- .../list/table/cells/site-dialog.tsx | 1 + .../list/table/cells/use-site-dialog-state.ts | 4 ++++ .../site-dialog-site-record.test.tsx | 11 +++++++++++ 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/app/(protected)/workorders/_components/list/table/cells/site-dialog-poc-section.tsx b/src/app/(protected)/workorders/_components/list/table/cells/site-dialog-poc-section.tsx index 684d4800..9b81279d 100644 --- a/src/app/(protected)/workorders/_components/list/table/cells/site-dialog-poc-section.tsx +++ b/src/app/(protected)/workorders/_components/list/table/cells/site-dialog-poc-section.tsx @@ -10,12 +10,23 @@ type SiteDialogPocSectionProps = { primaryRequired?: boolean; /** Edits go to the site record rather than only this work order. */ editsSiteRecord?: boolean; + /** The site record did not load, so Save writes this work order only. */ + siteRecordUnavailable?: boolean; onPocNameChange: (value: string) => void; onPocPhoneChange: (value: string) => void; onPocNotesChange: (value: string) => void; onAdditionalContactsChange: (contacts: WorkOrderAdditionalContact[]) => void; }; +function helperText(editsSiteRecord: boolean, siteRecordUnavailable: boolean): string { + if (!editsSiteRecord) { + return "Auto-filled from site records when empty. Additional contacts persist on save."; + } + return siteRecordUnavailable + ? "Site record unavailable — changes apply to this work order only." + : "Contacts and notes are saved to the site record and apply to all its work orders."; +} + export function SiteDialogPocSection({ pocName, pocPhone, @@ -24,6 +35,7 @@ export function SiteDialogPocSection({ showPrimaryErrors = false, primaryRequired = false, editsSiteRecord = false, + siteRecordUnavailable = false, onPocNameChange, onPocPhoneChange, onPocNotesChange, @@ -41,11 +53,7 @@ export function SiteDialogPocSection({ onPocPhoneChange={onPocPhoneChange} onPocNotesChange={onPocNotesChange} onAdditionalContactsChange={onAdditionalContactsChange} - helperText={ - editsSiteRecord - ? "Contacts and notes are saved to the site record and apply to all its work orders." - : "Auto-filled from site records when empty. Additional contacts persist on save." - } + helperText={helperText(editsSiteRecord, siteRecordUnavailable)} /> ); } diff --git a/src/app/(protected)/workorders/_components/list/table/cells/site-dialog.tsx b/src/app/(protected)/workorders/_components/list/table/cells/site-dialog.tsx index 2187a33a..6ee17752 100644 --- a/src/app/(protected)/workorders/_components/list/table/cells/site-dialog.tsx +++ b/src/app/(protected)/workorders/_components/list/table/cells/site-dialog.tsx @@ -139,6 +139,7 @@ export function SiteDialog({ showPrimaryErrors={s.requiresPoc && s.showErrors} primaryRequired={s.requiresPoc} editsSiteRecord={s.editsSiteRecord} + siteRecordUnavailable={s.siteRecordUnavailable} onPocNameChange={s.setPn} onPocPhoneChange={s.setPp} onPocNotesChange={s.setNotes} diff --git a/src/app/(protected)/workorders/_components/list/table/cells/use-site-dialog-state.ts b/src/app/(protected)/workorders/_components/list/table/cells/use-site-dialog-state.ts index e08a184e..f23b1b01 100644 --- a/src/app/(protected)/workorders/_components/list/table/cells/use-site-dialog-state.ts +++ b/src/app/(protected)/workorders/_components/list/table/cells/use-site-dialog-state.ts @@ -95,6 +95,9 @@ export function useSiteDialogState({ locationDetailError: liveLocationDetailError, fields, }); + // The site failed to load (or the user typed before it did), so Save writes this work order only. + const siteRecordUnavailable = + editsSiteRecord && Boolean(locId) && !siteRecord.synced && !siteRecord.loading; const updateSite = useUpdateSiteContactInfo(); const pocMissing = !pn.trim() || !pp.trim(); const requiresPoc = createMode || editsSiteRecord; @@ -166,6 +169,7 @@ export function useSiteDialogState({ saving: updateSite.isPending, siteRecordLoading: siteRecord.loading, editsSiteRecord, + siteRecordUnavailable, requiresPoc, setPn: fields.setPnDirty, setPp: fields.setPpDirty, diff --git a/src/test/app/(protected)/workorders/site-dialog-site-record.test.tsx b/src/test/app/(protected)/workorders/site-dialog-site-record.test.tsx index 79dfb6a0..121e7dbd 100644 --- a/src/test/app/(protected)/workorders/site-dialog-site-record.test.tsx +++ b/src/test/app/(protected)/workorders/site-dialog-site-record.test.tsx @@ -34,6 +34,10 @@ const dallas: Location = { const sites = [{ id: "1", name: "DAL1" }]; +const SITE_RECORD_COPY = + "Contacts and notes are saved to the site record and apply to all its work orders."; +const SITE_UNAVAILABLE_COPY = "Site record unavailable — changes apply to this work order only."; + function renderDialog(overrides: Partial[0]> = {}) { const onSave = vi.fn(); const onOpenChange = vi.fn(); @@ -87,6 +91,8 @@ describe("Work order Site dialog edits the site record", () => { expect(screen.getByTitle("Site location map")).toBeInTheDocument(); expect(screen.getByText("(214) 555-0100")).toBeInTheDocument(); expect(screen.getByText("dal1@acme.test")).toBeInTheDocument(); + expect(screen.getByText(SITE_RECORD_COPY)).toBeInTheDocument(); + expect(screen.queryByText(SITE_UNAVAILABLE_COPY)).not.toBeInTheDocument(); }); it("locks the contact fields until the site loads, so typed input is never replaced", async () => { @@ -118,12 +124,17 @@ describe("Work order Site dialog edits the site record", () => { const { onSave, queryClient } = renderDialog(); await waitFor(() => expect(primaryField("POC name")).toBeEnabled()); + expect(screen.getByText(SITE_UNAVAILABLE_COPY)).toBeInTheDocument(); + expect(screen.queryByText(SITE_RECORD_COPY)).not.toBeInTheDocument(); fireEvent.change(primaryField("POC name"), { target: { value: "John" } }); await queryClient.refetchQueries({ queryKey: queryKeys.locations.detail("1") }); await waitFor(() => expect(getById).toHaveBeenCalledTimes(2)); await screen.findByText("(214) 555-0100"); + // The typed input stays on the work order, so the copy still says so after the refetch. + expect(screen.getByText(SITE_UNAVAILABLE_COPY)).toBeInTheDocument(); + expect(screen.queryByText(SITE_RECORD_COPY)).not.toBeInTheDocument(); expect(primaryField("POC name")).toHaveValue("John"); expect(primaryField("POC name")).toBeEnabled(); expect(primaryField("POC phone")).toHaveValue("(000) 000-0000");