src/app/enrolled-course-details-page/enrolled-course-details-page.ts
OnInit
OnDestroy
ConsentPopoverActionsDelegate
selector | app-enrolled-course-details-page |
styleUrls | ./enrolled-course-details-page.scss |
templateUrl | ./enrolled-course-details-page.html |
constructor(profileService: ProfileService, contentService: ContentService, eventsBusService: EventsBusService, courseService: CourseService, preferences: SharedPreferences, authService: AuthService, downloadService: DownloadService, discussionService: DiscussionService, zone: NgZone, events: Events, fileSizePipe: FileSizePipe, popoverCtrl: PopoverController, courseUtilService: CourseUtilService, platform: Platform, appGlobalService: AppGlobalService, telemetryGeneratorService: TelemetryGeneratorService, commonUtilService: CommonUtilService, datePipe: DatePipe, utilityService: UtilityService, headerService: AppHeaderService, location: Location, router: Router, contentDeleteHandler: ContentDeleteHandler, localCourseService: LocalCourseService, sbProgressLoader: SbProgressLoader, categoryKeyTranslator: CategoryKeyTranslator, consentService: ConsentService, tncUpdateHandlerService: TncUpdateHandlerService)
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Parameters :
|
Async batchEndDateStatus | ||||
batchEndDateStatus(batchEndDate)
|
||||
Parameters :
Returns :
any
|
cancelDownload |
cancelDownload()
|
Returns :
void
|
checkCurrentUserType |
checkCurrentUserType()
|
Returns :
void
|
Async checkDataSharingStatus |
checkDataSharingStatus()
|
Returns :
any
|
Private Async checkRetiredOpenBatch |
checkRetiredOpenBatch(content: any, layoutName?: string)
|
Returns :
any
|
Private checkUserLoggedIn |
checkUserLoggedIn()
|
Returns :
void
|
editDataSettings |
editDataSettings()
|
Returns :
void
|
Async enrollIntoBatch | |||||||||
enrollIntoBatch(item: Batch, course?)
|
|||||||||
Parameters :
Returns :
any
|
expandDataSettings |
expandDataSettings()
|
Returns :
void
|
Async extractApiResponse | ||||||
extractApiResponse(data: Content)
|
||||||
Function to extract api response. Check content is locally available or not. If locally available then make childContents api call else make import content api call
Parameters :
Returns :
any
|
Private generateContentNavExtras | |||||||||
generateContentNavExtras(content: Content, depth)
|
|||||||||
Parameters :
Returns :
NavigationExtras
|
generateDataForDF |
generateDataForDF()
|
Returns :
void
|
generateEndEvent | ||||||||
generateEndEvent(objectId, objectType, objectVersion)
|
||||||||
Parameters :
Returns :
void
|
generateImpressionEvent | ||||||||
generateImpressionEvent(objectId, objectType, objectVersion)
|
||||||||
Parameters :
Returns :
void
|
Private generateLogEvent | ||||||
generateLogEvent(message: string)
|
||||||
Parameters :
Returns :
void
|
generateQRSessionEndEvent |
generateQRSessionEndEvent(pageId: string, qrData: string)
|
Returns :
void
|
generateStartEvent | ||||||||
generateStartEvent(objectId, objectType, objectVersion)
|
||||||||
Parameters :
Returns :
void
|
Async getAllBatches |
getAllBatches()
|
Returns :
any
|
getBatchCreatorName |
getBatchCreatorName()
|
Returns :
void
|
Async getBatchDetails | ||||
getBatchDetails(batchId?)
|
||||
Get batch details
Parameters :
Returns :
any
|
getContentsSize | ||||
getContentsSize(data?)
|
||||
Parameters :
Returns :
void
|
Async getContentState | ||||||
getContentState(returnRefresh: boolean)
|
||||||
Parameters :
Returns :
any
|
Async getCourseHierarchy | |||||||||
getCourseHierarchy(request: ContentDetailRequest, data: Content)
|
|||||||||
Parameters :
Returns :
any
|
getCourseProgress |
getCourseProgress()
|
Returns :
void
|
getImportContentRequestBody | ||||||||||||
getImportContentRequestBody(identifiers, isChild: boolean)
|
||||||||||||
Function to get import content api request params
Parameters :
Returns :
Array<ContentImport>
|
Private getLeafNodeIdsWithoutDuplicates | ||||||
getLeafNodeIdsWithoutDuplicates(contents: Content[])
|
||||||
Parameters :
Returns :
Set<string>
|
Private getLeafNodes | ||||||
getLeafNodes(contents: Content[])
|
||||||
Parameters :
Returns :
any
|
getLocalCourseAndUnitProgress |
getLocalCourseAndUnitProgress()
|
Returns :
void
|
Private getNextContent | |||||||||
getNextContent(courseHeirarchy, contentStateList: ContentState[])
|
|||||||||
Parameters :
Returns :
Content
|
Private getStatusOfCourseCompletion | ||||||
getStatusOfCourseCompletion(childrenData: Content[])
|
||||||
Function to get status of child contents
Parameters :
Returns :
void
|
Async goBack |
goBack()
|
Returns :
any
|
handleBackButton |
handleBackButton()
|
Returns :
void
|
Async handleHeaderEvents | ||||
handleHeaderEvents($event)
|
||||
Parameters :
Returns :
any
|
handleNavBackButton |
handleNavBackButton()
|
Returns :
void
|
handleUnenrollButton |
handleUnenrollButton()
|
Returns :
void
|
Async handleUnenrollment | ||||
handleUnenrollment(unenroll)
|
||||
Parameters :
Returns :
any
|
importContent | ||||||||||||||||
importContent(identifiers, isChild: boolean, isDownloadAllClicked?)
|
||||||||||||||||
Function to get import content api request params
Parameters :
Returns :
void
|
Private initNextContent |
initNextContent()
|
Returns :
void
|
ionViewDidEnter |
ionViewDidEnter()
|
Returns :
void
|
Async ionViewWillEnter |
ionViewWillEnter()
|
Ionic life cycle hook
Returns :
any
|
ionViewWillLeave |
ionViewWillLeave()
|
Ionic life cycle hook
Returns :
void
|
isCourseEnrolled | ||||||
isCourseEnrolled(identifier: string)
|
||||||
Parameters :
Returns :
void
|
isCourseMentorValidation |
isCourseMentorValidation()
|
Returns :
void
|
isCourseModifiedAfterEnrolment |
isCourseModifiedAfterEnrolment()
|
Returns :
boolean
|
isGroupShown | ||||
isGroupShown(group)
|
||||
Parameters :
Returns :
boolean
|
Async joinTraining |
joinTraining()
|
Returns :
any
|
markContent |
markContent()
|
Returns :
void
|
mergeProperties | ||||
mergeProperties(mergeProp)
|
||||
Parameters :
Returns :
any
|
Async navigateToBatchListPage |
navigateToBatchListPage()
|
checks whether batches are available or not and then Navigate user to batch list page
Returns :
any
|
Async navigateToBatchListPopup |
navigateToBatchListPopup(content: any, layoutName?: string, retiredBatched?: any)
|
Returns :
any
|
Private navigateToContentDetails | |||||||||
navigateToContentDetails(content: Content, depth)
|
|||||||||
Redirect to child content details page
Parameters :
Returns :
void
|
navigateToDashboard |
navigateToDashboard()
|
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Angular life cycle hooks
Returns :
void
|
onboardingSkippedBackAction |
onboardingSkippedBackAction()
|
Returns :
Promise<boolean>
|
onConsentPopoverDismiss |
onConsentPopoverDismiss()
|
Returns :
void
|
onConsentPopoverShow |
onConsentPopoverShow()
|
Returns :
void
|
onSegmentChange | ||||
onSegmentChange(event)
|
||||
Parameters :
Returns :
void
|
onTocCardClick | ||||
onTocCardClick(event)
|
||||
Parameters :
Returns :
boolean
|
openBrowser | ||||
openBrowser(url)
|
||||
url opens in browser
Parameters :
Returns :
void
|
populateCorRelationData | ||||
populateCorRelationData(batchId)
|
||||
Parameters :
Returns :
void
|
Async promptToLogin | ||||
promptToLogin(batchdetail)
|
||||
Parameters :
Returns :
any
|
Async rateContent | ||||
rateContent(event)
|
||||
Function to rate content
Parameters :
Returns :
any
|
Async refreshCourseDetails | ||||
refreshCourseDetails(data)
|
||||
Parameters :
Returns :
any
|
refreshHeader |
refreshHeader()
|
Returns :
void
|
Private Async reloadPageAfterEnrollment | ||||
reloadPageAfterEnrollment(res)
|
||||
Parameters :
Returns :
any
|
restoreDownloadState |
restoreDownloadState()
|
Returns :
void
|
Async resumeContent |
resumeContent()
|
Function gets executed when user click on resume course button.
Returns :
Promise<void>
|
Async saveChanges |
saveChanges()
|
Returns :
any
|
saveContentContext | ||||||||||
saveContentContext(userId, courseId, batchId, batchStatus)
|
||||||||||
Parameters :
Returns :
void
|
Async setChildContents |
setChildContents()
|
Function to set child contents
Returns :
any
|
setContentDetails | ||||
setContentDetails(identifier)
|
||||
Set course details by passing course identifier
Parameters :
Returns :
void
|
setCourseStructure |
setCourseStructure()
|
Set course structure
Returns :
void
|
Private setExtrasData | ||||
setExtrasData(extrasState)
|
||||
Parameters :
Returns :
void
|
Async share |
share()
|
Returns :
any
|
Async showConfirmAlert |
showConfirmAlert()
|
Returns :
any
|
showDeletePopup |
showDeletePopup()
|
Returns :
void
|
Async showDownloadConfirmationAlert |
showDownloadConfirmationAlert()
|
Returns :
any
|
Async showOverflowMenu | ||||
showOverflowMenu(event)
|
||||
Parameters :
Returns :
any
|
Private Async showProfileNameConfirmationPopup |
showProfileNameConfirmationPopup()
|
Returns :
any
|
Private Async startContent |
startContent()
|
Returns :
any
|
Async startLearning |
startLearning()
|
Returns :
any
|
subscribeSdkEvent |
subscribeSdkEvent()
|
Subscribe Sunbird-SDK event to get content download progress
Returns :
void
|
subscribeTrackDownloads |
subscribeTrackDownloads()
|
Returns :
void
|
subscribeUtilityEvents |
subscribeUtilityEvents()
|
Returns :
void
|
Async syncProgress |
syncProgress()
|
Returns :
any
|
toggleGroup | ||||||
toggleGroup(group, content)
|
||||||
Parameters :
Returns :
void
|
Async updateEnrolledCourseData |
updateEnrolledCourseData()
|
Returns :
any
|
viewCredits |
viewCredits()
|
Opens up popup for the credits.
Returns :
void
|
accessDiscussionComponent |
Type : AccessDiscussionComponent
|
Decorators :
@ViewChild(AccessDiscussionComponent, {static: false})
|
activityData |
Type : ActivityData
|
appName |
Type : any
|
Public authService |
Type : AuthService
|
Decorators :
@Inject('AUTH_SERVICE')
|
backButtonFunc |
Default value : undefined
|
baseUrl |
Type : string
|
Default value : ''
|
batchCount |
Type : number
|
batchDetails |
Type : Batch
|
batchEndDate |
Type : string
|
Public batches |
Type : Array<any>
|
To check batches available or not |
batchExp |
Default value : false
|
batchId |
Type : string
|
Default value : ''
|
batchRemaningTime |
Type : any
|
Private Optional batchRemaningTimingIntervalRef |
Type : any
|
certificateDescription |
Type : string
|
Default value : ''
|
certificateDetails |
Type : any
|
content |
Type : Content
|
contentDeleteObservable |
Type : any
|
contentId |
Type : string
|
contentStatusData |
Type : ContentStateResponse
|
corRelationList |
Type : Array<CorrelationData>
|
course |
Type : any
|
Contains content details |
courseBatchesRequest |
Type : CourseBatchesRequest
|
courseCardData |
Type : any
|
Contains card data of previous state |
Public courseCompletionData |
Type : object
|
Default value : {}
|
courseHeirarchy |
Type : any
|
Contains children content data |
courseStartDate |
To hold start date of a course |
createUserReq |
Type : object
|
Default value : {
username: '',
identifier: ''
}
|
Private csGroupAddableBloc |
Type : CsGroupAddableBloc
|
currentCount |
Type : number
|
Default value : 0
|
dataSharingStatus |
Type : any
|
didViewLoad |
Type : boolean
|
downloadIdentifiers |
Default value : new Set()
|
Contains identifier(s) of locally not available content(s) |
downloadProgress |
Type : number
|
Default value : 0
|
Contains child content import / download progress |
downloadSize |
Type : number
|
Default value : 0
|
Contains total size of locally not available content(s) |
enrollmentEndDate |
Type : string
|
Private eventSubscription |
Type : Subscription
|
faultyIdentifiers |
Type : Array<any>
|
Default value : []
|
fetchForumIdReq |
Type : object
|
Default value : {
identifier: [],
type: ''
}
|
Optional forumId |
Type : string
|
forumIds |
Private hasInit |
Default value : false
|
headerObservable |
Type : any
|
identifier |
Type : string
|
To hold identifier |
importProgressMessage |
Type : string
|
isAlreadyEnrolled |
Default value : false
|
isBatchNotStarted |
Default value : false
|
Whole child content is stored and it is used to find first child |
isCertifiedCourse |
Type : boolean
|
isChild |
Default value : false
|
isConsentPopUp |
Default value : false
|
isContentPlayed |
isCourseMentor |
Default value : false
|
isDataShare |
Default value : false
|
isDownloadComplete |
Default value : false
|
isDownloadStarted |
Default value : false
|
isFirstContent |
Default value : false
|
Private isFromChannelDeeplink |
Type : any
|
isFromGroupFlow |
Default value : false
|
isGuestUser |
Default value : false
|
isMinor |
Type : boolean
|
isNavigatingWithinCourse |
Default value : false
|
isNextContentFound |
Default value : false
|
Private isOnboardingSkipped |
Type : any
|
isQrCodeLinkToContent |
Type : any
|
isShared |
Type : any
|
lastUpdateOn |
Type : string
|
leaveTrainigPopover |
Type : any
|
licenseDetails |
Optional loader |
Type : HTMLIonLoadingElement
|
nextContent |
Type : Content
|
objectKeys |
Default value : Object.keys
|
To get course structure keyspkgVersion |
objId |
Public objRollup |
Type : Rollup
|
objType |
objVer |
pageId |
Type : string
|
Default value : PageId.COURSE_DETAIL
|
pageName |
Type : string
|
Default value : ''
|
Optional profile |
Type : Profile
|
profileType |
Type : string
|
Default value : ''
|
queuedIdentifiers |
Type : Array<string>
|
Default value : []
|
ratingComment |
Type : string
|
Default value : ''
|
resumeCourseFlag |
Default value : false
|
Public rollUpMap |
Type : literal type
|
Default value : {}
|
segmentType |
Type : string
|
Default value : 'info'
|
shouldGenerateEndTelemetry |
Default value : false
|
showCertificateDetails |
Default value : false
|
showChildrenLoader |
Type : boolean
|
Show loader while importing content |
showCollapsedPopup |
Default value : true
|
showCredits |
Default value : false
|
showDownload |
Type : boolean
|
showDownloadProgress |
Type : boolean
|
showLoading |
Default value : false
|
shownGroup |
showOfflineSection |
Default value : false
|
showResumeBtn |
Type : boolean
|
Flag to show / hide resume button |
showShareData |
Default value : false
|
showSheenAnimation |
Default value : true
|
Public showUnenroll |
Type : boolean
|
showUnenrollButton |
Default value : false
|
skipCheckRetiredOpenBatch |
Default value : false
|
source |
Type : string
|
Default value : ''
|
stickyPillsRef |
Type : ElementRef
|
Decorators :
@ViewChild('stickyPillsRef', {static: false})
|
Public telemetryObject |
Type : TelemetryObject
|
Public todayDate |
Type : any
|
totalDownload |
Type : number
|
trackDownloads$ |
Type : Observable<DownloadTracking>
|
updatedCourseCardData |
Type : Course
|
userId |
Type : string
|
Default value : ''
|
userRating |
Type : number
|
Default value : 0
|
import { Component, ElementRef, Inject, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { Platform, PopoverController } from '@ionic/angular';
import { Events } from '@app/util/events';
import isObject from 'lodash/isObject';
import forEach from 'lodash/forEach';
import { FileSizePipe } from '@app/pipes/file-size/file-size';
import { AppGlobalService } from '@app/services/app-global-service.service';
import { CommonUtilService } from '@app/services/common-util.service';
import { CourseUtilService } from '@app/services/course-util.service';
import { TelemetryGeneratorService } from '@app/services/telemetry-generator.service';
import { UtilityService } from '@app/services/utility-service';
import { AppHeaderService } from '@app/services/app-header.service';
import { DatePipe, Location } from '@angular/common';
import {
AuditState, AuthService,
Batch,
ChildContentRequest, Consent, Content, ContentDetailRequest,
ContentEventType, ContentImport, ContentImportCompleted,
ContentImportRequest, ContentImportResponse, ContentImportStatus,
ContentService, ContentState, ContentStateResponse, ContentUpdate,
CorrelationData, Course, CourseBatchesRequest, CourseBatchStatus,
CourseEnrollmentType, CourseService,
DownloadEventType, DownloadProgress,
DownloadService, DownloadTracking,
EventsBusEvent, EventsBusService,
FetchEnrolledCourseRequest,
GetContentStateRequest,
NetworkError,
ProfileService,
Profile,
Rollup,
ServerProfileDetailsRequest, SharedPreferences, SortOrder,
TelemetryErrorCode, TelemetryObject,
UnenrollCourseRequest, DiscussionService, LogLevel, ContentAccess, ContentAccessStatus, ContentMarkerRequest, MarkerType
} from 'sunbird-sdk';
import { Observable, Subscription } from 'rxjs';
import {
AuditType,
CorReleationDataType,
Environment, ErrorType,
ImpressionType, InteractSubtype, InteractType,
Mode,
PageId
} from '../../services/telemetry-constants';
import {
BatchConstants, ContentCard, EventTopics, MimeType,
PreferenceKey, ProfileConstants, RouterLinks, ShareItemType
} from '../app.constant';
import { SbGenericPopoverComponent } from '../components/popups/sb-generic-popover/sb-generic-popover.component';
import { ConfirmAlertComponent, ContentActionsComponent, ContentRatingAlertComponent } from '../components';
import { NavigationExtras, Router } from '@angular/router';
import { ContentUtil } from '@app/util/content-util';
import { SbPopoverComponent } from '../components/popups';
import { ContentInfo } from '@app/services/content/content-info';
import { ContentDeleteHandler } from '@app/services/content/content-delete-handler';
import { LocalCourseService } from '@app/services';
import { EnrollCourse } from './course.interface';
import { SbSharePopupComponent } from '../components/popups/sb-share-popup/sb-share-popup.component';
import { share } from 'rxjs/operators';
import { SbProgressLoader } from '../../services/sb-progress-loader.service';
import { CsGroupAddableBloc } from '@project-sunbird/client-services/blocs';
import { CsPrimaryCategory } from '@project-sunbird/client-services/services/content';
import { ConsentStatus, UserConsent } from '@project-sunbird/client-services/models';
import { ConsentPopoverActionsDelegate } from '@app/services/local-course.service';
import { CategoryKeyTranslator } from '@app/pipes/category-key-translator/category-key-translator-pipe';
import { ConsentService } from '@app/services/consent-service';
import {
ProfileNameConfirmationPopoverComponent
} from '../components/popups/sb-profile-name-confirmation-popup/sb-profile-name-confirmation-popup.component';
import { TncUpdateHandlerService } from '@app/services/handlers/tnc-update-handler.service';
import { EnrollmentDetailsComponent } from '../components/enrollment-details/enrollment-details.component';
import { TagPrefixConstants } from '@app/services/segmentation-tag/segmentation-tag.service';
import { AccessDiscussionComponent } from '@app/app/components/access-discussion/access-discussion.component';
import { ActivityData } from '../my-groups/group.interface';
declare const cordova;
@Component({
selector: 'app-enrolled-course-details-page',
templateUrl: './enrolled-course-details-page.html',
styleUrls: ['./enrolled-course-details-page.scss'],
})
export class EnrolledCourseDetailsPage implements OnInit, OnDestroy, ConsentPopoverActionsDelegate {
/**
* Contains content details
*/
course: any;
/**
* Contains children content data
*/
courseHeirarchy: any;
shownGroup: null;
/**
* Show loader while importing content
*/
showChildrenLoader: boolean;
/**
* Contains identifier(s) of locally not available content(s)
*/
downloadIdentifiers = new Set();
/**
* Contains total size of locally not available content(s)
*/
downloadSize = 0;
/**
* Flag to show / hide resume button
*/
showResumeBtn: boolean;
/**
* Contains card data of previous state
*/
courseCardData: any;
/**
* To get course structure keyspkgVersion
*/
objectKeys = Object.keys;
/**
* To hold identifier
*/
identifier: string;
/**
* Contains child content import / download progress
*/
downloadProgress = 0;
/**
* To check batches available or not
*/
public batches: Array<any>;
isNavigatingWithinCourse = false;
contentStatusData: ContentStateResponse;
/**
* To hold start date of a course
*/
courseStartDate;
isContentPlayed;
showLoading = false;
showDownloadProgress: boolean;
totalDownload: number;
currentCount = 0;
isDownloadComplete = false;
queuedIdentifiers: Array<string> = [];
faultyIdentifiers: Array<any> = [];
isDownloadStarted = false;
batchDetails: Batch;
batchExp = false;
userId = '';
userRating = 0;
ratingComment = '';
batchId = '';
baseUrl = '';
isGuestUser = false;
isAlreadyEnrolled = false;
profileType = '';
objId;
objType;
batchCount: number;
batchEndDate: string;
objVer;
didViewLoad: boolean;
backButtonFunc = undefined;
shouldGenerateEndTelemetry = false;
source = '';
isFromGroupFlow = false;
/** Whole child content is stored and it is used to find first child */
isBatchNotStarted = false;
private eventSubscription: Subscription;
corRelationList: Array<CorrelationData>;
headerObservable: any;
content: Content;
appName: any;
updatedCourseCardData: Course;
importProgressMessage: string;
segmentType = 'info';
showDownload: boolean;
enrollmentEndDate: string;
loader?: HTMLIonLoadingElement;
isQrCodeLinkToContent: any;
leaveTrainigPopover: any;
showOfflineSection = false;
courseBatchesRequest: CourseBatchesRequest;
showUnenrollButton = false;
licenseDetails;
forumId?: string;
@ViewChild('stickyPillsRef', { static: false }) stickyPillsRef: ElementRef;
@ViewChild(AccessDiscussionComponent, { static: false }) accessDiscussionComponent: AccessDiscussionComponent;
public objRollup: Rollup;
pageName = '';
contentId: string;
isChild = false;
public telemetryObject: TelemetryObject;
showCredits = false;
contentDeleteObservable: any;
public showUnenroll: boolean;
public todayDate: any;
public rollUpMap: { [key: string]: Rollup } = {};
public courseCompletionData = {};
isCertifiedCourse: boolean;
showSheenAnimation = true;
private isOnboardingSkipped: any;
private isFromChannelDeeplink: any;
trackDownloads$: Observable<DownloadTracking>;
showCollapsedPopup = true;
resumeCourseFlag = false;
isNextContentFound = false;
isFirstContent = false;
nextContent: Content;
certificateDescription = '';
private csGroupAddableBloc: CsGroupAddableBloc;
pageId: string = PageId.COURSE_DETAIL;
showShareData = false;
isDataShare = false;
isShared: any;
dataSharingStatus: any;
lastUpdateOn: string;
isConsentPopUp = false;
skipCheckRetiredOpenBatch = false;
forumIds;
private hasInit = false;
fetchForumIdReq = {
identifier: [],
type: ''
};
createUserReq = {
username: '',
identifier: ''
};
batchRemaningTime: any;
private batchRemaningTimingIntervalRef?: any;
isMinor: boolean;
activityData: ActivityData;
showCertificateDetails= false;
certificateDetails: any;
isCourseMentor = false;
profile?: Profile;
constructor(
@Inject('PROFILE_SERVICE') private profileService: ProfileService,
@Inject('CONTENT_SERVICE') private contentService: ContentService,
@Inject('EVENTS_BUS_SERVICE') private eventsBusService: EventsBusService,
@Inject('COURSE_SERVICE') private courseService: CourseService,
@Inject('SHARED_PREFERENCES') private preferences: SharedPreferences,
@Inject('AUTH_SERVICE') public authService: AuthService,
@Inject('DOWNLOAD_SERVICE') private downloadService: DownloadService,
@Inject('DISCUSSION_SERVICE') private discussionService: DiscussionService,
private zone: NgZone,
private events: Events,
private fileSizePipe: FileSizePipe,
private popoverCtrl: PopoverController,
private courseUtilService: CourseUtilService,
private platform: Platform,
private appGlobalService: AppGlobalService,
private telemetryGeneratorService: TelemetryGeneratorService,
private commonUtilService: CommonUtilService,
private datePipe: DatePipe,
private utilityService: UtilityService,
private headerService: AppHeaderService,
private location: Location,
private router: Router,
private contentDeleteHandler: ContentDeleteHandler,
private localCourseService: LocalCourseService,
private sbProgressLoader: SbProgressLoader,
private categoryKeyTranslator: CategoryKeyTranslator,
private consentService: ConsentService,
private tncUpdateHandlerService: TncUpdateHandlerService,
) {
this.objRollup = new Rollup();
this.csGroupAddableBloc = CsGroupAddableBloc.instance;
const extrasState = this.router.getCurrentNavigation().extras.state;
this.setExtrasData(extrasState);
this.events.subscribe(EventTopics.DEEPLINK_COURSE_PAGE_OPEN, (data) => {
if (data.content) {
this.refreshCourseDetails(data);
}
});
}
private setExtrasData(extrasState) {
if (extrasState) {
this.courseCardData = extrasState.content;
this.isOnboardingSkipped = extrasState.isOnboardingSkipped;
this.isFromChannelDeeplink = extrasState.isFromChannelDeeplink;
this.identifier = this.courseCardData.contentId || this.courseCardData.identifier;
this.corRelationList = extrasState.corRelation;
this.source = extrasState.source;
if (CsGroupAddableBloc.instance.initialised) {
this.isFromGroupFlow = true;
}
this.isQrCodeLinkToContent = extrasState.isQrCodeLinkToContent;
this.resumeCourseFlag = extrasState.resumeCourseFlag || false;
this.skipCheckRetiredOpenBatch = extrasState.skipCheckRetiredOpenBatch;
this.activityData = extrasState.activityData || undefined;
this.pageId = this.commonUtilService.appendTypeToPrimaryCategory(this.courseCardData) || this.pageId;
}
}
async refreshCourseDetails(data){
// For Deeplink scenario on same page
this.ionViewWillLeave();
this.ngOnDestroy();
this.setExtrasData(data);
this.ngOnInit();
await this.ionViewWillEnter();
this.ionViewDidEnter();
}
/**
* Angular life cycle hooks
*/
ngOnInit() {
this.commonUtilService.getAppName().then((res) => { this.appName = res; });
this.subscribeUtilityEvents();
if (this.courseCardData.batchId) {
this.segmentType = 'modules';
}
this.generateDataForDF();
}
showDeletePopup() {
this.contentDeleteObservable = this.contentDeleteHandler.contentDeleteCompleted$.subscribe(async () => {
if (await this.onboardingSkippedBackAction()) {
return;
}
this.location.back();
});
const contentInfo: ContentInfo = {
telemetryObject: this.telemetryObject,
rollUp: this.objRollup,
correlationList: this.corRelationList,
hierachyInfo: undefined
};
this.contentDeleteHandler.showContentDeletePopup(this.content, this.isChild, contentInfo, this.pageId);
}
subscribeUtilityEvents() {
this.utilityService.getBuildConfigValue('BASE_URL')
.then(response => {
this.baseUrl = response;
});
this.events.subscribe(EventTopics.ENROL_COURSE_SUCCESS, async (res) => {
this.reloadPageAfterEnrollment(res);
});
this.events.subscribe(EventTopics.UNENROL_COURSE_SUCCESS, async () => {
// to show 'Enroll in Course' button courseCardData.batchId should be undefined/null
this.getAllBatches();
await this.updateEnrolledCourseData(); // enrolled course list updated
if (this.courseCardData) {
delete this.courseCardData.batchId;
}
delete this.batchDetails;
this.isAlreadyEnrolled = false; // and isAlreadyEnrolled should be false
this.isBatchNotStarted = false; // this is needed to change behaviour onclick of individual content
this.segmentType = 'info';
this.getLocalCourseAndUnitProgress();
});
this.events.subscribe('courseToc:content-clicked', (data) => {
console.log('courseToc:content-clicked', data);
if (this.course.createdBy !== this.userId) {
if (!data.isEnrolled && !data.isBatchNotStarted) {
this.joinTraining();
} else if (data.isEnrolled && data.isBatchNotStarted) {
this.commonUtilService.showToast(this.commonUtilService.translateMessage('COURSE_WILL_BE_AVAILABLE',
this.datePipe.transform(this.courseStartDate, 'mediumDate')));
}
}
});
this.events.subscribe('header:setzIndexToNormal', () => {
if (this.stickyPillsRef && this.stickyPillsRef.nativeElement) {
this.stickyPillsRef.nativeElement.classList.remove('z-index-0');
}
});
this.events.subscribe('header:decreasezIndex', () => {
if (this.stickyPillsRef && this.stickyPillsRef.nativeElement) {
this.stickyPillsRef.nativeElement.classList.add('z-index-0');
}
});
}
private async reloadPageAfterEnrollment(res) {
await this.appGlobalService.getActiveProfileUid()
.then((uid) => {
this.userId = uid;
});
this.checkUserLoggedIn();
await this.updateEnrolledCourseData();
this.courseCardData.batchId = res.batchId;
await this.getBatchDetails();
this.segmentType = 'modules';
this.getContentState(true);
if (res && res.batchId) {
this.batchId = res.batchId;
if (this.identifier && res.courseId && this.identifier === res.courseId) {
await this.isCourseEnrolled(this.identifier);
this.zone.run(() => {
this.getContentsSize(this.courseHeirarchy.children);
if (this.loader) {
this.loader.dismiss();
this.loader = undefined;
}
});
}
}
this.accessDiscussionComponent && this.accessDiscussionComponent.fetchForumIds();
}
private checkUserLoggedIn() {
this.isGuestUser = !this.appGlobalService.isUserLoggedIn();
}
async updateEnrolledCourseData() {
const fetchEnrolledCourseRequest: FetchEnrolledCourseRequest = {
userId: this.userId,
returnFreshCourses: true
};
console.log('updateEnrolledCourseData');
this.updatedCourseCardData = await this.courseService.getEnrolledCourses(fetchEnrolledCourseRequest).toPromise()
.then((enrolledCourses) => {
this.appGlobalService.setEnrolledCourseList(enrolledCourses || []);
return enrolledCourses.find((element) =>
(this.courseCardData.batchId && element.batchId === this.courseCardData.batchId)
|| (!this.courseCardData.batchId && element.courseId === this.identifier));
})
.catch(e => {
console.log(e);
return undefined;
});
if (this.updatedCourseCardData && !this.courseCardData.batch) {
this.courseCardData.batch = this.updatedCourseCardData.batch;
this.courseCardData.batchId = this.updatedCourseCardData.batchId;
}
}
subscribeTrackDownloads() {
this.trackDownloads$ = this.downloadService.trackDownloads({ groupBy: { fieldPath: 'rollUp.l1', value: this.identifier } }).pipe(
share());
}
checkCurrentUserType() {
if (this.isGuestUser) {
this.appGlobalService.getGuestUserInfo()
.then((userType) => {
this.profileType = userType;
})
.catch((error) => {
this.profileType = '';
});
}
}
async joinTraining() {
if (!this.batches.length) {
this.commonUtilService.showToast('NO_BATCHES_AVAILABLE');
return;
} else if (
this.batches.length === 1 &&
this.batches[0].enrollmentEndDate &&
((new Date().setHours(0, 0, 0, 0)) > new Date(this.batches[0].enrollmentEndDate).setHours(0, 0, 0, 0))
) {
this.commonUtilService.showToast(
'ENROLLMENT_ENDED_ON',
null,
null,
null,
null,
this.datePipe.transform(this.batches[0].enrollmentEndDate)
);
return;
}
const confirm = await this.popoverCtrl.create({
component: SbPopoverComponent,
componentProps: {
sbPopoverMainTitle: this.categoryKeyTranslator.transform('FRMELEMNTS_MSG_YOU_MUST_JOIN_AN_ACTIVE_BATCH', this.course),
metaInfo: this.commonUtilService.translateMessage('REGISTER_TO_COMPLETE_ACCESS'),
sbPopoverHeading: this.categoryKeyTranslator.transform('FRMELEMNTS_LBL_JOIN_TRAINING', this.course) + '?',
isNotShowCloseIcon: true,
actionsButtons: [
{
btntext: this.categoryKeyTranslator.transform('FRMELEMNTS_LBL_JOIN_TRAINING', this.course),
btnClass: 'popover-color label-uppercase label-bold-font'
},
],
},
cssClass: 'sb-popover info',
});
await confirm.present();
confirm.onDidDismiss().then(({ data }) => {
if (data && data.canDelete) {
this.navigateToBatchListPage();
}
});
}
/**
* Function to rate content
*/
async rateContent(event) {
if (!this.isGuestUser) {
if (this.course.isAvailableLocally) {
const popUp = await this.popoverCtrl.create({
component: ContentRatingAlertComponent,
event,
componentProps: {
content: this.course,
rating: this.userRating,
comment: this.ratingComment,
pageId: this.pageId
},
cssClass: 'sb-popover info',
});
await popUp.present();
const { data } = await popUp.onDidDismiss();
if (data && data.message === 'rating.success') {
this.userRating = data.rating;
this.ratingComment = data.comment;
}
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.RATING_CLICKED,
Environment.HOME,
PageId.CONTENT_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList);
} else {
this.commonUtilService.showToast('TRY_BEFORE_RATING');
}
} else {
if (this.commonUtilService.isAccessibleForNonStudentRole(this.profileType)) {
this.commonUtilService.showToast('SIGNIN_TO_USE_FEATURE');
}
}
}
async showOverflowMenu(event) {
this.telemetryGeneratorService.generateInteractTelemetry( InteractType.TOUCH, InteractSubtype.COURSE_KEBAB_MENU_CLICKED,
Environment.COURSE,
PageId.COURSE_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList);
this.leaveTrainigPopover = await this.popoverCtrl.create({
component: ContentActionsComponent,
event,
cssClass: 'leave-training-popup',
showBackdrop: false,
componentProps: {
content: this.course,
batchDetails: this.batchDetails,
pageName: this.pageId,
corRelationList: this.corRelationList,
objRollup: this.telemetryObject,
showUnenrollButton: this.showUnenrollButton
},
});
await this.leaveTrainigPopover.present();
const { data } = await this.leaveTrainigPopover.onDidDismiss();
if (data && data.unenroll) {
this.showConfirmAlert();
} else if (data && data.syncProgress) {
this.syncProgress();
}
}
async syncProgress() {
const loader = await this.commonUtilService.getLoader();
this.generateLogEvent(InteractSubtype.SYNC_PROGRESS_INITIATE);
await loader.present();
this.courseService.syncCourseProgress({
courseId: this.identifier,
userId: this.userId,
batchId: this.batchDetails.id
}).toPromise()
.then(async () => {
this.generateLogEvent(InteractSubtype.SYNC_PROGRESS_SUCCESS);
await loader.dismiss();
this.commonUtilService.showToast('FRMELEMNTS_MSG_SYNC_COURSE_PROGRESS_SUCCESS');
}).catch(async () => {
await loader.dismiss();
this.generateLogEvent(InteractSubtype.SYNC_PROGRESS_FAILED);
this.commonUtilService.showToast('ERROR_TECHNICAL_PROBLEM');
});
}
private generateLogEvent(message: string) {
this.telemetryGeneratorService.generateLogEvent(
LogLevel.INFO,
message,
Environment.COURSE,
'api_call',
this.corRelationList || []
);
}
async showConfirmAlert() {
const confirm = await this.popoverCtrl.create({
component: SbGenericPopoverComponent,
componentProps: {
sbPopoverHeading: this.categoryKeyTranslator.transform('FRMELEMNTS_LBL_LEAVE_TRAINING_HEADING', this.course),
sbPopoverMainTitle: this.commonUtilService.translateMessage('UNENROLL_CONFIRMATION_MESSAGE'),
actionsButtons: [
{
btntext: this.commonUtilService.translateMessage('CANCEL'),
btnClass: 'sb-btn sb-btn-sm sb-btn-outline-info'
},
{
btntext: this.commonUtilService.translateMessage('CONFIRM'),
btnClass: 'popover-color'
}
],
icon: null
},
cssClass: 'sb-popover info',
});
await confirm.present();
const { data } = await confirm.onDidDismiss();
let unenroll = false;
if (data && data.isLeftButtonClicked === false) {
unenroll = true;
this.handleUnenrollment(unenroll);
}
}
/*
* check for user confirmation
* if confirmed then unenrolls the user from the course
*/
async handleUnenrollment(unenroll) {
if (unenroll) {
const loader = await this.commonUtilService.getLoader();
await loader.present();
const unenrolCourseRequest: UnenrollCourseRequest = {
userId: this.appGlobalService.getUserId(),
courseId: this.batchDetails.courseId,
batchId: this.batchDetails.id
};
this.courseService.unenrollCourse(unenrolCourseRequest)
.subscribe(() => {
this.zone.run(async () => {
await loader.dismiss();
this.commonUtilService.showToast(this.categoryKeyTranslator.transform('FRMELEMNTS_MSG_COURSE_UNENROLLED', this.course));
this.events.publish(EventTopics.UNENROL_COURSE_SUCCESS, {});
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.OTHER,
InteractSubtype.UNENROL_SUCCESS,
Environment.HOME,
PageId.COURSE_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList);
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.OTHER,
InteractSubtype.UNENROL_SUCCESS,
Environment.HOME,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList);
});
}, (error) => {
this.zone.run(async () => {
await loader.dismiss();
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.OTHER,
InteractSubtype.UNENROL_FAILURE,
Environment.HOME,
PageId.COURSE_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList);
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.OTHER,
InteractSubtype.UNENROL_FAILURE,
Environment.HOME,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList);
if (error && error.error === 'CONNECTION_ERROR') {
this.commonUtilService.showToast(this.commonUtilService.translateMessage('ERROR_NO_INTERNET_MESSAGE'));
} else {
this.commonUtilService.showToast(this.commonUtilService.translateMessage('FRMELEMNTS_MSG_UNABLE_TO_ENROLL'));
}
});
});
}
}
/**
* Set course details by passing course identifier
*/
setContentDetails(identifier): void {
const option: ContentDetailRequest = {
contentId: identifier,
objectType: this.courseCardData.objectType,
attachFeedback: true,
emitUpdateIfAny: true,
attachContentAccess: true
};
this.contentService.getContentDetails(option).toPromise()
.then((data: Content) => {
this.zone.run(() => {
if (!data.isAvailableLocally) {
this.extractApiResponse(data);
this.getCourseHierarchy(option, data);
} else {
this.extractApiResponse(data);
this.showSheenAnimation = false;
}
});
})
.catch((error: any) => {
if (NetworkError.isInstance(error)) {
this.commonUtilService.showToast('ERROR_NO_INTERNET_MESSAGE');
} else {
this.commonUtilService.showToast('ERROR_FETCHING_DATA');
}
this.isConsentPopUp = true;
this.showSheenAnimation = false;
this.location.back();
});
}
async getCourseHierarchy(request: ContentDetailRequest, data: Content) {
this.telemetryGeneratorService.generatefastLoadingTelemetry(
InteractSubtype.FAST_LOADING_INITIATED,
PageId.COURSE_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
this.telemetryGeneratorService.generatefastLoadingTelemetry(
InteractSubtype.FAST_LOADING_INITIATED,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
this.contentService.getContentHeirarchy(request).toPromise()
.then((content: Content) => {
/* setting child content here */
this.showSheenAnimation = false;
this.courseHeirarchy = content;
this.checkRetiredOpenBatch(this.courseHeirarchy);
this.toggleGroup(0, content.children[0]);
this.telemetryGeneratorService.generatefastLoadingTelemetry(
InteractSubtype.FAST_LOADING_FINISHED,
PageId.COURSE_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
this.telemetryGeneratorService.generatefastLoadingTelemetry(
InteractSubtype.FAST_LOADING_FINISHED,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
//IOS specific changes
if (this.platform.is('ios')) this.getContentState(true);
})
.catch(error => {
console.log('Error Fetching Childrens', error);
this.extractApiResponse(data);
this.showSheenAnimation = false;
});
}
/**
* Function to extract api response. Check content is locally available or not.
* If locally available then make childContents api call else make import content api call
*/
async extractApiResponse(data: Content) {
if (data.contentData) {
this.course = data.contentData;
this.forumId = this.course.forumId || this.forumId;
this.licenseDetails = data.contentData.licenseDetails || this.licenseDetails;
this.content = data;
this.objId = this.course.identifier;
this.objType = this.course.contentType;
this.objVer = this.course.pkgVersion;
this.showLoading = false;
this.pageId = this.commonUtilService.appendTypeToPrimaryCategory(this.course);
this.markContent();
this.telemetryObject = ContentUtil.getTelemetryObject(this.content);
if (!this.didViewLoad) {
this.generateImpressionEvent(this.course.identifier, this.course.contentType, this.course.pkgVersion);
this.generateStartEvent(this.course.identifier, this.course.contentType, this.course.pkgVersion);
if (this.course.createdBy === this.userId) {
this.commonUtilService.showToast('FRMELEMNTS_MSG_ENROLLMENT_ERROR');
}
}
this.didViewLoad = true;
if (this.course && this.course.isAvailableLocally) {
this.headerService.showHeaderWithBackButton();
}
if (this.course.status !== 'Live') {
this.commonUtilService.showToast('COURSE_NOT_AVAILABLE');
this.location.back();
}
if (this.course.gradeLevel && this.course.gradeLevel.length) {
this.course.gradeLevel = this.course.gradeLevel.join(', ');
}
if (this.course.attributions && this.course.attributions.length) {
this.course.attributions = (this.course.attributions.sort()).join(', ');
}
// User Rating
const contentFeedback: any = data.contentFeedback ? data.contentFeedback : [];
if (contentFeedback !== undefined && contentFeedback.length !== 0) {
this.userRating = contentFeedback[0].rating;
this.ratingComment = contentFeedback[0].comments;
}
} else {
this.commonUtilService.showToast('ERROR_CONTENT_NOT_AVAILABLE');
this.location.back();
}
if (Boolean(data.isAvailableLocally)) {
await this.setChildContents();
} else {
this.showLoading = true;
this.telemetryGeneratorService.generateSpineLoadingTelemetry(data, true);
this.importContent([this.identifier], false);
}
/* getting batch details for the course
Check Point: should be called on the condition of already enrolled courses only */
await this.getBatchDetails();
this.course.isAvailableLocally = data.isAvailableLocally;
if (this.isAlreadyEnrolled) {
await this.checkDataSharingStatus();
}
this.setCourseStructure();
}
/**
* Get batch details
*/
async getBatchDetails(batchId?) {
if (!batchId && (!this.courseCardData || !this.courseCardData.batchId)) {
return;
}
const currentBatchId = batchId || this.courseCardData.batchId;
this.courseService.getBatchDetails({ batchId: currentBatchId }).toPromise()
.then((data: Batch) => {
this.zone.run(() => {
if (!data) {
return;
}
this.batchDetails = data;
this.showCertificateDetails = this.batchDetails.cert_templates ? true : false;
for (var key in this.batchDetails.cert_templates) {
this.certificateDetails = this.batchDetails.cert_templates;
if (this.certificateDetails) {
this.isCertifiedCourse = true;
if (this.certificateDetails[key].description) {
this.certificateDescription = this.certificateDetails[key].description;
}
} else {
this.isCertifiedCourse = false;
}
}
if (this.batchRemaningTimingIntervalRef) {
clearInterval(this.batchRemaningTimingIntervalRef);
this.batchRemaningTimingIntervalRef = undefined;
}
if (this.batchDetails.endDate || this.batchDetails.enrollmentEndDate) {
this.batchEndDate = this.batchEndDate ? this.batchEndDate : this.batchDetails.endDate;
this.batchEndDateStatus( this.batchDetails.endDate || this.batchDetails.enrollmentEndDate);
}
this.saveContentContext(this.appGlobalService.getUserId(),
this.batchDetails.courseId, this.courseCardData.batchId, this.batchDetails.status);
this.preferences.getString(PreferenceKey.COURSE_IDENTIFIER).toPromise()
.then(async val => {
if (val && val === this.batchDetails.identifier) {
this.batchExp = true;
} else if (this.batchDetails.status === 2) {
this.batchExp = true;
} else if (this.batchDetails.status === 0) {
this.isBatchNotStarted = true;
this.courseStartDate = this.batchDetails.startDate;
} else if (this.batchDetails.status === 1) {
this.batchExp = false;
}
});
this.getBatchCreatorName();
});
})
.catch((error: any) => {
if (this.courseCardData.batch) {
this.batchDetails = this.courseCardData.batch;
if (this.courseCardData.batch.endDate || this.courseCardData.batch.enrollmentEndDate) {
this.batchEndDateStatus(this.courseCardData.batch.endDate || this.courseCardData.batch.enrollmentEndDate);
}
this.saveContentContext(this.appGlobalService.getUserId(),
this.courseCardData.courseId, this.courseCardData.batchId, this.courseCardData.batch.status);
}
});
}
/** url opens in browser */
openBrowser(url) {
this.commonUtilService.openUrlInBrowser(url);
}
saveContentContext(userId, courseId, batchId, batchStatus) {
const contentContextMap = new Map();
// store content context in the below map
contentContextMap['userId'] = userId;
contentContextMap['courseId'] = courseId;
contentContextMap['batchId'] = batchId;
contentContextMap['isCertified'] = this.isCertifiedCourse;
const leafNodeIds = this.courseHeirarchy.contentData.leafNodes;
contentContextMap['leafNodeIds'] = leafNodeIds;
if (batchStatus) {
contentContextMap['batchStatus'] = batchStatus;
}
// store the contentContextMap in shared preference and access it from SDK
this.preferences.putString(PreferenceKey.CONTENT_CONTEXT, JSON.stringify(contentContextMap)).toPromise().then();
}
getBatchCreatorName() {
const req: ServerProfileDetailsRequest = {
userId: this.batchDetails.createdBy,
requiredFields: ProfileConstants.REQUIRED_FIELDS
};
this.profileService.getServerProfilesDetails(req).toPromise()
.then((serverProfile) => {
if (serverProfile) {
if (this.batchDetails && this.batchDetails.creatorDetails) {
this.batchDetails.creatorDetails.firstName = serverProfile.firstName ? serverProfile.firstName : '';
this.batchDetails.creatorDetails.lastName = serverProfile.lastName ? serverProfile.lastName : '';
}
}
});
}
/**
* Set course structure
*/
setCourseStructure(): void {
if (this.course.contentTypesCount) {
if (!isObject(this.course.contentTypesCount)) {
this.course.contentTypesCount = JSON.parse(this.course.contentTypesCount);
}
} else if (this.courseCardData.contentTypesCount && !isObject(this.courseCardData.contentTypesCount)) {
this.course.contentTypesCount = JSON.parse(this.courseCardData.contentTypesCount);
}
}
/**
* Function to get import content api request params
*
* @param identifiers contains list of content identifier(s)
*/
getImportContentRequestBody(identifiers, isChild: boolean): Array<ContentImport> {
const requestParams = [];
const folderPath = this.platform.is('ios') ? cordova.file.documentsDirectory : cordova.file.externalDataDirectory;
identifiers.forEach((value) => {
requestParams.push({
isChildContent: isChild,
destinationFolder: folderPath,
contentId: value,
correlationData: this.corRelationList !== undefined ? this.corRelationList : [],
rollUp: this.rollUpMap[value]
});
});
return requestParams;
}
refreshHeader() {
this.events.publish('header:setzIndexToNormal');
}
/**
* Function to get import content api request params
*
* @param identifiers contains list of content identifier(s)
*/
importContent(identifiers, isChild: boolean, isDownloadAllClicked?) {
this.showChildrenLoader = this.downloadIdentifiers.size === 0;
const option: ContentImportRequest = {
contentImportArray: this.getImportContentRequestBody(identifiers, isChild),
contentStatusArray: ['Live'],
fields: ['appIcon', 'name', 'subject', 'size', 'gradeLevel']
};
this.contentService.importContent(option).toPromise()
.then((data: ContentImportResponse[]) => {
this.zone.run(() => {
if (data && data.length && data[0].status === ContentImportStatus.NOT_FOUND) {
this.showLoading = false;
this.headerService.showHeaderWithBackButton();
}
if (data && data.length && this.isDownloadStarted) {
data.forEach((value) => {
if (value.status === ContentImportStatus.ENQUEUED_FOR_DOWNLOAD) {
this.queuedIdentifiers.push(value.identifier);
} else if (value.status === ContentImportStatus.NOT_FOUND) {
this.faultyIdentifiers.push(value.identifier);
}
});
if (isDownloadAllClicked) {
this.telemetryGeneratorService.generateDownloadAllClickTelemetry(
PageId.COURSE_DETAIL,
this.course,
this.queuedIdentifiers,
identifiers.length,
this.objRollup,
this.corRelationList
);
this.telemetryGeneratorService.generateDownloadAllClickTelemetry(
this.pageId,
this.course,
this.queuedIdentifiers,
identifiers.length,
this.objRollup,
this.corRelationList
);
}
if (this.queuedIdentifiers.length === 0) {
this.restoreDownloadState();
}
if (this.faultyIdentifiers.length > 0) {
const stackTrace: any = {};
stackTrace.parentIdentifier = this.course.identifier;
stackTrace.faultyIdentifiers = this.faultyIdentifiers;
this.telemetryGeneratorService.generateErrorTelemetry(Environment.HOME,
TelemetryErrorCode.ERR_DOWNLOAD_FAILED,
ErrorType.SYSTEM,
PageId.COURSE_DETAIL,
JSON.stringify(stackTrace),
);
this.telemetryGeneratorService.generateErrorTelemetry(Environment.HOME,
TelemetryErrorCode.ERR_DOWNLOAD_FAILED,
ErrorType.SYSTEM,
this.pageId,
JSON.stringify(stackTrace),
);
}
}
});
})
.catch((error) => {
this.zone.run(() => {
if (this.isDownloadStarted) {
this.restoreDownloadState();
} else {
this.showChildrenLoader = false;
}
if (error && error.error === 'NETWORK_ERROR') {
this.commonUtilService.showToast('NEED_INTERNET_TO_CHANGE');
} else {
this.commonUtilService.showToast('UNABLE_TO_FETCH_CONTENT');
}
});
});
}
restoreDownloadState() {
this.isDownloadStarted = false;
}
async showDownloadConfirmationAlert() {
if (this.commonUtilService.networkInfo.isNetworkAvailable) {
let contentTypeCount;
if (this.downloadIdentifiers.size) {
contentTypeCount = this.downloadIdentifiers.size;
} else {
contentTypeCount = '';
}
if (!this.isBatchNotStarted) {
this.downloadProgress = 0;
} else {
this.commonUtilService.showToast(this.commonUtilService.translateMessage('COURSE_WILL_BE_AVAILABLE',
this.datePipe.transform(this.courseStartDate, 'mediumDate')));
}
const popover = await this.popoverCtrl.create({
component: ConfirmAlertComponent,
componentProps: {
sbPopoverHeading: this.commonUtilService.translateMessage('DOWNLOAD'),
sbPopoverMainTitle: this.course.name,
isNotShowCloseIcon: true,
actionsButtons: [
{
btntext: this.commonUtilService.translateMessage('DOWNLOAD'),
btnClass: 'popover-color'
},
],
icon: null,
metaInfo: this.commonUtilService.translateMessage('ITEMS', contentTypeCount)
+ ' (' + this.fileSizePipe.transform(this.downloadSize, 2) + ')',
},
cssClass: 'sb-popover info',
});
await popover.present();
const response = await popover.onDidDismiss();
if (response && response.data) {
this.isDownloadStarted = true;
this.showCollapsedPopup = false;
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
'download-all-button-clicked',
Environment.HOME,
PageId.COURSE_DETAIL
);
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
'download-all-button-clicked',
Environment.HOME,
this.pageId
);
this.events.publish('header:decreasezIndex');
this.importContent(this.downloadIdentifiers, true, true);
this.showDownload = true;
} else {
}
} else {
this.commonUtilService.showToast('ERROR_NO_INTERNET_MESSAGE');
}
}
private getLeafNodes(contents: Content[]) {
return contents.reduce((acc, content) => {
if (content.children) {
acc = acc.concat(this.getLeafNodes(content.children));
} else {
acc.push(content);
}
return acc;
}, []);
}
private getLeafNodeIdsWithoutDuplicates(contents: Content[]): Set<string> {
return contents.reduce((acc, content) => {
if (content.children && !(content.mimeType === 'application/vnd.sunbird.questionset')) {
this.getLeafNodeIdsWithoutDuplicates(content.children).forEach((c) => acc.add(c));
} else {
if (!acc.has(content.identifier)) {
if (content.mimeType !== MimeType.COLLECTION) {
acc.add(content.identifier);
}
}
}
return acc;
}, new Set<string>());
}
/**
* Function to get status of child contents
*/
private getStatusOfCourseCompletion(childrenData: Content[]) {
const contentStatusData = this.contentStatusData;
this.initNextContent();
this.zone.run(() => {
childrenData.forEach((childContent) => {
if (childContent.children && childContent.children.length) {
this.courseCompletionData[childContent.identifier] =
this.getLeafNodes(childContent.children).every((eachContent) => {
if (contentStatusData.contentList.length) {
const statusData = contentStatusData.contentList.find(c => c.contentId === eachContent.identifier);
if (statusData) {
return !(statusData.status === 0 || statusData.status === 1);
}
return false;
}
return false;
});
}
});
console.log('courseCompletionData ', this.courseCompletionData);
});
}
async getAllBatches() {
this.courseBatchesRequest = {
filters: {
courseId: this.identifier,
status: [CourseBatchStatus.NOT_STARTED, CourseBatchStatus.IN_PROGRESS],
enrollmentType: CourseEnrollmentType.OPEN
},
sort_by: { createdDate: SortOrder.DESC },
fields: BatchConstants.REQUIRED_FIELDS
};
this.courseService.getCourseBatches(this.courseBatchesRequest).toPromise()
.then(async (data: Batch[]) => {
if (data && data.length) {
data.forEach((batch) => {
this.showCertificateDetails = !!batch.cert_templates;
});
}
this.handleUnenrollButton();
this.showOfflineSection = false;
this.batches = data || [];
if(!this.isAlreadyEnrolled && this.batches && this.batches.length){
const batchDetails = this.batches[0];
this.showCertificateDetails = batchDetails.cert_templates ? true : false;
this.certificateDetails = batchDetails.cert_templates ? batchDetails.cert_templates : '';
}
if (data && data.length > 1) {
this.batchCount = data.length;
} else if (data && data.length === 1) {
this.batchEndDate = data[0].endDate;
this.enrollmentEndDate = data[0].enrollmentEndDate;
this.getBatchDetails(data[0].identifier);
}
})
.catch(async (error: any) => {
if (NetworkError.isInstance(error) && !this.courseCardData) {
this.showOfflineSection = true;
} else {
this.showOfflineSection = false;
}
console.log('Error while fetching all Batches', error);
});
}
toggleGroup(group, content) {
let isCollapsed = true;
if (this.isGroupShown(group)) {
isCollapsed = false;
this.shownGroup = null;
} else {
isCollapsed = false;
this.shownGroup = group;
}
const values = new Map();
values['isCollapsed'] = isCollapsed;
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.UNIT_CLICKED,
Environment.HOME,
PageId.COURSE_DETAIL,
ContentUtil.getTelemetryObject(content),
values,
undefined,
this.corRelationList
);
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.UNIT_CLICKED,
Environment.HOME,
this.pageId,
ContentUtil.getTelemetryObject(content),
values,
undefined,
this.corRelationList
);
}
// to check whether the card is toggled or not
isGroupShown(group) {
return this.shownGroup === group;
}
/**
* Function to set child contents
*/
async setChildContents() {
this.showChildrenLoader = true;
const option: ChildContentRequest = {
contentId: this.identifier,
hierarchyInfo: null
};
this.contentService.getChildContents(option).toPromise()
.then((data: Content) => {
this.zone.run(async () => {
if (data && data.children) {
setTimeout(() => {
if (this.stickyPillsRef && this.stickyPillsRef.nativeElement) {
this.stickyPillsRef.nativeElement.classList.add('sticky');
}
}, 1000);
this.courseHeirarchy = data;
this.checkRetiredOpenBatch(this.courseHeirarchy);
if (this.hasInit) {
this.getContentState(false);
} else {
this.hasInit = !this.hasInit;
this.getContentState(true);
}
}
if (this.courseCardData.batchId) {
this.downloadSize = 0;
this.getContentsSize(this.courseHeirarchy.children);
}
this.showChildrenLoader = false;
});
}).catch(() => {
this.zone.run(async () => {
this.showChildrenLoader = false;
});
});
}
cancelDownload() {
const showHeader = () => {
this.zone.run(() => {
this.showLoading = false;
this.headerService.showHeaderWithBackButton();
this.location.back();
});
};
this.telemetryGeneratorService.generateCancelDownloadTelemetry(this.course);
this.contentService.cancelDownload(this.identifier).toPromise()
.then(() => {
showHeader();
}).catch(() => {
showHeader();
});
}
getContentsSize(data?) {
if (data) {
data.forEach((value) => {
if (value.contentData.size) {
this.downloadSize += Number(value.contentData.size);
}
if (value.children) {
this.getContentsSize(value.children);
}
if (!value.isAvailableLocally && (value.contentData.downloadUrl || value.mimeType === 'application/vnd.sunbird.questionset')) {
this.downloadIdentifiers.add(value.contentData.identifier);
this.rollUpMap[value.contentData.identifier] = ContentUtil.generateRollUp(value.hierarchyInfo, undefined);
}
});
}
}
async startLearning() {
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.START_CLICKED,
Environment.HOME,
PageId.COURSE_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.START_CLICKED,
Environment.HOME,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
const key = PreferenceKey.DO_NOT_SHOW_PROFILE_NAME_CONFIRMATION_POPUP + '-' + this.userId;
const doNotShow = await this.preferences.getBoolean(key).toPromise();
const optionReq = { requiredFields: ProfileConstants.REQUIRED_FIELDS };
const profile = await this.profileService.getActiveSessionProfile(optionReq).toPromise();
if (doNotShow || await this.tncUpdateHandlerService.isSSOUser(profile) || !this.isCertifiedCourse) {
this.startContent();
} else {
this.showProfileNameConfirmationPopup();
}
}
private async startContent() {
if (this.courseHeirarchy && this.courseHeirarchy.children
&& this.courseHeirarchy.children.length && !this.isBatchNotStarted) {
if (!this.nextContent) {
await this.getContentState(true).then(() => {
this.navigateToContentDetails(this.nextContent, 1);
});
} else {
this.navigateToContentDetails(this.nextContent, 1);
}
// this.navigateToContentDetails(this.nextContent, 1);
} else {
this.commonUtilService.showToast(this.commonUtilService.translateMessage('COURSE_WILL_BE_AVAILABLE',
this.datePipe.transform(this.courseStartDate, 'mediumDate')));
}
}
/**
* Function gets executed when user click on resume course button.
*/
async resumeContent(): Promise<void> {
if (!this.nextContent) {
await this.getContentState(true).then(() => {
this.navigateToContentDetails(this.nextContent, 1);
});
} else {
this.navigateToContentDetails(this.nextContent, 1);
}
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.RESUME_CLICKED,
Environment.HOME,
PageId.COURSE_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.RESUME_CLICKED,
Environment.HOME,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
}
/**
* Redirect to child content details page
*/
private navigateToContentDetails(content: Content, depth): void {
this.router.navigate([RouterLinks.CONTENT_DETAILS], this.generateContentNavExtras(content, depth));
}
private generateContentNavExtras(content: Content, depth) {
const params: NavigationExtras = {
state: {
content,
depth, // Needed to handle some UI elements.
contentState: {
batchId: this.courseCardData.batchId ? this.courseCardData.batchId : '',
courseId: this.identifier
},
// isResumedCourse: true,
isChildContent: true,
// resumedCourseCardData: this.courseCardData,
corRelation: this.corRelationList,
isCourse: true,
course: this.updatedCourseCardData
}
};
return params;
}
/**
* Ionic life cycle hook
*/
async ionViewWillEnter() {
this.profile = await this.profileService.getActiveSessionProfile({ requiredFields: ProfileConstants.REQUIRED_FIELDS }).toPromise();
this.isMinor = this.profile && this.profile.serverProfile && this.profile.serverProfile.isMinor;
this.checkUserLoggedIn();
await this.appGlobalService.getActiveProfileUid()
.then((uid) => {
this.userId = uid;
});
this.checkCurrentUserType();
this.todayDate = window.dayjs().format('YYYY-MM-DD');
this.identifier = this.courseCardData.contentId || this.courseCardData.identifier;
this.downloadSize = 0;
this.objRollup = ContentUtil.generateRollUp(this.courseCardData.hierarchyInfo, this.identifier);
this.headerService.showHeaderWithBackButton();
if (!this.isGuestUser) {
await this.updateEnrolledCourseData();
}
// check if the course is already enrolled
this.isCourseEnrolled(this.identifier);
if (this.batchId) {
this.courseCardData.batchId = this.batchId;
}
if (this.courseCardData.progress && this.courseCardData.progress > 0) {
this.showResumeBtn = true;
} else {
this.showResumeBtn = false;
}
if (!this.isAlreadyEnrolled) {
this.getAllBatches();
} else {
if (this.courseCardData.completionPercentage < 100) {
this.segmentType = 'modules';
}
}
this.downloadIdentifiers = new Set();
this.setContentDetails(this.identifier);
this.headerObservable = this.headerService.headerEventEmitted$.subscribe(eventName => {
this.handleHeaderEvents(eventName);
});
// If courseCardData does not have a batch id then it is not a enrolled course
this.subscribeSdkEvent();
this.populateCorRelationData(this.courseCardData.batchId);
this.handleBackButton();
window['segmentation'].SBTagService.pushTag(
window['segmentation'].SBTagService.getTags(TagPrefixConstants.CONTENT_ID) ? this.identifier : [this.identifier],
TagPrefixConstants.CONTENT_ID,
window['segmentation'].SBTagService.getTags(TagPrefixConstants.CONTENT_ID) ? false : true
);
this.isCourseMentorValidation();
}
ionViewDidEnter() {
this.sbProgressLoader.hide({ id: 'login' });
this.sbProgressLoader.hide({ id: this.identifier });
}
isCourseMentorValidation() {
if (this.profile.serverProfile && this.profile.serverProfile.roles && this.profile.serverProfile.roles.length) {
for (let i = 0; i < this.profile.serverProfile.roles.length; i++) {
if (this.profile.serverProfile.roles[i].role === 'COURSE_MENTOR') {
this.isCourseMentor = true;
break;
}
}
}
}
editDataSettings() {
this.showShareData = !this.showShareData;
}
expandDataSettings() {
this.showShareData = false;
this.isDataShare = !this.isDataShare;
}
handleBackButton() {
this.backButtonFunc = this.platform.backButton.subscribeWithPriority(10, async () => {
this.telemetryGeneratorService.generateBackClickedTelemetry(
PageId.COURSE_DETAIL,
Environment.HOME,
false,
this.identifier,
this.corRelationList,
this.objRollup,
this.telemetryObject
);
this.telemetryGeneratorService.generateBackClickedTelemetry(
this.pageId,
Environment.HOME,
false,
this.identifier,
this.corRelationList,
this.objRollup,
this.telemetryObject
);
this.didViewLoad = false;
this.generateEndEvent(this.objId, this.objType, this.objVer);
if (this.shouldGenerateEndTelemetry) {
this.generateQRSessionEndEvent(this.source, this.course.identifier);
}
if (this.localCourseService.isConsentPopupVisible()) {
this.localCourseService.setConsentPopupVisibility(false);
await this.popoverCtrl.dismiss();
}
if (await this.onboardingSkippedBackAction()) {
return;
}
await this.goBack();
});
}
populateCorRelationData(batchId) {
if (!this.corRelationList) {
this.corRelationList = [];
}
this.corRelationList = this.corRelationList.filter(x => x.type !== CorReleationDataType.COURSE_BATCH)
this.corRelationList.push({ id: batchId ? batchId : '', type: CorReleationDataType.COURSE_BATCH });
this.corRelationList.push({ id: this.identifier || '', type: CorReleationDataType.ROOT_ID });
this.corRelationList = this.commonUtilService.deDupe(this.corRelationList, 'type');
}
isCourseEnrolled(identifier: string) {
// get all the enrolled courses
const enrolledCourses = this.appGlobalService.getEnrolledCourseList();
if (enrolledCourses && enrolledCourses.length > 0) {
for (const course of enrolledCourses) {
if (course.courseId === identifier) {
if (!this.isGuestUser && this.courseCardData.batch && course.batchId
=== this.courseCardData.batch.identifier) {
this.isAlreadyEnrolled = true;
this.subscribeTrackDownloads();
this.courseCardData = course;
this.fetchForumIdReq.identifier = [this.courseCardData.batchId];
this.fetchForumIdReq.type = 'batch';
} else if (!this.courseCardData.batch) {
this.courseCardData = course;
}
}
}
}
}
isCourseModifiedAfterEnrolment() {
return (this.courseCardData && this.courseCardData.enrolledDate
&& this.course && this.course.lastPublishedOn
&& (new Date(this.courseCardData.enrolledDate).getTime() < new Date(this.course.lastPublishedOn).getTime()));
}
getCourseProgress() {
if (this.courseCardData.batchId && this.updatedCourseCardData) {
this.course.progress = this.updatedCourseCardData.completionPercentage;
}
}
/**
* Subscribe Sunbird-SDK event to get content download progress
*/
subscribeSdkEvent() {
this.eventSubscription = this.eventsBusService.events()
.subscribe((event: EventsBusEvent) => {
this.zone.run(() => {
// Show download percentage
if (event.type === DownloadEventType.PROGRESS) {
const downloadEvent = event as DownloadProgress;
if (downloadEvent.payload.identifier === this.identifier) {
this.downloadProgress = downloadEvent.payload.progress === -1 ? 0 : downloadEvent.payload.progress;
if (this.downloadProgress === 100) {
this.getBatchDetails();
this.showLoading = false;
this.headerService.showHeaderWithBackButton();
}
}
}
// Get child content
if (event.payload && event.type === ContentEventType.IMPORT_COMPLETED) {
this.showLoading = false;
this.isDownloadComplete = true;
this.headerService.showHeaderWithBackButton();
const contentImportCompleted = event as ContentImportCompleted;
if (this.queuedIdentifiers.length && this.isDownloadStarted) {
if (this.queuedIdentifiers.includes(contentImportCompleted.payload.contentId)) {
this.currentCount++;
}
if (this.queuedIdentifiers.length === this.currentCount) {
this.isDownloadStarted = false;
this.currentCount = 0;
this.showDownload = false;
this.downloadIdentifiers = new Set();
this.queuedIdentifiers.length = 0;
}
} else {
this.course.isAvailableLocally = true;
this.setContentDetails(this.identifier);
}
}
if (event.payload && event.type === ContentEventType.SERVER_CONTENT_DATA) {
this.licenseDetails = event.payload.licenseDetails;
if (event.payload.size) {
this.content.contentData.size = event.payload.size;
}
}
if (event.type === ContentEventType.IMPORT_PROGRESS) {
const totalCountMsg = Math.floor((event.payload.currentCount / event.payload.totalCount) * 100) +
'% (' + event.payload.currentCount + ' / ' + event.payload.totalCount + ')';
this.importProgressMessage = this.commonUtilService.translateMessage('EXTRACTING_CONTENT', totalCountMsg);
if (event.payload.currentCount === event.payload.totalCount) {
let timer = 30;
const interval = setInterval(() => {
this.importProgressMessage = `Getting things ready in ${timer--} seconds`;
if (timer === 0) {
this.importProgressMessage = 'Getting things ready';
clearInterval(interval);
}
}, 1000);
}
}
// For content update available
const hierarchyInfo = this.courseCardData.hierarchyInfo ? this.courseCardData.hierarchyInfo : null;
const contentUpdateEvent = event as ContentUpdate;
if (contentUpdateEvent.payload && contentUpdateEvent.payload.contentId === this.identifier &&
contentUpdateEvent.type === ContentEventType.UPDATE
&& hierarchyInfo === null) {
this.zone.run(() => {
this.showLoading = true;
this.headerService.hideHeader();
this.telemetryGeneratorService.generateSpineLoadingTelemetry(this.content, false);
this.importContent([this.identifier], false);
});
}
});
}) as any;
}
/**
* Ionic life cycle hook
*/
ionViewWillLeave(): void {
this.isNavigatingWithinCourse = true;
this.events.publish('header:setzIndexToNormal');
if (this.eventSubscription) {
this.eventSubscription.unsubscribe();
}
if (this.headerObservable) {
this.headerObservable.unsubscribe();
}
if (this.backButtonFunc) {
this.backButtonFunc.unsubscribe();
}
}
ngOnDestroy() {
this.events.unsubscribe(EventTopics.ENROL_COURSE_SUCCESS);
this.events.unsubscribe('courseToc:content-clicked');
this.events.unsubscribe(EventTopics.UNENROL_COURSE_SUCCESS);
this.events.unsubscribe('header:setzIndexToNormal');
this.events.unsubscribe('header:decreasezIndex');
if (this.batchRemaningTimingIntervalRef) {
clearInterval(this.batchRemaningTimingIntervalRef);
this.batchRemaningTimingIntervalRef = undefined;
}
}
/**
* checks whether batches are available or not and then Navigate user to batch list page
*/
async navigateToBatchListPage() {
if(this.isCourseMentor) {
this.commonUtilService.showToast('Course Mentor cannot join/leave any course');
}
else{
const loader = await this.commonUtilService.getLoader();
const reqvalues = new Map();
reqvalues['enrollReq'] = this.courseBatchesRequest;
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.ENROLL_CLICKED, Environment.HOME,
PageId.COURSE_DETAIL, this.telemetryObject, reqvalues, this.objRollup);
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.ENROLL_CLICKED, Environment.HOME,
this.pageId, this.telemetryObject, reqvalues, this.objRollup);
if (!this.commonUtilService.networkInfo.isNetworkAvailable) {
this.commonUtilService.showToast('ERROR_NO_INTERNET_MESSAGE');
return;
}
if (!this.localCourseService.isEnrollable(this.batches, this.course) && !this.isCourseMentor) {
return;
}
const ongoingBatches = [];
if (this.batches.length === 1) {
this.enrollIntoBatch(this.batches[0], this.course);
} else {
forEach(this.batches, (batch, key) => {
if (batch.status === 1) {
ongoingBatches.push(batch);
}
});
this.router.navigate([RouterLinks.COURSE_BATCHES], {
state: {
ongoingBatches,
upcommingBatches: [],
course: this.course,
objRollup: this.objRollup,
telemetryObject: this.telemetryObject,
corRelationList: this.corRelationList
}
});
}
}
}
async share() {
const popover = await this.popoverCtrl.create({
component: SbSharePopupComponent,
componentProps: {
content: this.content,
corRelationList: this.corRelationList,
pageId: this.pageId,
shareItemType: ShareItemType.ROOT_COLECTION
},
cssClass: 'sb-popover',
});
await popover.present();
}
handleNavBackButton() {
this.didViewLoad = false;
this.generateEndEvent(this.objId, this.objType, this.objVer);
if (this.shouldGenerateEndTelemetry) {
this.generateQRSessionEndEvent(this.source, this.course.identifier);
}
}
async goBack() {
this.appGlobalService.generateCourseCompleteTelemetry = false;
this.events.publish('event:update_course_data');
const guestUser = await this.commonUtilService.getGuestUserConfig();
if(!guestUser.syllabus[0]) {
this.events.publish('UPDATE_TABS', {navigateToCourse: {}});
this.router.navigate([RouterLinks.PROFILE_TAB]);
} else
if (this.isQrCodeLinkToContent) {
window.history.go(-2);
} else {
this.location.back();
}
}
generateQRSessionEndEvent(pageId: string, qrData: string) {
if (pageId !== undefined) {
const telemetryObject = new TelemetryObject(qrData, 'qr', undefined);
this.telemetryGeneratorService.generateEndTelemetry(
'qr',
Mode.PLAY,
pageId,
Environment.HOME,
telemetryObject,
this.objRollup,
this.corRelationList);
}
}
generateImpressionEvent(objectId, objectType, objectVersion) {
this.telemetryGeneratorService.generateImpressionTelemetry(ImpressionType.DETAIL,
'', PageId.COURSE_DETAIL,
Environment.HOME,
objectId,
objectType,
objectVersion,
this.objRollup,
this.corRelationList);
this.telemetryGeneratorService.generateImpressionTelemetry(ImpressionType.DETAIL,
'', this.pageId,
Environment.HOME,
objectId,
objectType,
objectVersion,
this.objRollup,
this.corRelationList);
}
generateStartEvent(objectId, objectType, objectVersion) {
const telemetryObject = new TelemetryObject(objectId, objectType || CsPrimaryCategory.COURSE, objectVersion);
this.telemetryGeneratorService.generateStartTelemetry(PageId.COURSE_DETAIL,
telemetryObject,
this.objRollup,
this.corRelationList
);
this.telemetryGeneratorService.generateStartTelemetry(this.pageId,
telemetryObject,
this.objRollup,
this.corRelationList
);
}
generateEndEvent(objectId, objectType, objectVersion) {
const telemetryObject = new TelemetryObject(objectId, objectType || CsPrimaryCategory.COURSE, objectVersion);
this.telemetryGeneratorService.generateEndTelemetry(objectType || CsPrimaryCategory.COURSE,
Mode.PLAY,
PageId.COURSE_DETAIL,
Environment.HOME,
telemetryObject,
this.objRollup,
this.corRelationList);
this.telemetryGeneratorService.generateEndTelemetry(objectType || CsPrimaryCategory.COURSE,
Mode.PLAY,
this.pageId,
Environment.HOME,
telemetryObject,
this.objRollup,
this.corRelationList);
}
/**
* Opens up popup for the credits.
*/
viewCredits() {
this.courseUtilService.showCredits(this.course, this.pageId, undefined, this.corRelationList);
}
async getContentState(returnRefresh: boolean) {
if (this.courseCardData.batchId) {
const request: GetContentStateRequest = {
userId: this.appGlobalService.getUserId(),
courseId: this.identifier,
contentIds: this.courseHeirarchy.contentData.leafNodes,
returnRefreshedContentStates: returnRefresh,
batchId: this.courseCardData.batchId,
fields: ['progress', 'score']
};
await this.courseService.getContentState(request).toPromise()
.then((contentStateResponse: ContentStateResponse) => {
this.contentStatusData = contentStateResponse;
this.initNextContent();
if (this.contentStatusData) { // && this.contentStatusData.contentList
this.getLocalCourseAndUnitProgress();
let progress = 0;
this.contentStatusData.contentList.forEach((contentState: ContentState) => {
if (contentState.status === 2) {
progress = progress + 1;
}
});
this.courseCardData.progress = progress;
if (this.courseCardData.progress && this.courseCardData.progress > 0) {
this.showResumeBtn = true;
} else {
this.showResumeBtn = false;
}
}
if (this.courseHeirarchy && this.courseHeirarchy.children) {
this.getStatusOfCourseCompletion(this.courseHeirarchy.children);
if (this.platform.is('ios')) {
this.downloadSize = 0;
this.getContentsSize(this.courseHeirarchy.children);
}
}
if (this.resumeCourseFlag) {
this.resumeContent();
this.resumeCourseFlag = false;
}
}).catch((error: any) => {
console.error('getContentState', error);
this.resumeCourseFlag = false;
});
} else {
// to be handled when there won't be any batchId
}
}
getLocalCourseAndUnitProgress() {
const courseLevelViewedContents = [];
let leafNodeIds;
this.courseHeirarchy.children.forEach(collection => {
// Reset progress before assigning the updated progress.
collection.progressPercentage = 0;
const leafNodeIds = Array.from(this.getLeafNodeIdsWithoutDuplicates([collection]));
const unitLevelViewedContents = [];
for (const contentId of leafNodeIds) {
if (this.contentStatusData.contentList.find((c) => c.contentId === contentId && c.status === 2)) {
if (unitLevelViewedContents.indexOf(contentId) === -1) {
unitLevelViewedContents.push(contentId);
}
if (courseLevelViewedContents.indexOf(contentId) === -1) {
courseLevelViewedContents.push(contentId);
}
}
}
if (unitLevelViewedContents.length && this.isAlreadyEnrolled) {
collection.progressPercentage = Math.round((unitLevelViewedContents.length / leafNodeIds.length) * 100);
}
});
if (courseLevelViewedContents.length) {
if (this.courseHeirarchy.contentData.leafNodes) {
leafNodeIds = this.courseHeirarchy.contentData.leafNodes;
}
this.course.progress = Math.floor((courseLevelViewedContents.length / leafNodeIds.length) * 100);
} else {
this.course.progress = 0;
}
this.handleUnenrollButton();
if (!this.course.progress || this.course.progress !== 100) {
this.appGlobalService.generateCourseCompleteTelemetry = true;
}
if (this.appGlobalService.generateCourseCompleteTelemetry && this.course.progress === 100) {
this.appGlobalService.generateCourseCompleteTelemetry = false;
const cdata = [
{
type: 'CourseId',
id: this.identifier
},
{
type: 'BatchId',
id: this.batchDetails.id || ''
},
{
type: 'UserId',
id: this.userId
},
];
this.telemetryGeneratorService.generateAuditTelemetry(
Environment.COURSE,
AuditState.AUDIT_UPDATED,
['progress'],
AuditType.COURSE_PROGRESS,
this.telemetryObject.id,
this.telemetryObject.type,
this.telemetryObject.version,
cdata,
this.telemetryObject.rollup
);
this.telemetryGeneratorService.generateAuditTelemetry(
Environment.COURSE,
AuditState.AUDIT_UPDATED,
['progress'],
this.commonUtilService.appendTypeToPrimaryCategory(this.content, '-progress'),
this.telemetryObject.id,
this.telemetryObject.type,
this.telemetryObject.version,
cdata,
this.telemetryObject.rollup
);
}
}
async handleHeaderEvents($event) {
switch ($event.name) {
case 'share':
this.share();
break;
case 'more':
this.showOverflowMenu($event.event);
break;
case 'back':
this.telemetryGeneratorService.generateBackClickedTelemetry(PageId.COURSE_DETAIL, Environment.HOME,
true, this.identifier, this.corRelationList, this.objRollup, this.telemetryObject);
this.telemetryGeneratorService.generateBackClickedTelemetry(this.pageId, Environment.HOME,
true, this.identifier, this.corRelationList, this.objRollup, this.telemetryObject);
this.handleNavBackButton();
if (await this.onboardingSkippedBackAction()) {
return;
}
await this.goBack();
break;
}
}
async enrollIntoBatch(item: Batch, course?) {
if (this.isGuestUser) {
this.promptToLogin(item);
} else {
const enrollCourseRequest = this.localCourseService.prepareEnrollCourseRequest(this.userId, item);
this.loader = await this.commonUtilService.getLoader();
if (this.loader) {
await this.loader.present();
}
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.ENROLL_CLICKED,
Environment.HOME,
PageId.COURSE_BATCHES, undefined,
this.localCourseService.prepareRequestValue(enrollCourseRequest));
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.ENROLL_CLICKED,
Environment.HOME,
this.commonUtilService.appendTypeToPrimaryCategory(this.content, '-batches'), undefined,
this.localCourseService.prepareRequestValue(enrollCourseRequest));
const enrollCourse: EnrollCourse = {
userId: this.userId,
batch: item,
pageId: PageId.COURSE_BATCHES,
courseId: this.course.identifier,
channel: this.course.channel,
telemetryObject: this.telemetryObject,
objRollup: this.objRollup,
corRelationList: this.corRelationList,
userConsent: this.course.userConsent
};
this.localCourseService.enrollIntoBatch(enrollCourse, this, course).toPromise()
.then((data: boolean) => {
this.zone.run(async () => {
this.courseCardData.batchId = item.id;
this.commonUtilService.showToast(this.commonUtilService.translateMessage('COURSE_ENROLLED'));
this.commonUtilService.showToast(this.categoryKeyTranslator.transform('FRMELEMNTS_MSG_COURSE_ENROLLED', this.course));
this.events.publish(EventTopics.ENROL_COURSE_SUCCESS, {
batchId: item.id,
courseId: item.courseId
});
this.isAlreadyEnrolled = true;
this.subscribeTrackDownloads();
this.populateCorRelationData(this.courseCardData.batchId)
});
}, (error) => {
this.zone.run(async () => {
if (this.loader) {
this.loader.dismiss();
this.loader = undefined;
}
});
});
}
}
async promptToLogin(batchdetail) {
this.telemetryGeneratorService.generateImpressionTelemetry(ImpressionType.VIEW,
'', PageId.SIGNIN_POPUP,
Environment.HOME,
this.telemetryObject.id,
this.telemetryObject.type,
this.telemetryObject.version,
this.objRollup,
this.corRelationList);
const confirm = await this.popoverCtrl.create({
component: SbPopoverComponent,
componentProps: {
sbPopoverMainTitle: this.categoryKeyTranslator.transform('FRMELEMNTS_MSG_YOU_MUST_JOIN_TO_ACCESS_TRAINING_DETAIL', this.course),
metaInfo: this.categoryKeyTranslator.transform('FRMELEMNTS_MSG_TRAININGS_ONLY_REGISTERED_USERS', this.course),
sbPopoverHeading: this.commonUtilService.translateMessage('OVERLAY_SIGN_IN'),
isNotShowCloseIcon: true,
actionsButtons: [
{
btntext: this.commonUtilService.translateMessage('OVERLAY_SIGN_IN'),
btnClass: 'popover-color label-uppercase label-bold-font'
},
]
},
cssClass: 'sb-popover info',
});
await confirm.present();
const { data } = await confirm.onDidDismiss();
if (data && data.canDelete) {
this.preferences.putString(PreferenceKey.BATCH_DETAIL_KEY, JSON.stringify(batchdetail)).toPromise();
this.preferences.putString(PreferenceKey.COURSE_DATA_KEY, JSON.stringify(this.course)).toPromise();
this.preferences.putString(PreferenceKey.CDATA_KEY, JSON.stringify(this.corRelationList)).toPromise();
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.LOGIN_CLICKED,
Environment.HOME,
PageId.SIGNIN_POPUP,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
this.appGlobalService.resetSavedQuizContent();
this.router.navigate([RouterLinks.SIGN_IN], {state: {navigateToCourse: true}});
}
}
onSegmentChange(event) {
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
event.detail.value === 'modules' ? InteractSubtype.TRAINING_MODULE_CLICKED : InteractSubtype.TRAINING_INFO_CLICKED,
Environment.HOME,
PageId.COURSE_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
event.detail.value === 'modules' ? InteractSubtype.TRAINING_MODULE_CLICKED : InteractSubtype.TRAINING_INFO_CLICKED,
Environment.HOME,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
}
// check wheather to show Unenroll button in overflow menu or not
handleUnenrollButton() {
const batchDetails = this.batchDetails ? this.batchDetails.status : 2;
const enrollmentType = this.batchDetails ? this.batchDetails.enrollmentType : '';
if (this.updatedCourseCardData) {
this.showUnenrollButton = (batchDetails !== 2 &&
(this.course.progress < 100 && this.updatedCourseCardData.status === 0 || this.updatedCourseCardData.status === 1) &&
enrollmentType !== 'invite-only');
} else {
this.showUnenrollButton = (
(batchDetails !== 2 &&
(this.course.progress < 100 && this.courseCardData.status === 0 || this.courseCardData.status === 1) &&
enrollmentType !== 'invite-only')
);
}
}
mergeProperties(mergeProp) {
return ContentUtil.mergeProperties(this.course, mergeProp);
}
onboardingSkippedBackAction(): Promise<boolean> {
return new Promise(async resolve => {
try {
const session = await this.authService.getSession().toPromise();
if ((this.isOnboardingSkipped && session) || this.isFromChannelDeeplink) {
resolve(true);
const navigationExtras: NavigationExtras = { replaceUrl: true };
this.router.navigate([`/${RouterLinks.TABS_COURSE}`], navigationExtras);
} else if (this.isOnboardingSkipped && !session) {
resolve(true);
const navigationExtras: NavigationExtras = { queryParams: { reOnboard: true }, replaceUrl: true };
this.router.navigate([`/${RouterLinks.PROFILE_SETTINGS}`], navigationExtras);
}
resolve(false);
} catch {
resolve(false);
}
});
}
onTocCardClick(event) {
// if from group flow then should not go to next page.
if (this.isFromGroupFlow) {
return;
}
if (this.isGuestUser) {
this.navigateToBatchListPage();
return false;
}
if (this.course.createdBy !== this.userId) {
if (!this.isAlreadyEnrolled && !this.isCourseMentor) {
this.joinTraining();
return false;
} else if (this.isAlreadyEnrolled && this.isBatchNotStarted) {
this.commonUtilService.showToast(this.commonUtilService.translateMessage('COURSE_WILL_BE_AVAILABLE',
this.datePipe.transform(this.courseStartDate, 'mediumDate')));
return false;
}
}
if (event.item.mimeType === MimeType.COLLECTION) {
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.TRAINING_MODULE_CLICKED,
Environment.HOME,
PageId.COURSE_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList);
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.TRAINING_MODULE_CLICKED,
Environment.HOME,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList);
const chapterParams: NavigationExtras = {
state: {
chapterData: event.item,
batches: this.batches,
isAlreadyEnrolled: this.isAlreadyEnrolled,
courseCardData: this.courseCardData,
batchExp: this.batchExp,
isChapterCompleted: this.courseCompletionData[event.item.identifier],
contentStatusData: this.contentStatusData,
courseContent: this.content,
corRelation: this.corRelationList,
courseHeirarchy: this.courseHeirarchy
}
};
this.router.navigate([`/${RouterLinks.CURRICULUM_COURSES}/${RouterLinks.CHAPTER_DETAILS}`],
chapterParams);
} else {
if (!this.batchId) {
return false;
}
this.navigateToContentDetails(event.item, 1);
}
}
private initNextContent() {
this.isNextContentFound = false;
this.isFirstContent = false;
this.nextContent = undefined;
this.getNextContent(this.courseHeirarchy, this.contentStatusData.contentList);
}
private getNextContent(courseHeirarchy, contentStateList: ContentState[]) {
const result = contentStateList.find(({ contentId }) => contentId === courseHeirarchy.identifier);
if (!this.isFirstContent && courseHeirarchy.mimeType !== MimeType.COLLECTION) {
this.nextContent = courseHeirarchy;
this.isFirstContent = true;
}
if ((result && (result.status === 0 || result.status === 1))
|| (!result && courseHeirarchy.mimeType !== MimeType.COLLECTION)) {
this.nextContent = courseHeirarchy;
this.isNextContentFound = true;
this.isFirstContent = true;
} else if (!this.isNextContentFound && courseHeirarchy && courseHeirarchy.children) {
courseHeirarchy.children.forEach((ele) => {
if (!this.isNextContentFound) {
this.getNextContent(ele, contentStateList);
}
});
}
return this.nextContent;
}
async saveChanges() {
const loader = await this.commonUtilService.getLoader();
await loader.present();
if (this.dataSharingStatus === ConsentStatus.ACTIVE) {
const request: Consent = {
status: ConsentStatus.REVOKED,
userId: this.courseCardData.userId,
consumerId: this.courseCardData.content ? this.courseCardData.content.channel : this.course.channel,
objectId: this.courseCardData.courseId,
objectType: 'Collection',
};
this.profileService.updateConsent(request).toPromise()
.then(async (data) => {
await loader.dismiss();
this.commonUtilService.showToast('FRMELEMNTS_MSG_DATA_SETTINGS_SUBMITED_SUCCESSFULLY');
this.showShareData = false;
this.checkDataSharingStatus();
})
.catch(async (e) => {
await loader.dismiss();
if (e.code === 'NETWORK_ERROR') {
this.commonUtilService.showToast('ERROR_NO_INTERNET_MESSAGE');
}
});
} else if (this.dataSharingStatus === ConsentStatus.REVOKED) {
await loader.dismiss();
await this.consentService.showConsentPopup(this.courseCardData, undefined, this.course);
this.showShareData = false;
this.checkDataSharingStatus();
}
}
async checkDataSharingStatus() {
if (!this.isMinor) {
const request: Consent = {
userId: this.courseCardData.userId,
consumerId: this.courseCardData.content ? this.courseCardData.content.channel : this.course.channel,
objectId: this.courseCardData.courseId
};
await this.profileService.getConsent(request).toPromise()
.then((data) => {
if (data) {
if (this.isAlreadyEnrolled && data.consents.length === 0) {
this.showShareData = true;
this.dataSharingStatus = 'REVOKED';
this.isDataShare = true;
}
this.dataSharingStatus = data.consents[0].status;
this.lastUpdateOn = data.consents[0].lastUpdatedOn;
this.localCourseService.setConsentPopupVisibility(false);
}
})
.catch(async (e) => {
if (this.isAlreadyEnrolled && e.response && e.response.body && e.response.body.params.err === 'USER_CONSENT_NOT_FOUND'
&& this.course.userConsent === UserConsent.YES) {
if (!this.isConsentPopUp) {
this.isConsentPopUp = true;
this.localCourseService.setConsentPopupVisibility(true);
await this.consentService.showConsentPopup(this.courseCardData, undefined, this.course);
await this.checkDataSharingStatus();
}
} else if (e.code === 'NETWORK_ERROR') {
this.commonUtilService.showToast('ERROR_NO_INTERNET_MESSAGE');
}
});
}
}
onConsentPopoverShow() {
if (this.loader) {
this.loader.dismiss();
this.loader = undefined;
}
this.localCourseService.setConsentPopupVisibility(true);
}
onConsentPopoverDismiss() {
this.localCourseService.setConsentPopupVisibility(false);
this.checkDataSharingStatus();
}
// openDiscussionForum(forumId: string) {
// if(this.commonUtilService.networkInfo.isNetworkAvailable){
// this.checkUserRegistration();
// } else {
// this.commonUtilService.showToast('ERROR_NO_INTERNET_MESSAGE');
// }
// }
private async showProfileNameConfirmationPopup() {
const popUp = await this.popoverCtrl.create({
component: ProfileNameConfirmationPopoverComponent,
componentProps: {
content: this.course
},
cssClass: 'sb-popover sb-profile-name-confirmation-popover',
});
await popUp.present();
const { data } = await popUp.onDidDismiss();
if (data !== undefined) {
if (data.buttonClicked) {
this.startContent();
}
} else {
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.CLOSE_CLICKED,
PageId.PROFILE_NAME_CONFIRMATION_POPUP,
Environment.HOME
);
}
}
private async checkRetiredOpenBatch(content: any, layoutName?: string) {
if (!this.isAlreadyEnrolled || this.skipCheckRetiredOpenBatch) {
return;
}
this.skipCheckRetiredOpenBatch = true;
let retiredBatches: Array<any> = [];
let anyOpenBatch = false;
const enrolledCourses = this.appGlobalService.getEnrolledCourseList() || [];
try {
if (layoutName !== ContentCard.LAYOUT_INPROGRESS) {
retiredBatches = enrolledCourses.filter((element) => {
if (element.contentId === content.identifier && element.batch.status === 1 && element.cProgress !== 100) {
anyOpenBatch = true;
content.batch = element.batch;
}
if (element.contentId === content.identifier && element.batch.status === 2 && element.cProgress !== 100) {
return element;
}
});
}
} catch (err) {
console.error('checkRetiredOpenBatch', err);
}
if (anyOpenBatch || !retiredBatches.length) {
// open the batch directly
// Do nothing.
} else if (retiredBatches.length) {
await this.navigateToBatchListPopup(content, layoutName, retiredBatches);
}
}
async navigateToBatchListPopup(content: any, layoutName?: string, retiredBatched?: any) {
if (this.isGuestUser || !this.commonUtilService.networkInfo.isNetworkAvailable) {
return;
}
const courseBatchesRequest: CourseBatchesRequest = {
filters: {
courseId: layoutName === ContentCard.LAYOUT_INPROGRESS ? content.contentId : content.identifier,
enrollmentType: CourseEnrollmentType.OPEN,
status: [CourseBatchStatus.NOT_STARTED, CourseBatchStatus.IN_PROGRESS]
},
sort_by: { createdDate: SortOrder.DESC },
fields: BatchConstants.REQUIRED_FIELDS
};
this.courseService.getCourseBatches(courseBatchesRequest).toPromise()
.then((res: Batch[]) => {
this.zone.run(async () => {
this.batches = res;
if (this.batches.length) {
const ongoingBatches = [];
this.batches.forEach((batch, key) => {
if (batch.status === 1) {
ongoingBatches.push(batch);
}
});
const reqvalues = new Map();
reqvalues['enrollReq'] = courseBatchesRequest;
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
'ongoing-batch-popup',
Environment.HOME,
PageId.COURSE_DETAIL, undefined,
reqvalues, undefined, this.corRelationList);
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
'ongoing-batch-popup',
Environment.HOME,
this.pageId, undefined,
reqvalues, undefined, this.corRelationList);
const popover = await this.popoverCtrl.create({
component: EnrollmentDetailsComponent,
componentProps: {
upcommingBatches: [],
ongoingBatches,
retiredBatched,
content
},
cssClass: 'enrollement-popover'
});
// await this.loader.dismiss();
await popover.present();
const { data } = await popover.onDidDismiss();
if (data && data.isEnrolled) {
// Reload the page
// this.getEnrolledCourses();
await this.reloadPageAfterEnrollment(data);
this.checkDataSharingStatus();
}
if (data && typeof data.isEnrolled === 'function') {
(data.isEnrolled as Function).call(this);
}
} else {
// Do nothing.
}
});
})
.catch((error: any) => {
console.error('error while fetching course batches ==>', error);
});
}
generateDataForDF() {
if (this.courseCardData.batchId) {
this.fetchForumIdReq.identifier = [this.courseCardData.batchId];
this.fetchForumIdReq.type = 'batch';
} else {
this.fetchForumIdReq.identifier = [this.identifier];
this.fetchForumIdReq.type = 'course';
}
this.profileService.getActiveSessionProfile({ requiredFields: ProfileConstants.REQUIRED_FIELDS }).toPromise().then((p) => {
this.createUserReq.username = (p.serverProfile && p.serverProfile['userName']) || p.handle;
this.isMinor = p.serverProfile && p.serverProfile.isMinor;
});
this.appGlobalService.getActiveProfileUid()
.then((uid) => {
this.userId = uid;
this.createUserReq.identifier = uid;
});
}
async batchEndDateStatus(batchEndDate) {
this.batchRemaningTime = await this.localCourseService.getTimeRemaining(batchEndDate);
this.batchRemaningTimingIntervalRef = setInterval(async () => {
this.batchRemaningTime = await this.localCourseService.getTimeRemaining(batchEndDate);
}, 1000 * 60);
}
navigateToDashboard(){
this.router.navigate([`/${RouterLinks.MY_GROUPS}/${RouterLinks.ACTIVITY_DETAILS}/${RouterLinks.ACTIVITY_DASHBOARD}`],
{
state: {
hierarchyData: this.courseHeirarchy,
activity: this.activityData && this.activityData.activity,
group: this.activityData && this.activityData.group,
loggedinUser: this.userId
}
});
}
markContent() {
const addContentAccessRequest: ContentAccess = {
status: ContentAccessStatus.PLAYED,
contentId: this.identifier,
contentType: this.content.contentType || this.courseCardData.content.contentType
};
const profile: Profile = this.appGlobalService.getCurrentUser();
this.profileService.addContentAccess(addContentAccessRequest).toPromise().then((data) => {
if (data) {
this.events.publish(EventTopics.LAST_ACCESS_ON, true);
}
});
const contentMarkerRequest: ContentMarkerRequest = {
uid: profile.uid,
contentId: this.identifier,
data: JSON.stringify(this.content.contentData || this.courseCardData.content),
marker: MarkerType.PREVIEWED,
isMarked: true,
extraInfo: {}
};
this.contentService.setContentMarker(contentMarkerRequest).toPromise().then();
}
}
<ion-content>
<div class="p-8" *ngIf="!showOfflineSection">
<ion-card class="sb-dt-card">
<app-toc-header [contentData]="course || courseCardData?.content"></app-toc-header>
<div class="hr-border-bottom"></div>
<ion-card-content class="sb-content-info">
<div *ngIf="isFromGroupFlow">
<add-activity-to-group [identifier]="identifier" [pageId]="pageId"></add-activity-to-group>
<div class="enrollment-info"
*ngIf="batches && course?.createdBy !== userId && (batches.length > 1 || (batches.length === 1 && !(todayDate > batches[0].enrollmentEndDate)))">
<ion-card-subtitle *ngIf="batchCount || enrollmentEndDate" class="font-12 margin-bottom-2">
<div *ngIf="batchCount">
<ion-icon class="information-icon" name="information-circle"></ion-icon> {{batchCount}}
{{'BATCHES_AVAILABLE' | translate}}
</div>
<div *ngIf="enrollmentEndDate">
<ion-icon class="information-icon" name="information-circle"></ion-icon>
{{'LAST_DATE_TO_JOIN' | translate:{'%s': enrollmentEndDate | date: 'dd/MM/yyyy'} }}
</div>
<div *ngIf="!enrollmentEndDate && batchEndDate">
{{'FRMELEMENTS_LBL_TRAINING_ENDS_ON' | categoryKeyTranslate : course}} {{batchEndDate | date: 'dd/MM/yyyy'}}
</div>
</ion-card-subtitle>
</div>
</div>
<div *ngIf="!isFromGroupFlow && !isAlreadyEnrolled">
<div class="enrollment-info"
*ngIf="batches && course?.createdBy !== userId && (batches.length > 1 || (batches.length === 1 && !(todayDate > batches[0].enrollmentEndDate)))">
<button [disabled]="isCourseMentor" class="enrolled-course-card-button label-uppercase label-bold-font" [ngClass]="{'disable-css': isCourseMentor,
'': !isCourseMentor}" (click)="navigateToBatchListPage();">{{'FRMELEMNTS_LBL_JOIN_TRAINING' | categoryKeyTranslate : course }}</button>
<ion-card-subtitle *ngIf="batchCount || enrollmentEndDate" class="font-12 margin-bottom-2">
<div *ngIf="batchCount">
<ion-icon class="information-icon" name="information-circle"></ion-icon> {{batchCount}}
{{'BATCHES_AVAILABLE' | translate}}
</div>
<div *ngIf="enrollmentEndDate">
<ion-icon class="information-icon" name="information-circle"></ion-icon>
{{'LAST_DATE_TO_JOIN' | translate:{'%s': enrollmentEndDate | date: 'dd/MM/yyyy'} }}
</div>
<div *ngIf="!enrollmentEndDate && batchEndDate">
{{'FRMELEMNTS_LBL_TRAINING_ENDS_ON' | categoryKeyTranslate : course}} {{batchEndDate | date: 'dd/MM/yyyy'}}
</div>
</ion-card-subtitle>
</div>
</div>
<div class="sb-course-end-container" *ngIf="batches && !isAlreadyEnrolled && !batches.length">
<p class="main-heading">
<strong>{{'NO_BATCHES_AVAILABLE' | translate}}</strong>
</p>
<p class="sub-heading">{{'FRMELEMNTS_MSG_THERE_ARE_NO_BATCHES_AVAILABLE_FOR_THIS_TRAINING' | categoryKeyTranslate : course }}</p>
</div>
<div class="sb-course-end-container"
*ngIf="batches && !isAlreadyEnrolled && batches.length === 1 && (todayDate > batches[0].enrollmentEndDate)">
<p class="main-heading">
<strong>{{'FRMELEMNTS_MSG_BATCH_ALREADY_CLOSED' | translate}}</strong>
</p>
<p class="sub-heading">{{'FRMELEMNTS_MSG_THERE_ARE_NO_BATCHES_AVAILABLE_FOR_THIS_TRAINING' | categoryKeyTranslate : course }}</p>
</div>
<div *ngIf="!isAlreadyEnrolled">
<div class="sb-dt-card-actions">
<div class="wrapper sb-btn-tile-group">
<button slot="icon-only" (click)="share()" class="card-button pb-8">
<ion-icon name="share" class="card-icons"></ion-icon>
<p class="card-text">{{'SHARE' | translate}}</p>
</button>
</div>
</div>
</div>
<div *ngIf="isAlreadyEnrolled">
<div>
<div>
<div class="sb-dt-card-actions">
<div class="wrapper"
*ngIf="!isFromGroupFlow">
<div *ngIf="trackDownloads$ | async; let downloads">
<button *ngIf="downloadIdentifiers.size" [disabled]="downloads.queued.length"
(click)="showDownloadConfirmationAlert()" slot="icon-only"
class="card-button">
<ion-icon name="cloud-download"
[ngClass]="(downloads.queued.length)? 'card-icons-downloadStarted': 'card-icons'">
</ion-icon>
<p class="card-text">{{'DOWNLOAD' | translate}}
</p>
</button>
<button *ngIf="isDownloadComplete || course?.isAvailableLocally"
[disabled]="downloads.queued.length" (click)="showDeletePopup()"
slot="icon-only" class="card-button">
<ion-icon name="trash" class="card-icons-red"></ion-icon>
<p class="card-text">{{'REMOVE' | translate}}
</p>
</button>
<button slot="icon-only" (click)="share()" class="card-button">
<ion-icon name="share" class="card-icons"></ion-icon>
<p class="card-text">{{'SHARE' | translate}}</p>
</button>
<accessDiscussion [fetchForumIdReq]="fetchForumIdReq" [createUserReq]="createUserReq" (forumData)="assignForumData($event)"> </accessDiscussion>
<div *ngIf="showUnenrollButton || course?.progress >= 100" class="PR16 pull-right">
<img class="menu-icon" (click)="showOverflowMenu($event)"
src="assets/imgs/menu.svg" alt="menu-icon">
</div>
</div>
</div>
<div *ngIf="isCourseModifiedAfterEnrolment()" class="course-modified">
<img src="assets/imgs/alert.svg" alt="course-modified-icon" class="alert" />
{{'FRMELEMNTS_LBL_COURSE_LAST_UPDATED_ON' | categoryKeyTranslate : course : {'last_updated_on_date': (course?.lastPublishedOn | date: 'dd/MM/yyyy') } }}
</div>
<div *ngIf="courseCardData?.batchId">
<div class="sb-course-progress-container"
*ngIf="!showSheenAnimation && course?.progress!==100 && !batchExp">
<p class="progress-label"><strong>{{'YOUR_PROGRESS_LABEL' | translate}}</strong>
</p>
<p>{{ 'COURSE_COMPLETED_LABEL' | translate:{'%s': course?.progress ? course?.progress : '0'} }}
</p>
<app-pb-horizontal [progress]="course?.progress? course?.progress : 0"
class="course-progress" [ngClass]="{'blurbackground': batchExp}"
isOnBoardCard="flase" isCourseProgress="true"></app-pb-horizontal>
</div>
<div class="sb-batch-end-container" *ngIf="course?.progress !== 100 && batchExp">
<p class="batch-end-main-heading">
{{'BATCHEND_MAIN_HEADING' | categoryKeyTranslate : course : {'%s': batchDetails?.endDate ? (batchDetails?.endDate | date: 'dd/MM/yyyy') : ''} }}
</p>
<p class="batch-end-sub-heading">{{'BATCHEND_SUB_HEADING' | categoryKeyTranslate : course }}</p>
</div>
<div *ngIf="course?.progress && course?.progress === 100"
class="sb-course-complete-container ion-padding">
<div class="img-container">
<img class="success-badge" src='assets/imgs/Badge green.svg'
alt="completed">
</div>
<div class="text-container">
<p><strong>{{'FRMELEMNTS_MSG_TRAINING_COMPLETED_SUCCESSFULLY' | categoryKeyTranslate : course }}</strong></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div *ngIf="activityData && activityData.isGroupCreatorOrAdmin">
<button (click)="navigateToDashboard()" slot="icon-only" class="enrolled-course-card-button">
<span><img src="assets/imgs/dashboard-icon-white.svg" class="card-icons-red play-icon" alt="">
{{'ACTIVITY_DASHBOARD' | translate}}</span>
</button>
</div>
</ion-card-content>
<div #stickyPillsRef
*ngIf="!isFromGroupFlow && !showSheenAnimation && isAlreadyEnrolled && courseCardData?.batchId && course?.progress !== 100"
class="enrolled-course-container">
<div class="timer-info" *ngIf="batchRemaningTime && !batchExp"><div><span>{{ 'BATCH_ENDS_TEXT' | translate }}</span> <span>{{batchRemaningTime}}</span></div></div>
<ion-card class="enrolled-course-card">
<ion-card-content class="ion-padding-top">
<ion-card-title class="last-read-content padding-bottom-8" role="heading" aria-level="2">{{nextContent?.name}}
</ion-card-title>
<button
*ngIf="!showResumeBtn && courseHeirarchy?.children?.length && nextContent?.contentType !== 'SelfAssess'"
class="enrolled-course-card-button" (click)="startLearning()">
<span>
<img class="play-icon" src="assets/imgs/Play@1.5x.svg" alt="play">
{{ 'START_LEARNING' | translate }} </span>
</button>
<button *ngIf="showResumeBtn && nextContent?.contentType !== 'SelfAssess'"
class="enrolled-course-card-button" (click)="resumeContent()">
<span>
<img class="play-icon" src="assets/imgs/Play@1.5x.svg" alt="play">
{{ 'CONTINUE_LEARNING' | translate }} </span>
</button>
<button *ngIf="nextContent?.contentType === 'SelfAssess'" class="enrolled-course-card-button"
(click)="resumeContent()">
<span>
<img class="play-icon" src="assets/imgs/Play@1.5x.svg" alt="play">
{{ 'START_ASSESSMENT' | translate }}
</span>
</button>
<div *ngIf="batchDetails?.endDate && !batchExp" class="enrollment-end-date ion-padding-bottom">
<ion-icon name="information-circle"></ion-icon>
<span *ngIf="!course?.certificate && nextContent?.contentType !== 'SelfAssess'">
{{'COMPLETE_TRAINING_TO_EARN_CERTIFICATE' | categoryKeyTranslate : course : {'%s': batchDetails?.endDate | date: 'dd/MM/yyyy'} }}
</span>
<span *ngIf="!course?.certificate && nextContent?.contentType === 'SelfAssess'">
{{'COMPLETE_ASSESSMENT_TO_EARN_CERTIFICATE' | translate: {'%s': batchDetails?.endDate | date: 'dd/MM/yyyy'} }}
</span>
<span *ngIf="course?.certificate">
{{'FRMELEMNTS_LBL_TO_EARN_CERTIFICATE' | categoryKeyTranslate : course : {'%s': batchDetails?.endDate | date: 'dd/MM/yyyy'} }}
</span>
</div>
</ion-card-content>
</ion-card>
</div>
</ion-card>
<ion-card class="card-box-shadow">
<ion-card-content *ngIf="!showSheenAnimation || (!isGuestUser && showSheenAnimation && isAlreadyEnrolled)"
class="card-content-bottom-0 card-content-top-0">
<ion-segment class="d-flex" [(ngModel)]="segmentType" (ionChange)="onSegmentChange($event)">
<ion-segment-button value="info" class="flex-5">
<ion-label class="font-12 text-transform-none">{{'FRMELEMNTS_LBL_TRAINING_DETAILS' | categoryKeyTranslate : course }}</ion-label>
</ion-segment-button>
<div class="hr-div">
<hr class="hr-height">
</div>
<ion-segment-button value="modules" class="flex-5">
<ion-label class="font-12 text-transform-none">{{'FRMELEMNTS_LBL_TRAINING_MODULES' | categoryKeyTranslate : course }}
</ion-label>
</ion-segment-button>
</ion-segment>
</ion-card-content>
</ion-card>
<ion-card *ngIf="showSheenAnimation && !isAlreadyEnrolled" class="card-box-shadow p-8">
<ion-card-content class="card-content-bottom-0 card-content-top-0 animation-card">
<div class="animation-card-content">
<div class="skeleton-search-card">
<app-skeleton-item [width]="'100%'" [height]="'18px'">
</app-skeleton-item>
</div>
<div class="line-seperator">
<app-skeleton-item [width]="'2px'" [height]="'34px'"> </app-skeleton-item>
</div>
<div class="skeleton-search-card">
<app-skeleton-item [width]="'100%'" [height]="'18px'"> </app-skeleton-item>
</div>
</div>
</ion-card-content>
</ion-card>
<ion-card *ngIf="(isGuestUser && showSheenAnimation) || (!isGuestUser && showSheenAnimation && !isAlreadyEnrolled)"
class="card-box-shadow p-8">
<ion-card-content class="card-content-bottom-0 card-content-top-0 animation-bottom-card">
<div class="skeleton-animation-item-1">
<app-skeleton-item [height]="'22px'"></app-skeleton-item>
</div>
<div class="skeleton-animation-item-2">
<app-skeleton-item [height]="'18px'"></app-skeleton-item>
</div>
<div class="skeleton-animation-item-3">
<app-skeleton-item [height]="'18px'"></app-skeleton-item>
</div>
<div class="skeleton-animation-item-4">
<app-skeleton-item [height]="'18px'"></app-skeleton-item>
</div>
<div class="skeleton-animation-item-5">
<app-skeleton-item [height]="'18px'"></app-skeleton-item>
</div>
<div class="skeleton-animation-item-6">
<app-skeleton-item [height]="'18px'"></app-skeleton-item>
</div>
<div class="skeleton-animation-item-7">
<app-skeleton-item [height]="'18px'"></app-skeleton-item>
</div>
<div class="skeleton-animation-item-8">
<app-skeleton-item [height]="'18px'"></app-skeleton-item>
</div>
<div class="skeleton-animation-item-9">
<app-skeleton-item [height]="'18px'"></app-skeleton-item>
</div>
<div class="skeleton-animation-item-10">
<app-skeleton-item [height]="'18px'"></app-skeleton-item>
</div>
</ion-card-content>
</ion-card>
<div *ngIf="isAlreadyEnrolled && showSheenAnimation">
<ion-card class="bg-grey" *ngFor="let i of [1, 2, 3, 4, 5, 6, 6]">
<ion-card-content class="card-content-bottom-0 card-content-top-0 animation-bottom-card mb-16 mt-16">
<div class="skeleton-animation-item-10 mb-16">
<app-skeleton-item [height]="'18px'"></app-skeleton-item>
</div>
<div class="skeleton-animation-item-11">
<app-skeleton-item [height]="'18px'"></app-skeleton-item>
</div>
</ion-card-content>
</ion-card>
</div>
<div *ngIf="(isGuestUser &&!showSheenAnimation) || (!isGuestUser && !showSheenAnimation)" [ngSwitch]="segmentType">
<ion-card *ngSwitchCase="'info'">
<app-relevant-content-card [contentData]="course"
[isAlreadyEnrolled]="isAlreadyEnrolled"
[isCertifiedCourse]="isCertifiedCourse"
[certificateDescription]="certificateDescription"
[batchEndDate]="batchEndDate"
[enrollmentEndDate]="batchDetails?.enrollmentEndDate"></app-relevant-content-card>
</ion-card>
<ion-card *ngSwitchCase="'info'">
<ion-card-content class="ion-no-padding" *ngIf="!isGuestUser && isAlreadyEnrolled && dataSharingStatus">
<div>
<div class="ion-padding">
<div class="font-14-new view-credits" role="button" aria-level="1" (click)="expandDataSettings()">
<span><strong [attr.aria-label]="isDataShare ?
'profile data sharing, expanded' : 'profile data sharing, Collapsed'">{{'FRMELEMNTS_LBL_DATA_SETTINGS' | translate}}</strong></span>
<span *ngIf="isDataShare" class="consent-arrow">
<ion-icon name="arrow-up" aria-hidden="true"></ion-icon>
</span>
<span *ngIf="!isDataShare" class="consent-arrow">
<ion-icon name="arrow-down" aria-hidden="true"></ion-icon>
</span>
</div>
<div *ngIf="isDataShare" class="showLicensce data-share-header">
<ion-card-title class="data-share-info" *ngIf="dataSharingStatus=='ACTIVE'">{{'FRMELEMNTS_LBL_DATA_SHARING_ON' | translate}}</ion-card-title>
<ion-card-title class="data-share-info" *ngIf="dataSharingStatus=='REVOKED'">{{'FRMELEMNTS_LBL_DATA_SHARING_OFF' | translate}}</ion-card-title>
<p *ngIf="dataSharingStatus=='ACTIVE'">{{'FRMELEMNTS_LBL_DATA_SHARING_ON_INFO' | translate}}</p>
<p *ngIf="dataSharingStatus=='REVOKED'">{{'FRMELEMNTS_LBL_DATA_SHARING_OFF_INFO' | translate}}</p>
<p *ngIf="dataSharingStatus=='ACTIVE'">{{'DFLT_TRK_FRMELEMNTS_LBL_COURSE_LAST_UPDATED_ON' | translate:{'last_updated_on_date': lastUpdateOn | date: 'dd/MM/yyyy'} }}</p>
<div class="edit-setting" (click)="editDataSettings()" *ngIf="!showShareData">{{'FRMELEMNTS_BTN_EDIT_SETTING' | translate}}</div>
<div class="edit-setting" (click)="editDataSettings()" *ngIf="showShareData">{{'FRMELEMNTS_BTN_CLOSE' | translate}}</div>
</div>
</div>
<div *ngIf="isDataShare && showShareData" class="showLicensce">
<div class="ion-padding">
<div class="hr-border-bottom-share"></div>
<div>
<ion-card-title class="font-12 subtitle-color label-margin-bottom" style="padding-top: 10px;">
<strong>{{'FRMELEMNTS_LBL_UPDATE_DATA_SETTINGS' | translate}}</strong>
</ion-card-title>
<ion-list lines="none" class="data-list">
<ion-radio-group [(ngModel)]="dataSharingStatus">
<ion-item class="ds-item" class="list-info">
<ion-label class="ds-m0">{{'FRMELEMNTS_LBL_SHARE_PROFILE_INFORMATION' | translate}}</ion-label>
<ion-radio class="ds-m0" [value]="'REVOKED'" slot="start" ></ion-radio>
</ion-item>
<ion-item class="ds-item" class="list-info">
<ion-label class="ds-m0">{{'FRMELEMNTS_LBL_DONOT_SHARE_PROFILE_INFO' |translate}}</ion-label>
<ion-radio class="ds-m0" [value]="'ACTIVE'" slot="start" ></ion-radio>
</ion-item>
</ion-radio-group>
</ion-list>
<div class="ion-text-center">
<button class="save-changes" (click)="saveChanges()">{{'SAVE' | translate}}</button>
</div>
</div>
</div>
</div>
</div>
</ion-card-content>
</ion-card>
<!--credits and license info-->
<div *ngIf="showCertificateDetails">
<div class="cd-license-card mb-8" *ngSwitchCase="'info'">
<app-show-certificate-component [content]="course"
[certificateDetails]="certificateDetails"
[objRollup]="objRollup"
[corRelationList]="corRelationList"
[pageId]="pageId"></app-show-certificate-component>
</div>
</div>
<div class="cd-license-card mb-8" *ngSwitchCase="'info'">
<app-license-card-component [content]="course"
[licenseDetails]="licenseDetails"
[appName]="appName"
[objRollup]="objRollup"
[corRelationList]="corRelationList"
[pageId]="pageId"></app-license-card-component>
</div>
<div *ngSwitchCase="'modules'">
<sb-toc-curriculum [isChapterListing]="true" [tocData]="courseHeirarchy"
(tocCardClick)="onTocCardClick($event)" shadowColor="#d2eadd" progressColor="#008840">
</sb-toc-curriculum>
</div>
</div>
</div>
<div class="mt-32 mb-32 ion-text-center ion-padding" *ngIf="showOfflineSection">
<img src="assets/imgs/outline-cloud_off.svg" alt="offline" />
<ion-text>
<h6 class="offline-header">
<strong>{{ 'NO_INTERNET_TITLE' | translate }}</strong>
</h6>
</ion-text>
<p class="offline-content">{{ 'OFFLINE_WARNING_ETBUI' | translate }}</p>
<button (click)="getAllBatches()" class="sb-btn sb-btn-outline-info retry-btn">{{'RETRY' | translate}}</button>
</div>
</ion-content>
<ng-container *ngIf="trackDownloads$ | async; let downloads">
<app-sb-download-popup *ngIf="downloads.queued.length" (cancelDownloadEmit)="cancelDownload($event)"
[currentCount]="downloads.completed.length"
[queuedIdentifiers]="(downloads.queued.length+downloads.completed.length)" [downloadSize]="downloadSize"
[collectionName]="course?.name" [showDownload]="true" [showPopover]="showCollapsedPopup">
</app-sb-download-popup>
</ng-container>
./enrolled-course-details-page.scss
@import 'src/assets/styles/_custom-mixins';
@import "src/assets/styles/variables";
@import "src/assets/styles/_variables.scss";
:host {
ion-card{
margin: 0 0 10px 0 !important;
--ion-item-background: white;
}
.z-index-0 {
z-index: 0 !important;
}
.retry-btn{
border-color: $orange;
color: $orange !important;
padding: 8px 40px;
font-size: $font-size-base;
border-radius: 0 !important;
}
.sb-url {
color: map-get($colors, bright_blue_a0);
font-size: $font-size-base;
text-decoration: underline;
}
.fontBold {
font-weight: bold;
}
.ion-ios-radio-button-on:before {
color: darkgrey;
}
.ion-ios-checkmark-circle:before {
color: map-get($colors, office_green);
margin-right: 4px;
margin-left: 0px;
}
.structure-text{
padding: 7px 0px 0px 4px;
}
.certified-section-color{
color: map-get($colors, bright_blue_9f);
}
.certified-training-section{
background-color: map-get($colors, pale_blue);
padding: 8px;
}
.font-10{
font-size: 0.625rem;
}
.font-12 {
font-size: 0.75rem!important;
}
.font-13{
font-size: 0.813rem !important;
}
.font-16{
font-size: 1rem!important;
}
.font-14{
font-size: $font-size-base !important;
}
.font-18{
font-size: 1.125rem;
}
.padding-left-8{
@include padding(0px 0px 0px 8px);
}
.child-item{
--padding-start: 0 !important;
@include padding(null, null, null, 0 !important)
}
.text-transform-none{
text-transform: none !important;
}
.card-content-bottom-0{
padding-bottom: 0px !important;
}
.card-content-top-0{
padding-top: 0px !important;
}
.subtitle-color{
color: var(--app-gray)
}
.enrolled-course-container {
&.sticky {
position: sticky;
top: 0;
left: 0;
z-index: 10;
}
}
.traning-derived-label-background {
background-color: map-get($colors, white_f2);
padding: 8px 0px 8px 15px;
}
ion-card ion-card-content p {
font-size: $font-size-base;
}
.enrolled-course-card{
background-color: map-get($colors, pale_green);
margin-bottom: 0 !important;
}
.play-icon{
display: inline;
width: 1.313rem;
vertical-align: middle;
margin-right: 6.43px;
}
ion-content{
--ion-background-color: white;
}
.hr-border-bottom {
box-sizing: border-box;
height: 1px;
width: 100%;
border: 0.5px solid map-get($colors, medium_gray);
margin-top: 9px;
}
.hr-border-bottom-share {
box-sizing: border-box;
height: 1px;
border: 1px solid #E9DED3;
margin-top: 8px;
}
hr {
border:0.5px solid $gray-300;
}
.blurbackground {
.progress-inner-primary {
background-color: gray !important;
}
.progress-inner-secondary {
background-color: gray !important;
}
}
.loading-backdrop {
background-color: map-get($colors, white);
height: 100%;
z-index: 1000;
opacity: 1 !important;
top: 0;
bottom: 0;
.backdrop-container {
width: 100%;
padding: 16px;
text-align: center;
position: absolute;
top: 50%;
margin-top: -50px;
}
.backdrop-footer {
position: absolute;
width: 100%;
bottom: 0;
padding-bottom: 16px;
}
}
.scroll-content {
margin-bottom: 0 !important;
}
.toolbar-p-16{
padding: ($base-block-space * 2) ($base-block-space * 2) ($base-block-space / 2) ($base-block-space * 2) !important;
}
.size_txt {
font-size: 0.75rem;
}
.padding-right-3 {
padding-right: 3px;
}
.list-mb-48{
margin-bottom: ($base-block-space * 6) !important;
}
.sc-ion-buttons-md-s ion-button {
height: 1.25rem;
font-size: 0.625rem;
}
.label-margin-bottom{
margin-bottom: 3px !important;
}
.sb-accordian-header{
padding: 12px 14px;
.dd-icon {
position: relative;
bottom: 0.188rem;
}
.sb-checkmark-icon{
color: map-get($colors, office_green);
}
}
.custom-card-header{
padding-bottom: 0px !important;
}
.sb-accordian-arrow{
float: right;
font-size: $font-size-base;
padding-top: 10px;
}
.enrollment-info{
ion-icon{
position: relative;
top: 0.125rem;
}
}
.enrolled-course-card-button{
background-color: $green;
border: none;
color: white;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 1rem;
cursor: pointer;
outline: none;
margin: 4px 0 8px;
width: 100%;
padding: 16px 0 16px 0;
}
.disable-css {
opacity : 0.5;
}
.segment-button-checked{
ion-label.sc-ion-label-md-h.sc-ion-label-md-s.md.hydrated{
font-weight: bold;
}
}
.border-right{
border-right: 1.5px solid map-get($colors, white_e6);
margin: 0px 0px 10px 11px;
}
.hr-div {
padding: 0px 10px 0px 10px;
}
hr.hr-height {
height: 2rem;
}
.segment-button-indicator{
width: 84% !important;
margin-right: 8% !important;
}
.info-icon-pr-8 {
padding-right: 8px !important;
}
}
.sb-topics-containe{
padding-right: 5%;
}
.sb-hidden-content{
background-color: map-get($colors, pale_blue) !important;
// height: 34.15% !important;
width: 100% !important;
border-radius: 0 0 2px 2px !important;
padding-top: 2% !important;
padding-bottom: 5% !important;
}
.sb-accordian-card{
// height: 6.1% !important;
width: 100% !important;
border-radius: 2px !important;
background-color: map-get($colors, white) !important;
box-shadow: 0px 5px 5px 3px map-get($colors, light_gray_dd);
}
.sb-topic-text {
// padding-top: 5px;
padding: 0;
ion-icon{
vertical-align: middle;
}
// height: 2.44%;
// width: 80%;
color: $blue;
font-size: $font-size-base;
// line-height: 20px;
}
.certificate-container {
display: inline-flex;
flex-wrap: nowrap;
align-items:center;
background-color: map-get($colors, pale_blue_f6);
padding: 4px;
.certificate-icon {
padding-right: 5px;
}
}
.sc-ion-segment-md-h{
--color-checked : #{$blue};
font-weight: bold;
--color: #{map-get($colors, cornflower_blue)};
}
.wrapper {
grid-template-columns: 100px 100px 100px auto;
margin-bottom: -8px;
border-radius: 5px;
& > div {
border-radius: 5px;
padding: 1em 0;
}
}
.pull-right{
float: right;
}
.menu-icon{
display: block;
width: 100%;
height: 1rem;
margin-top: 18px;
float: right;
}
.card-icons {
font-size: 1.875rem;
color: $blue;
}
.card-icons-downloadStarted {
font-size: 1.875rem;
color: map-get($colors, text_gray);
}
.card-icons-red{
font-size: 1.875rem !important;
color:map-get($colors , danger);
}
.sb-course-complete-container {
white-space: nowrap;
width: 100%;
background-color: map-get($colors, light_grayish_green);
@include padding(8px);
.img-container{
width: 20%;
vertical-align: middle;
display: inline-block;
}
.text-container{
color: map-get($colors, office_green);
font-family: "Noto Sans", sans-serif;
font-size: $font-size-base !important;
font-weight: bold;
width: 80%;
vertical-align: middle;
display: inline-block;
padding-left: 10px;
@include padding(0px 0px 0px 11px);
white-space: normal;
}
}
.card-text{
height: 1.125rem;
width: auto;
color: map-get($colors, granite_gray);
font-family: "Noto Sans", sans-serif;
font-size: 0.813rem !important;
line-height: 1.25rem;
text-align: center;
}
.card-button{
background-color: transparent !important;
outline: none;
padding: 0px 16px;
}
.padding-bottom-6{
padding-bottom: 6px;
}
.padding-bottom-8{
padding-bottom: 8px;
}
.margin-bottom-2{
margin-bottom: 2px;
}
.margin-bottom-16{
margin-bottom: 16px;
}
.sb-course-progress-container{
background-color: map-get($colors, pale_blue);
padding: 8px;
height: 4.38rem;
width: auto;
}
.last-read-content{
font-size: 1rem!important;
font-weight:bold;
@include rtl() {
padding-bottom: 4px;
}
@include ltr() {
padding-left: 4px;
}
}
.sb-batch-end-container{
background-color: map-get($colors, pale_red);
padding: 8px 16px;
height: auto;
width: auto;
.batch-end-main-heading{
font-size: 0.75rem !important;
color: $orange;
font-weight: bold;
}
.batch-end-sub-heading{
color: map-get($colors, primary_black);
font-family: "Noto Sans", sans-serif;
font-size: 0.75rem !important;
}
}
.enrollment-end-date{
font-size: 0.75rem;
color: map-get($colors, primary_black);
font-family: "Noto Sans", sans-serif;
ion-icon{
position: relative;
top: 0.125rem;
}
}
.padding-left-5em{
padding-left: 5em !important;
}
.sb-course-end-container{
background-color: map-get($colors, pale_red);
padding: 10px;
height: 4.38rem;
width: auto;
.main-heading{
font-size: $font-size-base !important;
color: $orange;
}
.sub-heading{
color: map-get($colors, primary_black);
font-family: "Noto Sans", sans-serif;
font-size: 0.75rem !important;
}
}
.information-icon {
color: map-get($colors, dark);
font-size: $font-size-base;
}
.progress-label {
font-size: 0.625rem!important;
color: map-get($colors, primary_black);
}
ion-segment-button{
--ripple-color: transparent;
--background-hover: transparent;
--background-activated: transparent;
}
.flex-5 {
flex: 5;
}
#card-mb-0{
margin-bottom: 0 !important;
}
.card-box-shadow {
box-shadow: 0px 5px 5px 3px map-get($colors, light_gray_dd);
margin: 0 0 1rem 0 !important
}
.animation-card{
padding:8px 16px;
.animation-card-content{
display:flex;
justify-content:space-between;
align-items: center;
.skeleton-search-card{
width:45%;
}
}
}
.animation-bottom-card {
.skeleton-animation-item-1{
width:40%; margin-bottom:20px
}
.skeleton-animation-item-2, .skeleton-animation-item-4, .skeleton-animation-item-6{
width:48%; margin-bottom:8px
}
.skeleton-animation-item-3{
width:25%;margin-bottom:8px
}
.skeleton-animation-item-5{
width:25%;margin-bottom:20px
}
.skeleton-animation-item-7{
width:25%;margin-bottom:16px;
}
.skeleton-animation-item-8, .skeleton-animation-item-9{
width:100%;margin-bottom:8px;
}
.skeleton-animation-item-10 {
width:48%;
}
.skeleton-animation-item-11 {
width:25%;
}
}
.bg-grey {
background: map-get($colors, white_f0) !important;
}
.card-button[disabled]{
opacity: 0.7 !important;
pointer-events: none;
cursor: default;
}
.course-modified {
padding: 16px;
margin-bottom: 16px;
box-sizing: border-box;
border: 1px solid map-get($colors, dark_orange);
border-radius: 2px;
background-color: map-get($colors, ligth_yellow);
color: $gray-800;
font-size: 0.75rem;
.alert {
width: 1.5rem;
height: 1.5rem;
display: inline-block;
margin-right: 8px;
}
}
.edit-setting{
float: right;
padding: 12px;
color: $blue;
font-weight: bold;
}
.sb-content-info{
padding: 4px 14px;
}
.save-changes{
color: map-get($colors, white);
background-color: $blue;
padding: 12px 45px;
outline: none;
border: none;
text-transform: uppercase;
font-weight: bold;
font-size: 0.75rem;
}
.ds-m0 {
color: map-get($colors, primary_black);
font-family: "Noto Sans", sans-serif;
font-size: 0.75rem;
letter-spacing: 0;
line-height: 1.25rem;
}
.ds-item{
--padding-start: 0px;
}
ion-radio{
margin-right: 10px !important;
}
.font-14-new{
font-size: 1rem !important;
margin-top: 8px;
}
.data-share-info{
padding: 5px;
margin-left: -6px;
font-size: 0.938rem;
text-transform: uppercase;
}
.data-share-header{
margin-left: 2px;
}
.timer-info{
text-align: center;
width: 100%;
font-size: 1.2rem;
font-weight: 600;
color: indianred;
padding: 0 0 10px;
}
.data-list{
background: unset !important;
}
.list-info{
margin-top: -13px; opacity: 1;
}
.consent-arrow{
float: right
}
.consent-arrow {
ion-icon{
font-size: 1.5rem;
color: #024f9d;
}
}
.sb--card__meta1 {
margin-top:0px;
width: 100%;
.data_1, .data_2 {
color: var(--cc-sbcard-data1-2-text);
border-radius: 0.5rem;
font-size: $font-size-base;
width:auto;flex: initial;
white-space: nowrap;
}
.data_2 {
&:last-child {
margin-right:0px;
}
}
}
.course-details{
ion-card-title{
strong{
color: var(--app-medium-gray);
}
}
p{
color: var(--app-gray);
}
}