Merge remote-tracking branch 'origin/feat/ab/sh-335-wo-site-dialog' into feat/ab/sh-312-site-map-preview

This commit is contained in:
Alexandre Brandizzi 2026-09-25 16:42:55 -03:00
commit 4f90e0dce1
4 changed files with 29 additions and 5 deletions

View file

@ -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)}
/>
);
}

View file

@ -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}

View file

@ -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,

View file

@ -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<Parameters<typeof SiteDialog>[0]> = {}) {
const onSave = vi.fn();
const onOpenChange = vi.fn();
@ -93,6 +97,8 @@ describe("Work order Site dialog edits the site record", () => {
expect(screen.queryByText("Enter an address to preview the location")).not.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 () => {
@ -124,12 +130,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");