src/app/modules/certificate/components/certificate-configuration/certificate-configuration.component.ts
OnInit
OnDestroy
selector | app-certificate-configuration |
styleUrls | ./certificate-configuration.component.scss |
templateUrl | ./certificate-configuration.component.html |
constructor(certificateService: CertificateService, userService: UserService, playerService: PlayerService, sanitizer: DomSanitizer, resourceService: ResourceService, certRegService: CertRegService, uploadCertificateService: UploadCertificateService, navigationHelperService: NavigationHelperService, activatedRoute: ActivatedRoute, toasterService: ToasterService, router: Router, telemetryService: TelemetryService, layoutService: LayoutService, formService: FormService)
|
|||||||||||||||||||||||||||||||||||||||||||||
Parameters :
|
window:popstate |
Arguments : '$event'
|
window:popstate(event)
|
|
Public addRule |
addRule()
|
Returns :
void
|
attachCertificateToBatch |
attachCertificateToBatch()
|
Returns :
void
|
cancelSelection |
cancelSelection()
|
Returns :
void
|
certificateCreation |
certificateCreation()
|
Returns :
void
|
checkMultipleAssessment |
checkMultipleAssessment()
|
Returns :
void
|
closeModal | ||||
closeModal(event)
|
||||
Parameters :
Returns :
void
|
closeTemplateDetectModal |
closeTemplateDetectModal()
|
Returns :
void
|
editCertificate |
editCertificate()
|
Returns :
void
|
getBatchDetails | ||||
getBatchDetails(batchId)
|
||||
Parameters :
Returns :
any
|
getCertConfigFields |
getCertConfigFields()
|
Returns :
void
|
getCertificateFormData |
getCertificateFormData()
|
Returns :
any
|
getConfig | |||||||||
getConfig(config: literal type, template)
|
|||||||||
Parameters :
Returns :
{ show: boolean; label: string; name: string; }
|
getCourseDetails | ||||||
getCourseDetails(courseId: string)
|
||||||
Parameters :
Returns :
any
|
getCriteria | ||||
getCriteria(rawDropdownValues)
|
||||
Parameters :
Returns :
any
|
getTemplateList |
getTemplateList()
|
Returns :
any
|
goBack |
goBack()
|
Returns :
void
|
handleCertificateEvent | |||||||||
handleCertificateEvent(event, template: literal type)
|
|||||||||
Parameters :
Returns :
void
|
handleParameterChange | ||||
handleParameterChange(event)
|
||||
Parameters :
Returns :
void
|
initializeFormFields |
initializeFormFields()
|
Returns :
void
|
initializeLabels |
initializeLabels()
|
Returns :
void
|
navigateToCertRules |
navigateToCertRules()
|
Returns :
void
|
navigateToCreateTemplate |
navigateToCreateTemplate()
|
Returns :
void
|
ngAfterViewInit |
ngAfterViewInit()
|
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
onPopState | ||||
onPopState(event)
|
||||
Decorators :
@HostListener('window:popstate', ['$event'])
|
||||
Parameters :
Returns :
void
|
processCertificateDetails | ||||
processCertificateDetails(certTemplateDetails)
|
||||
Parameters :
Returns :
void
|
processCriteria | ||||
processCriteria(criteria)
|
||||
Parameters :
Returns :
void
|
redoLayout |
redoLayout()
|
Returns :
void
|
refreshData |
refreshData()
|
Returns :
void
|
removeRule |
removeRule()
|
Returns :
void
|
removeSelectedCertificate |
removeSelectedCertificate()
|
Returns :
void
|
sendInteractData | ||||
sendInteractData(interactData)
|
||||
Parameters :
Returns :
void
|
setCertEditable |
setCertEditable()
|
Returns :
void
|
setTelemetryImpressionData |
setTelemetryImpressionData()
|
Returns :
void
|
updateCertificate |
updateCertificate()
|
Returns :
void
|
validateForm |
validateForm()
|
Returns :
void
|
addScoreRule |
Default value : false
|
arrayValue |
Type : object
|
Default value : {}
|
batchDetails |
Type : any
|
certConfigModalInstance |
Default value : new CertConfigModel()
|
certEditable |
Default value : true
|
certificate |
Type : any
|
certificateFormConfig |
Type : any
|
certTemplateList |
Type : Array<literal type>
|
Default value : []
|
certTypes |
Type : any
|
config |
Type : literal type
|
configurationMode |
Type : string
|
courseDetails |
Type : any
|
currentState |
Type : any
|
disableAddCertificate |
Default value : true
|
FIRST_PANEL_LAYOUT |
instance |
Type : string
|
isSingleAssessment |
Default value : false
|
isStateCertificate |
Default value : false
|
issueTo |
Type : any
|
isTemplateChanged |
Default value : false
|
layoutConfiguration |
Type : any
|
Public layoutService |
Type : LayoutService
|
Public navigationHelperService |
Type : NavigationHelperService
|
newTemplateIdentifier |
Type : any
|
previewTemplate |
Type : any
|
previewUrl |
Type : string
|
queryParams |
Type : any
|
scoreRange |
Type : any
|
screenStates |
Type : any
|
Default value : { 'default': 'default', 'certRules': 'certRules' }
|
SECOND_PANEL_LAYOUT |
selectCertType |
Decorators :
@ViewChild('selectCertType')
|
selectedTemplate |
Type : any
|
selectRecipient |
Decorators :
@ViewChild('selectRecipient')
|
selectScoreRange |
Decorators :
@ViewChild('selectScoreRange')
|
showAlertModal |
Default value : false
|
showLoader |
Default value : true
|
showPreviewModal |
showTemplateDetectModal |
telemetryImpression |
Type : IImpressionEventInput
|
templateChangeModal |
Decorators :
@ViewChild('templateChangeModal')
|
templateIdentifier |
Type : string
|
Public unsubscribe$ |
Default value : new Subject<void>()
|
Public uploadCertificateService |
Type : UploadCertificateService
|
userPreference |
Type : UntypedFormGroup
|
import { UploadCertificateService } from './../../services/upload-certificate/upload-certificate.service';
import { CertConfigModel } from './../../models/cert-config-model/cert-config-model';
import { Component, OnInit, OnDestroy, ViewChild, HostListener } from '@angular/core';
import { CertificateService, UserService, PlayerService, CertRegService, FormService } from '@sunbird/core';
import * as _ from 'lodash-es';
import { UntypedFormGroup, UntypedFormControl, Validators } from '@angular/forms';
import { ResourceService, NavigationHelperService, ToasterService, LayoutService, COLUMN_TYPE } from '@sunbird/shared';
import { Router, ActivatedRoute } from '@angular/router';
import { combineLatest, of, Subject } from 'rxjs';
import { catchError, tap, map } from 'rxjs/operators';
import { TelemetryService, IImpressionEventInput } from '@sunbird/telemetry';
import { DomSanitizer } from '@angular/platform-browser';
export interface IConfigLabels {
label: string;
name: string;
show: boolean;
}
@Component({
selector: 'app-certificate-configuration',
templateUrl: './certificate-configuration.component.html',
styleUrls: ['./certificate-configuration.component.scss']
})
export class CertificateConfigurationComponent implements OnInit, OnDestroy {
@ViewChild('selectCertType') selectCertType;
@ViewChild('selectRecipient') selectRecipient;
@ViewChild('templateChangeModal') templateChangeModal;
@ViewChild('selectScoreRange') selectScoreRange;
public unsubscribe$ = new Subject<void>();
showPreviewModal;
showTemplateDetectModal;
certTypes: any;
issueTo: any;
telemetryImpression: IImpressionEventInput;
userPreference: UntypedFormGroup;
disableAddCertificate = true;
queryParams: any;
courseDetails: any;
showLoader = true;
certTemplateList: Array<{}> = [];
batchDetails: any;
currentState: any;
screenStates: any = { 'default': 'default', 'certRules': 'certRules' };
selectedTemplate: any;
previewTemplate: any;
configurationMode: string;
certConfigModalInstance = new CertConfigModel();
previewUrl: string;
templateIdentifier: string;
isTemplateChanged = false;
certEditable = true;
config: { select: IConfigLabels, preview: IConfigLabels, remove: IConfigLabels };
certificate: any;
newTemplateIdentifier: any;
showAlertModal = false;
addScoreRule = false;
arrayValue = {};
scoreRange: any;
isSingleAssessment = false;
isStateCertificate = false;
instance: string;
layoutConfiguration: any;
FIRST_PANEL_LAYOUT;
SECOND_PANEL_LAYOUT;
certificateFormConfig: any;
constructor(
private certificateService: CertificateService,
private userService: UserService,
private playerService: PlayerService,
private sanitizer: DomSanitizer,
private resourceService: ResourceService,
private certRegService: CertRegService,
public uploadCertificateService: UploadCertificateService,
public navigationHelperService: NavigationHelperService,
private activatedRoute: ActivatedRoute,
private toasterService: ToasterService,
private router: Router,
private telemetryService: TelemetryService,
public layoutService: LayoutService,
private formService: FormService) {
this.instance = (<HTMLInputElement>document.getElementById('instance'))
? (<HTMLInputElement>document.getElementById('instance')).value : 'sunbird';
}
/**
* @description - It will handle back button click.
*/
@HostListener('window:popstate', ['$event'])
onPopState(event) {
if (this.isTemplateChanged) {
this.isTemplateChanged = false;
}
}
/**
* @since - release-3.2.10
* @description - It will prepare all the necessary data along with the apis.
*/
ngOnInit() {
this.initializeLabels();
this.layoutConfiguration = this.layoutService.initlayoutConfig();
this.redoLayout();
this.currentState = this.screenStates.default;
this.uploadCertificateService.certificate.subscribe(res => {
if (res && !_.isEmpty(res)) {
this.showAlertModal = true;
this.currentState = 'certRules';
this.showPreviewModal = false;
this.newTemplateIdentifier = _.get(res , 'identifier');
}
});
this.navigationHelperService.setNavigationUrl();
this.initializeFormFields();
this.activatedRoute.queryParams.subscribe((params) => {
this.queryParams = params;
this.configurationMode = _.get(this.queryParams, 'type');
});
combineLatest(
this.getCourseDetails(_.get(this.queryParams, 'courseId')),
this.getBatchDetails(_.get(this.queryParams, 'batchId')),
this.getTemplateList(),
this.getCertificateFormData()
).subscribe((data) => {
this.showLoader = false;
this.checkMultipleAssessment();
}, (error) => {
this.showLoader = false;
this.toasterService.error(this.resourceService.messages.emsg.m0005);
});
}
checkMultipleAssessment() {
try {
const contentTypes = JSON.parse(_.get(this.courseDetails, 'contentTypesCount'));
const selfAssessCount = _.get(contentTypes, 'SelfAssess');
if (selfAssessCount && selfAssessCount > 1) {
this.isSingleAssessment = false;
} else if (selfAssessCount && selfAssessCount == 1) {
this.isSingleAssessment = true;
} else {
this.isSingleAssessment = false;
}
} catch (error) {
console.log(error)
}
}
certificateCreation() {
this.currentState = this.screenStates.certRules;
}
/**
* @description - It will trigger impression telemetry event once the view is ready.
*/
ngAfterViewInit() {
this.setTelemetryImpressionData();
}
/**
* @description - It will prepare the config data for the hover activity of the cert-list cards.
*/
initializeLabels() {
this.config = {
select: {
label: _.get(this.resourceService, 'frmelmnts.lbl.Select'),
name: 'Select',
show: true
},
preview: {
label: _.get(this.resourceService, 'frmelmnts.cert.lbl.preview'),
name: 'Preview',
show: true
},
remove: {
label: _.get(this.resourceService, 'frmelmnts.cert.lbl.unselect'),
name: 'Remove',
show: false
}
};
}
/**
* @description - It will fetch the drop-down values by calling the preference api with proper request payload.
*/
getCertConfigFields() {
const request = {
request: {
orgId: _.get(this.userService, 'userProfile.rootOrgId'),
key: 'certRules'
}
};
this.certificateService.fetchCertificatePreferences(request).subscribe(certRulesData => {
const dropDownValues = this.certConfigModalInstance.getDropDownValues(_.get(certRulesData, 'result.response.data.fields'));
this.certTypes = _.get(dropDownValues, 'certTypes');
this.issueTo = _.get(dropDownValues, 'issueTo');
this.scoreRange = _.get(dropDownValues, 'scoreRange');
}, error => {
this.toasterService.error(this.resourceService.messages.emsg.m0005);
});
}
/**
* @description - It will fetch list of certificate templates from preference api.
*/
getTemplateList() {
const request = {
'request': {
'filters': {
'certType': 'cert template',
'channel': this.userService.channel,
'mediaType': 'image'
},
'sort_by': {
'lastUpdatedOn': 'desc'
},
'fields': ['indentifier', 'name', 'code', 'certType', 'data', 'issuer', 'signatoryList', 'artifactUrl', 'primaryCategory', 'channel'],
'limit': 100
}
};
return this.uploadCertificateService.getCertificates(request).pipe(
tap((certTemplateData) => {
const templatList = _.get(certTemplateData, 'result.content');
this.certTemplateList = templatList;
// To select the newly created certificate
let tempIdToSelect;
if (this.newTemplateIdentifier) {
tempIdToSelect = this.newTemplateIdentifier;
} else {
tempIdToSelect = this.templateIdentifier;
}
const templateData = templatList.find(templat => tempIdToSelect && (templat.identifier === tempIdToSelect));
if (templateData) {
_.remove(this.certTemplateList, (cert) => _.get(cert, 'identifier') === _.get(templateData , 'identifier'));
this.certTemplateList.unshift(templateData);
this.selectedTemplate = templateData;
}
}), catchError(error => {
return of({});
})
);
}
refreshData() {
this.getTemplateList().subscribe(response => {
}, (error) => {
this.toasterService.error(this.resourceService.messages.emsg.m0005);
});
}
/**
* @param {string} batchId
* @description - It will fetch the batch details.
*/
getBatchDetails(batchId) {
return this.certificateService.getBatchDetails(batchId).pipe(
tap(batchDetails => {
this.batchDetails = _.get(batchDetails, 'result.response');
const cert_templates = _.get(this.batchDetails, 'cert_templates');
if (_.isEmpty(cert_templates)) {
this.getCertConfigFields();
} else {
// Certifciate has attached to a batch
if (_.isArray(cert_templates)) {
this.batchDetails.cert_templates = cert_templates[0];
}
this.processCertificateDetails(cert_templates);
}
})
);
}
initializeFormFields() {
this.userPreference = new UntypedFormGroup({
scoreRange: new UntypedFormControl(''),
issueTo: new UntypedFormControl('', [Validators.required]),
allowPermission: new UntypedFormControl('', [Validators.required])
});
this.userPreference.valueChanges.subscribe(val => {
this.validateForm();
});
}
validateForm() {
if (this.userPreference.status === 'VALID'
&& _.get(this.userPreference, 'value.allowPermission') && !_.isEmpty(this.selectedTemplate)) {
this.disableAddCertificate = false;
} else {
this.disableAddCertificate = true;
}
}
/**
* @param {string} courseId
* @description - It will fetch the course details.
*/
getCourseDetails(courseId: string) {
return this.playerService.getCollectionHierarchy(courseId).pipe(
tap(courseData => {
this.courseDetails = _.get(courseData, 'result.content');
}, catchError(error => {
return of({});
}))
);
}
/**
* @description - It will check for the template change or update the certificate.
*/
updateCertificate() {
if (this.templateIdentifier !== _.get(this.selectedTemplate, 'name')) {
this.isTemplateChanged = true;
} else {
this.attachCertificateToBatch();
}
}
attachCertificateToBatch() {
this.sendInteractData({ id: this.configurationMode === 'add' ? 'attach-certificate' : 'confirm-template-change' });
if (this.addScoreRule === false) {
this.userPreference.value['scoreRange'] = null;
}
const request = {
'request': {
'batch': {
'courseId': _.get(this.queryParams, 'courseId'),
'batchId': _.get(this.queryParams, 'batchId'),
'template': {
'identifier': _.get(this.selectedTemplate, 'identifier'),
'criteria': this.getCriteria(this.userPreference.value),
'name': _.get(this.selectedTemplate, 'name'),
'issuer': JSON.parse(_.get(this.selectedTemplate, 'issuer')),
'data': JSON.stringify(_.get(this.selectedTemplate, 'data')),
'previewUrl': _.get(this.selectedTemplate, 'artifactUrl'),
'signatoryList': JSON.parse(_.get(this.selectedTemplate, 'signatoryList'))
}
}
}
};
if (this.isTemplateChanged) {
request['request']['oldTemplateId'] = this.templateIdentifier;
}
this.certRegService.addCertificateTemplate(request).subscribe(data => {
this.isTemplateChanged = false;
if (this.configurationMode === 'add') {
this.toasterService.success(_.get(this.resourceService, 'frmelmnts.cert.lbl.certAddSuccess'));
} else {
this.toasterService.success(_.get(this.resourceService, 'frmelmnts.cert.lbl.certUpdateSuccess'));
}
this.certificateService.getBatchDetails(_.get(this.queryParams, 'batchId')).subscribe(batchDetails => {
this.batchDetails = _.get(batchDetails, 'result.response');
this.processCertificateDetails(_.get(this.batchDetails, 'cert_templates'));
this.goBack();
}, error => {
this.toasterService.error(this.resourceService.messages.emsg.m0005);
});
}, error => {
if (this.configurationMode === 'add') {
this.toasterService.error(_.get(this.resourceService, 'frmelmnts.cert.lbl.certAddError'));
} else {
this.toasterService.error(_.get(this.resourceService, 'frmelmnts.cert.lbl.certEditError'));
}
});
}
processCertificateDetails(certTemplateDetails) {
const templateData = _.pick(_.get(certTemplateDetails, Object.keys(certTemplateDetails)), ['criteria', 'previewUrl', 'artifactUrl', 'identifier', 'data', 'issuer', 'signatoryList', 'name', 'url']);
this.templateIdentifier = _.get(templateData, 'identifier');
this.selectedTemplate = {
'name': _.get(templateData, 'name'),
'identifier': _.get(templateData, 'identifier'),
'previewUrl': _.get(templateData, 'previewUrl'),
'issuer': JSON.stringify(_.get(templateData, 'issuer')),
'data': JSON.stringify(_.get(templateData, 'data')),
'signatoryList': JSON.stringify(_.get(templateData, 'signatoryList')),
'artifactUrl': _.get(templateData, 'artifactUrl')
};
if (!_.get(templateData, 'previewUrl') && _.get(templateData, 'url')) {
this.selectedTemplate['previewUrl'] = _.get(templateData, 'url');
templateData['previewUrl'] = _.get(templateData, 'url');
}
// if (!_.isEmpty(this.newTemplateIdentifier)) {
// this.templateIdentifier = this.newTemplateIdentifier;
// this.selectedTemplate = null;
// }
this.previewUrl = _.get(templateData, 'previewUrl');
this.setCertEditable();
this.processCriteria(_.get(templateData, 'criteria'));
}
setCertEditable() {
this.certEditable = this.previewUrl ? true : false;
}
editCertificate() {
this.configurationMode = 'edit';
this.currentState = this.screenStates.certRules;
this.sendInteractData({ id: 'edit-certificate' });
}
getCriteria(rawDropdownValues) {
const processedData = this.certConfigModalInstance.processDropDownValues(rawDropdownValues, _.get(this.userService, 'userProfile.rootOrgId'));
return processedData;
}
processCriteria(criteria) {
const data = this.certConfigModalInstance.processCriteria(criteria);
this.issueTo = _.get(data, 'issueTo');
const scoreRange = _.get(data, 'scoreRange');
if (scoreRange) {
this.addRule();
}
const scoreRangeFormEle = this.userPreference.controls['scoreRange'];
const issueToFormEle = this.userPreference.controls['issueTo'];
this.issueTo && this.issueTo.length > 0 ? issueToFormEle.setValue(this.issueTo[0].name) : issueToFormEle.setValue('');
scoreRange ? scoreRangeFormEle.setValue(scoreRange) : scoreRangeFormEle.setValue('');
}
handleCertificateEvent(event, template: {}) {
const show = _.get(this.selectedTemplate, 'name') === _.get(template, 'name');
switch (_.lowerCase(_.get(event, 'name'))) {
case 'select':
this.selectedTemplate = template;
this.config.remove.show = show;
this.config.select.show = !show;
this.validateForm();
this.sendInteractData({ id: 'select-template' });
break;
case 'remove':
this.selectedTemplate = {};
this.config.select.show = show;
this.config.remove.show = !show;
this.validateForm();
this.sendInteractData({ id: 'unselect-template' });
break;
case 'preview':
this.previewTemplate = template;
this.showPreviewModal = true;
this.sendInteractData({ id: 'preview-template' });
break;
}
}
getConfig(config: { show: boolean, label: string, name: string }, template) {
const show = _.get(this.selectedTemplate, 'name') === _.get(template, 'name');
if (_.lowerCase(_.get(config, 'label')) === 'select') {
return ({ show: !show, label: config.label, name: config.name });
} else {
return ({ show: show, label: config.label, name: config.name });
}
}
closeModal(event) {
_.remove(this.certTemplateList, (template) => _.get(template, 'identifier') === _.get(event, 'template.identifier'));
this.certTemplateList.unshift(_.get(event, 'template'));
this.showPreviewModal = false;
this.selectedTemplate = _.get(event, 'name') ? _.get(event, 'template') : this.selectedTemplate;
this.validateForm();
if (_.get(event, 'name')) {
this.sendInteractData({ id: 'select-template' });
} else {
this.sendInteractData({ id: 'close-preview' });
}
}
closeTemplateDetectModal() {
this.isTemplateChanged = false;
this.sendInteractData({ id: 'cancel-template-change' });
}
navigateToCertRules() {
this.currentState = this.screenStates.certRules;
this.sendInteractData({ id: 'add-certificate' });
}
goBack() {
if (this.currentState === this.screenStates.certRules) {
// Goback to cert list screen
this.currentState = this.screenStates.default;
} else {
this.router.navigate([`/learn/course/${_.get(this.queryParams, 'courseId')}`]);
}
}
cancelSelection() {
this.currentState = this.screenStates.default;
this.userPreference.controls['allowPermission'].reset();
this.sendInteractData({ id: this.configurationMode === 'add' ? 'cancel-add-certificate' : 'cancel-update-certificate' });
if (this.configurationMode === 'add') {
this.userPreference.reset();
this.selectedTemplate = {};
} else {
const cert_templates = _.get(this.batchDetails, 'cert_templates');
this.processCertificateDetails(cert_templates);
}
}
setTelemetryImpressionData() {
this.telemetryImpression = {
context: {
env: this.activatedRoute.snapshot.data.telemetry.env,
cdata: [{
type: 'Batch',
id: _.get(this.queryParams, 'batchId')
},
{
type: 'Course',
id: _.get(this.queryParams, 'courseId')
}]
},
edata: {
type: this.activatedRoute.snapshot.data.telemetry.type,
subtype: this.activatedRoute.snapshot.data.telemetry.subtype,
pageid: this.activatedRoute.snapshot.data.telemetry.pageid,
uri: this.router.url,
duration: this.navigationHelperService.getPageLoadTime()
}
};
this.telemetryService.impression(this.telemetryImpression);
}
sendInteractData(interactData) {
const data = {
context: {
env: this.activatedRoute.snapshot.data.telemetry.env,
cdata: [{
type: 'Batch',
id: _.get(this.queryParams, 'batchId')
},
{
type: 'Course',
id: _.get(this.queryParams, 'courseId')
}]
},
edata: {
id: _.get(interactData, 'id'),
type: 'CLICK',
pageid: this.activatedRoute.snapshot.data.telemetry.pageid
}
};
if (this.configurationMode === 'edit') {
data['object'] = {
id: _.get(this.selectedTemplate, 'name'),
type: 'Certificate',
ver: '1.0',
rollup: { l1: _.get(this.queryParams, 'courseId') }
};
}
this.telemetryService.interact(data);
}
navigateToCreateTemplate() {
if(_.get(this.certificateFormConfig, 'enableSVGEditor')) {
this.router.navigate([`/certs/configure/create-certificate-template`], {
queryParams: {
type: this.configurationMode,
courseId: _.get(this.queryParams, 'courseId'),
batchId: _.get(this.queryParams, 'batchId')
}
});
} else {
this.router.navigate([`/certs/configure/create-template`], {
queryParams: {
type: this.configurationMode,
courseId: _.get(this.queryParams, 'courseId'),
batchId: _.get(this.queryParams, 'batchId')
}
});
}
}
removeSelectedCertificate() {
this.selectedTemplate = null;
}
ngOnDestroy() {
this.unsubscribe$.next();
this.unsubscribe$.complete();
this.uploadCertificateService.certificate.next(null);
}
public addRule() {
this.addScoreRule = true;
let range = 100;
const step = 10;
const arr = [];
while (range > 0) {
arr.push(range);
range = range - step;
}
this.arrayValue['range'] = arr;
}
removeRule() {
setTimeout(() => {
this.userPreference.value['scoreRange'] = null;
}, 500);
this.addScoreRule = false;
}
redoLayout() {
if (this.layoutConfiguration != null) {
this.FIRST_PANEL_LAYOUT = this.layoutService.redoLayoutCSS(0, this.layoutConfiguration, COLUMN_TYPE.threeToNine);
this.SECOND_PANEL_LAYOUT = this.layoutService.redoLayoutCSS(1, this.layoutConfiguration, COLUMN_TYPE.threeToNine);
} else {
this.FIRST_PANEL_LAYOUT = this.layoutService.redoLayoutCSS(0, null, COLUMN_TYPE.fullLayout);
this.SECOND_PANEL_LAYOUT = this.layoutService.redoLayoutCSS(1, null, COLUMN_TYPE.fullLayout);
}
}
handleParameterChange(event) {
if (_.get(event, 'value') === 'My state teacher') {
this.isStateCertificate = true;
} else {
this.isStateCertificate = false;
}
}
getCertificateFormData() {
const formServiceInputParams = {
formType: 'certificate',
contentType: 'course',
formAction: 'certificateCreate',
component: 'portal'
};
return this.formService.getFormConfig(formServiceInputParams, null, 'data').pipe(
map((data) => {
this.certificateFormConfig = data;
return data;
}),tap(mapping => {
}),
catchError((err) => {
return of([])
})
);
}
}
<!-- Loader -->
<div class="two wide column" *ngIf="showLoader">
<app-loader></app-loader>
</div>
<!-- /Loader-->
<div [ngClass]="layoutConfiguration ? 'sbt-inside-page-container' : ''">
<div *ngIf="!showLoader">
<!-- Header -->
<div class="sb-bg-color-white relative position back-btn-container cc-player__btn-back relative9">
<div class="ui container">
<div class="py-8 d-flex flex-ai-center">
<button class="sb-btn sb-btn-normal sb-btn-link sb-btn-link-primary sb-left-icon-btn mr-auto" id="goBack"
type="button" tabindex="0" (click)="goBack()">
<i class="icon-svg icon-svg--xxs icon-back mr-4">
<svg class="icon icon-svg--primary">
<use xlink:href="assets/images/sprite.svg#arrow-long-left"></use>
</svg></i>
{{resourceService?.frmelmnts?.btn?.back}}
</button>
<div class="d-flex flex-ai-center">
<!---->
<!---->
<!---->
</div>
</div>
</div>
</div>
<div class="textbook-container cc-player__content-header relative9">
<div class="ui container">
<div class="textbook py-16 sb-g cc-player">
<div class="sb-g-col-xs-12 sb-g-col-md-9 sb-g-col-lg-9 sb-g-col-xxxl-12">
<!-- Textbook details -->
<div class="textbook__details d-flex flex-ai-center">
<!-- Textbook image -->
<div class="textbook__bookimg">
<img src="{{courseDetails?.appIcon}}" alt="textbook">
</div>
<div class="ml-8 textbook__heading">
<!-- Textbook title -->
<div class="textbook__title sb-color-primary font-weight-bold mb-0" tabindex="0">{{courseDetails?.name}}
</div>
<div class="fs-1 pt-8">{{courseDetails?.contentType}}</div>
</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 certified-course">
<div class="ml-auto text-right mt-8">
<!-- <button class="sb-btn sb-btn-primary sb-btn-normal px-24">
Save Configuration
</button> -->
</div>
</div>
</div>
</div>
</div>
<!-- / Header-->
<!-- first screen -->
<div class="certificate-container py-16 cc-player__content-header relative9"
*ngIf="currentState === screenStates.default">
<div class="ui container">
<div class="ui stackable grid m-0">
<div class="four wide column">
<div class="certificate-sidebar p-24 certificate-bg">
<div class="select-template-container d-flex flex-dc mb-16">
<div class="certificates-label pb-24 font-weight-bold text-left">
{{resourceService?.frmelmnts?.cert?.lbl?.configure}}</div>
<div class="certificate-scrollbar">
<div class="certificate-sbcard mb-16 py-16">
<div class="d-flex flex-ai-center flex-jc-space-between">
<div class="certificate-card-title sb__ellipsis sb__ellipsis--three px-16">{{courseDetails?.name}}
</div>
<div class="d-flex flex-ai-center">
<div class="certificate-card-img px-16">
<img src="assets/images/certificate-icon.png" width="25px" height="20px"
alt="certificate-icon" />
</div>
<div class="border-right"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="eight wide column">
<div *ngIf="!selectedTemplate" class="select-template-content p-24">
<div class="d-flex flex-dc flex-ai-center text-center mt-32">
<div><img src="../../assets/images/addcertificate.png" alt="add certificate "></div>
<p class="no-template-text pt-16 pb-24 mb-0">{{resourceService?.frmelmnts?.cert?.lbl?.noCertificate}}
<b>{{resourceService?.frmelmnts?.cert?.lbl?.addCert }}</b>
{{ resourceService?.frmelmnts?.cert?.lbl?.button}}
</p>
<button type="button" id="addNewCert" tabindex="0" (click)="certificateCreation()"
class="sb-btn sb-btn-normal sb-btn-outline-primary px-24">
{{resourceService?.frmelmnts?.cert?.lbl?.addCert }}
<img src="assets/images/plus-icon.svg" alt=" Add certificate " width="8px"
class="ml-4 plus-icon"></button>
</div>
</div>
<div *ngIf="selectedTemplate" class="certificate-edit-content p-24">
<div class="content">
<div class="fnormal pb-24 font-weight-bold text-left">
{{resourceService?.frmelmnts?.cert?.lbl?.certificate}}</div>
<div class="certificate-edit-area">
<div class="certificate-edit-sbcard">
<div class="d-flex flex-ai-center flex-dc p-16 certificate-edit-sbcard-content">
<div class="certificate-frame">
<div *ngIf="certEditable"><img src="{{previewUrl}}" alt="certificate edit"></div>
<div *ngIf="!certEditable"
class="d-flex flex-jc-center flex-dc p-24 fnormal text-center sb-color-error w-100 no-cert">
<h3>{{resourceService?.frmelmnts?.cert?.lbl?.noEditAction}}</h3>
</div>
</div>
</div>
<div class="d-flex flex-ai-center flex-jc-space-between w-100 pt-16">
<div class="d-flex flex-ai-center ml-auto d-flex">
<button type="button" [ngClass]="{'sb-btn-disabled': !certEditable }" [disabled]="!certEditable"
(click)="editCertificate()" tabindex="0"
class="sb-btn sb-btn-primary sb-btn-normal">{{resourceService?.frmelmnts?.lbl?.edit}}</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- second screen -->
<div class="certificate-container py-16 cc-player__content-header relative9"
*ngIf="currentState === screenStates.certRules">
<div class="ui container">
<div class="sb-g">
<div class="sb-g-col-xs-12 sb-g-col-md-8 sb-g-col-lg-8 sb-g-col-xxxl-12 certificate-bg">
<div class="certificate-content-area p-24">
<form [formGroup]="userPreference">
<div class='ui stackable grid mt-0'>
<div class="five wide column pt-0">
<div *ngIf="configurationMode === 'add'" class="pb-24 font-weight-bold certificates-label">
{{resourceService?.frmelmnts?.cert?.lbl?.addCert}}</div>
<div *ngIf="configurationMode === 'edit'" class="pb-24 font-weight-bold certificates-label">
{{resourceService?.frmelmnts?.cert?.lbl?.editCert}}</div>
</div>
</div>
<div class='ui stackable grid mt-0'>
<div class="seven wide column">
<div class="pt-8 pb-16 font-weight-bold fnormal text-left">
{{resourceService?.frmelmnts?.cert?.lbl?.certRules}}</div>
<div class="d-flex flex-dc w-50">
<mat-form-field appearance="fill" class="sb-mat__dropdown w-100 mb-16">
<mat-label>{{resourceService?.frmelmnts?.cert?.lbl?.issueTo}}</mat-label>
<mat-select formControlName="issueTo" role="listbox" aria-label="resourceService?.frmelmnts?.cert?.lbl?.issueTo"
class="selection" [disabled]="configurationMode === 'edit'" (selectionChange)="handleParameterChange($event)">
<mat-option class="mat-dropdown__options" role="option" *ngFor="let option of issueTo" [value]="option.name"
attr.aria-label="{{option.name}}">{{option.name}}</mat-option>
</mat-select>
</mat-form-field>
</div>
<label class="fnormal font-weight-normal text-left"
*ngIf="isStateCertificate">{{resourceService?.frmelmnts?.intxt?.ssousers |
interpolate:'{instance}': instance}}</label>
</div>
</div>
<hr class="mt-16 mb-24">
<div class="ui stackable grid mt-0">
<div class="twelve wide column pt-0">
<div class="d-flex rules-configuration px-16">
<label
class="d-flex flex-ai-center fnormal font-weight-normal mb-0 py-8">{{resourceService?.frmelmnts?.lbl?.addCertificateprogressrule}}</label>
<div class="mx-24 progress-separator"></div>
<div class="py-16 d-flex flex-wrap rules-form-content">
<div class="mr-16 sb-field-group">
<div class="sb-field">
<input class="sb-form-control fnormal font-weight-bold" type="text" placeholder="100%"
value="100%" readonly=true>
</div>
<p class="font-weight-normal fsmall mb-0 completion-text">
<span class="asterik">*</span>
{{resourceService?.frmelmnts?.lbl?.addCertificateText}}
</p>
</div>
</div>
</div>
</div>
</div>
<div class="progess-add-content" *ngIf="isSingleAssessment">
<div class="left-border"></div>
<button type="button" class="add-score-btn py-8 px-16 fsmall font-weight-bold"
*ngIf="addScoreRule">And</button>
<button type="button" class="d-flex flex-ai-center flex-jc-center plus-btn" *ngIf="!addScoreRule"
tabindex="0" (click)="addRule()"><img src="assets/images/plus-icon.svg"></button>
<div class="left-border" *ngIf="addScoreRule"></div>
</div>
<div class="ui stackable grid mt-0" *ngIf="addScoreRule && isSingleAssessment">
<div class="twelve wide column pt-0">
<div class="d-flex rules-configuration px-16">
<label
class="d-flex flex-ai-center fnormal font-weight-normal mb-0 py-8">{{resourceService?.frmelmnts?.lbl?.addCertificatescorerule}}</label>
<div class="mx-24 progress-separator"></div>
<div class="py-16 d-flex flex-dc rules-form-content my-16">
<div class="ui stackable grid mt-0 sb-field-group">
<div class="five wide column sb-field mb-0">
<input class="sb-form-control fnormal font-weight-bold" type="text"
placeholder="Best attempt score"
value="{{resourceService?.frmelmnts?.lbl?.bestScoreattempt}}" readonly="true">
</div>
<div class="three wide fnormal column mt-5">
{{resourceService?.frmelmnts?.lbl?.addCertificategreaterThan}}</div>
<div class="four wide column sb-field mb-0">
<sui-select class="selection form-control" [placeholder]="'Select'"
formControlName="scoreRange" [options]="scoreRange" #selectScoreRange>
<sui-select-option *ngFor="let option of arrayValue['range']" [value]="option + '%'">
</sui-select-option>
</sui-select>
</div>
<p class="font-weight-normal fsmall mb-0 completion-text">
<span class="asterik">*</span>
{{resourceService?.frmelmnts?.lbl?.addCertificateText}}
</p>
</div>
</div>
<div class="close-score" tabindex="0" (click)="removeRule()"><img src="assets/images/close.svg">
</div>
</div>
</div>
</div>
<div class='ui stackable grid mt-0'>
<div class="twelve wide column">
<div class="sb-checkbox sb-checkbox-secondary pt-24">
<input formControlName="allowPermission" value="true" type="checkbox" id="check2" name="selected">
<label for="check2" class="text-left">{{resourceService?.frmelmnts?.cert?.lbl?.verified}}</label>
</div>
</div>
</div>
</form>
</div>
<div *ngIf="selectedTemplate">
<div class="certificate-edit-area">
<div class="certificate-edit-sbcard">
<div class="d-flex flex-dc p-16 certificate-edit-sbcard-content">
<div class="certificate-frame">
<div><img src="{{selectedTemplate?.artifactUrl || selectedTemplate?.previewUrl}}"
alt="certificate edit"></div>
</div>
<div class="d-flex flex-ai-center flex-jc-space-between w-100 pt-16">
<div class="d-flex flex-ai-center ml-auto d-flex">
<button type="button" (click)="removeSelectedCertificate()" tabindex="0"
class="sb-btn sb-btn-primary sb-btn-normal">{{resourceService?.frmelmnts?.btn?.remove}}</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Side panel of cert-templates -->
<div class="sb-g-col-xs-12 sb-g-col-md-4 sb-g-col-lg-4 sb-g-col-xxxl-4">
<div class="select-template-content sb-bg-color-white p-24 certificate-bg">
<div class="select-template-container mb-16">
<div class="d-flex flex-ai-center text-left flex-jc-space-between">
<label class="certificates-label">{{resourceService?.frmelmnts?.cert?.lbl?.templates}}</label>
<button
class="add-new-template-btn sb-btn sb-btn-normal sb-btn-outline-primary sb-left-icon-btn font-weight-bold"
type="button" (click)="navigateToCreateTemplate()" tabindex="0">
<i
class="plus alternate outline icon"></i>{{resourceService?.frmelmnts?.cert?.btn?.createtemp}}</button>
</div>
<div class="d-flex flex-ai-center text-left flex-jc-space-between">
<label class="font-weight-normal fsmall">{{resourceService?.frmelmnts?.cert?.lbl?.certNote}}</label>
<button (click)="refreshData()" class="sb-btn sb-btn-normal sb-btn-outline-primary my-16"
tabindex="0">
{{resourceService?.frmelmnts?.cert?.btn?.refresh}}
</button>
</div>
<div *ngIf="certTemplateList" class="certificate-scrollbar">
<div *ngFor="let template of certTemplateList">
<sb-certificate-actions [preview]="config?.preview"
[isSelectedTemplate]="selectedTemplate?.identifier === template?.identifier && !showPreviewModal"
[template]="template?.artifactUrl" (buttonClick)="handleCertificateEvent($event, template)">
</sb-certificate-actions>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div *ngIf="currentState === screenStates.certRules">
<div class="ui stackable grid m-0">
<div class="twelve wide column px-0">
<div class="d-flex flex-ai-center flex-jc-flex-end sb-bg-color-white p-24">
<button class="sb-btn sb-btn-normal sb-btn-outline-primary" tabindex="0"
(click)="cancelSelection()">{{resourceService?.frmelmnts?.btn?.cancel}}</button>
<button [ngClass]="{'sb-btn-disabled': disableAddCertificate }" *ngIf="configurationMode === 'add'"
[disabled]="disableAddCertificate" tabindex="0" class="sb-btn sb-btn-normal sb-btn-primary ml-8 px-24"
(click)="attachCertificateToBatch()">{{resourceService?.frmelmnts?.cert?.lbl?.addCert}}</button>
<button id="update-certificate" [ngClass]="{'sb-btn-disabled': disableAddCertificate }"
*ngIf="configurationMode === 'edit'" [disabled]="disableAddCertificate"
class="sb-btn sb-btn-normal sb-btn-primary ml-8 px-24" tabindex="0"
(click)="updateCertificate()">{{resourceService?.frmelmnts?.cert?.lbl?.updateCert}}</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<app-cert-preview-popup *ngIf="showPreviewModal" (close)="closeModal($event)" [template]="previewTemplate">
</app-cert-preview-popup>
<!-- footer certificate -->
<app-modal-wrapper *ngIf="isTemplateChanged"
[config]="{disableClose: true, size: 'normal', panelClass: 'material-modal'}" (dismiss)="closeTemplateDetectModal()"
#templateChangeModal>
<ng-template sbModalContent>
<div class="sb-mat__modal">
<div mat-dialog-title class="mb-0">
<div class="title" tabindex="0">{{resourceService?.frmelmnts?.cert?.lbl?.changeDetected}}</div>
</div>
<div class="sb-mat__modal__content">
<div class="ui stackable grid mt-16 mb-8">
<div class="two wide column p-0">
<div class="checkbox-img"></div>
</div>
<div class="nine wide column p-0">
<p class="fnormal">{{resourceService?.frmelmnts?.cert?.lbl?.templateChange}}</p>
</div>
</div>
</div>
<mat-dialog-actions class="sb-mat__modal__actions">
<button (click)="attachCertificateToBatch()" tabindex="0" class="sb-btn sb-btn-normal sb-btn-primary">
{{resourceService?.frmelmnts?.lbl?.continue}}
</button>
<button (click)="closeTemplateDetectModal()" tabindex="0" class="sb-btn sb-btn-normal sb-btn-outline-primary">
{{resourceService?.frmelmnts?.btn?.cancel}}
</button>
</mat-dialog-actions>
</div>
</ng-template>
</app-modal-wrapper>
<app-modal-wrapper *ngIf="showAlertModal" [config]="{disableClose: true, size: 'small', panelClass: 'material-modal'}"
(dismiss)="showAlertModal = false" #modal>
<ng-template sbModalContent>
<div class="sb-mat__modal">
<div mat-dialog-title class="mb-0">
<div class="title" tabindex="0">{{resourceService?.frmelmnts?.cert?.lbl?.alertHeader}}</div>
<button aria-label="close dialog" mat-dialog-close class="close-btn"></button>
</div>
<div class="sb-mat__modal__content">
<div class="ui center aligned segment text-left">
<p>{{resourceService?.frmelmnts?.cert?.imsg?.alertMessageForCert}}</p>
</div>
</div>
<mat-dialog-actions class="sb-mat__modal__actions"></mat-dialog-actions>
</div>
</ng-template>
</app-modal-wrapper>
./certificate-configuration.component.scss
@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;
:host {
//back-header
.back-bar {
width: 100%;
}
// textbook header
.textbook {
&-container {
z-index: 2;
position: relative;
background-color: var(--gray-0);
}
&__details {
flex: 1;
min-width: 0;
}
&__bookimg {
width: calculateRem(48px);
height: calculateRem(48px);
img {
width: calculateRem(48px);
height: calculateRem(48px);
}
}
&__heading {
min-width: 0;
.textbook__title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: calculateRem(18px);
}
}
&__addbtn {
white-space: nowrap;
}
}
.certificate-container {
position: relative;
top: calculateRem(2px);
z-index: 2;
.certificate-scrollbar {
height: 90%;
overflow-y: auto;
padding-right: 0.5rem;
padding-left: 0;
html[dir="rtl"] & {
padding-right: 0;
padding-left: 0.5rem;
}
}
.certificates-label {
font-size: calculateRem(18px);
letter-spacing: 0;
line-height: calculateRem(20px);
}
.certificate-content-area {
width: 100%;
}
.certificate-sidebar {
height: 100vh;
// z-index: 2;
width: 100%;
background: var(--white);
@include respond-below(sm) {
height: auto;
margin-bottom: 0px;
}
.certificate-sbcard {
color: var(--gray-400);
font-size: calculateRem(12px);
min-height: calculateRem(52px);
box-shadow: 0 calculateRem(3px) calculateRem(4px) 0 rgba(var(--rc-rgba-primary), 0.1);
background-color: var(--white);
border: .0625rem solid var(--rc-e2e3e5);
border-radius: calculateRem(12px);
cursor: pointer;
position: relative;
overflow: hidden;
transition: box-shadow .3s ease-out, transform .3s ease-out, opacity .2s ease-out;
transition-delay: .1s;
&:active {
color: var(--primary-400);
font-weight: bold;
.border-right {
border-right: calculateRem(4px) solid var(--primary-400);
height: calculateRem(24px);
}
}
.certificate-card-img {
position: relative;
}
.certificate-card-count {
position: relative;
bottom: calculateRem(2px);
}
}
}
.select-template-container {
height: 100%;
position: relative;
}
.select-template-content {
height: 100vh;
width: 100%;
@include respond-below(sm) {
height: auto;
}
.no-template-text {
color: var(--gray-300);
text-align: center;
max-width: calculateRem(310px);
font-size: calculateRem(12px);
}
.plus-icon {
position: relative;
bottom: calculateRem(1px);
}
}
.certificate-edit-content {
background: var(--white);
width: 100%;
height: 100vh;
@include respond-below(sm) {
height: auto;
}
.certificate-edit-area {
display: grid;
grid-template-areas:
"smallcard smallcard2";
grid-gap: calculateRem(24px);
grid-template-columns: 1fr 1fr;
background: var(--white);
@include respond-below(sm) {
grid-template-areas:
"smallcard"
"smallcard2";
grid-template-columns: 1fr;
}
.certificate-edit-sbcard {
width: 100%;
border-radius: calculateRem(8px);
cursor: pointer;
border: calculateRem(1px) solid var(--rc-e0e0e0);
&:nth-child(1) {
grid-area: smallcard;
}
&:nth-child(2) {
grid-area: smallcard2;
}
.certificate-edit-sbcard-content {
height: 100%;
.certificate-frame {
box-shadow: 0 0.125rem 0.4375rem 0 rgba(var(--rc-rgba-black), .16);
position: relative;
width: 100%;
img {
max-width: 100%;
width: 100%;
}
.no-cert {
min-height: calculateRem(300px);
}
}
}
}
}
}
}
::ng-deep {
.ui.selection.dropdown>.text {
cursor: text;
font-weight: bold;
position: relative;
left: calculateRem(8px);
html[dir="rtl"] & {
right: calculateRem(8px);
left: 0px;
}
}
}
.sb-batch-update-modal {
.checkbox-img {
position: absolute;
top: 0.5rem;
left: 3rem;
display: inline;
width: 2rem;
height: 2rem;
background-color: var(--secondary-400);
-webkit-mask-image: url(../../../../../assets/images/warning.svg);
mask-image: url(../../../../../assets/images/warning.svg);
-webkit-mask-size: contain;
-webkit-mask-position: 50% 50%;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
mask-position: 50% 50%;
mask-repeat: no-repeat;
}
}
}
.add-new-template-btn {
position: absolute;
right: 0px;
top: 0px;
}
:host {
.rules-configuration {
border-radius: calculateRem(12px);
background-color: var(--white);
box-shadow: 0 calculateRem(3px) calculateRem(4px) 0 var(--sbt-box-shadow-primary);
position: relative;
@include respond-below(sm) {
flex-direction: column;
.rules-form-content {
flex-direction: column;
}
.ui.grid>[class*="twelve wide"].column {
padding: 0px !important;
}
}
.progress-separator {
box-sizing: border-box;
width: calculateRem(2px);
opacity: 0.3;
background-color: var(--rc-d0d0d0);
}
.completion-text {
color: var(--gray-300);
.asterik {
color: var(--red-400);
}
}
.close-score {
position: absolute;
right: 1rem;
top: 1rem;
html[dir="rtl"] & {
left: 1rem;
}
img {
width: 1.5rem;
height: 1.5rem;
}
}
}
}
::ng-deep {
.overlay-buttons .sb-btn-no-border {
align-items: center;
}
}
.progess-add-content {
.left-border {
width: calculateRem(1px);
background-color: var(--gray-100);
height: 2.0rem;
margin-left: calculateRem(20px);
}
.add-score-btn {
border-radius: 0.5rem;
background-color: var(--white);
box-shadow: calculateRem(5px) calculateRem(5px) calculateRem(2px) 0 var(--sbt-box-shadow-black);
border: none;
color: var(--rc-DD680F);
text-transform: uppercase;
}
.plus-btn {
border-radius: 50%;
background-color: var(--white);
border: none;
width: calculateRem(40px);
height: calculateRem(40px);
}
}