diff --git a/src/app/(protected)/workorders/_components/detail/tabs/slide-over-extras-tab.tsx b/src/app/(protected)/workorders/_components/detail/tabs/slide-over-extras-tab.tsx index ec6963e0..a5d2e118 100644 --- a/src/app/(protected)/workorders/_components/detail/tabs/slide-over-extras-tab.tsx +++ b/src/app/(protected)/workorders/_components/detail/tabs/slide-over-extras-tab.tsx @@ -1,4 +1,4 @@ -import { useRef } from "react"; +import { useRef, useState } from "react"; import { File as FileIcon, FileText, @@ -18,7 +18,10 @@ import { hasExplicitAvetaFile, resolveExtraDocCategory, } from "@/domain/work-orders/utils/extra-docs-aveta"; -import { screenWorkOrderUploads } from "@/domain/work-orders/utils/screen-work-order-uploads"; +import { + screenWorkOrderUploads, + type WorkOrderUploadScreenResult, +} from "@/domain/work-orders/utils/screen-work-order-uploads"; import { canDeleteWorkOrderMedia, countWorkOrderMediaKinds, @@ -189,16 +192,30 @@ export function SlideOverExtrasTab({ }: SlideOverExtrasTabProps) { const inputRef = useRef(null); const avetaAttached = hasExplicitAvetaFile(uploads); + // One selection at a time: a second pick during the async screen would read the + // same photo/video counts and could pass the per-work-order limit. + const screeningRef = useRef(false); + const [screening, setScreening] = useState(false); + const busy = pending || screening; const addFiles = async (files: FileList | null) => { - if (isReadOnly || pending || !files || files.length === 0) return; + if (isReadOnly || pending || screeningRef.current || !files || files.length === 0) return; // Snapshot synchronously: the input is reset right after this handler returns. const selected = Array.from(files); - const { accepted, rejections } = await screenWorkOrderUploads(selected, { - existing: mediaCounts ?? countWorkOrderMediaKinds(uploads), - isTypeAllowed: isWorkOrderExtraDocTypeAllowed, - unsupportedTypeMessage: UNSUPPORTED_TYPE_MESSAGE, - }); + screeningRef.current = true; + setScreening(true); + let screened: WorkOrderUploadScreenResult; + try { + screened = await screenWorkOrderUploads(selected, { + existing: mediaCounts ?? countWorkOrderMediaKinds(uploads), + isTypeAllowed: isWorkOrderExtraDocTypeAllowed, + unsupportedTypeMessage: UNSUPPORTED_TYPE_MESSAGE, + }); + } finally { + screeningRef.current = false; + setScreening(false); + } + const { accepted, rejections } = screened; for (const message of rejections) toast.error(message); if (accepted.length > 0) { onUpload(accepted); @@ -231,7 +248,7 @@ export function SlideOverExtrasTab({ <>