{"version":3,"sources":["../src/components/DownloadButton/DownloadButton.tsx"],"sourcesContent":["import { useCallback, useState } from 'react';\nimport { DownloadSimpleIcon } from '@phosphor-icons/react/dist/csr/DownloadSimple';\nimport IconButton from '../IconButton/IconButton';\nimport ProgressModal from '../ProgressModal/ProgressModal';\nimport { cn } from '../../utils/utils';\n\n/**\n * Download content interface for lesson materials\n */\nexport interface DownloadContent {\n  /** Initial frame image URL */\n  urlInitialFrame?: string;\n  /** Final frame image URL */\n  urlFinalFrame?: string;\n  /** Podcast audio URL */\n  urlPodcast?: string;\n  /** Video URL */\n  urlVideo?: string;\n}\n\n/**\n * Props for DownloadButton component\n */\nexport interface DownloadButtonProps {\n  /** Content URLs to download */\n  content: DownloadContent;\n  /** Additional CSS classes */\n  className?: string;\n  /** Callback fired when download starts */\n  onDownloadStart?: (contentType: string) => void;\n  /** Callback fired when download completes */\n  onDownloadComplete?: (contentType: string) => void;\n  /** Callback fired when download fails */\n  onDownloadError?: (contentType: string, error: Error) => void;\n  /** Lesson title for download file naming */\n  lessonTitle?: string;\n  /** Whether the button is disabled */\n  disabled?: boolean;\n}\n\n/** A single downloadable asset resolved from the lesson content */\ninterface DownloadItem {\n  type: string;\n  url: string;\n  label: string;\n}\n\n/**\n * Minimal shape of the File System Access API we rely on.\n *\n * Typed locally because `showDirectoryPicker` is not in the DOM lib yet, and\n * because only Chromium ships it — every use goes through `supportsDirectoryPicker`.\n */\ninterface FileSystemWritable {\n  write: (chunk: Uint8Array) => Promise<void>;\n  close: () => Promise<void>;\n  abort?: () => Promise<void>;\n}\n\ninterface FileSystemFileHandleLike {\n  createWritable: () => Promise<FileSystemWritable>;\n}\n\ninterface FileSystemDirectoryHandleLike {\n  getFileHandle: (\n    name: string,\n    options?: { create?: boolean }\n  ) => Promise<FileSystemFileHandleLike>;\n}\n\ntype DirectoryPicker = (options?: {\n  mode?: string;\n  id?: string;\n}) => Promise<FileSystemDirectoryHandleLike>;\n\n/**\n * Whether the browser can stream downloads straight to a folder on disk.\n *\n * Chromium-based browsers ship the File System Access API; Safari and Firefox\n * do not, and fall back to plain per-file downloads.\n *\n * @returns Whether `showDirectoryPicker` is available\n */\nconst supportsDirectoryPicker = (): boolean =>\n  typeof (globalThis as { showDirectoryPicker?: DirectoryPicker })\n    .showDirectoryPicker === 'function';\n\n/**\n * Get file extension from URL\n * @param url - URL to extract extension from\n * @returns File extension or default\n */\nconst getFileExtension = (url: string): string => {\n  try {\n    const u = new URL(url, globalThis.location?.origin || 'http://localhost');\n    url = u.pathname;\n  } catch {\n    // keep original url (likely relative)\n  }\n  const path = url.split(/[?#]/)[0];\n  const dot = path.lastIndexOf('.');\n  return dot > -1 ? path.slice(dot + 1).toLowerCase() : 'file';\n};\n\n/**\n * Slugify a lesson title for safe use in filenames\n * @param lessonTitle - Title of the lesson\n * @returns Sanitized slug\n */\nconst slugifyTitle = (lessonTitle: string): string =>\n  lessonTitle\n    .toLowerCase()\n    .replaceAll(/[^a-z0-9\\s]/g, '')\n    .replaceAll(/\\s+/g, '-')\n    .substring(0, 50);\n\n/**\n * Generate the filename an asset is saved as\n * @param contentType - Type of content being downloaded\n * @param url - URL to get extension from\n * @param lessonTitle - Title of the lesson\n * @returns Generated filename\n */\nconst generateFilename = (\n  contentType: string,\n  url: string,\n  lessonTitle: string = 'aula'\n): string =>\n  `${slugifyTitle(lessonTitle)}-${contentType}.${getFileExtension(url)}`;\n\n/**\n * Read the byte size of a remote file without downloading it.\n *\n * Weights per-file progress against the real payload — a lesson video can be\n * hundreds of MB while the board frames are ~1MB, so counting files would make\n * the bar jump. Returns 0 when the server omits `content-length` or the request\n * fails, and callers then fall back to counting files.\n *\n * @param url - URL to probe\n * @returns Size in bytes, or 0 when unknown\n */\nconst getRemoteFileSize = async (url: string): Promise<number> => {\n  try {\n    const response = await fetch(url, { method: 'HEAD', mode: 'cors' });\n    if (!response.ok) return 0;\n    return Number(response.headers.get('content-length')) || 0;\n  } catch {\n    return 0;\n  }\n};\n\n/**\n * Stream a remote file straight into a file on disk.\n *\n * Nothing is buffered in memory: each chunk is written to the file handle as it\n * arrives. This is what makes a ~900MB lesson video downloadable — holding it\n * in a Blob (and zipping it) exhausts the tab's memory and silently drops the\n * assets queued behind it.\n *\n * @param url - URL to download\n * @param dirHandle - Directory the user granted write access to\n * @param filename - Name to save the file as\n * @param onBytes - Called with the byte length of each chunk written\n */\nconst streamToDisk = async (\n  url: string,\n  dirHandle: FileSystemDirectoryHandleLike,\n  filename: string,\n  onBytes: (chunkSize: number) => void\n): Promise<void> => {\n  const response = await fetch(url, { mode: 'cors' });\n\n  if (!response.ok) {\n    throw new Error(\n      `Failed to fetch file: ${response.status} ${response.statusText}`\n    );\n  }\n  if (!response.body) {\n    throw new Error('Response has no readable body');\n  }\n\n  const fileHandle = await dirHandle.getFileHandle(filename, { create: true });\n  const writable = await fileHandle.createWritable();\n\n  try {\n    const reader = response.body.getReader();\n\n    for (;;) {\n      const { done, value } = await reader.read();\n      if (done) break;\n      await writable.write(value);\n      onBytes(value.length);\n    }\n\n    await writable.close();\n  } catch (error) {\n    await writable.abort?.();\n    throw error;\n  }\n};\n\n/**\n * Save a file through a plain anchor click, letting the browser download it.\n *\n * Fallback for browsers without the File System Access API (Safari, Firefox).\n * Note the `download` attribute is ignored cross-origin, and the CDN does not\n * send `Content-Disposition: attachment`, so these browsers may open the asset\n * in a tab rather than save it. Fixing that properly means setting that header\n * on the CDN — it cannot be forced from the client.\n *\n * The browser streams the response to its own downloads folder, so memory is\n * not a concern — but it\n * cannot report progress, and firing several in a row is unreliable, which is\n * why the caller spaces them out.\n *\n * @param url - URL to download\n * @param filename - Suggested filename\n */\nconst triggerBrowserDownload = (url: string, filename: string): void => {\n  const link = document.createElement('a');\n  link.href = url;\n  link.download = filename;\n  link.rel = 'noopener noreferrer';\n\n  document.body.appendChild(link);\n  link.click();\n  link.remove();\n};\n\n/**\n * DownloadButton component for downloading lesson content\n *\n * Downloads every asset of a lesson (video, podcast and board frames), matching\n * the mobile app's \"baixar aula completa\". Where the browser supports it, the\n * user picks a folder and each file is streamed straight to disk with real\n * progress; elsewhere the browser downloads them one by one.\n *\n * @param props - DownloadButton component props\n * @returns Download button element\n */\nconst DownloadButton = ({\n  content,\n  className,\n  onDownloadStart,\n  onDownloadComplete,\n  onDownloadError,\n  lessonTitle = 'aula',\n  disabled = false,\n}: DownloadButtonProps) => {\n  const [isDownloading, setIsDownloading] = useState(false);\n  const [progress, setProgress] = useState(0);\n\n  /**\n   * Check if URL is valid and not empty\n   * @param url - URL to validate\n   * @returns Whether URL is valid\n   */\n  const isValidUrl = useCallback((url?: string): boolean => {\n    return Boolean(\n      url && url.trim() !== '' && url !== 'undefined' && url !== 'null'\n    );\n  }, []);\n\n  /**\n   * Get available download content\n   * @returns Array of available download items\n   */\n  const getAvailableContent = useCallback((): DownloadItem[] => {\n    const downloads: DownloadItem[] = [];\n\n    if (isValidUrl(content.urlVideo)) {\n      downloads.push({ type: 'video', url: content.urlVideo!, label: 'Vídeo' });\n    }\n\n    if (isValidUrl(content.urlPodcast)) {\n      downloads.push({\n        type: 'podcast',\n        url: content.urlPodcast!,\n        label: 'Podcast',\n      });\n    }\n\n    if (isValidUrl(content.urlInitialFrame)) {\n      downloads.push({\n        type: 'quadro-inicial',\n        url: content.urlInitialFrame!,\n        label: 'Quadro Inicial',\n      });\n    }\n\n    if (isValidUrl(content.urlFinalFrame)) {\n      downloads.push({\n        type: 'quadro-final',\n        url: content.urlFinalFrame!,\n        label: 'Quadro Final',\n      });\n    }\n\n    return downloads;\n  }, [content, isValidUrl]);\n\n  /**\n   * Download every asset by streaming it into the folder the user picked.\n   *\n   * @param items - Assets to download\n   * @param dirHandle - Directory the user granted write access to\n   */\n  const downloadToFolder = useCallback(\n    async (items: DownloadItem[], dirHandle: FileSystemDirectoryHandleLike) => {\n      const sizes = await Promise.all(\n        items.map((item) => getRemoteFileSize(item.url))\n      );\n      const totalBytes = sizes.reduce((sum, size) => sum + size, 0);\n      // No content-length anywhere: weight each file equally instead of by bytes.\n      const weighByFile = totalBytes === 0;\n\n      let downloadedBytes = 0;\n      let succeeded = 0;\n\n      for (const [index, item] of items.entries()) {\n        try {\n          onDownloadStart?.(item.type);\n\n          await streamToDisk(\n            item.url,\n            dirHandle,\n            generateFilename(item.type, item.url, lessonTitle),\n            (chunkSize) => {\n              downloadedBytes += chunkSize;\n              if (!weighByFile) {\n                setProgress(\n                  Math.min(99, Math.round((downloadedBytes / totalBytes) * 100))\n                );\n              }\n            }\n          );\n\n          succeeded++;\n          onDownloadComplete?.(item.type);\n        } catch (error) {\n          onDownloadError?.(\n            item.type,\n            error instanceof Error\n              ? error\n              : new Error(`Falha ao baixar ${item.label}`)\n          );\n        } finally {\n          if (weighByFile) {\n            setProgress(\n              Math.min(99, Math.round(((index + 1) / items.length) * 100))\n            );\n          }\n        }\n      }\n\n      if (succeeded === 0) {\n        throw new Error('Nenhum conteúdo da aula pôde ser baixado');\n      }\n\n      setProgress(100);\n    },\n    [lessonTitle, onDownloadStart, onDownloadComplete, onDownloadError]\n  );\n\n  /**\n   * Hand each asset to the browser's own downloader, one at a time.\n   *\n   * Used where the File System Access API is missing. Downloads are spaced out\n   * because browsers throttle several programmatic downloads fired at once.\n   *\n   * @param items - Assets to download\n   */\n  const downloadViaBrowser = useCallback(\n    async (items: DownloadItem[]) => {\n      for (const [index, item] of items.entries()) {\n        onDownloadStart?.(item.type);\n\n        triggerBrowserDownload(\n          item.url,\n          generateFilename(item.type, item.url, lessonTitle)\n        );\n\n        onDownloadComplete?.(item.type);\n        setProgress(Math.round(((index + 1) / items.length) * 100));\n\n        if (index < items.length - 1) {\n          await new Promise((resolve) => setTimeout(resolve, 800));\n        }\n      }\n    },\n    [lessonTitle, onDownloadStart, onDownloadComplete]\n  );\n\n  /**\n   * Download every asset of the lesson.\n   *\n   * Prefers streaming to a user-picked folder, which is the only approach that\n   * survives a large lesson video. Falls back to the browser's downloader when\n   * the File System Access API is unavailable.\n   */\n  const handleDownload = useCallback(async () => {\n    if (disabled || isDownloading) return;\n\n    const availableContent = getAvailableContent();\n    if (availableContent.length === 0) return;\n\n    let dirHandle: FileSystemDirectoryHandleLike | null = null;\n\n    if (supportsDirectoryPicker()) {\n      try {\n        const picker = (globalThis as { showDirectoryPicker?: DirectoryPicker })\n          .showDirectoryPicker!;\n        dirHandle = await picker({ mode: 'readwrite', id: 'aulas' });\n      } catch {\n        // The user dismissed the folder picker: abort quietly, nothing to report.\n        return;\n      }\n    }\n\n    setIsDownloading(true);\n    setProgress(0);\n\n    try {\n      if (dirHandle) {\n        await downloadToFolder(availableContent, dirHandle);\n      } else {\n        await downloadViaBrowser(availableContent);\n      }\n    } catch (error) {\n      onDownloadError?.(\n        'aula',\n        error instanceof Error\n          ? error\n          : new Error('Falha ao baixar o conteúdo da aula')\n      );\n    } finally {\n      setIsDownloading(false);\n      setProgress(0);\n    }\n  }, [\n    disabled,\n    isDownloading,\n    getAvailableContent,\n    downloadToFolder,\n    downloadViaBrowser,\n    onDownloadError,\n  ]);\n\n  // Don't render if no content is available\n  const availableCount = getAvailableContent().length;\n\n  if (availableCount === 0) {\n    return null;\n  }\n\n  const suffix = availableCount > 1 ? 's' : '';\n\n  return (\n    <div className={cn('flex items-center', className)}>\n      <IconButton\n        icon={<DownloadSimpleIcon size={24} />}\n        onClick={handleDownload}\n        disabled={disabled || isDownloading}\n        aria-label={\n          isDownloading\n            ? 'Baixando conteúdo...'\n            : `Baixar conteúdo da aula (${availableCount} arquivo${suffix})`\n        }\n        className={cn(\n          '!bg-transparent hover:!bg-black/10 transition-colors',\n          isDownloading && 'opacity-60 cursor-not-allowed'\n        )}\n      />\n\n      <ProgressModal\n        isOpen={isDownloading}\n        onClose={() => {}}\n        message=\"Baixando conteúdo da aula...\"\n        progress={progress}\n      />\n    </div>\n  );\n};\n\nexport default DownloadButton;\n"],"mappings":"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","names":[]}