health-apps-cms/src/components/CustomFileUpload.jsx

496 lines
15 KiB
JavaScript

import React, {
forwardRef,
useEffect,
useImperativeHandle,
useRef,
useState,
} from 'react';
import { useStyles } from './styles/customFileUploadStyles';
import {
Box,
Button,
CircularProgress,
Grid,
InputLabel,
Modal,
Typography,
} from '@mui/material';
import { TransformWrapper, TransformComponent } from 'react-zoom-pan-pinch';
import Dropzone from 'react-dropzone';
import SaveAltIcon from '@mui/icons-material/SaveAlt';
import RemoveRedEyeOutlinedIcon from '@mui/icons-material/RemoveRedEyeOutlined';
import RemoveOutlinedIcon from '@mui/icons-material/RemoveOutlined';
import AddOutlinedIcon from '@mui/icons-material/AddOutlined';
import ZoomOutOutlinedIcon from '@mui/icons-material/ZoomOutOutlined';
import CloseIcon from '@mui/icons-material/Close';
import downloadIcon from '../assets/images/icon/download.svg';
import { pushNotification } from '../utils/notification';
import { FILE_TYPE, NOTIFICATION } from '../constants';
import uploadIcon from '../assets/images/icon/upload.svg';
import PdfIcon from '../assets/images/icon/pdf.png';
import DocIcon from '../assets/images/icon/doc.png';
import { fileUpload } from '../services/file.upload.services';
import { IMAGE_LOCATION_BASE_URL } from '../common/envVariables';
const CustomFileUpload = forwardRef(function CustomFileUpload(
{
documentName,
label,
saveFileName,
onUploadDone,
maxFileSizeInMb,
maxFiles,
uploadedFileUrl,
errorMessage,
isDisabled = false,
},
ref
) {
const classes = useStyles();
const imageRef = useRef(null);
const fileInputRef = useRef(null);
const [image, setImage] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [openPreview, setOpenPreview] = useState(false);
const [imageName, setImageName] = useState(
uploadedFileUrl ? uploadedFileUrl.split('/').pop() : ''
);
const [fileExtension, setFileExtension] = useState(
uploadedFileUrl ? uploadedFileUrl.split('.').pop() : ''
);
const [oldUploadedFileUrl, setOldUploadedFileUrl] = useState(
uploadedFileUrl ? uploadedFileUrl : ''
);
useImperativeHandle(ref, () => ({
focus: () => {
if (fileInputRef.current) {
fileInputRef.current.focus();
}
},
scrollIntoView: (...args) => {
if (fileInputRef.current) {
fileInputRef.current.scrollIntoView(...args);
}
},
}));
useEffect(() => {
const makeFullUrlIfNeeded = (url) => {
// Return early if url is undefined or empty
if (!url) {
setOldUploadedFileUrl('');
setFileExtension('');
setImageName('');
return;
}
const isHttp = url.startsWith('http://') || url.startsWith('https://');
if (!isHttp) {
setOldUploadedFileUrl(`${IMAGE_LOCATION_BASE_URL}${url}`);
setFileExtension(url.split('.').pop() || '');
setImageName(url.split('/').pop() || '');
return;
}
const urlObject = new URL(url);
const fileName = urlObject.pathname.split('/').pop();
setImageName(fileName);
setFileExtension(fileName.split('.').pop());
setOldUploadedFileUrl(url);
return url;
};
makeFullUrlIfNeeded(uploadedFileUrl);
}, [uploadedFileUrl]);
const handleClearImage = () => {
setImage(null);
setImageName('');
setFileExtension('');
setOldUploadedFileUrl('');
onUploadDone(documentName, '');
};
const handleFileUpload = async (value) => {
if (!value) {
return;
}
let formData = new FormData();
formData.append('file', value);
formData.append('fileName', value?.name);
try {
setIsLoading(true);
const data = await fileUpload(formData);
onUploadDone(documentName, data?.data?.data?.Key);
return;
} catch (error) {
// console.error(error);
pushNotification('Error while uploading file', NOTIFICATION.ERROR);
} finally {
setIsLoading(false);
}
};
const handleDrop = async (acceptedFiles) => {
const file = acceptedFiles[0];
await handleFileUpload(file);
setImage(file);
setImageName(file.name);
setOldUploadedFileUrl('');
setFileExtension('');
};
const handelRejection = (rejectedFiles) => {
rejectedFiles.forEach((rejection) => {
pushNotification(
`${rejection?.file?.name} : ${rejection?.errors?.[0]?.message}`,
NOTIFICATION.ERROR
);
});
};
const handlePreview = () => {
setOpenPreview(true);
};
const handleClose = () => {
setOpenPreview(false);
};
const handleDownload = () => {
if (image) {
const imageUrl = URL.createObjectURL(image);
const anchor = document.createElement('a');
anchor.href = imageUrl;
anchor.download = saveFileName || imageName || 'Image';
anchor.click();
}
if (oldUploadedFileUrl) {
const imageUrl = oldUploadedFileUrl;
const anchor = document.createElement('a');
anchor.href = imageUrl;
anchor.download = saveFileName || imageName || 'Image';
anchor.click();
}
};
const Controls = ({ zoomIn, zoomOut, resetTransform }) => (
<>
<Grid className={classes.controlButtons}>
<Button
className={`${classes.zoomOutButton} ${classes.controlButton}`}
onClick={() => zoomOut()}
>
<RemoveOutlinedIcon className={classes.iconSize} />
</Button>
<Button
className={`${classes.zoomResetButton} ${classes.controlButton}`}
onClick={() => resetTransform()}
>
<ZoomOutOutlinedIcon className={classes.iconSize} />
</Button>
<Button
className={`${classes.zoomInButton} ${classes.controlButton}`}
onClick={() => zoomIn()}
>
<AddOutlinedIcon className={classes.iconSize} />
</Button>
</Grid>
</>
);
const FileUploadComponent = ({
isLoading,
fileUrl,
fileExtension,
maxFileSizeInMb,
handlePreview,
handleDownload,
classes,
}) => (
<>
<Box className={classes?.addButton}>
<Box className={classes?.addButtonContent}>
{isLoading ? (
<CircularProgress />
) : (
<>
{fileUrl ? (
<>
{fileExtension === 'pdf' ? (
<img
alt="Uploaded file"
src={PdfIcon}
height="125px"
width="auto"
/>
) : fileExtension === 'doc' ||
fileExtension === 'docx' ||
fileExtension ===
'vnd.openxmlformats-officedocument.wordprocessingml.document' ||
fileExtension === 'msword' ? (
<img
alt="Uploaded file"
src={DocIcon}
height="125px"
width="auto"
/>
) : (
<img
alt="Uploaded file"
src={fileUrl}
height="125px"
width="auto"
/>
)}
<Box className={classes?.onImageButton}>
<button
type="button"
className={classes.eyeButton}
onClick={handlePreview}
>
<RemoveRedEyeOutlinedIcon className={classes.iconSize} />
</button>
<button
type="button"
className={classes.downloadButton}
onClick={handleDownload}
>
<SaveAltIcon className={classes.iconSize} />
</button>
</Box>
</>
) : (
<>
<Box
className={classes?.addIcon}
component="img"
src={uploadIcon}
/>
<Typography className={classes?.addText}>
Drag and drop file here, or click add
</Typography>
<Typography className={classes.addSubtext}>
Allowed file types are jpeg, png, pdf, svg, doc to a maximum
size of {maxFileSizeInMb} MB
</Typography>
</>
)}
</>
)}
</Box>
</Box>
{errorMessage && (
<Box className={classes.errorMessage}>{errorMessage}</Box>
)}
</>
);
const PreviewComponent = ({
fileUrl,
fileExtension,
handleDownload,
classes,
}) => (
<>
{fileExtension === 'pdf' ? (
<>
<Box className={classes.pdfAndDocPreviewBox}>
<img
alt="Uploaded file"
src={PdfIcon}
ref={imageRef}
height="125px"
width="auto"
/>
<Button
className={classes.pdfAndDocPreviewDownloadButton}
variant="contained"
onClick={handleDownload}
>
Download
</Button>
</Box>
</>
) : fileExtension === 'doc' ||
fileExtension === 'docx' ||
fileExtension ===
'vnd.openxmlformats-officedocument.wordprocessingml.document' ||
fileExtension === 'msword' ? (
<>
<Box className={classes.pdfAndDocPreviewBox}>
<img
alt="Uploaded file"
src={DocIcon}
ref={imageRef}
height="125px"
width="auto"
/>
<Button
className={classes.pdfAndDocPreviewDownloadButton}
variant="contained"
onClick={handleDownload}
>
Download
</Button>
</Box>
</>
) : (
<TransformWrapper>
{(utils) => (
<React.Fragment>
<Box className={classes.transFormImageBox}>
<TransformComponent
wrapperClass={classes.customTransFormWrapper}
>
<img
alt="Uploaded file"
src={fileUrl}
ref={imageRef}
height="250px"
width="auto"
/>
</TransformComponent>
</Box>
<Controls {...utils} />
</React.Fragment>
)}
</TransformWrapper>
)}
</>
);
return (
<>
<Box className={classes.mainBox}>
<InputLabel className={classes?.inputTitle}>
{label}
{(image || oldUploadedFileUrl) && (
<div>
{!isDisabled && (
<button
className={classes.imgButton}
onClick={handleClearImage}
>
REMOVE
</button>
)}
</div>
)}
</InputLabel>
<Box display="flex">
<Box className={classes.dropZoneOuterBox}>
<label htmlFor="file" ref={fileInputRef}>
<Dropzone
accept={{
'image/': [...FILE_TYPE],
}}
onDrop={handleDrop}
onDropRejected={handelRejection}
maxFiles={maxFiles}
maxSize={maxFileSizeInMb * 1024 * 1024}
disabled={isDisabled}
>
{({ getRootProps, getInputProps }) => (
<div
{...getRootProps({
onClick: (event) => {
if (image || oldUploadedFileUrl) {
event.stopPropagation();
}
},
})}
>
<input {...getInputProps()} />
{!oldUploadedFileUrl ? (
<>
<FileUploadComponent
isLoading={isLoading}
fileUrl={image ? URL.createObjectURL(image) : null}
fileExtension={
image ? image.type.split('/')[1] : null
}
maxFileSizeInMb={maxFileSizeInMb}
handlePreview={handlePreview}
handleDownload={handleDownload}
classes={classes}
/>
</>
) : (
<>
<FileUploadComponent
isLoading={isLoading}
fileUrl={oldUploadedFileUrl}
fileExtension={fileExtension}
maxFileSizeInMb={maxFileSizeInMb}
handlePreview={handlePreview}
handleDownload={handleDownload}
classes={classes}
/>
</>
)}
</div>
)}
</Dropzone>
</label>
</Box>
</Box>
</Box>
<Modal open={openPreview} onClose={handleClose}>
<Box className={classes.previewFullScreenBox}>
<Grid md={12} className={classes.previewHeading}>
<Grid md={2}>
<Button
className={classes.previewDownloadButton}
onClick={handleDownload}
>
<img
src={downloadIcon}
className={classes.previewDownloadIcon}
/>
</Button>
<Button
onClick={handleClose}
className={classes.previewCloseButton}
>
<CloseIcon className={classes.iconSize} />
</Button>
</Grid>
</Grid>
<Grid container>
<Grid item md={12} className={classes.previewFileTitle}>
<Typography color="white">{imageName}</Typography>
</Grid>
</Grid>
<Grid xs={12} className={classes.previewImageGrid}>
{!oldUploadedFileUrl ? (
<>
<PreviewComponent
fileUrl={image ? URL.createObjectURL(image) : null}
fileExtension={image ? image.type.split('/')[1] : null}
handlePreview={handlePreview}
handleDownload={handleDownload}
classes={classes}
/>
</>
) : (
<>
<PreviewComponent
fileUrl={oldUploadedFileUrl}
fileExtension={fileExtension}
handlePreview={handlePreview}
handleDownload={handleDownload}
classes={classes}
/>
</>
)}
</Grid>
</Box>
</Modal>
</>
);
});
export default CustomFileUpload;