diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/comments/comments.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/comments/comments.component.ts index 203e834a8..1ca3a20c1 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/comments/comments.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/components/comments/comments.component.ts @@ -1,13 +1,15 @@ -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, Input, ViewChild } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, Input, OnChanges, ViewChild } from '@angular/core'; import { File, IComment } from '@red/domain'; import { ManualAnnotationService } from '../../../../services/manual-annotation.service'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { UserService } from '@services/user.service'; import { PermissionsService } from '@services/permissions.service'; -import { InputWithActionComponent, trackBy } from '@iqser/common-ui'; +import { AutoUnsubscribe, InputWithActionComponent, LoadingService, trackBy } from '@iqser/common-ui'; import { FilesMapService } from '@services/entity-services/files-map.service'; import { ActivatedRoute } from '@angular/router'; import { Observable } from 'rxjs'; +import { CommentingService } from '../../services/commenting.service'; +import { tap } from 'rxjs/operators'; @Component({ selector: 'redaction-comments', @@ -15,11 +17,11 @@ import { Observable } from 'rxjs'; styleUrls: ['./comments.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class CommentsComponent { +export class CommentsComponent extends AutoUnsubscribe implements OnChanges { @Input() annotation: AnnotationWrapper; readonly trackBy = trackBy(); readonly file$: Observable; - @HostBinding('class.hidden') private _hidden = true; + @HostBinding('class.hidden') _hidden = true; @ViewChild(InputWithActionComponent) private readonly _input: InputWithActionComponent; private readonly _fileId: string; private readonly _dossierId: string; @@ -28,49 +30,58 @@ export class CommentsComponent { readonly permissionsService: PermissionsService, private readonly _userService: UserService, private readonly _manualAnnotationService: ManualAnnotationService, - private readonly _changeDetectorRef: ChangeDetectorRef, + private readonly _commentingService: CommentingService, + private readonly _loadingService: LoadingService, + private readonly _changeRef: ChangeDetectorRef, readonly filesMapService: FilesMapService, activatedRoute: ActivatedRoute, ) { + super(); this._fileId = activatedRoute.snapshot.paramMap.get('fileId'); this._dossierId = activatedRoute.snapshot.paramMap.get('dossierId'); this.file$ = filesMapService.watch$(this._dossierId, this._fileId); } - addComment(value: string): void { + ngOnChanges() { + this.addSubscription = this._commentingService + .isActive$(this.annotation.id) + .pipe( + tap(active => { + this._hidden = !active; + }), + ) + .subscribe(); + } + + async addComment(value: string): Promise { if (!value) { return; } - this._manualAnnotationService + this._loadingService.start(); + const commentId = await this._manualAnnotationService .addComment(value, this.annotation.id, this._dossierId, this._fileId) - .toPromise() - .then(commentId => { - this.annotation.comments.push({ - text: value, - id: commentId, - annotationId: this.annotation.id, - user: this._userService.currentUser.id, - }); - this._input.reset(); - this._changeDetectorRef.markForCheck(); - }); + .toPromise(); + this.annotation.comments.push({ + text: value, + id: commentId, + annotationId: this.annotation.id, + user: this._userService.currentUser.id, + }); + this._input.reset(); + this._changeRef.markForCheck(); + this._loadingService.stop(); } toggleExpandComments($event?: MouseEvent): void { $event?.stopPropagation(); - this._hidden = !this._hidden; + this._commentingService.toggle(this.annotation.id); } - deleteComment(comment: IComment): void { - this._manualAnnotationService - .deleteComment(comment.id, this.annotation.id, this._dossierId, this._fileId) - .toPromise() - .then(() => { - this.annotation.comments.splice(this.annotation.comments.indexOf(comment), 1); - if (!this.annotation.comments.length) { - this._hidden = true; - } - this._changeDetectorRef.markForCheck(); - }); + async deleteComment(comment: IComment): Promise { + this._loadingService.start(); + await this._manualAnnotationService.deleteComment(comment.id, this.annotation.id, this._dossierId, this._fileId).toPromise(); + this.annotation.comments.splice(this.annotation.comments.indexOf(comment), 1); + this._changeRef.markForCheck(); + this._loadingService.stop(); } } diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts index 4ff4c076a..78783215f 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts @@ -46,6 +46,7 @@ import { MultiSelectService } from './services/multi-select.service'; import { DocumentInfoService } from './services/document-info.service'; import { ReanalysisService } from '../../../../services/reanalysis.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { CommentingService } from './services/commenting.service'; import Annotation = Core.Annotations.Annotation; import PDFNet = Core.PDFNet; @@ -54,7 +55,7 @@ const ALL_HOTKEY_ARRAY = ['Escape', 'F', 'f', 'ArrowUp', 'ArrowDown']; @Component({ templateUrl: './file-preview-screen.component.html', styleUrls: ['./file-preview-screen.component.scss'], - providers: [FilterService, ExcludedPagesService, ViewModeService, MultiSelectService, DocumentInfoService], + providers: [FilterService, ExcludedPagesService, ViewModeService, MultiSelectService, DocumentInfoService, CommentingService], }) export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnInit, OnDestroy, OnAttach, OnDetach { readonly circleButtonTypes = CircleButtonTypes; diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/commenting.service.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/commenting.service.ts new file mode 100644 index 000000000..523631f3a --- /dev/null +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/services/commenting.service.ts @@ -0,0 +1,38 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { map, startWith } from 'rxjs/operators'; +import { shareDistinctLast } from '@iqser/common-ui'; + +@Injectable() +export class CommentingService { + private _activeAnnotations = new BehaviorSubject>(new Set()); + + isActive$(annotationId: string): Observable { + return this._activeAnnotations.pipe( + map(annotations => annotations.has(annotationId)), + startWith(false), + shareDistinctLast(), + ); + } + + toggle(annotationId: string): void { + if (this._activeAnnotations.value.has(annotationId)) { + this._deactivate(annotationId); + } else { + this._activate(annotationId); + } + } + + private _activate(annotationId: string): void { + const currentValue = this._activeAnnotations.value; + const newSet = new Set(currentValue).add(annotationId); + this._activeAnnotations.next(newSet); + } + + private _deactivate(annotationId: string): void { + const currentValue = this._activeAnnotations.value; + const newSet = new Set(currentValue); + newSet.delete(annotationId); + this._activeAnnotations.next(newSet); + } +} diff --git a/libs/common-ui b/libs/common-ui index a1c1be7ed..795a273c9 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit a1c1be7edc783bdea42b86c0f8b1f74437065b76 +Subproject commit 795a273c9cde2a47c8a53e81a1b1efeb3ad81ddb