UNPKG

@hmcts/media-viewer

Version:
1,464 lines (1,449 loc) 558 kB
import * as i5 from 'rpx-xui-translation'; import { RpxTranslationModule } from 'rpx-xui-translation'; import * as i0 from '@angular/core'; import { Injectable, Component, ViewChild, HostListener, Directive, Input, ViewEncapsulation, Pipe, EventEmitter, Output, ViewChildren, NgModule } from '@angular/core'; import * as i4 from '@angular/common'; import { DatePipe, CommonModule } from '@angular/common'; import * as i2 from '@angular/forms'; import { UntypedFormControl, FormGroup, FormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms'; import * as i1$1 from '@angular/common/http'; import { HttpClientModule } from '@angular/common/http'; import { BehaviorSubject, Subject, of, combineLatest, asyncScheduler, filter as filter$1, take as take$1, delay } from 'rxjs'; import { take, distinctUntilChanged, filter, auditTime, tap, throttleTime, map, catchError, switchMap, concatMap, exhaustMap, withLatestFrom } from 'rxjs/operators'; import * as i1 from '@ngrx/store'; import { createFeatureSelector, createSelector, select, StoreModule } from '@ngrx/store'; import { v4 } from 'uuid'; import moment from 'moment-timezone'; import 'pdfjs-dist/build/pdf.mjs'; import * as pdfjsViewer from 'pdfjs-dist/web/pdf_viewer.mjs'; import { PDFLinkService } from 'pdfjs-dist/web/pdf_viewer.mjs'; import * as pdfjs from 'pdfjs-dist'; import 'pdfjs-dist/build/pdf.worker'; import { some } from 'lodash'; import * as i4$1 from 'ngx-chips'; import { TagInputModule } from 'ngx-chips'; import * as i3 from '@angular/router'; import { RouterModule } from '@angular/router'; import * as i4$2 from 'mutable-div'; import { MutableDivModule } from 'mutable-div'; import { SelectionModel, ArrayDataSource } from '@angular/cdk/collections'; import * as i3$1 from '@angular/cdk/tree'; import { NestedTreeControl, CdkTreeModule } from '@angular/cdk/tree'; import * as i4$3 from '@angular/cdk/drag-drop'; import { DragDropModule } from '@angular/cdk/drag-drop'; import * as i5$1 from '@angular/cdk/scrolling'; import * as i8 from '@angular/cdk/overlay'; import { ConnectionPositionPair, OverlayModule } from '@angular/cdk/overlay'; import * as i5$2 from '@angular/cdk/a11y'; import { A11yModule } from '@angular/cdk/a11y'; import * as i8$1 from '@swimlane/ngx-datatable'; import { NgxDatatableModule } from '@swimlane/ngx-datatable'; import * as i1$2 from '@ngrx/effects'; import { createEffect, ofType, EffectsModule } from '@ngrx/effects'; var ResponseType; (function (ResponseType) { ResponseType["SUCCESS"] = "SUCCESS"; ResponseType["FAILURE"] = "FAILURE"; ResponseType["UNSUPPORTED"] = "UNSUPPORTED"; })(ResponseType || (ResponseType = {})); class ViewerException { constructor(exceptionType, detail) { this.exceptionType = exceptionType; this.detail = detail; } } const SET_DOCUMENT_ID = '[Document] Set Document Id'; const POSITION_UPDATED = '[Document] Position Updated'; const ADD_PAGES = '[Document] Add Pages'; const CONVERT = '[Document] Convert'; const CONVERT_SUCCESS = '[Document] Convert Success'; const CONVERT_FAIL = '[Document] Convert Fail'; const CLEAR_CONVERT_DOC_URL = '[Document] Clear Convert Doc Url'; const LOAD_ROTATION = '[Document] Load Rotation'; const LOAD_ROTATION_SUCCESS = '[Document] Load Rotation Success'; const LOAD_ROTATION_FAIL = '[Document] Load Rotation Fail'; const SAVE_ROTATION = '[Document] Save Rotation'; const SAVE_ROTATION_SUCCESS = '[Document] Save Rotation Success'; const SAVE_ROTATION_FAIL = '[Document] Save Rotation Fail'; class SetDocumentId { constructor(payload) { this.payload = payload; this.type = SET_DOCUMENT_ID; } } class AddPages { constructor(payload) { this.payload = payload; this.type = ADD_PAGES; } } class PdfPositionUpdate { constructor(payload) { this.payload = payload; this.type = POSITION_UPDATED; } } class Convert { constructor(payload) { this.payload = payload; this.type = CONVERT; } } class ConvertSuccess { constructor(payload) { this.payload = payload; this.type = CONVERT_SUCCESS; } } class ConvertFailure { constructor(payload) { this.payload = payload; this.type = CONVERT_FAIL; } } class ClearConvertDocUrl { constructor() { this.type = CLEAR_CONVERT_DOC_URL; } } class LoadRotation { constructor(payload) { this.payload = payload; this.type = LOAD_ROTATION; } } class LoadRotationSuccess { constructor(payload) { this.payload = payload; this.type = LOAD_ROTATION_SUCCESS; } } class LoadRotationFailure { constructor(payload) { this.payload = payload; this.type = LOAD_ROTATION_FAIL; } } class SaveRotation { constructor(payload) { this.payload = payload; this.type = SAVE_ROTATION; } } class SaveRotationSuccess { constructor(payload) { this.payload = payload; this.type = SAVE_ROTATION_SUCCESS; } } class SaveRotationFailure { constructor(payload) { this.payload = payload; this.type = SAVE_ROTATION_FAIL; } } const UPDATE_TAGS = '[Tags] Update Tags'; const ADD_FILTER_TAGS = '[Tags] Add Filter Tags'; const CLEAR_FILTER_TAGS = '[Tags] Clear Filter Tags'; class UpdateTags { constructor(payload) { this.payload = payload; this.type = UPDATE_TAGS; } } class AddFilterTags { constructor(payload) { this.payload = payload; this.type = ADD_FILTER_TAGS; } } class ClearFilterTags { constructor() { this.type = CLEAR_FILTER_TAGS; } } const SET_CASE_ID = '[Icp] Set Case Id'; const LOAD_ICP_SESSION = '[Icp] Load Session'; const LOAD_ICP_SESSION_FAIL = '[Icp] Load Session Failure'; const JOIN_ICP_SOCKET_SESSION = '[Icp] Join Socket Session'; const ICP_SOCKET_SESSION_JOINED = '[Icp] Socket Session Joined'; const LEAVE_ICP_SOCKET_SESSION = '[Icp] Leave Socket Session'; const ICP_PRESENTER_UPDATED = '[Icp] Presenter Updated'; const ICP_PARTICIPANT_LIST_UPDATED = '[Icp] Participant List Updated'; class SetCaseId { constructor(payload) { this.payload = payload; this.type = SET_CASE_ID; } } class LoadIcpSession { constructor(payload) { this.payload = payload; this.type = LOAD_ICP_SESSION; } } class LoadIcpSessionFailure { constructor(payload) { this.payload = payload; this.type = LOAD_ICP_SESSION_FAIL; } } class JoinIcpSocketSession { constructor(payload) { this.payload = payload; this.type = JOIN_ICP_SOCKET_SESSION; } } class IcpSocketSessionJoined { constructor(payload) { this.payload = payload; this.type = ICP_SOCKET_SESSION_JOINED; } } class LeaveIcpSocketSession { constructor() { this.type = LEAVE_ICP_SOCKET_SESSION; } } class IcpPresenterUpdated { constructor(payload) { this.payload = payload; this.type = ICP_PRESENTER_UPDATED; } } class IcpParticipantListUpdated { constructor(payload) { this.payload = payload; this.type = ICP_PARTICIPANT_LIST_UPDATED; } } const initialDocumentState = { convertedDocument: undefined, documentId: undefined, pdfPosition: undefined, pages: {}, hasDifferentPageSize: false, rotation: undefined, rotationLoaded: false, loading: false, loaded: false }; function docReducer(state = initialDocumentState, action) { switch (action.type) { case CONVERT_SUCCESS: { const convertedDocument = { url: action.payload, error: undefined }; return { ...state, convertedDocument }; } case CONVERT_FAIL: { const convertedDocument = { url: undefined, error: action.payload }; return { ...state, convertedDocument }; } case CLEAR_CONVERT_DOC_URL: { const convertedDocument = undefined; return { ...state, convertedDocument }; } case LOAD_ROTATION: { return { ...state, rotationLoaded: false }; } case LOAD_ROTATION_SUCCESS: { const metadata = action.payload; const rotation = metadata ? metadata.rotationAngle : 0; return { ...state, rotation, rotationLoaded: true }; } case LOAD_ROTATION_FAIL: { return { ...state, rotation: 0, rotationLoaded: true }; } case SAVE_ROTATION_SUCCESS: { const metadata = action.payload; const rotation = metadata.rotationAngle; return { ...state, rotation }; } case SET_DOCUMENT_ID: { return { ...state, documentId: action.payload }; } case ADD_PAGES: { const payload = action.payload; let pages = {}; let pageHeight; let pageWidth; let hasDifferentPageSize = state.hasDifferentPageSize; const pageNumberInput = document.getElementById('pageNumber'); const pageIndex = pageNumberInput?.value ? parseInt(pageNumberInput.value, 10) - 1 : 0; const loadedPage = payload[pageIndex]?.div['attributes']?.style?.value ?? ''; payload.forEach(page => { const sizingValue = page.div?.['attributes']?.style?.value ?? ''; const widthMatch = sizingValue.match(/width:\s*round\(down,\s*var\(--scale-factor\)\s*\*\s*([\d.]+)([a-z%]+)?,.*var\(--scale-round-x, ([\d.]+)([a-z%]+)?\)\)/); const heightMatch = sizingValue.match(/height:\s*round\(down,\s*var\(--scale-factor\)\s*\*\s*([\d.]+)([a-z%]+)?,.*var\(--scale-round-y, ([\d.]+)([a-z%]+)?\)\)/); const scaleRoundXMatch = loadedPage.match(/--scale-round-x:\s*([\d.]+)([a-z%]+)?/); const scaleRoundYMatch = loadedPage.match(/--scale-round-y:\s*([\d.]+)([a-z%]+)?/); // You can now use widthUnit, heightUnit, scaleRoundXUnit, scaleRoundYUnit as needed const scaleFactor = page.viewportScale ?? 1; const scaleRoundX = scaleRoundXMatch ? parseFloat(scaleRoundXMatch[1]) : 1; const scaleRoundY = scaleRoundYMatch ? parseFloat(scaleRoundYMatch[1]) : 1; const baseWidth = widthMatch ? parseFloat(widthMatch[1]) : undefined; const baseHeight = heightMatch ? parseFloat(heightMatch[1]) : undefined; function roundDown(value, step) { return Math.floor(value / step) * step; } const computedWidth = baseWidth !== undefined ? roundDown(scaleFactor * baseWidth, scaleRoundX) : page.div['clientWidth']; const computedHeight = baseHeight !== undefined ? roundDown(scaleFactor * baseHeight, scaleRoundY) : page.div['clientHeight']; if (!hasDifferentPageSize && pageHeight && pageWidth && (pageHeight !== computedHeight || pageWidth !== computedWidth)) { hasDifferentPageSize = true; } else { pageHeight = computedHeight; pageWidth = computedWidth; } const styles = { left: page.div['offsetLeft'], height: computedHeight, width: computedWidth }; const scaleRotation = { scale: page.scale, rotation: page.rotation }; const p = { styles, scaleRotation, viewportScale: page.viewportScale }; pages = { ...pages, [page.id]: p }; }); return { ...state, pages, hasDifferentPageSize }; } case POSITION_UPDATED: { const pdfPosition = action.payload; return { ...state, pdfPosition }; } } return state; } const getDocPages = (state) => state.pages; const getDocId = (state) => state.documentId; const getPdfPos = (state) => state.pdfPosition; const getHasDifferentPageSizes = (state) => state.hasDifferentPageSize; const getRotation$1 = (state) => state.rotation; const rotationLoaded$1 = (state) => state.rotationLoaded; const getConvertedDocument$1 = (state) => state.convertedDocument; const LOAD_ANNOTATION_SET = '[Annotations] Load Annotation Set'; const LOAD_ANNOTATION_SET_SUCCESS = '[Annotations] Load Annotation Set Success'; const LOAD_ANNOTATION_SET_FAIL = '[Annotations] Load Annotation Set Fail'; const SAVE_ANNOTATION_SET = '[Annotations] Save Annotation Set'; const SAVE_ANNOTATION_SET_SUCCESS = '[Annotations] Save Annotation Set Success'; const SAVE_ANNOTATION_SET_FAIL = '[Annotations] Save Annotation Set Fail'; const SAVE_ANNOTATION = '[Annotations] Save Annotation'; const SAVE_ANNOTATION_SUCCESS = '[Annotations] Save Annotation Success'; const SAVE_ANNOTATION_FAIL = '[Annotations] Save Annotation Fail'; const ADD_OR_EDIT_COMMENT = '[Annotations] Add or Edit Comment'; const DELETE_ANNOTATION = '[Annotations] Delete Annotation'; const DELETE_ANNOTATION_SUCCESS = '[Annotations] Delete Annotation Success'; const DELETE_ANNOTATION_FAIL = '[Annotations] Delete Annotation Fail'; const SELECT_ANNOTATION = '[Annotations] Select Annotation'; const SEARCH_COMMENT = '[Comments] Search Comments'; const APPLY_COMMENT_SUMMARY_FILTER = '[Comments] Apply Comment Summary Filter'; const CLEAR_COMMENT_SUMMARY_FILTER = '[Comments] Clear Comment Summary Filter'; class LoadAnnotationSet { constructor(payload) { this.payload = payload; this.type = LOAD_ANNOTATION_SET; } } class SaveAnnotationSet { constructor(payload) { this.payload = payload; this.type = SAVE_ANNOTATION_SET; } } class LoadAnnotationSetSucess { constructor(payload) { this.payload = payload; this.type = LOAD_ANNOTATION_SET_SUCCESS; } } class SaveAnnotationSetSuccess { constructor(payload) { this.payload = payload; this.type = SAVE_ANNOTATION_SET_SUCCESS; } } class LoadAnnotationSetFail { constructor(payload) { this.payload = payload; this.type = LOAD_ANNOTATION_SET_FAIL; } } class SaveAnnotationSetFail { constructor(payload) { this.payload = payload; this.type = SAVE_ANNOTATION_SET_FAIL; } } class SaveAnnotation { constructor(payload) { this.payload = payload; this.type = SAVE_ANNOTATION; } } class SaveAnnotationSuccess { constructor(payload) { this.payload = payload; this.type = SAVE_ANNOTATION_SUCCESS; } } class SaveAnnotationFail { constructor(payload) { this.payload = payload; this.type = SAVE_ANNOTATION_FAIL; } } class AddOrEditComment { constructor(payload) { this.payload = payload; this.type = ADD_OR_EDIT_COMMENT; } } class DeleteAnnotation { constructor(payload) { this.payload = payload; this.type = DELETE_ANNOTATION; } } class DeleteAnnotationSuccess { constructor(payload) { this.payload = payload; this.type = DELETE_ANNOTATION_SUCCESS; } } class DeleteAnnotationFail { constructor(payload) { this.payload = payload; this.type = DELETE_ANNOTATION_FAIL; } } class SelectedAnnotation { constructor(payload) { this.payload = payload; this.type = SELECT_ANNOTATION; } } class SearchComment { constructor(payload) { this.payload = payload; this.type = SEARCH_COMMENT; } } class ApplyCommentSymmaryFilter { constructor(payload) { this.payload = payload; this.type = APPLY_COMMENT_SUMMARY_FILTER; } } class ClearCommentSummaryFilters { constructor() { this.type = CLEAR_COMMENT_SUMMARY_FILTER; } } /* @dynamic marking class as dynamic to stop compiler throwing error for lambda in static function see https://github.com/angular/angular/issues/19698#issuecomment-338340211 */ class StoreUtils { static groupByKeyEntities(annotations, key) { return annotations.reduce((h, obj) => Object.assign(h, { [obj[key]]: (h[obj[key]] || []).concat(obj) }), {}); } static generateCommentsEntities(annotations) { return annotations.reduce((commentEntities, annotation) => { if (annotation.comments.length) { const comment = { ...annotation.comments[0] || '', tags: [...annotation.tags || []] }; return { ...commentEntities, [annotation.id]: comment }; } return { ...commentEntities }; }, {}); } static genTagNameEntities(annotations) { const filterAnnoWithoutCommentsTags = annotations.filter(a => (a.comments.length && a.tags.length)); const allTags = filterAnnoWithoutCommentsTags.map(anno => this.groupByKeyEntities(anno.tags, 'name')); const groupedByName = allTags.reduce((tagEntitiy, tagItem) => { return { ...tagEntitiy, ...tagItem }; }, {}); return this.genNameEnt(annotations, groupedByName); } static genNameEnt(annos, groupedByName) { return Object.keys(groupedByName).reduce((tagNameEnt, key) => { const readyAnno = annos.filter(anno => anno.tags.find(tag => tag.name === key)) .map(anno => anno.id) .reduce((obj, anno) => ({ ...obj, [anno]: anno }), {}); return { ...tagNameEnt, [key]: readyAnno }; }, {}); } static generateAnnotationEntities(anno) { return anno.reduce((annoEntities, annotation) => { const annot = { ...annotation, positionTop: annotation.rectangles[0].y // todo remove this }; return { ...annoEntities, [annotation.id]: annot }; }, {}); } static generateRedactionEntities(redactions) { return redactions.reduce((redactEntities, redaction) => { return { ...redactEntities, [redaction.redactionId]: redaction }; }, {}); } static resetCommentEntSelect(ent) { return Object.keys(ent).reduce((object, key) => { object[key] = { ...ent[key], editable: false, selected: false }; return object; }, {}); } static filterCommentsSummary(comments, filters) { if (Object.keys(filters).length) { const tagFilterApplied = Object.keys(filters.tagFilters) .filter(key => filters.tagFilters[key] === true).length; const dateFilterApplied = (filters.dateRangeFrom || filters.dateRangeTo); const filteredComments = comments.filter(comment => { let hasTagFilter = false; let hasDateFilter = false; // check tags if (filters.hasOwnProperty('tagFilters')) { Object.keys(filters.tagFilters).forEach(filter => { const label = filters.tagFilters[filter]; if (label) { return comment.tags.forEach(tag => { if (tag.name === filter && !hasTagFilter) { hasTagFilter = true; } }); } }); } // check for dates if (dateFilterApplied) { const commentDate = moment(comment.lastModifiedDate); const dateFrom = filters.dateRangeFrom !== null ? moment(filters.dateRangeFrom) : undefined; const dateTo = filters.dateRangeTo !== null ? moment(filters.dateRangeTo) : undefined; if (dateTo && dateFrom) { if (commentDate > dateFrom && commentDate < dateTo) { hasDateFilter = true; } } if (dateTo && !dateFrom) { if (commentDate <= dateTo) { hasDateFilter = true; } } if (dateFrom && !dateTo) { if (commentDate > dateFrom) { hasDateFilter = true; } } } return (hasTagFilter || hasDateFilter); }); return (tagFilterApplied || dateFilterApplied) ? filteredComments : comments; } else { return comments; } } } const initialState = { annotationSet: {}, annotationEntities: {}, commentEntities: {}, annotationPageEntities: {}, selectedAnnotation: null, commentSearchQueries: { commentSearch: '' }, commentSummaryFilters: { hasFilter: false, filters: {} }, loading: false, loaded: false, }; function reducer(state = initialState, action) { switch (action.type) { case LOAD_ANNOTATION_SET: { const annotationSet = { ...state.annotationSet, documentId: action.payload }; return { ...initialState, annotationSet, loading: true }; } case LOAD_ANNOTATION_SET_SUCCESS: case LOAD_ANNOTATION_SET_FAIL: { const annotationSet = action.payload.status === 200 ? action.payload.body : { ...state.annotationSet, annotations: [], id: v4() }; const annotationEntities = StoreUtils.generateAnnotationEntities(annotationSet.annotations); const annotationPageEntities = StoreUtils.groupByKeyEntities(annotationSet.annotations, 'page'); const commentEntities = StoreUtils.generateCommentsEntities(annotationSet.annotations); return { ...state, annotationSet, annotationEntities, annotationPageEntities, commentEntities, loading: false, loaded: true }; } case SAVE_ANNOTATION_SET_SUCCESS: { const anno = action.payload.annotations; const annEntities = { ...state.annotationEntities, ...anno }; const annotArray = Object.keys(annEntities).map(key => annEntities[key]); const annotationEntities = StoreUtils.generateAnnotationEntities(annotArray); const annotationPageEntities = StoreUtils.groupByKeyEntities(annotArray, 'page'); const commentEntities = StoreUtils.generateCommentsEntities(annotArray); const selectedAnnotation = { ...state.selectedAnnotation, ...anno, editable: false }; return { ...state, annotationEntities, annotationPageEntities, commentEntities, selectedAnnotation, loading: false, loaded: true }; } case SAVE_ANNOTATION_SUCCESS: { const anno = action.payload; const annEntities = { ...state.annotationEntities, [anno.id]: anno }; const annotArray = Object.keys(annEntities).map(key => annEntities[key]); const annotationEntities = StoreUtils.generateAnnotationEntities(annotArray); const annotationPageEntities = StoreUtils.groupByKeyEntities(annotArray, 'page'); const commentEntities = StoreUtils.generateCommentsEntities(annotArray); const selectedAnnotation = { ...state.selectedAnnotation, annotationId: anno.id, editable: false }; return { ...state, annotationEntities, annotationPageEntities, commentEntities, selectedAnnotation, loading: false, loaded: true }; } case DELETE_ANNOTATION_SUCCESS: { const id = action.payload; const page = state.annotationEntities[id].page; const annotationEntities = { ...state.annotationEntities }; delete annotationEntities[id]; const pageAnnotationsRemoved = [ ...state.annotationPageEntities[page].filter(anno => anno.id !== id) ]; const annotationPageEntities = { ...state.annotationPageEntities, [page]: pageAnnotationsRemoved }; const commentEntities = { ...state.commentEntities }; if (state.commentEntities[id]) { delete commentEntities[id]; } return { ...state, annotationEntities, annotationPageEntities, commentEntities }; } case ADD_OR_EDIT_COMMENT: { const comment = { [action.payload.annotationId]: action.payload }; const comments = { ...state.commentEntities, ...comment }; return { ...state, commentEntities: comments }; } case SELECT_ANNOTATION: { const payload = action.payload; const commentEntity = { ...state.commentEntities[payload.annotationId], editable: payload.editable, selected: payload.selected }; const resetCommentEntSelect = StoreUtils.resetCommentEntSelect({ ...state.commentEntities }); const commentEntities = payload.annotationId && state.commentEntities[payload.annotationId] ? { ...resetCommentEntSelect, [payload.annotationId]: commentEntity } : { ...resetCommentEntSelect }; return { ...state, commentEntities, selectedAnnotation: action.payload }; } case SEARCH_COMMENT: { const commentSearchQueries = { ...state.commentSearchQueries, commentSearch: action.payload }; const commentEntities = StoreUtils.resetCommentEntSelect({ ...state.commentEntities }); return { ...state, commentEntities, commentSearchQueries }; } case APPLY_COMMENT_SUMMARY_FILTER: { const payload = action.payload; const hasTagFilter = () => { let isFiltered = false; if (payload.tagFilters) { Object.keys(payload.tagFilters).map(filter => { if (payload.tagFilters[filter] && !isFiltered) { isFiltered = true; } }); } return isFiltered; }; const hasFilter = (hasTagFilter() || !!payload.dateRangeFrom || !!payload.dateRangeTo); const commentSummaryFilters = { hasFilter, filters: payload }; return { ...state, commentSummaryFilters: commentSummaryFilters }; } case CLEAR_COMMENT_SUMMARY_FILTER: { return { ...state, commentSummaryFilters: { ...initialState.commentSummaryFilters } }; } } return state; } const getAnnoSet = (state) => state.annotationSet; const getCommentEnts = (state) => state.commentEntities; const getAnnoPageEnt = (state) => state.annotationPageEntities; const getAnnoEnt = (state) => state.annotationEntities; const getSelectedAnno = (state) => state.selectedAnnotation; const commentSearchQ = (state) => state.commentSearchQueries; const getSummaryFilters = (state) => state.commentSummaryFilters; const initialTagState = { tagNameEnt: {}, annotations: [], filteredPageEntities: {}, filteredComments: {}, formFilterState: {}, filters: [] }; function tagsReducer(state = initialTagState, action) { switch (action.type) { case LOAD_ANNOTATION_SET: { return { ...state, ...initialTagState }; } case LOAD_ANNOTATION_SET_SUCCESS: { const annotations = action.payload.body.annotations; const tagNameEnt = StoreUtils.genTagNameEntities(annotations); return { ...state, tagNameEnt, annotations }; } case SAVE_ANNOTATION_SUCCESS: { const payload = action.payload; const anno = [...state.annotations].filter(a => a.id !== payload.id) || []; const annotations = [...anno, payload]; const tagNameEnt = StoreUtils.genTagNameEntities(annotations); return { ...state, annotations, tagNameEnt }; } case DELETE_ANNOTATION_SUCCESS: { const id = action.payload; const annotations = [...state.annotations].filter(a => a.id !== id); const tagNameEnt = StoreUtils.genTagNameEntities(annotations); const filteredPageEntities = StoreUtils.groupByKeyEntities(annotations, 'page'); const filteredComments = { ...state.filteredComments }; delete filteredComments[id]; return { ...state, annotations, tagNameEnt, filteredComments, filteredPageEntities, filters: [] }; } case ADD_FILTER_TAGS: { const formFilterState = action.payload; const filters = Object.keys(formFilterState).reduce((arr, key) => { return formFilterState[key] ? [...arr, key] : arr; }, []); const filteredComments = filters.reduce((obj, f) => { return { ...obj, ...state.tagNameEnt[f] }; }, {}); const annotations = Object.keys(filteredComments).map(key => state.annotations.filter(a => a.id === key)[0]); const filteredPageEntities = StoreUtils.groupByKeyEntities(annotations, 'page'); return { ...state, filters, filteredComments, filteredPageEntities, }; } case CLEAR_FILTER_TAGS: { return { ...state, filters: [], filteredComments: {}, filteredPageEntities: {}, }; } } return state; } const getTagNameEnt = (state) => state.tagNameEnt; const getFilters = (state) => state.filters; const getFilteredComments = (state) => state.filteredComments; const getFilteredPageEnt = (state) => state.filteredPageEntities; const LOAD_BOOKMARKS = '[Bookmarks] Load Bookmarks'; const LOAD_BOOKMARKS_SUCCESS = '[Bookmarks] Load Bookmarks Success'; const LOAD_BOOKMARKS_FAIL = '[Bookmarks] Load Bookmarks Failure'; const CREATE_BOOKMARK = '[Bookmarks] Create Bookmark'; const CREATE_BOOKMARK_SUCCESS = '[Bookmarks] Create Bookmark Success'; const CREATE_BOOKMARK_FAIL = '[Bookmarks] Create Bookmark Failure'; const DELETE_BOOKMARK = '[Bookmarks] Delete Bookmark'; const DELETE_BOOKMARK_SUCCESS = '[Bookmarks] Delete Bookmark Success'; const DELETE_BOOKMARK_FAIL = '[Bookmarks] Delete Bookmark Failure'; const MOVE_BOOKMARK = '[Bookmarks] Move Bookmark'; const MOVE_BOOKMARK_SUCCESS = '[Bookmarks] Move Bookmark Success'; const MOVE_BOOKMARK_FAIL = '[Bookmarks] Move Bookmark Failure'; const UPDATE_BOOKMARK = '[Bookmarks] Update Bookmark'; const UPDATE_BOOKMARK_SUCCESS = '[Bookmarks] Update Bookmark Success'; const UPDATE_BOOKMARK_FAIL = '[Bookmarks] Update Bookmark Failure'; const UPDATE_BOOKMARK_SCROLL_TOP = '[Bookmarks] Update Bookmark Scroll Top'; class LoadBookmarks { constructor() { this.type = LOAD_BOOKMARKS; } } class LoadBookmarksSuccess { constructor(payload) { this.payload = payload; this.type = LOAD_BOOKMARKS_SUCCESS; } } class LoadBookmarksFailure { constructor(payload) { this.payload = payload; this.type = LOAD_BOOKMARKS_FAIL; } } class CreateBookmark { constructor(payload) { this.payload = payload; this.type = CREATE_BOOKMARK; } } class CreateBookmarkSuccess { constructor(payload) { this.payload = payload; this.type = CREATE_BOOKMARK_SUCCESS; } } class CreateBookmarkFailure { constructor(payload) { this.payload = payload; this.type = CREATE_BOOKMARK_FAIL; } } class DeleteBookmark { constructor(payload) { this.payload = payload; this.type = DELETE_BOOKMARK; } } class DeleteBookmarkSuccess { constructor(payload) { this.payload = payload; this.type = DELETE_BOOKMARK_SUCCESS; } } class DeleteBookmarkFailure { constructor(payload) { this.payload = payload; this.type = DELETE_BOOKMARK_FAIL; } } class MoveBookmark { constructor(payload) { this.payload = payload; this.type = MOVE_BOOKMARK; } } class MoveBookmarkSuccess { constructor(payload) { this.payload = payload; this.type = MOVE_BOOKMARK_SUCCESS; } } class MoveBookmarkFailure { constructor(payload) { this.payload = payload; this.type = MOVE_BOOKMARK_FAIL; } } class UpdateBookmark { constructor(payload) { this.payload = payload; this.type = UPDATE_BOOKMARK; } } class UpdateBookmarkSuccess { constructor(payload) { this.payload = payload; this.type = UPDATE_BOOKMARK_SUCCESS; } } class UpdateBookmarkFailure { constructor(payload) { this.payload = payload; this.type = UPDATE_BOOKMARK_FAIL; } } class UpdateBookmarkScrollTop { constructor(payload) { this.payload = payload; this.type = UPDATE_BOOKMARK_SCROLL_TOP; } } const getBookmarkChildren = (bookmarks) => { if (bookmarks) { return bookmarks.reduce((childIds, bookmark) => { if (bookmark.children && bookmark.children.length > 0) { return [...childIds, bookmark.id, ...getBookmarkChildren(bookmark.children)]; } return [...childIds, bookmark.id]; }, []); } else { return []; } }; const generateBookmarkEntities = (bookmarks) => { return bookmarks.reduce((bookmarkEntities, bookmark) => Object.assign(bookmarkEntities, { [bookmark.id]: bookmark }), {}); }; const indexEntities = (entities) => { const entityIds = Object.keys(entities); for (let index = 0; entityIds.length > 0; index++) { let keysToRemove = []; entityIds.forEach(key => { if (!entities[key].previous || !entityIds.includes(entities[key].previous.toString())) { entities[key].index = index; keysToRemove.push(key); } }); keysToRemove.forEach(key => entityIds.splice(entityIds.indexOf(key), 1)); keysToRemove = []; } }; const generateBookmarkNodes = (entities) => { const bookmarkEntities = JSON.parse(JSON.stringify(entities)); indexEntities(bookmarkEntities); return Object.keys(bookmarkEntities).reduce((nodes, bookmarkId) => { const bookmarkEntity = bookmarkEntities[bookmarkId]; if (bookmarkEntity.parent) { const parentEntity = bookmarkEntities[bookmarkEntity.parent]; if (!parentEntity.children) { parentEntity.children = []; } parentEntity.children[bookmarkEntity.index] = bookmarkEntity; } else { nodes[bookmarkEntity.index] = bookmarkEntity; } return nodes; }, []); }; const initialBookmarksState = { bookmarks: [], bookmarkEntities: {}, bookmarkPageEntities: {}, editableBookmark: undefined, loaded: false, loading: false, scrollTop: null, }; function bookmarksReducer(state = initialBookmarksState, action) { switch (action.type) { case LOAD_BOOKMARKS: { return { ...state, loading: true }; } case LOAD_BOOKMARKS_SUCCESS: case LOAD_BOOKMARKS_FAIL: { const bookmarks = action.payload.status === 200 ? action.payload.body : []; const bookmarkEntities = generateBookmarkEntities(bookmarks); const bookmarkPageEntities = StoreUtils.groupByKeyEntities(bookmarks, 'pageNumber'); return { ...state, bookmarks, bookmarkEntities, bookmarkPageEntities, loaded: true }; } case CREATE_BOOKMARK_SUCCESS: { const bookmark = action.payload; const bookmarkEntities = { ...state.bookmarkEntities, [bookmark.id]: bookmark, }; const bookmarkArray = Object.keys(bookmarkEntities).map(key => bookmarkEntities[key]); const bookmarkPageEntities = StoreUtils.groupByKeyEntities(bookmarkArray, 'pageNumber'); const editableBookmark = bookmark.id; return { ...state, bookmarkEntities, editableBookmark, bookmarkPageEntities, loading: false, loaded: true }; } case MOVE_BOOKMARK_SUCCESS: { const movedBookmarks = generateBookmarkEntities(action.payload); const bookmarkEntities = { ...state.bookmarkEntities, ...movedBookmarks }; return { ...state, bookmarkEntities, loading: false, loaded: true }; } case DELETE_BOOKMARK_SUCCESS: { const bookmarkIds = action.payload; const bookmarkEntities = { ...state.bookmarkEntities }; const bookmarkPageEntities = { ...state.bookmarkPageEntities }; const removeBookmarksByPage = {}; bookmarkIds.forEach(bookmarkId => { if (removeBookmarksByPage[bookmarkEntities[bookmarkId].pageNumber] !== undefined && removeBookmarksByPage[bookmarkEntities[bookmarkId].pageNumber].length > 0) { removeBookmarksByPage[bookmarkEntities[bookmarkId].pageNumber].push(bookmarkId); } else { removeBookmarksByPage[bookmarkEntities[bookmarkId].pageNumber] = [bookmarkId]; } delete bookmarkEntities[bookmarkId]; }); Object.entries(removeBookmarksByPage).forEach(([pageNumber, bmrkIds]) => { bookmarkPageEntities[pageNumber] = bookmarkPageEntities[pageNumber].filter(bookmark => !bmrkIds.includes(bookmark.id)); }); return { ...state, bookmarkEntities, bookmarkPageEntities, loading: false, loaded: true }; } case UPDATE_BOOKMARK_SUCCESS: { const bookmark = action.payload; const bookmarkEntities = { ...state.bookmarkEntities, [bookmark.id]: { ...bookmark } }; const bookmarkArray = Object.keys(bookmarkEntities).map(key => bookmarkEntities[key]); const bookmarkPageEntities = StoreUtils.groupByKeyEntities(bookmarkArray, 'pageNumber'); const editableBookmark = undefined; return { ...state, bookmarkEntities, editableBookmark, bookmarkPageEntities, loading: false, loaded: true }; } case UPDATE_BOOKMARK_SCROLL_TOP: { const scrollTop = action.payload; return { ...state, scrollTop: scrollTop }; } } return state; } const getBookmarks = (state) => state.bookmarks; const getBookmarkEnts = (state) => state.bookmarkEntities; const getBookmarkPageEnt = (state) => state.bookmarkPageEntities; const getEditBookmark = (state) => state.editableBookmark; const getScrollTop$1 = (state) => state.scrollTop; const LOAD_REDACTIONS = '[Redaction] Load Redaction'; const LOAD_REDACTION_SUCCESS = '[Redaction] Load Redaction Success'; const LOAD_REDACTION_FAIL = '[Redaction] Load Redaction Fail'; const SAVE_REDACTION = '[Redaction] Save Redaction'; const SAVE_REDACTION_SUCCESS = '[Redaction] Save Redaction Success'; const SAVE_REDACTION_FAIL = '[Redaction] Save Redaction Fail'; const SAVE_BULK_REDACTION = '[Redaction] Save bulk Redaction'; const SAVE_BULK_REDACTION_SUCCESS = '[Redaction] Save bulk Redaction Success'; const SAVE_BULK_REDACTION_FAIL = '[Redaction] Save bulk Redaction Fail'; const DELETE_REDACTION = '[Redaction] Delete Redaction'; const DELETE_REDACTION_SUCCESS = '[Redaction] Delete Redaction Success'; const DELETE_REDACTION_FAIL = '[Redaction] Delete Redaction Fail'; const SELECT_REDACTION = '[Redaction] Select Redaction'; const REDACT = '[Redaction] Redact'; const REDACT_SUCCESS = '[Redaction] Redact Success'; const REDACT_FAIL = '[Redaction] Redact Fail'; const RESET_REDACTED_DOCUMENT = '[Redaction] Reset Redacted Document'; const UNMARK_ALL = '[Redaction] Unmark All'; const UNMARK_ALL_SUCCESS = '[Redaction] Unmark All Success'; class LoadRedactions { constructor(payload) { this.payload = payload; this.type = LOAD_REDACTIONS; } } class LoadRedactionSuccess { constructor(payload) { this.payload = payload; this.type = LOAD_REDACTION_SUCCESS; } } class LoadRedactionFailure { constructor(payload) { this.payload = payload; this.type = LOAD_REDACTION_FAIL; } } class SaveRedaction { constructor(payload) { this.payload = payload; this.type = SAVE_REDACTION; } } class SaveRedactionSuccess { constructor(payload) { this.payload = payload; this.type = SAVE_REDACTION_SUCCESS; } } class SaveRedactionFailure { constructor(payload) { this.payload = payload; this.type = SAVE_REDACTION_FAIL; } } class SaveBulkRedactionFailure { constructor(payload) { this.payload = payload; this.type = SAVE_BULK_REDACTION_FAIL; } } class SaveBulkRedaction { constructor(payload) { this.payload = payload; this.type = SAVE_BULK_REDACTION; } } class SaveBulkRedactionSuccess { constructor(payload) { this.payload = payload; this.type = SAVE_BULK_REDACTION_SUCCESS; } } class DeleteRedaction { constructor(payload) { this.payload = payload; this.type = DELETE_REDACTION; } } class DeleteRedactionSuccess { constructor(payload) { this.payload = payload; this.type = DELETE_REDACTION_SUCCESS; } } class DeleteRedactionFailure { constructor(payload) { this.payload = payload; this.type = DELETE_REDACTION_FAIL; } } class SelectRedaction { constructor(payload) { this.payload = payload; this.type = SELECT_REDACTION; } } class Redact { constructor(payload) { this.payload = payload; this.type = REDACT; } } class RedactSuccess { constructor(payload) { this.payload = payload; this.type = REDACT_SUCCESS; } } class RedactFailure { constructor(payload) { this.payload = payload; this.type = REDACT_FAIL; } } class ResetRedactedDocument { constructor() { this.type = RESET_REDACTED_DOCUMENT; } } class UnmarkAll { constructor(payload) { this.payload = payload; this.type = UNMARK_ALL; } } class UnmarkAllSuccess { constructor() { this.type = UNMARK_ALL_SUCCESS; } } const initialRedactionState = { redactionEntities: {}, redactionPageEntities: {}, selectedRedaction: {}, redactedDocumentInfo: undefined, documentId: undefined }; function redactionReducer(state = initialRedactionState, action) { switch (action.type) { case LOAD_REDACTIONS: { return { ...state, ...initialRedactionState }; } case LOAD_REDACTION_SUCCESS: { const payload = action.payload; if (payload) { const redactionEntities = StoreUtils.generateRedactionEntities(payload); const redactionPageEntities = StoreUtils.groupByKeyEntities(payload, 'page'); return { ...state, redactionEntities, redactionPageEntities }; } return { ...state }; } case SAVE_REDACTION_SUCCESS: { const { payload } = action; const redactionEntities = { ...state.redactionEntities, [payload.redactionId]: payload }; const redactionArray = Object.keys(redactionEntities).map(key => redactionEntities[key]); const redactionPageEntities = StoreUtils.groupByKeyEntities(redactionArray, 'page'); return { ...state, redactionEntities, redactionPageEntities }; } case SAVE_BULK_REDACTION_SUCCESS: { const payloadResult = Object.assign({}, ...action.payload.searchRedactions.map((x) => ({ [x.redactionId]: x }))); const redactionEntities = { ...state.redactionEntities, ...payloadResult }; const redactionArray = Object.keys(redactionEntities).map(key => redactionEntities[key]); const redactionPageEntities = StoreUtils.groupByKeyEntities(redactionArray, 'page'); return { ...state, redactionEntities, redactionPageEntities }; } case SELECT_REDACTION: case SELECT_ANNOTATION: { return { ...state, selectedRedaction: action.payload }; } case DELETE_REDACTION_SUCCESS: { const page = action.payload.page; const id = action.payload.redactionId; const redactionEntities = { ...state.redactionEntities }; delete redactionEntities[id]; const pageRedactionRemoved = [ ...state.redactionPageEntities[page].filter(redaction => redaction.redactionId !== id) ]; const redactionPageEntities = { ...state.redactionPageEntities, [page]: pageRedactionRemoved }; return { ...state, redactionPageEntities, redactionEntities, }; } case REDACT_SUCCESS: { const redactedDocumentInfo = action.payload; return { ...state, ...initialRedactionState, redactedDocumentInfo }; } case RESET_REDACTED_DOCUMENT: { return { ...state, redactedDocumentInfo: undefined }; } case UNMARK_ALL_SUCCESS: { return { ...state, ...initialRedactionState }; } } return state; } const getRedactionEnt$1 = (state) => state.redactionEntities; const getPageEnt = (state) => state.redactionPageEntities; const getSelectedRedaction = (state) => state.selectedRedaction; const getRedactedDocInfo = (state) => state.redactedDocumentInfo; const initialIcpSessionState = { session: null, presenter: null, client: null, participants: [] }; function icpReducer(state = initialIcpSessionState, action) { switch (action.type) { case SET_CASE_ID: { const caseId = action.payload; const session = { ...state.sess