diff --git a/web/src/components/FOI/Home/Edit.tsx b/web/src/components/FOI/Home/Edit.tsx new file mode 100644 index 000000000..1a7cb8f03 --- /dev/null +++ b/web/src/components/FOI/Home/Edit.tsx @@ -0,0 +1,88 @@ +import { ReactComponent as EditLogo } from "../../../assets/images/icon-pencil-line.svg"; + + const disableMultiSelectEdit = (_selectedAnnotations: any) => { + if (_selectedAnnotations && _selectedAnnotations.length > 0) { + return _selectedAnnotations.some( + (obj: any) => + obj.Subject !== "Redact" && obj.getCustomData("sections") === "" + ); + } + return true; + }; + + //START: Bulk Edit using Multi Select Option + const MultiSelectEdit = ({docInstance, editRedactions}: any) => { + let _selectedAnnotations = + docInstance?.Core?.annotationManager.getSelectedAnnotations(); + const disableEdit = disableMultiSelectEdit(_selectedAnnotations); + const _selectedRedactions = _selectedAnnotations?.filter( + (obj: any) => + obj.Subject !== "Redact" && obj.getCustomData("sections") !== "" + ); + return ( + + ); + }; + //END: Bulk Edit using Multi Select Option + + + const Edit = ({instance, editAnnotation}: any) => { + let _selectedAnnotations = instance?.Core?.annotationManager.getSelectedAnnotations(); + const disableEdit = _selectedAnnotations.some( + (obj: any) => + obj.Subject !== "Redact" && obj.getCustomData("sections") === "" + ); + const _selectedRedaction = _selectedAnnotations.filter( + (obj: any) => obj.Subject === "Redact" + ); + return ( + + ); + }; + + export { + MultiSelectEdit, + Edit + }; \ No newline at end of file diff --git a/web/src/components/FOI/Home/Redlining.js b/web/src/components/FOI/Home/Redlining.js index 9fe6b8a2c..8c29df5e0 100644 --- a/web/src/components/FOI/Home/Redlining.js +++ b/web/src/components/FOI/Home/Redlining.js @@ -52,7 +52,11 @@ import { getStitchedPageNoFromOriginal, createPageFlagPayload, sortByLastModified, + createRedactionSectionsString, + getSections, + getValidSections, } from "./utils"; +import { Edit, MultiSelectEdit } from "./Edit"; import _ from "lodash"; const Redlining = React.forwardRef( @@ -121,10 +125,8 @@ const Redlining = React.forwardRef( // State variables for Bulk Edit using Multi Selection option const [editRedacts, setEditRedacts] = useState(null); - const [multiSelectedAnnotations, setMultiSelectedAnnotations] = useState( - [] - ); const [multiSelectFooter, setMultiSelectFooter] = useState(null); + const [enableMultiSelect, setEnableMultiSelect] = useState(false); //xml parser const parser = new XMLParser(); @@ -190,56 +192,15 @@ const Redlining = React.forwardRef( isReadyForSignOff() && requestStatus == RequestStates["Response"] ); - //START: Bulk Edit using Multi Select Option - const MultiSelectEdit = () => { - let _selectedAnnotations = multiSelectedAnnotations; - const disableEdit = - _selectedAnnotations.length === 0 || - _selectedAnnotations?.some( - (obj) => - obj.Subject !== "Redact" && obj.getCustomData("sections") === "" - ); - const _selectedRedactions = _selectedAnnotations?.filter( - (obj) => - obj.Subject !== "Redact" && obj.getCustomData("sections") !== "" - ); - return ( - - ); - }; - //END: Bulk Edit using Multi Select Option - // const [storedannotations, setstoreannotations] = useState(localStorage.getItem("storedannotations") || []) // if using a class, equivalent of componentDidMount useEffect(() => { let initializeWebViewer = async () => { let currentDocumentS3Url = currentDocument?.currentDocumentS3Url; fetchSections(requestid, (error) => console.log(error)); - let response = await fetchPDFTronLicense( - null, - (error) => console.log(error) - ) + let response = await fetchPDFTronLicense(null, (error) => + console.log(error) + ); WebViewer( { licenseKey: response.data.license, @@ -390,45 +351,12 @@ const Redlining = React.forwardRef( ); }); - const Edit = () => { - let _selectedAnnotations = annotationManager.getSelectedAnnotations(); - const disableEdit = _selectedAnnotations.some( - (obj) => - obj.Subject !== "Redact" && obj.getCustomData("sections") === "" - ); - const _selectedRedaction = _selectedAnnotations.filter( - (obj) => obj.Subject === "Redact" - ); - return ( - - ); - }; - instance.UI.annotationPopup.add({ type: "customElement", title: "Edit", - render: () => , + render: () => ( + + ), }); setDocInstance(instance); @@ -506,7 +434,7 @@ const Redlining = React.forwardRef( multiDeleteButton?.addEventListener("click", function () { root = null; setMultiSelectFooter(root); - setMultiSelectedAnnotations([]); + setEnableMultiSelect(false); }); } @@ -516,7 +444,7 @@ const Redlining = React.forwardRef( closeButton?.addEventListener("click", function () { root = null; setMultiSelectFooter(root); - setMultiSelectedAnnotations([]); + setEnableMultiSelect(false); }); } @@ -530,7 +458,7 @@ const Redlining = React.forwardRef( if (isActive) { root = null; setMultiSelectFooter(root); - setMultiSelectedAnnotations([]); + setEnableMultiSelect(false); } }); @@ -548,40 +476,19 @@ const Redlining = React.forwardRef( _multiSelectFooter.firstChild ); } - const listItems = document.querySelectorAll('[role="listitem"]'); + const listItems = + document.querySelectorAll('[role="listitem"]'); listItems.forEach((listItem) => { - let checkbox = listItem.querySelector('input[type="checkbox"]'); + let checkbox = listItem.querySelector( + 'input[type="checkbox"]' + ); if (checkbox) { if (root === null) { root = createRoot(editButton); setMultiSelectFooter(root); } checkbox.addEventListener("click", function () { - checkbox = listItem.querySelector('input[type="checkbox"]'); - const spanWrapper = checkbox.parentElement.parentElement; // Get the parent span element - // Check if the span element has the "ui__choice--checked" class - const isChecked = spanWrapper.classList.contains( - "ui__choice--checked" - ); //actual scenario isChecked = true when you uncheck the checkbox - const selectedIdString = checkbox.id?.split("_"); - if (selectedIdString.length > 0) { - const annotationName = selectedIdString[1]; - const _annot = - annotationManager.getAnnotationById(annotationName); - setMultiSelectedAnnotations((prevSelectedAnnotations) => { - const isExists = prevSelectedAnnotations.find( - (_annotation) => _annotation.Id === annotationName - ); - if (isExists === undefined && !isChecked) { - return [...prevSelectedAnnotations, _annot]; - } else if (isExists && isChecked) { - return prevSelectedAnnotations.filter( - (_annotation) => _annotation.Id !== annotationName - ); - } - return prevSelectedAnnotations; - }); - } + setEnableMultiSelect(true); }); } }); @@ -591,19 +498,10 @@ const Redlining = React.forwardRef( true ); }); - } + }; initializeWebViewer(); }, []); - //START: UE to render MultiSelectEdit part of Bulk Edit using Multi Select Option - useEffect(() => { - if (multiSelectFooter) { - multiSelectFooter.render(); - } - }, [multiSelectedAnnotations]); - - //END: UE to render MultiSelectEdit part of Bulk Edit using Multi Select Option - useEffect(() => { const changeLayer = async () => { if (currentLayer) { @@ -967,7 +865,7 @@ const Redlining = React.forwardRef( } } }); - docInstance.Core.Annotations.NoMove=true; + docInstance.Core.Annotations.NoMove = true; setAnnots(docInstance.Core.Annotations); } }, @@ -982,25 +880,14 @@ const Redlining = React.forwardRef( useEffect(() => { annotManager?.addEventListener("annotationSelected", (annotations) => { - //START - handled grouped annotation selection due to auto multi select issue part of Bulk Edit using Multi Select Option. - // get freetext annotations with redaction sections alone - const _selectedRedactions = annotations.filter( - (obj) => - obj.Subject !== "Redact" && obj.getCustomData("sections") !== "" - ); - let annotationName = _selectedRedactions[0]?.Id; - if (annotationName) { - setMultiSelectedAnnotations((prevSelectedAnnotations) => { - const isExists = prevSelectedAnnotations.find( - (_annotation) => _annotation.Id === annotationName - ); - if (isExists === undefined) { - return [...prevSelectedAnnotations, _selectedRedactions[0]]; - } - return prevSelectedAnnotations; - }); + if (multiSelectFooter && enableMultiSelect) { + multiSelectFooter.render( + + ); } - //END - handled grouped annotation selection due to auto multi select issue part of Bulk Edit using Multi Select Option. }); annotManager?.removeEventListener( @@ -1023,6 +910,8 @@ const Redlining = React.forwardRef( newRedaction, pageSelections, redlineSaving, + multiSelectFooter, + enableMultiSelect, ]); useImperativeHandle(ref, () => ({ @@ -1195,7 +1084,7 @@ const Redlining = React.forwardRef( _annotation.NoMove = true; if (_annotation.Subject === "Redact") { _annotation.IsHoverable = false; - + if (_annotation.type === "fullPage") { _annotation.NoResize = true; annotManager.bringToBack(_annotation); @@ -1259,26 +1148,16 @@ const Redlining = React.forwardRef( childAnnotation.Y = _redact.Y; childAnnotation.FontSize = _redact.FontSize; if (redactionSectionsIds.length > 0) { - let redactionSections = sections - .filter((s) => redactionSectionsIds.indexOf(s.id) > -1) - .map((s) => s.section) - .join(", "); - if ( - redactionSectionsIds?.length == 1 && - redactionSectionsIds[0] === 25 - ) { - redactionSections = " "; - } + let redactionSections = createRedactionSectionsString( + sections, + redactionSectionsIds + ); childAnnotation.setContents(redactionSections); const displayedDoc = pageMappedDocs.stitchedPageLookup[Number(node.attributes.page) + 1]; childAnnotation.setCustomData( "sections", - JSON.stringify( - sections - .filter((s) => redactionSectionsIds.indexOf(s.id) > -1) - .map((s) => ({ id: s.id, section: s.section })) - ) + JSON.stringify(getSections(sections, redactionSectionsIds)) ); childAnnotation.setCustomData("docid", displayedDoc.docid); childAnnotation.setCustomData("docversion", displayedDoc.docversion); @@ -1323,7 +1202,7 @@ const Redlining = React.forwardRef( }); } setSelectedSections([]); - setMultiSelectedAnnotations([]); + setEnableMultiSelect(false); setEditRedacts(null); }); @@ -1361,16 +1240,10 @@ const Redlining = React.forwardRef( childAnnotation = getCoordinates(childAnnotation, redaction, X); let redactionSectionsIds = selectedSections; if (redactionSectionsIds.length > 0) { - let redactionSections = sections - .filter((s) => redactionSectionsIds.indexOf(s.id) > -1) - .map((s) => s.section) - .join(", "); - if ( - redactionSectionsIds?.length == 1 && - redactionSectionsIds[0] === 25 - ) { - redactionSections = " "; - } + let redactionSections = createRedactionSectionsString( + sections, + redactionSectionsIds + ); childAnnotation.setContents(redactionSections); const displayedDoc = pageMappedDocs.stitchedPageLookup[ @@ -1378,11 +1251,7 @@ const Redlining = React.forwardRef( ]; childAnnotation.setCustomData( "sections", - JSON.stringify( - sections - .filter((s) => redactionSectionsIds.indexOf(s.id) > -1) - .map((s) => ({ id: s.id, section: s.section })) - ) + JSON.stringify(getSections(sections, redactionSectionsIds)) ); childAnnotation.setCustomData("docid", displayedDoc.docid); childAnnotation.setCustomData( @@ -1470,22 +1339,16 @@ const Redlining = React.forwardRef( annot.Author = user?.name || user?.preferred_username || ""; let redactionSectionsIds = defaultSections.length > 0 ? defaultSections : selectedSections; - let redactionSections = sections.filter( - (s) => redactionSectionsIds.indexOf(s.id) > -1 + let redactionSections = createRedactionSectionsString( + sections, + redactionSectionsIds ); - let redactionSectionsString = redactionSections - .map((s) => s.section) - .join(", "); - if (selectedSections?.length == 1 && selectedSections[0] === 25) { - redactionSectionsString = " "; - } - annot.setContents(redactionSectionsString); + annot.setAutoSizeType("auto"); + annot.setContents(redactionSections); annot.setCustomData("parentRedaction", redaction.Id); annot.setCustomData( "sections", - JSON.stringify( - redactionSections.map((s) => ({ id: s.id, section: s.section })) - ) + JSON.stringify(getSections(sections, redactionSectionsIds)) ); const doc = docViewer.getDocument(); const pageInfo = doc.getPageInfo(annot.PageNumber); @@ -1539,7 +1402,10 @@ const Redlining = React.forwardRef( } } - for (let section of redactionSections) { + for (let section of getValidSections( + sections, + redactionSectionsIds + )) { section.count++; } //delete if there are existing fullpage redactions @@ -2049,7 +1915,7 @@ const Redlining = React.forwardRef( // saves the document with annotations in it xfdfString: xfdfString, downloadType: downloadType, - flatten: true + flatten: true, }) .then(async (_data) => { const _arr = new Uint8Array(_data); diff --git a/web/src/components/FOI/Home/utils.js b/web/src/components/FOI/Home/utils.js index e5af50971..7aedd0a3a 100644 --- a/web/src/components/FOI/Home/utils.js +++ b/web/src/components/FOI/Home/utils.js @@ -71,3 +71,27 @@ export const getProgramAreas = (pageFlagList) => { // Helper function to sort files by lastmodified date export const sortByLastModified = (files) => files.sort(docSorting); + +export const getValidSections = (sections, redactionSectionsIds) => { + return sections.filter((s) => redactionSectionsIds.indexOf(s.id) > -1); +}; + +export const getSections = (sections, redactionSectionsIds) => { + return getValidSections(sections, redactionSectionsIds).map((s) => ({ + id: s.id, + section: s.section, + })); +}; + +export const createRedactionSectionsString = ( + sections, + redactionSectionsIds +) => { + let redactionSections = getValidSections(sections, redactionSectionsIds) + .map((s) => s.section) + .join(", "); + if (redactionSectionsIds?.length == 1 && redactionSectionsIds[0] === 25) { + redactionSections = " "; + } + return redactionSections; +};