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");