src/app/modules/workspace/components/review-comments/review-comments.component.ts
OnInit
OnChanges
OnDestroy
selector | app-review-comments |
styleUrls | ./review-comments.component.scss |
templateUrl | ./review-comments.component.html |
Properties |
|
Methods |
Inputs |
Outputs |
constructor(resourceService: ResourceService, toasterService: ToasterService, userService: UserService, reviewCommentsService: ReviewCommentsService)
|
|||||||||||||||
Parameters :
|
contentData | |
Type : ContentData
|
|
playerLoaded | |
Type : boolean
|
|
stageId | |
Type : string
|
|
reviewCommentEvent | |
Type : EventEmitter
|
|
addReviewComments |
addReviewComments()
|
Returns :
void
|
focusOnInput |
focusOnInput()
|
Returns :
void
|
getReviewComments |
getReviewComments()
|
Returns :
any
|
ngOnChanges |
ngOnChanges()
|
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
setInteractEventData |
setInteractEventData()
|
Returns :
void
|
commentInput |
Type : ElementRef
|
Decorators :
@ViewChild('commentInput')
|
comments |
Default value : new UntypedFormControl()
|
contentComments |
Type : any
|
disableSubmitcommentsButton |
Default value : true
|
disableTextArea |
Default value : false
|
Public resourceService |
Type : ResourceService
|
Public reviewCommentsService |
Type : ReviewCommentsService
|
sortedComments |
Type : any
|
Default value : {}
|
Public submitCommentsInteractEdata |
Type : IInteractEventEdata
|
Creates a object of the form control |
Public telemetryInteractObject |
Type : IInteractEventObject
|
Public toasterService |
Type : ToasterService
|
Public unsubscribe |
Default value : new Subject<void>()
|
Public userService |
Type : UserService
|
import { Component, OnInit, Input, OnChanges, OnDestroy, ViewChild, ElementRef, Output, EventEmitter } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { ResourceService, ToasterService, ContentData, ServerResponse } from '@sunbird/shared';
import { UserService } from '@sunbird/core';
import { ReviewCommentsService } from '../../services';
import { Subject } from 'rxjs';
import { takeUntil, map } from 'rxjs/operators';
import * as _ from 'lodash-es';
import { IInteractEventObject, IInteractEventEdata } from '@sunbird/telemetry';
import dayjs from 'dayjs';
@Component({
selector: 'app-review-comments',
templateUrl: './review-comments.component.html',
styleUrls: ['./review-comments.component.scss']
})
export class ReviewCommentsComponent implements OnInit, OnChanges, OnDestroy {
public unsubscribe = new Subject<void>();
/**
* Creates a object of the form control
*/
public submitCommentsInteractEdata: IInteractEventEdata;
public telemetryInteractObject: IInteractEventObject;
comments = new UntypedFormControl();
sortedComments: any = {};
contentComments: any;
disableSubmitcommentsButton = true;
disableTextArea = false;
@Input() contentData: ContentData;
@Input() stageId: string;
@Input() playerLoaded: boolean;
@Output() reviewCommentEvent = new EventEmitter();
@ViewChild('commentInput') commentInput: ElementRef;
constructor(public resourceService: ResourceService, public toasterService: ToasterService,
public userService: UserService, public reviewCommentsService: ReviewCommentsService,
) { }
ngOnInit() {
this.setInteractEventData();
this.getReviewComments().pipe(takeUntil(this.unsubscribe)).subscribe(
(data) => {
this.sortedComments = data;
this.reviewCommentEvent.emit(this.sortedComments ); // emit data to parent
this.reviewCommentsService.contextDetails = {
contentId: this.contentData.identifier,
contentVer: this.contentData.pkgVersion ? this.contentData.pkgVersion.toString() : '0', // this should be version not versionKey
contentType: this.contentData.mimeType
};
},
(error) => this.toasterService.error(this.resourceService.messages.emsg.m0011));
}
ngOnChanges() {
if (!this.stageId) {
this.disableTextArea = true;
} else {
this.disableTextArea = false;
}
this.comments = new UntypedFormControl();
}
focusOnInput() {
this.commentInput.nativeElement.focus();
}
getReviewComments() {
// fetch all comments for content then show content related to stageID
const requestBody = {
request: {
contextDetails: {
contentId: this.contentData.identifier,
contentVer: this.contentData.pkgVersion ? this.contentData.pkgVersion.toString() : '0', // this should be version not versionKey
contentType: this.contentData.mimeType
}
}
};
return this.reviewCommentsService.getComments(requestBody).pipe(map((data) => {
const commentList = _.get(data, 'result.comments');
return commentList.reduce((accumulator, current) => {
if (accumulator[current.stageId]) {
accumulator[current.stageId].push(current);
} else {
accumulator[current.stageId] = [];
accumulator[current.stageId].push(current);
}
return accumulator;
}, {});
}));
}
addReviewComments() {
if (!this.stageId) { // if stageId not fetched, throw error
this.toasterService.error(this.resourceService.messages.emsg.m0010);
return;
}
if (!this.comments.value || !this.comments.value.trim()) {
return;
}
this.disableTextArea = true;
const requestBody: any = {
request: {
contextDetails: {
contentId: this.contentData.identifier,
contentVer: this.contentData.pkgVersion ? this.contentData.pkgVersion.toString() : '0', // this should be version not versionKey
contentType: this.contentData.mimeType,
stageId: this.stageId
},
body: this.comments.value,
userId: this.userService.userProfile.userId,
userInfo: {
name: this.userService.userProfile.firstName + ' ' + this.userService.userProfile.lastName
}
}
};
if (this.userService.userProfile.avatar) {
requestBody.request.userInfo.logo = this.userService.userProfile.avatar;
}
this.reviewCommentsService.createComment(requestBody).pipe(
takeUntil(this.unsubscribe))
.subscribe(
(apiResponse: ServerResponse) => {
this.disableTextArea = false;
const newComment = {
userId: this.userService.userProfile.userId,
userInfo: {
name: this.userService.userProfile.firstName + ' ' + this.userService.userProfile.lastName,
logo: this.userService.userProfile.avatar,
},
body: this.comments.value,
createdOn: dayjs().format()
};
if (this.sortedComments[this.stageId]) {
this.sortedComments[this.stageId].push(newComment);
} else {
this.sortedComments[this.stageId] = [];
this.sortedComments[this.stageId].push(newComment);
}
this.reviewCommentEvent.emit(this.sortedComments); // emit data to parent
this.comments = new UntypedFormControl();
},
err => {
this.disableTextArea = false;
this.toasterService.error(this.resourceService.messages.emsg.m0010);
}
);
}
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
}
setInteractEventData() {
this.submitCommentsInteractEdata = {
id: 'submit-review-comments',
type: 'click',
pageid: 'upForReview-content-player'
};
this.telemetryInteractObject = {
id: this.contentData.identifier,
type: this.contentData.contentType,
ver: this.contentData.pkgVersion ? this.contentData.pkgVersion.toString() : '1.0'
};
}
}
<div *ngIf="playerLoaded" class="review-comments-box br-4 bs-2 p-8">
<div class="ui small comments scrolling p-5" *ngIf="sortedComments[stageId] && sortedComments[stageId].length else emptyComments" >
<div class="comment" *ngFor="let commentList of sortedComments[stageId]">
<span class="avatar">
<img *ngIf="commentList.userInfo.logo" src="{{commentList.userInfo.logo | cdnprefixurl}}">
<i *ngIf="!commentList.userInfo.logo" class="icon sb-icon-reviewer" aria-hidden="true"></i>
</span>
<div class="content pr-8">
<div class="d-flex flex-jc-space-between mb-5">
<span class="sb-color-primary">{{commentList.userInfo.name}}</span>
<span class="date ui metadata">{{commentList.createdOn | date: 'MMM d'}}</span>
</div>
<div class="text">
{{commentList.body}}
</div>
</div>
</div>
</div>
<ng-template #emptyComments>
<div tabindex="0" (click)="focusOnInput()" class="ui comments scrolling">
<div class="placeholder">
<i class="sb-icon-comment"></i>
<span class="">{{resourceService.frmelmnts.lbl.emptycomments}}</span>
</div>
</div>
</ng-template>
<div class="ui form p-8">
<div class="content mb-5 d-flex flex-jc-space-between">
<span class="ui metadata">{{resourceService.frmelmnts.lbl.dropcomment}} </span>
<span class="ui metadata" *ngIf="comments.value"> {{comments.value.trim().length}} / 250</span>
</div>
<div [ngClass]="{ 'disabled' : disableTextArea }" class="ui icon input width-100">
<textarea [attr.disabled]="disableTextArea ? true : null" #commentInput maxlength="250" autocomplete="off" class="width-100 br-4 reply-box form-control"[formControl]="comments"></textarea>
<i id="submit-review-comments" (click)="addReviewComments()" class="opacity-1 mr-5 right sb-icon-send icon link" aria-hidden="true" tabindex="0"
appTelemetryInteract [telemetryInteractObject]="telemetryInteractObject" [telemetryInteractEdata]="submitCommentsInteractEdata"></i>
</div>
</div>
</div>
<div *ngIf="!playerLoaded" class="review-comments-box br-4 bs-2 p-8 review-comments-loader">
<div class="ui active inverted dimmer">
<div class="ui text loader">{{resourceService.frmelmnts.instn.t0080}}</div>
</div>
</div>
./review-comments.component.scss
@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;
.review-comments-box {
max-height: calc(100% - calculateRem(4px));
position: absolute;
top: calculateRem(15px);
bottom: calculateRem(18px);
left: calculateRem(15px);
right: calculateRem(15px);
}
.ui.dimmer{
z-index: inherit;
}
.ui.comments.scrolling{
height:calc(100% - calculateRem(115px));
max-height: calc(100% - calculateRem(115px));
overflow-y: auto;
}
.reply-box{
height: calculateRem(60px) !important;
max-height: calculateRem(60px) !important;
min-height: calculateRem(10px) !important;
resize: none !important;
padding-right: 2.67142857em !important;
border: calculateRem(1px) solid var(--gray-300) !important;
border-radius: calculateRem(4px) !important;
}
.icon.sb-icon-send:before {
font-size: calculateRem(18px);
width: 1.671429em;
}
.sb-icon-comment:before {
font-size: calculateRem(72px);
width: calculateRem(72px);
color: var(--secondary-color);
}
.icon.sb-icon-reviewer:before {
font-size: calculateRem(30px);
color: var(--primary-color);
}
textarea:focus+i.icon.sb-icon-send:before {
color: var(--primary-color);
}
.ui.form textarea:focus {
border-color:var(--primary-color) !important;
}
.comment:after {
content: "";
visibility: hidden;
display: block;
height: 0;
clear: both;
}
.review-comments-loader {
position: relative;
}
.placeholder{
height:100%;
}