src/app/modules/groups/components/add-member/add-member.component.ts
OnInit
OnDestroy
selector | app-add-member |
styleUrls | ./add-member.component.scss |
templateUrl | ./add-member.component.html |
Properties |
|
Methods |
Outputs |
constructor(resourceService: ResourceService, groupsService: GroupsService, toasterService: ToasterService, activatedRoute: ActivatedRoute, groupService: GroupsService, router: Router, location: Location, recaptchaService: RecaptchaService, telemetryService: TelemetryService, layoutService: LayoutService)
|
|||||||||||||||||||||||||||||||||
Parameters :
|
members | |
Type : EventEmitter
|
|
addMemberToGroup |
addMemberToGroup()
|
Returns :
void
|
captchaResolved | ||||||
captchaResolved(captchaResponse: string)
|
||||||
Parameters :
Returns :
void
|
getUpdatedGroupData |
getUpdatedGroupData()
|
Returns :
void
|
initLayout |
initLayout()
|
Returns :
void
|
initRecaptcha |
initRecaptcha()
|
Returns :
void
|
isExistingMember |
isExistingMember()
|
Returns :
boolean
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
onVerifyMember |
onVerifyMember()
|
Returns :
void
|
reset |
reset()
|
Returns :
void
|
resetValue | ||||
resetValue(memberId?)
|
||||
Parameters :
Returns :
void
|
setInteractData | ||||||||||||
setInteractData(id, extra?, Cdata?, edata?, obj?)
|
||||||||||||
Parameters :
Returns :
void
|
showErrorMsg | ||||
showErrorMsg(response?)
|
||||
Parameters :
Returns :
void
|
showInvalidUser |
showInvalidUser()
|
Returns :
void
|
toggleModal | ||||||||
toggleModal(visibility: boolean)
|
||||||||
Parameters :
Returns :
void
|
verifyMember |
verifyMember()
|
Returns :
void
|
captchaRef |
Type : RecaptchaComponent
|
Decorators :
@ViewChild('captchaRef')
|
captchaResponse |
Type : string
|
Default value : ''
|
config |
Type : object
|
Default value : { size: 'medium', isBold: true, isSelectable: false, view: 'horizontal' }
|
disableBtn |
Default value : false
|
googleCaptchaSiteKey |
Type : string
|
Default value : ''
|
groupData |
Type : IGroupCard
|
instance |
Type : string
|
isCaptchEnabled |
Default value : false
|
isInvalidUser |
Default value : false
|
isVerifiedUser |
Default value : false
|
layoutConfiguration |
Type : any
|
Public layoutService |
Type : LayoutService
|
memberId |
Type : string
|
membersList |
Type : IGroupMember[]
|
Public recaptchaService |
Type : RecaptchaService
|
Public resourceService |
Type : ResourceService
|
showLoader |
Default value : false
|
showModal |
Default value : false
|
telemetryImpression |
Type : IImpressionEventInput
|
Public telemetryService |
Type : TelemetryService
|
Public unsubscribe$ |
Default value : new Subject<void>()
|
verifiedMember |
Type : IGroupMember
|
Public VERIFY_USER |
Default value : VERIFY_USER
|
import { Location } from '@angular/common';
import { ActivatedRoute, Router } from '@angular/router';
import { takeUntil } from 'rxjs/operators';
import {ResourceService, ToasterService, RecaptchaService, LayoutService} from '@sunbird/shared';
import { Component, OnInit, Output, EventEmitter, OnDestroy, ViewChild } from '@angular/core';
import * as _ from 'lodash-es';
import { IGroupMember, IGroupCard, IMember } from '../../interfaces';
import { GroupsService } from '../../services';
import { Subject } from 'rxjs';
import { IImpressionEventInput } from '@sunbird/telemetry';
import { RecaptchaComponent } from 'ng-recaptcha';
import { TelemetryService } from '@sunbird/telemetry';
import { VERIFY_USER, USER_SEARCH } from '../../interfaces/telemetryConstants';
import { sessionKeys } from '../../../../modules/groups/interfaces/group';
@Component({
selector: 'app-add-member',
templateUrl: './add-member.component.html',
styleUrls: ['./add-member.component.scss']
})
export class AddMemberComponent implements OnInit, OnDestroy {
showModal = false;
instance: string;
membersList: IGroupMember[] ;
groupData: IGroupCard;
showLoader = false;
isVerifiedUser = false;
memberId: string;
config = { size: 'medium', isBold: true, isSelectable: false, view: 'horizontal' };
isInvalidUser = false;
disableBtn = false;
verifiedMember: IGroupMember;
telemetryImpression: IImpressionEventInput;
public unsubscribe$ = new Subject<void>();
@Output() members = new EventEmitter<any>();
@ViewChild('captchaRef') captchaRef: RecaptchaComponent;
captchaResponse = '';
googleCaptchaSiteKey = '';
isCaptchEnabled = false;
layoutConfiguration: any;
public VERIFY_USER = VERIFY_USER;
constructor(public resourceService: ResourceService, private groupsService: GroupsService,
private toasterService: ToasterService,
private activatedRoute: ActivatedRoute,
private groupService: GroupsService,
private router: Router,
private location: Location,
public recaptchaService: RecaptchaService,
public telemetryService: TelemetryService,
public layoutService: LayoutService
) {
}
ngOnInit() {
this.initLayout();
this.showModal = !localStorage.getItem('login_members_ftu');
this.groupData = this.groupsService.groupData || JSON.parse(sessionStorage.getItem(sessionKeys.GROUPDATA));
this.initRecaptcha();
this.instance = _.upperCase(this.resourceService.instance);
this.membersList = this.groupsService.addFieldsToMember(_.get(this.groupData, 'members'));
this.telemetryImpression = this.groupService.getImpressionObject(this.activatedRoute.snapshot, this.router.url, {type: USER_SEARCH});
}
initLayout() {
this.layoutConfiguration = this.layoutService.initlayoutConfig();
this.layoutService.switchableLayout().pipe(takeUntil(this.unsubscribe$)).subscribe(layoutConfig => {
if (layoutConfig != null) {
this.layoutConfiguration = layoutConfig.layout;
}
});
}
initRecaptcha() {
this.groupService.getRecaptchaSettings().subscribe((res: any) => {
if (res.result.response) {
try {
const captchaConfig = _.get(res, 'result.response.value') ? JSON.parse(_.get(res, 'result.response.value')) : {};
this.googleCaptchaSiteKey = captchaConfig.key || '';
this.isCaptchEnabled = captchaConfig.isEnabled || false;
} catch (e) {
console.log(_.get(res, 'result.response'));
}
}
});
}
reset() {
this.showLoader = false;
this.isInvalidUser = false;
this.isVerifiedUser = false;
}
resetValue(memberId?) {
this.setInteractData('reset-userId', {searchQuery: memberId});
this.memberId = '';
this.groupsService.emitShowLoader(false);
this.reset();
}
captchaResolved(captchaResponse: string) {
this.captchaResponse = captchaResponse;
this.verifyMember();
}
onVerifyMember() {
this.reset();
if (this.isCaptchEnabled) {
this.showLoader = true;
this.captchaRef.execute();
} else {
this.verifyMember();
}
}
verifyMember() {
this.showLoader = true;
this.memberId = (this.memberId.replace(/([^\w\s]|_)+(?=\s|$)/g, ''));
this.groupsService.getUserData((this.memberId), {token: this.captchaResponse})
.pipe(takeUntil(this.unsubscribe$)).subscribe(member => {
this.verifiedMember = this.groupsService.addFields(member);
if (member.exists) {
this.showLoader = false;
this.isVerifiedUser = !this.isExistingMember();
this.captchaRef.reset();
} else {
this.showInvalidUser();
}
}, (err) => {
this.showInvalidUser();
});
}
showInvalidUser () {
this.isInvalidUser = true;
this.showLoader = false;
this.captchaRef.reset();
}
isExistingMember() {
const isExisting = _.find(this.membersList, { userId: _.get(this.verifiedMember, 'id') });
if (isExisting) {
this.resetValue();
this.toasterService.error(this.resourceService.messages.emsg.m007);
return true;
}
return false;
}
addMemberToGroup() {
this.setInteractData('add-user-to-group', {}, {id: _.get(this.verifiedMember, 'id'), type: 'Member'});
this.groupsService.emitShowLoader(true);
this.disableBtn = true;
if (!this.isExistingMember()) {
const member: IMember = {members: [{ userId: _.get(this.verifiedMember, 'id'), role: 'member' }]};
const groupId = _.get(this.groupData, 'id') || _.get(this.activatedRoute.snapshot, 'params.groupId');
this.groupsService.addMemberById(groupId, member).pipe(takeUntil(this.unsubscribe$)).subscribe(response => {
this.getUpdatedGroupData();
this.disableBtn = false;
const value = _.isEmpty(response.error) ? this.toasterService.success((this.resourceService.messages.smsg.m004).replace('{memberName}',
this.verifiedMember['title'])) : this.showErrorMsg(response);
this.memberId = '';
this.reset();
}, err => {
this.groupsService.emitShowLoader(false);
this.disableBtn = false;
this.memberId = '';
this.reset();
this.showErrorMsg();
});
}
}
showErrorMsg(response?) {
if (_.get(response, 'error.members[0].errorCode') === 'EXCEEDED_MEMBER_MAX_LIMIT') {
this.toasterService.error(this.resourceService.messages.groups.emsg.m002);
this.setInteractData('exceeded-member-max-limit', {searchQuery: this.memberId,
member_count: this.membersList.length});
} else {
this.toasterService.error((this.resourceService.messages.emsg.m006).replace('{name}', _.get(response, 'errors')
|| _.get(this.verifiedMember, 'title')));
}
}
getUpdatedGroupData() {
const groupId = _.get(this.groupData, 'id') || _.get(this.activatedRoute.snapshot, 'params.groupId');
this.groupsService.getGroupById(groupId, true).pipe(takeUntil(this.unsubscribe$)).subscribe(groupData => {
this.groupsService.groupData = groupData || JSON.parse(sessionStorage.getItem(sessionKeys.GROUPDATA));
this.groupData = groupData;
this.membersList = this.groupsService.addFieldsToMember(_.get(groupData, 'members'));
this.groupsService.emitMembers(this.membersList);
this.groupsService.emitShowLoader(false);
}, err => {
this.groupsService.emitShowLoader(false);
this.membersList.push(this.verifiedMember);
});
}
toggleModal(visibility: boolean = false) {
this.showModal = visibility;
}
setInteractData (id, extra?, Cdata?, edata?, obj?) {
const interactData = {
context: {
env: _.get(this.activatedRoute, 'snapshot.data.telemetry.env'),
cdata: [
{
id: _.get(this.groupData, 'id'),
type: 'Group'
}
]
},
edata: {
id: id,
type: 'CLICK',
pageid: _.get(this.activatedRoute, 'snapshot.data.telemetry.pageid')
}
};
if (edata) {
interactData.edata.type = edata.type;
}
if (extra) {
interactData.edata['extra'] = extra;
}
if (Cdata) {
interactData.context.cdata.push(Cdata);
}
if (obj) {
interactData['object'] = obj;
}
this.telemetryService.interact(interactData);
}
ngOnDestroy() {
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
}
<app-landing-section [layoutConfiguration]="layoutConfiguration" [noTitle]="true">
</app-landing-section>
<div [ngClass]="layoutConfiguration ? 'sb-back-actionbar mt-0' : 'sb-bg-white cc-player__btn-back'" class="relative position mt-0" [appTelemetryImpression]="telemetryImpression">
<div class="ui container d-flex flex-ai-center">
<app-back-button></app-back-button>
<div class="d-flex flex-ai-center flex-jc-space-between flex-w-wrap ml-16 w-100">
<div class="d-flex flex-dc">
<h4 class="mb-4 font-weight-bold sb__ellipsis sb__ellipsis--one d-flex">{{resourceService?.frmelmnts?.lbl?.addNewMember}}</h4>
<div class="fsmall"></div>
</div>
<div class="d-flex flex-ai-end flex-w-wrap content-header__buttons">
</div>
</div>
</div>
</div>
<div [ngClass]="layoutConfiguration ? 'sbt-center-container sbt-add-member relative9' : ''">
<div class="ui container" [appTelemetryImpression]="telemetryImpression">
<div class="sb-g mt-24">
<div class="sb-g-col-xs-12 sb-g-col-md-9 sb-g-col-lg-9 sb-g-col-xxxl-12">
<div class="sb-bg-color-white p-24">
<div class="sb-field instance-id-verify">
<div class="d-flex flex-jc-space-between flex-ai-center">
<div class="w-100">
<div class="d-inline-flex flex-ai-center flex-jc-space-between w-100"><span> {{resourceService?.frmelmnts?.lbl?.instanceId | interpolate:'{instance}': instance}}*</span>
<span class="cursor-pointer"><i class="icon-svg icon-svg--xs icon-info ml-4" tabindex="0" (click)="toggleModal(true);setInteractData('member-ftu-popup')"><svg class="icon icon-svg--primary">
<use xlink:href="./assets/images/sprite.svg#info"></use>
</svg></i></span>
</div>
<div class="d-flex flex-jc-space-between flex-dc">
<div class="w-100 relative">
<input type="id" name="id" aria-label="search user id" class="sb-form-control" [ngClass]="{'is-invalid': isInvalidUser}" placeholder="{{resourceService?.frmelmnts?.lbl?.enterInstanceId | interpolate:'{instance}': instance}}" [(ngModel)]="memberId" (ngModelChange)="reset()">
<i class="icon close icon-input-close" tabindex="0" (click)="resetValue(memberId);"></i>
</div>
<small class="message sb-color-error font-weight-bold mt-8" *ngIf="isInvalidUser">{{resourceService?.messages?.emsg?.m004 | interpolate:'{instance}': instance}}</small>
</div>
</div>
<re-captcha class="recaptcha" *ngIf="isCaptchEnabled" #captchaRef="reCaptcha" (resolved)="$event && captchaResolved($event)" siteKey="{{googleCaptchaSiteKey}}" size="invisible"></re-captcha>
<button type="button" class="sb-btn sb-btn-normal sb-btn-nolayer" tabindex="0" [ngClass]="{'sb-btn-primary': memberId?.trim(), 'sb-btn-disabled': !memberId?.trim()}" [disabled]="!memberId?.trim()" (click)="onVerifyMember();setInteractData('verify-member', {searchQuery: memberId}, '', {type: VERIFY_USER})">{{resourceService?.frmelmnts?.btn?.verify}}</button>
</div>
</div>
<!-- Add to group button content -->
<div class="text-left fnormal mt-16 mb-8" *ngIf="isVerifiedUser">{{resourceService?.frmelmnts?.lbl?.memberVerificationMsg | interpolate:'{instance}': instance}}</div>
<div class="flex-ai-jc-center add-member-content p-24" *ngIf="showLoader">
<div class="flex-ai-jc-center"><img class="mr-8" src="./assets/images/loader.gif" width="32" /><span>{{resourceService?.frmelmnts?.lbl?.verifying}}</span></div>
</div>
<div class="d-flex flex-ai-center flex-jc-space-between add-member-content p-16" *ngIf="isVerifiedUser">
<div class="add-member-text flex-basis-1">
<sb-member-card [title]="verifiedMember?.title" [identifier]="verifiedMember?.identifier" [config]="config"
[indexOfMember]="verifiedMember?.indexOfMember" [initial]="verifiedMember?.initial">
</sb-member-card>
</div>
<button type="button" class="sb-btn sb-btn-primary sb-btn-normal sb-btn-nolayer" tabindex="0" [disabled]= "disableBtn" tabindex="0" (click)="addMemberToGroup();"
[ngClass]="{'sb-btn-disabled': disableBtn}">
<img src="./assets/images/ic_person_add.svg" width="16px" class="mr-4"> {{resourceService?.frmelmnts?.lbl?.AddtoGroup}}
</button>
</div>
</div>
</div>
<div class="sb-g-col-xs-12 sb-g-col-md-3 sb-g-col-lg-3 sb-g-col-xxxl-4 sb-members-column">
<app-group-members [members]="membersList" [groupData]="groupData"></app-group-members>
</div>
</div>
</div>
</div>
<app-ftu-popup *ngIf="showModal" [showMemberPopup]="showModal" (close)="toggleModal(false)"></app-ftu-popup>
./add-member.component.scss
@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;
.title {
color: var(--gray-800);
}
.icon-input-close {
position: absolute;
top: calculateRem(4px);
right: calculateRem(4px);
cursor: pointer;
width: calculateRem(24px);
height: calculateRem(24px);
html[dir="rtl"] & {
left: calculateRem(8px);
right: inherit;
}
}
.add-member-content {
width: 100%;
background: var(--rc-E0F1FD);
flex-direction: row;
@include respond-below(sm) {
flex-direction: column;
button {
margin-top: calculateRem(16px);
}
}
.add-member-text {
margin: calculateRem(8px) calculateRem(8px) calculateRem(8px) 0px;
html[dir="rtl"] & {
margin: calculateRem(8px) 0px calculateRem(8px) calculateRem(8px);
}
@include respond-below(sm) {
align-self: self-start;
margin: 0px;
width: 100%;
}
}
}
.sb-field {
.message {
font-size: calculateRem(10px);
display: flex;
@include respond-below(sm) {
margin: 0.5rem 0;
}
}
}
.instance-id-verify {
button {
margin-top: calculateRem(24px);
margin-left: calculateRem(8px);
align-self: normal;
@include respond-below(sm) {
margin-top: calculateRem(8px);
margin-left: 0px;
}
}
& > div {
@include respond-below(sm) {
flex-direction: column;
margin-bottom: calculateRem(24px);
}
}
}
.recaptcha {
z-index: 1;
}
.sb-members-column {
@include respond-below(sm) {
margin-top: calculateRem(16px);
}
}