Skip to content

Commit

Permalink
feat: new file preview
Browse files Browse the repository at this point in the history
  • Loading branch information
tomicvladan committed Sep 19, 2023
1 parent b9a7eab commit 9040d21
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 30 deletions.
124 changes: 104 additions & 20 deletions src/components/FilePreview/FilePreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Button } from '@components/Buttons';
import ConsentViewer from '@components/ConsentViewer/ConsentViewer';
import { useLocales } from '@context/LocalesContext';
import { FileItem } from '@fairdatasociety/fdp-storage';
import { FC } from 'react';
import { FC, useEffect, useState } from 'react';

interface FilePreviewProps {
file: FileItem;
Expand All @@ -13,6 +13,26 @@ interface FilePreviewProps {
onError: () => void;
}

enum PreviewType {
Consent,
Text,
Video,
Image,
Unknown,
}

const TEXT_FILE_EXTENSIONS = [
'.txt',
'.srt',
'.log',
'.csv',
'.sub',
'.md',
'.json',
];

const IMAGE_FILE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.svg', '.gif', '.bmp'];

const VIDEO_FILE_EXTENSIONS = [
'.mpg',
'.mp2',
Expand All @@ -36,6 +56,23 @@ function isString(data: unknown): boolean {
return typeof data === 'string';
}

function checkFileExtension(fileName: string, extensions: string[]): boolean {
const lowercaseFileName = fileName.toLowerCase();
return extensions.some((extension) => lowercaseFileName.endsWith(extension));
}

function isTextFile(fileName: string): boolean {
return checkFileExtension(fileName, TEXT_FILE_EXTENSIONS);
}

function isFileImage(fileName: string): boolean {
return checkFileExtension(fileName, IMAGE_FILE_EXTENSIONS);
}

function isFileVideo(fileName: string): boolean {
return checkFileExtension(fileName, VIDEO_FILE_EXTENSIONS);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function isFileConsent(data: any): boolean {
return (
Expand All @@ -54,13 +91,6 @@ function isFileConsent(data: any): boolean {
);
}

function isFileVideo(fileName: string): boolean {
const lowercaseFileName = fileName.toLowerCase();
return VIDEO_FILE_EXTENSIONS.some((extension) =>
lowercaseFileName.endsWith(extension)
);
}

const FilePreview: FC<FilePreviewProps> = ({
file,
pod,
Expand All @@ -69,12 +99,56 @@ const FilePreview: FC<FilePreviewProps> = ({
onError,
}) => {
const { intl } = useLocales();
const [type, setType] = useState<PreviewType | null>(null);
const [content, setContent] = useState<unknown>(source);

if (isFileConsent(source)) {
const preparePreview = async () => {
try {
const fileName = file.name;

if (isFileVideo(fileName)) {
setContent(window.URL.createObjectURL(source));
return setType(PreviewType.Video);
}

if (isFileImage(fileName)) {
setContent(window.URL.createObjectURL(source));
return setType(PreviewType.Image);
}

if (isTextFile(fileName)) {
const text = await source.text();

if (fileName.endsWith('.json')) {
const json = JSON.parse(text);

if (isFileConsent(json)) {
setType(PreviewType.Consent);
return setContent(json);
}
}

setContent(text);
return setType(PreviewType.Text);
}

throw new Error('Unknown type');
} catch (error) {
setType(PreviewType.Unknown);

onError();
}
};

useEffect(() => {
preparePreview();
}, [file, source]);

if (type === PreviewType.Consent) {
return (
<>
<div className="w-full h-auto my-10 rounded">
<ConsentViewer data={source} />
<ConsentViewer data={content} />
</div>
{(!directory || !directory.includes('/')) && (
<div className="mb-4">
Expand All @@ -97,22 +171,32 @@ const FilePreview: FC<FilePreviewProps> = ({
);
}

if (isFileVideo(file.name || '')) {
if (type === PreviewType.Text) {
return (
<p className="w-full h-auto my-10 max-h-48 overflow-auto">{content}</p>
);
}

if (type === PreviewType.Video) {
return (
<video className="w-full h-auto my-10 rounded" controls>
<source src={source} />
<source src={content as string} />
</video>
);
}

return (
<img
src={source}
alt="Preview Image"
className="w-full h-auto my-10 rounded"
onError={onError}
/>
);
if (type === PreviewType.Image) {
return (
<img
src={content as string}
alt="Preview Image"
className="w-full h-auto my-10 rounded"
onError={onError}
/>
);
}

return null;
};

export default FilePreview;
15 changes: 5 additions & 10 deletions src/components/Modals/PreviewFileModal/PreviewFileModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const PreviewFileModal: FC<PreviewModalProps> = ({
const { activePod, directoryName } = useContext(PodContext);
const [loading, setLoading] = useState(false);

const [imageSource, setImageSource] = useState('');
const [fileContent, setFileContent] = useState<Blob | null>(null);
const [errorMessage, setErrorMessage] = useState('');
const [showShareFileModal, setShowShareFileModal] = useState(false);
const [showConfirmDeleteModal, setShowConfirmDeleteModal] = useState(false);
Expand All @@ -71,12 +71,7 @@ const PreviewFileModal: FC<PreviewModalProps> = ({
const blob = await response.arrayBuffer();
const content = new Blob([blob]);

if (previewFile?.name.endsWith('.json')) {
const json = await content.text();
return setImageSource(JSON.parse(json));
}

setImageSource(window.URL.createObjectURL(content));
setFileContent(content);
})
.catch((e) => {
setErrorMessage(intl.get('FILE_PREVIEW_ERROR'));
Expand Down Expand Up @@ -152,16 +147,16 @@ const PreviewFileModal: FC<PreviewModalProps> = ({
headerTitle={intl.get('PREVIEW_FILE')}
className="w-full md:w-98"
>
{imageSource ? (
{fileContent ? (
<FilePreview
file={previewFile}
source={imageSource}
source={fileContent}
pod={activePod}
directory={directoryName}
onError={() => setErrorMessage(intl.get('FILE_PREVIEW_ERROR'))}
/>
) : null}
<Spinner isLoading={loading} />
<Spinner className="my-8" isLoading={loading} />

{errorMessage ? (
<div className="my-28 text-color-status-negative-day text-xs text-center leading-none">
Expand Down

0 comments on commit 9040d21

Please sign in to comment.