import type { EnvironmentId } from "@t3tools/contracts"; export type ReadyAttachmentUpload = { readonly status: "ready"; readonly environmentId: EnvironmentId; readonly attachmentId: string; }; export type AttachmentUploadState = | { readonly status: "uploading"; readonly environmentId: EnvironmentId; readonly progress: number; readonly previous?: ReadyAttachmentUpload; } | ReadyAttachmentUpload | { readonly status: "failed"; readonly environmentId: EnvironmentId; readonly reason: string; readonly attachmentId?: string; readonly previous?: ReadyAttachmentUpload; }; export function attachmentUploadBlockReason(input: { readonly imageIds: ReadonlyArray; readonly uploadsByImageId: Readonly>; readonly environmentId: EnvironmentId; }): string | null { let pending = 0; let failed = 0; for (const imageId of input.imageIds) { const upload = input.uploadsByImageId[imageId]; if (upload?.status === "failed" && upload.environmentId === input.environmentId) { failed += 1; } else if (upload?.status !== "ready" || upload.environmentId !== input.environmentId) { pending += 1; } } if (failed > 0) { return failed === 1 ? "Retry or remove the failed image" : "Retry or remove the failed images"; } if (pending > 0) { return pending === 1 ? "Image still uploading" : "Images still uploading"; } return null; } export function formatAttachmentUploadProgress(progress: number): string { const bounded = Math.max(0, Math.min(1, Number.isFinite(progress) ? progress : 0)); return `${Math.floor(bounded * 100)}%`; }