diff --git a/src/addons/badges/pages/badge-class/badge-class.html b/src/addons/badges/pages/badge-class/badge-class.html index 28b8aabbdf3..4e71a3be291 100644 --- a/src/addons/badges/pages/badge-class/badge-class.html +++ b/src/addons/badges/pages/badge-class/badge-class.html @@ -4,8 +4,9 @@ - @if (badge) { -

{{ badge.name }}

+ @let badgeToShow = badge(); + @if (badgeToShow) { +

{{ badgeToShow.name }}

} @else {

{{ 'addon.badges.badgedetails' | translate }}

} @@ -13,68 +14,68 @@

{{ 'addon.badges.badgedetails' | translate }}

- + - - @if (badge) { + + @if (badgeToShow) { - @if (badge.image) { - + @if (badgeToShow.image) { + } - @if (badge.name) { + @if (badgeToShow.name) {

{{ 'core.name' | translate}}

-

{{ badge.name }}

+

{{ badgeToShow.name }}

} - @if (badge.issuer) { + @if (badgeToShow.issuer) {

{{ 'addon.badges.issuername' | translate}}

-

} - @if (badge.coursefullname) { + @if (badgeToShow.coursefullname) {

{{ 'core.course' | translate}}

- +

} - @if (badge.description) { + @if (badgeToShow.description) {

{{ 'core.description' | translate}}

-

{{ badge.description }}

+

{{ badgeToShow.description }}

}
- @if (badge.alignment?.length) { + @if (badgeToShow.alignment?.length) {

{{ 'addon.badges.alignment' | translate}}

-

{{ alignment.targetName }}

diff --git a/src/addons/badges/pages/badge-class/badge-class.ts b/src/addons/badges/pages/badge-class/badge-class.ts index 1af8131e333..e3023f439c4 100644 --- a/src/addons/badges/pages/badge-class/badge-class.ts +++ b/src/addons/badges/pages/badge-class/badge-class.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, OnInit, inject } from '@angular/core'; +import { Component, OnInit, inject, signal } from '@angular/core'; import { CorePromiseUtils } from '@singletons/promise-utils'; import { CoreNavigator } from '@services/navigator'; import { ActivatedRoute } from '@angular/router'; @@ -38,9 +38,8 @@ export default class AddonBadgesBadgeClassPage implements OnInit { protected badgeId = 0; protected logView: (badge: AddonBadgesBadgeClass) => void; - badge?: AddonBadgesBadgeClass; - badgeLoaded = false; - currentTime = 0; + readonly badge = signal(undefined); + readonly loaded = signal(false); constructor() { this.badgeId = CoreNavigator.getRequiredRouteNumberParam('badgeId'); @@ -59,22 +58,20 @@ export default class AddonBadgesBadgeClassPage implements OnInit { /** * @inheritdoc */ - ngOnInit(): void { - this.fetchBadgeClass().finally(() => { - this.badgeLoaded = true; - }); + async ngOnInit(): Promise { + await this.fetchBadgeClass(); + + this.loaded.set(true); } /** * Fetch the badge class required for the view. - * - * @returns Promise resolved when done. */ async fetchBadgeClass(): Promise { try { - this.badge = await AddonBadges.getBadgeClass(this.badgeId); - - this.logView(this.badge); + const badge = await AddonBadges.getBadgeClass(this.badgeId); + this.badge.set(badge); + this.logView(badge); } catch (message) { CoreAlerts.showError(message, { default: 'Error getting badge data.' }); } diff --git a/src/addons/badges/pages/issued-badge/issued-badge.html b/src/addons/badges/pages/issued-badge/issued-badge.html index 90835d20e46..afea17ec309 100644 --- a/src/addons/badges/pages/issued-badge/issued-badge.html +++ b/src/addons/badges/pages/issued-badge/issued-badge.html @@ -5,8 +5,9 @@

- @if (badge) { - + @let badgeToShow = badge(); + @if (badgeToShow) { + } @else { {{ 'addon.badges.badges' | translate }} } @@ -14,59 +15,62 @@

- - + + - - @if (badge) { + + @if (badgeToShow) { - @if (badge.badgeurl) { + @if (badgeToShow.badgeurl) {
- - @if (badge.dateexpire && currentTime >= badge.dateexpire) { + + @if (badgeToShow.dateexpire && currentTime() >= badgeToShow.dateexpire) { {{ 'addon.badges.expireddate' | translate:
-                                        {$a: (badge.dateexpire * 1000 | coreFormatDate)} }} + {$a: (badgeToShow.dateexpire * 1000 | coreFormatDate)} }}" /> }
}
- @if (badge.name) { + @if (badgeToShow.name) { -

+

}

- {{ 'addon.badges.awardedto' | translate: {$a: badge.recipientfullname } }} + {{ 'addon.badges.awardedto' | translate: {$a: badgeToShow.recipientfullname } }}

- @if (badge.dateissued || badge.dateexpire) { + @if (badgeToShow.dateissued || badgeToShow.dateexpire) { - @if (badge.dateissued) { + @if (badgeToShow.dateissued) {

- {{ 'addon.badges.issuedon' | translate: {$a: (badge.dateissued * 1000 | coreFormatDate)} }} + {{ 'addon.badges.issuedon' | translate: + {$a: (badgeToShow.dateissued * 1000 | coreFormatDate)} }}

} - @if (badge.dateexpire) { - @if (currentTime < badge.dateexpire) { + @if (badgeToShow.dateexpire) { + @if (currentTime() < badgeToShow.dateexpire) {

- {{ 'addon.badges.expiresin' | translate: {$a: (badge.dateexpire * 1000 | coreFormatDate)} }} + {{ 'addon.badges.expiresin' | translate: + {$a: (badgeToShow.dateexpire * 1000 | coreFormatDate)} }}

} @else {

- {{ 'addon.badges.expiredin' | translate: {$a: (badge.dateexpire * 1000 | coreFormatDate)} }} + {{ 'addon.badges.expiredin' | translate: + {$a: (badgeToShow.dateexpire * 1000 | coreFormatDate)} }}

} } @@ -74,21 +78,21 @@

} - @if (badge.issuername) { + @if (issuerWithMail()) { -

+

} - @if (badge.coursefullname) { + @if (badgeToShow.coursefullname) {

- +

@@ -97,10 +101,10 @@

- @if (badge.description) { + @if (badgeToShow.description) { -

{{ badge.description }}

+

{{ badgeToShow.description }}

} @@ -116,96 +120,96 @@

- @if (badge.version) { + @if (badgeToShow.version) {

{{ 'addon.badges.version' | translate}}

-

{{ badge.version }}

+

{{ badgeToShow.version }}

} - @if (badge.language) { + @if (badgeToShow.language) {

{{ 'addon.badges.language' | translate}}

-

{{ badge.language }}

+

{{ badgeToShow.language }}

} - @if (badge.imagecaption) { + @if (badgeToShow.imagecaption) {

{{ 'addon.badges.imagecaption' | translate}}

-

{{ badge.imagecaption }}

+

{{ badgeToShow.imagecaption }}

}
- @if (badge.endorsement) { + @if (badgeToShow.endorsement) {

{{ 'addon.badges.bendorsement' | translate}}

- @if (badge.endorsement.issuername) { + @if (badgeToShow.endorsement.issuername) {

{{ 'addon.badges.issuername' | translate}}

-

{{ badge.endorsement.issuername }}

+

{{ badgeToShow.endorsement.issuername }}

} - @if (badge.endorsement.issueremail) { + @if (badgeToShow.endorsement.issueremail) {

{{ 'addon.badges.issueremail' | translate}}

- - {{ badge.endorsement.issueremail }} + + {{ badgeToShow.endorsement.issueremail }}

} - @if (badge.endorsement.issuerurl) { + @if (badgeToShow.endorsement.issuerurl) {

{{ 'addon.badges.issuerurl' | translate}}

-

- {{ badge.endorsement.issuerurl }} +

+ {{ badgeToShow.endorsement.issuerurl }}

} - @if (badge.endorsement.dateissued) { + @if (badgeToShow.endorsement.dateissued) {

{{ 'addon.badges.dateawarded' | translate}}

-

{{ badge.endorsement.dateissued * 1000 | coreFormatDate }}

+

{{ badgeToShow.endorsement.dateissued * 1000 | coreFormatDate }}

} - @if (badge.endorsement.claimid) { + @if (badgeToShow.endorsement.claimid) {

{{ 'addon.badges.claimid' | translate}}

-

- {{ badge.endorsement.claimid }} +

+ {{ badgeToShow.endorsement.claimid }}

} - @if (badge.endorsement.claimcomment) { + @if (badgeToShow.endorsement.claimcomment) {

{{ 'addon.badges.claimcomment' | translate}}

-

{{ badge.endorsement.claimcomment }}

+

{{ badgeToShow.endorsement.claimcomment }}

} @@ -213,14 +217,14 @@

{{ 'addon.badges.bendorsement' | translate}}

} - @if (badge.relatedbadges?.length > 0) { + @if (badgeToShow.relatedbadges?.length > 0) {

{{ 'addon.badges.relatedbages' | translate}}

- @for (relatedBadge of badge.relatedbadges; track relatedBadge.id) { + @for (relatedBadge of badgeToShow.relatedbadges; track relatedBadge.id) {

{{ relatedBadge.name }}

@@ -231,14 +235,14 @@

{{ 'addon.badges.relatedbages' | translate}}

} - @if (badge.alignment?.length > 0) { + @if (badgeToShow.alignment?.length > 0) {

{{ 'addon.badges.alignment' | translate}}

- @for (alignment of badge.alignment; track alignment.id) { + @for (alignment of badgeToShow.alignment; track alignment.id) {

{{ alignment.targetName }}

diff --git a/src/addons/badges/pages/issued-badge/issued-badge.ts b/src/addons/badges/pages/issued-badge/issued-badge.ts index 841238b5469..2d4d5f39b77 100644 --- a/src/addons/badges/pages/issued-badge/issued-badge.ts +++ b/src/addons/badges/pages/issued-badge/issued-badge.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, OnDestroy, OnInit, inject } from '@angular/core'; +import { Component, OnDestroy, OnInit, computed, inject, signal } from '@angular/core'; import { CoreSites } from '@services/sites'; import { CoreUser } from '@features/user/services/user'; import { AddonBadges, AddonBadgesUserBadge } from '../../services/badges'; @@ -41,23 +41,31 @@ import { CoreAlerts } from '@services/overlays/alerts'; }) export default class AddonBadgesIssuedBadgePage implements OnInit, OnDestroy { + readonly courseId = CoreNavigator.getRouteNumberParam('courseId') || 0; // Use 0 for site badges. + protected readonly badgeHash = CoreNavigator.getRouteParam('badgeHash') || ''; + protected readonly userId = CoreNavigator.getRouteNumberParam('userId') || CoreSites.getRequiredCurrentSite().getUserId(); + protected route = inject(ActivatedRoute); - protected badgeHash = ''; - protected userId!: number; protected logView: (badge: AddonBadgesUserBadge) => void; - courseId = 0; - badge?: AddonBadgesUserBadge; - issuerWithMail = ''; - badges?: CoreSwipeNavigationItemsManager; - badgeLoaded = false; - currentTime = 0; + readonly badge = signal(undefined); + readonly issuerWithMail = computed(() => { + const badge = this.badge(); - constructor() { - this.courseId = CoreNavigator.getRouteNumberParam('courseId') || this.courseId; // Use 0 for site badges. - this.userId = CoreNavigator.getRouteNumberParam('userId') || CoreSites.getRequiredCurrentSite().getUserId(); - this.badgeHash = CoreNavigator.getRouteParam('badgeHash') || ''; + if (!badge?.issuername) { + return ''; + } + + return badge.issuercontact ? + '' + badge.issuername + '' + : badge.issuername; + }); + readonly badges = signal(undefined); + readonly loaded = signal(false); + readonly currentTime = signal(0); + + constructor() { const routeData = CoreNavigator.getRouteData(this.route); if (routeData.usesSwipeNavigation) { const source = CoreRoutedItemsManagerSourcesTracker.getOrCreateSource( @@ -65,7 +73,7 @@ export default class AddonBadgesIssuedBadgePage implements OnInit, OnDestroy { [this.courseId, this.userId], ); - this.badges = new CoreSwipeNavigationItemsManager(source); + this.badges.set(new CoreSwipeNavigationItemsManager(source)); } this.logView = CoreTime.once((badge) => { @@ -84,17 +92,17 @@ export default class AddonBadgesIssuedBadgePage implements OnInit, OnDestroy { */ ngOnInit(): void { this.fetchIssuedBadge().finally(() => { - this.badgeLoaded = true; + this.loaded.set(true); }); - this.badges?.start(); + this.badges()?.start(); } /** * @inheritdoc */ ngOnDestroy(): void { - this.badges?.destroy(); + this.badges()?.destroy(); } /** @@ -104,12 +112,12 @@ export default class AddonBadgesIssuedBadgePage implements OnInit, OnDestroy { */ async fetchIssuedBadge(): Promise { const site = CoreSites.getRequiredCurrentSite(); - this.currentTime = CoreTime.timestamp(); + this.currentTime.set(CoreTime.timestamp()); try { // Search the badge in the user badges. const badges = await AddonBadges.getUserBadges(this.courseId, this.userId); - let badge = badges.find((badge) => this.badgeHash == badge.uniquehash); + let badge = badges.find((badge) => this.badgeHash === badge.uniquehash); if (badge) { if (!site.isVersionGreaterEqualThan('4.5')) { @@ -138,11 +146,7 @@ export default class AddonBadgesIssuedBadgePage implements OnInit, OnDestroy { } } - this.issuerWithMail = badge.issuercontact ? - '' + badge.issuername + '' - : badge.issuername; - - this.badge = badge; + this.badge.set(badge); this.logView(badge); } catch (message) { @@ -161,9 +165,7 @@ export default class AddonBadgesIssuedBadgePage implements OnInit, OnDestroy { AddonBadges.invalidateUserBadgeByHash(this.badgeHash), ]); - await CorePromiseUtils.ignoreErrors(Promise.all([ - this.fetchIssuedBadge(), - ])); + await CorePromiseUtils.ignoreErrors(this.fetchIssuedBadge()); refresher?.complete(); } diff --git a/src/addons/badges/pages/user-badges/user-badges.html b/src/addons/badges/pages/user-badges/user-badges.html index a616d26e4db..b46723bc50b 100644 --- a/src/addons/badges/pages/user-badges/user-badges.html +++ b/src/addons/badges/pages/user-badges/user-badges.html @@ -10,29 +10,31 @@

{{ 'addon.badges.badges' | translate }}

- + - - @if (badges.empty) { + + @if (badges().empty) { } @else { - - - - - -

{{ badge.name }}

-

{{ badge.dateissued * 1000 | coreFormatDate :'strftimedatetimeshort' }}

-
- @if (badge.dateexpire && currentTime >= badge.dateexpire) { - - {{ 'addon.badges.expired' | translate }} - - } -
+ @for (badge of badges().items; track badge.uniquehash) { + + + + + +

{{ badge.name }}

+

{{ badge.dateissued * 1000 | coreFormatDate :'strftimedatetimeshort' }}

+
+ @if (badge.dateexpire && currentTime() >= badge.dateexpire) { + + {{ 'addon.badges.expired' | translate }} + + } +
+ }
}
diff --git a/src/addons/badges/pages/user-badges/user-badges.ts b/src/addons/badges/pages/user-badges/user-badges.ts index 8b28cf92bd0..db5251f48b9 100644 --- a/src/addons/badges/pages/user-badges/user-badges.ts +++ b/src/addons/badges/pages/user-badges/user-badges.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { AfterViewInit, Component, OnDestroy, viewChild } from '@angular/core'; +import { AfterViewInit, Component, OnDestroy, signal, viewChild, WritableSignal } from '@angular/core'; import { AddonBadges, AddonBadgesUserBadge } from '../../services/badges'; import { CoreSites } from '@services/sites'; import { CorePromiseUtils } from '@singletons/promise-utils'; @@ -39,33 +39,35 @@ import { CoreSharedModule } from '@/core/shared.module'; }) export default class AddonBadgesUserBadgesPage implements AfterViewInit, OnDestroy { - currentTime = 0; - badges: CoreListItemsManager; + readonly currentTime = signal(0); + readonly badges: WritableSignal>; readonly splitView = viewChild.required(CoreSplitViewComponent); protected logView: () => void; + protected courseId: number; + protected userId: number; constructor() { - let courseId = CoreNavigator.getRouteNumberParam('courseId') ?? 0; // Use 0 for site badges. - const userId = CoreNavigator.getRouteNumberParam('userId') ?? CoreSites.getCurrentSiteUserId(); + this.courseId = CoreNavigator.getRouteNumberParam('courseId') ?? 0; // Use 0 for site badges. + this.userId = CoreNavigator.getRouteNumberParam('userId') ?? CoreSites.getCurrentSiteUserId(); - if (courseId === CoreSites.getCurrentSiteHomeId()) { + if (this.courseId === CoreSites.getCurrentSiteHomeId()) { // Use courseId 0 for site home, otherwise the site doesn't return site badges. - courseId = 0; + this.courseId = 0; } - this.badges = new CoreListItemsManager( - CoreRoutedItemsManagerSourcesTracker.getOrCreateSource(AddonBadgesUserBadgesSource, [courseId, userId]), + this.badges = signal(new CoreListItemsManager( + CoreRoutedItemsManagerSourcesTracker.getOrCreateSource(AddonBadgesUserBadgesSource, [this.courseId, this. userId]), AddonBadgesUserBadgesPage, - ); + )); this.logView = CoreTime.once(() => { CoreAnalytics.logEvent({ type: CoreAnalyticsEventType.VIEW_ITEM_LIST, ws: 'core_badges_view_user_badges', name: Translate.instant('addon.badges.badges'), - data: { courseId: this.badges.getSource().courseId, category: 'badges' }, + data: { courseId: this.courseId, category: 'badges' }, url: '/badges/mybadges.php', }); }); @@ -77,14 +79,14 @@ export default class AddonBadgesUserBadgesPage implements AfterViewInit, OnDestr async ngAfterViewInit(): Promise { await this.fetchInitialBadges(); - this.badges.start(this.splitView()); + this.badges().start(this.splitView()); } /** * @inheritdoc */ ngOnDestroy(): void { - this.badges.destroy(); + this.badges().destroy(); } /** @@ -94,12 +96,9 @@ export default class AddonBadgesUserBadgesPage implements AfterViewInit, OnDestr */ async refreshBadges(refresher?: HTMLIonRefresherElement): Promise { await CorePromiseUtils.ignoreErrors( - AddonBadges.invalidateUserBadges( - this.badges.getSource().courseId, - this.badges.getSource().userId, - ), + AddonBadges.invalidateUserBadges(this.courseId, this.userId), ); - await CorePromiseUtils.ignoreErrors(this.badges.reload()); + await CorePromiseUtils.ignoreErrors(this.badges().reload()); refresher?.complete(); } @@ -108,16 +107,16 @@ export default class AddonBadgesUserBadgesPage implements AfterViewInit, OnDestr * Obtain the initial list of badges. */ private async fetchInitialBadges(): Promise { - this.currentTime = CoreTime.timestamp(); + this.currentTime.set(CoreTime.timestamp()); try { - await this.badges.reload(); + await this.badges().reload(); this.logView(); } catch (message) { CoreAlerts.showError(message, { default: 'Error loading badges' }); - this.badges.reset(); + this.badges().reset(); } } diff --git a/src/addons/badges/services/badges-helper.ts b/src/addons/badges/services/badges-helper.ts index 9b3a27ed2df..9f432582eff 100644 --- a/src/addons/badges/services/badges-helper.ts +++ b/src/addons/badges/services/badges-helper.ts @@ -45,9 +45,8 @@ export class AddonBadgesHelperProvider { // Open in app if badge is one of the user badges. const badges = await AddonBadges.getUserBadges(0, site.getUserId()); - const badge = badges.find((badge) => badgeHash == badge.uniquehash); - return badge !== undefined; + return badges.some((badge) => badgeHash === badge.uniquehash); } } diff --git a/src/addons/badges/services/badges.ts b/src/addons/badges/services/badges.ts index 74573d60538..0f0cf39d498 100644 --- a/src/addons/badges/services/badges.ts +++ b/src/addons/badges/services/badges.ts @@ -101,7 +101,6 @@ export class AddonBadgesProvider { * @param courseId Course ID. * @param userId ID of the user to get the badges from. * @param siteId Site ID. If not defined, current site. - * @returns Promise resolved when data is invalidated. */ async invalidateUserBadges(courseId: number, userId: number, siteId?: string): Promise { const site = await CoreSites.getSite(siteId); @@ -157,7 +156,6 @@ export class AddonBadgesProvider { * * @param hash Badge issued hash. * @param siteId Site ID. If not defined, current site. - * @returns Promise resolved when data is invalidated. */ async invalidateUserBadgeByHash(hash: string, siteId?: string): Promise { const site = await CoreSites.getSite(siteId); @@ -214,7 +212,6 @@ export class AddonBadgesProvider { * * @param id Badge ID. * @param siteId Site ID. If not defined, current site. - * @returns Promise resolved when data is invalidated.รง * @since 4.5 */ async invalidateBadgeClass(id: number, siteId?: string): Promise { diff --git a/src/addons/calendar/pages/day/day.html b/src/addons/calendar/pages/day/day.html index d7f41c782d5..0d123ba097b 100644 --- a/src/addons/calendar/pages/day/day.html +++ b/src/addons/calendar/pages/day/day.html @@ -15,7 +15,7 @@

{{ 'addon.calendar.calendarevents' | translate }}

} - diff --git a/src/addons/calendar/pages/day/day.ts b/src/addons/calendar/pages/day/day.ts index 4ba91081e59..e2a227c7595 100644 --- a/src/addons/calendar/pages/day/day.ts +++ b/src/addons/calendar/pages/day/day.ts @@ -28,10 +28,9 @@ import { AddonCalendarSync } from '../../services/calendar-sync'; import { CoreCategoryData, CoreCourses, CoreEnrolledCourseData } from '@features/courses/services/courses'; import { CoreCoursesHelper } from '@features/courses/services/courses-helper'; import { dayjs, Dayjs } from '@/core/utils/dayjs'; -import { NgZone, Translate } from '@singletons'; +import { Translate } from '@singletons'; import { CoreNavigator } from '@services/navigator'; import { Params } from '@angular/router'; -import { Subscription } from 'rxjs'; import { CoreArray } from '@singletons/array'; import { CoreConstants } from '@/core/constants'; import { CoreSwipeSlidesDynamicItemsManager } from '@classes/items-management/swipe-slides-dynamic-items-manager'; @@ -80,14 +79,13 @@ export default class AddonCalendarDayPage implements OnInit, OnDestroy { // Observers. protected eventObservers: CoreEventObserver[] = []; - protected onlineObserver: Subscription; protected managerUnsubscribe?: () => void; protected logView: () => void; periodName?: string; manager?: CoreSwipeSlidesDynamicItemsManager; loaded = false; - isOnline = false; + readonly isOnline = CoreNetwork.onlineSignal(); syncIcon = CoreConstants.ICON_LOADING; filter: AddonCalendarFilter = { filtered: false, @@ -189,14 +187,6 @@ export default class AddonCalendarDayPage implements OnInit, OnDestroy { }, )); - // Refresh online status when changes. - this.onlineObserver = CoreNetwork.onChange().subscribe(() => { - // Execute the callback in the Angular zone, so change detection doesn't stop working. - NgZone.run(() => { - this.isOnline = CoreNetwork.isOnline(); - }); - }); - this.logView = CoreTime.once(() => { const day = this.manager?.getSelectedItem(); if (!day) { @@ -268,7 +258,6 @@ export default class AddonCalendarDayPage implements OnInit, OnDestroy { */ async fetchData(sync?: boolean): Promise { this.syncIcon = CoreConstants.ICON_LOADING; - this.isOnline = CoreNetwork.isOnline(); if (sync) { await this.sync(); @@ -484,7 +473,6 @@ export default class AddonCalendarDayPage implements OnInit, OnDestroy { */ ngOnDestroy(): void { this.eventObservers.forEach((observer) => observer.off()); - this.onlineObserver?.unsubscribe(); this.manager?.getSource().forgetRelatedSources(); this.manager?.destroy(); this.managerUnsubscribe?.(); diff --git a/src/addons/calendar/pages/event/event.html b/src/addons/calendar/pages/event/event.html index 9e084c81542..6ddb77ecfbf 100644 --- a/src/addons/calendar/pages/event/event.html +++ b/src/addons/calendar/pages/event/event.html @@ -13,7 +13,7 @@

- { - // Execute the callback in the Angular zone, so change detection doesn't stop working. - NgZone.run(() => { - this.isOnline = CoreNetwork.isOnline(); - }); - }); - // Reload reminders if default notification time changes. this.defaultTimeChangedObserver = CoreEvents.on(REMINDERS_DEFAULT_NOTIFICATION_TIME_CHANGED, () => { this.loadReminders(); @@ -215,7 +206,6 @@ export default class AddonCalendarEventPage implements OnInit, OnDestroy { * @returns Promise resolved when done. */ async fetchEvent(sync = false, showErrors = false): Promise { - this.isOnline = CoreNetwork.isOnline(); if (sync) { const deleted = await this.syncEvents(showErrors); @@ -685,7 +675,6 @@ export default class AddonCalendarEventPage implements OnInit, OnDestroy { this.editEventObserver.off(); this.syncObserver.off(); this.manualSyncObserver.off(); - this.onlineObserver.unsubscribe(); this.newEventObserver.off(); this.events?.destroy(); this.appResumeSubscription.unsubscribe(); diff --git a/src/addons/calendar/pages/index/index.html b/src/addons/calendar/pages/index/index.html index e20082c93fa..b7511c397f2 100644 --- a/src/addons/calendar/pages/index/index.html +++ b/src/addons/calendar/pages/index/index.html @@ -23,7 +23,7 @@

{{ 'addon.calendar.calendar' | translate }}

} -
diff --git a/src/addons/calendar/pages/index/index.ts b/src/addons/calendar/pages/index/index.ts index b1bfa57cd92..fd5ce539613 100644 --- a/src/addons/calendar/pages/index/index.ts +++ b/src/addons/calendar/pages/index/index.ts @@ -21,8 +21,7 @@ import { AddonCalendar } from '../../services/calendar'; import { AddonCalendarOffline } from '../../services/calendar-offline'; import { AddonCalendarSync } from '../../services/calendar-sync'; import { AddonCalendarFilter, AddonCalendarHelper } from '../../services/calendar-helper'; -import { NgZone, Translate } from '@singletons'; -import { Subscription } from 'rxjs'; +import { Translate } from '@singletons'; import { CoreEnrolledCourseData } from '@features/courses/services/courses'; import { ActivatedRoute, Params } from '@angular/router'; import { AddonCalendarCalendarComponent } from '../../components/calendar/calendar'; @@ -73,7 +72,6 @@ export default class AddonCalendarIndexPage implements OnInit, OnDestroy { protected undeleteEventObserver?: CoreEventObserver; protected syncObserver?: CoreEventObserver; protected manualSyncObserver?: CoreEventObserver; - protected onlineObserver?: Subscription; protected filterChangedObserver?: CoreEventObserver; protected route = inject(ActivatedRoute); @@ -83,7 +81,7 @@ export default class AddonCalendarIndexPage implements OnInit, OnDestroy { courses: CoreEnrolledCourseData[] = []; loaded = false; hasOffline = false; - isOnline = false; + readonly isOnline = CoreNetwork.onlineSignal(); syncIcon = CoreConstants.ICON_LOADING; showCalendar = true; loadUpcoming = false; @@ -165,14 +163,6 @@ export default class AddonCalendarIndexPage implements OnInit, OnDestroy { this.canCreate = await AddonCalendarHelper.canEditEvents(this.filter.courseId); }, ); - - // Refresh online status when changes. - this.onlineObserver = CoreNetwork.onChange().subscribe(() => { - // Execute the callback in the Angular zone, so change detection doesn't stop working. - NgZone.run(() => { - this.isOnline = CoreNetwork.isOnline(); - }); - }); } /** @@ -209,7 +199,6 @@ export default class AddonCalendarIndexPage implements OnInit, OnDestroy { async fetchData(sync?: boolean, showErrors?: boolean): Promise { this.syncIcon = CoreConstants.ICON_LOADING; - this.isOnline = CoreNetwork.isOnline(); let refreshComponent = false; @@ -418,7 +407,6 @@ export default class AddonCalendarIndexPage implements OnInit, OnDestroy { this.syncObserver?.off(); this.manualSyncObserver?.off(); this.filterChangedObserver?.off(); - this.onlineObserver?.unsubscribe(); } } diff --git a/src/addons/coursecompletion/constants.ts b/src/addons/coursecompletion/constants.ts new file mode 100644 index 00000000000..34b2307f1b9 --- /dev/null +++ b/src/addons/coursecompletion/constants.ts @@ -0,0 +1,35 @@ +// (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. + +/** + * Course completion criteria aggregation method. + */ +export enum AddonCourseCompletionAggregation { + ALL = 1, + ANY = 2, +} + +/** + * Criteria type constant, primarily for storing criteria type in the database. + */ +export enum AddonCourseCompletionCriteriaType { + SELF = 1, // Self completion criteria type. + DATE = 2, // Date completion criteria type. + UNENROL = 3, // Unenrol completion criteria type. + ACTIVITY = 4, // Activity completion criteria type. + DURATION = 5, // Duration completion criteria type. + GRADE = 6, // Grade completion criteria type. + ROLE = 7, // Role completion criteria type. + COURSE = 8, // Course completion criteria type. +} diff --git a/src/addons/coursecompletion/pages/report/report.html b/src/addons/coursecompletion/pages/report/report.html index e5f06895d6b..5a41a438035 100644 --- a/src/addons/coursecompletion/pages/report/report.html +++ b/src/addons/coursecompletion/pages/report/report.html @@ -9,34 +9,35 @@

{{ 'addon.coursecompletion.coursecompletion' | translate }}

- + - - @if (user) { + + @let userDisplay = user(); + @if (userDisplay) { - + -

{{user.fullname}}

+

{{userDisplay.fullname}}

} - @if (completion && tracked) { + @let completionDisplay = completion(); + @if (completionDisplay && tracked()) {

{{ 'addon.coursecompletion.status' | translate }}

-

{{ statusText! | translate }}

+

{{ statusText() | translate }}

{{ 'addon.coursecompletion.required' | translate }}

- @if (completion.aggregation === 1) { + @if (completionDisplay.aggregation === aggregationType.ALL) {

{{ 'addon.coursecompletion.criteriarequiredall' | translate }}

- } - @if (completion.aggregation === 2) { + } @else if (completionDisplay.aggregation === aggregationType.ANY) {

{{ 'addon.coursecompletion.criteriarequiredany' | translate }}

}
@@ -48,21 +49,25 @@

{{ 'addon.coursecompletion.coursecompletion' | translate }}

{{ 'addon.coursecompletion.requiredcriteria' | translate }}

- - -

- -

-

- -

-
- @if (criteria.complete) { - {{ 'core.yes' | translate }} - } @else { - {{ 'core.no' | translate }} - } -
+ @for (criteria of completionDisplay.completions; track criteria) { + + +

+ +

+

+ +

+
+ + @if (criteria.complete) { + {{ 'core.yes' | translate }} + } @else { + {{ 'core.no' | translate }} + } + +
+ } @@ -73,7 +78,8 @@

{{ 'addon.coursecompletion.requiredcriteria' | translate }}

{{ 'addon.coursecompletion.complete' | translate }} {{ 'addon.coursecompletion.completiondate' | translate }}
- + @for (criteria of completionDisplay.completions; track criteria) { + @@ -86,24 +92,25 @@

{{ 'addon.coursecompletion.requiredcriteria' | translate }}

- @if (criteria.complete) { - {{ 'core.yes' | translate }} - } @else { - {{ 'core.no' | translate }} - } - @if (criteria.timecompleted) { - + + @if (criteria.complete) { + {{ 'core.yes' | translate }} + } @else { + {{ 'core.no' | translate }} + } + + + @if (criteria.timecompleted) { {{ criteria.timecompleted * 1000 | coreFormatDate :'strftimedatetimeshort' }} - - } @else { - - } + } +
+ }
} - @if (showSelfComplete && tracked) { + @if (showSelfComplete() && tracked()) { @@ -118,7 +125,7 @@

{{ 'addon.coursecompletion.manualselfcompletion' | translate }}

- } @else if (!tracked) { + } @else if (!tracked()) {