I am using a shared component for uploading files which accepts only application/json, here is the component's code:
import React, { DragEvent, useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
export interface UploadFieldProps extends React.InputHTMLAttributes<HTMLInputElement> {
label?: string;
mainErrorMessage?: string;
subErrorMessage?: string;
onFilesChange?: (files: FileList | File[] | null) => void;
multiple?: boolean;
inputId?: string;
defaultFiles?: DefaultFiles[];
route?: string;
showDelete?: boolean;
maxSize?: number;
deleteHandler?: (id: string) => void;
showDownloadIcon?: boolean;
}
export interface DefaultFiles {
fileId: string;
name: string;
}
const MAX_SIZE = 5242880;
interface IFile extends File {
fileId?: string;
}
export function UploadField({
className = '',
inputId = 'upload-input',
disabled = false,
label = 'Drag files here or ...',
mainErrorMessage,
subErrorMessage,
multiple = false,
onFilesChange,
defaultFiles = [],
route,
showDelete = true,
maxSize = MAX_SIZE,
deleteHandler,
showDownloadIcon,
...props
}: UploadFieldProps) {
const [errorMessage, setErrorMessage] = useState('');
const [files, setFiles] = useState<FileList | File[] | null | Array<File>>(
defaultFiles as unknown as File[]
);
useEffect(() => {
setFiles(defaultFiles as unknown as File[]);
}, [defaultFiles]);
const createDataTransferFiles = (filesChanged: FileList) => {
const dataTransfer = new DataTransfer();
setErrorMessage('');
Array.from(filesChanged).forEach((file) => {
if (file.size <= maxSize) {
if (dataTransfer.files.length !== 0) {
for (const fileData of Array.from(dataTransfer.files)) {
if (fileData.name !== file.name) {
dataTransfer.items.add(file);
break;
}
}
} else {
dataTransfer.items.add(file);
}
} else {
setErrorMessage(`${file.name} exceeds size limit. 5mb max file size supported.`);
}
});
setFiles([...Array.from(dataTransfer.files), ...(files as [])]);
return dataTransfer.files;
};
const stopDragAndDropDefaultEvent = (e: DragEvent<HTMLDivElement>) => {
e.preventDefault();
e.stopPropagation();
};
const onDragAndDrop = (e: DragEvent<HTMLDivElement>) => {
if (disabled) {
return;
}
stopDragAndDropDefaultEvent(e);
const files = e.dataTransfer.files;
if (files && files.length) {
const fileList = createDataTransferFiles(e.dataTransfer.files);
onFilesChange && onFilesChange(fileList);
}
};
const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files) {
const fileList = createDataTransferFiles(event.target.files);
onFilesChange && onFilesChange(fileList);
}
};
return (
<div
className='relative z-0 w-full'
onDragOver={stopDragAndDropDefaultEvent}
onDragEnter={stopDragAndDropDefaultEvent}
onDrop={onDragAndDrop}
>
<input
id={inputId}
accept='application/JSON'
type='file'
data-testid='upload-input'
className='hidden'
multiple={multiple}
disabled={disabled}
onChange={onChange}
{...props}
/>
{label && <label htmlFor='upload-input'>{label}</label>}
<div>
<div className='flex items-center'>
<button disabled={disabled} data-testid='add-file' title='Upload file' />
</div>
</div>
{files?.length !== 0 &&
<div className='pt-2'>
{files &&
Array.from([...(files as unknown as File[])]).map((file, index) => {
return (
<div className='flex items-center content-center p-2 mb-3' key={index}>
{file?.name && defaultFiles[index]?.fileId ?
<Link to={`${route + defaultFiles[index].fileId}`} className='flex font-bold'>
{file?.name}
</Link>
:
<span className='pr-8 font-bold'>{file?.name}</span>
}
</div>
);
})}
</div>
}
{(!!mainErrorMessage || !!errorMessage) &&
<div className='flex flex-row ml-2 text-sm text-status-red' id='error'>
<span className='pr-2 font-bold'>{mainErrorMessage || errorMessage}</span>
<span>{subErrorMessage}</span>
</div>
}
</div>
);
}
export default UploadField;
When a file is dropped in that area, it show its name but I cannot find out how to show the content of that file.
As it can be seen, a file has the type File which says:
interface File extends Blob {
readonly lastModified: number;
readonly name: string;
readonly webkitRelativePath: string;
}
Is there a way to show the actual JSON content after drag & drop?
Something like:
if (files?.length) {
console.log('File content: ', files[0].something);
}