MOBILE-3686 courses: Filter my courses and add download to categories
parent
ad45289f4b
commit
264309593f
|
@ -7,6 +7,16 @@
|
|||
<core-format-text [text]="title" contextLevel="coursecat" [contextInstanceId]="currentCategory && currentCategory!.id">
|
||||
</core-format-text>
|
||||
</h1>
|
||||
<ion-buttons slot="end">
|
||||
<core-context-menu>
|
||||
<core-context-menu-item *ngIf="downloadCourseEnabled || downloadCoursesEnabled" [priority]="1000"
|
||||
[content]="'core.settings.showdownloadoptions' | translate" (action)="toggleDownload(!downloadEnabled)"
|
||||
iconAction="toggle" [toggle]="downloadEnabled"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="myCoursesEnabled" [priority]="900"
|
||||
[content]="'core.courses.showonlyenrolled' | translate" (action)="toggleEnrolled(!showOnlyEnrolled)"
|
||||
iconAction="toggle" [toggle]="showOnlyEnrolled"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
|
@ -17,22 +27,18 @@
|
|||
<ion-item *ngIf="currentCategory" class="ion-text-wrap">
|
||||
<ion-icon name="fas-folder" slot="start" [attr.aria-label]="'core.category' | translate"></ion-icon>
|
||||
<ion-label>
|
||||
<h2>
|
||||
<core-format-text [text]="currentCategory!.name" contextLevel="coursecat"
|
||||
[contextInstanceId]="currentCategory!.id"></core-format-text>
|
||||
</h2>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item class="ion-text-wrap" *ngIf="currentCategory && currentCategory!.description">
|
||||
<ion-label>
|
||||
<h2>
|
||||
<core-format-text [text]="currentCategory!.description" maxHeight="60" contextLevel="coursecat"
|
||||
[contextInstanceId]="currentCategory!.id"></core-format-text>
|
||||
</h2>
|
||||
<p class="item-heading">
|
||||
<core-format-text [text]="currentCategory.name" contextLevel="coursecat"
|
||||
[contextInstanceId]="currentCategory.id"></core-format-text>
|
||||
</p>
|
||||
<p *ngIf="currentCategory.description">
|
||||
<core-format-text [text]="currentCategory.description" maxHeight="60" contextLevel="coursecat"
|
||||
[contextInstanceId]="currentCategory.id"></core-format-text>
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<div *ngIf="categories.length > 0">
|
||||
<ng-container *ngIf="categories.length > 0">
|
||||
<ion-item-divider>
|
||||
<ion-label>
|
||||
<h2>{{ 'core.courses.categories' | translate }}</h2>
|
||||
|
@ -48,22 +54,24 @@
|
|||
</core-format-text>
|
||||
</h2>
|
||||
</ion-label>
|
||||
<ion-badge slot="end" *ngIf="category.coursecount > 0" color="light">
|
||||
<ion-badge slot="end" *ngIf="!showOnlyEnrolled && category.coursecount > 0" color="light">
|
||||
<span aria-hidden="true">{{ category.coursecount }}</span>
|
||||
<span class="sr-only">{{ 'core.courses.therearecourses' | translate:{ $a: category.coursecount } }}</span>
|
||||
</ion-badge>
|
||||
</ion-item>
|
||||
</section>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div *ngIf="courses.length > 0">
|
||||
<ng-container *ngIf="courses.length > 0">
|
||||
<ion-item-divider>
|
||||
<ion-label>
|
||||
<h2>{{ 'core.courses.courses' | translate }}</h2>
|
||||
<h2 *ngIf="!showOnlyEnrolled">{{ 'core.courses.courses' | translate }}</h2>
|
||||
<h2 *ngIf="showOnlyEnrolled">{{ 'core.courses.mycourses' | translate }}</h2>
|
||||
</ion-label>
|
||||
</ion-item-divider>
|
||||
<core-courses-course-list-item *ngFor="let course of courses" [course]="course"></core-courses-course-list-item>
|
||||
</div>
|
||||
<core-courses-course-list-item *ngFor="let course of courses" [course]="course" [showDownload]="downloadEnabled">
|
||||
</core-courses-course-list-item>
|
||||
</ng-container>
|
||||
<core-empty-box *ngIf="!categories.length && !courses.length" icon="fas-graduation-cap"
|
||||
[message]="'core.courses.nocoursesyet' | translate">
|
||||
</core-empty-box>
|
||||
|
|
|
@ -12,14 +12,15 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { IonRefresher } from '@ionic/angular';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreCategoryData, CoreCourses, CoreCourseSearchedData } from '../../services/courses';
|
||||
import { CoreCategoryData, CoreCourseListItem, CoreCourses, CoreCoursesProvider } from '../../services/courses';
|
||||
import { Translate } from '@singletons';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
|
||||
/**
|
||||
* Page that displays a list of categories and the courses in the current category if any.
|
||||
|
@ -28,25 +29,64 @@ import { CoreNavigator } from '@services/navigator';
|
|||
selector: 'page-core-courses-categories',
|
||||
templateUrl: 'categories.html',
|
||||
})
|
||||
export class CoreCoursesCategoriesPage implements OnInit {
|
||||
export class CoreCoursesCategoriesPage implements OnInit, OnDestroy {
|
||||
|
||||
title: string;
|
||||
currentCategory?: CoreCategoryData;
|
||||
categories: CoreCategoryData[] = [];
|
||||
courses: CoreCourseSearchedData[] = [];
|
||||
courses: CoreCourseListItem[] = [];
|
||||
categoriesLoaded = false;
|
||||
myCoursesEnabled = true;
|
||||
|
||||
showOnlyEnrolled = false;
|
||||
|
||||
downloadEnabled = false;
|
||||
downloadCourseEnabled = false;
|
||||
downloadCoursesEnabled = false;
|
||||
|
||||
protected categoryCourses: CoreCourseListItem[] = [];
|
||||
protected currentSiteId: string;
|
||||
protected categoryId = 0;
|
||||
protected myCoursesObserver: CoreEventObserver;
|
||||
protected siteUpdatedObserver: CoreEventObserver;
|
||||
protected isDestroyed = false;
|
||||
|
||||
constructor() {
|
||||
this.title = Translate.instant('core.courses.categories');
|
||||
this.currentSiteId = CoreSites.getRequiredCurrentSite().getId();
|
||||
|
||||
// Update list if user enrols in a course.
|
||||
this.myCoursesObserver = CoreEvents.on(
|
||||
CoreCoursesProvider.EVENT_MY_COURSES_UPDATED,
|
||||
(data) => {
|
||||
if (data.action == CoreCoursesProvider.ACTION_ENROL) {
|
||||
this.fetchCategories();
|
||||
}
|
||||
},
|
||||
|
||||
this.currentSiteId,
|
||||
);
|
||||
|
||||
// Refresh the enabled flags if site is updated.
|
||||
this.siteUpdatedObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
|
||||
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
||||
this.downloadCoursesEnabled = !CoreCourses.isDownloadCoursesDisabledInSite();
|
||||
this.myCoursesEnabled = !CoreCourses.isMyCoursesDisabledInSite();
|
||||
|
||||
this.downloadEnabled = (this.downloadCourseEnabled || this.downloadCoursesEnabled) && this.downloadEnabled;
|
||||
}, this.currentSiteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* View loaded.
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.categoryId = CoreNavigator.getRouteNumberParam('id') || 0;
|
||||
this.showOnlyEnrolled = CoreNavigator.getRouteBooleanParam('enrolled') || this.showOnlyEnrolled;
|
||||
|
||||
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
||||
this.downloadCoursesEnabled = !CoreCourses.isDownloadCoursesDisabledInSite();
|
||||
this.myCoursesEnabled = !CoreCourses.isMyCoursesDisabledInSite();
|
||||
|
||||
this.fetchCategories().finally(() => {
|
||||
this.categoriesLoaded = true;
|
||||
|
@ -87,13 +127,14 @@ export class CoreCoursesCategoriesPage implements OnInit {
|
|||
this.title = this.currentCategory.name;
|
||||
|
||||
try {
|
||||
this.courses = await CoreCourses.getCoursesByField('category', this.categoryId);
|
||||
this.categoryCourses = await CoreCourses.getCoursesByField('category', this.categoryId);
|
||||
await this.toggleEnrolled(this.showOnlyEnrolled);
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'core.courses.errorloadcourses', true);
|
||||
!this.isDestroyed && CoreDomUtils.showErrorModalDefault(error, 'core.courses.errorloadcourses', true);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'core.courses.errorloadcategories', true);
|
||||
!this.isDestroyed && CoreDomUtils.showErrorModalDefault(error, 'core.courses.errorloadcategories', true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +149,7 @@ export class CoreCoursesCategoriesPage implements OnInit {
|
|||
promises.push(CoreCourses.invalidateUserCourses());
|
||||
promises.push(CoreCourses.invalidateCategories(this.categoryId, true));
|
||||
promises.push(CoreCourses.invalidateCoursesByField('category', this.categoryId));
|
||||
promises.push(CoreSites.getCurrentSite()!.invalidateConfig());
|
||||
promises.push(CoreSites.getRequiredCurrentSite().invalidateConfig());
|
||||
|
||||
Promise.all(promises).finally(() => {
|
||||
this.fetchCategories().finally(() => {
|
||||
|
@ -123,7 +164,56 @@ export class CoreCoursesCategoriesPage implements OnInit {
|
|||
* @param categoryId Category Id.
|
||||
*/
|
||||
openCategory(categoryId: number): void {
|
||||
CoreNavigator.navigateToSitePath('courses/categories/' + categoryId);
|
||||
CoreNavigator.navigateToSitePath(
|
||||
'courses/categories/' + categoryId,
|
||||
{ params: {
|
||||
enrolled: this.showOnlyEnrolled,
|
||||
} },
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle show only my courses.
|
||||
*
|
||||
* @param enable If enable or disable.
|
||||
*/
|
||||
async toggleEnrolled(enable: boolean): Promise<void> {
|
||||
this.showOnlyEnrolled = enable;
|
||||
|
||||
if (!this.showOnlyEnrolled) {
|
||||
this.courses = this.categoryCourses;
|
||||
} else {
|
||||
await Promise.all(this.categoryCourses.map(async (course) => {
|
||||
const isEnrolled = course.progress !== undefined;
|
||||
|
||||
if (!isEnrolled) {
|
||||
try {
|
||||
const userCourse = await CoreCourses.getUserCourse(course.id);
|
||||
course.progress = userCourse.progress;
|
||||
course.completionusertracked = userCourse.completionusertracked;
|
||||
} catch {
|
||||
// Ignore errors.
|
||||
}
|
||||
}
|
||||
}));
|
||||
this.courses = this.categoryCourses.filter((course) => 'progress' in course);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle download enabled.
|
||||
*/
|
||||
toggleDownload(enabled: boolean): void {
|
||||
this.downloadEnabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.myCoursesObserver?.off();
|
||||
this.siteUpdatedObserver?.off();
|
||||
this.isDestroyed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue