File

src/app/profile/certificate-view/certificate-view.page.ts

Implements

OnInit AfterViewInit OnDestroy

Metadata

Index

Properties
Methods

Constructor

constructor(certificateService: CertificateService, certificateDownloadService: CertificateDownloadService, appHeaderService: AppHeaderService, commonUtilService: CommonUtilService, appGlobalService: AppGlobalService, router: Router, fileOpener: FileOpener, toastController: ToastController, popoverCtrl: PopoverController, platform: Platform, telemetryGeneratorService: TelemetryGeneratorService, location: Location, apiService: UnnatiDataService)
Parameters :
Name Type Optional
certificateService CertificateService No
certificateDownloadService CertificateDownloadService No
appHeaderService AppHeaderService No
commonUtilService CommonUtilService No
appGlobalService AppGlobalService No
router Router No
fileOpener FileOpener No
toastController ToastController No
popoverCtrl PopoverController No
platform Platform No
telemetryGeneratorService TelemetryGeneratorService No
location Location No
apiService UnnatiDataService No

Methods

Private generateDownloadTypeTelemetry
generateDownloadTypeTelemetry(type: string)
Parameters :
Name Type Optional
type string No
Returns : void
getProjectCertificate
getProjectCertificate()
Returns : void
Private initCertificateTemplate
initCertificateTemplate(template: string)
Parameters :
Name Type Optional
template string No
Returns : void
Private Async listenActionEvents
listenActionEvents(option)
Parameters :
Name Optional
option No
Returns : any
Private Async loadCertificate
loadCertificate()
Returns : any
ngAfterViewInit
ngAfterViewInit()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
Public onGestureEvent
onGestureEvent(ev)
Parameters :
Name Optional
ev No
Returns : void
Async showCertificateMenu
showCertificateMenu(event)
Parameters :
Name Optional
event No
Returns : any

Properties

