From 0d66e66fddb18b737fc3f48357962741558774bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Fri, 20 Nov 2020 12:03:44 +0100 Subject: [PATCH] MOBILE-3594 sitehome: Course listing components of sitehome --- .../courses/components/components.module.ts | 44 +++++++ .../core-courses-course-list-item.html | 14 ++ .../course-list-item/course-list-item.ts | 105 +++++++++++++++ src/core/features/courses/courses.module.ts | 49 ++++++- .../available-courses/available-courses.html | 19 +++ .../available-courses.page.module.ts | 50 +++++++ .../available-courses.page.ts | 78 +++++++++++ .../courses/pages/categories/categories.html | 67 ++++++++++ .../categories/categories.page.module.ts | 50 +++++++ .../pages/categories/categories.page.ts | 123 ++++++++++++++++++ .../features/courses/pages/search/search.html | 24 ++++ .../pages/search/search.page.module.ts | 52 ++++++++ .../courses/pages/search/search.page.ts | 100 ++++++++++++++ .../features/sitehome/pages/index/index.html | 4 +- 14 files changed, 774 insertions(+), 5 deletions(-) create mode 100644 src/core/features/courses/components/components.module.ts create mode 100644 src/core/features/courses/components/course-list-item/core-courses-course-list-item.html create mode 100644 src/core/features/courses/components/course-list-item/course-list-item.ts create mode 100644 src/core/features/courses/pages/available-courses/available-courses.html create mode 100644 src/core/features/courses/pages/available-courses/available-courses.page.module.ts create mode 100644 src/core/features/courses/pages/available-courses/available-courses.page.ts create mode 100644 src/core/features/courses/pages/categories/categories.html create mode 100644 src/core/features/courses/pages/categories/categories.page.module.ts create mode 100644 src/core/features/courses/pages/categories/categories.page.ts create mode 100644 src/core/features/courses/pages/search/search.html create mode 100644 src/core/features/courses/pages/search/search.page.module.ts create mode 100644 src/core/features/courses/pages/search/search.page.ts diff --git a/src/core/features/courses/components/components.module.ts b/src/core/features/courses/components/components.module.ts new file mode 100644 index 000000000..513b7aee1 --- /dev/null +++ b/src/core/features/courses/components/components.module.ts @@ -0,0 +1,44 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { IonicModule } from '@ionic/angular'; +import { TranslateModule } from '@ngx-translate/core'; + +import { CoreComponentsModule } from '@components/components.module'; +import { CoreDirectivesModule } from '@directives/directives.module'; +import { CorePipesModule } from '@pipes/pipes.module'; + +import { CoreCoursesCourseListItemComponent } from './course-list-item/course-list-item'; + +@NgModule({ + declarations: [ + CoreCoursesCourseListItemComponent, + ], + imports: [ + CommonModule, + IonicModule, + TranslateModule.forChild(), + CoreComponentsModule, + CoreDirectivesModule, + CorePipesModule, + ], + providers: [ + ], + exports: [ + CoreCoursesCourseListItemComponent, + ], +}) +export class CoreCoursesComponentsModule {} diff --git a/src/core/features/courses/components/course-list-item/core-courses-course-list-item.html b/src/core/features/courses/components/course-list-item/core-courses-course-list-item.html new file mode 100644 index 000000000..1495e6d9f --- /dev/null +++ b/src/core/features/courses/components/course-list-item/core-courses-course-list-item.html @@ -0,0 +1,14 @@ + + + +

+ + +

+
+ + + +
diff --git a/src/core/features/courses/components/course-list-item/course-list-item.ts b/src/core/features/courses/components/course-list-item/course-list-item.ts new file mode 100644 index 000000000..3faa41bce --- /dev/null +++ b/src/core/features/courses/components/course-list-item/course-list-item.ts @@ -0,0 +1,105 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, Input, OnInit } from '@angular/core'; +import { NavController } from '@ionic/angular'; +import { CoreCourseHelper } from '@features/course/services/course.helper'; +import { CoreCourses, CoreCourseSearchedData } from '@features/courses/services/courses'; + +/** + * This directive is meant to display an item for a list of courses. + * + * Example usage: + * + * + */ +@Component({ + selector: 'core-courses-course-list-item', + templateUrl: 'core-courses-course-list-item.html', +}) +export class CoreCoursesCourseListItemComponent implements OnInit { + + @Input() course!: CoreCourseSearchedData; // The course to render. + + icons: CoreCoursesEnrolmentIcons[] = []; + isEnrolled = false; + + constructor( + protected navCtrl: NavController, + ) { + } + + /** + * Component being initialized. + */ + async ngOnInit(): Promise { + // Check if the user is enrolled in the course. + try { + await CoreCourses.instance.getUserCourse(this.course.id); + + this.isEnrolled = true; + } catch { + this.isEnrolled = false; + this.icons = []; + + this.course.enrollmentmethods.forEach((instance) => { + if (instance === 'self') { + this.icons.push({ + label: 'core.courses.selfenrolment', + icon: 'fas-key', + }); + } else if (instance === 'guest') { + this.icons.push({ + label: 'core.courses.allowguests', + icon: 'fas-unlock', + }); + } else if (instance === 'paypal') { + this.icons.push({ + label: 'core.courses.paypalaccepted', + icon: 'fab-paypal', + }); + } + }); + + if (this.icons.length == 0) { + this.icons.push({ + label: 'core.courses.notenrollable', + icon: 'fas-lock', + }); + } + } + } + + /** + * Open a course. + * + * @param course The course to open. + */ + openCourse(): void { + if (this.isEnrolled) { + CoreCourseHelper.instance.openCourse(this.course); + } else { + this.navCtrl.navigateForward('/courses/preview', { queryParams: { course: this.course } }); + } + } + +} + +/** + * Enrolment icons to show on the list with a label. + */ +export type CoreCoursesEnrolmentIcons = { + label: string; + icon: string; +}; diff --git a/src/core/features/courses/courses.module.ts b/src/core/features/courses/courses.module.ts index 570eb5569..b1a4e1cac 100644 --- a/src/core/features/courses/courses.module.ts +++ b/src/core/features/courses/courses.module.ts @@ -13,12 +13,12 @@ // limitations under the License. import { NgModule } from '@angular/core'; -import { Routes } from '@angular/router'; +import { RouterModule, Routes } from '@angular/router'; import { CoreHomeRoutingModule } from '../mainmenu/pages/home/home-routing.module'; import { CoreHomeDelegate } from '../mainmenu/services/home.delegate'; import { CoreDashboardHomeHandler } from './services/handlers/dashboard.home'; -const routes: Routes = [ +const homeRoutes: Routes = [ { path: 'dashboard', loadChildren: () => @@ -26,9 +26,50 @@ const routes: Routes = [ }, ]; +const routes: Routes = [ + { + path: 'courses', + children: [ + { + path: '', + redirectTo: 'all', + pathMatch: 'full', + }, + { + path: 'categories', + redirectTo: 'categories/root', // Fake "id". + pathMatch: 'full', + }, + { + path: 'categories/:id', + loadChildren: () => + import('@features/courses/pages/categories/categories.page.module').then(m => m.CoreCoursesCategoriesPageModule), + }, + { + path: 'all', + loadChildren: () => + import('@features/courses/pages/available-courses/available-courses.page.module') + .then(m => m.CoreCoursesAvailableCoursesPageModule), + }, + { + path: 'search', + loadChildren: () => + import('@features/courses/pages/search/search.page.module') + .then(m => m.CoreCoursesSearchPageModule), + }, + ], + }, +]; + @NgModule({ - imports: [CoreHomeRoutingModule.forChild(routes)], - exports: [CoreHomeRoutingModule], + imports: [ + CoreHomeRoutingModule.forChild(homeRoutes), + RouterModule.forChild(routes), + ], + exports: [ + CoreHomeRoutingModule, + RouterModule, + ], providers: [ CoreDashboardHomeHandler, ], diff --git a/src/core/features/courses/pages/available-courses/available-courses.html b/src/core/features/courses/pages/available-courses/available-courses.html new file mode 100644 index 000000000..eafff0704 --- /dev/null +++ b/src/core/features/courses/pages/available-courses/available-courses.html @@ -0,0 +1,19 @@ + + + + + + {{ 'core.courses.availablecourses' | translate }} + + + + + + + + + + + + + diff --git a/src/core/features/courses/pages/available-courses/available-courses.page.module.ts b/src/core/features/courses/pages/available-courses/available-courses.page.module.ts new file mode 100644 index 000000000..ef135f506 --- /dev/null +++ b/src/core/features/courses/pages/available-courses/available-courses.page.module.ts @@ -0,0 +1,50 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterModule, Routes } from '@angular/router'; +import { IonicModule } from '@ionic/angular'; +import { TranslateModule } from '@ngx-translate/core'; + +import { CoreComponentsModule } from '@components/components.module'; +import { CoreDirectivesModule } from '@directives/directives.module'; +import { CoreCoursesComponentsModule } from '../../components/components.module'; + +import { CoreCoursesAvailableCoursesPage } from './available-courses.page'; + + +const routes: Routes = [ + { + path: '', + component: CoreCoursesAvailableCoursesPage, + }, +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes), + CommonModule, + IonicModule, + TranslateModule.forChild(), + CoreComponentsModule, + CoreDirectivesModule, + CoreCoursesComponentsModule, + ], + declarations: [ + CoreCoursesAvailableCoursesPage, + ], + exports: [RouterModule], +}) +export class CoreCoursesAvailableCoursesPageModule { } diff --git a/src/core/features/courses/pages/available-courses/available-courses.page.ts b/src/core/features/courses/pages/available-courses/available-courses.page.ts new file mode 100644 index 000000000..d979dbd41 --- /dev/null +++ b/src/core/features/courses/pages/available-courses/available-courses.page.ts @@ -0,0 +1,78 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; +import { IonRefresher } from '@ionic/angular'; + +import { CoreSites } from '@services/sites'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreCourses, CoreCourseSearchedData } from '../../services/courses'; + +/** + * Page that displays available courses in current site. + */ +@Component({ + selector: 'page-core-courses-available-courses', + templateUrl: 'available-courses.html', +}) +export class CoreCoursesAvailableCoursesPage implements OnInit { + + courses: CoreCourseSearchedData[] = []; + coursesLoaded = false; + + /** + * View loaded. + */ + ngOnInit(): void { + this.loadCourses().finally(() => { + this.coursesLoaded = true; + }); + } + + /** + * Load the courses. + * + * @return Promise resolved when done. + */ + protected async loadCourses(): Promise { + const frontpageCourseId = CoreSites.instance.getCurrentSite()!.getSiteHomeId(); + + try { + const courses = await CoreCourses.instance.getCoursesByField(); + + this.courses = courses.filter((course) => course.id != frontpageCourseId); + } catch (error) { + CoreDomUtils.instance.showErrorModalDefault(error, 'core.courses.errorloadcourses', true); + } + } + + /** + * Refresh the courses. + * + * @param refresher Refresher. + */ + refreshCourses(refresher: CustomEvent): void { + const promises: Promise[] = []; + + promises.push(CoreCourses.instance.invalidateUserCourses()); + promises.push(CoreCourses.instance.invalidateCoursesByField()); + + Promise.all(promises).finally(() => { + this.loadCourses().finally(() => { + refresher?.detail.complete(); + }); + }); + } + +} diff --git a/src/core/features/courses/pages/categories/categories.html b/src/core/features/courses/pages/categories/categories.html new file mode 100644 index 000000000..7af0a9e5b --- /dev/null +++ b/src/core/features/courses/pages/categories/categories.html @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + +

+ +

+
+
+ + +

+ +

+
+
+ +
+ + +

{{ 'core.courses.categories' | translate }}

+
+
+
+ + + +

+ + +

+
+ {{category.coursecount}} +
+
+
+ +
+ + +

{{ 'core.courses.courses' | translate }}

+
+
+ +
+ + +
+
diff --git a/src/core/features/courses/pages/categories/categories.page.module.ts b/src/core/features/courses/pages/categories/categories.page.module.ts new file mode 100644 index 000000000..2266c2d4d --- /dev/null +++ b/src/core/features/courses/pages/categories/categories.page.module.ts @@ -0,0 +1,50 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterModule, Routes } from '@angular/router'; +import { IonicModule } from '@ionic/angular'; +import { TranslateModule } from '@ngx-translate/core'; + +import { CoreComponentsModule } from '@components/components.module'; +import { CoreDirectivesModule } from '@directives/directives.module'; +import { CoreCoursesComponentsModule } from '../../components/components.module'; + +import { CoreCoursesCategoriesPage } from './categories.page'; + + +const routes: Routes = [ + { + path: '', + component: CoreCoursesCategoriesPage, + }, +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes), + CommonModule, + IonicModule, + TranslateModule.forChild(), + CoreComponentsModule, + CoreDirectivesModule, + CoreCoursesComponentsModule, + ], + declarations: [ + CoreCoursesCategoriesPage, + ], + exports: [RouterModule], +}) +export class CoreCoursesCategoriesPageModule { } diff --git a/src/core/features/courses/pages/categories/categories.page.ts b/src/core/features/courses/pages/categories/categories.page.ts new file mode 100644 index 000000000..1980fcdf4 --- /dev/null +++ b/src/core/features/courses/pages/categories/categories.page.ts @@ -0,0 +1,123 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; +import { IonRefresher, NavController } 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 { Translate } from '@singletons/core.singletons'; +import { ActivatedRoute } from '@angular/router'; + +/** + * Page that displays a list of categories and the courses in the current category if any. + */ +@Component({ + selector: 'page-core-courses-categories', + templateUrl: 'categories.html', +}) +export class CoreCoursesCategoriesPage implements OnInit { + + title: string; + currentCategory?: CoreCategoryData; + categories: CoreCategoryData[] = []; + courses: CoreCourseSearchedData[] = []; + categoriesLoaded = false; + + protected categoryId = 0; + + constructor( + protected navCtrl: NavController, + protected route: ActivatedRoute, + ) { + this.title = Translate.instance.instant('core.courses.categories'); + } + + /** + * View loaded. + */ + ngOnInit(): void { + this.categoryId = parseInt(this.route.snapshot.params['id'], 0) || 0; + + this.fetchCategories().finally(() => { + this.categoriesLoaded = true; + }); + } + + /** + * Fetch the categories. + * + * @return Promise resolved when done. + */ + protected async fetchCategories(): Promise { + try{ + const categories: CoreCategoryData[] = await CoreCourses.instance.getCategories(this.categoryId, true); + + this.currentCategory = undefined; + + const index = categories.findIndex((category) => category.id == this.categoryId); + + if (index >= 0) { + this.currentCategory = categories[index]; + // Delete current Category to avoid problems with the formatTree. + delete categories[index]; + } + + // Sort by depth and sortorder to avoid problems formatting Tree. + categories.sort((a, b) => { + if (a.depth == b.depth) { + return (a.sortorder > b.sortorder) ? 1 : ((b.sortorder > a.sortorder) ? -1 : 0); + } + + return a.depth > b.depth ? 1 : -1; + }); + + this.categories = CoreUtils.instance.formatTree(categories, 'parent', 'id', this.categoryId); + + if (this.currentCategory) { + this.title = this.currentCategory.name; + + try { + this.courses = await CoreCourses.instance.getCoursesByField('category', this.categoryId); + } catch (error) { + CoreDomUtils.instance.showErrorModalDefault(error, 'core.courses.errorloadcourses', true); + } + } + } catch (error) { + CoreDomUtils.instance.showErrorModalDefault(error, 'core.courses.errorloadcategories', true); + } + } + + /** + * Refresh the categories. + * + * @param refresher Refresher. + */ + refreshCategories(refresher?: CustomEvent): void { + const promises: Promise[] = []; + + promises.push(CoreCourses.instance.invalidateUserCourses()); + promises.push(CoreCourses.instance.invalidateCategories(this.categoryId, true)); + promises.push(CoreCourses.instance.invalidateCoursesByField('category', this.categoryId)); + promises.push(CoreSites.instance.getCurrentSite()!.invalidateConfig()); + + Promise.all(promises).finally(() => { + this.fetchCategories().finally(() => { + refresher?.detail.complete(); + }); + }); + } + +} diff --git a/src/core/features/courses/pages/search/search.html b/src/core/features/courses/pages/search/search.html new file mode 100644 index 000000000..a67c4bb35 --- /dev/null +++ b/src/core/features/courses/pages/search/search.html @@ -0,0 +1,24 @@ + + + + + + {{ 'core.courses.searchcourses' | translate }} + + + + + + + +

{{ 'core.courses.totalcoursesearchresults' | translate:{$a: total} }}

+
+ + + +
+ +
+ diff --git a/src/core/features/courses/pages/search/search.page.module.ts b/src/core/features/courses/pages/search/search.page.module.ts new file mode 100644 index 000000000..a24a9bb09 --- /dev/null +++ b/src/core/features/courses/pages/search/search.page.module.ts @@ -0,0 +1,52 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterModule, Routes } from '@angular/router'; +import { IonicModule } from '@ionic/angular'; +import { TranslateModule } from '@ngx-translate/core'; + +import { CoreComponentsModule } from '@components/components.module'; +import { CoreDirectivesModule } from '@directives/directives.module'; +import { CoreCoursesComponentsModule } from '../../components/components.module'; +import { CoreSearchComponentsModule } from '@features/search/components/components.module'; + +import { CoreCoursesSearchPage } from './search.page'; + +const routes: Routes = [ + { + path: '', + component: CoreCoursesSearchPage, + }, +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes), + CommonModule, + IonicModule, + TranslateModule.forChild(), + CoreComponentsModule, + CoreDirectivesModule, + CoreCoursesComponentsModule, + CoreSearchComponentsModule, + ], + declarations: [ + CoreCoursesSearchPage, + ], + exports: [RouterModule], +}) +export class CoreCoursesSearchPageModule { } + diff --git a/src/core/features/courses/pages/search/search.page.ts b/src/core/features/courses/pages/search/search.page.ts new file mode 100644 index 000000000..57c04555e --- /dev/null +++ b/src/core/features/courses/pages/search/search.page.ts @@ -0,0 +1,100 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component } from '@angular/core'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreCourseBasicSearchedData, CoreCourses } from '../../services/courses'; + +/** + * Page that allows searching for courses. + */ +@Component({ + selector: 'page-core-courses-search', + templateUrl: 'search.html', +}) +export class CoreCoursesSearchPage { + + total = 0; + courses: CoreCourseBasicSearchedData[] = []; + canLoadMore = false; + loadMoreError = false; + + protected page = 0; + protected currentSearch = ''; + + /** + * Search a new text. + * + * @param text The text to search. + */ + async search(text: string): Promise { + this.currentSearch = text; + this.courses = []; + this.page = 0; + this.total = 0; + + const modal = await CoreDomUtils.instance.showModalLoading('core.searching', true); + this.searchCourses().finally(() => { + modal.dismiss(); + }); + } + + /** + * Clear search box. + */ + clearSearch(): void { + this.currentSearch = ''; + this.courses = []; + this.page = 0; + this.total = 0; + } + + /** + * Load more results. + * + * @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading. + */ + loadMoreResults(infiniteComplete?: () => void ): void { + this.searchCourses().finally(() => { + infiniteComplete && infiniteComplete(); + }); + } + + /** + * Search courses or load the next page of current search. + * + * @return Promise resolved when done. + */ + protected async searchCourses(): Promise { + this.loadMoreError = false; + + try { + const response = await CoreCourses.instance.search(this.currentSearch, this.page); + + if (this.page === 0) { + this.courses = response.courses; + } else { + this.courses = this.courses.concat(response.courses); + } + this.total = response.total; + + this.page++; + this.canLoadMore = this.courses.length < this.total; + } catch (error) { + this.loadMoreError = true; // Set to prevent infinite calls with infinite-loading. + CoreDomUtils.instance.showErrorModalDefault(error, 'core.courses.errorsearching', true); + } + } + +} diff --git a/src/core/features/sitehome/pages/index/index.html b/src/core/features/sitehome/pages/index/index.html index f4492cf3b..fff613a26 100644 --- a/src/core/features/sitehome/pages/index/index.html +++ b/src/core/features/sitehome/pages/index/index.html @@ -39,7 +39,9 @@ - + + +