) => void,
) {
- if (shouldAnnounceSeverityEscalation(row.severity, severity)) {
- toast.warn(formatSeverityEscalationToast(row.woNumber, severity));
+ const patch = { type, severity };
+ if (!shouldAnnounceSeverityEscalation(row.severity, severity)) {
+ onPatch(row.id, patch);
+ return;
}
- onPatchRow({ type, severity });
+ onPatch(row.id, patch, {
+ onSuccess: () => toast.warn(formatSeverityEscalationToast(row.woNumber, severity)),
+ });
}
diff --git a/src/app/(protected)/workorders/_components/list/table/wo-table-row-cells.tsx b/src/app/(protected)/workorders/_components/list/table/wo-table-row-cells.tsx
index 283d732c..f5700a47 100644
--- a/src/app/(protected)/workorders/_components/list/table/wo-table-row-cells.tsx
+++ b/src/app/(protected)/workorders/_components/list/table/wo-table-row-cells.tsx
@@ -2,6 +2,7 @@ import type { CSSProperties } from "react";
import type { LocationOption, WorkOrderUser } from "@/domain/work-orders/types/work-order";
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
import { applyAssignedToTableSave } from "@/domain/work-orders/utils/work-order-feedback-toasts";
+import { isWorkOrderCompletionSurfaceReadOnly } from "@/domain/work-orders/utils/work-order-lock";
import { saveExistingRowType } from "./save-existing-row-type";
import { AssignedToCell } from "./cells/assigned-to-cell";
import { DateCell } from "./cells/date-cell";
@@ -104,7 +105,8 @@ export function WoTableRowCells({
value={row.type}
severity={row.severity}
q={search}
- onSave={(t, sev) => saveExistingRowType(row, t, sev, onPatchRow)}
+ viewOnly={isWorkOrderCompletionSurfaceReadOnly(row.status)}
+ onSave={(t, sev) => saveExistingRowType(handlers.onPatch, row, t, sev)}
/>
| ({
import { saveExistingRowType } from "@/app/(protected)/workorders/_components/list/table/save-existing-row-type";
+const row = { id: 7, woNumber: "00000024965", severity: 3 as const };
+
describe("saveExistingRowType", () => {
beforeEach(() => {
toastWarn.mockReset();
});
- it("warns when severity newly enters SEV 1 and still patches the row", () => {
- const onPatchRow = vi.fn();
+ it("warns when severity newly enters SEV 1 only after persist onSuccess", () => {
+ const onPatch = vi.fn();
- saveExistingRowType({ woNumber: "00000024965", severity: 3 }, "Emergency", 1, onPatchRow);
+ saveExistingRowType(onPatch, row, "Emergency", 1);
+ expect(toastWarn).not.toHaveBeenCalled();
+ expect(onPatch).toHaveBeenCalledWith(
+ 7,
+ { type: "Emergency", severity: 1 },
+ expect.objectContaining({ onSuccess: expect.any(Function) }),
+ );
+
+ const { onSuccess } = onPatch.mock.calls[0]![2] as { onSuccess: () => void };
+ onSuccess();
expect(toastWarn).toHaveBeenCalledWith("WO #00000024965 escalated to SEV 1.");
- expect(onPatchRow).toHaveBeenCalledWith({ type: "Emergency", severity: 1 });
});
it("does not warn when staying on a critical severity", () => {
- const onPatchRow = vi.fn();
+ const onPatch = vi.fn();
- saveExistingRowType({ woNumber: "00000024965", severity: 1 }, "Emergency", 1, onPatchRow);
+ saveExistingRowType(onPatch, { ...row, severity: 1 }, "Emergency", 1);
expect(toastWarn).not.toHaveBeenCalled();
- expect(onPatchRow).toHaveBeenCalledWith({ type: "Emergency", severity: 1 });
+ expect(onPatch).toHaveBeenCalledWith(7, { type: "Emergency", severity: 1 });
+ expect(onPatch.mock.calls[0]![2]).toBeUndefined();
});
it("does not warn when clearing severity on a PM correction", () => {
- const onPatchRow = vi.fn();
+ const onPatch = vi.fn();
- saveExistingRowType({ woNumber: "00000024965", severity: 2 }, "PM", null, onPatchRow);
+ saveExistingRowType(onPatch, { ...row, severity: 2 }, "PM", null);
expect(toastWarn).not.toHaveBeenCalled();
- expect(onPatchRow).toHaveBeenCalledWith({ type: "PM", severity: null });
+ expect(onPatch).toHaveBeenCalledWith(7, { type: "PM", severity: null });
+ expect(onPatch.mock.calls[0]![2]).toBeUndefined();
});
});
diff --git a/src/test/app/(protected)/workorders/type-cell.test.tsx b/src/test/app/(protected)/workorders/type-cell.test.tsx
index 64f6b02a..f7844681 100644
--- a/src/test/app/(protected)/workorders/type-cell.test.tsx
+++ b/src/test/app/(protected)/workorders/type-cell.test.tsx
@@ -83,6 +83,23 @@ describe("TypeCell", () => {
expect(onSave).toHaveBeenCalledWith("Reactive", 4);
});
+ it("does not open the picker or severity modal when viewOnly", async () => {
+ const onSave = vi.fn();
+ const user = userEvent.setup();
+ render();
+
+ expect(screen.queryByRole("button", { name: "Type of WO, Emergency" })).not.toBeInTheDocument();
+ expect(screen.getByText("Emergency")).toBeInTheDocument();
+ expect(screen.getByText("SEV 2")).toBeInTheDocument();
+
+ await user.click(screen.getByText("Emergency"));
+ await user.click(screen.getByText("SEV 2"));
+
+ expect(screen.queryByRole("button", { name: /^Reactive$/ })).not.toBeInTheDocument();
+ expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
+ expect(onSave).not.toHaveBeenCalled();
+ });
+
it("opens the modal from the severity badge", async () => {
const onSave = vi.fn();
const user = userEvent.setup();
diff --git a/src/test/app/(protected)/workorders/wo-table-row-cells-type-toast.test.tsx b/src/test/app/(protected)/workorders/wo-table-row-cells-type-toast.test.tsx
new file mode 100644
index 00000000..b98743e2
--- /dev/null
+++ b/src/test/app/(protected)/workorders/wo-table-row-cells-type-toast.test.tsx
@@ -0,0 +1,69 @@
+import { fireEvent, screen } from "@testing-library/react";
+import { describe, expect, it, vi } from "vitest";
+import { WoTableRowCells } from "@/app/(protected)/workorders/_components/list/table/wo-table-row-cells";
+import type { WoTableRowHandlers } from "@/app/(protected)/workorders/_components/list/table/wo-table-row";
+import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
+import { renderWithProviders } from "@/test/test-utils";
+
+vi.mock("@/app/(protected)/workorders/_components/list/table/cells/site-cell", () => ({
+ SiteCell: () => null,
+}));
+vi.mock(
+ "@/app/(protected)/workorders/_components/list/table/cells/editable-wo-number-cell",
+ () => ({
+ EditableWONumberCell: () => null,
+ }),
+);
+vi.mock("@/app/(protected)/workorders/_components/list/table/cells/type-cell", () => ({
+ TypeCell: ({ onSave }: { onSave: (type: string, severity: number) => void }) => (
+
+ ),
+}));
+vi.mock("@/app/(protected)/workorders/_components/list/table/cells/date-cell", () => ({
+ DateCell: () => null,
+}));
+vi.mock("@/app/(protected)/workorders/_components/list/table/cells/due-date-cell", () => ({
+ DueDateCell: () => null,
+}));
+vi.mock("@/app/(protected)/workorders/_components/list/table/cells/assigned-to-cell", () => ({
+ AssignedToCell: () => null,
+}));
+
+const row = { id: 7, woNumber: "00000024965", severity: 3 } as WorkOrderTableRow;
+
+describe("WoTableRowCells type persist", () => {
+ it("forwards type save through patch onSuccess instead of onPatchRow", () => {
+ const onPatch = vi.fn();
+ const onPatchRow = vi.fn();
+ const handlers = { onPatch } as unknown as WoTableRowHandlers;
+
+ renderWithProviders(
+ ,
+ { withAuth: false },
+ );
+
+ fireEvent.click(screen.getByRole("button", { name: "persist-type" }));
+
+ expect(onPatchRow).not.toHaveBeenCalled();
+ expect(onPatch).toHaveBeenCalledWith(
+ 7,
+ { type: "Emergency", severity: 1 },
+ expect.objectContaining({ onSuccess: expect.any(Function) }),
+ );
+ });
+});
diff --git a/src/test/app/(protected)/workorders/wo-table-row-completed-lock.test.tsx b/src/test/app/(protected)/workorders/wo-table-row-completed-lock.test.tsx
index 2c02e58c..7ced9b99 100644
--- a/src/test/app/(protected)/workorders/wo-table-row-completed-lock.test.tsx
+++ b/src/test/app/(protected)/workorders/wo-table-row-completed-lock.test.tsx
@@ -133,4 +133,56 @@ describe("WoTableRow completed selective lock", () => {
expect(screen.queryByRole("button", { name: /in progress/i })).not.toBeInTheDocument();
expect(handlers.onPatch).not.toHaveBeenCalled();
});
+
+ it("does not expose the type picker on a Completed row", () => {
+ const row = makeRow();
+ renderWithProviders(
+ ,
+ { withAuth: false },
+ );
+
+ expect(screen.queryByRole("button", { name: "Type of WO, PM" })).not.toBeInTheDocument();
+ expect(screen.getByText("PM")).toBeInTheDocument();
+ });
+
+ it("does not expose the type picker on a Canceled row", () => {
+ const row = makeRow({ status: "Canceled" });
+ renderWithProviders(
+ ,
+ { withAuth: false },
+ );
+
+ expect(screen.queryByRole("button", { name: "Type of WO, PM" })).not.toBeInTheDocument();
+ expect(screen.getByText("PM")).toBeInTheDocument();
+ });
});
|