import { Component, Inject } from '@angular/core'; import { FormBuilder, FormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; import { Router } from '@angular/router'; import { Annotation, AnnotationPersist } from '@annotation-service/core/model/annotation.model'; import { AnnotationLookup } from '@annotation-service/core/query/annotation.lookup'; import { AnnotationService } from '@annotation-service/services/http/annotation.service'; import { AnnotationProtectionType } from '@app/core/common/enum/annotation-protection-type.enum'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; import { BaseComponent } from '@common/base/base.component'; import { FormService } from '@common/forms/form-service'; import { Guid } from '@common/types/guid'; import { TranslateService } from '@ngx-translate/core'; import { takeUntil } from 'rxjs/operators'; import { nameof } from 'ts-simple-nameof'; @Component({ selector: 'app-annotation-dialog', templateUrl: './annotation-dialog.component.html', styleUrls: ['./annotation-dialog.component.scss'] }) export class AnnotationDialogComponent extends BaseComponent { annotationProtectionTypeEnumValues = this.enumUtils.getEnumValues(AnnotationProtectionType); annotationProtectionTypeEnum = AnnotationProtectionType; private entityId: Guid; private anchor: string; private entityType: string; private changesMade: boolean = false; public comments = new Array(); public threads = new Set(); public annotationsCount: number = 0; public annotationsPerThread = {}; public showRepliesPerThread = {}; public replyEnabledPerThread = {}; public parentAnnotationsPerThread = {}; threadReplyTextsFG: Array; threadFormGroup: UntypedFormGroup; private formBuilder: FormBuilder = new FormBuilder(); constructor( public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any, private router: Router, public dialog: MatDialog, private uiNotificationService: UiNotificationService, private language: TranslateService, private annotationService: AnnotationService, private formService: FormService, private enumUtils: EnumUtils, ) { super(); this.entityId = data.entityId; this.anchor = data.anchor; this.entityType = data.entityType; dialogRef.backdropClick().pipe(takeUntil(this._destroyed)).subscribe(() => dialogRef.close(this.changesMade)); } ngOnInit(): void { this.threadFormGroup = new UntypedFormGroup({ text: new FormControl(null, [Validators.required]), protectionType: new FormControl(AnnotationProtectionType.EntityAccessors, [Validators.required]) }); if (this.entityId != null) { this.loadThreads(); } } createThread() { this.formService.removeAllBackEndErrors(this.threadFormGroup); this.formService.touchAllFormFields(this.threadFormGroup); if (!this.isFormValid(this.threadFormGroup)) { return; } const threadToCreate: AnnotationPersist = { threadId: Guid.create(), payload: this.threadFormGroup.get('text').value, protectionType: this.threadFormGroup.get('protectionType').value, entityId: this.entityId, entityType: this.entityType, anchor: this.anchor }; this.annotationService.persist(threadToCreate).pipe(takeUntil(this._destroyed)) .subscribe( complete => this.onCallbackSuccess(), error => this.onCallbackError(error) ); } replyThread(threadId: Guid) { // if (!this.threadReplyTexts[threadId.toString()] || this.threadReplyTexts[threadId.toString()].length === 0) { return; } this.formService.removeAllBackEndErrors(this.threadReplyTextsFG[threadId.toString()]); this.formService.touchAllFormFields(this.threadReplyTextsFG[threadId.toString()]); if (!this.isFormValid(this.threadReplyTextsFG[threadId.toString()])) { return; } const replyToCreate: AnnotationPersist = { threadId: threadId, payload: this.threadReplyTextsFG[threadId.toString()].get('replyText').value, protectionType: this.parentAnnotationsPerThread[threadId.toString()].protectionType, entityId: this.entityId, entityType: this.entityType, anchor: this.anchor, parentId: this.parentAnnotationsPerThread[threadId.toString()].id }; this.annotationService.persist(replyToCreate).pipe(takeUntil(this._destroyed)) .subscribe( complete => this.onCallbackSuccess(), error => this.onCallbackError(error) ); } private refreshAnnotations() { this.threadReplyTextsFG.forEach(element => { element.reset(); }); this.loadThreads(); } private loadThreads() { const lookup: AnnotationLookup = new AnnotationLookup(); lookup.entityIds = [this.entityId]; lookup.anchors = [this.anchor]; lookup.entityTypes = [this.entityType]; lookup.project = { fields: [ nameof(x => x.id), nameof(x => x.threadId), nameof(x => x.parent.id), nameof(x => x.timeStamp), nameof(x => x.author.name), nameof(x => x.payload), nameof(x => x.protectionType), ] }; this.annotationService.query(lookup) .pipe(takeUntil(this._destroyed)) .subscribe( data => { this.annotationsCount = data.count; this.annotationsPerThread = {}; this.parentAnnotationsPerThread = {}; this.threads = new Set(); this.threadReplyTextsFG = new Array(); this.resetFormGroup(); this.comments = data.items.sort((a1, a2) => new Date(a2.timeStamp).getTime() - new Date(a1.timeStamp).getTime()); this.comments.forEach(element => { // this.threadReplyTextsFG.addControl(element.id.toString(), new FormControl(null)); this.threadReplyTextsFG[element.threadId.toString()] = this.formBuilder.group({ replyText: new FormControl(null, [Validators.required]) }); this.annotationsPerThread[element.threadId.toString()] = data.items.filter(x => x.threadId === element.threadId && x.id !== element.id).sort((a1, a2) => new Date(a1.timeStamp).getTime() - new Date(a2.timeStamp).getTime()); this.parentAnnotationsPerThread[element.threadId.toString()] = data.items.filter(x => x.threadId === element.threadId && x.id === element.id)[0]; this.threads.add(element.threadId); }); console.log(this.parentAnnotationsPerThread); // console.log(this.comments); // console.log(this.threads); // console.log(this.parentAnnotationsPerThread); // console.log(this.annotationsPerThread); // this.annotationsChanged.emit(this.threads); }, error => this.onCallbackError(error), ); } getParentAnnotation(thread: Guid): Annotation { return this.parentAnnotationsPerThread[thread.toString()]; } resetFormGroup() { this.threadFormGroup.reset(); this.threadFormGroup.get('protectionType').setValue(AnnotationProtectionType.EntityAccessors); } isValidText(text: string): boolean { return !isNullOrUndefined(text) && text.length !== 0 && text !== ''; } // ngOnInit() { // const lookup: AnnotationLookup = new AnnotationLookup(); // lookup.entityIds = [this.entityId]; // // lookup.anchors = [this.anchor]; // lookup.entityTypes = [this.entityType]; // this.annotationService.query(lookup).pipe(takeUntil(this._destroyed)) // .subscribe( // data => { // this.annotations = data.items; // }, // error => this.onCallbackError(error) // ); // } public isFormValid(value: any) { return value.valid; } private onCallbackSuccess() { this.uiNotificationService.snackBarNotification(this.language.instant('ANNOTATION-DIALOG.SUCCESS'), SnackBarNotificationLevel.Success); this.refreshAnnotations(); this.changesMade = true; } private onCallbackError(error: any) { this.uiNotificationService.snackBarNotification(this.language.instant(error.message), SnackBarNotificationLevel.Error); } getAnnotationProtectionType(thread: Guid): string { return this.enumUtils.toAnnotationProtectionTypeString(this.parentAnnotationsPerThread[thread.toString()].protectionType); } cancel() { this.dialogRef.close(this.changesMade); } close() { this.dialogRef.close(this.changesMade); } startWizard() { this.router.navigate(['/plans/new']); this.close(); } showReplies(threadId: string): void { this.showRepliesPerThread[threadId] = true; } enableReply(threadId: string): void { this.replyEnabledPerThread[threadId] = true; } }