@@ -17,22 +27,18 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
- 0">
+ 0">
{{ 'core.courses.categories' | translate }}
@@ -48,22 +54,24 @@
- 0" color="light">
+ 0" color="light">
{{ category.coursecount }}
{{ 'core.courses.therearecourses' | translate:{ $a: category.coursecount } }}
-
+
- 0">
+ 0">
- {{ 'core.courses.courses' | translate }}
+ {{ 'core.courses.courses' | translate }}
+ {{ 'core.courses.mycourses' | translate }}
-
-
+
+
+
diff --git a/src/core/features/courses/pages/categories/categories.ts b/src/core/features/courses/pages/categories/categories.ts
index df71c1c88..d3de228a0 100644
--- a/src/core/features/courses/pages/categories/categories.ts
+++ b/src/core/features/courses/pages/categories/categories.ts
@@ -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 {
+ 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;
}
}