src/app/modules/certificate/components/certificate-details/certificate-details.component.ts
OnInit
OnDestroy
selector | app-certificate-details |
styleUrls | ./certificate-details.component.scss |
templateUrl | ./certificate-details.component.html |
Properties |
|
Methods |
constructor(activatedRoute: ActivatedRoute, certificateService: CertificateService, resourceService: ResourceService, configService: ConfigService, userService: UserService, playerService: PublicPlayerService, router: Router, tenantService: TenantService, CsCertificateService: CsCertificateService, toasterService: ToasterService)
|
|||||||||||||||||||||||||||||||||
Parameters :
|
certificateVerify |
certificateVerify()
|
It will call the validate cert. api and course_details api (after taking courseId)
Returns :
void
|
getCodeLength | ||||||
getCodeLength(event: any)
|
||||||
To handle verify button enable/disable fucntionality
Parameters :
Returns :
void
|
getCourseVideoUrl | ||||||
getCourseVideoUrl(courseId: string)
|
||||||
to get the certtificate video url and courseId from that url
Parameters :
Returns :
void
|
navigateToCoursesPage |
navigateToCoursesPage()
|
To redirect to courses tab (for mobile device, they will handle 'href' change)
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
playContent | ||||||
playContent(contentId: string)
|
||||||
to play content on the certificate details page
Parameters :
Returns :
void
|
processVideoUrl | ||||||
processVideoUrl(url: string)
|
||||||
Parameters :
Returns :
void
|
setTelemetryData |
setTelemetryData()
|
To set the telemetry
Returns :
void
|
validateCertificate |
validateCertificate()
|
Function to validate certificate if URL has
Returns :
void
|
validateTCertificate |
validateTCertificate()
|
Function to validate certificate if URL has
Returns :
void
|
Public activatedRoute |
Type : ActivatedRoute
|
certificateCode |
Type : string
|
Public certificateService |
Type : CertificateService
|
codeInputField |
Type : ElementRef
|
Decorators :
@ViewChild('codeInputField')
|
Public configService |
Type : ConfigService
|
contentId |
Type : string
|
courseName |
Type : string
|
enableVerifyButton |
Default value : false
|
error |
Default value : false
|
instance |
Type : string
|
isInvalidCertificate |
Type : boolean
|
Default value : false
|
issuedOn |
Type : string
|
loader |
Type : boolean
|
logo |
Type : string
|
pageId |
Type : string
|
playerConfig |
Type : PlayerConfig
|
Public playerService |
Type : PublicPlayerService
|
recipient |
Type : string
|
To store the certificate details data |
Public resourceService |
Type : ResourceService
|
Public router |
Type : Router
|
showVideoThumbnail |
Default value : true
|
telemetryCdata |
Type : Array<literal type>
|
Default value : []
|
telemetryImpressionData |
Type : IImpressionEventInput
|
tenantDataSubscription |
Type : Subscription
|
tenantName |
Type : string
|
Public tenantService |
Type : TenantService
|
Public userService |
Type : UserService
|
validateRCCertificate |
Type : boolean
|
Default value : false
|
viewCertificate |
Type : boolean
|
watchVideoLink |
Type : string
|
wrongCertificateCode |
Default value : false
|
import { PublicPlayerService } from '@sunbird/public';
import {CertificateService, UserService, TenantService} from '@sunbird/core';
import { ServerResponse, ResourceService, ConfigService, PlayerConfig, ToasterService } from '@sunbird/shared';
import { Component, OnInit, ViewChild, ElementRef, OnDestroy, Inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import * as _ from 'lodash-es';
import dayjs from 'dayjs';
import { IImpressionEventInput } from '@sunbird/telemetry';
import { Subscription} from 'rxjs';
import { CsCertificateService } from '@project-sunbird/client-services/services/certificate/interface';
@Component({
selector: 'app-certificate-details',
templateUrl: './certificate-details.component.html',
styleUrls: ['./certificate-details.component.scss']
})
export class CertificateDetailsComponent implements OnInit , OnDestroy {
loader: boolean;
viewCertificate: boolean;
error = false;
enableVerifyButton = false;
certificateCode: string;
wrongCertificateCode = false;
instance: string;
telemetryImpressionData: IImpressionEventInput;
telemetryCdata: Array<{}> = [];
pageId: string;
playerConfig: PlayerConfig;
contentId: string;
showVideoThumbnail = true;
logo: string;
tenantName: string;
tenantDataSubscription: Subscription;
/** To store the certificate details data */
recipient: string;
courseName: string;
issuedOn: string;
watchVideoLink: string;
validateRCCertificate: boolean = false;
@ViewChild('codeInputField') codeInputField: ElementRef;
isInvalidCertificate: boolean = false;
constructor(
public activatedRoute: ActivatedRoute,
public certificateService: CertificateService,
public resourceService: ResourceService,
public configService: ConfigService,
public userService: UserService,
public playerService: PublicPlayerService,
public router: Router,
public tenantService: TenantService,
@Inject('CS_CERTIFICATE_SERVICE') private CsCertificateService: CsCertificateService,
private toasterService: ToasterService,
) { }
ngOnInit() {
this.instance = _.upperCase(this.resourceService.instance);
this.pageId = this.activatedRoute.snapshot.data.telemetry.pageid;
if (_.get(this.activatedRoute, 'snapshot.queryParams.data')) {
this.validateRCCertificate = true;
this.validateCertificate();
} else if (_.get(this.activatedRoute, 'snapshot.queryParams.t')) {
this.validateRCCertificate = true;
this.validateTCertificate();
}
this.setTelemetryData();
this.tenantDataSubscription = this.tenantService.tenantData$.subscribe(data => {
if (data && !data.err && data.tenantData) {
this.logo = data.tenantData.logo;
this.tenantName = data.tenantData.titleName;
}
});
}
/** It will call the validate cert. api and course_details api (after taking courseId) */
certificateVerify() {
this.loader = true;
const request = {
request: {
'certId': this.activatedRoute.snapshot.params.uuid,
'accessCode': _.trim(this.certificateCode),
'verifySignature': true,
}
};
this.certificateService.validateCertificate(request).subscribe(
(data: ServerResponse) => {
if (_.get(data, 'result.response.related.certVideoUrl')) {
this.watchVideoLink = _.get(data, 'result.response.related.certVideoUrl');
this.processVideoUrl(this.watchVideoLink);
} else {
this.getCourseVideoUrl(_.get(data, 'result.response.related.courseId'));
}
const certData = _.get(data, 'result.response.json');
this.loader = false;
this.viewCertificate = true;
this.recipient = _.get(certData, 'recipient.name');
this.courseName = _.get(certData, 'badge.name');
this.issuedOn = dayjs(new Date(_.get(certData, 'issuedOn'))).format('DD MMM YYYY');
},
(err) => {
this.wrongCertificateCode = true;
this.loader = false;
this.codeInputField.nativeElement.value = '';
this.codeInputField.nativeElement.focus();
this.enableVerifyButton = false;
}
);
}
/** To handle verify button enable/disable fucntionality */
getCodeLength(event: any) {
this.wrongCertificateCode = false;
if (event.target.value.length === 6) {
this.enableVerifyButton = true;
} else {
this.enableVerifyButton = false;
}
}
/** To redirect to courses tab (for mobile device, they will handle 'href' change) */
navigateToCoursesPage() {
if (this.activatedRoute.snapshot.queryParams.clientId === 'android') {
window.location.href = '/explore-course';
} else {
this.router.navigate(['/explore-course']);
}
}
/** To set the telemetry*/
setTelemetryData() {
const context = { env: this.activatedRoute.snapshot.data.telemetry.env };
if (_.get(this.activatedRoute, 'snapshot.queryParams.clientId') === 'android' &&
_.get(this.activatedRoute, 'snapshot.queryParams.context')) {
const telemetryData = JSON.parse(decodeURIComponent(_.get(this.activatedRoute, 'snapshot.queryParams.context')));
context['env'] = telemetryData.env;
}
this.telemetryImpressionData = {
context: context,
edata: {
type: this.activatedRoute.snapshot.data.telemetry.type,
pageid: this.pageId,
uri: this.router.url
}
};
this.telemetryCdata = [
{
id: 'course:qrcode:scan:cert',
type: 'Feature'
},
{
id: 'SB-13854',
type: 'Task'
}
];
}
/** to get the certtificate video url and courseId from that url */
getCourseVideoUrl(courseId: string) {
this.playerService.getCollectionHierarchy(courseId).subscribe(
(response: ServerResponse) => {
this.watchVideoLink = _.get(response, 'result.content.certVideoUrl');
this.processVideoUrl(this.watchVideoLink);
}, (error) => {
});
}
processVideoUrl(url: string) {
if (url) {
const splitedData = url.split('/');
splitedData.forEach((value) => {
if (value.includes('do_')) {
this.contentId = value;
}
});
}
}
/** to play content on the certificate details page */
playContent(contentId: string) {
this.showVideoThumbnail = false;
const option = { params: this.configService.appConfig.ContentPlayer.contentApiQueryParams };
this.playerService.getContent(contentId, option).subscribe(
(response) => {
const contentDetails = {
contentId: contentId,
contentData: response.result.content
};
this.playerConfig = this.playerService.getConfig(contentDetails);
},
(err) => {
});
}
ngOnDestroy() {
if (this.tenantDataSubscription) {
this.tenantDataSubscription.unsubscribe();
}
}
/**
* @description
* Function to validate certificate if URL has `data` params
*/
validateCertificate() {
this.loader = true;
let url = _.get(this.activatedRoute, 'snapshot.queryParams.data').toString();
url = url.replace(/ /g, "+");
this.CsCertificateService
.getEncodedData(url)
.then((resp) => {
let requestBody = {
certificateData: resp,
schemaName: 'certificate',
certificateId: _.get(this.activatedRoute, 'snapshot.params.uuid'),
};
this.CsCertificateService.verifyCertificate(requestBody, {
apiPath: '/learner/certreg/v2',
apiPathLegacy: '/certreg/v1',
rcApiPath: '/learner/rc/${schemaName}/v1',
}).subscribe(
(data) => {
const certData = _.get(data, 'certificateData');
this.loader = false;
if (_.get(data, 'verified')) {
this.viewCertificate = true;
this.recipient = _.get(certData, 'issuedTo');
this.courseName = _.get(certData, 'trainingName');
this.issuedOn = dayjs(new Date(_.get(certData, 'issuanceDate'))).format('DD MMM YYYY');
} else {
this.viewCertificate = false;
this.isInvalidCertificate = true;
}
},
(err) => {
this.loader = false;
this.viewCertificate = false;
this.isInvalidCertificate = true;
this.toasterService.error(this.resourceService.messages.emsg.m0005);
}
);
}).catch(error => {
this.viewCertificate = false;
this.isInvalidCertificate = true;
});
}
/**
* @description
* Function to validate certificate if URL has `t` params
*/
validateTCertificate() {
let requestBody = {
schemaName: 'certificate',
certificateId: _.get(this.activatedRoute, 'snapshot.params.uuid'),
};
this.CsCertificateService.verifyCertificate(requestBody, {
apiPath: '/learner/certreg/v2',
apiPathLegacy: '/certreg/v1',
rcApiPath: '/learner/rc/${schemaName}/v1',
}).subscribe(
(data) => {
const certData = _.get(data, 'certificateData');
this.loader = false;
if (_.get(data, 'verified')) {
this.viewCertificate = true;
this.recipient = _.get(certData, 'issuedTo');
this.courseName = _.get(certData, 'trainingName');
this.issuedOn = dayjs(new Date(_.get(certData, 'issuanceDate'))).format('DD MMM YYYY');
} else {
this.viewCertificate = false;
this.isInvalidCertificate = true;
}
},
(err) => {
this.loader = false;
this.toasterService.error(this.resourceService.messages.emsg.m0005);
this.viewCertificate = false;
this.isInvalidCertificate = true;
}
);
}
}
<div class="sb-certificatePage-bg" [appTelemetryImpression]="telemetryImpressionData">
<div *ngIf="!viewCertificate && !validateRCCertificate" class="sb-certificatePage" [class.loading]="loader" [class.error]="error">
<div class="sb-certificatePage-overlay"></div>
<div class="sb-certificatePage-header">
<img alt="{{tenantName}}" src="{{logo}}" class="sb-certificatePage-logo" />
</div>
<div class="sb-certificatePage-desc mb-auto m-0">
<div class="sb-certificatePage-loader">
<p>{{resourceService?.frmelmnts?.lbl?.verifyingCertificate}}</p>
<img src="assets/images/loader.gif" class="sb-certificatePage-loader-img" alt="Loader"/>
</div>
<img src="assets/images/certificate.png" class="sb-certificatePage-desc-img" alt="Certificate Desc"/>
</div>
<div class="sb-certificatePage-form mb-auto">
<div class="sb-form-field-group">
<label *ngIf="!wrongCertificateCode" class="sb-certificatePage-label" for="certificate">
{{resourceService?.frmelmnts?.lbl?.enterCertificateCode}}
</label>
<label *ngIf="wrongCertificateCode" class="sb-field-error-label sb-certificatePage-label sb-color-error" for="certificate">
{{resourceService?.frmelmnts?.lbl?.enterValidCertificateCode}}
</label>
<div class="sb-certificatePage-field sb-field" id="certificate">
<input #codeInputField (keyup)="getCodeLength($event)" (keydown.space)="$event.preventDefault();" [(ngModel)]="certificateCode" type="text" maxlength="6" pattern="^[-a-zA-Z0-9@\.+_]+$" required autofocus name="certificate" class="sb-form-control text-center"/>
<button [disabled]="!enableVerifyButton" type="button" class="sb-btn sb-btn-primary sb-btn-normal width-100 mt-32" (click)="certificateVerify()" tabindex="0"
appTelemetryInteract [telemetryInteractEdata]="{id:'verify-certificate-button' , type:'click' , pageid:pageId }"
[telemetryInteractCdata]="telemetryCdata">
{{resourceService?.frmelmnts?.btn?.verify}}
</button>
</div>
</div>
</div>
</div>
<div *ngIf="viewCertificate && !validateRCCertificate">
<div class="sb-certificatePage sb-certificate-view sb-certificatePage-flexHeight">
<div class="sb-certificatePage-header">
<img alt="{{tenantName}}" src="{{logo}}" class="sb-certificatePage-logo"/>
</div>
<div class="sb-certificatePage-holder-details mb-auto">
<img src="assets/images/badge.svg" class="sb-icon-badge mt-24 mb-8" alt="Badge"/>
<p *ngIf="recipient" class="sb-certificatePage-holder-desc sb-certificatePage-holder-desc-primary">
{{resourceService?.frmelmnts?.lbl?.certificateIssuedTo}}
</p>
<h4 *ngIf="recipient" class="sb-certificatePage-holder-name">
{{recipient}}
</h4>
<p *ngIf="courseName && issuedOn" class="sb-certificatePage-holder-desc">
{{resourceService?.frmelmnts?.lbl?.completingCourseSuccessfully}}
<strong class="d-block">“{{courseName}}”</strong>
<span class="d-block">{{resourceService?.frmelmnts?.lbl?.onDiksha | interpolate:'{instance}':instance}}<strong> {{issuedOn}}</strong></span>
</p>
</div>
</div>
<div class="sb-mobileDevice text-center" *ngIf="watchVideoLink">
<div class="sb-mobileDevice-screen">
<div class="sb-mobileDevice-sensors">
<div class="sb-mobileDevice-sensor"></div>
<div class="sb-mobileDevice-speaker"></div>
<div class="sb-mobileDevice-sensor"></div>
</div>
<div class="player-thumbnail" appTelemetryInteract [telemetryInteractEdata]="{id:'watch-video-button' , type:'click' , pageid:pageId }" (click)="playContent(contentId)" tabindex="0" *ngIf="showVideoThumbnail"></div>
<div class="h-100 certificate-area-player" *ngIf="!showVideoThumbnail">
<app-player class="content-player" [overlayImagePath]="'assets/images/featured-content.jpg'" [pageId]="pageId" [isSingleContent]="false" [playerConfig]="playerConfig"></app-player>
</div>
</div>
</div>
<div class="sb-certificatePage sb-certificate-view min-height-auto">
<div class="sb-certificatePage-holder-details">
<a appTelemetryInteract [telemetryInteractEdata]="{id:'return-to-courses-button' , type:'click' , pageid:pageId }" (click)="navigateToCoursesPage()" tabindex="0" class="mt-32 width-100 d-flex flex-jc-space-between p-8 cursor-pointer sb-btn-arrow" title="Return to Courses">
{{resourceService?.frmelmnts?.lbl?.returnToCourses}} <i class="angle right icon"></i>
</a>
</div>
</div>
</div>
<!-- RC Certificate validation -->
<div *ngIf="validateRCCertificate && viewCertificate">
<div class="sb-certificatePage sb-certificate-view sb-certificatePage-flexHeight">
<div class="sb-certificatePage-header">
<img alt="{{tenantName}}" src="{{logo}}" class="sb-certificatePage-logo" />
</div>
<div class="sb-certificatePage-holder-details mb-auto">
<img src="assets/images/badge.svg" class="sb-icon-badge mt-24 mb-8" alt="Badge" />
<p *ngIf="recipient" class="sb-certificatePage-holder-desc sb-certificatePage-holder-desc-primary">
{{resourceService?.frmelmnts?.lbl?.certificateIssuedTo}}
</p>
<h4 *ngIf="recipient" class="sb-certificatePage-holder-name">
{{recipient}}
</h4>
<p *ngIf="courseName && issuedOn" class="sb-certificatePage-holder-desc">
{{resourceService?.frmelmnts?.lbl?.completingCourseSuccessfully}}
<strong class="d-block">“{{courseName}}”</strong>
<span class="d-block">{{resourceService?.frmelmnts?.lbl?.onDiksha | interpolate:'{instance}':instance}}<strong>
{{issuedOn}}</strong></span>
</p>
</div>
</div>
</div>
<div *ngIf="validateRCCertificate && !viewCertificate && isInvalidCertificate" class="sb-certificatePage" [class.loading]="loader" [class.error]="error">
<div class="sb-certificatePage sb-certificate-view sb-certificatePage-flexHeight">
<div class="sb-certificatePage-header">
<img alt="{{tenantName}}" src="{{logo}}" class="sb-certificatePage-logo" />
</div>
<div class="sb-certificatePage-holder-details mb-auto">
<img class="mr-8" src="assets/images/exclamation.svg" width="20px">
{{resourceService?.frmelmnts?.cert?.imsg?.rcInvalid}}
</div>
</div>
</div>
<!-- RC Certificate validation -->
</div>
./certificate-details.component.scss
@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;
.sb-mobileDevice {
.sb-mobileDevice-screen {
height: calvulteRem(202.5px);
width: calculateRem(360px);
border: calculateRem(10px) solid var(--black);
border-radius: calculateRem(15px);
margin: 0 auto;
position: relative;
overflow: hidden;
.sb-mobileDevice-sensors {
position: absolute;
z-index: 9;
top: 50%;
transform: translateY(-50%);
margin: auto;
left: 0;
background: var(--black);
padding: calculateRem(10px) calculateRem(5px) calculateRem(10px) 0;
border-top-right-radius: calculateRem(25px);
border-bottom-right-radius: calculateRem(25px);
.sb-mobileDevice-sensor {
width: calculateRem(8px);
height: calculateRem(8px);
background: var(--black);
border-radius: 50%;
}
.sb-mobileDevice-speaker {
width: calculateRem(5px);
height: calculateRem(74px);
background: var(--black);
border-radius: calculateRem(10px);
margin: calculateRem(10px) 0 calculateRem(10px) calculateRem(1px);
}
}
.sb-mobileDevice-videoScreen {
width: 100%;
height: 100%;
cursor: pointer;
border-radius: calculateRem(5px);
border: none;
}
@media only screen and (min-width: 540px) {
height: calculateRem(340px);
width: calculateRem(680px);
}
@media only screen and (min-width: 769px) {
height: calculateRem(400px);
max-width: calculateRem(800px);
}
}
}
.player-thumbnail {
position: absolute;
top: 0;
left: 0;
width: 100%;
background: url(../../../../../assets/images/featured-content.jpg) no-repeat;
background-size: cover;
background-position: center;
height: 100%;
cursor: pointer;
border-radius: calculateRem(5px);
}
::ng-deep {
.certificate-area-player {
.contentViewerIframeShadow {
height:100% !important;
}
}
}