acceptType
Type : string
Default value : 'image/svg+xml'
Private activeUserId
Type : string
certificateContainer
Type : ElementRef
Decorators :
@ViewChild('certificateContainer', {static: true})
Private gestureState
Type : object
Default value : { posX: 0, posY: 0, scale: 1, last_scale: 1, last_posX: 0, last_posY: 0, max_pos_x: 0, max_pos_y: 0, transform: '' }
headerConfig
Type : any
message
Type : string
onPopupOpen
Default value : false
pageData
Type : literal type
Public platform
Type : Platform
projectData
Type : any
scrollWrap
Type : ElementRef
Decorators :
@ViewChild('scrollWrap', {static: true})
import { AfterViewInit, Component, ElementRef, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { ApplicationHeaderKebabMenuComponent } from '@app/app/components/application-header/application-header-kebab-menu.component';
import { urlConstants } from '@app/app/manage-learn/core/constants/urlConstants';
import { AppGlobalService, AppHeaderService, Environment, InteractSubtype, PageId, TelemetryGeneratorService } from '@app/services';
import { CommonUtilService } from '@app/services/common-util.service';
import { FileOpener } from '@ionic-native/file-opener/ngx';
import { Platform, PopoverController, ToastController } from '@ionic/angular';
import { CourseCertificate } from '@project-sunbird/client-services/models';
import { tap } from 'rxjs/operators';
import { CertificateDownloadService } from 'sb-svg2pdf';
import { CertificateService, InteractType } from 'sunbird-sdk';
import { Location } from '@angular/common';
import { UnnatiDataService } from '@app/app/manage-learn/core/services/unnati-data.service';
declare var cordova;

@Component({
  selector: 'app-certificate-view',
  templateUrl: './certificate-view.page.html',
  styleUrls: ['./certificate-view.page.scss'],
  providers: [CertificateDownloadService]
})
export class CertificateViewPage implements OnInit, AfterViewInit, OnDestroy {
  @ViewChild('certificateContainer', {static: true}) certificateContainer: ElementRef;
  @ViewChild('scrollWrap', {static: true}) scrollWrap: ElementRef;

  private activeUserId: string;

  pageData: {
    courseId: string;
    certificate: CourseCertificate;
  };
  acceptType = 'image/svg+xml';
  private gestureState = {
    posX: 0,
    posY: 0,
    scale: 1,
    last_scale: 1,
    last_posX: 0,
    last_posY: 0,
    max_pos_x: 0,
    max_pos_y: 0,
    transform: ''
  };
  headerConfig: any;
  onPopupOpen = false;
  projectData:any;
  message:string;
  constructor(
    @Inject('CERTIFICATE_SERVICE') private certificateService: CertificateService,
    private certificateDownloadService: CertificateDownloadService,
    private appHeaderService: AppHeaderService,
    private commonUtilService: CommonUtilService,
    private appGlobalService: AppGlobalService,
    private router: Router,
    private fileOpener: FileOpener,
    private toastController: ToastController,
    private popoverCtrl: PopoverController,
    public platform: Platform,
    private telemetryGeneratorService: TelemetryGeneratorService,
    private location: Location,
    private apiService : UnnatiDataService
  ) {}

  ngOnInit() {
    this.appGlobalService.getActiveProfileUid().then((activeUserId) => this.activeUserId = activeUserId);
    let paramData = this.router.getCurrentNavigation().extras.state.request;
      if( paramData.type == 'project'){
        this.projectData =  paramData;
        let keys = Object.keys(this.projectData.certificate);
        if( this.projectData.certificate &&  this.projectData.certificate.eligible && this.projectData.certificate.osid){
          this.getProjectCertificate();
        }else{
          if((this.projectData.certificate && (keys[this.projectData.certificate.eligible]  && !this.projectData.certificate.eligible) ) || (this.projectData.certificate && this.projectData.certificate.eligible && !this.projectData.certificate.osid)){
            this.message = 'FRMELEMNTS_MSG_PROJECT_SUBMITTED_CERTIFICATE_SOON'
          }else
          if((this.projectData.certificate && !keys[this.projectData.certificate.eligible] )){
            this.message = 'FRMELEMNTS_MSG_NOT_MET_CERTIFCATE'
          }
        }
      }else{
        this.pageData =paramData;
        this.loadCertificate();
      } 

    this.appHeaderService.showHeaderWithBackButton();
  }

  ngAfterViewInit() {}
  getProjectCertificate(){
    const config ={
      url : urlConstants.API_URLS.PROJECT_CERTIFICATE_DOWNLOAD + this.projectData.certificate.osid,
     headers:{
      template :this.projectData.templateUrl,
      accept:this.acceptType
     }
    }
    this.apiService.get(config).pipe(
      tap(this.initCertificateTemplate.bind(this)),
    ).toPromise();
  }
  ngOnDestroy() {

  }

  public onGestureEvent(ev) {
    /* istanbul ignore next */
    (/* gesture based pan/zoom */() => {
      const el = this.scrollWrap.nativeElement;

      let {
        posX,
        posY,
        scale,
        last_scale,
        last_posX,
        last_posY,
        max_pos_x,
        max_pos_y,
        transform
      } = this.gestureState;

      // pan
      if (scale !== 1) {
        posX = last_posX + ev.deltaX;
        posY = last_posY + ev.deltaY;
        max_pos_x = Math.ceil((scale - 1) * el.clientWidth / 2);
        max_pos_y = Math.ceil((scale - 1) * el.clientHeight / 2);
        if (posX > max_pos_x) {
          posX = max_pos_x;
        }
        if (posX < -max_pos_x) {
          posX = -max_pos_x;
        }
        if (posY > max_pos_y) {
          posY = max_pos_y;
        }
        if (posY < -max_pos_y) {
          posY = -max_pos_y;
        }
      }


      // pinch
      if (ev.type === 'pinch') {
        scale = Math.max(.999, Math.min(last_scale * (ev.scale), 4));
      }
      if (ev.type === 'pinchend') {last_scale = scale; }

      // panend
      if (ev.type === 'panend') {
        last_posX = posX < max_pos_x ? posX : max_pos_x;
        last_posY = posY < max_pos_y ? posY : max_pos_y;
      }

      if (scale !== 1) {
        transform =
            'translate3d(' + posX + 'px,' + posY + 'px, 0) ' +
            'scale3d(' + scale + ', ' + scale + ', 1)';
      }

      if (transform) {
        el.style.webkitTransform = transform;
      }

      this.gestureState = {
        posX,
        posY,
        scale,
        last_scale,
        last_posX,
        last_posY,
        max_pos_x,
        max_pos_y,
        transform
      };
    })();
  }

  private async loadCertificate() {
    const loader = await this.commonUtilService.getLoader();
    loader.present();

    await this.certificateService.getCertificate(this.pageData).pipe(
      tap(this.initCertificateTemplate.bind(this)),
    ).toPromise();

    loader.dismiss();
  }

  private initCertificateTemplate(template: string) {
    if (template.startsWith('data:image/svg+xml,')) {
      template = decodeURIComponent(template.replace(/data:image\/svg\+xml,/, '')).replace(/\<!--\s*[a-zA-Z0-9\-]*\s*--\>/g, '');
    }
    
    if (this.platform.is('ios')) {
      template = template.replace("`${maxFontSize}px`", "'18px'");
      template = template.replace("`${minFontSize}px`", "'13px'");
      template = template.replace(/`/gi, "\"");
      var ref = cordova.InAppBrowser.open('', '_blank');
      ref.executeScript( { code : `
        var certs = document.createElement('div');
        certs.setAttribute('id', 'certid');
        document.body.appendChild(certs);`
      } );
  
      let funcExecute = () => {
        ref.executeScript({ code: `
          var certs = document.getElementById('certid');
          certs.innerHTML = \`${template}\`
        ` });
        ref.insertCSS({ code: "body{height: 100%;}" });
      };
      setTimeout(funcExecute, 1000);
      let that = this;
      ref.addEventListener('exit', function (event) {
        that.location.back();
      });
    } else {
      this.certificateContainer.nativeElement.innerHTML = template;
    }
  }

  private async listenActionEvents(option) {
      const toast = await this.toastController.create({
        message: this.commonUtilService.translateMessage('CERTIFICATE_DOWNLOAD_INFO')
      });
      await toast.present();

      try {
        const downloadRequest = await (async () => {
        const baseFileName =  this.pageData ?
          `${this.pageData.certificate.name}_${this.pageData.courseId}_${this.activeUserId}` : `${this.projectData.name}_${this.projectData.project}_${this.activeUserId}`
          switch (option.label) {
            case 'PDF': {
              this.generateDownloadTypeTelemetry('pdf');
              return {
                fileName: baseFileName + '.pdf',
                mimeType: 'application/pdf',
                blob: await this.certificateDownloadService.buildBlob(
                  this.certificateContainer.nativeElement.querySelector('svg'),
                  'pdf'
                )
              };
            }
            case 'PNG': {
              this.generateDownloadTypeTelemetry('png');
              return {
                fileName: baseFileName + '.png',
                mimeType: 'image/png',
                blob: await this.certificateDownloadService.buildBlob(
                  this.certificateContainer.nativeElement.querySelector('svg'),
                  'png'
                )
              };
            }
            default: {
              toast.dismiss();
              throw new Error('INVALID_OPTION');
            }
          }
        })();

        const { path } = await this.certificateService.downloadCertificate(downloadRequest).toPromise();
        await this.fileOpener.open(path, downloadRequest.mimeType);
      } catch (e) {
        this.commonUtilService.showToast(this.commonUtilService.translateMessage('SOMETHING_WENT_WRONG'));
        console.error(e);
      } finally {
        toast.dismiss();
      }

  }

  private generateDownloadTypeTelemetry(type: string) {
    this.telemetryGeneratorService.generateInteractTelemetry(
      type, '',
      Environment.USER,
      PageId.CERTIFICATE_VIEW,
      undefined,
      undefined,
      undefined,
      undefined,
      InteractSubtype.DOWNLOAD_CLICKED
    );
  }

  async showCertificateMenu(event) {
    this.telemetryGeneratorService.generateInteractTelemetry(
      InteractType.TOUCH, InteractSubtype.DOWNLOAD_CLICKED,
      Environment.USER,
      PageId.CERTIFICATE_VIEW
    );
    const certificatePopover = await this.popoverCtrl.create({
      component: ApplicationHeaderKebabMenuComponent,
      event,
      showBackdrop: false,
      componentProps: {
        options: [
          { label: 'PDF', value: {} },
          { label: 'PNG', value: {} },
        ] || []
      },
      cssClass: 'certificate-popup'
    });
    this.onPopupOpen = true;
    certificatePopover.present();
    const { data } = await certificatePopover.onDidDismiss();
    this.onPopupOpen = false;
    if (!data) {
      return;
    }
    this.listenActionEvents(data.option);
  }
}


