MOBILE-3833 my: Revert to basic filters with advanced option
parent
bf5f9c8b99
commit
dc934ffcb2
|
@ -40,10 +40,10 @@
|
|||
"addon.block_learningplans.pluginname": "block_lp",
|
||||
"addon.block_myoverview.all": "block_myoverview",
|
||||
"addon.block_myoverview.allincludinghidden": "block_myoverview",
|
||||
"addon.block_myoverview.aria:favourites": "block_myoverview",
|
||||
"addon.block_myoverview.aria:hiddencourses": "block_myoverview",
|
||||
"addon.block_myoverview.card": "block_myoverview",
|
||||
"addon.block_myoverview.favourites": "block_myoverview",
|
||||
"addon.block_myoverview.future": "block_myoverview",
|
||||
"addon.block_myoverview.hiddencourses": "block_myoverview",
|
||||
"addon.block_myoverview.inprogress": "block_myoverview",
|
||||
"addon.block_myoverview.lastaccessed": "block_myoverview",
|
||||
"addon.block_myoverview.list": "block_myoverview",
|
||||
|
@ -1451,7 +1451,6 @@
|
|||
"core.allparticipants": "moodle",
|
||||
"core.answer": "moodle",
|
||||
"core.answered": "quiz",
|
||||
"core.applyfilters": "user",
|
||||
"core.areyousure": "moodle",
|
||||
"core.back": "moodle",
|
||||
"core.block.blocks": "moodle",
|
||||
|
|
|
@ -17,12 +17,10 @@ import { NgModule } from '@angular/core';
|
|||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
import { CoreCoursesComponentsModule } from '@features/courses/components/components.module';
|
||||
import { AddonBlockMyOverviewComponent } from './myoverview/myoverview';
|
||||
import { AddonBlockMyOverviewFilterOptionsComponent } from './filteroptions/filteroptions';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonBlockMyOverviewComponent,
|
||||
AddonBlockMyOverviewFilterOptionsComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>
|
||||
<h1>{{ 'core.courses.filtermycourses' | translate }}</h1>
|
||||
</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
|
||||
<ion-icon name="fas-times" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-list>
|
||||
<ion-radio-group [(ngModel)]="options.timeFilterSelected">
|
||||
<ion-item class="ion-text-wrap" *ngIf="options.show.all">
|
||||
<ion-label>{{'addon.block_myoverview.all' | translate}}</ion-label>
|
||||
<ion-radio slot="end" value="all"></ion-radio>
|
||||
</ion-item>
|
||||
<ion-item class="ion-text-wrap" *ngIf="options.show.inprogress">
|
||||
<ion-label>{{'addon.block_myoverview.inprogress' | translate}}</ion-label>
|
||||
<ion-radio slot="end" value="inprogress"></ion-radio>
|
||||
</ion-item>
|
||||
<ion-item class="ion-text-wrap" *ngIf="options.show.future">
|
||||
<ion-label>{{'addon.block_myoverview.future' | translate}}</ion-label>
|
||||
<ion-radio slot="end" value="future"></ion-radio>
|
||||
</ion-item>
|
||||
<ion-item class="ion-text-wrap" *ngIf="options.show.past">
|
||||
<ion-label>{{'addon.block_myoverview.past' | translate}}</ion-label>
|
||||
<ion-radio slot="end" value="past"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
|
||||
<core-spacer *ngIf="options.show.custom"></core-spacer>
|
||||
<ion-radio-group [(ngModel)]="options.customSelected" *ngIf="options.show.custom" allowEmptySelection="true">
|
||||
<ion-item class="ion-text-wrap" *ngFor="let customOption of options.customFilters">
|
||||
<ion-label>{{customOption.name}}</ion-label>
|
||||
<ion-radio slot="end" [value]="customOption.value"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
|
||||
<core-spacer></core-spacer>
|
||||
<ion-item *ngIf="options.show.favourite">
|
||||
<ion-label>{{ 'addon.block_myoverview.aria:favourites' | translate }}</ion-label>
|
||||
<ion-toggle [(ngModel)]="options.favouriteSelected"></ion-toggle>
|
||||
</ion-item>
|
||||
|
||||
<ion-item *ngIf="options.show.hidden">
|
||||
<ion-label>{{ 'addon.block_myoverview.aria:hiddencourses' | translate }}</ion-label>
|
||||
<ion-toggle [(ngModel)]="options.hiddenSelected"></ion-toggle>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
</ion-content>
|
||||
<ion-footer class="ion-padding">
|
||||
<ion-button (click)="apply()" expand="block" [attr.aria-label]="'core.applyfilters' | translate" class="ion-text-wrap">
|
||||
{{ 'core.applyfilters' | translate }}
|
||||
</ion-button>
|
||||
</ion-footer>
|
|
@ -1,8 +0,0 @@
|
|||
ion-footer {
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
ion-button {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
|
@ -1,45 +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, Input } from '@angular/core';
|
||||
import { ModalController } from '@singletons';
|
||||
import { AddonBlockMyOverviewFilterOptions } from '../myoverview/myoverview';
|
||||
|
||||
/**
|
||||
* Component to render a my overview filter options.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-block-myoverview-filter-options',
|
||||
templateUrl: 'filteroptions.html',
|
||||
styleUrls: ['filteroptions.scss'],
|
||||
})
|
||||
export class AddonBlockMyOverviewFilterOptionsComponent {
|
||||
|
||||
@Input() options!: AddonBlockMyOverviewFilterOptions;
|
||||
|
||||
/**
|
||||
* Appl filters.
|
||||
*/
|
||||
apply(): void {
|
||||
ModalController.dismiss(this.options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close modal.
|
||||
*/
|
||||
closeModal(): void {
|
||||
ModalController.dismiss();
|
||||
}
|
||||
|
||||
}
|
|
@ -26,20 +26,51 @@
|
|||
<ion-col>
|
||||
<!-- Filter courses. -->
|
||||
<ion-searchbar [(ngModel)]="textFilter" (ionInput)="filterTextChanged($event.target)"
|
||||
(ionCancel)="filterTextChanged($event.target)" [placeholder]="'core.filter' | translate">
|
||||
(ionCancel)="filterTextChanged($event.target)" [placeholder]="'core.courses.filtermycourses' | translate">
|
||||
</ion-searchbar>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row class="ion-justify-content-between ion-align-items-center addon-block-myoverview-filter" *ngIf="hasCourses">
|
||||
<ion-col size="auto" *ngIf="filters.enabled">
|
||||
<core-combobox interface="modal" [label]="'core.courses.filtermycourses' | translate" (onChange)="filterOptionsChanged($event)"
|
||||
icon="fas-filter" [badge]="filters.count" [modalOptions]="filterModalOptions">
|
||||
<core-combobox [label]="'core.courses.filtermycourses' | translate" [selection]="filters.timeFilterSelected"
|
||||
(onChange)="filterOptionsChanged($event)">
|
||||
<ion-select-option class="ion-text-wrap core-select-option-border-bottom" value="allincludinghidden"
|
||||
*ngIf="filters.show.allincludinghidden">
|
||||
{{ 'addon.block_myoverview.allincludinghidden' | translate }}
|
||||
</ion-select-option>
|
||||
<ion-select-option class="ion-text-wrap core-select-option-border-bottom" value="all" *ngIf="filters.show.all">
|
||||
{{ 'addon.block_myoverview.all' | translate }}
|
||||
</ion-select-option>
|
||||
<ion-select-option class="ion-text-wrap"
|
||||
[class.core-select-option-border-bottom]="!filters.show.past && !filters.show.future" value="inprogress"
|
||||
*ngIf="filters.show.inprogress">
|
||||
{{ 'addon.block_myoverview.inprogress' | translate }}
|
||||
</ion-select-option>
|
||||
<ion-select-option class="ion-text-wrap" [class.core-select-option-border-bottom]="!filters.show.past" value="future"
|
||||
*ngIf="filters.show.future">
|
||||
{{ 'addon.block_myoverview.future' | translate }}
|
||||
</ion-select-option>
|
||||
<ion-select-option class="ion-text-wrap core-select-option-border-bottom" value="past" *ngIf="filters.show.past">
|
||||
{{ 'addon.block_myoverview.past' | translate }}
|
||||
</ion-select-option>
|
||||
<ng-container *ngIf="filters.show.custom">
|
||||
<ng-container *ngFor="let customOption of filters.customFilters; let index = index; let last = last">
|
||||
<ion-select-option class="ion-text-wrap" value="custom-{{index}}" [class.core-select-option-border-bottom]="last">
|
||||
{{ customOption.name }}</ion-select-option>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<ion-select-option class="ion-text-wrap core-select-option-border-bottom" value="favourite" *ngIf="filters.show.favourite">
|
||||
{{ 'addon.block_myoverview.favourites' | translate }}
|
||||
</ion-select-option>
|
||||
<ion-select-option class="ion-text-wrap" value="hidden" *ngIf="filters.show.hidden">
|
||||
{{ 'addon.block_myoverview.hiddencourses' | translate }}
|
||||
</ion-select-option>
|
||||
</core-combobox>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<!-- Filter courses. -->
|
||||
<ion-searchbar class="ion-hide-md-down" [(ngModel)]="textFilter" (ionInput)="filterTextChanged($event.target)"
|
||||
(ionCancel)="filterTextChanged($event.target)" [placeholder]="'core.filter' | translate">
|
||||
(ionCancel)="filterTextChanged($event.target)" [placeholder]="'core.courses.filtermycourses' | translate">
|
||||
</ion-searchbar>
|
||||
</ion-col>
|
||||
<ion-col size="auto" *ngIf="sort.enabled">
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { ModalOptions } from '@ionic/core';
|
||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
import { CoreTimeUtils } from '@services/utils/time';
|
||||
import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
|
||||
|
@ -27,12 +26,12 @@ import { CoreUtils } from '@services/utils/utils';
|
|||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { AddonCourseCompletion } from '@addons/coursecompletion/services/coursecompletion';
|
||||
import { AddonBlockMyOverviewFilterOptionsComponent } from '../filteroptions/filteroptions';
|
||||
import { IonSearchbar } from '@ionic/angular';
|
||||
import moment from 'moment';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
|
||||
const FILTER_PRIORITY: AddonBlockMyOverviewTimeFilters[] = ['all', 'inprogress', 'future', 'past'];
|
||||
const FILTER_PRIORITY: AddonBlockMyOverviewTimeFilters[] =
|
||||
['all', 'inprogress', 'future', 'past', 'favourite', 'allincludinghidden', 'hidden'];
|
||||
|
||||
/**
|
||||
* Component to render a my overview block.
|
||||
|
@ -59,6 +58,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
filters: AddonBlockMyOverviewFilterOptions = {
|
||||
enabled: false,
|
||||
show: { // Options are visible, disabled, hidden.
|
||||
allincludinghidden: true,
|
||||
all: true,
|
||||
past: true,
|
||||
inprogress: true,
|
||||
|
@ -68,14 +68,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
custom: false,
|
||||
},
|
||||
timeFilterSelected: 'inprogress',
|
||||
favouriteSelected: false,
|
||||
hiddenSelected: false,
|
||||
customFilters: [],
|
||||
count: 0,
|
||||
};
|
||||
|
||||
filterModalOptions: ModalOptions = {
|
||||
component: AddonBlockMyOverviewFilterOptionsComponent,
|
||||
};
|
||||
|
||||
isLayoutSwitcherAvailable = false;
|
||||
|
@ -100,6 +93,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
protected fetchContentDefaultError = 'Error getting my overview data.';
|
||||
protected gradePeriodAfter = 0;
|
||||
protected gradePeriodBefore = 0;
|
||||
protected today = 0;
|
||||
|
||||
constructor() {
|
||||
super('AddonBlockMyOverviewComponent');
|
||||
|
@ -151,43 +145,11 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
return;
|
||||
}));
|
||||
|
||||
// Wait for the migration.
|
||||
await this.currentSite.getLocalSiteConfig<string>(
|
||||
promises.push(this.currentSite.getLocalSiteConfig(
|
||||
'AddonBlockMyOverviewFilter',
|
||||
this.filters.timeFilterSelected,
|
||||
).then(async (value) => {
|
||||
if (FILTER_PRIORITY.includes(value as AddonBlockMyOverviewTimeFilters)) {
|
||||
this.filters.timeFilterSelected = value as AddonBlockMyOverviewTimeFilters;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Migrate setting.
|
||||
this.filters.hiddenSelected = value == 'allincludinghidden' || value == 'hidden';
|
||||
|
||||
if (value == 'favourite') {
|
||||
this.filters.favouriteSelected = true;
|
||||
} else {
|
||||
this.filters.favouriteSelected = false;
|
||||
}
|
||||
|
||||
return await this.saveFilters('all');
|
||||
});
|
||||
|
||||
promises.push(this.currentSite.getLocalSiteConfig(
|
||||
'AddonBlockMyOverviewFavouriteFilter',
|
||||
this.filters.favouriteSelected ? 1 : 0,
|
||||
).then((value) => {
|
||||
this.filters.favouriteSelected = value == 1;
|
||||
|
||||
return;
|
||||
}));
|
||||
|
||||
promises.push(this.currentSite.getLocalSiteConfig(
|
||||
'AddonBlockMyOverviewHiddenFilter',
|
||||
this.filters.hiddenSelected ? 1 : 0,
|
||||
).then((value) => {
|
||||
this.filters.hiddenSelected = value == 1;
|
||||
this.filters.timeFilterSelected = value;
|
||||
|
||||
return;
|
||||
}));
|
||||
|
@ -315,6 +277,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
config?.displaygroupingallincludinghidden?.value == '1' ||
|
||||
sampleCourse.hidden !== undefined && (!config || config.displaygroupinghidden?.value == '1');
|
||||
|
||||
this.filters.show.allincludinghidden = !config || config.displaygroupingallincludinghidden?.value == '1';
|
||||
this.filters.show.all = !config || config.displaygroupingall?.value == '1';
|
||||
this.filters.show.inprogress = !config || config.displaygroupinginprogress?.value == '1';
|
||||
this.filters.show.past = !config || config.displaygroupingpast?.value == '1';
|
||||
|
@ -338,10 +301,6 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
this.saveFilters('all');
|
||||
}
|
||||
|
||||
this.filterModalOptions.componentProps = {
|
||||
options: Object.assign({}, this.filters),
|
||||
};
|
||||
|
||||
this.filterCourses();
|
||||
}
|
||||
|
||||
|
@ -475,81 +434,66 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
* Set selected courses filter.
|
||||
*/
|
||||
protected async filterCourses(): Promise<void> {
|
||||
this.filters.count = 0;
|
||||
|
||||
let timeFilter = this.filters.timeFilterSelected;
|
||||
|
||||
// Filter is not active, take the first active or all.
|
||||
if (!this.filters.show[timeFilter]) {
|
||||
timeFilter = FILTER_PRIORITY.find((name) => this.filters.show[name]) || 'all';
|
||||
|
||||
this.saveFilters(timeFilter);
|
||||
}
|
||||
|
||||
if (timeFilter !== 'all') {
|
||||
this.filters.count++;
|
||||
}
|
||||
|
||||
this.filteredCourses = this.allCourses;
|
||||
|
||||
const customFilterName = this.block.configsRecord?.customfiltergrouping.value;
|
||||
const customFilterValue = this.filters.customSelected;
|
||||
if (customFilterName && this.filters.show.custom && customFilterValue !== undefined) {
|
||||
this.filters.count++;
|
||||
if (this.filters.show.custom && timeFilter.startsWith('custom-')) {
|
||||
// Custom filter.
|
||||
const customFilterName = this.block.configsRecord?.customfiltergrouping.value;
|
||||
const customFilterValue = this.filters.customFilters[timeFilter.substring(7)]?.value;
|
||||
|
||||
this.loaded = false;
|
||||
try {
|
||||
const courses = await CoreCourses.getEnrolledCoursesByCustomField(customFilterName, customFilterValue);
|
||||
if (customFilterName !== undefined && customFilterValue !== undefined) {
|
||||
this.loaded = false;
|
||||
try {
|
||||
const courses = await CoreCourses.getEnrolledCoursesByCustomField(customFilterName, customFilterValue);
|
||||
|
||||
const courseIds = courses.map((course) => course.id);
|
||||
// Get the courses information from allincludinghidden to get the max info about the course.
|
||||
const courseIds = courses.map((course) => course.id);
|
||||
|
||||
this.filteredCourses = this.filteredCourses.filter((course) => courseIds.includes(course.id));
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModalDefault(error, this.fetchContentDefaultError);
|
||||
} finally {
|
||||
this.loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
const onlyFavourite = this.filters.show.favourite && this.filters.favouriteSelected;
|
||||
if (onlyFavourite) {
|
||||
this.filters.count++;
|
||||
}
|
||||
|
||||
const showHidden = this.filters.show.hidden && this.filters.hiddenSelected;
|
||||
if (showHidden) {
|
||||
this.filters.count++;
|
||||
}
|
||||
|
||||
// Time filter, favourite and hidden.
|
||||
const today = CoreTimeUtils.timestamp();
|
||||
|
||||
this.filteredCourses = this.filteredCourses.filter((course) => {
|
||||
let include = timeFilter == 'all';
|
||||
|
||||
if (!include) {
|
||||
if ((course.enddate && this.courseClassifyEndDate(course.enddate) < today) || course.completed) {
|
||||
// Courses that have already ended.
|
||||
include = timeFilter == 'past';
|
||||
} else if (course.startdate && this.courseClassifyStartDate(course.startdate) > today) {
|
||||
// Courses that have not started yet.
|
||||
include = timeFilter == 'future';
|
||||
} else {
|
||||
// Courses still in progress.
|
||||
include = timeFilter == 'inprogress';
|
||||
this.filteredCourses = this.filteredCourses.filter((course) => courseIds.includes(course.id));
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModalDefault(error, this.fetchContentDefaultError);
|
||||
} finally {
|
||||
this.loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (onlyFavourite) {
|
||||
include = include && !!course.isfavourite;
|
||||
} else {
|
||||
// Filter is not active, take the first active or all. Custom is never saved.
|
||||
if (!this.filters.show[timeFilter]) {
|
||||
timeFilter = FILTER_PRIORITY.find((name) => this.filters.show[name]) || 'all';
|
||||
}
|
||||
this.saveFilters(timeFilter);
|
||||
|
||||
if (!showHidden) {
|
||||
include = include && !course.hidden;
|
||||
// Update today date.
|
||||
this.today = Date.now();
|
||||
|
||||
// Apply filters.
|
||||
switch(timeFilter) {
|
||||
case 'allincludinghidden':
|
||||
// No nothing, it's all courses.
|
||||
break;
|
||||
case 'all':
|
||||
this.filteredCourses = this.filteredCourses.filter((course) => !course.hidden);
|
||||
break;
|
||||
case 'inprogress':
|
||||
this.filteredCourses = this.filteredCourses.filter((course) =>
|
||||
!course.hidden && !this.isPastCourse(course) && !this.isFutureCourse(course));
|
||||
break;
|
||||
case 'future':
|
||||
this.filteredCourses = this.filteredCourses.filter((course) => !course.hidden && this.isFutureCourse(course));
|
||||
break;
|
||||
case 'past':
|
||||
this.filteredCourses = this.filteredCourses.filter((course) => !course.hidden && this.isPastCourse(course));
|
||||
break;
|
||||
case 'favourite':
|
||||
this.filteredCourses = this.filteredCourses.filter((course) => !course.hidden && course.isfavourite);
|
||||
break;
|
||||
case 'hidden':
|
||||
this.filteredCourses = this.filteredCourses.filter((course) => course.hidden);
|
||||
break;
|
||||
}
|
||||
|
||||
return include;
|
||||
});
|
||||
}
|
||||
|
||||
// Text filter.
|
||||
const value = this.textFilter.trim().toLowerCase();
|
||||
|
@ -572,23 +516,41 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
}
|
||||
|
||||
/**
|
||||
* This function calculates the end date to use for display classification purposes, incorporating the grace period, if any.
|
||||
* Calculates if course date is past.
|
||||
*
|
||||
* @param endDate Course end date.
|
||||
* @return The new enddate.
|
||||
* @param course Course Object.
|
||||
* @return Wether the course is past.
|
||||
*/
|
||||
protected courseClassifyEndDate(endDate: number): number {
|
||||
return moment(endDate).add(this.gradePeriodAfter, 'days').valueOf();
|
||||
protected isPastCourse(course: CoreEnrolledCourseDataWithOptions): boolean {
|
||||
if (course.completed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!course.enddate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate the end date to use for display classification purposes, incorporating the grace period, if any.
|
||||
const endDate = moment(course.enddate * 1000).add(this.gradePeriodAfter, 'days').valueOf();
|
||||
|
||||
return endDate < this.today;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculates the start date to use for display classification purposes, incorporating the grace period, if any.
|
||||
* Calculates if course date is future.
|
||||
*
|
||||
* @param startDate Course start date.
|
||||
* @return The new startdate.
|
||||
* @param course Course Object.
|
||||
* @return Wether the course is future.
|
||||
*/
|
||||
protected courseClassifyStartDate(startDate: number): number {
|
||||
return moment(startDate).subtract(this.gradePeriodBefore, 'days').valueOf();
|
||||
protected isFutureCourse(course: CoreEnrolledCourseDataWithOptions): boolean {
|
||||
if (this.isPastCourse(course) || !course.startdate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate the start date to use for display classification purposes, incorporating the grace period, if any.
|
||||
const startDate = moment(course.startdate * 1000).subtract(this.gradePeriodBefore, 'days').valueOf();
|
||||
|
||||
return startDate > this.today;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -630,18 +592,9 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
* @param timeFilter New time filter.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
async saveFilters(timeFilter: AddonBlockMyOverviewTimeFilters): Promise<void> {
|
||||
async saveFilters(timeFilter: string): Promise<void> {
|
||||
this.filters.timeFilterSelected = timeFilter;
|
||||
|
||||
this.filterModalOptions.componentProps = {
|
||||
options: Object.assign({}, this.filters),
|
||||
};
|
||||
|
||||
await Promise.all([
|
||||
this.currentSite.setLocalSiteConfig('AddonBlockMyOverviewFilter', this.filters.timeFilterSelected),
|
||||
this.currentSite.setLocalSiteConfig('AddonBlockMyOverviewFavouriteFilter', this.filters.favouriteSelected ? 1 : 0),
|
||||
this.currentSite.setLocalSiteConfig('AddonBlockMyOverviewHiddenFilter', this.filters.hiddenSelected ? 1 : 0),
|
||||
]);
|
||||
await this.currentSite.setLocalSiteConfig('AddonBlockMyOverviewFilter', timeFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -669,13 +622,13 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
}
|
||||
|
||||
/**
|
||||
* Opens display Options modal.
|
||||
* Option selected save and apply filter.
|
||||
*
|
||||
* @param selected Option selected.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
filterOptionsChanged(modalData: AddonBlockMyOverviewFilterOptions): void {
|
||||
this.filters = modalData;
|
||||
this.saveFilters(this.filters.timeFilterSelected);
|
||||
async filterOptionsChanged(selected: AddonBlockMyOverviewTimeFilters): Promise<void> {
|
||||
this.filters.timeFilterSelected = selected;
|
||||
this.filterCourses();
|
||||
}
|
||||
|
||||
|
@ -698,11 +651,12 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
}
|
||||
|
||||
type AddonBlockMyOverviewLayouts = 'card'|'list';
|
||||
type AddonBlockMyOverviewTimeFilters = 'all'|'inprogress'|'future'|'past';
|
||||
type AddonBlockMyOverviewTimeFilters = 'allincludinghidden'|'all'|'inprogress'|'future'|'past'|'favourite'|'hidden';
|
||||
|
||||
export type AddonBlockMyOverviewFilterOptions = {
|
||||
enabled: boolean;
|
||||
show: {
|
||||
allincludinghidden: boolean;
|
||||
all: boolean;
|
||||
inprogress: boolean;
|
||||
future: boolean;
|
||||
|
@ -711,15 +665,11 @@ export type AddonBlockMyOverviewFilterOptions = {
|
|||
hidden: boolean;
|
||||
custom: boolean;
|
||||
};
|
||||
timeFilterSelected: AddonBlockMyOverviewTimeFilters;
|
||||
favouriteSelected: boolean;
|
||||
hiddenSelected: boolean;
|
||||
timeFilterSelected: string;
|
||||
customFilters: {
|
||||
name: string;
|
||||
value: string;
|
||||
}[];
|
||||
customSelected?: string;
|
||||
count: number;
|
||||
};
|
||||
|
||||
type AddonBlockMyOverviewSortOptions = {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"all": "All",
|
||||
"allincludinghidden": "All (including archived)",
|
||||
"aria:favourites": "Show starred courses only",
|
||||
"aria:hiddencourses": "Show archived courses",
|
||||
"card": "Card",
|
||||
"favourites": "Starred",
|
||||
"future": "Future",
|
||||
"hiddencourses": "Archived",
|
||||
"inprogress": "In progress",
|
||||
"lastaccessed": "Last accessed",
|
||||
"list": "List",
|
||||
|
|
|
@ -53,7 +53,6 @@ export class CoreComboboxComponent {
|
|||
|
||||
// Additional options when interface modal is selected.
|
||||
@Input() icon?: string; // Icon for modal interface.
|
||||
@Input() badge?: number; // Badge number to show near the icon.
|
||||
@Input() modalOptions?: ModalOptions; // Will emit an event the value changed.
|
||||
@Input() listboxId = '';
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<ion-button (click)="openSelect($event)" *ngIf="interface != 'modal' && icon" [disabled]="disabled">
|
||||
<ion-icon [name]="icon" [attr.aria-label]="label" slot="start">
|
||||
</ion-icon>
|
||||
<ion-badge *ngIf="badge && badge > 0" slot="start">{{badge}}</ion-badge>
|
||||
<div class="select-icon" role="presentation" aria-hidden="true">
|
||||
<div class="select-icon-inner"></div>
|
||||
</div>
|
||||
|
@ -14,7 +13,6 @@
|
|||
<ion-button *ngIf="interface == 'modal'" aria-haspopup="listbox" [attr.aria-controls]="listboxId" [attr.aria-owns]="listboxId"
|
||||
[attr.aria-expanded]="expanded" (click)="openSelect()" [disabled]="disabled" expand="block" role="combobox">
|
||||
<ion-icon *ngIf="icon" [name]="icon" slot="start" aria-hidden="true"></ion-icon>
|
||||
<ion-badge *ngIf="badge && badge > 0" slot="start">{{badge}}</ion-badge>
|
||||
<span class="sr-only" *ngIf="label">{{ label }}:</span>
|
||||
<div class="select-text">
|
||||
<slot name="text">{{selection}}</slot>
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
"allparticipants": "All participants",
|
||||
"answer": "Answer",
|
||||
"answered": "Answered",
|
||||
"applyfilters": "Apply filters",
|
||||
"areyousure": "Are you sure?",
|
||||
"back": "Back",
|
||||
"browser": "Browser",
|
||||
|
|
|
@ -1020,10 +1020,16 @@ ion-select::part(icon) {
|
|||
opacity: 1;
|
||||
}
|
||||
|
||||
ion-select-popover ion-item.core-select-option-title {
|
||||
cursor: pointer;
|
||||
ion-radio {
|
||||
display: none;
|
||||
ion-select-popover {
|
||||
ion-item.core-select-option-border-bottom {
|
||||
border-bottom: 1px solid var(--stroke);
|
||||
}
|
||||
|
||||
ion-item.core-select-option-title {
|
||||
cursor: pointer;
|
||||
ion-radio {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue