src/app/modules/shared-feature/components/global-consent-pii/global-consent-pii.component.ts
                OnInit
    
| selector | app-global-consent-pii | 
| styleUrls | ./global-consent-pii.component.scss | 
| templateUrl | ./global-consent-pii.component.html | 
| Properties | 
| 
 | 
| Methods | 
| Inputs | 
| Outputs | 
| constructor(csUserService: CsUserService, toasterService: ToasterService, userService: UserService, resourceService: ResourceService, tncService: TncService, utilService: UtilService, popupControlService: PopupControlService, activatedRoute: ActivatedRoute, coursesService: CoursesService, router: Router, generaliseLabelService: GeneraliseLabelService) | ||||||||||||||||||||||||||||||||||||
| 
                                    Parameters :
                                     
 | 
| collection | |
| Type : any | |
| consentConfig | |
| Type : any | |
| isglobalConsent | |
| Type : any | |
| profileInfo | |
| Type : any | |
| showConsentPopup | |
| Type : any | |
| type | |
| Type : any | |
| close | |
| Type : EventEmitter | |
| consentShare | |
| Type : EventEmitter | |
| checkQueryParams | 
| checkQueryParams() | 
| 
                        Returns :          void | 
| fetchTncData | 
| fetchTncData() | 
| 
                        Returns :          void | 
| getDeclarationReqObject | ||||
| getDeclarationReqObject(usersProfile) | ||||
| 
                        Parameters :
                        
                         
 
                        Returns :      { operation: string; userId: any; orgId: any; info: any; } | 
| getUserConsent | 
| getUserConsent() | 
| 
                        Returns :          void | 
| getUserInformation | 
| getUserInformation() | 
| 
                        Returns :          void | 
| ngOnDestroy | 
| ngOnDestroy() | 
| 
                        Returns :          void | 
| ngOnInit | 
| ngOnInit() | 
| 
                        Returns :          void | 
| removeQueryParam | 
| removeQueryParam() | 
| 
                        Returns :          void | 
| saveConsent | 
| saveConsent() | 
| 
                        Returns :          void | 
| showAndHidePopup | ||||||
| showAndHidePopup(mode: boolean) | ||||||
| 
                        Parameters :
                        
                         
 
                        Returns :          void | 
| toggleEditSetting | 
| toggleEditSetting() | 
| 
                        Returns :          void | 
| updateUserConsent | ||||||
| updateUserConsent(isActive: boolean) | ||||||
| 
                        Parameters :
                        
                         
 
                        Returns :          void | 
| updateUserDeclaration | ||||
| updateUserDeclaration(request) | ||||
| 
                        Parameters :
                        
                         
 
                        Returns :          void | 
| consentPii | 
| Type : string | 
| Default value : 'Yes' | 
| editSetting | 
| Default value : false | 
| Public generaliseLabelService | 
| Type : GeneraliseLabelService | 
| instance | 
| Type : string | 
| isDataShareOn | 
| Default value : false | 
| isOpen | 
| Default value : false | 
| isTncAgreed | 
| Default value : false | 
| lastUpdatedOn | 
| Type : string | 
| Default value : '' | 
| Public popupControlService | 
| Type : PopupControlService | 
| profileDetailsModal | 
| Decorators : 
                            @ViewChild('profileDetailsModal') | 
| Public resourceService | 
| Type : ResourceService | 
| showSettingsPage | 
| Type : boolean | 
| showTncPopup | 
| Default value : false | 
| termsAndConditionLink | 
| Type : string | 
| Public tncService | 
| Type : TncService | 
| unsubscribe | 
| Default value : new Subject<void>() | 
| userInformation | 
| Type : [] | 
| Default value : [] | 
| Public userService | 
| Type : UserService | 
| Private usersProfile | 
| Type : any | 
| Public utilService | 
| Type : UtilService | 
import { Component, Inject, Input, OnInit, ViewChild, Output, EventEmitter } from '@angular/core';
import { Consent, ConsentStatus } from '@project-sunbird/client-services/models';
import { CsUserService } from '@project-sunbird/client-services/services/user/interface';
import { TncService, UserService, CoursesService, GeneraliseLabelService } from '@sunbird/core';
import { ResourceService, ServerResponse, ToasterService, UtilService } from '@sunbird/shared';
import * as _ from 'lodash-es';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { PopupControlService } from '../../../../service/popup-control.service';
import { ActivatedRoute, Router } from '@angular/router';
@Component({
  selector: 'app-global-consent-pii',
  templateUrl: './global-consent-pii.component.html',
  styleUrls: ['./global-consent-pii.component.scss']
})
export class GlobalConsentPiiComponent implements OnInit {
  @Input() collection;
  @Input() type;
  @Input() showConsentPopup;
  @Input() consentConfig;
  @Input() isglobalConsent;
  @Input() profileInfo;
  @ViewChild('profileDetailsModal') profileDetailsModal;
  @Output() close = new EventEmitter<any>();
  @Output() consentShare = new EventEmitter<any>();
  isOpen = false;
  instance: string;
  consentPii = 'Yes';
  isDataShareOn = false;
  lastUpdatedOn = '';
  userInformation = [];
  editSetting = false;
  isTncAgreed = false;
  // showConsentPopup = false;
  showTncPopup = false;
  termsAndConditionLink: string;
  unsubscribe = new Subject<void>();
  private usersProfile: any;
  showSettingsPage: boolean;
  constructor(
    @Inject('CS_USER_SERVICE') private csUserService: CsUserService,
    private toasterService: ToasterService,
    public userService: UserService,
    public resourceService: ResourceService,
    public tncService: TncService,
    public utilService: UtilService,
    public popupControlService: PopupControlService,
    private activatedRoute: ActivatedRoute,
    private coursesService: CoursesService,
    private router: Router,
    public generaliseLabelService: GeneraliseLabelService
  ) {
    this.instance = (<HTMLInputElement>document.getElementById('instance'))
      ? (<HTMLInputElement>document.getElementById('instance')).value.toUpperCase() : 'SUNBIRD';
  }
  ngOnInit() {
    this.usersProfile = _.cloneDeep(this.userService.userProfile);
    this.getUserInformation();
    this.getUserConsent();
    if (this.isglobalConsent || this.type === 'program-consent') {
      this.showSettingsPage = false;
    } else {
      this.showSettingsPage = true;
    }
    this.checkQueryParams();
    this.coursesService.revokeConsent
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((res) => {
        this.updateUserConsent(false);
      });
  }
  checkQueryParams() {
    this.activatedRoute.queryParams
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(response => {
        if (response.consent) {
          if (this.type === 'course-consent' || this.type === 'global-consent') {
            this.showConsentPopup = true;
          }
          this.removeQueryParam();
        }
      });
  }
  getUserInformation() {
    this.userInformation['name'] = this.usersProfile.lastName ?
     `${this.usersProfile.firstName} ${this.usersProfile.lastName}` : this.usersProfile.firstName;
    this.userInformation['userid'] = this.usersProfile.userId;
    this.userInformation['emailId'] = this.usersProfile.email;
    this.userInformation['phone'] = this.usersProfile.phone;
    if (this.usersProfile && this.usersProfile.externalIds) {
      _.forEach(this.usersProfile.externalIds, (externaleId) => {
        if (externaleId.provider === this.usersProfile.channel) {
          this.userInformation['externalId'] = externaleId.id;
        }
      });
    }
    if (_.get(this.usersProfile, 'userLocations.length')) {
      this.usersProfile.userLocations.forEach(locDetail => {
        switch (locDetail.type) {
          case 'state':
            this.userInformation['state'] = locDetail.name;
            break;
          case 'district':
            this.userInformation['district'] = locDetail.name;
            break;
          case 'block':
            this.userInformation['block'] = locDetail.name;
            break;
          case 'school':
            this.userInformation['schoolName'] = locDetail.name;
            this.userInformation['schoolId'] = locDetail.code;
            break;
        }
      });
    }
    if (_.get(this.usersProfile, 'declarations.length')) {
      for (const [key, value] of Object.entries(this.usersProfile.declarations[0].info)) {
        switch (key) {
          case 'declared-email':
            this.userInformation['emailId'] = value;
            break;
          case 'declared-phone':
            this.userInformation['phone'] = value;
            break;
          case 'declared-school-udise-code':
            this.userInformation['schoolId'] = this.userInformation['schoolId'] || value;
            break;
          case 'declared-school-name':
            this.userInformation['schoolName'] = this.userInformation['schoolName'] || value;
            break;
        }
      }
    }
    if (this.profileInfo) {
      this.userInformation = _.assign(this.userInformation, this.profileInfo);
    }
  }
  fetchTncData() {
    this.tncService.getTncConfig().pipe(takeUntil(this.unsubscribe)).subscribe((data: ServerResponse) => {
      const response = _.get(data, 'result.response.value');
      if (response) {
        try {
          const tncConfig = this.utilService.parseJson(response);
          const version = _.get(tncConfig, 'latestVersion') || {};
          this.termsAndConditionLink = tncConfig[version].url;
        } catch (e) {
          this.toasterService.error(_.get(this.resourceService, 'messages.fmsg.m0004'));
        }
      }
    }, () => {
      this.toasterService.error(_.get(this.resourceService, 'messages.fmsg.m0004'));
    }
    );
  }
  saveConsent() {
    const isActive = _.upperCase(this.consentPii) === 'YES';
    if (isActive) {
      this.showConsentPopup = true;
    } else {
      this.updateUserConsent(isActive);
    }
    this.toggleEditSetting();
  }
  toggleEditSetting() {
    this.editSetting = !this.editSetting;
  }
  showAndHidePopup(mode: boolean) {
    this.showTncPopup = mode;
    this.popupControlService.changePopupStatus(true);
  }
  getUserConsent() {
    const request = {
      userId: this.userService.userid,
      consumerId: '',
      objectId: ''
    };
    if (this.type === 'course-consent') {
      request.consumerId = this.collection ? this.collection.channel : '';
      request.objectId = this.collection ? this.collection.identifier : '';
    } else if ( this.type === 'global-consent') {
      request.consumerId = this.userService.channel;
      request.objectId = this.userService.channel;
      const declReq = [];
      if (this.getDeclarationReqObject(this.usersProfile)) {
        declReq.push(this.getDeclarationReqObject(this.usersProfile));
        this.updateUserDeclaration(declReq);
      }
    } else if(this.type === 'program-consent'){
      request.consumerId = this.collection.rootOrganisations;
      request.objectId = this.collection.programId
    }
    this.csUserService.getConsent(request, { apiPath: '/learner/user/v1' })
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(res => {
        if (this.type === 'global-consent') {
          this.showConsentPopup = false;
          this.type = '';
          this.isglobalConsent = false;
        }
        this.isDataShareOn = _.get(res, 'consents[0].status') === ConsentStatus.ACTIVE;
        this.consentPii = this.isDataShareOn ? 'No' : 'Yes';
        this.lastUpdatedOn = _.get(res, 'consents[0].lastUpdatedOn') || '';
      }, error => {
        console.error('error', error);
        if (error.code === 'HTTP_CLIENT_ERROR' && _.get(error, 'response.responseCode') === 404) {
          this.showConsentPopup = true;
        } else {
          this.toasterService.error(_.get(this.resourceService, 'messages.fmsg.m0004'));
        }
      });
  }
  updateUserConsent(isActive: boolean) {
    this.showConsentPopup = false;
    const request: Consent = {
      status: isActive ? ConsentStatus.ACTIVE : ConsentStatus.REVOKED,
      userId: this.userService.userid,
      consumerId: '',
      objectId: '',
      objectType: ''
    };
    if (this.type === 'course-consent') {
      request.consumerId = this.collection ? this.collection.channel : '';
      request.objectId = this.collection ? this.collection.identifier : '';
      request.objectType = 'Collection';
    } else if ( this.type === 'global-consent') {
      request.consumerId = this.userService.channel;
      request.objectId = this.userService.channel;
      request.objectType = 'Organisation';
    } else if(this.type === 'program-consent'){
      request.consumerId = this.collection.rootOrganisations;
      request.objectId = this.collection.programId;
      request.objectType = 'Program'
    }
    this.csUserService.updateConsent(request, { apiPath: '/learner/user/v1' })
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(() => {
        if(this.type === 'program-consent'){
          this.consentShare.emit({consent:true})
        }
        this.type !== 'program-consent' && this.toasterService.success(_.get(this.resourceService, 'messages.smsg.dataSettingSubmitted'));
        this.getUserConsent();
        this.close.emit();
        this.popupControlService.changePopupStatus(true);
      }, error => {
        this.isTncAgreed = false;
        this.toasterService.error(_.get(this.resourceService, 'messages.emsg.m0005'));
        console.error('Error while updating user consent', error);
        if(this.type === 'program-consent'){
          this.consentShare.emit({consent:false})
        }
      });
  }
  removeQueryParam() {
    this.router.navigate([], {
      queryParams: { 'consent': null },
      queryParamsHandling: 'merge',
      replaceUrl: true
    });
  }
  updateUserDeclaration(request) {
    this.csUserService.updateUserDeclarations(request, { apiPath: '/learner/user/v1' })
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(() => {
        this.toasterService.success(_.get(this.resourceService, 'messages.smsg.m0037'));
    }, err => {
      this.toasterService.error(this.resourceService.messages.emsg.m0052);
    });
  }
  getDeclarationReqObject(usersProfile) {
    let userExternalId = null;
    if (usersProfile && usersProfile.externalIds) {
      _.forEach(usersProfile.externalIds, (externaleId) => {
        if (externaleId.provider === usersProfile.channel) {
          userExternalId = externaleId.id;
        }
      });
    }
    const info: any = {
      'declared-ext-id': userExternalId,
      'declared-phone': '',
      'declared-email': ''
    };
    const declarationObj = {
      operation: 'add',
      userId : usersProfile.userId,
      orgId: usersProfile.rootOrgId,
      info: info
    };
    if (userExternalId) {
      return declarationObj;
    } else {
      return null;
    }
  }
  ngOnDestroy() {
    this.unsubscribe.next();
    this.unsubscribe.complete();
    if (_.get(this.profileDetailsModal, 'deny')) {
      this.profileDetailsModal.deny();
    }
  }
}<mat-accordion class="sb-mat-accordion mb-16" *ngIf="showSettingsPage">
  <mat-expansion-panel>
    <mat-expansion-panel-header>
      <mat-panel-title class="sb-mat-accordion__title">
        {{resourceService?.frmelmnts?.lbl?.dataSetting}}
      </mat-panel-title>
    </mat-expansion-panel-header>
    <div class="sb-mat-accordion__content" role="region" id="dataSetting"
      aria-labelledby="dataSetting">
      <label class="fnormal font-weight-normal text-uppercase">{{resourceService?.frmelmnts?.lbl?.dataSharingIs}}
        <span>{{ isDataShareOn ? resourceService?.frmelmnts?.lbl?.on : resourceService?.frmelmnts?.lbl?.off }}</span>
      </label>
      <p class="fsmall mb-0" *ngIf="isDataShareOn">{{resourceService?.frmelmnts?.lbl?.dataShareOnNote}}</p>
      <p class="fsmall mb-0" *ngIf="!isDataShareOn">{{resourceService?.frmelmnts?.lbl?.dataShareOffNote}}</p>
      <label class="fsmall font-weight-normal data-labels"
        *ngIf="lastUpdatedOn">{{resourceService?.frmelmnts?.lbl?.lastUpdatedOn}} {{lastUpdatedOn | date
        :'dd/MM/yyyy'}}</label>
      <div class="d-flex flex-ai-end flex-jc-flex-end">
        <button class="sb-btn sb-btn-normal sb-btn-link sb-btn-link-primary font-weight-bold"
          (click)="toggleEditSetting()" tabindex="0">
          {{ editSetting ? resourceService?.frmelmnts?.btn?.close : resourceService?.frmelmnts?.lbl?.editSetting }}
        </button>
      </div>
      <div *ngIf="editSetting" class="sb-update-data-settings">
        <hr>
        <label
          class="fsmall mb-0 font-weight-bold data-labels">{{resourceService?.frmelmnts?.lbl?.updateSetting}}</label>
        <div class="d-flex py-8 flex-w-wrap">
          <div class="sb-radio-btn-checkbox sb-radio-btn-primary">
            <input [value]="'Yes'" id="shareConsent" type="radio" [(ngModel)]="consentPii">
            <label for="shareConsent" class="fsmall">{{resourceService?.frmelmnts?.lbl?.shareProfileDetails}}</label>
          </div>
          <div class="sb-radio-btn-checkbox sb-radio-btn-primary">
            <input [value]="'No'" id="noShareContent" type="radio" [(ngModel)]="consentPii">
            <label for="noShareContent"
              class="fsmall">{{resourceService?.frmelmnts?.lbl?.notShareProfileDetails}}</label>
          </div>
        </div>
        <button class="sb-btn sb-btn-normal sb-btn-outline-primary w-100 text-uppercase" tabindex="0"
          (click)="saveConsent()">{{resourceService?.frmelmnts?.btn?.save}}</button>
      </div>
    </div>
  </mat-expansion-panel>
