mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-07 16:19:01 +00:00
Merge pull request #193 from Sea-Haven-Industries/fix/ab/sh-339-wizard-complete-image
Some checks failed
Some checks failed
SH-339: Allow completing Reactive/Emergency WOs from the side panel after photo upload
This commit is contained in:
commit
d6510b262e
2 changed files with 74 additions and 1 deletions
|
|
@ -269,6 +269,20 @@ export function boardMediaItemsToMediaFiles(items: WorkOrderBoardMediaItem[]): M
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `GET workorders/{id}/detail` info serializes the board row's `MediaCount` as 0 — the detail
|
||||||
|
* DTO inherits the field but the service never sets it — so trusting it verbatim would leave the
|
||||||
|
* slide-over closability gate reporting "At least 1 photo" even after an upload. Take the larger
|
||||||
|
* of the reported count and the stored (non-legacy) attachments: a positive API count still wins,
|
||||||
|
* but a spurious (or omitted) 0 can no longer mask media that are actually present.
|
||||||
|
*/
|
||||||
|
function resolveDetailMediaCount(infoRaw: unknown, media: WorkOrderBoardMediaItem[]): number {
|
||||||
|
const record = asRecord(infoRaw);
|
||||||
|
const explicit = record.mediaCount ?? record.MediaCount;
|
||||||
|
const nonLegacyCount = media.filter((item) => !item.isLegacy).length;
|
||||||
|
return Math.max(typeof explicit === "number" ? explicit : 0, nonLegacyCount);
|
||||||
|
}
|
||||||
|
|
||||||
export function mapWorkOrderBoardDetail(raw: unknown): WorkOrderBoardDetail {
|
export function mapWorkOrderBoardDetail(raw: unknown): WorkOrderBoardDetail {
|
||||||
const root = asRecord(raw);
|
const root = asRecord(raw);
|
||||||
const infoRaw = root.info ?? root.Info ?? root;
|
const infoRaw = root.info ?? root.Info ?? root;
|
||||||
|
|
@ -283,8 +297,10 @@ export function mapWorkOrderBoardDetail(raw: unknown): WorkOrderBoardDetail {
|
||||||
: [];
|
: [];
|
||||||
const media = Array.isArray(mediaRaw) ? mediaRaw.map(mapBoardDetailMediaItem) : [];
|
const media = Array.isArray(mediaRaw) ? mediaRaw.map(mapBoardDetailMediaItem) : [];
|
||||||
|
|
||||||
|
const info = mapWorkOrderTableRow(infoRaw);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
info: mapWorkOrderTableRow(infoRaw),
|
info: { ...info, mediaCount: resolveDetailMediaCount(infoRaw, media) },
|
||||||
completion: mapCompletion(completionRaw ?? {}),
|
completion: mapCompletion(completionRaw ?? {}),
|
||||||
comments,
|
comments,
|
||||||
audit,
|
audit,
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,10 @@ import {
|
||||||
mapBoardDetailMediaItem,
|
mapBoardDetailMediaItem,
|
||||||
mapWorkOrderBoardDetail,
|
mapWorkOrderBoardDetail,
|
||||||
} from "@/domain/work-orders/mappers/work-order-board-detail-mapper";
|
} from "@/domain/work-orders/mappers/work-order-board-detail-mapper";
|
||||||
|
import {
|
||||||
|
getClosabilityGaps,
|
||||||
|
tableRowToClosabilityInput,
|
||||||
|
} from "@/domain/work-orders/utils/wo-closability";
|
||||||
|
|
||||||
const SAMPLE_DETAIL = {
|
const SAMPLE_DETAIL = {
|
||||||
info: {
|
info: {
|
||||||
|
|
@ -279,3 +283,56 @@ describe("mapWorkOrderBoardDetail", () => {
|
||||||
expect(completionForm.get("file")).toBeInstanceOf(File);
|
expect(completionForm.get("file")).toBeInstanceOf(File);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("mapWorkOrderBoardDetail media count (SH-339)", () => {
|
||||||
|
const reactiveInfo = { ...SAMPLE_DETAIL.info, workOrderType: 6 };
|
||||||
|
|
||||||
|
it("derives mediaCount from stored media when detail info omits it", () => {
|
||||||
|
const detail = mapWorkOrderBoardDetail({ ...SAMPLE_DETAIL, info: reactiveInfo });
|
||||||
|
|
||||||
|
expect(detail.info.type).toBe("Reactive");
|
||||||
|
expect(detail.info.mediaCount).toBe(2);
|
||||||
|
expect(getClosabilityGaps(tableRowToClosabilityInput(detail.info))).not.toContain(
|
||||||
|
"At least 1 photo",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("prefers stored media when detail info reports an explicit zero", () => {
|
||||||
|
const detail = mapWorkOrderBoardDetail({
|
||||||
|
...SAMPLE_DETAIL,
|
||||||
|
info: { ...reactiveInfo, mediaCount: 0 },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(detail.info.mediaCount).toBe(2);
|
||||||
|
expect(getClosabilityGaps(tableRowToClosabilityInput(detail.info))).not.toContain(
|
||||||
|
"At least 1 photo",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not count legacy URL-column media, matching the board row count", () => {
|
||||||
|
const detail = mapWorkOrderBoardDetail({
|
||||||
|
...SAMPLE_DETAIL,
|
||||||
|
info: reactiveInfo,
|
||||||
|
media: [
|
||||||
|
{
|
||||||
|
id: -1,
|
||||||
|
category: 1,
|
||||||
|
url: "https://cdn.example.com/legacy.jpg",
|
||||||
|
fileName: "legacy.jpg",
|
||||||
|
isLegacy: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(detail.info.mediaCount).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps an explicit info mediaCount", () => {
|
||||||
|
const detail = mapWorkOrderBoardDetail({
|
||||||
|
...SAMPLE_DETAIL,
|
||||||
|
info: { ...reactiveInfo, mediaCount: 5 },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(detail.info.mediaCount).toBe(5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue