mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-01 14:23:11 +00:00
Board Clear uses empty-week patch; slide-over Save derives Pending via mergeAutoSchedulePatch.
179 lines
5.4 KiB
TypeScript
179 lines
5.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
buildSlideOverPatch,
|
|
isSlideOverDraftDirty,
|
|
SLIDE_OVER_EDIT_KEYS,
|
|
} from "@/domain/work-orders/utils/slide-over-draft";
|
|
import { EMPTY_UPLIFT_SUMMARY } from "@/domain/work-orders/types/work-order-uplift";
|
|
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
|
|
import { mergeAutoSchedulePatch } from "@/domain/work-orders/utils/wo-lifecycle-transitions";
|
|
|
|
function baseRow(overrides: Partial<WorkOrderTableRow> = {}): WorkOrderTableRow {
|
|
return {
|
|
id: 1,
|
|
woNumber: "1001",
|
|
site: "SITE-A",
|
|
type: "PM",
|
|
severity: null,
|
|
dispatcherId: "10",
|
|
dispatcherName: "Alex",
|
|
scheduledOn: "2026-07-16",
|
|
completedDate: "",
|
|
targetWeek: "",
|
|
dayGroup: "2026-07-16",
|
|
dayLabel: "Thu",
|
|
location: "Main",
|
|
locationId: 5,
|
|
pm: "Plumbing",
|
|
serviceNotes: "",
|
|
extraServices: [],
|
|
vendorId: "v1",
|
|
company: "Acme",
|
|
tech: "Sam",
|
|
techPhone: "",
|
|
apptStart: "",
|
|
apptEnd: "",
|
|
apptTime: "09:00",
|
|
status: "Incomplete",
|
|
docStatus: "",
|
|
pocName: "",
|
|
pocPhone: "",
|
|
pocNotes: "",
|
|
additionalContacts: [],
|
|
dueDate: "2026-07-20",
|
|
rescheduleCount: 0,
|
|
carriedOver: 0,
|
|
isAddOn: false,
|
|
originalWeek: "",
|
|
originalDate: "",
|
|
isPastDue: false,
|
|
scheduleWeekOnly: false,
|
|
mediaCount: 0,
|
|
title: "",
|
|
priority: "",
|
|
primaryDispatchId: null,
|
|
rowVersion: "1",
|
|
dispatchRowVersion: "",
|
|
flagColor: null,
|
|
upliftSummary: EMPTY_UPLIFT_SUMMARY,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe("slide-over-draft", () => {
|
|
it("exposes only board-persistable edit keys", () => {
|
|
expect(SLIDE_OVER_EDIT_KEYS).toContain("woNumber");
|
|
expect(SLIDE_OVER_EDIT_KEYS).toContain("status");
|
|
expect(SLIDE_OVER_EDIT_KEYS).toContain("vendorId");
|
|
expect(SLIDE_OVER_EDIT_KEYS).toContain("additionalContacts");
|
|
expect(SLIDE_OVER_EDIT_KEYS).toContain("avetaRequired");
|
|
expect(SLIDE_OVER_EDIT_KEYS).not.toContain("pocName");
|
|
expect(SLIDE_OVER_EDIT_KEYS).not.toContain("locationId");
|
|
expect(SLIDE_OVER_EDIT_KEYS).not.toContain("techPhone");
|
|
expect(SLIDE_OVER_EDIT_KEYS).not.toContain("company");
|
|
expect(SLIDE_OVER_EDIT_KEYS).not.toContain("tech");
|
|
});
|
|
|
|
it("tracks vendor via vendorId only (company/tech are display companions)", () => {
|
|
const row = baseRow();
|
|
const draft = baseRow({ company: "Other Co", tech: "Pat" });
|
|
expect(isSlideOverDraftDirty(draft, row)).toBe(false);
|
|
expect(buildSlideOverPatch(draft, row)).toEqual({});
|
|
|
|
const vendorDraft = baseRow({ vendorId: "v2", company: "Other Co", tech: "Pat" });
|
|
expect(isSlideOverDraftDirty(vendorDraft, row)).toBe(true);
|
|
expect(buildSlideOverPatch(vendorDraft, row)).toEqual({ vendorId: "v2" });
|
|
});
|
|
|
|
it("ignores POC-only edits for dirty state", () => {
|
|
const row = baseRow();
|
|
const draft = baseRow({ pocName: "Jordan", pocPhone: "555-0100" });
|
|
expect(isSlideOverDraftDirty(draft, row)).toBe(false);
|
|
expect(buildSlideOverPatch(draft, row)).toEqual({});
|
|
});
|
|
|
|
it("detects dirty draft when a tracked field changes", () => {
|
|
const row = baseRow();
|
|
const draft = baseRow({ scheduledOn: "2026-07-17" });
|
|
expect(isSlideOverDraftDirty(draft, row)).toBe(true);
|
|
});
|
|
|
|
it("clears client schedule range overlays in the save patch", () => {
|
|
const row = baseRow({
|
|
scheduleEnd: "2026-07-18",
|
|
schedMode: "range",
|
|
});
|
|
const draft = baseRow({
|
|
scheduledOn: "",
|
|
scheduleEnd: "",
|
|
schedMode: undefined,
|
|
});
|
|
|
|
expect(buildSlideOverPatch(draft, row)).toEqual({
|
|
scheduledOn: "",
|
|
scheduleEnd: "",
|
|
schedMode: undefined,
|
|
});
|
|
});
|
|
|
|
it("is not dirty when values match", () => {
|
|
const row = baseRow();
|
|
expect(isSlideOverDraftDirty(row, row)).toBe(false);
|
|
});
|
|
|
|
it("builds a patch with only changed fields", () => {
|
|
const row = baseRow();
|
|
const draft = baseRow({
|
|
woNumber: "1002",
|
|
status: "Completed",
|
|
extraServices: ["HVAC"],
|
|
});
|
|
expect(buildSlideOverPatch(draft, row)).toEqual({
|
|
woNumber: "1002",
|
|
status: "Completed",
|
|
extraServices: ["HVAC"],
|
|
});
|
|
});
|
|
|
|
it("derives Pending on persist when a Scheduled draft clears Schedule On", () => {
|
|
const baseline = baseRow({
|
|
status: "Scheduled",
|
|
scheduledOn: "2026-07-16",
|
|
scheduleWeekOnly: false,
|
|
targetWeek: "",
|
|
scheduleEnd: "",
|
|
schedMode: "date",
|
|
});
|
|
const draft = baseRow({
|
|
status: "Scheduled",
|
|
scheduledOn: "",
|
|
scheduleWeekOnly: false,
|
|
targetWeek: "",
|
|
scheduleEnd: "",
|
|
schedMode: undefined,
|
|
});
|
|
|
|
const patch = buildSlideOverPatch(draft, baseline);
|
|
expect(patch).toEqual({
|
|
scheduledOn: "",
|
|
schedMode: undefined,
|
|
});
|
|
expect(patch.status).toBeUndefined();
|
|
expect(mergeAutoSchedulePatch(baseline, patch)).toEqual(
|
|
expect.objectContaining({
|
|
scheduledOn: "",
|
|
status: "Pending",
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("tracks ordered additionalContacts for dirty state and patch (SH-218)", () => {
|
|
const row = baseRow();
|
|
const contacts = [{ name: "Backup", phone: "555-0101", notes: "Gate" }];
|
|
const draft = baseRow({ additionalContacts: contacts });
|
|
|
|
expect(isSlideOverDraftDirty(draft, row)).toBe(true);
|
|
expect(buildSlideOverPatch(draft, row)).toEqual({ additionalContacts: contacts });
|
|
expect(isSlideOverDraftDirty(baseRow({ additionalContacts: [] }), row)).toBe(false);
|
|
});
|
|
});
|