diff --git a/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-filters.png b/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-filters.png index 4a551b64..cb3e224a 100644 Binary files a/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-filters.png and b/e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-filters.png differ diff --git a/src/app/(protected)/workorders/_components/detail/work-order-slide-over-tabs.tsx b/src/app/(protected)/workorders/_components/detail/work-order-slide-over-tabs.tsx index 04a68747..3a653c78 100644 --- a/src/app/(protected)/workorders/_components/detail/work-order-slide-over-tabs.tsx +++ b/src/app/(protected)/workorders/_components/detail/work-order-slide-over-tabs.tsx @@ -10,6 +10,7 @@ import type { WorkOrderUser, } from "@/domain/work-orders/types/work-order"; import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row"; +import { resolveSlideOverAvetaRequired } from "@/domain/work-orders/utils/resolve-slide-over-aveta-required"; import type { useWorkOrderSlideOver, SlideOverTab } from "./use-work-order-slide-over"; import { WorkOrderSlideOverTabPanel } from "./work-order-slide-over-tab-panel"; @@ -146,7 +147,11 @@ export function WorkOrderSlideOverTabs({ > { diff --git a/src/domain/work-orders/utils/resolve-slide-over-aveta-required.ts b/src/domain/work-orders/utils/resolve-slide-over-aveta-required.ts new file mode 100644 index 00000000..7d4b3daf --- /dev/null +++ b/src/domain/work-orders/utils/resolve-slide-over-aveta-required.ts @@ -0,0 +1,8 @@ +/** Extras overlay follows the unsaved Info draft while editing. */ +export function resolveSlideOverAvetaRequired( + editing: boolean, + persisted: boolean | undefined, + draft: boolean | undefined, +): boolean { + return Boolean(editing ? draft : persisted); +} diff --git a/src/test/app/(protected)/workorders/slide-over-extras-aveta-draft.test.tsx b/src/test/app/(protected)/workorders/slide-over-extras-aveta-draft.test.tsx new file mode 100644 index 00000000..50a808d3 --- /dev/null +++ b/src/test/app/(protected)/workorders/slide-over-extras-aveta-draft.test.tsx @@ -0,0 +1,117 @@ +import { screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; +import { WorkOrderSlideOverTabs } from "@/app/(protected)/workorders/_components/detail/work-order-slide-over-tabs"; +import type { useWorkOrderSlideOver } from "@/app/(protected)/workorders/_components/detail/use-work-order-slide-over"; +import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row"; +import { renderWithProviders } from "@/test/test-utils"; + +type SlideOverState = ReturnType; + +function baseRow(overrides: Partial = {}): WorkOrderTableRow { + return { + id: 42, + woNumber: "WO-42", + site: "SEA1", + type: "PM", + severity: null, + dispatcherId: "u1", + dispatcherName: "Dispatcher", + scheduledOn: "2026-07-20", + completedDate: "", + targetWeek: "", + dayGroup: "07/20", + dayLabel: "Mon", + location: "Seattle", + locationId: "loc-1", + pm: "HVAC", + serviceNotes: "", + extraServices: [], + company: "Vendor Co", + tech: "Tech", + techPhone: "", + vendorId: "v1", + apptStart: "", + apptEnd: "", + apptTime: "", + status: "Scheduled", + docStatus: "No", + pocName: "", + pocPhone: "", + pocNotes: "", + additionalContacts: [], + dueDate: "", + rescheduleCount: 0, + carriedOver: 0, + originalWeek: "", + originalDate: "", + isPastDue: false, + scheduleWeekOnly: false, + mediaCount: 0, + title: "PM — SEA1", + priority: "Sev 3", + primaryDispatchId: null, + rowVersion: "v1", + dispatchRowVersion: "", + flagColor: null, + isAddOn: false, + avetaRequired: false, + upliftSummary: { hasUplift: false, pendingCount: 0 }, + ...overrides, + }; +} + +function extrasState(editing: boolean, persisted: boolean, draft: boolean): SlideOverState { + return { + error: null, + detailForRow: undefined, + isLoading: false, + infoSource: baseRow({ avetaRequired: persisted }), + activeDraft: baseRow({ avetaRequired: draft }), + showDetailSkeleton: false, + errorMessage: "", + refetch: vi.fn(), + extrasUploads: [], + isExtrasReadOnly: true, + mediaPending: false, + uploadExtraFiles: vi.fn(), + removeMedia: vi.fn(), + editing, + } as unknown as SlideOverState; +} + +function renderExtras(state: SlideOverState) { + return renderWithProviders( + , + ); +} + +describe("WorkOrderSlideOverTabs Extras Aveta draft", () => { + it("shows the Extras Aveta indicator from an unsaved false-to-true draft", () => { + renderExtras(extrasState(true, false, true)); + + expect(screen.getByText("Extra Documents")).toBeInTheDocument(); + expect(screen.getByText("Aveta")).toBeInTheDocument(); + }); + + it("hides the Extras Aveta indicator from an unsaved true-to-false draft", () => { + renderExtras(extrasState(true, true, false)); + + expect(screen.getByText("Extra Documents")).toBeInTheDocument(); + expect(screen.queryByText("Aveta")).not.toBeInTheDocument(); + }); + + it("keeps the persisted Aveta indicator when not editing", () => { + renderExtras(extrasState(false, true, false)); + + expect(screen.getByText("Aveta")).toBeInTheDocument(); + }); +}); diff --git a/src/test/domain/work-orders/utils/resolve-slide-over-aveta-required.test.ts b/src/test/domain/work-orders/utils/resolve-slide-over-aveta-required.test.ts new file mode 100644 index 00000000..bf4c7193 --- /dev/null +++ b/src/test/domain/work-orders/utils/resolve-slide-over-aveta-required.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, it } from "vitest"; +import { resolveSlideOverAvetaRequired } from "@/domain/work-orders/utils/resolve-slide-over-aveta-required"; + +describe("resolveSlideOverAvetaRequired", () => { + it("uses the draft when editing false-to-true", () => { + expect(resolveSlideOverAvetaRequired(true, false, true)).toBe(true); + }); + + it("uses the draft when editing true-to-false", () => { + expect(resolveSlideOverAvetaRequired(true, true, false)).toBe(false); + }); + + it("uses the persisted row when not editing", () => { + expect(resolveSlideOverAvetaRequired(false, false, true)).toBe(false); + expect(resolveSlideOverAvetaRequired(false, true, false)).toBe(true); + }); +});