shoc-frontend-new/src/domain/work-orders/use-cases/submit-work-order-uplift.ts
Arthur Bassi 64686a59eb feat(work-orders): accept more than one uplift evidence file
Stage every selected file, wait for each scan, and download by document id.
Refresh the work-order detail snapshot for the current tab strip.
2026-09-28 16:25:45 -03:00

77 lines
2.4 KiB
TypeScript

import type { UpliftEvidenceSnapshot } from "@/domain/work-orders/api/work-order-uplifts-api";
import type {
CreateWorkOrderUpliftInput,
WorkOrderUplift,
} from "@/domain/work-orders/types/work-order-uplift";
const POLL_INTERVAL_MS = 1000;
const MAX_POLL_ATTEMPTS = 30;
type CreateUpliftBody = {
amount: number;
notes: string;
evidenceDocumentId?: number;
evidenceDocumentIds?: number[];
};
export type SubmitWorkOrderUpliftDeps = {
uploadEvidence: (workOrderId: string | number, file: File) => Promise<UpliftEvidenceSnapshot>;
getEvidenceStatus: (
workOrderId: string | number,
documentId: number,
) => Promise<UpliftEvidenceSnapshot>;
create: (workOrderId: string | number, input: CreateUpliftBody) => Promise<WorkOrderUplift>;
sleep?: (ms: number) => Promise<void>;
};
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
function scanFailureMessage(scanStatus: "Rejected" | "Timeout"): string {
if (scanStatus === "Rejected") {
return "The evidence file was rejected by the security scan.";
}
return "The evidence file is still being scanned. Try again in a moment.";
}
async function waitForPassedScan(
workOrderId: string | number,
file: File,
deps: SubmitWorkOrderUpliftDeps,
): Promise<number> {
const pause = deps.sleep ?? sleep;
const uploaded = await deps.uploadEvidence(workOrderId, file);
for (let attempt = 0; attempt < MAX_POLL_ATTEMPTS; attempt += 1) {
const document =
attempt === 0 ? uploaded : await deps.getEvidenceStatus(workOrderId, uploaded.id);
if (document.scanStatus === "Passed") {
return uploaded.id;
}
if (document.scanStatus === "Rejected") {
throw new Error(scanFailureMessage("Rejected"));
}
await pause(POLL_INTERVAL_MS);
}
throw new Error(scanFailureMessage("Timeout"));
}
export async function submitWorkOrderUplift(
workOrderId: string | number,
input: CreateWorkOrderUpliftInput,
deps: SubmitWorkOrderUpliftDeps,
): Promise<WorkOrderUplift> {
const evidenceDocumentIds: number[] = [];
for (const file of input.files ?? []) {
evidenceDocumentIds.push(await waitForPassedScan(workOrderId, file, deps));
}
const [evidenceDocumentId] = evidenceDocumentIds;
return deps.create(workOrderId, {
amount: input.amount,
notes: input.notes,
evidenceDocumentId,
evidenceDocumentIds: evidenceDocumentIds.length > 0 ? evidenceDocumentIds : undefined,
});
}