From 013f99967d456ff1440ac59df4efa2fedf3c743d Mon Sep 17 00:00:00 2001 From: himeshr Date: Wed, 3 Apr 2024 14:13:51 +0530 Subject: [PATCH] #1133 | WIP: Correctly handle upload of single/multiple image or video upload in forms --- src/dataEntryApp/components/MediaUploader.js | 199 ++++++++++--------- 1 file changed, 108 insertions(+), 91 deletions(-) diff --git a/src/dataEntryApp/components/MediaUploader.js b/src/dataEntryApp/components/MediaUploader.js index c669f06ed..701f05895 100644 --- a/src/dataEntryApp/components/MediaUploader.js +++ b/src/dataEntryApp/components/MediaUploader.js @@ -1,5 +1,5 @@ import React, { Fragment, useEffect, useState } from "react"; -import { get, isEmpty, includes, lowerCase } from "lodash"; +import { get, isEmpty, includes, lowerCase, isArrayLikeObject } from "lodash"; import { Box, Button, Grid, makeStyles, Typography } from "@material-ui/core"; import FormControl from "@material-ui/core/FormControl"; import http from "../../common/utils/httpClient"; @@ -9,7 +9,6 @@ import Audiotrack from "@material-ui/icons/Audiotrack"; import CloudUploadIcon from "@material-ui/icons/CloudUpload"; import CustomizedBackdrop from "./CustomizedBackdrop"; import CloseIcon from "@material-ui/icons/Close"; -import ReactImageVideoLightbox from "react-image-video-lightbox"; import { Concept } from "avni-models"; import { FilePreview } from "./FilePreview"; import MediaService from "../../adminApp/service/MediaService"; @@ -56,101 +55,130 @@ const isValidType = (formElement, type, isFile) => { : includes(type, lowerCase(formElement.getType())); }; +function updatePreviewWithObsResults(observationValue, setPreview) { + MediaService.getMedia(observationValue).then(res => + setPreview(oldPreview => ({ + ...oldPreview, + [observationValue]: res + })) + ); +} + +function addMediaUrlToLocalObsValue(setLocalObsValue, isMultiSelect, localObsValue, r) { + if (isMultiSelect) { + if (isArrayLikeObject(localObsValue)) { + setLocalObsValue(locObsValue => [...locObsValue, r.data]); + } else { + setLocalObsValue(locObsValue => [locObsValue, r.data].filter(ele => !isEmpty(ele))); + } + } else { + setLocalObsValue(r.data); + } +} + export const MediaUploader = ({ label, obsValue, mediaType, update, formElement }) => { const classes = useStyles(); const Icon = iconMap[mediaType]; - const [value, setValue] = useState(""); - const [file, setFile] = useState(); - const [preview, setPreview] = useState(); + const [localObsValue, setLocalObsValue] = useState(obsValue); + const [preview, setPreview] = useState({}); + const [uploadButtonClicked, setUploadButtonClicked] = useState(0); const [uploading, setUploading] = useState(false); - const [openImage, setOpenImage] = useState(false); const isFileDataType = formElement.getType() === Concept.dataType.File; const supportedMIMEType = isFileDataType ? getFileMimeType(formElement) : `${mediaType}/*`; + const isMultiSelect = formElement.isMultiSelect(); useEffect(() => { - if (!file) { - setPreview(); - return; - } - const objectUrl = URL.createObjectURL(file); - setPreview(objectUrl); - // free memory when ever this component is unmounted - return () => URL.revokeObjectURL(objectUrl); - }, [file]); + // Push consolidated changes to ObservationHolder, doing it directly without state messes up the multi-select flows + update(localObsValue); + }, [localObsValue]); useEffect(() => { if (!isEmpty(obsValue)) { - MediaService.getMedia(obsValue).then(res => setPreview(res)); + if (isArrayLikeObject(obsValue)) { + obsValue.forEach(obsItrValue => updatePreviewWithObsResults(obsItrValue, setPreview)); + } else { + updatePreviewWithObsResults(obsValue, setPreview); + } } }, [obsValue]); useEffect(() => { - if (openImage) { - const LightBoxContainer = document.querySelector("div.imagePreviewContainer"); - LightBoxContainer.firstChild.style.zIndex = 1; - } - }, [openImage]); + setUploading(uploadButtonClicked > 0); + }, [uploadButtonClicked]); const onMediaSelect = event => { - const fileReader = new FileReader(); - event.target.files[0] && fileReader.readAsText(event.target.files[0]); - const file = event.target.files[0]; - if (!isValidType(formElement, file.type, isFileDataType)) { - alert("Selected file type not supported. Please choose proper file."); - return; - } - if (isFileDataType && isBiggerFile(formElement, file.size)) { - const oneMBInBytes = 1000000; - alert( - `Selected file size ${file.size / - oneMBInBytes} MB is more than the set max file size ${formElement.allowedMaxSize / - oneMBInBytes} MB.` - ); + const alerts = []; + const etFiles = Array.from(event.target.files); + etFiles.forEach(file => { + if (!isValidType(formElement, file.type, isFileDataType)) { + alerts.push( + `Selected files type not supported for file ${file.name}. Please choose proper files.\n` + ); + } + if (isFileDataType && isBiggerFile(formElement, file.size)) { + const oneMBInBytes = 1000000; + alerts.push( + `Selected file size ${file.size / + oneMBInBytes} MB is more than the set max file size ${formElement.allowedMaxSize / + oneMBInBytes} MB for file ${file.name}.\n` + ); + } + }); + if (!isEmpty(alerts)) { + alert(alerts); return; } - setValue(event.target.value); - fileReader.onloadend = event => { - setFile(file); - setUploading(true); - http - .uploadFile("/web/uploadMedia", file) - .then(r => { - setUploading(false); - update(r.data); - }) - .catch(r => { - const error = `${get(r, "response.data") || - get(r, "message") || - "Unknown error occurred while uploading media"}`; - setUploading(false); - onDelete(); - alert(error); - }); - }; + etFiles.forEach(file => { + const fileReader = new FileReader(); + file && fileReader.readAsText(file); + setUploadButtonClicked(oldValue => oldValue + 1); + fileReader.onloadend = event => { + http + .uploadFile("/web/uploadMedia", file) + .then(r => { + setUploadButtonClicked(oldValue => oldValue - 1); + addMediaUrlToLocalObsValue(setLocalObsValue, isMultiSelect, localObsValue, r); + }) + .catch(r => { + const error = `${get(r, "response.data") || + get(r, "message") || + "Unknown error occurred while uploadButtonClicked media"}`; + setUploadButtonClicked(oldValue => oldValue - 1); + onDelete(file.name); + alert(error); + }); + }; + }); }; - const onDelete = () => { - setFile(); - setPreview(); - update(); - preview && URL.revokeObjectURL(preview); + const onDelete = fileName => { + if (isMultiSelect && isArrayLikeObject(localObsValue)) { + const filteredObsValue = localObsValue.filter(item => item != fileName); + setLocalObsValue([...filteredObsValue]); + } else { + if (localObsValue === fileName) setLocalObsValue(); //Remove previous value + } + preview[fileName] && URL.revokeObjectURL(preview[fileName]); + setPreview(oldPreview => ({ + ...oldPreview, + [fileName]: null + })); }; - const mediaPreviewMap = { - image: ( - {label} setOpenImage(true)} /> - ), + //TODO ONCLICK open in new tab + const mediaPreviewMap = fileToPreview => ({ + image: {label}, video: ( ), - audio: