Add function to download all files as a zip

This commit is contained in:
Elias Schneider
2022-04-30 23:30:23 +02:00
parent 7ddce593f9
commit b070f17d67
7 changed files with 265 additions and 16 deletions

View File

@@ -0,0 +1,67 @@
import { Tooltip, Button } from "@mantine/core";
import saveAs from "file-saver";
import JSZip from "jszip";
import { Dispatch, SetStateAction, useState } from "react";
import { AppwriteFileWithPreview } from "../../types/File.type";
import aw from "../../utils/appwrite.util";
const DownloadAllButton = ({
shareId,
files,
setFiles,
}: {
shareId: string;
files: AppwriteFileWithPreview[];
setFiles: Dispatch<SetStateAction<AppwriteFileWithPreview[]>>;
}) => {
const [isLoading, setIsLoading] = useState<boolean>(false);
const downloadAll = async () => {
setIsLoading(true);
var zip = new JSZip();
for (let i = 0; i < files.length; i++) {
files[i].uploadingState = "inProgress";
setFiles([...files]);
zip.file(
files[i].name,
await (
await fetch(
aw.storage.getFileDownload(shareId, files[i].$id).toString()
)
).blob()
);
files[i].uploadingState = "finished";
setFiles([...files]);
}
zip.generateAsync({ type: "blob" }).then(function (content) {
setIsLoading(false);
saveAs(content, `${shareId}-pingvin-share.zip`);
});
};
const isFileTooBig = () => {
let shareSize = 0;
files.forEach((file) => (shareSize = +file.sizeOriginal));
return 150000000 > shareSize;
};
if (!isFileTooBig())
return (
<Tooltip
wrapLines
position="bottom"
width={220}
withArrow
label="Only available if your share is smaller than 150 MB."
>
<Button variant="outline" onClick={downloadAll} disabled>
Download all
</Button>
</Tooltip>
);
return (
<Button variant="outline" loading={isLoading} onClick={downloadAll}>
Download all
</Button>
);
};
export default DownloadAllButton;

View File

@@ -1,7 +1,7 @@
import { ActionIcon, Skeleton, Table } from "@mantine/core";
import { ActionIcon, Loader, Skeleton, Table } from "@mantine/core";
import Image from "next/image";
import { useRouter } from "next/router";
import { Download } from "tabler-icons-react";
import { CircleCheck, Download } from "tabler-icons-react";
import { AppwriteFileWithPreview } from "../../types/File.type";
import aw from "../../utils/appwrite.util";
import { bytesToSize } from "../../utils/math/byteToSize.util";
@@ -50,14 +50,22 @@ const FileList = ({
<td>{file.name}</td>
<td>{bytesToSize(file.sizeOriginal)}</td>
<td>
<ActionIcon
size={25}
onClick={() =>
router.push(aw.storage.getFileDownload(shareId, file.$id))
}
>
<Download />
</ActionIcon>
{file.uploadingState ? (
file.uploadingState != "finished" ? (
<Loader size={22} />
) : (
<CircleCheck color="green" size={22} />
)
) : (
<ActionIcon
size={25}
onClick={() =>
router.push(aw.storage.getFileDownload(shareId, file.$id))
}
>
<Download />
</ActionIcon>
)}
</td>
</tr>
));

View File

@@ -1,7 +1,9 @@
import { Group } from "@mantine/core";
import { useModals } from "@mantine/modals";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import Meta from "../../components/Meta";
import DownloadAllButton from "../../components/share/DownloadAllButton";
import FileList from "../../components/share/FileList";
import showEnterPasswordModal from "../../components/share/showEnterPasswordModal";
import showShareNotFoundModal from "../../components/share/showShareNotFoundModal";
@@ -13,7 +15,7 @@ const Share = () => {
const router = useRouter();
const modals = useModals();
const shareId = router.query.shareId as string;
const [shareList, setShareList] = useState<AppwriteFileWithPreview[]>([]);
const [fileList, setFileList] = useState<AppwriteFileWithPreview[]>([]);
const submitPassword = async (password: string) => {
await shareService.authenticateWithPassword(shareId, password).then(() => {
@@ -25,7 +27,9 @@ const Share = () => {
const getFiles = (password?: string) =>
shareService
.get(shareId, password)
.then((files) => setShareList(files))
.then((files) => {
setFileList(files);
})
.catch((e) => {
const error = e.response.data.message;
if (e.response.status == 404) {
@@ -44,10 +48,17 @@ const Share = () => {
return (
<>
<Meta title={`Share ${shareId}`} />
<Group position="right">
<DownloadAllButton
shareId={shareId}
files={fileList}
setFiles={setFileList}
/>
</Group>
<FileList
files={shareList}
files={fileList}
shareId={shareId}
isLoading={shareList.length == 0}
isLoading={fileList.length == 0}
/>
</>
);

View File

@@ -3,5 +3,7 @@ import { Models } from "appwrite";
export type FileUpload = File & { uploadingState?: UploadState };
export type UploadState = "finished" | "inProgress" | undefined;
export type AppwriteFileWithPreview = Models.File & { preview: Buffer };
export interface AppwriteFileWithPreview extends Models.File {
uploadingState?: UploadState;
preview: Buffer;
}