fix(work-orders): adapt Add-On indicator unstack onto independently approvable base

Extract inline schedule cell for the maintainability gate, drop completedDate
patch coverage that is not on WorkOrderTableRow on dev, and align range create
expectations with assignWizardScheduleFields.
This commit is contained in:
arthur.bassi 2026-08-11 15:42:29 -03:00
parent 56f007bcf2
commit 99724f831c
4 changed files with 43 additions and 78 deletions

View file

@ -28,6 +28,44 @@ type WoTableInlineRowCellsProps = {
onPatch: (patch: Partial<WorkOrderTableDraft>) => void;
};
function InlineScheduleOnCell({
draft,
weekDefault,
onPatch,
}: {
draft: WorkOrderTableDraft;
weekDefault: boolean;
onPatch: (patch: Partial<WorkOrderTableDraft>) => void;
}) {
return (
<td className="group/cell" style={{ padding: "0 14px" }}>
<DateCell
value={draft.scheduledOn}
allowWeekMode
targetWeek={draft.targetWeek}
defaultMode={weekDefault ? "week" : "date"}
highlight={!draft.scheduledOn && !draft.targetWeek}
onSave={(date) =>
onPatch({
scheduledOn: date,
scheduleWeekOnly: false,
targetWeek: "",
isAddOnOverride: false,
})
}
onSaveWeek={(week) =>
onPatch({
scheduledOn: "",
targetWeek: week,
scheduleWeekOnly: true,
isAddOnOverride: false,
})
}
/>
</td>
);
}
export function WoTableInlineRowCells({
draft,
weekDefault,
@ -84,31 +122,7 @@ export function WoTableInlineRowCells({
/>
</td>
<td className="group/cell" style={{ padding: "0 14px" }}>
<DateCell
value={draft.scheduledOn}
allowWeekMode
targetWeek={draft.targetWeek}
defaultMode={weekDefault ? "week" : "date"}
highlight={!draft.scheduledOn && !draft.targetWeek}
onSave={(date) =>
onPatch({
scheduledOn: date,
scheduleWeekOnly: false,
targetWeek: "",
isAddOnOverride: false,
})
}
onSaveWeek={(week) =>
onPatch({
scheduledOn: "",
targetWeek: week,
scheduleWeekOnly: true,
isAddOnOverride: false,
})
}
/>
</td>
<InlineScheduleOnCell draft={draft} weekDefault={weekDefault} onPatch={onPatch} />
<td className="group/cell" style={{ padding: "0 14px" }}>
<DueDateCell

View file

@ -40,6 +40,7 @@ const unscheduledRow: WorkOrderTableRow = {
dueDate: "2026-07-15",
rescheduleCount: 0,
carriedOver: 0,
isAddOn: false,
originalWeek: "",
originalDate: "",
isPastDue: false,

View file

@ -85,7 +85,7 @@ describe("mapWizardDraftToBoardCreatePayload", () => {
expect(payload.isAddOn).toBe(true);
});
it("derives isAddOn from range start via cutoff (range persists scheduledDate)", () => {
it("derives isAddOn from range start via cutoff (range omits scheduledDate on create)", () => {
const payload = mapWizardDraftToBoardCreatePayload({
...EMPTY_WIZARD_DRAFT,
type: "PM",
@ -96,7 +96,8 @@ describe("mapWizardDraftToBoardCreatePayload", () => {
isAddOnOverride: false,
});
expect(payload.scheduledDate).toBe("2026-07-08");
// On create, range mode does not persist scheduledDate (notes carry the range).
expect(payload.scheduledDate).toBeUndefined();
// createdAt defaults to now; after prior-Saturday 2026-07-04 for that week → true
expect(payload.isAddOn).toBe(true);
});

View file

@ -42,14 +42,12 @@ function makeWrapper() {
type ServerState = {
status: string;
scheduledDate: string;
completedDate: string;
docStatus: CompletionDocStatus;
};
const BASE_SERVER: ServerState = {
status: "Open",
scheduledDate: "2026-06-01",
completedDate: "",
docStatus: "No",
};
@ -61,7 +59,6 @@ const BASE_ROW = {
dispatcherId: "d1",
dispatcherName: "Dispatcher",
scheduledOn: "2026-06-01",
completedDate: "",
targetWeek: "",
dayGroup: "",
dayLabel: "",
@ -129,14 +126,6 @@ describe("useWorkOrderTableMutations completion-doc persistence", () => {
rowVersion: `${payload.workOrderVersion}-next`,
};
}
if (payload.field === "completedDate" && typeof payload.value === "string") {
serverState = { ...serverState, completedDate: payload.value };
rowState = {
...rowState,
completedDate: payload.value,
rowVersion: `${payload.workOrderVersion}-date`,
};
}
events.push(`boardPatch:${payload.field}:end`);
return { ...rowState };
},
@ -170,46 +159,6 @@ describe("useWorkOrderTableMutations completion-doc persistence", () => {
expect(getById).not.toHaveBeenCalled();
expect(serverState.docStatus).toBe("NN");
});
it("serializes board docStatus and completedDate via PATCH without racing or EditWorkorder", async () => {
const onPatch = vi.fn();
const { result } = renderHook(
() =>
useWorkOrderTableMutations({
onPatch,
clearPatch: () => undefined,
getRow: () => rowState,
}),
{ wrapper: makeWrapper() },
);
act(() => {
result.current.patchField(42, { docStatus: "Yes" });
result.current.patchField(42, { completedDate: "2026-07-20" });
});
await waitFor(() => expect(events).toContain("boardPatch:completedDate:end"));
await waitFor(() => expect(events).toContain("boardPatch:docStatus:end"));
expect(events).toEqual([
"boardPatch:docStatus:start",
"boardPatch:docStatus:end",
"boardPatch:completedDate:start",
"boardPatch:completedDate:end",
]);
expect(getById).not.toHaveBeenCalled();
expect(update).not.toHaveBeenCalled();
expect(patchBoardField).toHaveBeenCalledWith(
42,
expect.objectContaining({ field: "completedDate", value: "2026-07-20" }),
);
expect(serverState.docStatus).toBe("Yes");
expect(serverState.completedDate).toBe("2026-07-20");
expect(serverState.scheduledDate).toBe(BASE_SERVER.scheduledDate);
expect(serverState.status).toBe(BASE_SERVER.status);
});
});
describe("applySchedulePatch isAddOn optimistic clear", () => {