UNPKG

analytica-frontend-lib

Version:

Repositório público dos componentes utilizados nas plataformas da Analytica Ensino

250 lines (246 loc) 7.51 kB
// src/components/DownloadButton/DownloadButton.tsx import { useCallback, useState } from "react"; import { DownloadSimple } from "phosphor-react"; // src/components/IconButton/IconButton.tsx import { forwardRef } from "react"; // src/utils/utils.ts import { clsx } from "clsx"; import { twMerge } from "tailwind-merge"; function cn(...inputs) { return twMerge(clsx(inputs)); } // src/components/IconButton/IconButton.tsx import { jsx } from "react/jsx-runtime"; var IconButton = forwardRef( ({ icon, size = "md", active = false, className = "", disabled, ...props }, ref) => { const baseClasses = [ "inline-flex", "items-center", "justify-center", "rounded-lg", "font-medium", "bg-transparent", "text-text-950", "cursor-pointer", "hover:bg-primary-600", "hover:text-text", "focus-visible:outline-none", "focus-visible:ring-2", "focus-visible:ring-offset-0", "focus-visible:ring-indicator-info", "disabled:opacity-50", "disabled:cursor-not-allowed", "disabled:pointer-events-none" ]; const sizeClasses = { sm: ["w-6", "h-6", "text-sm"], md: ["w-10", "h-10", "text-base"] }; const activeClasses = active ? ["!bg-primary-50", "!text-primary-950", "hover:!bg-primary-100"] : []; const allClasses = [ ...baseClasses, ...sizeClasses[size], ...activeClasses ].join(" "); const ariaLabel = props["aria-label"] ?? "Bot\xE3o de a\xE7\xE3o"; return /* @__PURE__ */ jsx( "button", { ref, type: "button", className: cn(allClasses, className), disabled, "aria-pressed": active, "aria-label": ariaLabel, ...props, children: /* @__PURE__ */ jsx("span", { className: "flex items-center justify-center", children: icon }) } ); } ); IconButton.displayName = "IconButton"; var IconButton_default = IconButton; // src/components/DownloadButton/DownloadButton.tsx import { jsx as jsx2 } from "react/jsx-runtime"; var getMimeType = (url) => { const extension = getFileExtension(url); const mimeTypes = { pdf: "application/pdf", png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg", mp3: "audio/mpeg", mp4: "video/mp4", vtt: "text/vtt" }; return mimeTypes[extension] || "application/octet-stream"; }; var triggerDownload = async (url, filename) => { try { const response = await fetch(url, { mode: "cors", credentials: "same-origin" }); if (!response.ok) { throw new Error( `Failed to fetch file: ${response.status} ${response.statusText}` ); } const blob = await response.blob(); const mimeType = getMimeType(url); const typedBlob = new Blob([blob], { type: mimeType }); const blobUrl = URL.createObjectURL(typedBlob); const link = document.createElement("a"); link.href = blobUrl; link.download = filename; link.rel = "noopener noreferrer"; document.body.appendChild(link); link.click(); link.remove(); setTimeout(() => { URL.revokeObjectURL(blobUrl); }, 1e3); } catch (error) { console.warn("Fetch download failed, falling back to direct link:", error); const link = document.createElement("a"); link.href = url; link.download = filename; link.rel = "noopener noreferrer"; link.target = "_blank"; document.body.appendChild(link); link.click(); link.remove(); } }; var getFileExtension = (url) => { try { const u = new URL(url, globalThis.location?.origin || "http://localhost"); url = u.pathname; } catch { } const path = url.split(/[?#]/)[0]; const dot = path.lastIndexOf("."); return dot > -1 ? path.slice(dot + 1).toLowerCase() : "file"; }; var generateFilename = (contentType, url, lessonTitle = "aula") => { const sanitizedTitle = lessonTitle.toLowerCase().replaceAll(/[^a-z0-9\s]/g, "").replaceAll(/\s+/g, "-").substring(0, 50); const extension = getFileExtension(url); return `${sanitizedTitle}-${contentType}.${extension}`; }; var DownloadButton = ({ content, className, onDownloadStart, onDownloadComplete, onDownloadError, lessonTitle = "aula", disabled = false }) => { const [isDownloading, setIsDownloading] = useState(false); const isValidUrl = useCallback((url) => { return Boolean( url && url.trim() !== "" && url !== "undefined" && url !== "null" ); }, []); const getAvailableContent = useCallback(() => { const downloads = []; if (isValidUrl(content.urlDoc)) { downloads.push({ type: "documento", url: content.urlDoc, label: "Documento" }); } if (isValidUrl(content.urlInitialFrame)) { downloads.push({ type: "quadro-inicial", url: content.urlInitialFrame, label: "Quadro Inicial" }); } if (isValidUrl(content.urlFinalFrame)) { downloads.push({ type: "quadro-final", url: content.urlFinalFrame, label: "Quadro Final" }); } if (isValidUrl(content.urlPodcast)) { downloads.push({ type: "podcast", url: content.urlPodcast, label: "Podcast" }); } if (isValidUrl(content.urlVideo)) { downloads.push({ type: "video", url: content.urlVideo, label: "V\xEDdeo" }); } return downloads; }, [content, isValidUrl]); const handleDownload = useCallback(async () => { if (disabled || isDownloading) return; const availableContent = getAvailableContent(); if (availableContent.length === 0) { return; } setIsDownloading(true); try { for (let i = 0; i < availableContent.length; i++) { const item = availableContent[i]; try { onDownloadStart?.(item.type); const filename = generateFilename(item.type, item.url, lessonTitle); await triggerDownload(item.url, filename); onDownloadComplete?.(item.type); if (i < availableContent.length - 1) { await new Promise((resolve) => setTimeout(resolve, 200)); } } catch (error) { onDownloadError?.( item.type, error instanceof Error ? error : new Error(`Falha ao baixar ${item.label}`) ); } } } finally { setIsDownloading(false); } }, [ disabled, isDownloading, getAvailableContent, lessonTitle, onDownloadStart, onDownloadComplete, onDownloadError ]); const hasContent = getAvailableContent().length > 0; if (!hasContent) { return null; } return /* @__PURE__ */ jsx2("div", { className: cn("flex items-center", className), children: /* @__PURE__ */ jsx2( IconButton_default, { icon: /* @__PURE__ */ jsx2(DownloadSimple, { size: 24 }), onClick: handleDownload, disabled: disabled || isDownloading, "aria-label": (() => { if (isDownloading) { return "Baixando conte\xFAdo..."; } const contentCount = getAvailableContent().length; const suffix = contentCount > 1 ? "s" : ""; return `Baixar conte\xFAdo da aula (${contentCount} arquivo${suffix})`; })(), className: cn( "!bg-transparent hover:!bg-black/10 transition-colors", isDownloading && "opacity-60 cursor-not-allowed" ) } ) }); }; var DownloadButton_default = DownloadButton; export { DownloadButton_default as default }; //# sourceMappingURL=index.mjs.map