diff --git a/components/FileListing.tsx b/components/FileListing.tsx index b424788..9de1167 100644 --- a/components/FileListing.tsx +++ b/components/FileListing.tsx @@ -14,10 +14,13 @@ import { getExtension, getFileIcon, hasKey } from '../utils/getFileIcon' import { extensions, preview } from '../utils/getPreviewType' import { useProtectedSWRInfinite } from '../utils/fetchWithSWR' import { getBaseUrl } from '../utils/getBaseUrl' -import { downloadMultipleFiles, downloadTreelikeMultipleFiles, traverseFolder } from '../utils/downloadMultipleFiles' +import { + DownloadingToast, + downloadMultipleFiles, + downloadTreelikeMultipleFiles, + traverseFolder, +} from './MultiFileDownloader' -import { VideoPreview } from './previews/VideoPreview' -import { AudioPreview } from './previews/AudioPreview' import Loading, { LoadingIcon } from './Loading' import FourOhFour from './FourOhFour' import Auth from './Auth' @@ -25,6 +28,8 @@ import TextPreview from './previews/TextPreview' import MarkdownPreview from './previews/MarkdownPreview' import CodePreview from './previews/CodePreview' import OfficePreview from './previews/OfficePreview' +import AudioPreview from './previews/AudioPreview' +import VideoPreview from './previews/VideoPreview' import DownloadBtn from './DownloadBtn' // Disabling SSR for some previews (image gallery view, and PDF view) @@ -285,17 +290,16 @@ const FileListing: FunctionComponent<{ query?: ParsedUrlQuery }> = ({ query }) = el.remove() } else if (files.length > 1) { setTotalGenerating(true) - const toastId = toast.loading('Downloading selected files. Refresh to cancel, this may take some time...') - downloadMultipleFiles({ toastId, files, folder }) + + const toastId = toast.loading(DownloadingToast(router)) + downloadMultipleFiles({ toastId, router, files, folder }) .then(() => { setTotalGenerating(false) - toast.dismiss(toastId) - toast.success('Finished downloading selected files.') + toast.success('Finished downloading selected files.', { id: toastId }) }) .catch(() => { setTotalGenerating(false) - toast.dismiss(toastId) - toast.error('Failed to download selected files.') + toast.error('Failed to download selected files.', { id: toastId }) }) } } @@ -314,18 +318,16 @@ const FileListing: FunctionComponent<{ query?: ParsedUrlQuery }> = ({ query }) = })() setFolderGenerating({ ...folderGenerating, [id]: true }) - const toastId = toast.loading('Downloading folder. Refresh to cancel, this may take some time...') + const toastId = toast.loading(DownloadingToast(router)) - downloadTreelikeMultipleFiles({ toastId, files, basePath: path, folder: name }) + downloadTreelikeMultipleFiles({ toastId, router, files, basePath: path, folder: name }) .then(() => { setFolderGenerating({ ...folderGenerating, [id]: false }) - toast.dismiss(toastId) - toast.success('Finished downloading folder.') + toast.success('Finished downloading folder.', { id: toastId }) }) .catch(() => { setFolderGenerating({ ...folderGenerating, [id]: false }) - toast.dismiss(toastId) - toast.error('Failed to download folder.') + toast.error('Failed to download folder.', { id: toastId }) }) } diff --git a/utils/downloadMultipleFiles.ts b/components/MultiFileDownloader.tsx similarity index 77% rename from utils/downloadMultipleFiles.ts rename to components/MultiFileDownloader.tsx index 4113e14..1eb0bef 100644 --- a/utils/downloadMultipleFiles.ts +++ b/components/MultiFileDownloader.tsx @@ -1,8 +1,37 @@ +import { NextRouter } from 'next/router' import toast from 'react-hot-toast' import JSZip from 'jszip' -import { fetcher } from './fetchWithSWR' -import { getStoredToken } from './protectedRouteHandler' +import { fetcher } from '../utils/fetchWithSWR' +import { getStoredToken } from '../utils/protectedRouteHandler' + +/** + * Generates a loading toast with file download progress support + * @param router Next router instance, used for reloading the page + * @param progress Current downloading and compression progress (returned by jszip metadata) + * @returns Toast component with loading progress + */ +export function DownloadingToast(router: NextRouter, progress?: string) { + return ( +
+
+ Downloading {progress ? `${progress}%` : 'selected files...'} + +
+
+
+
+
+
+ +
+ ) +} // Blob download helper export function downloadBlob({ blob, name }: { blob: Blob; name: string }) { @@ -28,10 +57,12 @@ export function downloadBlob({ blob, name }: { blob: Blob; name: string }) { */ export async function downloadMultipleFiles({ toastId, + router, files, folder, }: { toastId: string + router: NextRouter files: { name: string; url: string }[] folder?: string }): Promise { @@ -50,9 +81,7 @@ export async function downloadMultipleFiles({ // Create zip file and download it const b = await zip.generateAsync({ type: 'blob' }, metadata => { - toast.loading(`Downloading ${metadata.percent.toFixed(0)}%. Refresh to cancel...`, { - id: toastId, - }) + toast.loading(DownloadingToast(router, metadata.percent.toFixed(0)), { id: toastId }) }) downloadBlob({ blob: b, name: folder ? folder + '.zip' : 'download.zip' }) } @@ -68,14 +97,15 @@ export async function downloadMultipleFiles({ * @param basePath Root dir path of files to be downloaded * @param folder Optional folder name to hold files, otherwise flatten files in the zip */ - export async function downloadTreelikeMultipleFiles({ toastId, + router, files, basePath, folder, }: { toastId: string + router: NextRouter files: AsyncGenerator<{ name: string url?: string @@ -117,9 +147,7 @@ export async function downloadTreelikeMultipleFiles({ // Create zip file and download it const b = await zip.generateAsync({ type: 'blob' }, metadata => { - toast.loading(`Downloading ${metadata.percent.toFixed(0)}%. Refresh to cancel...`, { - id: toastId, - }) + toast.loading(DownloadingToast(router, metadata.percent.toFixed(0)), { id: toastId }) }) downloadBlob({ blob: b, name: folder ? folder + '.zip' : 'download.zip' }) } diff --git a/components/previews/AudioPreview.tsx b/components/previews/AudioPreview.tsx index 6d31963..73b5198 100644 --- a/components/previews/AudioPreview.tsx +++ b/components/previews/AudioPreview.tsx @@ -11,7 +11,7 @@ enum PlayerState { Paused, } -export const AudioPreview: FunctionComponent<{ file: any }> = ({ file }) => { +const AudioPreview: FunctionComponent<{ file: any }> = ({ file }) => { const [playerStatus, setPlayerStatus] = useState(PlayerState.Loading) return ( @@ -79,3 +79,5 @@ export const AudioPreview: FunctionComponent<{ file: any }> = ({ file }) => { ) } + +export default AudioPreview diff --git a/components/previews/VideoPreview.tsx b/components/previews/VideoPreview.tsx index 8cc0045..69646f7 100644 --- a/components/previews/VideoPreview.tsx +++ b/components/previews/VideoPreview.tsx @@ -6,9 +6,9 @@ import { useClipboard } from 'use-clipboard-copy' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import toast, { Toaster } from 'react-hot-toast' -import { getBaseUrl } from "../../utils/getBaseUrl" +import { getBaseUrl } from '../../utils/getBaseUrl' -export const VideoPreview: FunctionComponent<{ file: any }> = ({ file }) => { +const VideoPreview: FunctionComponent<{ file: any }> = ({ file }) => { const { asPath } = useRouter() const clipboard = useClipboard() @@ -81,3 +81,5 @@ export const VideoPreview: FunctionComponent<{ file: any }> = ({ file }) => { ) } + +export default VideoPreview