File

src/app/modules/groups/components/add-member/add-member.component.ts

Implements

OnInit OnDestroy

Metadata

Index

Properties
Methods
Outputs

Constructor

constructor(resourceService: ResourceService, groupsService: GroupsService, toasterService: ToasterService, activatedRoute: ActivatedRoute, groupService: GroupsService, router: Router, location: Location, recaptchaService: RecaptchaService, telemetryService: TelemetryService, layoutService: LayoutService)
Parameters :
Name Type Optional
resourceService ResourceService No
groupsService GroupsService No
toasterService ToasterService No
activatedRoute ActivatedRoute No
groupService GroupsService No
router Router No
location Location No
recaptchaService RecaptchaService No
telemetryService TelemetryService No
layoutService LayoutService No

Outputs

members
Type : EventEmitter

Methods

addMemberToGroup
addMemberToGroup()
Returns : void
captchaResolved
captchaResolved(captchaResponse: string)
Parameters :
Name Type Optional
captchaResponse string No
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 :
Name Optional
memberId Yes
Returns : void
setInteractData
setInteractData(id, extra?, Cdata?, edata?, obj?)
Parameters :
Name Optional
id No
extra Yes
Cdata Yes
edata Yes
obj Yes
Returns : void
showErrorMsg
showErrorMsg(response?)
Parameters :
Name Optional
response Yes
Returns : void
showInvalidUser
showInvalidUser()
Returns : void
toggleModal
toggleModal(visibility: boolean)
Parameters :
Name Type Optional Default value
visibility boolean No false
Returns : void
verifyMember
verifyMember()
Returns : void

Properties

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);
	}
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""