mirror of
https://github.com/swissmakers/swiss-datashare.git
synced 2026-04-23 10:44:56 +02:00
feat: file preview
This commit is contained in:
93
frontend/src/pages/share/[shareId]/index.tsx
Normal file
93
frontend/src/pages/share/[shareId]/index.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import { Box, Group, Text, Title } from "@mantine/core";
|
||||
import { useModals } from "@mantine/modals";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
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 showErrorModal from "../../../components/share/showErrorModal";
|
||||
import shareService from "../../../services/share.service";
|
||||
import { Share as ShareType } from "../../../types/share.type";
|
||||
|
||||
export function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
return {
|
||||
props: { shareId: context.params!.shareId },
|
||||
};
|
||||
}
|
||||
|
||||
const Share = ({ shareId }: { shareId: string }) => {
|
||||
const modals = useModals();
|
||||
const [share, setShare] = useState<ShareType>();
|
||||
|
||||
const getShareToken = async (password?: string) => {
|
||||
await shareService
|
||||
.getShareToken(shareId, password)
|
||||
.then(() => {
|
||||
modals.closeAll();
|
||||
getFiles();
|
||||
})
|
||||
.catch((e) => {
|
||||
if (e.response.data.error == "share_max_views_exceeded") {
|
||||
showErrorModal(
|
||||
modals,
|
||||
"Visitor limit exceeded",
|
||||
"The visitor limit from this share has been exceeded."
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const getFiles = async () => {
|
||||
shareService
|
||||
.get(shareId)
|
||||
.then((share) => {
|
||||
setShare(share);
|
||||
})
|
||||
.catch((e) => {
|
||||
const { error } = e.response.data;
|
||||
if (e.response.status == 404) {
|
||||
if (error == "share_removed") {
|
||||
showErrorModal(modals, "Share removed", e.response.data.message);
|
||||
} else {
|
||||
showErrorModal(
|
||||
modals,
|
||||
"Not found",
|
||||
"This share can't be found. Please check your link."
|
||||
);
|
||||
}
|
||||
} else if (error == "share_password_required") {
|
||||
showEnterPasswordModal(modals, getShareToken);
|
||||
} else if (error == "share_token_required") {
|
||||
getShareToken();
|
||||
} else {
|
||||
showErrorModal(modals, "Error", "An unknown error occurred.");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getFiles();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Meta
|
||||
title={`Share ${shareId}`}
|
||||
description="Look what I've shared with you."
|
||||
/>
|
||||
|
||||
<Group position="apart" mb="lg">
|
||||
<Box style={{ maxWidth: "70%" }}>
|
||||
<Title order={3}>{share?.id}</Title>
|
||||
<Text size="sm">{share?.description}</Text>
|
||||
</Box>
|
||||
{share?.files.length > 1 && <DownloadAllButton shareId={shareId} />}
|
||||
</Group>
|
||||
|
||||
<FileList files={share?.files} shareId={shareId} isLoading={!share} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Share;
|
||||
92
frontend/src/pages/share/[shareId]/preview/[fileId].tsx
Normal file
92
frontend/src/pages/share/[shareId]/preview/[fileId].tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
import { Center, Stack, Text, Title } from "@mantine/core";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import { useState } from "react";
|
||||
|
||||
export function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
const { shareId, fileId } = context.params!;
|
||||
|
||||
const mimeType = context.query.type as string;
|
||||
|
||||
return {
|
||||
props: { shareId, fileId, mimeType },
|
||||
};
|
||||
}
|
||||
|
||||
const UnSupportedFile = () => {
|
||||
return (
|
||||
<Center style={{ height: "70vh" }}>
|
||||
<Stack align="center" spacing={10}>
|
||||
<Title order={3}>Preview not supported</Title>
|
||||
<Text>
|
||||
A preview for thise file type is unsupported. Please download the file
|
||||
to view it.
|
||||
</Text>
|
||||
</Stack>
|
||||
</Center>
|
||||
);
|
||||
};
|
||||
|
||||
const FilePreview = ({
|
||||
shareId,
|
||||
fileId,
|
||||
mimeType,
|
||||
}: {
|
||||
shareId: string;
|
||||
fileId: string;
|
||||
mimeType: string;
|
||||
}) => {
|
||||
const [isNotSupported, setIsNotSupported] = useState(false);
|
||||
|
||||
if (isNotSupported) return <UnSupportedFile />;
|
||||
|
||||
if (mimeType == "application/pdf") {
|
||||
window.location.href = `/api/shares/${shareId}/files/${fileId}?download=false`;
|
||||
return null;
|
||||
} else if (mimeType.startsWith("video/")) {
|
||||
return (
|
||||
<video
|
||||
width="100%"
|
||||
controls
|
||||
onError={() => {
|
||||
setIsNotSupported(true);
|
||||
}}
|
||||
>
|
||||
<source src={`/api/shares/${shareId}/files/${fileId}?download=false`} />
|
||||
</video>
|
||||
);
|
||||
} else if (mimeType.startsWith("image/")) {
|
||||
return (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
onError={() => {
|
||||
setIsNotSupported(true);
|
||||
}}
|
||||
src={`/api/shares/${shareId}/files/${fileId}?download=false`}
|
||||
alt={`${fileId}_preview`}
|
||||
width="100%"
|
||||
/>
|
||||
);
|
||||
} else if (mimeType.startsWith("audio/")) {
|
||||
return (
|
||||
<Center style={{ height: "70vh" }}>
|
||||
<Stack align="center" spacing={10} style={{ width: "100%" }}>
|
||||
<audio
|
||||
controls
|
||||
style={{ width: "100%" }}
|
||||
onError={() => {
|
||||
setIsNotSupported(true);
|
||||
}}
|
||||
>
|
||||
<source
|
||||
src={`/api/shares/${shareId}/files/${fileId}?download=false`}
|
||||
/>
|
||||
</audio>
|
||||
</Stack>
|
||||
</Center>
|
||||
);
|
||||
} else {
|
||||
return <UnSupportedFile />;
|
||||
}
|
||||
};
|
||||
|
||||
export default FilePreview;
|
||||
Reference in New Issue
Block a user