mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-07 04:42:03 +00:00
fix(work-orders): require explicit Aveta Extra Docs category
This commit is contained in:
parent
7a30335ab8
commit
5dfb2fb1c1
5 changed files with 47 additions and 44 deletions
|
|
@ -40,22 +40,16 @@ type SlideOverExtrasTabProps = {
|
||||||
|
|
||||||
function ExtraDocRow({
|
function ExtraDocRow({
|
||||||
file,
|
file,
|
||||||
index,
|
|
||||||
uploads,
|
|
||||||
avetaRequired,
|
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
pending,
|
pending,
|
||||||
onRemove,
|
onRemove,
|
||||||
}: {
|
}: {
|
||||||
file: MediaFile;
|
file: MediaFile;
|
||||||
index: number;
|
|
||||||
uploads: MediaFile[];
|
|
||||||
avetaRequired: boolean;
|
|
||||||
isReadOnly: boolean;
|
isReadOnly: boolean;
|
||||||
pending: boolean;
|
pending: boolean;
|
||||||
onRemove: (id: string) => void;
|
onRemove: (id: string) => void;
|
||||||
}) {
|
}) {
|
||||||
const category = resolveExtraDocCategory(file, index, avetaRequired, uploads);
|
const category = resolveExtraDocCategory(file);
|
||||||
const isAveta = category === "Aveta";
|
const isAveta = category === "Aveta";
|
||||||
const ItemIcon = isAveta ? ShieldCheck : FILETYPE_ICON[file.fileType];
|
const ItemIcon = isAveta ? ShieldCheck : FILETYPE_ICON[file.fileType];
|
||||||
const showDelete = !isReadOnly && canDeleteWorkOrderMedia(file);
|
const showDelete = !isReadOnly && canDeleteWorkOrderMedia(file);
|
||||||
|
|
@ -192,13 +186,10 @@ export function SlideOverExtrasTab({
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
{uploads.map((file, index) => (
|
{uploads.map((file) => (
|
||||||
<ExtraDocRow
|
<ExtraDocRow
|
||||||
key={file.id}
|
key={file.id}
|
||||||
file={file}
|
file={file}
|
||||||
index={index}
|
|
||||||
uploads={uploads}
|
|
||||||
avetaRequired={avetaRequired}
|
|
||||||
isReadOnly={isReadOnly}
|
isReadOnly={isReadOnly}
|
||||||
pending={pending}
|
pending={pending}
|
||||||
onRemove={onRemove}
|
onRemove={onRemove}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ export function useSlideOverMediaState({
|
||||||
setMediaBatchPending(true);
|
setMediaBatchPending(true);
|
||||||
try {
|
try {
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
// Board purpose is Extra only; Aveta is a UI overlay when avetaRequired.
|
// Board purpose is Extra only; Aveta overlay requires an explicit Extra Docs category.
|
||||||
await uploadMediaMutation.mutateAsync({ file, category: "Extra" });
|
await uploadMediaMutation.mutateAsync({ file, category: "Extra" });
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,14 @@
|
||||||
import type { MediaCategory, MediaFile } from "@/domain/work-orders/types/work-order-media";
|
import type { MediaCategory, MediaFile } from "@/domain/work-orders/types/work-order-media";
|
||||||
|
|
||||||
/** First Extra Docs file defaults to Aveta when the WO is flagged and none is Aveta yet.
|
/**
|
||||||
* Board media purpose stays Extra (API enum Before/After/Extra/Completion). */
|
* Extra Docs overlay category. Board purpose stays Extra
|
||||||
export function resolveExtraDocCategory(
|
* (API enum Before/After/Extra/Completion). Aveta is never inferred from
|
||||||
file: MediaFile,
|
* upload order — only an explicit Aveta category counts.
|
||||||
index: number,
|
*/
|
||||||
avetaRequired: boolean,
|
export function resolveExtraDocCategory(file: MediaFile): MediaCategory {
|
||||||
files: MediaFile[],
|
|
||||||
): MediaCategory {
|
|
||||||
if (file.category === "Aveta") {
|
|
||||||
return "Aveta";
|
|
||||||
}
|
|
||||||
const hasExplicitAveta = files.some((item) => item.category === "Aveta");
|
|
||||||
if (avetaRequired && index === 0 && !hasExplicitAveta) {
|
|
||||||
return "Aveta";
|
|
||||||
}
|
|
||||||
return file.category;
|
return file.category;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function shouldDefaultFirstExtraToAveta(
|
export function hasExplicitAvetaFile(files: MediaFile[]): boolean {
|
||||||
avetaRequired: boolean,
|
return files.some((item) => item.category === "Aveta");
|
||||||
existing: MediaFile[],
|
|
||||||
): boolean {
|
|
||||||
return avetaRequired && !existing.some((item) => item.category === "Aveta");
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,16 @@ const photo: MediaFile = {
|
||||||
category: "Report",
|
category: "Report",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const avetaDoc: MediaFile = {
|
||||||
|
id: "m2",
|
||||||
|
name: "aveta-clearance.pdf",
|
||||||
|
fileType: "pdf",
|
||||||
|
url: "blob:2",
|
||||||
|
category: "Aveta",
|
||||||
|
};
|
||||||
|
|
||||||
describe("SlideOverExtrasTab Aveta", () => {
|
describe("SlideOverExtrasTab Aveta", () => {
|
||||||
it("labels the first extra document as Aveta when the WO is flagged", () => {
|
it("does not label the first extra document as Aveta when none is explicitly Aveta", () => {
|
||||||
renderWithProviders(
|
renderWithProviders(
|
||||||
<SlideOverExtrasTab
|
<SlideOverExtrasTab
|
||||||
uploads={[photo]}
|
uploads={[photo]}
|
||||||
|
|
@ -24,7 +32,23 @@ describe("SlideOverExtrasTab Aveta", () => {
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(screen.getAllByText("Aveta").length).toBeGreaterThan(0);
|
|
||||||
expect(screen.getByText("safety-form.pdf")).toBeInTheDocument();
|
expect(screen.getByText("safety-form.pdf")).toBeInTheDocument();
|
||||||
|
expect(screen.getAllByText("Aveta")).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("labels only an explicitly Aveta-categorized extra document", () => {
|
||||||
|
renderWithProviders(
|
||||||
|
<SlideOverExtrasTab
|
||||||
|
uploads={[photo, avetaDoc]}
|
||||||
|
avetaRequired
|
||||||
|
isReadOnly
|
||||||
|
onUpload={vi.fn()}
|
||||||
|
onRemove={vi.fn()}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText("safety-form.pdf")).toBeInTheDocument();
|
||||||
|
expect(screen.getByText("aveta-clearance.pdf")).toBeInTheDocument();
|
||||||
|
expect(screen.getAllByText("Aveta").length).toBeGreaterThanOrEqual(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import type { MediaFile } from "@/domain/work-orders/types/work-order-media";
|
import type { MediaFile } from "@/domain/work-orders/types/work-order-media";
|
||||||
import {
|
import {
|
||||||
|
hasExplicitAvetaFile,
|
||||||
resolveExtraDocCategory,
|
resolveExtraDocCategory,
|
||||||
shouldDefaultFirstExtraToAveta,
|
|
||||||
} from "@/domain/work-orders/utils/extra-docs-aveta";
|
} from "@/domain/work-orders/utils/extra-docs-aveta";
|
||||||
|
|
||||||
function file(category: MediaFile["category"]): MediaFile {
|
function file(category: MediaFile["category"]): MediaFile {
|
||||||
|
|
@ -16,23 +16,23 @@ function file(category: MediaFile["category"]): MediaFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("extra-docs-aveta", () => {
|
describe("extra-docs-aveta", () => {
|
||||||
it("defaults the first extra file to Aveta when required and none is Aveta", () => {
|
it("does not label the first extra file as Aveta when the WO is flagged and none is Aveta", () => {
|
||||||
const files = [file("Photo"), file("Report")];
|
const files = [file("Photo"), file("Report")];
|
||||||
expect(resolveExtraDocCategory(files[0], 0, true, files)).toBe("Aveta");
|
expect(resolveExtraDocCategory(files[0])).toBe("Photo");
|
||||||
expect(resolveExtraDocCategory(files[1], 1, true, files)).toBe("Report");
|
expect(resolveExtraDocCategory(files[1])).toBe("Report");
|
||||||
expect(shouldDefaultFirstExtraToAveta(true, files)).toBe(true);
|
expect(hasExplicitAvetaFile(files)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps an explicit Aveta file and does not relabel others", () => {
|
it("keeps an explicit Aveta file and does not relabel others", () => {
|
||||||
const files = [file("Photo"), file("Aveta")];
|
const files = [file("Photo"), file("Aveta")];
|
||||||
expect(resolveExtraDocCategory(files[0], 0, true, files)).toBe("Photo");
|
expect(resolveExtraDocCategory(files[0])).toBe("Photo");
|
||||||
expect(resolveExtraDocCategory(files[1], 1, true, files)).toBe("Aveta");
|
expect(resolveExtraDocCategory(files[1])).toBe("Aveta");
|
||||||
expect(shouldDefaultFirstExtraToAveta(true, files)).toBe(false);
|
expect(hasExplicitAvetaFile(files)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not label extras as Aveta when the WO is not flagged", () => {
|
it("does not label extras as Aveta when the WO is not flagged", () => {
|
||||||
const files = [file("Photo")];
|
const files = [file("Photo")];
|
||||||
expect(resolveExtraDocCategory(files[0], 0, false, files)).toBe("Photo");
|
expect(resolveExtraDocCategory(files[0])).toBe("Photo");
|
||||||
expect(shouldDefaultFirstExtraToAveta(false, files)).toBe(false);
|
expect(hasExplicitAvetaFile(files)).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue