Add function to download all files as a zip
This commit is contained in:
67
src/components/share/DownloadAllButton.tsx
Normal file
67
src/components/share/DownloadAllButton.tsx
Normal 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;
|
||||
@@ -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>
|
||||
));
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user