src/app/modules/learn/components/course-consumption/course-consumption-header/course-consumption-header.component.ts
OnInit
AfterViewInit
OnDestroy
selector | app-course-consumption-header |
styleUrls | ./course-consumption-header.component.scss |
templateUrl | ./course-consumption-header.component.html |
constructor(activatedRoute: ActivatedRoute, courseConsumptionService: CourseConsumptionService, resourceService: ResourceService, router: Router, permissionService: PermissionService, toasterService: ToasterService, copyContentService: CopyContentService, changeDetectorRef: ChangeDetectorRef, courseProgressService: CourseProgressService, contentUtilsServiceService: ContentUtilsServiceService, externalUrlPreviewService: ExternalUrlPreviewService, coursesService: CoursesService, userService: UserService, telemetryService: TelemetryService, groupService: GroupsService, navigationHelperService: NavigationHelperService, orgDetailsService: OrgDetailsService, generaliseLabelService: GeneraliseLabelService, connectionService: ConnectionService, courseBatchService: CourseBatchService, utilService: UtilService, contentManagerService: ContentManagerService, formService: FormService, offlineCardService: OfflineCardService, discussionService: DiscussionService, discussionTelemetryService: DiscussionTelemetryService)
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Parameters :
|
courseHierarchy | |
Type : any
|
|
enrolledBatchInfo | |
Type : any
|
|
groupId | |
Type : string
|
|
layoutConfiguration | |
Type : any
|
|
showAddGroup | |
Type : boolean
|
|
Default value : false
|
|
assignForumData | ||||
assignForumData(routerData)
|
||||
Parameters :
Returns :
void
|
checkDownloadStatus |
checkDownloadStatus()
|
Returns :
void
|
checkStatus | ||||
checkStatus(status)
|
||||
Parameters :
Returns :
any
|
closeDashboard |
closeDashboard()
|
Returns :
void
|
closeSharePopup | ||||
closeSharePopup(id)
|
||||
Parameters :
Returns :
void
|
copyContent | ||||||
copyContent(contentData: ContentData)
|
||||||
This method calls the copy API service
Parameters :
Returns :
void
|
deleteCollection | ||||
deleteCollection(collectionData)
|
||||
Parameters :
Returns :
void
|
downloadCollection | ||||
downloadCollection(collection)
|
||||
Parameters :
Returns :
void
|
exportCollection | ||||
exportCollection(collection)
|
||||
Parameters :
Returns :
void
|
flagCourse |
flagCourse()
|
Returns :
void
|
generateDataForDF |
generateDataForDF()
|
Returns :
void
|
getAllBatchDetails |
getAllBatchDetails()
|
Returns :
void
|
getBatchStatus |
getBatchStatus()
|
Returns :
boolean
|
Private getCustodianOrgUser |
getCustodianOrgUser()
|
Returns :
void
|
getFormData |
getFormData()
|
Returns :
void
|
getTimeRemaining | ||||
getTimeRemaining(endTime)
|
||||
Parameters :
Returns :
string
|
Async goBack |
goBack()
|
Returns :
any
|
isEnrollmentAllowed | ||||
isEnrollmentAllowed(enrollmentEndDate)
|
||||
Parameters :
Returns :
any
|
isValidEnrollmentEndDate | ||||
isValidEnrollmentEndDate(enrollmentEndDate)
|
||||
Parameters :
Returns :
boolean
|
isYoutubeContentPresent | ||||
isYoutubeContentPresent(collection)
|
||||
Parameters :
Returns :
void
|
logTelemetry | |||||||||
logTelemetry(id, content?: literal type)
|
|||||||||
Parameters :
Returns :
void
|
ngAfterViewInit |
ngAfterViewInit()
|
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
onShareLink |
onShareLink()
|
Returns :
void
|
resumeCourse | ||||||
resumeCourse(showExtUrlMsg?: boolean)
|
||||||
Parameters :
Returns :
void
|
setTelemetryShareData | ||||
setTelemetryShareData(param)
|
||||
Parameters :
Returns :
void
|
showDashboard |
showDashboard()
|
Returns :
void
|
showJoinModal | ||||
showJoinModal(event)
|
||||
Parameters :
Returns :
void
|
updateCollection | ||||
updateCollection(collection)
|
||||
Parameters :
Returns :
void
|
batchEndCounter |
Type : number
|
batchEndDate |
Type : any
|
batchId |
Type : any
|
batchList |
Type : []
|
Default value : []
|
batchRemaningTime |
Type : any
|
Public connectionService |
Type : ConnectionService
|
contentDownloadStatus |
Type : object
|
Default value : {}
|
contentId |
Type : string
|
Public contentManagerService |
Type : ContentManagerService
|
Public contentUtilsServiceService |
Type : ContentUtilsServiceService
|
Public copyContentService |
Type : CopyContentService
|
Public courseBatchService |
Type : CourseBatchService
|
Public courseConsumptionService |
Type : CourseConsumptionService
|
courseId |
Type : string
|
courseInteractObject |
Type : IInteractEventObject
|
Public coursesService |
Type : CoursesService
|
courseStatus |
Type : string
|
dashboardPermission |
Type : []
|
Default value : ['COURSE_MENTOR', 'CONTENT_CREATOR']
|
disableDelete |
Default value : false
|
Public discussionService |
Type : DiscussionService
|
Public discussionTelemetryService |
Type : DiscussionTelemetryService
|
enableProgress |
Default value : false
|
enrolledCourse |
Default value : false
|
enrollmentEndDate |
Type : string
|
Public externalUrlPreviewService |
Type : ExternalUrlPreviewService
|
fetchForumIdReq |
Type : IForumContext
|
input data for fetchforum Ids |
flaggedCourse |
Default value : false
|
contains link that can be shared |
forumIds |
Type : []
|
Default value : []
|
Public generaliseLabelService |
Type : GeneraliseLabelService
|
Public interval |
Type : any
|
isAvailableLocally |
Default value : false
|
isConnected |
Default value : true
|
isCustodianOrgUser |
Default value : false
|
isDesktopApp |
Default value : false
|
isGroupAdmin |
Default value : false
|
isGroupURL |
Type : Boolean
|
isTrackable |
Default value : false
|
lastPlayedContentId |
Type : string
|
onPageLoadResume |
Default value : false
|
Public orgDetailsService |
Type : OrgDetailsService
|
Public permissionService |
Type : PermissionService
|
profileInfo |
Type : literal type
|
progress |
Type : number
|
Default value : 0
|
Public resourceService |
Type : ResourceService
|
Public router |
Type : Router
|
shareLink |
Type : string
|
sharelinkModal |
Type : boolean
|
showBatchCounter |
Type : boolean
|
showCopyLoader |
Default value : false
|
to show loader while copying content |
showDeleteModal |
Default value : false
|
showDownloadLoader |
Default value : false
|
showError |
Default value : false
|
showExportLoader |
Default value : false
|
showLoader |
Default value : false
|
showModal |
Default value : false
|
showProfileUpdatePopup |
Default value : false
|
showResumeCourse |
Default value : true
|
showUpdate |
Default value : false
|
telemetryCdata |
Type : Array<literal type>
|
telemetryShareData |
Type : Array<ITelemetryShare>
|
telemetryShareData |
Public toasterService |
Type : ToasterService
|
tocId |
todayDate |
Default value : dayjs(new Date()).format('YYYY-MM-DD')
|
Public unsubscribe |
Default value : new Subject<void>()
|
viewDashboard |
Default value : false
|
import { combineLatest as observableCombineLatest, Subject } from 'rxjs';
import { takeUntil} from 'rxjs/operators';
import { Component, OnInit, Input, AfterViewInit, ChangeDetectorRef, OnDestroy } from '@angular/core';
import { CourseConsumptionService, CourseProgressService } from './../../../services';
import { ActivatedRoute, Router } from '@angular/router';
import * as _ from 'lodash-es';
import { CoursesService, PermissionService, CopyContentService,
OrgDetailsService, UserService, GeneraliseLabelService, } from '@sunbird/core';
import {
ResourceService, ToasterService, ContentData, ContentUtilsServiceService, ITelemetryShare,
ExternalUrlPreviewService, UtilService, ConnectionService, OfflineCardService, ServerResponse
} from '@sunbird/shared';
import { IInteractEventObject, TelemetryService } from '@sunbird/telemetry';
import dayjs from 'dayjs';
import { GroupsService } from '../../../../groups/services/groups/groups.service';
import { NavigationHelperService } from '@sunbird/shared';
import { CourseBatchService } from './../../../services';
import { DiscussionService } from '../../../../discussion/services/discussion/discussion.service';
import { FormService } from '../../../../core/services/form/form.service';
import { IForumContext } from '../../../interfaces';
import { ContentManagerService } from '../../../../public/module/offline/services';
import { DiscussionTelemetryService } from './../../../../shared/services/discussion-telemetry/discussion-telemetry.service';
@Component({
selector: 'app-course-consumption-header',
templateUrl: './course-consumption-header.component.html',
styleUrls: ['./course-consumption-header.component.scss']
})
export class CourseConsumptionHeaderComponent implements OnInit, AfterViewInit, OnDestroy {
sharelinkModal: boolean;
showProfileUpdatePopup = false;
profileInfo: {
firstName: string,
lastName: string,
id: string
};
/**
* input data for fetchforum Ids
*/
fetchForumIdReq: IForumContext;
/**
* contains link that can be shared
*/
flaggedCourse = false;
/**
* telemetryShareData
*/
telemetryShareData: Array<ITelemetryShare>;
shareLink: string;
/**
* to show loader while copying content
*/
showCopyLoader = false;
onPageLoadResume = false;
courseInteractObject: IInteractEventObject;
@Input() courseHierarchy: any;
@Input() enrolledBatchInfo: any;
@Input() groupId: string;
@Input() showAddGroup = false;
@Input() layoutConfiguration;
isGroupAdmin = false;
enrolledCourse = false;
batchId: any;
dashboardPermission = ['COURSE_MENTOR', 'CONTENT_CREATOR'];
courseId: string;
lastPlayedContentId: string;
showResumeCourse = true;
contentId: string;
progress = 0;
courseStatus: string;
public unsubscribe = new Subject<void>();
batchEndDate: any;
batchRemaningTime: any;
public interval: any;
telemetryCdata: Array<{}>;
enableProgress = false;
isCustodianOrgUser = false;
// courseMentor = false;
// courseCreator = false;
forumIds = [];
isTrackable = false;
viewDashboard = false;
tocId;
showLoader = false;
batchEndCounter: number;
showBatchCounter: boolean;
isDesktopApp = false;
isConnected = true;
contentDownloadStatus = {};
showUpdate = false;
showExportLoader = false;
showModal = false;
showDownloadLoader = false;
disableDelete = false;
isAvailableLocally = false;
showDeleteModal = false;
batchList = [];
enrollmentEndDate: string;
todayDate = dayjs(new Date()).format('YYYY-MM-DD');
showError = false;
isGroupURL: Boolean;
constructor(private activatedRoute: ActivatedRoute, public courseConsumptionService: CourseConsumptionService,
public resourceService: ResourceService, public router: Router, public permissionService: PermissionService,
public toasterService: ToasterService, public copyContentService: CopyContentService, private changeDetectorRef: ChangeDetectorRef,
private courseProgressService: CourseProgressService, public contentUtilsServiceService: ContentUtilsServiceService,
public externalUrlPreviewService: ExternalUrlPreviewService, public coursesService: CoursesService, private userService: UserService,
private telemetryService: TelemetryService, private groupService: GroupsService,
private navigationHelperService: NavigationHelperService, public orgDetailsService: OrgDetailsService,
public generaliseLabelService: GeneraliseLabelService, public connectionService: ConnectionService,
public courseBatchService: CourseBatchService, private utilService: UtilService, public contentManagerService: ContentManagerService,
private formService: FormService, private offlineCardService: OfflineCardService,
public discussionService: DiscussionService, public discussionTelemetryService: DiscussionTelemetryService) { }
showJoinModal(event) {
this.courseConsumptionService.showJoinCourseModal.emit(event);
}
ngOnInit() {
this.isGroupAdmin = _.get(this.groupService, 'groupData.isAdmin');
this.isGroupURL=_.includes(_.get(this.router,'url'),'groupId');
this.isDesktopApp = this.utilService.isDesktopApp;
if (this.isDesktopApp) {
this.connectionService.monitor().pipe(takeUntil(this.unsubscribe)).subscribe(isConnected => {
this.isConnected = isConnected;
});
this.contentManagerService.contentDownloadStatus$.pipe(takeUntil(this.unsubscribe)).subscribe( contentDownloadStatus => {
this.contentDownloadStatus = contentDownloadStatus;
this.checkDownloadStatus();
});
}
this.getCustodianOrgUser();
if (!this.courseConsumptionService.getCoursePagePreviousUrl) {
this.courseConsumptionService.setCoursePagePreviousUrl();
}
this.isTrackable = this.courseConsumptionService.isTrackableCollection(this.courseHierarchy);
this.viewDashboard = this.courseConsumptionService.canViewDashboard(this.courseHierarchy);
this.profileInfo = this.userService.userProfile;
observableCombineLatest(this.activatedRoute.firstChild.params, this.activatedRoute.firstChild.queryParams,
(params, queryParams) => {
return { ...params, ...queryParams };
}).subscribe((params) => {
this.courseId = params.courseId;
this.batchId = params.batchId;
this.getAllBatchDetails();
this.courseStatus = params.courseStatus;
this.contentId = params.contentId;
this.tocId = params.textbook;
this.courseInteractObject = {
id: this.courseHierarchy.identifier,
type: 'Course',
ver: this.courseHierarchy.pkgVersion ? this.courseHierarchy.pkgVersion.toString() : '1.0',
};
if (this.courseHierarchy.status === 'Flagged') {
this.flaggedCourse = true;
}
if (this.batchId) {
this.enrolledCourse = true;
this.telemetryCdata = [{ id: this.batchId, type: 'CourseBatch' }];
}
});
this.interval = setInterval(() => {
if (document.getElementById('closebutton')) {
this.showResumeCourse = true;
} else {
this.showResumeCourse = false;
}
}, 500);
this.courseConsumptionService.userCreatedAnyBatch.subscribe((visibility: boolean) => {
this.viewDashboard = this.viewDashboard && visibility;
});
this.generateDataForDF();
}
ngAfterViewInit() {
this.courseProgressService.courseProgressData.pipe(
takeUntil(this.unsubscribe))
.subscribe((courseProgressData) => {
if (this.batchId) {
this.enrolledCourse = true;
this.progress = courseProgressData.progress ? Math.floor(courseProgressData.progress) : 0;
this.lastPlayedContentId = courseProgressData.lastPlayedContentId;
if (!this.flaggedCourse && this.onPageLoadResume &&
!this.contentId && this.enrolledBatchInfo.status > 0 && this.lastPlayedContentId) {
this.onPageLoadResume = false;
this.showResumeCourse = false;
this.resumeCourse();
} else if (!this.flaggedCourse && this.contentId && this.enrolledBatchInfo.status > 0 && this.lastPlayedContentId) {
this.onPageLoadResume = false;
this.showResumeCourse = false;
} else {
this.onPageLoadResume = false;
}
}
});
this.courseConsumptionService.updateContentConsumedStatus.emit(
{
courseId: this.courseId,
batchId: this.batchId,
courseHierarchy: this.courseHierarchy
});
}
getTimeRemaining(endTime) {
this.getFormData();
const countDownDate = new Date(endTime).getTime() + 1000 * 60 * 60 * 24;
const now = new Date().getTime();
const total = countDownDate - now;
const days = Math.floor(total / (1000 * 60 * 60 * 24));
const hours = Math.floor((total / (1000 * 60 * 60)) % 24);
const minutes = Math.floor((total / 1000 / 60) % 60);
if (days >= 0) {
this.showBatchCounter = this.batchEndCounter >= days;
if (this.showBatchCounter) {
return days + ' ' + 'day(s)' + ' ' + hours + 'h' + ' ' + minutes + 'm';
}
} else {
this.showBatchCounter = false;
}
return;
}
getFormData() {
const formServiceInputParams = {
formType: 'contentcategory',
formAction: 'menubar',
contentType: 'global'
};
this.formService.getFormConfig(formServiceInputParams).subscribe((data: any) => {
_.forEach(data, (value, key) => {
if ('frmelmnts.tab.courses' === value.title) {
this.batchEndCounter = value.batchEndCounter || null;
}
});
});
}
showDashboard() {
this.router.navigate(['learn/course', this.courseId, 'dashboard', 'batches']);
}
// To close the dashboard
closeDashboard() {
this.router.navigate(['learn/course', this.courseId]);
}
resumeCourse(showExtUrlMsg?: boolean) {
const IsStoredLocally = localStorage.getItem('isCertificateNameUpdated_' + this.profileInfo.id) || 'false' ;
const certificateDescription = this.courseBatchService.getcertificateDescription(this.enrolledBatchInfo);
if (IsStoredLocally !== 'true'
&&
certificateDescription &&
certificateDescription.isCertificate
&& this.isCustodianOrgUser && this.progress < 100) {
this.showProfileUpdatePopup = true;
} else {
this.courseConsumptionService.launchPlayer.emit();
this.coursesService.setExtContentMsg(showExtUrlMsg);
}
}
flagCourse() {
this.router.navigate(['flag'], { relativeTo: this.activatedRoute.firstChild });
}
/**
* This method calls the copy API service
* @param {contentData} ContentData Content data which will be copied
*/
copyContent(contentData: ContentData) {
this.showCopyLoader = true;
this.copyContentService.copyContent(contentData).pipe(
takeUntil(this.unsubscribe))
.subscribe(
(response) => {
this.toasterService.success(this.resourceService.messages.smsg.m0042);
this.showCopyLoader = false;
},
(err) => {
this.showCopyLoader = false;
this.toasterService.error(this.resourceService.messages.emsg.m0008);
});
}
onShareLink() {
this.shareLink = this.contentUtilsServiceService.getCoursePublicShareUrl(this.courseId);
this.setTelemetryShareData(this.courseHierarchy);
}
setTelemetryShareData(param) {
this.telemetryShareData = [{
id: param.identifier,
type: param.contentType,
ver: param.pkgVersion ? param.pkgVersion.toString() : '1.0'
}];
}
ngOnDestroy() {
clearInterval(this.interval);
this.unsubscribe.next();
this.unsubscribe.complete();
}
getBatchStatus() {
/* istanbul ignore else */
if (_.get(this.enrolledBatchInfo, 'endDate')) {
this.batchEndDate = dayjs(this.enrolledBatchInfo.endDate).format('YYYY-MM-DD');
const leftTimeDate = dayjs(this.batchEndDate).format('MMM DD, YYYY');
this.batchRemaningTime = this.getTimeRemaining(leftTimeDate);
}
return (_.get(this.enrolledBatchInfo, 'status') === 2 && this.progress <= 100);
}
closeSharePopup(id) {
this.sharelinkModal = false;
const interactData = {
context: {
env: _.get(this.activatedRoute.snapshot.data.telemetry, 'env') || 'content',
cdata: this.telemetryCdata
},
edata: {
id: id,
type: 'click',
pageid: _.get(this.activatedRoute.snapshot.data.telemetry, 'pageid') || 'course-details',
},
object: {
id: _.get(this.courseHierarchy, 'identifier'),
type: _.get(this.courseHierarchy, 'contentType') || 'Course',
ver: `${_.get(this.courseHierarchy, 'pkgVersion')}` || `1.0`,
rollup: {l1: this.courseId}
}
};
this.telemetryService.interact(interactData);
}
private getCustodianOrgUser() {
this.orgDetailsService.getCustodianOrgDetails().subscribe(custodianOrg => {
if (_.get(this.userService, 'userProfile.rootOrg.rootOrgId') === _.get(custodianOrg, 'result.response.value')) {
this.isCustodianOrgUser = true;
} else {
this.isCustodianOrgUser = false;
}
});
}
logTelemetry(id, content?: {}) {
if (this.batchId) {
this.telemetryCdata = [{ id: this.batchId, type: 'courseBatch' }];
}
const objectRollUp = this.courseConsumptionService.getContentRollUp(this.courseHierarchy, _.get(content, 'identifier'));
const interactData = {
context: {
env: _.get(this.activatedRoute.snapshot.data.telemetry, 'env') || 'Course',
cdata: this.telemetryCdata || []
},
edata: {
id: id,
type: 'click',
pageid: _.get(this.activatedRoute.snapshot.data.telemetry, 'pageid') || 'course-consumption',
},
object: {
id: content ? _.get(content, 'identifier') : this.activatedRoute.snapshot.params.courseId,
type: content ? _.get(content, 'primaryCategory') : 'Course',
ver: content ? `${_.get(content, 'pkgVersion')}` : `1.0`,
rollup: this.courseConsumptionService.getRollUp(objectRollUp) || {}
}
};
this.telemetryService.interact(interactData);
}
generateDataForDF() {
const isCreator = this.userService.userid === _.get(this.courseHierarchy, 'createdBy');
const isMentor = this.permissionService.checkRolesPermissions(['COURSE_MENTOR']);
if (isCreator) {
this.fetchForumIdReq = {
type: 'course',
identifier: [this.courseId]
};
} else if (this.enrolledCourse) {
this.fetchForumIdReq = {
type: 'batch',
identifier: [this.batchId]
};
} else if (isMentor) {
// TODO: make getBatches() api call;
this.fetchForumIdReq = {
type: 'course',
identifier: [this.courseId]
};
}
}
async goBack() {
const previousPageUrl: any = this.courseConsumptionService.getCoursePagePreviousUrl;
this.courseConsumptionService.coursePagePreviousUrl = '';
if (this.isDesktopApp && !this.isConnected) {
this.router.navigate(['/mydownloads'], { queryParams: { selectedTab: 'mydownloads' } });
return;
}
if (this.tocId) {
const navigateUrl = this.userService.loggedIn ? '/resources/play/collection' : '/play/collection';
this.router.navigate([navigateUrl, this.tocId], { queryParams: { textbook: this.tocId } });
} else if (!previousPageUrl) {
this.router.navigate(['/resources'], { queryParams: { selectedTab: 'course' } });
return;
}
if (previousPageUrl.url.indexOf('/my-groups/') >= 0) {
this.navigationHelperService.goBack();
} else {
if (previousPageUrl.queryParams) {
this.router.navigate([previousPageUrl.url], {queryParams: previousPageUrl.queryParams});
} else {
this.router.navigate([previousPageUrl.url]);
}
}
}
checkStatus(status) {
this.checkDownloadStatus();
return this.utilService.getPlayerDownloadStatus(status, this.courseHierarchy);
}
checkDownloadStatus() {
if (this.courseHierarchy) {
const downloadStatus = ['CANCELED', 'CANCEL', 'FAILED', 'DOWNLOAD'];
const status = this.contentDownloadStatus[this.courseHierarchy.identifier];
this.courseHierarchy['downloadStatus'] = _.isEqual(downloadStatus, status) ? 'DOWNLOAD' :
(_.includes(['INPROGRESS', 'RESUME', 'INQUEUE'], status) ? 'DOWNLOADING' : _.isEqual(status, 'COMPLETED') ? 'DOWNLOADED' : status);
}
}
updateCollection(collection) {
collection['downloadStatus'] = this.resourceService.messages.stmsg.m0140;
this.logTelemetry('update-collection');
const request = {
contentId: collection.identifier
};
this.contentManagerService.updateContent(request).pipe(takeUntil(this.unsubscribe)).subscribe(data => {
collection['downloadStatus'] = this.resourceService.messages.stmsg.m0140;
this.showUpdate = false;
}, (err) => {
this.showUpdate = true;
const errorMessage = !this.isConnected ? _.replace(this.resourceService.messages.smsg.m0056, '{contentName}', collection.name) :
this.resourceService.messages.fmsg.m0096;
this.toasterService.error(errorMessage);
});
}
exportCollection(collection) {
this.logTelemetry('export-collection');
this.showExportLoader = true;
this.contentManagerService.exportContent(collection.identifier)
.pipe(takeUntil(this.unsubscribe))
.subscribe(data => {
this.showExportLoader = false;
this.toasterService.success(this.resourceService.messages.smsg.m0059);
}, error => {
this.showExportLoader = false;
if (_.get(error, 'error.responseCode') !== 'NO_DEST_FOLDER') {
this.toasterService.error(this.resourceService.messages.fmsg.m0091);
}
});
}
isYoutubeContentPresent(collection) {
this.logTelemetry('is-youtube-in-collection');
this.showModal = this.offlineCardService.isYoutubeContent(collection);
if (!this.showModal) {
this.downloadCollection(collection);
}
}
downloadCollection(collection) {
this.showDownloadLoader = true;
this.disableDelete = false;
collection['downloadStatus'] = this.resourceService.messages.stmsg.m0140;
this.logTelemetry('download-collection');
this.contentManagerService.downloadContentId = collection.identifier;
this.contentManagerService.downloadContentData = collection;
this.contentManagerService.failedContentName = collection.name;
this.contentManagerService.startDownload({}).pipe(takeUntil(this.unsubscribe)).subscribe(data => {
this.contentManagerService.downloadContentId = '';
this.contentManagerService.downloadContentData = {};
this.showDownloadLoader = false;
collection['downloadStatus'] = this.resourceService.messages.stmsg.m0140;
}, error => {
this.disableDelete = true;
this.showDownloadLoader = false;
this.contentManagerService.downloadContentId = '';
this.contentManagerService.downloadContentData = {};
this.contentManagerService.failedContentName = '';
collection['downloadStatus'] = this.resourceService.messages.stmsg.m0138;
if (!(error.error.params.err === 'LOW_DISK_SPACE')) {
this.toasterService.error(this.resourceService.messages.fmsg.m0090);
}
});
}
deleteCollection(collectionData) {
this.disableDelete = true;
this.logTelemetry('delete-collection');
const request = {request: {contents: [collectionData.identifier]}};
this.contentManagerService.deleteContent(request).pipe(takeUntil(this.unsubscribe)).subscribe(data => {
this.toasterService.success(this.resourceService.messages.stmsg.desktop.deleteCourseSuccessMessage);
collectionData['downloadStatus'] = 'DOWNLOAD';
collectionData['desktopAppMetadata.isAvailable'] = false;
this.goBack();
}, err => {
this.disableDelete = false;
this.toasterService.error(this.resourceService.messages.etmsg.desktop.deleteCourseErrorMessage);
});
}
/**
* @description - navigate to the DF Page when the event is emited from the access-discussion component
* @param {} routerData
*/
assignForumData(routerData) {
this.router.navigate(['/discussion-forum'], {
queryParams: {
categories: JSON.stringify({ result: routerData.forumIds }),
userId: routerData.userId
}
});
}
isEnrollmentAllowed(enrollmentEndDate) {
return dayjs(enrollmentEndDate).isBefore(this.todayDate);
}
isValidEnrollmentEndDate(enrollmentEndDate) {
return !!enrollmentEndDate;
}
getAllBatchDetails() {
this.batchList = [];
const searchParams: any = {
filters: {
status: '1',
courseId: this.courseId
},
offset: 0,
sort_by: { createdDate: 'desc' }
};
searchParams.filters.enrollmentType = 'open';
this.courseBatchService.getAllBatchDetails(searchParams).pipe(
takeUntil(this.unsubscribe))
.subscribe((data: ServerResponse) => {
if (data.result.response.content && data.result.response.content.length > 0) {
this.batchList = data.result.response.content;
this.enrollmentEndDate = _.get(this.batchList[0], 'enrollmentEndDate');
}
},
(err: ServerResponse) => {
this.showError = true;
this.toasterService.error(this.resourceService.messages.fmsg.m0004);
});
}
}
<!-- Loader -->
<div class="two wide column" *ngIf="showLoader">
<app-loader></app-loader>
</div>
<!-- /Loader-->
<!-- Back Button -->
<div [ngClass]="layoutConfiguration ? 'sb-back-actionbar' : 'sb-bg-color-white back-btn-container cc-player__btn-back relative9'" class="relative position mt-0">
<div class="ui container px-0 d-flex flex-ai-center">
<div class="w-100 d-flex flex-ai-center flex-w-wrap flex-jc-space-between">
<div class="d-flex flex-ai-center">
<!-- /* Back button */ -->
<button type="button" [ngClass]="layoutConfiguration ? 'sb-btn-primary sb-btn-round' : 'sb-btn-link sb-btn-link-primary sb-left-icon-btn px-0'" class="sb-btn sb-btn-normal" tabindex="0" (click)="goBack()" attr.aria-label="{{resourceService?.frmelmnts?.btn?.back}}">
<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>
<span>{{resourceService?.frmelmnts?.btn?.back}}</span>
</button>
<!-- Textbook details with continue playing and join course button routerLink="/registration" -->
<!-- Textbook details -->
<div class="textbook__details d-flex ml-16 flex-basis-1 flex-ai-center">
<!-- Textbook image -->
<div class="textbook__bookimg">
<img src="{{courseHierarchy?.appIcon || 'assets/images/book.png'}}" alt="{{courseHierarchy?.name}}">
</div>
<div class="ml-8 textbook__heading">
<!-- Textbook title -->
<h5 class="sb-color-primary font-weight-bold mb-0 sb__ellipsis" tabindex="0">{{courseHierarchy?.name}}
</h5>
<!-- Textbook Rating with share icon -->
<div class="textbook__rating d-flex flex-ai-center">
<sui-rating *ngIf="courseStatus !== 'Unlisted'" class="star mini" [isReadonly]="true"
[ngModel]="courseHierarchy.me_averageRating || 0" [maximum]="5"></sui-rating>
<button tabindex="0" (click)="onShareLink();sharelinkModal=true;"
class="sb-btn sb-btn-normal sb-btn-link sb-btn-link-primary sb-left-icon-btn ml-8 sb-btn-icon-fix">
<i class="icon-svg icon-svg--xs icon-share mr-8"><svg class="icon icon-svg--primary">
<use xlink:href="assets/images/sprite.svg#share"></use>
</svg></i>
{{resourceService?.frmelmnts?.lbl?.share}}
</button>
<button class="sb-btn sb-btn-normal sb-btn-link sb-btn-link-primary sb-left-icon-btn ml-8 sb-btn-icon-fix"
*ngIf="!isDesktopApp && permissionService?.permissionAvailable && courseStatus !== 'Unlisted'" appPermission
appTelemetryInteract [telemetryInteractObject]="courseInteractObject"
[telemetryInteractEdata]="{id:'copyContent' , type: 'click' , pageid:'course-consumption'}"
[permission]="['CONTENT_CREATOR', 'CONTENT_REVIEWER']" tabindex="0" (click)="copyContent(courseHierarchy)"
title="{{resourceService?.frmelmnts?.lbl?.copy}}">
<i class="icon-svg icon-svg--xs icon-edit mr-8"><svg class="icon icon-svg--primary">
<use xlink:href="assets/images/sprite.svg#copy-alternate"></use>
</svg></i>
{{resourceService?.frmelmnts?.lbl?.copy}}
</button>
<!-- Discussion Forum -->
<app-access-discussion *ngIf="isConnected && fetchForumIdReq" [fetchForumIdReq]="fetchForumIdReq"
(routerData)="assignForumData($event)"> </app-access-discussion>
</div>
</div>
</div>
</div>
<div class="d-flex flex-w-wrap flex-ai-center textbook cc-player ml-auto">
<div class="batch-details__created mt-8 fsmall mx-8"
*ngIf="!enrolledBatchInfo && isValidEnrollmentEndDate(enrollmentEndDate)">
<span class="sb-label-12size"
*ngIf="!isEnrollmentAllowed(enrollmentEndDate)">{{resourceService?.messages?.stmsg?.m0136}}
{{enrollmentEndDate | dateFormat}}</span>
<span class="sb-label-status-error"
*ngIf="isEnrollmentAllowed(enrollmentEndDate)">{{resourceService?.messages?.emsg?.m008 | interpolate:'{endDate}':enrollmentEndDate}}</span>
</div>
<div *ngIf="batchEndDate && showBatchCounter" class="d-flex">
<span class="fnormal sb-color-gray-400">{{resourceService?.frmelmnts?.lbl?.BatchExpiringIn}}: </span>
<span class="fsmall font-weight-bold mb-8 sb-color-gray-800">
<h6>{{batchRemaningTime}}</h6>
</span>
</div>
<div class="d-flex flex-dc flex-basis-1 mr-32">
<!-- Info displaying if course is flagged -->
<h6 class="ui small negative message" *ngIf="courseHierarchy.status === 'Flagged'">
{{resourceService?.messages?.imsg?.m0001}}</h6>
<!-- Info displaying if batch has expired -->
<h6 class="ui small info message" *ngIf="enrolledCourse && getBatchStatus() && batchEndDate">
{{resourceService?.frmelmnts?.lbl?.expiredBatchWarning | interpolate:'{EndDate}':batchEndDate}}</h6>
</div>
<div class="d-flex flex-ai-end flex-w-wrap certified-course" [ngClass]="{'d-flex': isDesktopApp}">
<div class="certified-course__btn py-8" *ngIf="showAddGroup">
<button class="sb-btn sb-btn-secondary sb-btn-normal ml-auto textbook__addbtn" appAddToGroup
[identifier]="courseHierarchy?.identifier" [pageId]="courseHierarchy?.primaryCategory.toLowerCase()">
{{resourceService?.frmelmnts?.lbl?.AddtoGroup}}</button>
</div>
<div *ngIf="isDesktopApp && enrolledCourse && !viewDashboard" class="d-flex py-8">
<button type="button" class="sb-btn sb-btn-outline-primary sb-btn-normal mr-8"
*ngIf="isConnected && (checkStatus('DOWNLOADED')) && showUpdate" tabindex="0"
(click)="updateCollection(courseHierarchy)">{{resourceService?.frmelmnts?.btn?.update}}</button>
<button type="button" class="sb-btn sb-btn-outline-primary sb-btn-normal mr-8"
*ngIf="checkStatus('DOWNLOADED')" [disabled]="disableDelete" tabindex="0"
(click)="logTelemetry('confirm-delete-collection'); showDeleteModal = !showDeleteModal;">{{resourceService?.frmelmnts?.btn?.delete}}</button>
<button type="button" class="sb-btn sb-btn-outline-primary sb-btn-normal mr-8"
*ngIf="checkStatus('DOWNLOADED')" tabindex="0"
(click)="exportCollection(courseHierarchy)">{{resourceService?.frmelmnts?.lbl?.saveToPenDrive}}</button>
<button type="button" class="sb-btn sb-btn-outline-primary sb-btn-normal mr-8" *ngIf="checkStatus('DOWNLOAD')"
appOnlineOnly tabindex="0"
(click)="isYoutubeContentPresent(courseHierarchy)">{{resourceService?.frmelmnts?.btn?.download}}</button>
<button type="button" class="sb-btn sb-btn-outline-primary sb-btn-normal mr-8"
*ngIf="checkStatus('DOWNLOADING')">{{resourceService?.frmelmnts?.lbl?.downloading}}</button>
<button type="button" class="sb-btn sb-btn-outline-primary sb-btn-normal mr-8"
*ngIf="checkStatus('PAUSED')">{{resourceService.frmelmnts?.lbl?.downloadingPaused}}</button>
</div>
<!-- join course, start learning, continue learning, view dashboard buttons -->
<div *ngIf="!showAddGroup && isTrackable">
<div class="certified-course__btn py-8" *ngIf="!enrolledCourse && !viewDashboard">
<button [disabled]="!(courseConsumptionService.enableCourseEntrollment | async) || isEnrollmentAllowed(enrollmentEndDate)"
[ngClass]="{'sb-btn-disabled': (!(courseConsumptionService.enableCourseEntrollment | async) || isEnrollmentAllowed(enrollmentEndDate))}"
class="sb-btn sb-btn-secondary sb-btn-normal ml-auto textbook__addbtn" tabindex="0"
(click)="showJoinModal(true); this.logTelemetry(courseHierarchy?.primaryCategory.toLowerCase() === 'course' ? 'join-course' : 'join', courseHierarchy)">{{resourceService?.frmelmnts?.btn?.enroll}}</button>
</div>
<div class="certified-course__btn py-8" *ngIf="enrolledCourse && progress===0 && !viewDashboard">
<button class="sb-btn sb-btn-secondary sb-btn-normal ml-auto textbook__addbtn" [disabled]="showResumeCourse"
tabindex="0"
(click)="resumeCourse(true); this.logTelemetry('course-start', courseHierarchy)">{{resourceService?.frmelmnts?.lbl?.startLearning}}</button>
</div>
<div class="certified-course__btn py-8" *ngIf="enrolledCourse && progress>0 && !viewDashboard">
<button class="sb-btn sb-btn-secondary sb-btn-normal textbook__addbtn ml-8 sb-btn-icon-fix"
[disabled]="showResumeCourse" tabindex="0"
(click)="resumeCourse(true); this.logTelemetry('course-resume', courseHierarchy)">
<i class="icon-svg icon-svg--xs icon-play mr-8"><svg class="icon icon-svg--primary">
<use xlink:href="assets/images/sprite.svg#play-continue"></use>
</svg></i>{{resourceService?.frmelmnts?.btn?.continueLearning}}</button>
</div>
<div class="ml-auto text-right py-8"
*ngIf="!enrolledCourse && viewDashboard && !router.url.includes('/dashboard')">
<button appTelemetryInteract [telemetryInteractObject]="courseInteractObject"
[telemetryInteractEdata]="{id:'viewCourseDashboard' , type: 'click' , pageid:'course-consumption'}"
class="sb-btn sb-btn-secondary sb-btn-normal" tabindex="0" (click)="showDashboard()">
{{resourceService?.frmelmnts?.btn?.viewCourseStatsDashboard}}
</button>
</div>
<div class="ml-auto text-right py-8"
*ngIf="!isDesktopApp && permissionService?.permissionAvailable && !enrolledCourse && viewDashboard && router.url.includes('/dashboard')"
appPermission [permission]="dashboardPermission">
<button appTelemetryInteract [telemetryInteractObject]="courseInteractObject"
[telemetryInteractEdata]="{id:'close-course-dashboard' , type: 'click' , pageid:'course-consumption'}"
class="sb-btn sb-btn-normal sb-btn-outline-primary" tabindex="0" (click)="closeDashboard()">
{{resourceService?.frmelmnts?.btn?.closedb}}
</button>
</div>
</div>
<!--Activity Dashboard-->
<div *ngIf="isGroupAdmin && isGroupURL" class="sb-activity-dashboard-btn-content py-8">
<button
class="sb-btn sb-btn-normal sb-left-icon-btn ml-8 sb-btn-icon-fix disabled sb-btn-secondary sb-activity-dashboard-btn"
appActivityDashboard [hierarchyData]="courseHierarchy">
<img src="assets/images/Activity_icon.svg" width="20px" class="mr-8" alt="Activity Dashboard">
{{resourceService?.frmelmnts?.btn?.activityDashboard}}</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="ui active inverted dimmer" *ngIf="showCopyLoader">
<div class="ui text centered inline loader mt-40">{{resourceService.frmelmnts.lbl.copycontent}}</div>
</div>
<app-certificate-name-update-popup *ngIf="showProfileUpdatePopup" [profileInfo]="profileInfo"
(close)="showProfileUpdatePopup = false"></app-certificate-name-update-popup>
<app-modal-wrapper *ngIf="sharelinkModal" [config]="{disableClose: false, panelClass: 'material-modal'}"
(dismiss)="closeSharePopup('close-share-link-popup')">
<ng-template sbModalContent>
<app-share-link [shareLink]="shareLink" [telemetryShareData]="telemetryShareData">
</app-share-link>
</ng-template>
</app-modal-wrapper>
<div *ngIf="isDesktopApp">
<app-modal-wrapper *ngIf="showModal" [config]="{disableClose: true, size: 'normal'}" (dismiss)="showModal = !showModal;"
#modal>
<ng-template sbModalContent>
<div class="sb-modal">
<div class="transition ui dimmer page modals active visible">
<div class="ui modal transition active visible normal">
<div class="sb-modal-header">
{{resourceService.frmelmnts?.btn?.download}}
</div>
<div class="sb-modal-content">
<p>{{resourceService?.messages?.stmsg?.m0137}}</p>
</div>
<div class="sb-modal-actions">
<button class="sb-btn sb-btn-normal sb-btn-primary" tabindex="0"
(click)="downloadCollection(courseHierarchy); showModal = !showModal;">
{{resourceService.frmelmnts?.btn?.download}}
</button>
<button class="sb-btn sb-btn-normal sb-btn-outline-primary" tabindex="0"
(click)="logTelemetry('cancel-download-collection'); showModal = !showModal;">
{{resourceService.frmelmnts?.btn?.cancel}}
</button>
</div>
</div>
</div>
</div>
</ng-template>
</app-modal-wrapper>
<app-modal-wrapper *ngIf="showDeleteModal" [config]="{disableClose: true, size: 'normal'}"
(dismiss)="showDeleteModal = !showDeleteModal;" #modal>
<ng-template sbModalContent>
<div class="sb-modal">
<div class="transition ui dimmer page modals active visible">
<div class="ui modal transition active visible normal">
<div class="sb-modal-header">
{{resourceService?.frmelmnts?.lbl?.delete}}
</div>
<div class="sb-modal-content">
<p>{{resourceService?.frmelmnts?.lbl?.desktop?.deleteCourse | interpolate:'{name}': courseHierarchy?.name}}
</p>
</div>
<div class="sb-modal-actions">
<button class="sb-btn sb-btn-normal sb-btn-primary" tabindex="0"
(click)="deleteCollection(courseHierarchy); showDeleteModal = !showDeleteModal;">
{{resourceService?.frmelmnts?.lbl?.delete}}
</button>
<button class="sb-btn sb-btn-normal sb-btn-outline-primary" tabindex="0"
(click)="logTelemetry('cancel-delete-collection'); showDeleteModal = !showDeleteModal;">
{{resourceService.frmelmnts?.btn?.cancel}}
</button>
</div>
</div>
</div>
</div>
</ng-template>
</app-modal-wrapper>
</div>
./course-consumption-header.component.scss
@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;
.back-btn-container {
z-index: 1;
}
.certified-course {
display: flex;
justify-self: end;
align-self: center;
}
.textbook {
&-container {
z-index: 2;
box-shadow: 0 0.125rem 0.4375rem 0 rgba(0, 0, 0, .16);
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;
}
}
&__addbtn {
white-space: nowrap;
}
}
@include respond-below(sm) {
.certified-course {
justify-self: start;
}
}
// profile certificate modal styles
.profile-section-content{
margin: 0 calculateRem(48px);
@include respond-below(sm) {
margin: 0;
}
.profile-info{
span{
&:first-child{
font-size: calculateRem(12px);
}
color: var(--gray);
font-size: calculateRem(20px);
}
}
.profile-info-para{
font-size: calculateRem(14px);
}
}
.sb-activity-dashboard-btn {
box-shadow: none;
color: var(--white) !important;
font-size: calculateRem(12px);
padding-bottom: calculateRem(28px);
}