2026-08-19 14:45:59 -03:00
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
|
|
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
|
|
|
|
|
|
import { currentWeekMonday } from "@/domain/work-orders/utils/list-week-utils";
|
|
|
|
|
|
import {
|
|
|
|
|
|
buildSelectedDayGroup,
|
|
|
|
|
|
firstWeekday,
|
|
|
|
|
|
formatDayTabLabel,
|
|
|
|
|
|
initialSelectedDay,
|
2026-08-20 09:21:45 -03:00
|
|
|
|
isDayScopedSearchEmpty,
|
2026-08-20 10:28:04 -03:00
|
|
|
|
isUnassignedQueueReady,
|
2026-08-19 14:45:59 -03:00
|
|
|
|
rowMatchesSelectedDay,
|
2026-08-20 09:21:45 -03:00
|
|
|
|
scheduledDayTab,
|
2026-08-19 14:45:59 -03:00
|
|
|
|
weekdaysMonFri,
|
|
|
|
|
|
} from "@/domain/work-orders/utils/week-day-nav-utils";
|
|
|
|
|
|
import { addDaysIso } from "@/domain/work-orders/utils/wizard-date-utils";
|
|
|
|
|
|
|
|
|
|
|
|
function row(overrides: Partial<WorkOrderTableRow>): WorkOrderTableRow {
|
|
|
|
|
|
return {
|
|
|
|
|
|
id: "1",
|
|
|
|
|
|
woNumber: "1",
|
|
|
|
|
|
site: "",
|
|
|
|
|
|
type: "PM",
|
|
|
|
|
|
severity: null,
|
|
|
|
|
|
dispatcherId: "d1",
|
|
|
|
|
|
dispatcherName: "D",
|
|
|
|
|
|
scheduledOn: "",
|
|
|
|
|
|
completedDate: "",
|
|
|
|
|
|
targetWeek: "",
|
|
|
|
|
|
dayGroup: "",
|
|
|
|
|
|
dayLabel: "",
|
|
|
|
|
|
location: "",
|
|
|
|
|
|
locationId: "",
|
|
|
|
|
|
pm: "",
|
|
|
|
|
|
serviceNotes: "",
|
|
|
|
|
|
extraServices: [],
|
|
|
|
|
|
vendorId: "",
|
|
|
|
|
|
company: "",
|
|
|
|
|
|
tech: "",
|
|
|
|
|
|
techPhone: "",
|
|
|
|
|
|
apptStart: "",
|
|
|
|
|
|
apptEnd: "",
|
|
|
|
|
|
apptTime: "",
|
|
|
|
|
|
status: "Incomplete",
|
|
|
|
|
|
docStatus: "No",
|
|
|
|
|
|
pocName: "",
|
|
|
|
|
|
pocPhone: "",
|
|
|
|
|
|
pocNotes: "",
|
|
|
|
|
|
additionalContacts: [],
|
|
|
|
|
|
dueDate: "",
|
|
|
|
|
|
rescheduleCount: 0,
|
|
|
|
|
|
carriedOver: 0,
|
|
|
|
|
|
isAddOn: false,
|
|
|
|
|
|
originalWeek: "",
|
|
|
|
|
|
originalDate: "",
|
|
|
|
|
|
isPastDue: false,
|
|
|
|
|
|
scheduleWeekOnly: false,
|
|
|
|
|
|
mediaCount: 0,
|
|
|
|
|
|
title: "",
|
|
|
|
|
|
priority: "",
|
|
|
|
|
|
primaryDispatchId: null,
|
|
|
|
|
|
rowVersion: "",
|
|
|
|
|
|
dispatchRowVersion: "",
|
|
|
|
|
|
flagColor: null,
|
|
|
|
|
|
...overrides,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
describe("week-day-nav-utils (SH-240)", () => {
|
|
|
|
|
|
it("lists Mon–Fri of the active week", () => {
|
|
|
|
|
|
expect(weekdaysMonFri("2026-05-18")).toEqual([
|
|
|
|
|
|
"2026-05-18",
|
|
|
|
|
|
"2026-05-19",
|
|
|
|
|
|
"2026-05-20",
|
|
|
|
|
|
"2026-05-21",
|
|
|
|
|
|
"2026-05-22",
|
|
|
|
|
|
]);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it("formats day tabs as Title · MM/DD", () => {
|
|
|
|
|
|
expect(formatDayTabLabel("2026-05-18")).toBe("Mon · 05/18");
|
|
|
|
|
|
expect(formatDayTabLabel("2026-05-22")).toBe("Fri · 05/22");
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it("resets to Monday when the week changes", () => {
|
|
|
|
|
|
expect(firstWeekday("2026-05-25")).toBe("2026-05-25");
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it("selects today on the live week when today is a weekday", () => {
|
|
|
|
|
|
const liveMonday = currentWeekMonday();
|
|
|
|
|
|
const wednesday = addDaysIso(liveMonday, 2);
|
|
|
|
|
|
expect(initialSelectedDay(liveMonday, wednesday)).toBe(wednesday);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it("selects Monday on a non-live week", () => {
|
|
|
|
|
|
expect(initialSelectedDay("2026-05-18", "2026-05-20")).toBe("2026-05-18");
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it("excludes unscheduled and other days from the selected day group", () => {
|
|
|
|
|
|
const monday = row({
|
|
|
|
|
|
id: "mon",
|
|
|
|
|
|
scheduledOn: "2026-05-18",
|
|
|
|
|
|
dayGroup: "05/18",
|
|
|
|
|
|
dayLabel: "MON · 05/18",
|
|
|
|
|
|
});
|
|
|
|
|
|
const wednesday = row({
|
|
|
|
|
|
id: "wed",
|
|
|
|
|
|
scheduledOn: "2026-05-20",
|
|
|
|
|
|
dayGroup: "05/20",
|
|
|
|
|
|
dayLabel: "WED · 05/20",
|
|
|
|
|
|
});
|
|
|
|
|
|
const unscheduled = row({ id: "us", scheduledOn: "", scheduleWeekOnly: true });
|
|
|
|
|
|
|
|
|
|
|
|
expect(rowMatchesSelectedDay(unscheduled, "2026-05-18")).toBe(false);
|
|
|
|
|
|
expect(rowMatchesSelectedDay(monday, "2026-05-18")).toBe(true);
|
|
|
|
|
|
|
|
|
|
|
|
const group = buildSelectedDayGroup("2026-05-18", "2026-05-18", [
|
|
|
|
|
|
monday,
|
|
|
|
|
|
wednesday,
|
|
|
|
|
|
unscheduled,
|
|
|
|
|
|
]);
|
|
|
|
|
|
expect(group.date).toBe("2026-05-18");
|
|
|
|
|
|
expect(group.label).toBe("Mon · 05/18");
|
|
|
|
|
|
expect(group.items.map((item) => item.id)).toEqual(["mon"]);
|
|
|
|
|
|
});
|
2026-08-20 09:21:45 -03:00
|
|
|
|
|
|
|
|
|
|
it("maps a scheduled weekday onto its week and day tab", () => {
|
|
|
|
|
|
expect(scheduledDayTab("2026-05-20")).toEqual({
|
|
|
|
|
|
weekMonday: "2026-05-18",
|
|
|
|
|
|
selectedDayIso: "2026-05-20",
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it("treats search as empty only when the selected day and Unassigned have no hits", () => {
|
|
|
|
|
|
expect(
|
2026-08-20 10:28:04 -03:00
|
|
|
|
isDayScopedSearchEmpty({
|
|
|
|
|
|
searchActive: true,
|
|
|
|
|
|
unassignedCount: 0,
|
|
|
|
|
|
dayItemCount: 0,
|
|
|
|
|
|
unassignedQueueReady: true,
|
|
|
|
|
|
}),
|
2026-08-20 09:21:45 -03:00
|
|
|
|
).toBe(true);
|
|
|
|
|
|
expect(
|
2026-08-20 10:28:04 -03:00
|
|
|
|
isDayScopedSearchEmpty({
|
|
|
|
|
|
searchActive: true,
|
|
|
|
|
|
unassignedCount: 0,
|
|
|
|
|
|
dayItemCount: 1,
|
|
|
|
|
|
unassignedQueueReady: true,
|
|
|
|
|
|
}),
|
2026-08-20 09:21:45 -03:00
|
|
|
|
).toBe(false);
|
|
|
|
|
|
expect(
|
2026-08-20 10:28:04 -03:00
|
|
|
|
isDayScopedSearchEmpty({
|
|
|
|
|
|
searchActive: true,
|
|
|
|
|
|
unassignedCount: 2,
|
|
|
|
|
|
dayItemCount: 0,
|
|
|
|
|
|
unassignedQueueReady: true,
|
|
|
|
|
|
}),
|
2026-08-20 09:21:45 -03:00
|
|
|
|
).toBe(false);
|
|
|
|
|
|
expect(
|
2026-08-20 10:28:04 -03:00
|
|
|
|
isDayScopedSearchEmpty({
|
|
|
|
|
|
searchActive: false,
|
|
|
|
|
|
unassignedCount: 0,
|
|
|
|
|
|
dayItemCount: 0,
|
|
|
|
|
|
unassignedQueueReady: true,
|
|
|
|
|
|
}),
|
|
|
|
|
|
).toBe(false);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it("does not treat search as empty while the Unassigned queue is loading or failed", () => {
|
|
|
|
|
|
expect(isUnassignedQueueReady(true, null)).toBe(false);
|
|
|
|
|
|
expect(isUnassignedQueueReady(false, new Error("queue unavailable"))).toBe(false);
|
|
|
|
|
|
expect(isUnassignedQueueReady(false, null)).toBe(true);
|
|
|
|
|
|
expect(
|
|
|
|
|
|
isDayScopedSearchEmpty({
|
|
|
|
|
|
searchActive: true,
|
|
|
|
|
|
unassignedCount: 0,
|
|
|
|
|
|
dayItemCount: 0,
|
|
|
|
|
|
unassignedQueueReady: false,
|
|
|
|
|
|
}),
|
2026-08-20 09:21:45 -03:00
|
|
|
|
).toBe(false);
|
|
|
|
|
|
});
|
2026-08-19 14:45:59 -03:00
|
|
|
|
});
|
2026-09-01 14:16:52 -03:00
|
|
|
|
|
|
|
|
|
|
describe("week-day-nav-utils carry-over display", () => {
|
|
|
|
|
|
it("places a prior-week unresolved WO on the same weekday of the viewed week", () => {
|
|
|
|
|
|
const carried = row({
|
|
|
|
|
|
id: "co",
|
|
|
|
|
|
scheduledOn: "2026-05-13",
|
|
|
|
|
|
dayGroup: "05/13",
|
|
|
|
|
|
status: "Scheduled",
|
|
|
|
|
|
carriedOver: 2,
|
|
|
|
|
|
originalWeek: "2026-05-11",
|
|
|
|
|
|
});
|
|
|
|
|
|
const nativeWed = row({
|
|
|
|
|
|
id: "native",
|
|
|
|
|
|
scheduledOn: "2026-05-20",
|
|
|
|
|
|
dayGroup: "05/20",
|
|
|
|
|
|
status: "Scheduled",
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
expect(rowMatchesSelectedDay(carried, "2026-05-20", "2026-05-18")).toBe(true);
|
|
|
|
|
|
expect(rowMatchesSelectedDay(carried, "2026-05-18", "2026-05-18")).toBe(false);
|
|
|
|
|
|
|
|
|
|
|
|
const group = buildSelectedDayGroup("2026-05-18", "2026-05-20", [carried, nativeWed]);
|
|
|
|
|
|
expect(group.items.map((item) => item.id)).toEqual(["co", "native"]);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it("does not map completed carry-overs onto the viewed week", () => {
|
|
|
|
|
|
const completed = row({
|
|
|
|
|
|
id: "done",
|
|
|
|
|
|
scheduledOn: "2026-05-13",
|
|
|
|
|
|
status: "Completed",
|
|
|
|
|
|
carriedOver: 2,
|
|
|
|
|
|
});
|
|
|
|
|
|
expect(rowMatchesSelectedDay(completed, "2026-05-20", "2026-05-18")).toBe(false);
|
|
|
|
|
|
expect(buildSelectedDayGroup("2026-05-18", "2026-05-20", [completed]).items).toEqual([]);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it("keeps unscheduled rows out of day groups", () => {
|
|
|
|
|
|
const unscheduled = row({ id: "us", scheduledOn: "", scheduleWeekOnly: true, carriedOver: 2 });
|
|
|
|
|
|
expect(rowMatchesSelectedDay(unscheduled, "2026-05-18", "2026-05-18")).toBe(false);
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|