</mat-accordion>
<app-modal-wrapper *ngIf="showConsentPopup" [config]="{disableClose: true, size: 'normal', panelClass: ['overflow-visible', 'material-modal']}"
  (dismiss)="showConsentPopup = false;" #profileDetailsModal>
  <ng-template sbModalContent>
    <div class="sb-mat__modal">
          <!--Header-->
          <div mat-dialog-title class="mb-0 px-16">
            <div class="title">{{resourceService?.frmelmnts?.lbl?.consentsharedetail}}</div>
          </div>
          <!--/Header-->
          <!--Content-->
          <div class="sb-mat__modal__content d-flex flex-dc o-y-visible lineHeight-normal">
            <div class="profile-fields">
              <div class="d-flex mb-16 fnormal">
                <label
                  class="font-weight-bold profile-field-label">{{resourceService?.frmelmnts?.lbl?.dashboardsortbyusername}}<span
                    class="mx-8">:</span></label>
                <div class="font-weight-normal">{{userInformation.name || '-'}}</div>
              </div>
              <div class="d-flex mb-16 fnormal">
                <label class="font-weight-bold profile-field-label">{{resourceService?.frmelmnts?.lbl?.state}}<span
                    class="mx-8">:</span></label>
                <div class="font-weight-normal">{{userInformation.state || '-'}}</div>
              </div>
              <div class="d-flex mb-16 fnormal">
                <label class="font-weight-bold profile-field-label">{{resourceService?.frmelmnts?.lbl?.userId}}<span
                    class="mx-8">:</span></label>
                <div class="font-weight-normal">{{userInformation.userid || '-'}}</div>
              </div>
              <div class="d-flex mb-16 fnormal">
                <label class="font-weight-bold profile-field-label">{{resourceService?.frmelmnts?.lbl?.externalId}}<span
                    class="mx-8">:</span></label>
                <div class="font-weight-normal">{{userInformation.externalId || '-'}}</div>
              </div>
              <div class="d-flex mb-16 fnormal">
                <label class="font-weight-bold profile-field-label">{{resourceService?.frmelmnts?.lbl?.district}}<span
                    class="mx-8">:</span></label>
                <div class="font-weight-normal">{{userInformation.district || '-'}}</div>
              </div>
              <div class="d-flex mb-16 fnormal">
                <label class="font-weight-bold profile-field-label">{{resourceService?.frmelmnts?.lbl?.block}}<span
                    class="mx-8">:</span></label>
                <div class="font-weight-normal">{{userInformation.block || '-'}}</div>
              </div>
              <div class="d-flex mb-16 fnormal">
                <label class="font-weight-bold profile-field-label">{{resourceService?.frmelmnts?.lbl?.schoolId}}<span
                    class="mx-8">:</span></label>
                <div class="font-weight-normal">{{userInformation.schoolId || '-'}}</div>
              </div>
              <div class="d-flex mb-16 fnormal">
                <label class="font-weight-bold profile-field-label">{{resourceService?.frmelmnts?.lbl?.schoolName}}<span
                    class="mx-8">:</span></label>
                <div class="font-weight-normal">{{userInformation.schoolName || '-'}}</div>
              </div>
              <div class="d-flex mb-16 fnormal">
                <label
                  class="font-weight-bold profile-field-label">{{resourceService?.frmelmnts?.lbl?.mobileNumber}}<span
                    class="mx-8">:</span></label>
                <div class="font-weight-normal">{{userInformation.phone || '-'}}</div>
              </div>
              <div class="d-flex mb-16 fnormal">
                <label class="font-weight-bold profile-field-label">{{resourceService?.frmelmnts?.lbl?.emailId}}<span
                    class="mx-8">:</span></label>
                <div class="font-weight-normal">{{userInformation.emailId || '-'}}</div>
              </div>
            </div>
            <div class="mb-16 fnormal font-weight-normal" *ngIf="type === 'course-consent' || type === 'program-consent'">
              <img src="../../../../../../assets/images/info-icon.svg" width="14px" height="14px" class="mr-8"
                alt="info">{{resourceService?.frmelmnts?.lbl?.canEditProfileDetails}}
            </div>
            <p class="mb-0fnormal font-weight-normal">
              <input type="checkbox" [(ngModel)]="isTncAgreed" class="mr-8" aria-label="term and condition checkbox">
              {{consentConfig.tncText | interpolate:'{instance}': instance}}
              <a class="sb-color-primary" href="javascript:void(0)" tabindex="0"
                (click)="showTncPopup=true">{{consentConfig.tncLink | interpolate:'{instance}':
                resourceService?.instance}}</a>
            </p>
          </div>
          <!--/Content-->
          <!--Actions-->
          <div class="sb-mat__modal__actions">
            <button class="sb-btn  sb-btn-normal sb-btn-outline-primary text-uppercase" tabindex="0"
              (click)="updateUserConsent(false)"
              *ngIf="type === 'course-consent' || type === 'program-consent'">{{resourceService?.frmelmnts?.lbl?.dontShare}}</button>
            <button type="button" tabindex="0" [ngClass]="{'sb-btn-disabled': !isTncAgreed}" [disabled]="!isTncAgreed"
              class="sb-btn sb-btn-normal sb-btn-primary text-uppercase ml-8" (click)="updateUserConsent(true)"
              *ngIf="type === 'global-consent'">{{resourceService?.frmelmnts?.lbl?.continue}}</button>
            <button type="button" tabindex="0" [ngClass]="{'sb-btn-disabled': !isTncAgreed}" [disabled]="!isTncAgreed"
            class="sb-btn sb-btn-normal sb-btn-primary text-uppercase ml-8" (click)="updateUserConsent(true)"
            *ngIf="type === 'course-consent' || type === 'program-consent'">{{resourceService?.frmelmnts?.lbl?.share}}</button>
          </div>
          <!--/Actions-->
    </div>
  </ng-template>
</app-modal-wrapper>
<app-tnc-popup (close)="showAndHidePopup(false)" [tncUrl]="termsAndConditionLink" *ngIf="showTncPopup">
</app-tnc-popup>
                    ./global-consent-pii.component.scss
                
@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;
.sb-modal-profile-details {
    input[type="checkbox"] {
        width: calculateRem(16px);
        height: calculateRem(16px);
        position: relative;
        top: calculateRem(2px);
    }
}
.profile-fields{
word-break: break-all;
    .profile-field-label{
        width: calculateRem(150px);
        @media screen and (max-width:768px) {
          width: auto;
        }
    }
}