File

src/app/modules/groups/components/group-members/group-members.component.ts

Implements

OnInit OnDestroy

Metadata

Index

Properties
Methods
Inputs

Constructor

constructor(router: Router, activatedRoute: ActivatedRoute, resourceService: ResourceService, groupsService: GroupsService, toasterService: ToasterService, userService: UserService)
Parameters :
Name Type Optional
router Router No
activatedRoute ActivatedRoute No
resourceService ResourceService No
groupsService GroupsService No
toasterService ToasterService No
userService UserService No

Inputs

config
Type : IGroupMemberConfig
Default value : { showMemberCount: false, showSearchBox: false, showAddMemberButton: false, showMemberMenu: false }
groupData
Type : IGroupCard
members
Type : IGroupMember[]
Default value : []

Methods

addMember
addMember()
Returns : void
addTelemetry
addTelemetry(id, extra?, edata?)
Parameters :
Name Optional Description
id No
extra Yes
edata Yes

? - it's an object to specify the type and subtype of edata

Returns : void
dismissRole
dismissRole(data)
Parameters :
Name Optional
data No
Returns : void
getMenuData
getMenuData(event, member)
Parameters :
Name Optional
event No
member No
Returns : void
getUpdatedGroupData
getUpdatedGroupData()
Returns : void
hideMemberMenu
hideMemberMenu()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
onActionConfirm
onActionConfirm(event: any)
Parameters :
Name Type Optional
event any No
Returns : void
onModalClose
onModalClose()
Returns : void
openModal
openModal(action: string)
Parameters :
Name Type Optional
action string No
Returns : void
promoteMember
promoteMember(data)
Parameters :
Name Optional
data No
Returns : void
removeMember
removeMember(data)
Parameters :
Name Optional
data No
Returns : void
resetValue
resetValue()
Returns : void
search
search(searchKey: string)
Parameters :
Name Type Optional
searchKey string No
Returns : void
showAddMember
showAddMember()
Returns : boolean

Properties