<ion-content hide-header-footer
             class="main-container avoid-bottom-tabs-space" scrollEvents="true">
<div *ngIf="pageData || (projectData && projectData.certificate.eligible && projectData.certificate.osid)">
  <div class="cert-container">
    <strong class="label">{{'CERTIFICATE' | translate}}</strong>
    <div class="cert-details">
      <div class="cert-info">
        <p class="title"> {{projectData?.name || pageData?.certificate?.name}}</p>
        <p class="date">{{(pageData?.certificate?.lastIssuedOn | date)  || (projectData?.certificate?.issuedOn | date)}}</p>
      </div>
      <div class="download-btn" *ngIf="!platform?.is('ios')">
        <button class="cert-btn" [ngClass]="{'highlight-cert-btn': onPopupOpen, '': !onPopupOpen }" (click)="showCertificateMenu($event)">
          <img src="assets/imgs/download-cloud-white.svg" alt="Download">
          <span>{{'DOWNLOAD' | translate}}</span>
        </button>
      </div>
    </div>
  </div>
  </div>
  <div *ngIf="(projectData  && !projectData.certificate.eligible) || (projectData && !projectData.certificate.osid)">
    <div class="cert-container">
    <strong class="label">{{'CERTIFICATE' | translate}}</strong>
    <div class="text-msg" >
      {{message | translate}}
      </div>
  </div>
    </div>
  <div #scrollWrap
       class="scroll-wrap"
       (pan)="onGestureEvent($event)"
       (pinch)="onGestureEvent($event)"
       (panend)="onGestureEvent($event)"
       (pinchend)="onGestureEvent($event)">
    <div #certificateContainer></div>
  </div>
</ion-content>

./certificate-view.page.scss

.scroll-wrap {
  height: 100%;
  padding: 32px;
}

.cert-container {
  margin: 1rem;
  .label {
    font-size: 1.2rem;
  }
  .cert-details {
    display: flex;
    margin: 1rem 0;
    .cert-info {
      width: 100%;
      .title,
      .date {
        font-size: 1rem;
        margin: 0;
        color: var(--app-gray);
      }
      .date {
        color: var(--app-medium-gray);
      }
    }
    .download-btn{
      width: 60%;
      .cert-btn{
        padding: 0.5rem;
        background-color: var(--app-primary-medium);
        width: 8.75rem !important;
        height: 3.75rem !important;
        img{
          float: left;
          margin-top: 0.2rem;
        }
        span{
          padding: 0 0.5rem;
          line-height: 1.5;
        }
      }
    }
  }
}

.certificate-info {
  display: flex;
  margin: 1rem;
}

.highlight-cert-btn{
  background-color: var(--app-primary);
}
.text-msg{
  margin: 4rem 1rem;
  font-size: 1rem;
  font-weight: 900;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""