mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-03 01:03:21 +00:00
65 lines
2.3 KiB
TypeScript
65 lines
2.3 KiB
TypeScript
|
|
import {
|
||
|
|
MAX_PHOTOS_PER_WORK_ORDER,
|
||
|
|
MAX_VIDEOS_PER_WORK_ORDER,
|
||
|
|
MAX_VIDEO_DURATION_SECONDS,
|
||
|
|
resolveWorkOrderUploadKind,
|
||
|
|
workOrderFileSizeRejection,
|
||
|
|
type WorkOrderMediaKindCounts,
|
||
|
|
} from "@/domain/work-orders/utils/work-order-media-limits";
|
||
|
|
import { probeVideoDurationSeconds } from "@/lib/probe-video-duration";
|
||
|
|
|
||
|
|
export type WorkOrderUploadScreen = {
|
||
|
|
/** Photos and videos already on the work order, across every surface. */
|
||
|
|
existing: WorkOrderMediaKindCounts;
|
||
|
|
isTypeAllowed: (file: File) => boolean;
|
||
|
|
unsupportedTypeMessage: string;
|
||
|
|
};
|
||
|
|
|
||
|
|
export type WorkOrderUploadScreenResult = { accepted: File[]; rejections: string[] };
|
||
|
|
|
||
|
|
/**
|
||
|
|
* SH-116 browser pre-check shared by every dispatcher upload surface: type, size,
|
||
|
|
* per-work-order photo/video count (including earlier files in the same selection)
|
||
|
|
* and video duration. The server enforces the same contract; a video whose duration
|
||
|
|
* the browser cannot read is never blocked here.
|
||
|
|
*/
|
||
|
|
export async function screenWorkOrderUploads(
|
||
|
|
files: readonly File[],
|
||
|
|
{ existing, isTypeAllowed, unsupportedTypeMessage }: WorkOrderUploadScreen,
|
||
|
|
): Promise<WorkOrderUploadScreenResult> {
|
||
|
|
const counts = { ...existing };
|
||
|
|
const accepted: File[] = [];
|
||
|
|
const rejections: string[] = [];
|
||
|
|
for (const file of files) {
|
||
|
|
if (!isTypeAllowed(file)) {
|
||
|
|
rejections.push(unsupportedTypeMessage);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const sizeRejection = workOrderFileSizeRejection(file);
|
||
|
|
if (sizeRejection) {
|
||
|
|
rejections.push(sizeRejection);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const kind = resolveWorkOrderUploadKind(file);
|
||
|
|
if (kind === "photo" && counts.photos >= MAX_PHOTOS_PER_WORK_ORDER) {
|
||
|
|
rejections.push(`A work order can have at most ${MAX_PHOTOS_PER_WORK_ORDER} photos.`);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (kind === "video" && counts.videos >= MAX_VIDEOS_PER_WORK_ORDER) {
|
||
|
|
rejections.push(`A work order can have at most ${MAX_VIDEOS_PER_WORK_ORDER} videos.`);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (kind === "video") {
|
||
|
|
const duration = await probeVideoDurationSeconds(file);
|
||
|
|
if (duration != null && duration > MAX_VIDEO_DURATION_SECONDS) {
|
||
|
|
rejections.push(`Videos must be ${MAX_VIDEO_DURATION_SECONDS} seconds or shorter.`);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (kind === "photo") counts.photos += 1;
|
||
|
|
if (kind === "video") counts.videos += 1;
|
||
|
|
accepted.push(file);
|
||
|
|
}
|
||
|
|
return { accepted, rejections };
|
||
|
|
}
|