Public ADD_MEMBER
Default value : ADD_MEMBER
currentUser
groupId
memberAction
Type : string
memberCardConfig
Type : object
Default value : { size: 'small', isBold: false, isSelectable: false, view: 'horizontal' }
memberListToShow
Type : IGroupMember[]
Default value : []
Public resourceService
Type : ResourceService
searchInputBox
Type : ElementRef
Decorators :
@ViewChild('searchInputBox')
searchQuery
Type : string
Default value : ''
selectedMember
Type : IGroupMember
showKebabMenu
Default value : false
showLoader
Default value : false
showModal
Default value : false
showSearchResults
Default value : false
Private unsubscribe$
Default value : new Subject<void>()
import { UserService } from '@sunbird/core';
import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { GroupMemberRole, GroupEntityStatus } from '@project-sunbird/client-services/models/group';
import { ResourceService, ToasterService } from '@sunbird/shared';
import * as _ from 'lodash-es';
import { fromEvent, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { GROUP_DETAILS, IGroupMember, IGroupMemberConfig, MY_GROUPS, IGroupCard } from '../../interfaces';
import { GroupsService } from '../../services';
import { ADD_MEMBER } from '../../interfaces/telemetryConstants';

@Component({
  selector: 'app-group-members',
  templateUrl: './group-members.component.html',
  styleUrls: ['./group-members.component.scss']
})
export class GroupMembersComponent implements OnInit, OnDestroy {
  @ViewChild('searchInputBox') searchInputBox: ElementRef;
  @Input() config: IGroupMemberConfig = {
    showMemberCount: false,
    showSearchBox: false,
    showAddMemberButton: false,
    showMemberMenu: false
  };
  @Input() members: IGroupMember[] = [];
  @Input() groupData: IGroupCard;
  currentUser;
  showKebabMenu = false;
  showModal = false;
  showSearchResults = false;
  memberListToShow: IGroupMember[] = [];
  memberAction: string;
  searchQuery = '';
  selectedMember: IGroupMember;
  private unsubscribe$ = new Subject<void>();
  groupId;
  showLoader = false;
  memberCardConfig = { size: 'small', isBold: false, isSelectable: false, view: 'horizontal' };
  public ADD_MEMBER = ADD_MEMBER;

  constructor(
    private router: Router,
    private activatedRoute: ActivatedRoute,
    public resourceService: ResourceService,
    private groupsService: GroupsService,
    private toasterService: ToasterService,
    private userService: UserService
  ) { }

  ngOnInit() {
    this.showLoader = false;
    this.groupId = _.get(this.activatedRoute, 'snapshot.params.groupId');
    this.memberListToShow = _.cloneDeep(this.members);
    this.hideMemberMenu();
    fromEvent(document, 'click')
      .pipe(takeUntil(this.unsubscribe$))
      .subscribe(item => {
        if (this.showKebabMenu) {
          this.showKebabMenu = false;
          this.addTelemetry('member-card-menu-close');
        }
      });
    this.groupsService.membersList.subscribe(members => {
      this.memberListToShow = members;
      this.hideMemberMenu();
    });

    this.groupsService.showMenu.subscribe(data => {
      this.showKebabMenu = data === 'member';
    });

    this.groupsService.updateEvent.pipe(takeUntil(this.unsubscribe$)).subscribe((status: GroupEntityStatus) => {
      this.groupData.active = this.groupsService.updateGroupStatus(this.groupData, status);
    });
  }

  hideMemberMenu() {
    /* istanbul ignore else */
    if (!this.config.showMemberMenu) {
      this.memberListToShow.forEach(item => item.isMenu = false);
    }
  }

  getMenuData(event, member) {
    this.showKebabMenu = !this.showKebabMenu;
    this.groupsService.emitMenuVisibility('member');
    this.showKebabMenu ? this.addTelemetry('member-card-menu-show') : this.addTelemetry('member-card-menu-close');
    this.selectedMember = member;
    event.event.stopImmediatePropagation();
  }

  search(searchKey: string) {
    searchKey = _.toLower(searchKey).trim();
    if (searchKey.trim().length) {
      this.showSearchResults = true;
      this.memberListToShow = this.members.filter(item => _.toLower(item.title).includes(searchKey));
      this.addTelemetry('group-member-search-input', { query: searchKey });
    } else {
      this.showSearchResults = false;
      this.memberListToShow = _.cloneDeep(this.members);
    }
  }

  openModal(action: string) {
    this.showModal = !this.showModal;
    this.memberAction = action;
  }

  addMember() {
    this.router.navigate([`${MY_GROUPS}/${GROUP_DETAILS}`, _.get(this.groupData, 'id') || this.groupId, 'add-member-to-group']);
  }

  onModalClose() {
    this.showModal = false;
    // Handle Telemetry
  }

  getUpdatedGroupData() {
    const groupId = _.get(this.groupData, 'id') || _.get(this.activatedRoute.snapshot, 'params.groupId');
    this.groupsService.getGroupById(groupId, true, true).pipe(takeUntil(this.unsubscribe$)).subscribe(groupData => {
      const user = _.find(_.get(groupData, 'members'), (m) => _.get(m, 'userId') === this.userService.userid);
      if (!user || _.get(groupData, 'status') === 'inactive') {
        this.groupsService.goBack();
      }
      this.groupsService.groupData = groupData;
      this.groupData = groupData;
      this.members = this.groupsService.addFieldsToMember(_.get(this.groupData, 'members'));
      this.memberListToShow = _.cloneDeep(this.members);
      this.showLoader = false;
    }, err => {
      this.showLoader = false;
      this.toasterService.error(this.resourceService.messages.emsg.m002);
      this.groupsService.goBack();
    });
  }

  onActionConfirm(event: any) {
    /* istanbul ignore else */
    if (event.action) {
      switch (event.action) {
        case 'promoteAsAdmin':
          this.promoteMember(event.data);
          break;
        case 'removeFromGroup':
          this.removeMember(event.data);
          break;
        case 'dismissAsAdmin':
          this.dismissRole(event.data);
          break;
      }
    }
  }

  promoteMember(data) {
    this.showLoader = true;
    const memberReq = {
      members: [{
        userId: _.get(data, 'userId'),
        role: GroupMemberRole.ADMIN
      }]
    };
    this.groupsService.updateMembers(this.groupId, memberReq).pipe(takeUntil(this.unsubscribe$)).subscribe(res => {
      this.showLoader = false;
      this.getUpdatedGroupData();
      this.toasterService.success(_.replace(this.resourceService.messages.smsg.promoteAsAdmin, '{memberName}', _.get(data, 'name')));
    }, error => {
      this.showLoader = false;
      this.toasterService.error(_.replace(this.resourceService.messages.emsg.promoteAsAdmin, '{memberName}', _.get(data, 'name')));
    });
  }

  removeMember(data) {
    this.showLoader = true;
    this.groupsService.removeMembers(this.groupId, [_.get(data, 'userId')]).pipe(takeUntil(this.unsubscribe$)).subscribe(res => {
      this.showLoader = false;
      this.getUpdatedGroupData();
      this.toasterService.success(_.replace(this.resourceService.messages.smsg.removeMember, '{memberName}', _.get(data, 'name')));
    }, error => {
      this.showLoader = false;
      this.toasterService.error(this.resourceService.messages.emsg.removeMember);
    });
  }

  dismissRole(data) {
    this.showLoader = true;
    const req = {
      members: [{
        userId: _.get(data, 'userId'),
        role: GroupMemberRole.MEMBER
      }]
    };
    this.groupsService.updateMembers(this.groupId, req).pipe(takeUntil(this.unsubscribe$)).subscribe(res => {
      this.showLoader = false;
      this.getUpdatedGroupData();
      this.toasterService.success(_.replace(this.resourceService.messages.smsg.dissmissAsAdmin, '{memberName}', _.get(data, 'name')));
    }, error => {
      this.showLoader = false;
      this.toasterService.error(this.resourceService.messages.emsg.dissmissAsAdmin);
    });
  }

   /**
   * @description - To set the telemetry Intract event data
   * @param  {} edata? - it's an object to specify the type and subtype of edata
   */
  addTelemetry(id, extra?, edata?) {
    this.groupsService.addTelemetry({id, extra, edata}, this.activatedRoute.snapshot, [], this.groupId);
  }

  showAddMember () {
    if (!this.groupData.active || !this.config.showAddMemberButton) {
      return false;
    }
    return (this.groupData['isAdmin'] && !this.showSearchResults);
  }

  ngOnDestroy() {
    this.unsubscribe$.next();
    this.unsubscribe$.complete();
  }

  resetValue() {
    this.searchInputBox.nativeElement.value = '';
    this.search('');
  }
}
<div class="flex-dc d-flex p-8 py-24 sb-bg-color-white br-4 sb-groups-members-card">
  <div class="title mb-16 font-weight-bold px-8">
    {{resourceService?.frmelmnts?.lbl?.members}}
    <span *ngIf="config?.showMemberCount" class="badge">{{groupData?.members?.length}}</span>
  </div>

  <div class="sb-library-cards">
    <div class="px-8" *ngIf="config?.showSearchBox">
      <div class="sb-search-box no-btn mb-16">
        <div class="input-div relative">
          <i class="search icon" aria-hidden="true"></i>
          <label for="search-within-group" class="hide">{{resourceService?.frmelmnts?.lbl?.searchWithinGroup}}</label>
          <input class="sb-search-input" id="search-within-group" type="text" #searchInputBox (input)="search(searchInputBox.value)"
            [placeholder]="resourceService?.frmelmnts?.lbl?.searchWithinGroup"/>
            <i class="icon close mt-4" (click)="resetValue();"></i>
        </div>
        <button class="sb-btn sb-btn-normal">{{resourceService?.frmelmnts?.lbl?.search}}</button>
      </div>
    </div>

    <div  *ngIf="showAddMember()" tabindex="0" (click)="addMember();addTelemetry('add-member-btn', '', { type: ADD_MEMBER})">
      <div class="cursor-pointer mb-8 fnormal px-8">
        <img alt="admin" src="./assets/images/add-member-1.png" width="32">
        {{resourceService?.frmelmnts?.lbl?.addMember}}
      </div>
      <div class="devided-line m-8"></div>
    </div>

    <div class="d-flex flex-dc" *ngIf="memberListToShow?.length && !showLoader">
      <div *ngFor="let member of memberListToShow" class="relative">
        <sb-member-card [title]="member?.title" [identifier]="member?.identifier" [config]="memberCardConfig"
          [isAdmin]="member?.isAdmin" [isMenu]="member?.isMenu && groupData?.active" [indexOfMember]="member?.indexOfMember"
          [initial]="member?.initial" (menuClick)="getMenuData($event, member)">
        </sb-member-card>
        <div class="kabab-menu-dropdown-content"
          *ngIf="showKebabMenu && selectedMember?.identifier === member?.identifier">
          <div class="list mb-8" tabindex="0" (click)="openModal('promoteAsAdmin')" *ngIf="!member?.isAdmin">
            <span>{{resourceService?.frmelmnts?.btn?.makeAdmin}}</span>
          </div>
          <div class="list mb-8" tabindex="0" (click)="openModal('dismissAsAdmin')" *ngIf="member?.isAdmin && !member?.isCreator">
            <span>{{resourceService?.frmelmnts?.btn?.dismissAdmin}}</span>
          </div>
          <div class="list sb-color-error" tabindex="0" (click)="openModal('removeFromGroup')" *ngIf="!member?.isCreator">
            <span>{{resourceService?.frmelmnts?.btn?.removeMember}}</span>
          </div>
        </div>
      </div>
    </div>

    <div class="d-flex flex-dc" *ngIf="showLoader"><!--showLoader && !memberListToShow?.length -->
      <div *ngFor="let item of [0,1,2,3]">
        <sb-member-card [isLoading]="true" [config]="memberCardConfig"></sb-member-card>
      </div>
    </div>

    <!--No Group member except admin-->
    <div class="d-flex flex-dc flex-jc-center flex-ai-center text-center my-24"
      *ngIf="memberListToShow?.length < 2 && !showSearchResults">
      <img width="197" alt="" src="./assets/images/add-member@2x.svg">
    </div>

    <!--No search results -->
    <div class="member-no-result pt-32" *ngIf="showSearchResults && !memberListToShow?.length">
      <div class="d-flex flex-dc flex-jc-center flex-ai-center text-center">
        <img alt="" height="165" width="206" src="./assets/images/group-search-empty.svg">
        <div class="mt-16 no-result-text">
          {{resourceService?.frmelmnts?.lbl?.NoSerchGroupMemberResults}}
        </div>
        <div class="my-8 no-result-desc hide">
          <div>{{resourceService?.frmelmnts?.lbl?.checkYourSpelling}}</div>
          <div>{{resourceService?.frmelmnts?.lbl?.similarButDiffName}}</div>
        </div>
      </div>
    </div>
  </div>
</div>
<app-member-actions *ngIf="showModal" [action]="memberAction" [member]="selectedMember" (modalClose)="onModalClose()"
  (actionConfirm)="onActionConfirm($event)"></app-member-actions>

./group-members.component.scss

@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;
@use "pages/kabab-menu" as *;
.devided-line {
    border-bottom: calculateRem(0.5px) solid var(--gray-100);
}
.member-no-result {
    .no-result-text {
        font-size: calculateRem(14px);
    }
    .no-result-desc {
        font-size: calculateRem(12px);
        color: var(--gray-200);
    }
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""