mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-06 06:32:05 +00:00
330 lines
9.2 KiB
TypeScript
330 lines
9.2 KiB
TypeScript
import { act, renderHook } from "@testing-library/react";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { useSlideOverMediaState } from "@/app/(protected)/workorders/_components/detail/use-slide-over-media-state";
|
|
import type { WorkOrderBoardDetail } from "@/domain/work-orders/types/work-order-board-detail";
|
|
import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row";
|
|
|
|
function baseInfo(overrides: Partial<WorkOrderTableRow> = {}): WorkOrderTableRow {
|
|
return {
|
|
id: 100,
|
|
woNumber: "100",
|
|
site: "SITE",
|
|
type: "Emergency",
|
|
severity: null,
|
|
dispatcherId: "d1",
|
|
dispatcherName: "Alex",
|
|
scheduledOn: "2026-07-16",
|
|
completedDate: "",
|
|
targetWeek: "",
|
|
dayGroup: "2026-07-16",
|
|
dayLabel: "Thu",
|
|
location: "Main",
|
|
locationId: 5,
|
|
pm: "",
|
|
serviceNotes: "",
|
|
extraServices: [],
|
|
vendorId: "v1",
|
|
company: "Acme",
|
|
tech: "Sam",
|
|
techPhone: "",
|
|
apptStart: "",
|
|
apptEnd: "",
|
|
apptTime: "",
|
|
status: "Incomplete",
|
|
docStatus: "",
|
|
pocName: "",
|
|
pocPhone: "",
|
|
pocNotes: "",
|
|
additionalContacts: [],
|
|
dueDate: "",
|
|
rescheduleCount: 0,
|
|
carriedOver: 0,
|
|
originalWeek: "",
|
|
originalDate: "",
|
|
isPastDue: false,
|
|
scheduleWeekOnly: false,
|
|
mediaCount: 0,
|
|
title: "",
|
|
priority: "",
|
|
primaryDispatchId: null,
|
|
rowVersion: "1",
|
|
dispatchRowVersion: "",
|
|
flagColor: null,
|
|
isAddOn: false,
|
|
upliftSummary: { hasUplift: false, pendingCount: 0 },
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
function detailWithMedia(
|
|
media: WorkOrderBoardDetail["media"],
|
|
infoOverrides: Partial<WorkOrderTableRow> = {},
|
|
): WorkOrderBoardDetail {
|
|
return {
|
|
info: baseInfo(infoOverrides),
|
|
completion: {
|
|
docStatus: "",
|
|
template: null,
|
|
signOffName: "",
|
|
signOffAttachment: "",
|
|
signOffSignature: "",
|
|
dispatchSignoffs: [],
|
|
},
|
|
comments: [],
|
|
audit: [],
|
|
media,
|
|
};
|
|
}
|
|
|
|
function idleMutation() {
|
|
return {
|
|
mutate: vi.fn(),
|
|
mutateAsync: vi.fn().mockResolvedValue({}),
|
|
isPending: false,
|
|
} as never;
|
|
}
|
|
|
|
describe("useSlideOverMediaState completion filter", () => {
|
|
beforeEach(() => {
|
|
sessionStorage.clear();
|
|
});
|
|
|
|
it("keeps Before/After/Completion after refetch mapped purpose (not file category)", () => {
|
|
const detail = detailWithMedia([
|
|
{
|
|
id: "1",
|
|
category: "Before",
|
|
url: "https://cdn.example.com/before.jpg",
|
|
fileName: "before.jpg",
|
|
uploadedAt: "2026-07-15T18:00:00.0000000Z",
|
|
isLegacy: false,
|
|
},
|
|
{
|
|
id: "2",
|
|
category: "After",
|
|
url: "https://cdn.example.com/after.jpg",
|
|
fileName: "after.jpg",
|
|
uploadedAt: "2026-07-15T18:00:00.0000000Z",
|
|
isLegacy: false,
|
|
},
|
|
{
|
|
id: "3",
|
|
category: "Completion",
|
|
url: "https://cdn.example.com/completion.pdf",
|
|
fileName: "completion.pdf",
|
|
uploadedAt: "2026-07-15T18:00:00.0000000Z",
|
|
isLegacy: false,
|
|
},
|
|
{
|
|
id: "4",
|
|
category: "Extra",
|
|
url: "https://cdn.example.com/extra.pdf",
|
|
fileName: "extra.pdf",
|
|
uploadedAt: "2026-07-15T18:00:00.0000000Z",
|
|
isLegacy: false,
|
|
},
|
|
{
|
|
id: "10",
|
|
category: "Extra",
|
|
url: "https://cdn.example.com/site.jpg",
|
|
fileName: "site.jpg",
|
|
uploadedAt: "2026-07-15T18:00:00.0000000Z",
|
|
isLegacy: false,
|
|
},
|
|
]);
|
|
|
|
const { result } = renderHook(() =>
|
|
useSlideOverMediaState({
|
|
detailForRow: detail,
|
|
uploadMediaMutation: idleMutation(),
|
|
deleteMediaMutation: idleMutation(),
|
|
categorizeMediaMutation: idleMutation(),
|
|
}),
|
|
);
|
|
|
|
expect(result.current.completionMedia.map((item) => item.purpose)).toEqual([
|
|
"Before",
|
|
"After",
|
|
"Completion",
|
|
"Extra",
|
|
]);
|
|
expect(result.current.completionMedia.map((item) => item.id)).toContain("10");
|
|
expect(
|
|
result.current.completionMedia.every((item) =>
|
|
["Photo", "Video", "Report", "Other"].includes(item.category),
|
|
),
|
|
).toBe(true);
|
|
expect(result.current.extrasUploads).toHaveLength(1);
|
|
expect(result.current.extrasUploads[0]?.purpose).toBe("Extra");
|
|
expect(result.current.extrasUploads[0]?.id).toBe("4");
|
|
});
|
|
|
|
it("keeps Extra photos on Completion Doc until Extra is assigned", () => {
|
|
const detail = detailWithMedia([
|
|
{
|
|
id: "10",
|
|
category: "Extra",
|
|
url: "https://cdn.example.com/site.jpg",
|
|
fileName: "site.jpg",
|
|
uploadedAt: "2026-07-15T18:00:00.0000000Z",
|
|
isLegacy: false,
|
|
},
|
|
]);
|
|
|
|
const { result } = renderHook(() =>
|
|
useSlideOverMediaState({
|
|
detailForRow: detail,
|
|
uploadMediaMutation: idleMutation(),
|
|
deleteMediaMutation: idleMutation(),
|
|
categorizeMediaMutation: idleMutation(),
|
|
}),
|
|
);
|
|
|
|
expect(result.current.completionMedia.map((item) => item.id)).toEqual(["10"]);
|
|
expect(result.current.extrasUploads).toHaveLength(0);
|
|
});
|
|
|
|
it("includes Aveta-categorized extra documents in extrasUploads", () => {
|
|
const detail = detailWithMedia([
|
|
{
|
|
id: "4",
|
|
category: "Extra",
|
|
url: "https://cdn.example.com/extra.pdf",
|
|
fileName: "extra.pdf",
|
|
uploadedAt: "2026-07-15T18:00:00.0000000Z",
|
|
isLegacy: false,
|
|
},
|
|
{
|
|
id: "5",
|
|
category: "Aveta",
|
|
url: "https://cdn.example.com/aveta.pdf",
|
|
fileName: "aveta.pdf",
|
|
uploadedAt: "2026-07-15T18:00:00.0000000Z",
|
|
isLegacy: false,
|
|
},
|
|
]);
|
|
|
|
const { result } = renderHook(() =>
|
|
useSlideOverMediaState({
|
|
detailForRow: detail,
|
|
uploadMediaMutation: idleMutation(),
|
|
deleteMediaMutation: idleMutation(),
|
|
categorizeMediaMutation: idleMutation(),
|
|
}),
|
|
);
|
|
|
|
expect(result.current.extrasUploads).toHaveLength(2);
|
|
expect(result.current.extrasUploads.map((item) => item.purpose)).toEqual(["Extra", "Aveta"]);
|
|
expect(result.current.extrasUploads[1]?.category).toBe("Aveta");
|
|
});
|
|
|
|
it("keeps an Extra photo in Extra Docs after assigning Extra and remounting", () => {
|
|
const detail = detailWithMedia([
|
|
{
|
|
id: "10",
|
|
category: "Extra",
|
|
url: "https://cdn.example.com/site.jpg",
|
|
fileName: "site.jpg",
|
|
uploadedAt: "2026-07-15T18:00:00.0000000Z",
|
|
isLegacy: false,
|
|
},
|
|
]);
|
|
const categorizeMutate = vi.fn((_input: unknown, options?: { onSuccess?: () => void }) =>
|
|
options?.onSuccess?.(),
|
|
);
|
|
const categorize = {
|
|
mutate: categorizeMutate,
|
|
mutateAsync: vi.fn().mockResolvedValue({}),
|
|
isPending: false,
|
|
} as never;
|
|
|
|
const { result, unmount } = renderHook(() =>
|
|
useSlideOverMediaState({
|
|
detailForRow: detail,
|
|
uploadMediaMutation: idleMutation(),
|
|
deleteMediaMutation: idleMutation(),
|
|
categorizeMediaMutation: categorize,
|
|
}),
|
|
);
|
|
|
|
expect(result.current.completionMedia).toHaveLength(1);
|
|
expect(result.current.extrasUploads).toHaveLength(0);
|
|
|
|
act(() => {
|
|
result.current.categorizeMedia("10", "Extra");
|
|
});
|
|
|
|
expect(result.current.completionMedia).toHaveLength(0);
|
|
expect(result.current.extrasUploads.map((item) => item.id)).toEqual(["10"]);
|
|
expect(categorizeMutate).toHaveBeenCalledWith(
|
|
{
|
|
mediaId: "10",
|
|
category: "Extra",
|
|
workOrderVersion: "1",
|
|
},
|
|
expect.objectContaining({ onSuccess: expect.any(Function) }),
|
|
);
|
|
|
|
unmount();
|
|
const remounted = renderHook(() =>
|
|
useSlideOverMediaState({
|
|
detailForRow: detail,
|
|
uploadMediaMutation: idleMutation(),
|
|
deleteMediaMutation: idleMutation(),
|
|
categorizeMediaMutation: idleMutation(),
|
|
}),
|
|
);
|
|
|
|
expect(remounted.result.current.completionMedia).toHaveLength(0);
|
|
expect(remounted.result.current.extrasUploads.map((item) => item.id)).toEqual(["10"]);
|
|
});
|
|
|
|
it("shows Extra photos and videos in Extra Docs on PM work orders", () => {
|
|
const detail = detailWithMedia(
|
|
[
|
|
{
|
|
id: "10",
|
|
category: "Extra",
|
|
url: "https://cdn.example.com/site.jpg",
|
|
fileName: "site.jpg",
|
|
uploadedAt: "2026-07-15T18:00:00.0000000Z",
|
|
isLegacy: false,
|
|
},
|
|
{
|
|
id: "11",
|
|
category: "Extra",
|
|
url: "https://cdn.example.com/walkthrough.mp4",
|
|
fileName: "walkthrough.mp4",
|
|
uploadedAt: "2026-07-15T18:00:00.0000000Z",
|
|
isLegacy: false,
|
|
},
|
|
{
|
|
id: "4",
|
|
category: "Extra",
|
|
url: "https://cdn.example.com/extra.pdf",
|
|
fileName: "extra.pdf",
|
|
uploadedAt: "2026-07-15T18:00:00.0000000Z",
|
|
isLegacy: false,
|
|
},
|
|
],
|
|
{ id: 200, type: "PM" },
|
|
);
|
|
|
|
const { result } = renderHook(() =>
|
|
useSlideOverMediaState({
|
|
detailForRow: detail,
|
|
uploadMediaMutation: idleMutation(),
|
|
deleteMediaMutation: idleMutation(),
|
|
categorizeMediaMutation: idleMutation(),
|
|
}),
|
|
);
|
|
|
|
expect(result.current.completionMedia).toHaveLength(0);
|
|
expect(result.current.extrasUploads.map((item) => item.id)).toEqual(["10", "11", "4"]);
|
|
expect(result.current.extrasUploads.map((item) => item.fileType)).toEqual([
|
|
"image",
|
|
"video",
|
|
"pdf",
|
|
]);
|
|
});
|
|
});
|