496 lines
15 KiB
JavaScript
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;
|