MOBILE-3686 courses: Merge available courses and search courses pages
This commit is contained in:
		
							parent
							
								
									55b6d9f76a
								
							
						
					
					
						commit
						5ac62106bf
					
				@ -33,16 +33,10 @@ const routes: Routes = [
 | 
			
		||||
                .then(m => m.CoreCoursesCategoriesPageModule),
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        path: 'all',
 | 
			
		||||
        path: 'list',
 | 
			
		||||
        loadChildren: () =>
 | 
			
		||||
            import('./pages/available-courses/available-courses.module')
 | 
			
		||||
                .then(m => m.CoreCoursesAvailableCoursesPageModule),
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        path: 'search',
 | 
			
		||||
        loadChildren: () =>
 | 
			
		||||
            import('./pages/search/search.module')
 | 
			
		||||
                .then(m => m.CoreCoursesSearchPageModule),
 | 
			
		||||
            import('./pages/list/list.module')
 | 
			
		||||
                .then(m => m.CoreCoursesListPageModule),
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        path: 'my',
 | 
			
		||||
 | 
			
		||||
@ -1,19 +0,0 @@
 | 
			
		||||
<ion-header>
 | 
			
		||||
    <ion-toolbar>
 | 
			
		||||
        <ion-buttons slot="start">
 | 
			
		||||
            <ion-back-button [text]="'core.back' | translate"></ion-back-button>
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
        <h1>{{ 'core.courses.availablecourses' | translate }}</h1>
 | 
			
		||||
    </ion-toolbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <ion-refresher slot="fixed" [disabled]="!coursesLoaded" (ionRefresh)="refreshCourses($event.target)">
 | 
			
		||||
        <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
			
		||||
    </ion-refresher>
 | 
			
		||||
    <core-loading [hideUntil]="coursesLoaded">
 | 
			
		||||
        <ng-container *ngIf="courses.length > 0">
 | 
			
		||||
            <core-courses-course-list-item *ngFor="let course of courses" [course]="course"></core-courses-course-list-item>
 | 
			
		||||
        </ng-container>
 | 
			
		||||
        <core-empty-box *ngIf="!courses.length" icon="fas-graduation-cap" [message]="'core.courses.nocourses' | translate"></core-empty-box>
 | 
			
		||||
    </core-loading>
 | 
			
		||||
</ion-content>
 | 
			
		||||
@ -1,41 +0,0 @@
 | 
			
		||||
// (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 { RouterModule, Routes } from '@angular/router';
 | 
			
		||||
 | 
			
		||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
			
		||||
import { CoreCoursesComponentsModule } from '../../components/components.module';
 | 
			
		||||
 | 
			
		||||
import { CoreCoursesAvailableCoursesPage } from './available-courses';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
    {
 | 
			
		||||
        path: '',
 | 
			
		||||
        component: CoreCoursesAvailableCoursesPage,
 | 
			
		||||
    },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    imports: [
 | 
			
		||||
        RouterModule.forChild(routes),
 | 
			
		||||
        CoreSharedModule,
 | 
			
		||||
        CoreCoursesComponentsModule,
 | 
			
		||||
    ],
 | 
			
		||||
    declarations: [
 | 
			
		||||
        CoreCoursesAvailableCoursesPage,
 | 
			
		||||
    ],
 | 
			
		||||
    exports: [RouterModule],
 | 
			
		||||
})
 | 
			
		||||
export class CoreCoursesAvailableCoursesPageModule { }
 | 
			
		||||
@ -1,78 +0,0 @@
 | 
			
		||||
// (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<void> {
 | 
			
		||||
        const frontpageCourseId = CoreSites.getCurrentSiteHomeId();
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const courses = await CoreCourses.getCoursesByField();
 | 
			
		||||
 | 
			
		||||
            this.courses = courses.filter((course) => course.id != frontpageCourseId);
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            CoreDomUtils.showErrorModalDefault(error, 'core.courses.errorloadcourses', true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Refresh the courses.
 | 
			
		||||
     *
 | 
			
		||||
     * @param refresher Refresher.
 | 
			
		||||
     */
 | 
			
		||||
    refreshCourses(refresher: IonRefresher): void {
 | 
			
		||||
        const promises: Promise<void>[] = [];
 | 
			
		||||
 | 
			
		||||
        promises.push(CoreCourses.invalidateUserCourses());
 | 
			
		||||
        promises.push(CoreCourses.invalidateCoursesByField());
 | 
			
		||||
 | 
			
		||||
        Promise.all(promises).finally(() => {
 | 
			
		||||
            this.loadCourses().finally(() => {
 | 
			
		||||
                refresher?.complete();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -167,7 +167,7 @@ export class CoreCoursesDashboardPage implements OnInit, OnDestroy {
 | 
			
		||||
     * Go to search courses.
 | 
			
		||||
     */
 | 
			
		||||
    async openSearch(): Promise<void> {
 | 
			
		||||
        CoreNavigator.navigateToSitePath('/courses/search');
 | 
			
		||||
        CoreNavigator.navigateToSitePath('/courses/list', { params : { mode: 'search' } });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										36
									
								
								src/core/features/courses/pages/list/list.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/core/features/courses/pages/list/list.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
<ion-header>
 | 
			
		||||
    <ion-toolbar>
 | 
			
		||||
        <ion-buttons slot="start">
 | 
			
		||||
            <ion-back-button [text]="'core.back' | translate"></ion-back-button>
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
        <h1>{{ 'core.courses.availablecourses' | translate }}</h1>
 | 
			
		||||
    </ion-toolbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <ion-refresher slot="fixed" [disabled]="!coursesLoaded" (ionRefresh)="refreshCourses($event.target)">
 | 
			
		||||
        <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
			
		||||
    </ion-refresher>
 | 
			
		||||
    
 | 
			
		||||
    <core-search-box *ngIf="searchEnabled" (onSubmit)="search($event)" (onClear)="clearSearch()"
 | 
			
		||||
        [placeholder]="'core.courses.search' | translate" [searchLabel]="'core.courses.search' | translate" [autoFocus]="searchMode"
 | 
			
		||||
        searchArea="CoreCoursesSearch"></core-search-box>
 | 
			
		||||
 | 
			
		||||
    <core-loading [hideUntil]="coursesLoaded">
 | 
			
		||||
        <ng-container *ngIf="searchMode && searchTotal > 0">
 | 
			
		||||
            <ion-item-divider>
 | 
			
		||||
                <ion-label><h2>{{ 'core.courses.totalcoursesearchresults' | translate:{$a: searchTotal} }}</h2></ion-label>
 | 
			
		||||
            </ion-item-divider>
 | 
			
		||||
        </ng-container>
 | 
			
		||||
        
 | 
			
		||||
        <core-courses-course-list-item *ngFor="let course of courses" [course]="course"></core-courses-course-list-item>
 | 
			
		||||
 | 
			
		||||
        <core-infinite-loading [enabled]="searchMode && searchCanLoadMore" (action)="loadMoreResults($event)" [error]="searchLoadMoreError">
 | 
			
		||||
        </core-infinite-loading>
 | 
			
		||||
        <core-empty-box *ngIf="searchMode && !courses.length" icon="fas-search" [message]="'core.courses.nosearchresults' | translate">
 | 
			
		||||
        </core-empty-box>
 | 
			
		||||
 | 
			
		||||
        <core-empty-box *ngIf="!searchMode && !courses.length" icon="fas-graduation-cap" [message]="'core.courses.nocourses' | translate">
 | 
			
		||||
        </core-empty-box>
 | 
			
		||||
        
 | 
			
		||||
    </core-loading>
 | 
			
		||||
</ion-content>
 | 
			
		||||
@ -19,12 +19,12 @@ import { CoreSharedModule } from '@/core/shared.module';
 | 
			
		||||
import { CoreCoursesComponentsModule } from '../../components/components.module';
 | 
			
		||||
import { CoreSearchComponentsModule } from '@features/search/components/components.module';
 | 
			
		||||
 | 
			
		||||
import { CoreCoursesSearchPage } from './search';
 | 
			
		||||
import { CoreCoursesListPage } from './list';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
    {
 | 
			
		||||
        path: '',
 | 
			
		||||
        component: CoreCoursesSearchPage,
 | 
			
		||||
        component: CoreCoursesListPage,
 | 
			
		||||
    },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@ -36,8 +36,8 @@ const routes: Routes = [
 | 
			
		||||
        CoreSearchComponentsModule,
 | 
			
		||||
    ],
 | 
			
		||||
    declarations: [
 | 
			
		||||
        CoreCoursesSearchPage,
 | 
			
		||||
        CoreCoursesListPage,
 | 
			
		||||
    ],
 | 
			
		||||
    exports: [RouterModule],
 | 
			
		||||
})
 | 
			
		||||
export class CoreCoursesSearchPageModule { }
 | 
			
		||||
export class CoreCoursesListPageModule { }
 | 
			
		||||
							
								
								
									
										211
									
								
								src/core/features/courses/pages/list/list.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								src/core/features/courses/pages/list/list.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,211 @@
 | 
			
		||||
// (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, OnDestroy, OnInit } from '@angular/core';
 | 
			
		||||
import { IonRefresher } from '@ionic/angular';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
			
		||||
import { CoreCourseBasicSearchedData, CoreCourses } from '../../services/courses';
 | 
			
		||||
 | 
			
		||||
type CoreCoursesListMode = 'search' | 'all';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Page that shows a list of courses.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'page-core-courses-list',
 | 
			
		||||
    templateUrl: 'list.html',
 | 
			
		||||
})
 | 
			
		||||
export class CoreCoursesListPage implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
    searchEnabled = false;
 | 
			
		||||
    searchMode = false;
 | 
			
		||||
    searchCanLoadMore = false;
 | 
			
		||||
    searchLoadMoreError = false;
 | 
			
		||||
    searchTotal = 0;
 | 
			
		||||
 | 
			
		||||
    mode: CoreCoursesListMode = 'all';
 | 
			
		||||
 | 
			
		||||
    courses: CoreCourseBasicSearchedData[] = [];
 | 
			
		||||
    coursesLoaded = false;
 | 
			
		||||
 | 
			
		||||
    protected currentSiteId: string;
 | 
			
		||||
    protected frontpageCourseId: number;
 | 
			
		||||
    protected searchPage = 0;
 | 
			
		||||
    protected searchText = '';
 | 
			
		||||
    protected siteUpdatedObserver: CoreEventObserver;
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.currentSiteId = CoreSites.getRequiredCurrentSite().getId();
 | 
			
		||||
        this.frontpageCourseId = CoreSites.getRequiredCurrentSite().getSiteHomeId();
 | 
			
		||||
 | 
			
		||||
        // Refresh the enabled flags if site is updated.
 | 
			
		||||
        this.siteUpdatedObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
 | 
			
		||||
            this.searchEnabled = !CoreCourses.isSearchCoursesDisabledInSite();
 | 
			
		||||
 | 
			
		||||
            if (!this.searchEnabled) {
 | 
			
		||||
                this.searchMode = false;
 | 
			
		||||
 | 
			
		||||
                this.fetchCourses();
 | 
			
		||||
            }
 | 
			
		||||
        }, this.currentSiteId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    ngOnInit(): void {
 | 
			
		||||
        this.mode = CoreNavigator.getRouteParam<CoreCoursesListMode>('mode') || this.mode;
 | 
			
		||||
 | 
			
		||||
        if (this.mode == 'search') {
 | 
			
		||||
            this.searchMode = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.searchEnabled = !CoreCourses.isSearchCoursesDisabledInSite();
 | 
			
		||||
        if (!this.searchEnabled) {
 | 
			
		||||
            this.searchMode = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.fetchCourses();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Load the course list.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async fetchCourses(): Promise<void> {
 | 
			
		||||
        try {
 | 
			
		||||
            if (this.searchMode && this.searchText) {
 | 
			
		||||
                await this.search(this.searchText);
 | 
			
		||||
            } else {
 | 
			
		||||
                await this.loadAvailableCourses();
 | 
			
		||||
            }
 | 
			
		||||
        } finally {
 | 
			
		||||
            this.coursesLoaded = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Load the courses.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async loadAvailableCourses(): Promise<void> {
 | 
			
		||||
        try {
 | 
			
		||||
            const courses = await CoreCourses.getCoursesByField();
 | 
			
		||||
 | 
			
		||||
            this.courses = courses.filter((course) => course.id != this.frontpageCourseId);
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            CoreDomUtils.showErrorModalDefault(error, 'core.courses.errorloadcourses', true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Refresh the courses.
 | 
			
		||||
     *
 | 
			
		||||
     * @param refresher Refresher.
 | 
			
		||||
     */
 | 
			
		||||
    refreshCourses(refresher: IonRefresher): void {
 | 
			
		||||
        const promises: Promise<void>[] = [];
 | 
			
		||||
 | 
			
		||||
        promises.push(CoreCourses.invalidateUserCourses());
 | 
			
		||||
        promises.push(CoreCourses.invalidateCoursesByField());
 | 
			
		||||
 | 
			
		||||
        Promise.all(promises).finally(() => {
 | 
			
		||||
            this.fetchCourses().finally(() => {
 | 
			
		||||
                refresher?.complete();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Search a new text.
 | 
			
		||||
     *
 | 
			
		||||
     * @param text The text to search.
 | 
			
		||||
     */
 | 
			
		||||
    async search(text: string): Promise<void> {
 | 
			
		||||
        this.searchMode = true;
 | 
			
		||||
        this.searchText = text;
 | 
			
		||||
        this.courses = [];
 | 
			
		||||
        this.searchPage = 0;
 | 
			
		||||
        this.searchTotal = 0;
 | 
			
		||||
 | 
			
		||||
        const modal = await CoreDomUtils.showModalLoading('core.searching', true);
 | 
			
		||||
        this.searchCourses().finally(() => {
 | 
			
		||||
            modal.dismiss();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clear search box.
 | 
			
		||||
     */
 | 
			
		||||
    clearSearch(): void {
 | 
			
		||||
        this.searchText = '';
 | 
			
		||||
        this.courses = [];
 | 
			
		||||
        this.searchPage = 0;
 | 
			
		||||
        this.searchTotal = 0;
 | 
			
		||||
        this.searchMode = false;
 | 
			
		||||
 | 
			
		||||
        this.coursesLoaded = false;
 | 
			
		||||
        this.fetchCourses();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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<void> {
 | 
			
		||||
        this.searchLoadMoreError = false;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const response = await CoreCourses.search(this.searchText, this.searchPage);
 | 
			
		||||
 | 
			
		||||
            if (this.searchPage === 0) {
 | 
			
		||||
                this.courses = response.courses;
 | 
			
		||||
            } else {
 | 
			
		||||
                this.courses = this.courses.concat(response.courses);
 | 
			
		||||
            }
 | 
			
		||||
            this.searchTotal = response.total;
 | 
			
		||||
 | 
			
		||||
            this.searchPage++;
 | 
			
		||||
            this.searchCanLoadMore = this.courses.length < this.searchTotal;
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            this.searchLoadMoreError = true; // Set to prevent infinite calls with infinite-loading.
 | 
			
		||||
            CoreDomUtils.showErrorModalDefault(error, 'core.courses.errorsearching', true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    ngOnDestroy(): void {
 | 
			
		||||
        this.siteUpdatedObserver?.off();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -204,7 +204,7 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy {
 | 
			
		||||
     * Go to search courses.
 | 
			
		||||
     */
 | 
			
		||||
    openSearch(): void {
 | 
			
		||||
        CoreNavigator.navigateToSitePath('courses/search');
 | 
			
		||||
        CoreNavigator.navigateToSitePath('courses/list', { params : { mode: 'search' } });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -1,23 +0,0 @@
 | 
			
		||||
<ion-header>
 | 
			
		||||
    <ion-toolbar>
 | 
			
		||||
        <ion-buttons slot="start">
 | 
			
		||||
            <ion-back-button [text]="'core.back' | translate"></ion-back-button>
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
        <h1>{{ 'core.courses.searchcourses' | translate }}</h1>
 | 
			
		||||
    </ion-toolbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <core-search-box (onSubmit)="search($event)" (onClear)="clearSearch()"
 | 
			
		||||
    [placeholder]="'core.courses.search' | translate" [searchLabel]="'core.courses.search' | translate" autoFocus="true"
 | 
			
		||||
    searchArea="CoreCoursesSearch"></core-search-box>
 | 
			
		||||
 | 
			
		||||
    <ng-container *ngIf="total > 0">
 | 
			
		||||
        <ion-item-divider>
 | 
			
		||||
            <ion-label><h2>{{ 'core.courses.totalcoursesearchresults' | translate:{$a: total} }}</h2></ion-label>
 | 
			
		||||
        </ion-item-divider>
 | 
			
		||||
        <core-courses-course-list-item *ngFor="let course of courses" [course]="course"></core-courses-course-list-item>
 | 
			
		||||
        <core-infinite-loading [enabled]="canLoadMore" (action)="loadMoreResults($event)" [error]="loadMoreError">
 | 
			
		||||
        </core-infinite-loading>
 | 
			
		||||
    </ng-container>
 | 
			
		||||
    <core-empty-box *ngIf="total == 0" icon="search" [message]="'core.courses.nosearchresults' | translate"></core-empty-box>
 | 
			
		||||
</ion-content>
 | 
			
		||||
@ -1,100 +0,0 @@
 | 
			
		||||
// (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<void> {
 | 
			
		||||
        this.currentSearch = text;
 | 
			
		||||
        this.courses = [];
 | 
			
		||||
        this.page = 0;
 | 
			
		||||
        this.total = 0;
 | 
			
		||||
 | 
			
		||||
        const modal = await CoreDomUtils.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<void> {
 | 
			
		||||
        this.loadMoreError = false;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const response = await CoreCourses.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.showErrorModalDefault(error, 'core.courses.errorsearching', true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -42,14 +42,17 @@ export class CoreCoursesIndexLinkHandlerService extends CoreContentLinksHandlerB
 | 
			
		||||
        return [{
 | 
			
		||||
            action: (siteId): void => {
 | 
			
		||||
                let pageName = CoreCoursesMyCoursesHomeHandlerService.PAGE_NAME;
 | 
			
		||||
                const pageParams: Params = {};
 | 
			
		||||
 | 
			
		||||
                if (params.categoryid) {
 | 
			
		||||
                    pageName += '/categories/' + params.categoryid;
 | 
			
		||||
                } else {
 | 
			
		||||
                    pageName += '/all';
 | 
			
		||||
                    pageName += '/list';
 | 
			
		||||
                    pageParams.mode = 'all';
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                CoreNavigator.navigateToSitePath(pageName, { siteId });
 | 
			
		||||
 | 
			
		||||
                CoreNavigator.navigateToSitePath(pageName, { params: pageParams, siteId });
 | 
			
		||||
            },
 | 
			
		||||
        }];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -218,14 +218,14 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy {
 | 
			
		||||
     * Go to search courses.
 | 
			
		||||
     */
 | 
			
		||||
    openSearch(): void {
 | 
			
		||||
        CoreNavigator.navigateToSitePath('courses/search');
 | 
			
		||||
        CoreNavigator.navigateToSitePath('courses/list', { params : { mode: 'search' } });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Go to available courses.
 | 
			
		||||
     */
 | 
			
		||||
    openAvailableCourses(): void {
 | 
			
		||||
        CoreNavigator.navigateToSitePath('courses/all');
 | 
			
		||||
        CoreNavigator.navigateToSitePath('courses/list', { params : { mode: 'all' } });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user