export interface DownloadFileOptions { downloadUrl: string; fileName: string; } const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( navigator.userAgent, ); export async function downloadBlobFile({ downloadUrl, fileName, }: DownloadFileOptions): Promise { // Use window.open for desktop, blob download for mobile if (!isMobile) { window.open(downloadUrl, "_blank"); return; } const response = await fetch(downloadUrl); const blob = await response.blob(); const contentType: string | null = response.headers.get("Content-Type"); const extensionMap: Record = { "application/pdf": "pdf", "image/jpeg": "jpg", "image/png": "png", "image/gif": "gif", "application/zip": "zip", "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx", }; let extension = contentType ? extensionMap[contentType] : undefined; if (!extension) { const urlWithoutQuery = downloadUrl.split("?")[0]; extension = urlWithoutQuery.includes(".") ? urlWithoutQuery.split(".").pop() : "pdf"; } const blobForDownload = new Blob([blob], { type: "application/octet-stream", }); const url = URL.createObjectURL(blobForDownload); const link = document.createElement("a"); link.href = url; link.download = `${fileName}.${extension}`; document.body.appendChild(link); link.click(); setTimeout(() => { document.body.removeChild(link); URL.revokeObjectURL(url); }, 100); }