src/app/courses/courses.page.ts
OnInit
OnDestroy
selector | app-courses |
styleUrls | ./courses.page.scss |
templateUrl | ./courses.page.html |
constructor(eventBusService: EventsBusService, preferences: SharedPreferences, courseService: CourseService, contentService: ContentService, frameworkService: FrameworkService, profileService: ProfileService, frameworkUtilService: FrameworkUtilService, formAndFrameworkUtilService: FormAndFrameworkUtilService, appVersion: AppVersion, ngZone: NgZone, qrScanner: SunbirdQRScanner, popCtrl: PopoverController, events: Events, appGlobalService: AppGlobalService, courseUtilService: CourseUtilService, commonUtilService: CommonUtilService, telemetryGeneratorService: TelemetryGeneratorService, network: Network, router: Router, toastController: ToastController, headerService: AppHeaderService, sbProgressLoader: SbProgressLoader, navService: NavigationService, contentAggregatorHandler: ContentAggregatorHandler, profileHandler: ProfileHandler, translate: TranslateService, platform: Platform)
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Defined in src/app/courses/courses.page.ts:125
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Parameters :
|
cancelDownload |
cancelDownload()
|
Defined in src/app/courses/courses.page.ts:734
|
Returns :
void
|
checkEmptySearchResult | ||||||
checkEmptySearchResult(isAfterLanguageChange)
|
||||||
Defined in src/app/courses/courses.page.ts:544
|
||||||
Parameters :
Returns :
void
|
Async checkRetiredOpenBatch | |||||||||
checkRetiredOpenBatch(content: any, courseDetails)
|
|||||||||
Defined in src/app/courses/courses.page.ts:799
|
|||||||||
Parameters :
Returns :
any
|
concatFilter | ||||||
concatFilter(filter, searchCriteria)
|
||||||
Defined in src/app/courses/courses.page.ts:1002
|
||||||
Parameters :
Returns :
any
|
Private contentDetailsImportCall | ||||
contentDetailsImportCall(identifier)
|
||||
Defined in src/app/courses/courses.page.ts:607
|
||||
Parameters :
Returns :
void
|
Async exploreOtherContents |
exploreOtherContents()
|
Defined in src/app/courses/courses.page.ts:1010
|
Returns :
any
|
generateExtraInfoTelemetry | ||||
generateExtraInfoTelemetry(sectionsCount)
|
||||
Defined in src/app/courses/courses.page.ts:339
|
||||
Parameters :
Returns :
void
|
generateNetworkType |
generateNetworkType()
|
Defined in src/app/courses/courses.page.ts:255
|
Returns :
void
|
Async getAggregatorResult | ||||||
getAggregatorResult(resetFilter?: boolean)
|
||||||
Defined in src/app/courses/courses.page.ts:956
|
||||||
Parameters :
Returns :
any
|
Async getCategoryData | ||||||||
getCategoryData(frameworkId, categoryName, currentCategory)
|
||||||||
Defined in src/app/courses/courses.page.ts:1037
|
||||||||
Parameters :
Returns :
Promise<any>
|
getContentDetails | ||||
getContentDetails(content)
|
||||
Defined in src/app/courses/courses.page.ts:572
|
||||
Parameters :
Returns :
void
|
getCourseTabData | ||||
getCourseTabData(refresher?)
|
||||
Defined in src/app/courses/courses.page.ts:379
|
||||
Parameters :
Returns :
void
|
Private getCurrentUser |
getCurrentUser()
|
Defined in src/app/courses/courses.page.ts:402
|
It will fetch the guest user profile details
Returns :
void
|
getUserId |
getUserId()
|
Defined in src/app/courses/courses.page.ts:363
|
Get user id. Used to get enrolled course(s) of logged-in user
Returns :
any
|
handleHeaderEvents | ||||
handleHeaderEvents($event)
|
||||
Defined in src/app/courses/courses.page.ts:748
|
||||
Parameters :
Returns :
void
|
Private importContent | ||||||
importContent(identifiers, isChild)
|
||||||
Defined in src/app/courses/courses.page.ts:681
|
||||||
Parameters :
Returns :
void
|
ionViewDidEnter |
ionViewDidEnter()
|
Defined in src/app/courses/courses.page.ts:227
|
Returns :
void
|
ionViewWillEnter |
ionViewWillEnter()
|
Defined in src/app/courses/courses.page.ts:215
|
Returns :
void
|
ionViewWillLeave |
ionViewWillLeave()
|
Defined in src/app/courses/courses.page.ts:239
|
Returns :
void
|
isGroupedCoursesAvailable | ||||
isGroupedCoursesAvailable(displayItems)
|
||||
Defined in src/app/courses/courses.page.ts:1054
|
||||
Parameters :
Returns :
void
|
Async navigateToBatchListPopup |
navigateToBatchListPopup(content: any, courseDetails: any, retiredBatched?: any)
|
Defined in src/app/courses/courses.page.ts:822
|
Returns :
any
|
Private navigateToContentDetailsPage | ||||
navigateToContentDetailsPage(content)
|
||||
Defined in src/app/courses/courses.page.ts:660
|
||||
Parameters :
Returns :
void
|
Async navigateToDetailPage |
navigateToDetailPage(content: any, courseDetails: any)
|
Defined in src/app/courses/courses.page.ts:883
|
Navigate to the course/content details page
Returns :
any
|
navigateToTextbookPage | ||||||
navigateToTextbookPage(items, subject)
|
||||||
Defined in src/app/courses/courses.page.ts:937
|
||||||
Parameters :
Returns :
void
|
navigateToViewMoreContentsPage | |||||||||||||||
navigateToViewMoreContentsPage(showEnrolledCourses: boolean, sectionId?: string, searchQuery?: any, headerTitle?: string)
|
|||||||||||||||
Defined in src/app/courses/courses.page.ts:613
|
|||||||||||||||
Parameters :
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Defined in src/app/courses/courses.page.ts:184
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Defined in src/app/courses/courses.page.ts:176
|
Angular life cycle hooks
Returns :
void
|
openCourseDetails | ||||||||
openCourseDetails(event, section, index)
|
||||||||
Defined in src/app/courses/courses.page.ts:784
|
||||||||
Parameters :
Returns :
void
|
openEnrolledCourseDetails | ||||
openEnrolledCourseDetails(event)
|
||||
Defined in src/app/courses/courses.page.ts:771
|
||||
Parameters :
Returns :
void
|
Private Async presentToastForOffline | ||||||
presentToastForOffline(msg: string)
|
||||||
Defined in src/app/courses/courses.page.ts:510
|
||||||
Parameters :
Returns :
any
|
Private redirectToActivedownloads |
redirectToActivedownloads()
|
Defined in src/app/courses/courses.page.ts:762
|
Returns :
void
|
Private removeOverlayAndShowError |
removeOverlayAndShowError()
|
Defined in src/app/courses/courses.page.ts:712
|
This method removes the loading/downloading overlay and displays the error message and also shows the bottom navigation bar
Returns :
any
|
resetFilter | ||||
resetFilter(data)
|
||||
Defined in src/app/courses/courses.page.ts:503
|
||||
Parameters :
Returns :
any
|
retryShowingPopularCourses | ||||||
retryShowingPopularCourses(showRefresh)
|
||||||
Defined in src/app/courses/courses.page.ts:566
|
||||||
Parameters :
Returns :
void
|
Async search |
search()
|
Defined in src/app/courses/courses.page.ts:407
|
Returns :
any
|
showFilter |
showFilter()
|
Defined in src/app/courses/courses.page.ts:426
|
Returns :
void
|
Async showFilterPage | ||||
showFilterPage(filterOptions)
|
||||
Defined in src/app/courses/courses.page.ts:524
|
||||
Parameters :
Returns :
any
|
showOfflineWarning |
showOfflineWarning()
|
Defined in src/app/courses/courses.page.ts:562
|
Returns :
void
|
spinner | ||||||
spinner(flag: boolean)
|
||||||
Defined in src/app/courses/courses.page.ts:352
|
||||||
To start / stop spinner
Parameters :
Returns :
void
|
Private subscribeSdkEvent |
subscribeSdkEvent()
|
Defined in src/app/courses/courses.page.ts:718
|
Returns :
void
|
subscribeUtilityEvents |
subscribeUtilityEvents()
|
Defined in src/app/courses/courses.page.ts:264
|
Returns :
void
|
unsubscribeUtilityEvents |
unsubscribeUtilityEvents()
|
Defined in src/app/courses/courses.page.ts:200
|
Returns :
void
|
appLabel |
Type : string
|
Defined in src/app/courses/courses.page.ts:93
|
appliedFilter |
Type : any
|
Defined in src/app/courses/courses.page.ts:95
|
callback |
Type : QRResultCallback
|
Defined in src/app/courses/courses.page.ts:110
|
Public commonUtilService |
Type : CommonUtilService
|
Defined in src/app/courses/courses.page.ts:143
|
Private corRelationList |
Type : Array<CorrelationData>
|
Defined in src/app/courses/courses.page.ts:115
|
courseCardType |
Default value : CourseCardGridTypes
|
Defined in src/app/courses/courses.page.ts:119
|
courseFilter |
Type : any
|
Defined in src/app/courses/courses.page.ts:94
|
downloadPercentage |
Type : number
|
Default value : 0
|
Defined in src/app/courses/courses.page.ts:105
|
dynamicCourses |
Type : any
|
Defined in src/app/courses/courses.page.ts:121
|
enrolledCourses |
Type : Array<Course>
|
Default value : []
|
Defined in src/app/courses/courses.page.ts:63
|
Contains enrolled course |
Private eventSubscription |
Type : Subscription
|
Defined in src/app/courses/courses.page.ts:113
|
filter |
Type : ContentSearchCriteria
|
Defined in src/app/courses/courses.page.ts:124
|
filterIcon |
Type : string
|
Default value : './assets/imgs/ic_action_filter.png'
|
Defined in src/app/courses/courses.page.ts:96
|
guestUser |
Default value : false
|
Defined in src/app/courses/courses.page.ts:87
|
headerObservable |
Type : any
|
Defined in src/app/courses/courses.page.ts:114
|
inProgressSection |
Type : string
|
Default value : 'My Courses'
|
Defined in src/app/courses/courses.page.ts:99
|
isCourseListEmpty |
Type : boolean
|
Defined in src/app/courses/courses.page.ts:125
|
isFilterApplied |
Default value : false
|
Defined in src/app/courses/courses.page.ts:109
|
isFilterOpen |
Default value : false
|
Defined in src/app/courses/courses.page.ts:116
|
isOnBoardingCardCompleted |
Default value : false
|
Defined in src/app/courses/courses.page.ts:89
|
isUpgradePopoverShown |
Default value : false
|
Defined in src/app/courses/courses.page.ts:112
|
isVisible |
Default value : false
|
Defined in src/app/courses/courses.page.ts:98
|
layoutInProgress |
Default value : ContentCard.LAYOUT_INPROGRESS
|
Defined in src/app/courses/courses.page.ts:80
|
layoutPopular |
Default value : ContentCard.LAYOUT_POPULAR
|
Defined in src/app/courses/courses.page.ts:81
|
loader |
Type : any
|
Defined in src/app/courses/courses.page.ts:120
|
onBoardingProgress |
Type : number
|
Default value : 0
|
Defined in src/app/courses/courses.page.ts:90
|
pageApiLoader |
Default value : true
|
Defined in src/app/courses/courses.page.ts:86
|
Flag to show latest and popular course loader |
pageFilterCallBack |
Type : PageFilterCallback
|
Defined in src/app/courses/courses.page.ts:111
|
Public platform |
Type : Platform
|
Defined in src/app/courses/courses.page.ts:154
|
popularAndLatestCourses |
Type : Array<any>
|
Defined in src/app/courses/courses.page.ts:68
|
Contains popular and latest courses ist |
profile |
Type : Profile
|
Defined in src/app/courses/courses.page.ts:97
|
queuedIdentifiers |
Type : Array<any>
|
Default value : []
|
Defined in src/app/courses/courses.page.ts:104
|
To queue downloaded identifier |
refresher |
Type : IonRefresher
|
Decorators :
@ViewChild('courseRefresher', {static: false})
|
Defined in src/app/courses/courses.page.ts:58
|
resetCourseFilter |
Type : boolean
|
Defined in src/app/courses/courses.page.ts:123
|
resumeContentData |
Type : any
|
Defined in src/app/courses/courses.page.ts:107
|
searchGroupingContents |
Type : any
|
Defined in src/app/courses/courses.page.ts:122
|
selectedLanguage |
Type : string
|
Default value : 'en'
|
Defined in src/app/courses/courses.page.ts:92
|
showLoader |
Default value : true
|
Defined in src/app/courses/courses.page.ts:78
|
Flag to show/hide loader |
showOverlay |
Default value : false
|
Defined in src/app/courses/courses.page.ts:106
|
showSignInCard |
Default value : false
|
Defined in src/app/courses/courses.page.ts:88
|
Private Optional ssoSectionId |
Type : string
|
Defined in src/app/courses/courses.page.ts:117
|
tabBarElement |
Type : any
|
Defined in src/app/courses/courses.page.ts:108
|
toast |
Type : any
|
Defined in src/app/courses/courses.page.ts:91
|
userId |
Type : string
|
Defined in src/app/courses/courses.page.ts:73
|
Contains user id |
import { Component, Inject, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { NavigationExtras, Router } from '@angular/router';
import { ContentAggregatorHandler } from '@app/services/content/content-aggregator-handler.service';
import { AggregatorPageType } from '@app/services/content/content-aggregator-namespaces';
import { NavigationService } from '@app/services/navigation-handler.service';
import { ProfileHandler } from '@app/services/profile-handler';
import { ContentUtil } from '@app/util/content-util';
import { AppVersion } from '@ionic-native/app-version/ngx';
import { Network } from '@ionic-native/network/ngx';
import { IonRefresher, Platform, PopoverController, ToastController } from '@ionic/angular';
import { Events } from '@app/util/events';
import { CsPrimaryCategory } from '@project-sunbird/client-services/services/content';
import { CourseCardGridTypes } from '@project-sunbird/common-consumption';
import forEach from 'lodash/forEach';
import { Subscription } from 'rxjs';
import {
Content,
ContentAggregatorRequest, ContentEventType, ContentImportRequest, ContentImportResponse, ContentImportStatus,
ContentSearchCriteria, ContentService,
CorrelationData, Course,
CourseBatchesRequest,
CourseBatchStatus,
CourseEnrollmentType,
CourseService, DownloadEventType, DownloadProgress, EventsBusEvent, EventsBusService,
FrameworkCategoryCode,
FrameworkCategoryCodesGroup,
FrameworkService, FrameworkUtilService, GetFrameworkCategoryTermsRequest, NetworkError, PageAssembleCriteria, PageName,
Profile, ProfileService, SharedPreferences,
SortOrder, TelemetryObject
} from 'sunbird-sdk';
import {
BatchConstants, ContentCard,
ContentFilterConfig, EventTopics,
MimeType, PreferenceKey, ProfileConstants,
ProgressPopupContext, RouterLinks, ViewMore
} from '../../app/app.constant';
import { AppGlobalService } from '../../services/app-global-service.service';
import { AppHeaderService } from '../../services/app-header.service';
import { CommonUtilService } from '../../services/common-util.service';
import { CourseUtilService } from '../../services/course-util.service';
import { FormAndFrameworkUtilService } from '../../services/formandframeworkutil.service';
import { SbProgressLoader } from '../../services/sb-progress-loader.service';
import { QRResultCallback, SunbirdQRScanner } from '../../services/sunbirdqrscanner.service';
import { CorReleationDataType, Environment, InteractSubtype, InteractType, PageId } from '../../services/telemetry-constants';
import { TelemetryGeneratorService } from '../../services/telemetry-generator.service';
import { applyProfileFilter, updateFilterInSearchQuery } from '../../util/filter.util';
import { EnrollmentDetailsComponent } from '../components/enrollment-details/enrollment-details.component';
import { PageFilterCallback, PageFilterPage } from '../page-filter/page-filter.page';
import { TranslateService } from '@ngx-translate/core';
@Component({
selector: 'app-courses',
templateUrl: './courses.page.html',
styleUrls: ['./courses.page.scss'],
})
export class CoursesPage implements OnInit, OnDestroy {
@ViewChild('courseRefresher', { static: false }) refresher: IonRefresher;
/**
* Contains enrolled course
*/
enrolledCourses: Array<Course> = [];
/**
* Contains popular and latest courses ist
*/
popularAndLatestCourses: Array<any>;
/**
* Contains user id
*/
userId: string;
/**
* Flag to show/hide loader
*/
showLoader = true;
layoutInProgress = ContentCard.LAYOUT_INPROGRESS;
layoutPopular = ContentCard.LAYOUT_POPULAR;
/**
* Flag to show latest and popular course loader
*/
pageApiLoader = true;
guestUser = false;
showSignInCard = false;
isOnBoardingCardCompleted = false;
onBoardingProgress = 0;
toast: any;
selectedLanguage = 'en';
appLabel: string;
courseFilter: any;
appliedFilter: any;
filterIcon = './assets/imgs/ic_action_filter.png';
profile: Profile;
isVisible = false;
inProgressSection = 'My Courses';
/**
* To queue downloaded identifier
*/
queuedIdentifiers: Array<any> = [];
downloadPercentage = 0;
showOverlay = false;
resumeContentData: any;
tabBarElement: any;
isFilterApplied = false;
callback: QRResultCallback;
pageFilterCallBack: PageFilterCallback;
isUpgradePopoverShown = false;
private eventSubscription: Subscription;
headerObservable: any;
private corRelationList: Array<CorrelationData>;
isFilterOpen = false;
private ssoSectionId?: string;
courseCardType = CourseCardGridTypes;
loader: any;
dynamicCourses: any;
searchGroupingContents: any;
resetCourseFilter: boolean;
filter: ContentSearchCriteria;
isCourseListEmpty: boolean;
constructor(
@Inject('EVENTS_BUS_SERVICE') private eventBusService: EventsBusService,
@Inject('SHARED_PREFERENCES') private preferences: SharedPreferences,
@Inject('COURSE_SERVICE') private courseService: CourseService,
@Inject('CONTENT_SERVICE') private contentService: ContentService,
@Inject('FRAMEWORK_SERVICE') private frameworkService: FrameworkService,
@Inject('PROFILE_SERVICE') private profileService: ProfileService,
@Inject('FRAMEWORK_UTIL_SERVICE') private frameworkUtilService: FrameworkUtilService,
private formAndFrameworkUtilService: FormAndFrameworkUtilService,
private appVersion: AppVersion,
private ngZone: NgZone,
private qrScanner: SunbirdQRScanner,
private popCtrl: PopoverController,
private events: Events,
private appGlobalService: AppGlobalService,
private courseUtilService: CourseUtilService,
public commonUtilService: CommonUtilService,
private telemetryGeneratorService: TelemetryGeneratorService,
private network: Network,
private router: Router,
private toastController: ToastController,
private headerService: AppHeaderService,
private sbProgressLoader: SbProgressLoader,
private navService: NavigationService,
private contentAggregatorHandler: ContentAggregatorHandler,
private profileHandler: ProfileHandler,
private translate: TranslateService,
public platform: Platform
) {
this.tabBarElement = document.querySelector('.tabbar.show-tabbar');
this.preferences.getString(PreferenceKey.SELECTED_LANGUAGE_CODE).toPromise()
.then(val => {
if (val && val.length) {
this.selectedLanguage = val;
}
});
this.subscribeUtilityEvents();
this.appVersion.getAppName()
.then((appName: any) => {
this.appLabel = appName;
});
this.generateNetworkType();
}
/**
* Angular life cycle hooks
*/
ngOnInit() {
this.getCourseTabData();
this.events.subscribe('event:update_course_data', () => {
this.getAggregatorResult();
});
}
ngOnDestroy() {
if (this.headerObservable) {
this.headerObservable.unsubscribe();
}
this.events.unsubscribe('update_header');
this.ngZone.run(() => {
if (this.eventSubscription) {
this.eventSubscription.unsubscribe();
}
this.isVisible = false;
this.showOverlay = false;
this.downloadPercentage = 0;
});
this.unsubscribeUtilityEvents();
}
unsubscribeUtilityEvents() {
this.events.unsubscribe(AppGlobalService.PROFILE_OBJ_CHANGED);
this.events.unsubscribe(EventTopics.COURSE_STATUS_UPDATED_SUCCESSFULLY);
this.events.unsubscribe('force_optional_upgrade');
this.events.unsubscribe('onboarding-card:completed');
this.events.unsubscribe('onboarding-card:increaseProgress');
this.events.unsubscribe('course:resume');
this.events.unsubscribe(EventTopics.ENROL_COURSE_SUCCESS);
this.events.unsubscribe('onAfterLanguageChange:update');
this.events.unsubscribe(EventTopics.COURSE_PAGE_ASSEMBLE_CHANNEL_CHANGE);
this.events.unsubscribe(EventTopics.TAB_CHANGE);
this.events.unsubscribe(EventTopics.REFRESH_ENROLL_COURSE_LIST);
this.events.unsubscribe(EventTopics.SIGN_IN_RELOAD);
}
ionViewWillEnter() {
this.refresher.disabled = false;
this.isVisible = true;
this.events.subscribe('update_header', () => {
this.headerService.showHeaderWithHomeButton(['search', 'download']);
});
this.headerObservable = this.headerService.headerEventEmitted$.subscribe(eventName => {
this.handleHeaderEvents(eventName);
});
this.headerService.showHeaderWithHomeButton(['search', 'download']);
}
ionViewDidEnter() {
this.sbProgressLoader.hide({ id: ProgressPopupContext.DEEPLINK });
this.appGlobalService.generateConfigInteractEvent(PageId.COURSES, this.isOnBoardingCardCompleted);
this.events.subscribe('event:showScanner', (data) => {
if (data.pageName === PageId.COURSES) {
this.qrScanner.startScanner(PageId.COURSES, false);
}
});
this.sbProgressLoader.hide({ id: 'login' });
}
ionViewWillLeave() {
this.refresher.disabled = true;
if (this.headerObservable) {
this.headerObservable.unsubscribe();
}
this.events.unsubscribe('update_header');
this.ngZone.run(() => {
if (this.eventSubscription) {
this.eventSubscription.unsubscribe();
}
this.isVisible = false;
this.showOverlay = false;
this.downloadPercentage = 0;
});
}
generateNetworkType() {
const values = new Map();
values['network-type'] = this.network.type;
this.telemetryGeneratorService.generateExtraInfoTelemetry(
values,
PageId.LIBRARY
);
}
subscribeUtilityEvents() {
// Event for optional and forceful upgrade
this.events.subscribe('force_optional_upgrade', async (upgrade) => {
if (upgrade && !this.isUpgradePopoverShown) {
await this.appGlobalService.openPopover(upgrade);
this.isUpgradePopoverShown = true;
}
});
this.events.subscribe('onboarding-card:completed', (param) => {
this.isOnBoardingCardCompleted = param.isOnBoardingCardCompleted;
});
this.events.subscribe(AppGlobalService.PROFILE_OBJ_CHANGED, () => {
this.getCourseTabData();
});
this.events.subscribe(EventTopics.COURSE_STATUS_UPDATED_SUCCESSFULLY, (data) => {
if (data.update) {
this.getAggregatorResult();
}
});
this.events.subscribe('onboarding-card:increaseProgress', (progress) => {
this.onBoardingProgress = progress.cardProgress;
});
this.events.subscribe('course:resume', (data) => {
this.resumeContentData = data.content;
this.getContentDetails(data.content);
});
this.events.subscribe(EventTopics.ENROL_COURSE_SUCCESS, (res) => {
if (res && res.batchId) {
this.getAggregatorResult();
}
});
this.events.subscribe('onAfterLanguageChange:update', (res) => {
if (res && res.selectedLanguage) {
this.selectedLanguage = res.selectedLanguage;
this.getAggregatorResult();
}
});
this.events.subscribe(EventTopics.COURSE_PAGE_ASSEMBLE_CHANNEL_CHANGE, () => {
this.ngZone.run(() => {
this.getAggregatorResult();
});
});
this.events.subscribe(EventTopics.TAB_CHANGE, (data: string) => {
this.ngZone.run(() => {
if (data.trim().toUpperCase() === 'COURSES') {
if (this.appliedFilter) {
this.filterIcon = './assets/imgs/ic_action_filter.png';
this.courseFilter = undefined;
this.appliedFilter = undefined;
this.isFilterApplied = false;
this.filter = undefined;
this.resetCourseFilter = true;
this.getAggregatorResult();
}
}
});
});
this.events.subscribe(EventTopics.REFRESH_ENROLL_COURSE_LIST, () => {
this.getAggregatorResult();
});
this.events.subscribe(EventTopics.SIGN_IN_RELOAD, async () => {
this.showSignInCard = false;
});
}
generateExtraInfoTelemetry(sectionsCount) {
const values = new Map();
values['pageSectionCount'] = sectionsCount;
values['networkAvailable'] = this.commonUtilService.networkInfo.isNetworkAvailable ? 'Y' : 'N';
this.telemetryGeneratorService.generateExtraInfoTelemetry(
values,
PageId.COURSES
);
}
/**
* To start / stop spinner
*/
spinner(flag: boolean) {
this.ngZone.run(() => {
this.showLoader = flag;
});
}
/**
* Get user id.
*
* Used to get enrolled course(s) of logged-in user
*/
getUserId() {
return new Promise((resolve, reject) => {
this.guestUser = !this.appGlobalService.isUserLoggedIn();
if (this.guestUser) {
this.getCurrentUser();
this.appGlobalService.setEnrolledCourseList([]);
reject('session expired');
} else {
const sessionObj = this.appGlobalService.getSessionData();
this.userId = sessionObj[ProfileConstants.USER_TOKEN];
resolve();
}
});
}
getCourseTabData(refresher?) {
setTimeout(() => {
if (refresher) {
refresher.target.complete();
this.telemetryGeneratorService.generatePullToRefreshTelemetry(PageId.COURSES, Environment.HOME);
}
}, 10);
this.enrolledCourses = [];
this.popularAndLatestCourses = [];
this.getUserId()
.then(() => {
this.getAggregatorResult();
})
.catch(() => {
this.getAggregatorResult();
});
}
/**
* It will fetch the guest user profile details
*/
private getCurrentUser(): void {
const profileType = this.appGlobalService.getGuestUserType();
this.showSignInCard = this.commonUtilService.isAccessibleForNonStudentRole(profileType);
}
async search() {
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.SEARCH_BUTTON_CLICKED,
Environment.HOME,
PageId.COURSES);
const primaryCategories = await this.formAndFrameworkUtilService.getSupportedContentFilterConfig(
ContentFilterConfig.NAME_COURSE);
this.router.navigate([RouterLinks.SEARCH], {
state: {
primaryCategories,
source: PageId.COURSES,
enrolledCourses: this.enrolledCourses,
guestUser: this.guestUser,
userId: this.userId,
searchWithBackButton: true
}
});
}
showFilter() {
if (this.isFilterOpen) {
return;
}
this.isFilterOpen = true;
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.FILTER_BUTTON_CLICKED,
Environment.HOME,
PageId.COURSES);
const that = this;
this.pageFilterCallBack = {
applyFilter(filter, appliedFilter, isChecked) {
that.ngZone.run(() => {
const criteria: PageAssembleCriteria = {
name: PageName.COURSE,
source: 'app'
};
criteria.filters = filter;
that.courseFilter = appliedFilter;
that.appliedFilter = filter;
let filterApplied = false;
that.isFilterApplied = false;
const values = new Map();
values['filters'] = filter;
that.telemetryGeneratorService.generateInteractTelemetry(
InteractType.OTHER,
InteractSubtype.APPLY_FILTER_CLICKED,
Environment.HOME,
PageId.COURSE_PAGE_FILTER,
undefined,
values
);
Object.keys(that.appliedFilter).forEach(key => {
if (that.appliedFilter[key].length > 0) {
filterApplied = true;
that.isFilterApplied = true;
}
});
if (filterApplied) {
that.filterIcon = './assets/imgs/ic_action_filter_applied.png';
} else {
that.filterIcon = './assets/imgs/ic_action_filter.png';
}
if (isChecked) {
that.filter = filter;
that.getAggregatorResult();
}
});
}
};
const filterOptions = {
callback: this.pageFilterCallBack,
pageId: PageId.COURSES
};
if (this.courseFilter) {
filterOptions['filter'] = this.courseFilter;
this.showFilterPage(filterOptions);
} else {
this.formAndFrameworkUtilService.getCourseFilterConfig().then((data) => {
if (this.resetCourseFilter) {
data = this.resetFilter(data);
this.resetCourseFilter = false;
}
filterOptions['filter'] = data;
this.showFilterPage(filterOptions);
}).catch(() => {
this.isFilterOpen = false;
});
}
}
resetFilter(data) {
for (let i = 0; data.length > i; i++) {
data[i].selected = [];
}
return data;
}
private async presentToastForOffline(msg: string) {
this.toast = await this.toastController.create({
duration: 3000,
message: this.commonUtilService.translateMessage(msg),
buttons: [],
position: 'top',
cssClass: 'toastHeader'
});
await this.toast.present();
this.toast.onDidDismiss().then(() => {
this.toast = undefined;
});
}
async showFilterPage(filterOptions) {
const backupFilter = this.appliedFilter ? JSON.parse(JSON.stringify(this.appliedFilter)) : this.appliedFilter;
const popup = await this.popCtrl.create({
component: PageFilterPage,
componentProps: {
callback: filterOptions.callback,
filter: filterOptions.filter,
pageId: PageId.COURSES,
reset: filterOptions.reset || false
},
cssClass: 'resource-filter'
});
await popup.present();
const { data } = await popup.onDidDismiss();
this.isFilterOpen = false;
if (!data || !data.apply) {
this.appliedFilter = backupFilter;
}
}
checkEmptySearchResult(isAfterLanguageChange = false) {
const flags = [];
forEach(this.popularAndLatestCourses, (value, key) => {
if (value.contents && value.contents.length) {
flags[key] = true;
}
});
if (flags.length && flags.includes(true)) {
} else {
if (!isAfterLanguageChange) {
if (this.commonUtilService.currentTabName === 'courses') {
this.commonUtilService.showToast('NO_CONTENTS_FOUND', this.isVisible);
}
}
}
}
showOfflineWarning() {
this.presentToastForOffline('NO_INTERNET_TITLE');
}
retryShowingPopularCourses(showRefresh = false) {
if (this.commonUtilService.networkInfo.isNetworkAvailable && showRefresh) {
this.getCourseTabData();
}
}
getContentDetails(content) {
const identifier = content.contentId || content.identifier;
this.corRelationList = [
{
id: content.batchId ? content.batchId : '',
type: CorReleationDataType.COURSE_BATCH
}
];
const request = {
contentId: identifier,
objectType: content.objectType,
emitUpdateIfAny: false
};
this.contentService.getContentDetails(request).toPromise()
.then((data: Content) => {
if (data && data.isAvailableLocally) {
if (data.contentData.pkgVersion < content.content.pkgVersion) {
this.contentDetailsImportCall(identifier);
} else {
this.showOverlay = false;
this.navigateToContentDetailsPage(content);
}
} else {
this.contentDetailsImportCall(identifier);
}
})
.catch((err) => {
if (NetworkError.isInstance(err)) {
this.commonUtilService.showToast('NO_INTERNET');
} else {
this.commonUtilService.showToast('ERROR_CONTENT_NOT_AVAILABLE');
}
});
}
private contentDetailsImportCall(identifier) {
this.subscribeSdkEvent();
this.showOverlay = true;
this.importContent([identifier], false);
}
navigateToViewMoreContentsPage(showEnrolledCourses: boolean, sectionId?: string, searchQuery?: any, headerTitle?: string) {
if (!this.commonUtilService.networkInfo.isNetworkAvailable) {
this.presentToastForOffline('NO_INTERNET_TITLE'); return;
}
let params: NavigationExtras;
let title;
if (showEnrolledCourses) {
title = this.commonUtilService.translateMessage('COURSES_IN_PROGRESS');
params = {
state: {
headerTitle: 'COURSES_IN_PROGRESS',
userId: this.userId,
pageName: ViewMore.PAGE_COURSE_ENROLLED,
sectionName: this.inProgressSection
}
};
} else {
searchQuery = updateFilterInSearchQuery(searchQuery, this.appliedFilter, this.isFilterApplied);
if (this.ssoSectionId && sectionId === this.ssoSectionId) {
searchQuery.request.filters['batches.createdFor'] = [this.frameworkService.activeChannelId];
}
title = headerTitle;
params = {
state: {
headerTitle,
pageName: ViewMore.PAGE_COURSE_POPULAR,
requestParams: searchQuery,
enrolledCourses: this.enrolledCourses,
guestUser: this.guestUser,
sectionName: headerTitle
}
};
}
const values = new Map();
values['SectionName'] = title;
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.VIEWALL_CLICKED,
Environment.HOME,
PageId.COURSES, undefined,
values);
this.router.navigate([RouterLinks.VIEW_MORE_ACTIVITY], params);
}
private navigateToContentDetailsPage(content) {
const identifier = content.contentId || content.identifier;
const extras: NavigationExtras = {
state: {
content: { identifier: content.lastReadContentId },
depth: '1',
contentState: {
batchId: content.batchId ? content.batchId : '',
courseId: identifier
},
isResumedCourse: true,
isChildContent: true,
resumedCourseCardData: content,
isCourse: true,
corRelation: this.corRelationList,
course: content
}
};
this.router.navigate([RouterLinks.CONTENT_DETAILS], extras);
}
private importContent(identifiers, isChild) {
const option: ContentImportRequest = {
contentImportArray: this.courseUtilService.getImportContentRequestBody(identifiers, isChild),
contentStatusArray: [],
fields: ['appIcon', 'name', 'subject', 'size', 'gradeLevel']
};
this.contentService.importContent(option).toPromise()
.then((data: ContentImportResponse[]) => {
this.ngZone.run(() => {
this.tabBarElement.style.display = 'none';
if (data && data.length) {
const importStatus = data[0];
if (importStatus.status !== ContentImportStatus.ENQUEUED_FOR_DOWNLOAD) {
this.removeOverlayAndShowError();
}
}
});
})
.catch(() => {
this.ngZone.run(() => {
this.removeOverlayAndShowError();
});
});
}
/**
* This method removes the loading/downloading overlay and displays the error message
* and also shows the bottom navigation bar
*/
private removeOverlayAndShowError(): any {
this.commonUtilService.showToast('COURSE_NOT_AVAILABLE');
this.tabBarElement.style.display = 'flex';
this.showOverlay = false;
}
private subscribeSdkEvent() {
this.eventSubscription = this.eventBusService.events().subscribe((event: EventsBusEvent) => {
this.ngZone.run(() => {
if (event.type === DownloadEventType.PROGRESS) {
const downloadEvent = event as DownloadProgress;
this.downloadPercentage = downloadEvent.payload.progress === -1 ? 0 : downloadEvent.payload.progress;
}
if (event.payload && event.type === ContentEventType.IMPORT_COMPLETED && this.downloadPercentage === 100) {
this.showOverlay = false;
this.navigateToContentDetailsPage(this.resumeContentData);
}
});
}) as any;
}
cancelDownload() {
this.ngZone.run(() => {
this.contentService.cancelDownload(this.resumeContentData.contentId ||
this.resumeContentData.identifier).toPromise()
.then(() => {
this.tabBarElement.style.display = 'flex';
this.showOverlay = false;
}).catch(() => {
this.tabBarElement.style.display = 'flex';
this.showOverlay = false;
});
});
}
handleHeaderEvents($event) {
switch ($event.name) {
case 'search':
this.search();
break;
case 'filter':
this.showFilter();
break;
case 'download':
this.redirectToActivedownloads();
break;
}
}
private redirectToActivedownloads() {
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.ACTIVE_DOWNLOADS_CLICKED,
Environment.HOME,
PageId.COURSES);
this.router.navigate([RouterLinks.ACTIVE_DOWNLOADS]);
}
openEnrolledCourseDetails(event) {
const params = {
env: 'home',
sectionName: this.inProgressSection,
pageName: 'course',
course: event.data,
guestUser: this.guestUser,
layoutName: this.layoutInProgress,
enrolledCourses: this.enrolledCourses
};
this.checkRetiredOpenBatch(params.course, params);
}
openCourseDetails(event, section, index) {
const params = {
env: 'home',
index,
sectionName: section.name,
pageName: 'course',
course: event.data,
guestUser: this.guestUser,
layoutName: this.layoutPopular,
enrolledCourses: this.enrolledCourses,
isFilterApplied: this.isFilterApplied
};
this.checkRetiredOpenBatch(params.course, params);
}
async checkRetiredOpenBatch(content: any, courseDetails) {
let anyRunningBatch = false;
let retiredBatches: Array<any> = [];
const enrolledCourses = courseDetails.enrolledCourses || [];
if (courseDetails.layoutName !== ContentCard.LAYOUT_INPROGRESS) {
retiredBatches = enrolledCourses.filter((element) => {
if (element.contentId === content.identifier && element.batch.status === 1 && element.cProgress !== 100) {
anyRunningBatch = true;
content.batch = element.batch;
}
if (element.contentId === content.identifier && element.batch.status === 2 && element.cProgress !== 100) {
return element;
}
});
}
if (anyRunningBatch || !retiredBatches.length) {
// open the batch directly
this.navigateToDetailPage(content, courseDetails);
} else if (retiredBatches.length) {
this.navigateToBatchListPopup(content, courseDetails, retiredBatches);
}
}
async navigateToBatchListPopup(content: any, courseDetails: any, retiredBatched?: any) {
const ongoingBatches = [];
const courseBatchesRequest: CourseBatchesRequest = {
filters: {
courseId: courseDetails.layoutName === ContentCard.LAYOUT_INPROGRESS ? content.contentId : content.identifier,
enrollmentType: CourseEnrollmentType.OPEN,
status: [CourseBatchStatus.IN_PROGRESS]
},
sort_by: { createdDate: SortOrder.DESC },
fields: BatchConstants.REQUIRED_FIELDS
};
const reqvalues = new Map();
reqvalues['enrollReq'] = courseBatchesRequest;
if (this.commonUtilService.networkInfo.isNetworkAvailable) {
if (!courseDetails.guestUser) {
this.courseService.getCourseBatches(courseBatchesRequest).toPromise()
.then((data: any) => {
this.ngZone.run(async () => {
const batches = data;
if (batches.length) {
batches.forEach((batch, key) => {
if (batch.status === 1) {
ongoingBatches.push(batch);
}
});
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
'showing-enrolled-ongoing-batch-popup',
Environment.HOME,
PageId.CONTENT_DETAIL, undefined,
reqvalues);
const popover = await this.popCtrl.create({
component: EnrollmentDetailsComponent,
componentProps: {
upcommingBatches: [],
ongoingBatches,
retiredBatched,
content
},
cssClass: 'enrollement-popover'
});
await popover.present();
} else {
this.navigateToDetailPage(content, courseDetails);
}
});
})
.catch((error: any) => {
console.log('error while fetching course batches ==>', error);
});
} else {
this.router.navigate([RouterLinks.COURSE_BATCHES]);
}
} else {
this.commonUtilService.showToast('ERROR_NO_INTERNET_MESSAGE');
}
}
/**
* Navigate to the course/content details page
*/
async navigateToDetailPage(content: any, courseDetails: any) {
const identifier = content.contentId || content.identifier;
let telemetryObject: TelemetryObject;
if (courseDetails.layoutName === ContentCard.LAYOUT_INPROGRESS) {
telemetryObject = new TelemetryObject(identifier, CsPrimaryCategory.COURSE, undefined);
} else {
telemetryObject = ContentUtil.getTelemetryObject(content);
}
const corRelationList: Array<CorrelationData> = [{
id: courseDetails.sectionName,
type: CorReleationDataType.SECTION
}, {
id: identifier || '',
type: CorReleationDataType.ROOT_ID
}];
if (courseDetails.isFilterApplied) {
corRelationList.push({
id: 'filter',
type: CorReleationDataType.DISCOVERY_TYPE
});
}
const values = new Map();
values['sectionName'] = courseDetails.sectionName;
values['positionClicked'] = courseDetails.index;
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.CONTENT_CLICKED,
courseDetails.env,
courseDetails.pageName ? courseDetails.pageName : courseDetails.layoutName,
telemetryObject,
values,
ContentUtil.generateRollUp(undefined, identifier),
this.commonUtilService.deDupe(corRelationList, 'type'));
if (courseDetails.layoutName === ContentCard.LAYOUT_INPROGRESS || ContentUtil.isTrackable(content) === 1) {
this.navService.navigateToTrackableCollection({
content,
isCourse: true,
corRelation: corRelationList
});
} else if (content.mimeType === MimeType.COLLECTION) {
this.navService.navigateToCollection({
content,
corRelation: corRelationList
});
} else {
this.navService.navigateToContent({
content,
isCourse: true,
corRelation: corRelationList
});
}
}
navigateToTextbookPage(items, subject) {
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.VIEW_MORE_CLICKED,
Environment.HOME,
PageId.LIBRARY,
ContentUtil.getTelemetryObject(items));
if (this.commonUtilService.networkInfo.isNetworkAvailable || items.isAvailableLocally) {
this.router.navigate([RouterLinks.TEXTBOOK_VIEW_MORE], {
state: {
contentList: items,
subjectName: subject
}
});
} else {
this.commonUtilService.presentToastForOffline('OFFLINE_WARNING_ETBUI');
}
}
async getAggregatorResult(resetFilter?: boolean) {
this.spinner(true);
this.profile = await this.profileService.getActiveSessionProfile({ requiredFields: ProfileConstants.REQUIRED_FIELDS }).toPromise();
const request: ContentAggregatorRequest = {
applyFirstAvailableCombination: {},
userPreferences: {
board: this.profile.board,
medium: this.profile.medium,
gradeLevel: this.profile.grade,
subject: this.profile.subject
},
interceptSearchCriteria: (contentSearchCriteria: ContentSearchCriteria) => {
if (this.filter) {
contentSearchCriteria = this.concatFilter(this.filter, contentSearchCriteria);
}
if (this.profile) {
if (this.profile.board && this.profile.board.length) {
contentSearchCriteria.board = applyProfileFilter(this.appGlobalService, this.profile.board,
contentSearchCriteria.board, 'board');
}
if (this.profile.medium && this.profile.medium.length) {
contentSearchCriteria.medium = applyProfileFilter(this.appGlobalService, this.profile.medium,
contentSearchCriteria.medium, 'medium');
}
if (this.profile.grade && this.profile.grade.length) {
contentSearchCriteria.grade = applyProfileFilter(this.appGlobalService, this.profile.grade,
contentSearchCriteria.grade, 'gradeLevel');
}
}
return contentSearchCriteria;
}
};
try {
this.dynamicCourses = await this.contentAggregatorHandler.newAggregate(request, AggregatorPageType.COURSE);
if (this.dynamicCourses) {
this.dynamicCourses = this.contentAggregatorHandler.populateIcons(this.dynamicCourses);
this.isGroupedCoursesAvailable(this.dynamicCourses);
}
this.spinner(false);
} catch (e) {
this.spinner(false);
}
}
concatFilter(filter, searchCriteria) {
if (filter.gradeLevel) {
filter.grade = filter.gradeLevel;
delete filter.gradeLevel;
}
return { ...filter, ...searchCriteria };
}
async exploreOtherContents() {
const syllabus: Array<string> = this.appGlobalService.getCurrentUser().syllabus;
const frameworkId = (syllabus && syllabus.length > 0) ? syllabus[0] : undefined;
const gradeLevelInfo = await this.getCategoryData(frameworkId, FrameworkCategoryCode.GRADE_LEVEL, this.profile.grade);
const mediumInfo = await this.getCategoryData(frameworkId, FrameworkCategoryCode.MEDIUM, this.profile.medium);
const subjectInfo = await this.getCategoryData(frameworkId, FrameworkCategoryCode.SUBJECT, this.profile.subject);
const navigationExtras = {
state: {
categoryGradeLevels: gradeLevelInfo['categoryList'],
primaryCategories: [CsPrimaryCategory.COURSE],
selectedGrade: gradeLevelInfo['selectedCategory'],
selectedMedium: mediumInfo['selectedCategory'],
subjects: [...subjectInfo['categoryList']]
}
};
this.router.navigate([RouterLinks.EXPLORE_BOOK], navigationExtras);
const corRelationList: Array<CorrelationData> = [];
corRelationList.push({ id: this.profile.board ? this.profile.board.join(',') : '', type: CorReleationDataType.BOARD });
corRelationList.push({
id: this.profile.grade && this.profile.grade.length ? this.profile.grade.join(',') : '',
type: CorReleationDataType.CLASS });
corRelationList.push({
id: this.profile.medium && this.profile.medium.length ? this.profile.medium.join(',') : '',
type: CorReleationDataType.MEDIUM });
}
async getCategoryData(frameworkId, categoryName, currentCategory): Promise<any> {
const req: GetFrameworkCategoryTermsRequest = {
currentCategoryCode: categoryName,
language: this.translate.currentLang,
requiredCategories: FrameworkCategoryCodesGroup.DEFAULT_FRAMEWORK_CATEGORIES,
frameworkId
};
const categoryMapList = await this.frameworkUtilService.getFrameworkCategoryTerms(req).toPromise();
const selectedCategory = ((categoryMapList || [])
.filter((category) => (currentCategory || []).includes(category.code)) || [])
.map((category) => category.name);
return {
selectedCategory,
categoryList: categoryMapList
};
}
isGroupedCoursesAvailable(displayItems) {
this.isCourseListEmpty = true;
for (let index = 0; index < displayItems.length; index++) {
if (displayItems[index] && displayItems[index].data && ((displayItems[index].data.length) ||
(displayItems[index].data.sections && displayItems[index].data.sections.length && displayItems[index].data.sections[0].contents && displayItems[index].data.sections[0].contents.length)
)) {
this.isCourseListEmpty = false;
break;
}
}
}
}
<ion-content hide-header-footer overflow-scroll="true"
class="main-container avoid-bottom-tabs-space" scrollEvents="true" [ngClass]="{'ui-container': !platform.is('ios')}">
<div class="ui-container" *ngIf="platform.is('ios')"></div>
<div class="ui-content">
<ion-refresher #courseRefresher slot="fixed" (ionRefresh)="getCourseTabData($event)">
<ion-refresher-content refreshingSpinner="circles"></ion-refresher-content>
</ion-refresher>
<div *ngIf="showSignInCard" class="enrolled-course-bg">
<app-sign-in-card [source]="'courses'" (valueChange)="showOfflineWarning($event)"></app-sign-in-card>
</div>
<div *ngIf="!guestUser" class="pt-8 enrolled-course-bg">
<ng-container *ngIf="showLoader && enrolledCourses && enrolledCourses.length === 0">
<sb-course-cards-hlist [type]="courseCardType.MY_COURSE_RECENTLY_VIEWED_CARD_GRID" [isLoading]="showLoader">
</sb-course-cards-hlist>
</ng-container>
</div>
<div *ngFor="let section of dynamicCourses">
<div *ngIf="!guestUser && section?.theme?.component === 'sb-course-cards-hlist'" class="pt-8 enrolled-course-bg">
<ng-container *ngIf="section?.theme?.component === 'sb-course-cards-hlist'">
<ng-container *ngFor="let subSection of section?.data?.sections">
<ng-container *ngIf="subSection?.contents?.length">
<sb-course-cards-hlist
[title]="(section?.title) | translateJson"
[type]="section?.theme?.inputs?.type || courseCardType.MY_COURSE_RECENTLY_VIEWED_CARD_GRID"
[contentList]="subSection.contents"
[hideProgress]="section?.theme?.inputs?.hideProgress || true"
[viewMoreButtonText]="(section?.theme?.inputs?.viewMoreButtonText | translateJson) || ('VIEW_ALL' | translate)"
[maxCardCount]="section?.theme?.inputs?.maxCardCount || 10"
(viewMoreClick)="navigateToViewMoreContentsPage(true)"
(cardClick)="openEnrolledCourseDetails($event)">
</sb-course-cards-hlist>
</ng-container>
</ng-container>
</ng-container>
</div>
<div *ngIf="section.theme.component === 'sb-library-cards-stack'">
<div class="section-header-style" role="heading" aria-level="2" *ngIf="section?.data.sections.length">{{section?.title | translateJson}}</div>
<div *ngFor="let section of section?.data.sections; let i=index">
<div *ngIf="section?.contents?.length" class="sb-textbook-container">
<sb-library-cards-stack [title]="section?.name" [contentList]="section?.contents"
[isOffline]="!commonUtilService.networkInfo.isNetworkAvailable"
[viewMoreButtonText]="'VIEW_MORE' | translate" [maxCardCount]="3"
(viewMoreClick)="navigateToTextbookPage(section?.contents, section.name)"
(cardClick)="openCourseDetails($event, section, i)" [isLoading]="showLoader">
</sb-library-cards-stack>
</div>
</div>
</div>
</div>
<ion-list class="m-n" *ngIf="showLoader && popularAndLatestCourses && popularAndLatestCourses.length === 0">
<app-skeleton-item height="16px" width="40%" style="padding: 16px;"></app-skeleton-item>
<ion-item *ngFor="let i of [0,1,2,3,4,5,6,7,8]" class="animation-background">
<ion-avatar item-start>
<app-skeleton-item height="72px" width="72px"></app-skeleton-item>
</ion-avatar>
<ion-label style="padding-left: 40px;">
<app-skeleton-item height="12px" width="67%" style="padding-bottom: 8px;"></app-skeleton-item>
<app-skeleton-item height="12px" width="47%" style="padding-bottom: 8px;"></app-skeleton-item>
</ion-label>
</ion-item>
</ion-list>
<div *ngIf="isCourseListEmpty" class="ion-text-center ion-padding">
<div class="sb-nodownloads-container" *ngIf="commonUtilService?.networkInfo?.isNetworkAvailable">
<div class="text-center">
<img style="width: 30%;" src="./assets/imgs/group.svg" alt="">
</div>
<div class="text-center">
<p class="sub-heading">{{'FRMELEMNTS_LBL_CONTENT_TO_BE_ADDED' | translate }}</p>
<ion-button class="explore-more-content" expand="block" fill="outline" (click)="exploreOtherContents()">
{{'FRMELEMENTS_LBL_SEE_MORE_COURSES' | translate}} </ion-button>
</div>
</div>
</div>
<div class="ion-text-center ion-padding" *ngIf="!commonUtilService?.networkInfo?.isNetworkAvailable">
<img height="80" width="100" src="assets/imgs/ic_offline.png" alt="offline" />
<ion-text>
<h6 color="secondary_black">
<strong>{{ 'NO_INTERNET_TITLE' | translate }}</strong>
</h6>
</ion-text>
<p color="dark_gray">{{ 'OFFLINE_WARNING' | translate }}</p>
<ion-text>
<strong class="ion-text-uppercase" color="primary"
(click)="retryShowingPopularCourses(true); showOfflineWarning();">{{'RETRY_ACTION' | translate}}</strong>
</ion-text>
</div>
</div>
</ion-content>
<ion-backdrop class="loading-backdrop ion-text-center" *ngIf="showOverlay">
<div class="backdrop-container">
<span *ngIf="downloadPercentage !== 100">
<ion-label>{{ 'LOADING_CONTENT' | translate }} {{ downloadPercentage ? (downloadPercentage) : '0' }} %</ion-label>
<app-pb-horizontal [progress]="downloadPercentage" isOnBoardCard="false"></app-pb-horizontal>
</span>
<ion-label *ngIf="downloadPercentage === 100">{{ 'LOADING_CONTENT' | translate }}</ion-label>
</div>
<div class="backdrop-footer" *ngIf="downloadPercentage !== 100">
<ion-button size="small" (click)="cancelDownload()">{{'CANCEL' | translate}}</ion-button>
</div>
</ion-backdrop>
./courses.page.scss
@import "src/assets/styles/base/_variables.scss";
@import "src/assets/styles/_custom-mixins.scss";
@import "src/assets/styles/fonts.scss";
@import "src/assets/styles/_variables.scss";
:host {
.loading-backdrop {
.backdrop-container {
width: 100%;
@include padding(16px !important);
text-align: center;
position: absolute;
top: 50%;
margin-top: -50px;
}
.backdrop-footer {
position: absolute;
width: 100%;
bottom: 0;
@include padding(null, null, 16px, null !important);
}
background-color: map-get($colors, white);
height: 100%;
z-index: 1000;
opacity: 1 !important;
}
.inner {
width: auto;
height: 100%;
course-card {
display: table-cell;
}
}
.sc-ion-buttons-md-s ion-button {
height: 0.813rem !important;
margin-bottom: 12px;
}
.inprogress-courses {
.bottom-container {
background: map-get($colors, gray_white);
}
}
.scroll-heading {
@include padding(10px, null, null, null);
@extend .NotoSans-bold;
@extend .font-weight-700;
font-size: 1.125rem;
padding-left:7px;
font-weight: 600 !important;
}
.view-all-link {
font-size: 0.75rem;
padding-top: 11px;
@extend .NotoSans-bold;
@extend .font-weight-700;
width: 15%;
float: right;
// @include text-align('end');
}
.course-scroll-holder {
background-color: map-get($colors, white_fe);
}
.toolbar-title-md {
margin-left: -5px !important;
@include margin(null, null, null, -5px !important);
}
.course-page-color {
background: map-get($colors, gray_white);
}
.padding-11 {
@include padding(11px);
overflow: hidden;
}
.height-130 {
height: 8.375rem;
}
.devider-line {
background: map-get($colors, gray_white);
height: 0.438rem;
}
ion-spinner {
display: block;
@include margin(auto);
}
ion-select {
max-width: 75%;
font-size: $font-size-base;
color: map-get($colors, vived_blue_ff);
@extend .font-weight-bold;
}
/* To give some space between the icons in the header */
.tool-icon {
@include margin(10px, 2px !important);
}
.offline-message {
background-color: red !important;
line-height: 2.5rem !important;
text-align: center !important;
color: white;
top: 0px;
position: sticky;
z-index: 11;
display: block;
width: 100%;
}
div[scrollx=true] {
overflow-x: auto;
overflow-y: hidden;
}
.enrolled-course-bg {
background: linear-gradient($green, $green 100px, white 100px, white 100%);
}
.course-grid-bg{
background-color: map-get($colors, pale_green_e0);
}
.course-card-pd{
padding: 1px 0 12px;
}
.section-header-style{
margin-left: 10px;
font-weight: 700;
font-size: 1rem;
padding-top: 14px;
padding-bottom: 4px;
}
.animation-background {
padding: 0 8px 0 8px;
background-color: map-get($colors, white_f2);
}
.sb-textbook-container{
padding: 0 8px !important;
}
}