diff --git a/scripts/langindex.json b/scripts/langindex.json index aba8a3680..93ec25362 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -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", diff --git a/src/addons/block/myoverview/components/components.module.ts b/src/addons/block/myoverview/components/components.module.ts index 49e53a2f4..c1829bd61 100644 --- a/src/addons/block/myoverview/components/components.module.ts +++ b/src/addons/block/myoverview/components/components.module.ts @@ -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, diff --git a/src/addons/block/myoverview/components/filteroptions/filteroptions.html b/src/addons/block/myoverview/components/filteroptions/filteroptions.html deleted file mode 100644 index 2a6caf36b..000000000 --- a/src/addons/block/myoverview/components/filteroptions/filteroptions.html +++ /dev/null @@ -1,58 +0,0 @@ - - - -

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

-
- - - - - -
-
- - - - - {{'addon.block_myoverview.all' | translate}} - - - - {{'addon.block_myoverview.inprogress' | translate}} - - - - {{'addon.block_myoverview.future' | translate}} - - - - {{'addon.block_myoverview.past' | translate}} - - - - - - - - {{customOption.name}} - - - - - - - {{ 'addon.block_myoverview.aria:favourites' | translate }} - - - - - {{ 'addon.block_myoverview.aria:hiddencourses' | translate }} - - - - - - - {{ 'core.applyfilters' | translate }} - - diff --git a/src/addons/block/myoverview/components/filteroptions/filteroptions.scss b/src/addons/block/myoverview/components/filteroptions/filteroptions.scss deleted file mode 100644 index 166260056..000000000 --- a/src/addons/block/myoverview/components/filteroptions/filteroptions.scss +++ /dev/null @@ -1,8 +0,0 @@ -ion-footer { - &::before { - display: none; - } - ion-button { - margin: 0; - } -} diff --git a/src/addons/block/myoverview/components/filteroptions/filteroptions.ts b/src/addons/block/myoverview/components/filteroptions/filteroptions.ts deleted file mode 100644 index ad77d9a5b..000000000 --- a/src/addons/block/myoverview/components/filteroptions/filteroptions.ts +++ /dev/null @@ -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(); - } - -} diff --git a/src/addons/block/myoverview/components/myoverview/addon-block-myoverview.html b/src/addons/block/myoverview/components/myoverview/addon-block-myoverview.html index f2a0b892e..d4328e235 100644 --- a/src/addons/block/myoverview/components/myoverview/addon-block-myoverview.html +++ b/src/addons/block/myoverview/components/myoverview/addon-block-myoverview.html @@ -26,20 +26,51 @@ + (ionCancel)="filterTextChanged($event.target)" [placeholder]="'core.courses.filtermycourses' | translate"> - + + + {{ 'addon.block_myoverview.allincludinghidden' | translate }} + + + {{ 'addon.block_myoverview.all' | translate }} + + + {{ 'addon.block_myoverview.inprogress' | translate }} + + + {{ 'addon.block_myoverview.future' | translate }} + + + {{ 'addon.block_myoverview.past' | translate }} + + + + + {{ customOption.name }} + + + + {{ 'addon.block_myoverview.favourites' | translate }} + + + {{ 'addon.block_myoverview.hiddencourses' | translate }} + + (ionCancel)="filterTextChanged($event.target)" [placeholder]="'core.courses.filtermycourses' | translate"> diff --git a/src/addons/block/myoverview/components/myoverview/myoverview.ts b/src/addons/block/myoverview/components/myoverview/myoverview.ts index d54b6c3b6..14bb2c6ff 100644 --- a/src/addons/block/myoverview/components/myoverview/myoverview.ts +++ b/src/addons/block/myoverview/components/myoverview/myoverview.ts @@ -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( + 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 { - 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 { + async saveFilters(timeFilter: string): Promise { 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 { + 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 = { diff --git a/src/addons/block/myoverview/lang.json b/src/addons/block/myoverview/lang.json index 8030a7813..40c94300b 100644 --- a/src/addons/block/myoverview/lang.json +++ b/src/addons/block/myoverview/lang.json @@ -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", diff --git a/src/core/components/combobox/combobox.ts b/src/core/components/combobox/combobox.ts index 32e56a904..83d1f4877 100644 --- a/src/core/components/combobox/combobox.ts +++ b/src/core/components/combobox/combobox.ts @@ -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 = ''; diff --git a/src/core/components/combobox/core-combobox.html b/src/core/components/combobox/core-combobox.html index baa897fa3..02b0cec27 100644 --- a/src/core/components/combobox/core-combobox.html +++ b/src/core/components/combobox/core-combobox.html @@ -1,7 +1,6 @@ - {{badge}} @@ -14,7 +13,6 @@ - {{badge}} {{ label }}:
{{selection}} diff --git a/src/core/lang.json b/src/core/lang.json index a66c1a6a3..7429c930b 100644 --- a/src/core/lang.json +++ b/src/core/lang.json @@ -9,7 +9,6 @@ "allparticipants": "All participants", "answer": "Answer", "answered": "Answered", - "applyfilters": "Apply filters", "areyousure": "Are you sure?", "back": "Back", "browser": "Browser", diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss index a162e6c0a..e135701a0 100644 --- a/src/theme/theme.base.scss +++ b/src/theme/theme.base.scss @@ -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; + } } }