Merge pull request #2185 from crazyserver/MOBILE-3210

MOBILE-3210 myoverview: Add custom filters
main
Juan Leyva 2019-12-04 15:42:46 +01:00 committed by GitHub
commit 09a033acd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 127 additions and 28 deletions

View File

@ -1,8 +1,8 @@
<ion-item-divider>
<h2>{{ 'addon.block_myoverview.pluginname' | translate }}</h2>
<!-- Download all courses. -->
<div *ngIf="downloadCoursesEnabled && downloadEnabled && courses[selectedFilter] && courses[selectedFilter].length > 1 && !showFilter" class="core-button-spinner" item-end>
<button *ngIf="prefetchCoursesData[selectedFilter].icon && prefetchCoursesData[selectedFilter].icon != 'spinner'" ion-button icon-only clear color="dark" (click)="prefetchCourses()">
<div *ngIf="downloadCoursesEnabled && downloadEnabled && filteredCourses.length > 1 && !showFilter" class="core-button-spinner" item-end>
<button *ngIf="prefetchCoursesData[selectedFilter] && prefetchCoursesData[selectedFilter].icon && prefetchCoursesData[selectedFilter].icon != 'spinner'" ion-button icon-only clear color="dark" (click)="prefetchCourses()">
<core-icon [name]="prefetchCoursesData[selectedFilter].icon"></core-icon>
</button>
<ion-badge class="core-course-download-courses-progress" *ngIf="prefetchCoursesData[selectedFilter].badge">{{prefetchCoursesData[selectedFilter].badge}}</ion-badge>
@ -23,11 +23,16 @@
<ion-option value="inprogress" *ngIf="showFilters.inprogress != 'hidden'" [disabled]="showFilters.inprogress == 'disabled'">{{ 'addon.block_myoverview.inprogress' | translate }}</ion-option>
<ion-option value="future" *ngIf="showFilters.future != 'hidden'" [disabled]="showFilters.future == 'disabled'">{{ 'addon.block_myoverview.future' | translate }}</ion-option>
<ion-option value="past" *ngIf="showFilters.past != 'hidden'" [disabled]="showFilters.past == 'disabled'">{{ 'addon.block_myoverview.past' | translate }}</ion-option>
<ng-container *ngIf="showFilters.custom != 'hidden'">
<ng-container *ngFor="let customOption of customFilter; let index = index">
<ion-option value="custom-{{index}}">{{ customOption.name }}</ion-option>
</ng-container>
</ng-container>
<ion-option value="favourite" *ngIf="showFilters.favourite != 'hidden'" [disabled]="showFilters.favourite == 'disabled'">{{ 'addon.block_myoverview.favourites' | translate }}</ion-option>
<ion-option value="hidden" *ngIf="showFilters.hidden != 'hidden'" [disabled]="showFilters.hidden == 'disabled'">{{ 'addon.block_myoverview.hiddencourses' | translate }}</ion-option>
</ion-select>
</div>
<core-empty-box *ngIf="courses[selectedFilter].length == 0" image="assets/img/icons/courses.svg" [message]="'addon.block_myoverview.nocourses' | translate"></core-empty-box>
<core-empty-box *ngIf="filteredCourses.length == 0" image="assets/img/icons/courses.svg" [message]="'addon.block_myoverview.nocourses' | translate"></core-empty-box>
<!-- Filter courses. -->
<ion-searchbar #searchbar *ngIf="showFilter" [(ngModel)]="courses.filter" (ionInput)="filterChanged($event)" (ionCancel)="filterChanged()" [placeholder]="'core.courses.filtermycourses' | translate">

View File

@ -43,12 +43,14 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
inprogress: [],
future: [],
favourite: [],
hidden: []
hidden: [],
custom: [], // Leave it empty to avoid download all those courses.
};
customFilter: any[] = [];
selectedFilter = 'inprogress';
sort = 'fullname';
currentSite: any;
filteredCourses: any[];
filteredCourses: any[] = [];
prefetchCoursesData = {
all: {},
allincludinghidden: {},
@ -56,7 +58,8 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
past: {},
future: {},
favourite: {},
hidden: {}
hidden: {},
custom: {}, // Leave it empty to avoid download all those courses.
};
showFilters = { // Options are show, disabled, hidden.
all: 'show',
@ -65,7 +68,8 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
inprogress: 'show',
future: 'show',
favourite: 'show',
hidden: 'show'
hidden: 'show',
custom: 'hidden', // True or false to show or hide.
};
showFilter = false;
showSelectorFilter = false;
@ -80,11 +84,15 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
protected courseIds = [];
protected fetchContentDefaultError = 'Error getting my overview data.';
constructor(injector: Injector, private coursesProvider: CoreCoursesProvider,
private courseCompletionProvider: AddonCourseCompletionProvider, private eventsProvider: CoreEventsProvider,
private courseHelper: CoreCourseHelperProvider,
private courseOptionsDelegate: CoreCourseOptionsDelegate, private coursesHelper: CoreCoursesHelperProvider,
private sitesProvider: CoreSitesProvider, private timeUtils: CoreTimeUtilsProvider) {
constructor(injector: Injector,
protected coursesProvider: CoreCoursesProvider,
protected courseCompletionProvider: AddonCourseCompletionProvider,
protected eventsProvider: CoreEventsProvider,
protected courseHelper: CoreCourseHelperProvider,
protected courseOptionsDelegate: CoreCourseOptionsDelegate,
protected coursesHelper: CoreCoursesHelperProvider,
protected sitesProvider: CoreSitesProvider,
protected timeUtils: CoreTimeUtilsProvider) {
super(injector, 'AddonBlockMyOverviewComponent');
}
@ -115,7 +123,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
this.sort = value;
}));
promises.push(this.currentSite.getLocalSiteConfig('AddonBlockMyOverviewFilter', this.selectedFilter).then((value) => {
this.selectedFilter = typeof this.courses[value] == 'undefined' ? 'inprogress' : value;
this.selectedFilter = value;
}));
Promise.all(promises).finally(() => {
@ -213,6 +221,15 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
(!config || config.displaygroupingstarred.value == '1'),
this.courses.favourite.length === 0);
this.showFilters.custom = this.getShowFilterValue(this.showSelectorFilter && config &&
config.displaygroupingcustomfield.value == '1' && config.customfieldsexport && config.customfieldsexport.value,
false);
if (this.showFilters.custom == 'show') {
this.customFilter = this.textUtils.parseJSON(config.customfieldsexport.value);
} else {
this.customFilter = [];
}
if (this.showSelectorFilter) {
// Check if any selector is shown and not disabled.
this.showSelectorFilter = Object.keys(this.showFilters).some((key) => {
@ -224,7 +241,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
// No selector, or the default option is disabled, show all.
this.selectedFilter = 'all';
}
this.filteredCourses = this.courses[this.selectedFilter];
this.setCourseFilter(this.selectedFilter);
this.initPrefetchCoursesIcons();
});
@ -248,17 +265,17 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
*/
filterChanged(event: any): void {
const newValue = event.target.value && event.target.value.trim().toLowerCase();
if (!newValue || !this.courses['all']) {
this.filteredCourses = this.courses['all'];
if (!newValue || this.courses.allincludinghidden.length <= 0) {
this.filteredCourses = this.courses.allincludinghidden;
} else {
// Use displayname if avalaible, or fullname if not.
if (this.courses['all'].length > 0 &&
typeof this.courses['all'][0].displayname != 'undefined') {
this.filteredCourses = this.courses['all'].filter((course) => {
if (this.courses.allincludinghidden.length > 0 &&
typeof this.courses.allincludinghidden[0].displayname != 'undefined') {
this.filteredCourses = this.courses.allincludinghidden.filter((course) => {
return course.displayname.toLowerCase().indexOf(newValue) > -1;
});
} else {
this.filteredCourses = this.courses['all'].filter((course) => {
this.filteredCourses = this.courses.allincludinghidden.filter((course) => {
return course.fullname.toLowerCase().indexOf(newValue) > -1;
});
}
@ -304,8 +321,50 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
* The selected courses filter have changed.
*/
selectedChanged(): void {
this.currentSite.setLocalSiteConfig('AddonBlockMyOverviewFilter', this.selectedFilter);
this.filteredCourses = this.courses[this.selectedFilter];
this.setCourseFilter(this.selectedFilter);
}
/**
* Set selected courses filter.
*
* @param {string} filter Filter name to set.
*/
protected setCourseFilter(filter: string): void {
this.selectedFilter = filter;
if (this.showFilters.custom == 'show' && filter.startsWith('custom-') &&
typeof this.customFilter[filter.substr(7)] != 'undefined') {
const filterName = this.block.configs.customfiltergrouping.value,
filterValue = this.customFilter[filter.substr(7)].value;
this.loaded = false;
this.coursesProvider.getEnrolledCoursesByCustomField(filterName, filterValue).then((courses) => {
// Get the courses information from allincludinghidden to get the max info about the course.
const courseIds = courses.map((course) => course.id);
this.filteredCourses = this.courses.allincludinghidden.filter((allCourse) =>
courseIds.indexOf(allCourse.id) !== -1);
}).catch((error) => {
this.domUtils.showErrorModalDefault(error, this.fetchContentDefaultError);
}).finally(() => {
this.loaded = true;
});
} else {
// Only save the filter if not a custom one.
this.currentSite.setLocalSiteConfig('AddonBlockMyOverviewFilter', filter);
if (this.showFilters[filter] == 'show') {
this.filteredCourses = this.courses[filter];
} else {
const activeFilter = Object.keys(this.showFilters).find((name) => {
return this.showFilters[name] == 'show';
});
if (activeFilter) {
this.setCourseFilter(activeFilter);
}
}
}
}
/**
@ -314,6 +373,8 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
* @param courses Courses to filter.
*/
initCourseFilters(courses: any[]): void {
this.courses.allincludinghidden = courses;
if (this.showSortFilter) {
if (this.sort == 'lastaccess') {
courses.sort((a, b) => {
@ -330,7 +391,6 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
}
this.courses.all = [];
this.courses.allincludinghidden = [];
this.courses.past = [];
this.courses.inprogress = [];
this.courses.future = [];
@ -339,7 +399,6 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
const today = this.timeUtils.timestamp();
courses.forEach((course) => {
this.courses.allincludinghidden.push(course);
if (course.hidden) {
this.courses.hidden.push(course);
} else {
@ -362,7 +421,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
}
});
this.filteredCourses = this.courses[this.selectedFilter];
this.setCourseFilter(this.selectedFilter);
}
/**
@ -373,7 +432,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
switchSort(sort: string): void {
this.sort = sort;
this.currentSite.setLocalSiteConfig('AddonBlockMyOverviewSort', this.sort);
this.initCourseFilters(this.courses.all.concat(this.courses.hidden));
this.initCourseFilters(this.courses.allincludinghidden);
}
/**
@ -382,7 +441,12 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
switchFilter(): void {
this.showFilter = !this.showFilter;
this.courses.filter = '';
this.filteredCourses = this.courses[this.showFilter ? 'all' : this.selectedFilter];
if (this.showFilter) {
this.filteredCourses = this.courses.allincludinghidden;
} else {
this.setCourseFilter(this.selectedFilter);
}
}
/**
@ -402,7 +466,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
* @return If switch button that enables the filter input is shown or not.
*/
showFilterSwitchButton(): boolean {
return this.loaded && this.courses['all'] && this.courses['all'].length > 5;
return this.loaded && this.courses.allincludinghidden && this.courses.allincludinghidden.length > 5;
}
/**

View File

@ -514,6 +514,36 @@ export class CoreCoursesProvider {
return this.ROOT_CACHE_KEY + 'coursesbyfield:' + field + ':' + value;
}
/**
* Get courses matching the given custom field. Only works in online.
*
* @param customFieldName Custom field name.
* @param customFieldValue Custom field value.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with the list of courses.
* @since 3.8
*/
getEnrolledCoursesByCustomField(customFieldName: string, customFieldValue: string, siteId?: string): Promise<any[]> {
return this.sitesProvider.getSite(siteId).then((site) => {
const data = {
classification: 'customfield',
customfieldname: customFieldName,
customfieldvalue: customFieldValue
},
preSets = {
getFromCache: false
};
return site.read('core_course_get_enrolled_courses_by_timeline_classification', data, preSets).then((courses) => {
if (courses.courses) {
return courses.courses;
}
return Promise.reject(null);
});
});
}
/**
* Check if get courses by field WS is available in a certain site.
*