mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-09-30 05:43:12 +00:00
fix(workorders): preserve partial POC edits
This commit is contained in:
parent
5b0c758a9f
commit
3b1da21abb
8 changed files with 59 additions and 18 deletions
|
|
@ -370,7 +370,7 @@ export const workOrdersApi = {
|
|||
payload,
|
||||
),
|
||||
|
||||
/** SH-379: manual POC override — same row/error contract as the board patch. */
|
||||
/** Manual POC override — same row/error contract as the board patch. */
|
||||
updatePoc: async (
|
||||
id: string | number,
|
||||
payload: WorkOrderPocPatchPayload,
|
||||
|
|
|
|||
|
|
@ -50,12 +50,12 @@ export function isLocalOnlyTablePatch(patch: WorkOrderTablePatch): boolean {
|
|||
return keys.length > 0 && keys.every((key) => LOCAL_ONLY_KEYS.has(key));
|
||||
}
|
||||
|
||||
/** SH-379: composite manual POC override op routed to PATCH …/poc. */
|
||||
/** Composite manual POC override op routed to PATCH …/poc. */
|
||||
export type BoardPocOp = {
|
||||
kind: "poc";
|
||||
pocName: string;
|
||||
pocPhone: string;
|
||||
pocNotes: string;
|
||||
pocName?: string;
|
||||
pocPhone?: string;
|
||||
pocNotes?: string;
|
||||
};
|
||||
|
||||
export type BoardOp = BoardFieldOp | BoardPocOp;
|
||||
|
|
@ -70,9 +70,9 @@ function expandPocOp(patch: WorkOrderTablePatch): BoardPocOp[] {
|
|||
return [
|
||||
{
|
||||
kind: "poc",
|
||||
pocName: patch.pocName ?? "",
|
||||
pocPhone: patch.pocPhone ?? "",
|
||||
pocNotes: patch.pocNotes ?? "",
|
||||
pocName: patch.pocName,
|
||||
pocPhone: patch.pocPhone,
|
||||
pocNotes: patch.pocNotes,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ export interface WorkOrderBoardPatchPayload {
|
|||
primaryDispatchId?: number | null;
|
||||
}
|
||||
|
||||
/** Payload for PATCH /workorders/{id}/poc (SH-379 manual POC override). */
|
||||
/** Payload for PATCH /workorders/{id}/poc (manual POC override). */
|
||||
export interface WorkOrderPocPatchPayload {
|
||||
pocName: string;
|
||||
pocPhone: string;
|
||||
|
|
|
|||
|
|
@ -54,19 +54,23 @@ export type WorkOrderTablePatchHandlers = {
|
|||
type PatchResult =
|
||||
{ kind: "local"; patch: WorkOrderTablePatch } | { kind: "board"; row: WorkOrderTableRow };
|
||||
|
||||
function isPocOp(op: BoardOp): op is Extract<BoardOp, { kind: "poc" }> {
|
||||
return "kind" in op && op.kind === "poc";
|
||||
}
|
||||
|
||||
async function applyBoardOp(
|
||||
id: string | number,
|
||||
op: BoardOp,
|
||||
row: WorkOrderTableRow,
|
||||
): Promise<WorkOrderTableRow> {
|
||||
if ("pocName" in op) {
|
||||
if (isPocOp(op)) {
|
||||
if (!row.rowVersion) {
|
||||
throw new Error("workOrderVersion is required for board patch");
|
||||
}
|
||||
return workOrdersApi.updatePoc(id, {
|
||||
pocName: op.pocName,
|
||||
pocPhone: op.pocPhone,
|
||||
pocNotes: op.pocNotes,
|
||||
pocName: op.pocName ?? row.pocName,
|
||||
pocPhone: op.pocPhone ?? row.pocPhone,
|
||||
pocNotes: op.pocNotes ?? row.pocNotes,
|
||||
workOrderVersion: row.rowVersion,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import type {
|
|||
/**
|
||||
* Fields compared for dirty state and included in Save patch.
|
||||
* Only keys that map to board PATCH (or required companions like dispatcherName).
|
||||
* Primary POC scalars persist via the dedicated POC endpoint (SH-379);
|
||||
* Primary POC scalars persist via the dedicated POC endpoint;
|
||||
* tech phone is not board-editable — exclude so Save cannot no-op.
|
||||
* additionalContacts is board-editable (SH-218 PATCH field).
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ describe("isLocalOnlyTablePatch", () => {
|
|||
expect(isLocalOnlyTablePatch({ scheduleEnd: "2026-06-12", schedMode: "range" })).toBe(true);
|
||||
});
|
||||
|
||||
it("does not treat POC edits as local-only (SH-379)", () => {
|
||||
it("does not treat POC edits as local-only", () => {
|
||||
expect(isLocalOnlyTablePatch({ pocName: "Pat", pocPhone: "111", pocNotes: "call" })).toBe(
|
||||
false,
|
||||
);
|
||||
|
|
@ -202,7 +202,7 @@ describe("expandTablePatchToBoardFieldOps", () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it("emits one composite POC op before scalar ops (SH-379)", () => {
|
||||
it("emits one composite POC op before scalar ops", () => {
|
||||
expect(
|
||||
expandTablePatchToBoardFieldOps({
|
||||
pocName: "Pat",
|
||||
|
|
@ -213,7 +213,7 @@ describe("expandTablePatchToBoardFieldOps", () => {
|
|||
{
|
||||
kind: "poc",
|
||||
pocName: "Pat",
|
||||
pocPhone: "",
|
||||
pocPhone: undefined,
|
||||
pocNotes: "call first",
|
||||
},
|
||||
{ field: "docStatus", value: "Yes" },
|
||||
|
|
|
|||
|
|
@ -9,12 +9,14 @@ import type {
|
|||
|
||||
const getById = vi.fn();
|
||||
const update = vi.fn();
|
||||
const updatePoc = vi.fn();
|
||||
const patchBoardField = vi.fn();
|
||||
|
||||
vi.mock("@/domain/work-orders/api/work-orders-api", () => ({
|
||||
workOrdersApi: {
|
||||
getById: (...args: unknown[]) => getById(...args),
|
||||
update: (...args: unknown[]) => update(...args),
|
||||
updatePoc: (...args: unknown[]) => updatePoc(...args),
|
||||
patchBoardField: (...args: unknown[]) => patchBoardField(...args),
|
||||
},
|
||||
}));
|
||||
|
|
@ -121,6 +123,7 @@ describe("useWorkOrderTableMutations completion-doc persistence", () => {
|
|||
beforeEach(() => {
|
||||
getById.mockReset();
|
||||
update.mockReset();
|
||||
updatePoc.mockReset();
|
||||
patchBoardField.mockReset();
|
||||
serverState = { ...BASE_SERVER };
|
||||
rowState = { ...BASE_ROW };
|
||||
|
|
@ -829,6 +832,40 @@ describe("useWorkOrderTableMutations type and severity", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("useWorkOrderTableMutations POC persistence", () => {
|
||||
it("fills omitted POC fields from the current row before the full replacement", async () => {
|
||||
const currentRow = {
|
||||
...BASE_ROW,
|
||||
pocName: "Alex",
|
||||
pocPhone: "555-0000",
|
||||
pocNotes: "Gate",
|
||||
};
|
||||
updatePoc.mockResolvedValue({ ...currentRow, pocName: "Jordan", rowVersion: "wo-v2" });
|
||||
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useWorkOrderTableMutations({
|
||||
onPatch: vi.fn(),
|
||||
clearPatch: () => undefined,
|
||||
getRow: () => currentRow,
|
||||
}),
|
||||
{ wrapper: makeWrapper() },
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.patchField(42, { pocName: "Jordan" });
|
||||
});
|
||||
|
||||
await waitFor(() => expect(updatePoc).toHaveBeenCalled());
|
||||
expect(updatePoc).toHaveBeenCalledWith(42, {
|
||||
pocName: "Jordan",
|
||||
pocPhone: "555-0000",
|
||||
pocNotes: "Gate",
|
||||
workOrderVersion: "AAAAAAA=",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("useWorkOrderTableMutations audit cache refresh", () => {
|
||||
it("invalidates work-order queries after a successful status transition", async () => {
|
||||
const client = new QueryClient({
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ describe("slide-over-draft", () => {
|
|||
expect(buildSlideOverPatch(vendorDraft, row)).toEqual({ vendorId: "v2" });
|
||||
});
|
||||
|
||||
it("tracks POC edits for dirty state and patch (SH-379)", () => {
|
||||
it("tracks POC edits for dirty state and patch", () => {
|
||||
const row = baseRow();
|
||||
const draft = baseRow({ pocName: "Jordan", pocPhone: "555-0100" });
|
||||
expect(isSlideOverDraftDirty(draft, row)).toBe(true);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue