From 7ee332445515cc79cf93356c4301cad2efe0c8f2 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 20 Oct 2021 12:02:39 +0200 Subject: [PATCH] MOBILE-3829 notifications: Display notification clicked in new page --- .../notifications-lazy.module.ts | 5 ++ src/addons/notifications/pages/list/list.ts | 45 ++-------- .../pages/notification/notification.html | 30 +++++++ .../pages/notification/notification.module.ts | 40 +++++++++ .../pages/notification/notification.ts | 90 +++++++++++++++++++ .../services/handlers/push-click.ts | 10 ++- .../services/notifications-helper.ts | 39 ++++++++ .../login/pages/reconnect/reconnect.ts | 2 +- 8 files changed, 221 insertions(+), 40 deletions(-) create mode 100644 src/addons/notifications/pages/notification/notification.html create mode 100644 src/addons/notifications/pages/notification/notification.module.ts create mode 100644 src/addons/notifications/pages/notification/notification.ts diff --git a/src/addons/notifications/notifications-lazy.module.ts b/src/addons/notifications/notifications-lazy.module.ts index 2e0aa2445..11879c29a 100644 --- a/src/addons/notifications/notifications-lazy.module.ts +++ b/src/addons/notifications/notifications-lazy.module.ts @@ -27,6 +27,11 @@ function buildRoutes(injector: Injector): Routes { }, loadChildren: () => import('./pages/list/list.module').then(m => m.AddonNotificationsListPageModule), }, + { + path: 'notification', + loadChildren: () => import('./pages/notification/notification.module') + .then(m => m.AddonNotificationsNotificationPageModule), + }, ...buildTabMainRoutes(injector, { redirectTo: 'list', pathMatch: 'full', diff --git a/src/addons/notifications/pages/list/list.ts b/src/addons/notifications/pages/list/list.ts index 59f83b549..23d0bc820 100644 --- a/src/addons/notifications/pages/list/list.ts +++ b/src/addons/notifications/pages/list/list.ts @@ -18,15 +18,17 @@ import { Subscription } from 'rxjs'; import { CoreSites } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; -import { CoreTextUtils } from '@services/utils/text'; import { CoreUtils } from '@services/utils/utils'; import { CoreEvents, CoreEventObserver } from '@singletons/events'; import { AddonNotifications, - AddonNotificationsNotificationMessageFormatted, AddonNotificationsProvider, } from '../../services/notifications'; import { CorePushNotificationsDelegate } from '@features/pushnotifications/services/push-delegate'; +import { + AddonNotificationsHelper, + AddonNotificationsNotificationToRender, +} from '@addons/notifications/services/notifications-helper'; /** * Page that displays the list of notifications. @@ -38,7 +40,7 @@ import { CorePushNotificationsDelegate } from '@features/pushnotifications/servi }) export class AddonNotificationsListPage implements OnInit, OnDestroy { - notifications: FormattedNotification[] = []; + notifications: AddonNotificationsNotificationToRender[] = []; notificationsLoaded = false; canLoadMore = false; loadMoreError = false; @@ -94,7 +96,8 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy { try { const result = await AddonNotifications.getNotifications(refresh ? [] : this.notifications); - const notifications = result.notifications.map((notification) => this.formatText(notification)); + const notifications = result.notifications + .map((notification) => AddonNotificationsHelper.formatNotificationText(notification)); if (refresh) { this.notifications = notifications; @@ -135,7 +138,7 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy { * * @param notifications Array of notification objects. */ - protected async markNotificationsAsRead(notifications: FormattedNotification[]): Promise { + protected async markNotificationsAsRead(notifications: AddonNotificationsNotificationToRender[]): Promise { if (notifications.length > 0) { const promises = notifications.map(async (notification) => { if (notification.read) { @@ -194,33 +197,6 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy { } } - /** - * Formats the text of a notification. - * - * @param notification The notification object. - */ - protected formatText(notification: AddonNotificationsNotificationMessageFormatted): FormattedNotification { - const formattedNotification: FormattedNotification = notification; - formattedNotification.displayfullhtml = this.shouldDisplayFullHtml(notification); - formattedNotification.iconurl = formattedNotification.iconurl || undefined; // Make sure the property exists. - - formattedNotification.mobiletext = formattedNotification.displayfullhtml ? - notification.fullmessagehtml : - CoreTextUtils.replaceNewLines((formattedNotification.mobiletext || '').replace(/-{4,}/ig, ''), '
'); - - return formattedNotification; - } - - /** - * Check whether we should display full HTML of the notification. - * - * @param notification Notification. - * @return Whether to display full HTML. - */ - protected shouldDisplayFullHtml(notification: FormattedNotification): boolean { - return notification.component == 'mod_forum' && notification.eventtype == 'digests'; - } - /** * User entered the page. */ @@ -253,8 +229,3 @@ export class AddonNotificationsListPage implements OnInit, OnDestroy { } } - -type FormattedNotification = AddonNotificationsNotificationMessageFormatted & { - displayfullhtml?: boolean; // Whether to display the full HTML of the notification. - iconurl?: string; -}; diff --git a/src/addons/notifications/pages/notification/notification.html b/src/addons/notifications/pages/notification/notification.html new file mode 100644 index 000000000..e4d879bb6 --- /dev/null +++ b/src/addons/notifications/pages/notification/notification.html @@ -0,0 +1,30 @@ + + + + + +

{{ 'addon.notifications.notifications' | translate }}

+
+
+ + + + + + + + +

{{ subject }}

+

{{ userFromFullName }}

+
+
+ + + + + + +
+
diff --git a/src/addons/notifications/pages/notification/notification.module.ts b/src/addons/notifications/pages/notification/notification.module.ts new file mode 100644 index 000000000..b316d8bd4 --- /dev/null +++ b/src/addons/notifications/pages/notification/notification.module.ts @@ -0,0 +1,40 @@ +// (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 { AddonNotificationsComponentsModule } from '../../components/components.module'; +import { AddonNotificationsNotificationPage } from './notification'; + +const routes: Routes = [ + { + path: '', + component: AddonNotificationsNotificationPage, + }, +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes), + CoreSharedModule, + AddonNotificationsComponentsModule, + ], + declarations: [ + AddonNotificationsNotificationPage, + ], + exports: [RouterModule], +}) +export class AddonNotificationsNotificationPageModule {} diff --git a/src/addons/notifications/pages/notification/notification.ts b/src/addons/notifications/pages/notification/notification.ts new file mode 100644 index 000000000..6b400b795 --- /dev/null +++ b/src/addons/notifications/pages/notification/notification.ts @@ -0,0 +1,90 @@ +// (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 { AddonNotificationsNotificationData } from '@addons/notifications/services/handlers/push-click'; +import { AddonNotifications } from '@addons/notifications/services/notifications'; +import { + AddonNotificationsHelper, + AddonNotificationsNotificationToRender, +} from '@addons/notifications/services/notifications-helper'; +import { Component, OnInit } from '@angular/core'; +import { CoreNavigator } from '@services/navigator'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreUtils } from '@services/utils/utils'; + +/** + * Page to render a notification. + */ +@Component({ + selector: 'page-addon-notifications-notification', + templateUrl: 'notification.html', +}) +export class AddonNotificationsNotificationPage implements OnInit { + + subject = ''; // Notification subject. + content = ''; // Notification content. + userIdFrom = -1; // User ID who sent the notification. + profileImageUrlFrom?: string; // Avatar of the user who sent the notification. + userFromFullName?: string; // Name of the user who sent the notification. + iconUrl?: string; // Icon URL. + loaded = false; + + /** + * @inheritdoc + */ + async ngOnInit(): Promise { + let notification: AddonNotificationsNotificationToRender | AddonNotificationsNotificationData; + + try { + notification = CoreNavigator.getRequiredRouteParam('notification'); + } catch (error) { + CoreDomUtils.showErrorModal(error); + + CoreNavigator.back(); + + return; + } + + if (!('subject' in notification)) { + // Try to find the notification using the WebService, it contains a better message. + const notifId = Number(notification.savedmessageid); + const result = await CoreUtils.ignoreErrors( + AddonNotifications.getNotifications([], { siteId: notification.site }), + ); + + const foundNotification = result?.notifications.find(notif => notif.id === notifId); + if (foundNotification) { + notification = AddonNotificationsHelper.formatNotificationText(foundNotification); + } + } + + if ('subject' in notification) { + this.subject = notification.subject; + this.content = notification.mobiletext || notification.fullmessagehtml; + this.userIdFrom = notification.useridfrom; + this.profileImageUrlFrom = notification.profileimageurlfrom; + this.userFromFullName = notification.userfromfullname; + this.iconUrl = notification.iconurl; + } else { + this.subject = notification.title || ''; + this.content = notification.message || ''; + this.userIdFrom = notification.userfromid ? Number(notification.userfromid) : -1; + this.profileImageUrlFrom = notification.senderImage; + this.userFromFullName = notification.userfromfullname; + } + + this.loaded = true; + } + +} diff --git a/src/addons/notifications/services/handlers/push-click.ts b/src/addons/notifications/services/handlers/push-click.ts index c935f1ba6..2312b4e75 100644 --- a/src/addons/notifications/services/handlers/push-click.ts +++ b/src/addons/notifications/services/handlers/push-click.ts @@ -127,10 +127,16 @@ export class AddonNotificationsPushClickHandlerService implements CorePushNotifi await CoreUtils.ignoreErrors(AddonNotifications.invalidateNotificationsList(notification.site)); await CoreNavigator.navigateToSitePath( - AddonNotificationsMainMenuHandlerService.PAGE_NAME, + `${AddonNotificationsMainMenuHandlerService.PAGE_NAME}/list`, { siteId: notification.site, preferCurrentTab: false, + nextNavigation: { + path: '../notification', + options: { + params: { notification }, + }, + }, }, ); } @@ -139,7 +145,7 @@ export class AddonNotificationsPushClickHandlerService implements CorePushNotifi export const AddonNotificationsPushClickHandler = makeSingleton(AddonNotificationsPushClickHandlerService); -type AddonNotificationsNotificationData = CorePushNotificationsNotificationBasicData & { +export type AddonNotificationsNotificationData = CorePushNotificationsNotificationBasicData & { contexturl?: string; // URL related to the notification. savedmessageid?: number; // Notification ID (optional). id?: number; // Notification ID (optional). diff --git a/src/addons/notifications/services/notifications-helper.ts b/src/addons/notifications/services/notifications-helper.ts index c83bea266..43b538796 100644 --- a/src/addons/notifications/services/notifications-helper.ts +++ b/src/addons/notifications/services/notifications-helper.ts @@ -18,12 +18,14 @@ import { CoreUtils } from '@services/utils/utils'; import { makeSingleton } from '@singletons'; import { AddonMessageOutputDelegate } from '@addons/messageoutput/services/messageoutput-delegate'; import { + AddonNotificationsNotificationMessageFormatted, AddonNotificationsPreferences, AddonNotificationsPreferencesComponent, AddonNotificationsPreferencesNotification, AddonNotificationsPreferencesNotificationProcessor, AddonNotificationsPreferencesProcessor, } from './notifications'; +import { CoreTextUtils } from '@services/utils/text'; /** * Service that provides some helper functions for notifications. @@ -31,6 +33,25 @@ import { @Injectable({ providedIn: 'root' }) export class AddonNotificationsHelperProvider { + /** + * Formats the text of a notification. + * + * @param notification The notification object. + */ + formatNotificationText( + notification: AddonNotificationsNotificationMessageFormatted, + ): AddonNotificationsNotificationToRender { + const formattedNotification: AddonNotificationsNotificationToRender = notification; + formattedNotification.displayfullhtml = this.shouldDisplayFullHtml(notification); + formattedNotification.iconurl = formattedNotification.iconurl || undefined; // Make sure the property exists. + + formattedNotification.mobiletext = formattedNotification.displayfullhtml ? + notification.fullmessagehtml : + CoreTextUtils.replaceNewLines((formattedNotification.mobiletext || '').replace(/-{4,}/ig, ''), '
'); + + return formattedNotification; + } + /** * Format preferences data. * @@ -119,6 +140,16 @@ export class AddonNotificationsHelperProvider { return result; } + /** + * Check whether we should display full HTML of the notification. + * + * @param notification Notification. + * @return Whether to display full HTML. + */ + protected shouldDisplayFullHtml(notification: AddonNotificationsNotificationToRender): boolean { + return notification.component == 'mod_forum' && notification.eventtype == 'digests'; + } + } export const AddonNotificationsHelper = makeSingleton(AddonNotificationsHelperProvider); @@ -151,3 +182,11 @@ export type AddonNotificationsPreferencesNotificationFormatted = AddonNotificati export type AddonNotificationsPreferencesProcessorFormatted = AddonNotificationsPreferencesProcessor & { supported?: boolean; // Calculated in the app. Whether the processor is supported in the app. }; + +/** + * Notification with some calculated data to render it. + */ +export type AddonNotificationsNotificationToRender = AddonNotificationsNotificationMessageFormatted & { + displayfullhtml?: boolean; // Whether to display the full HTML of the notification. + iconurl?: string; +}; diff --git a/src/core/features/login/pages/reconnect/reconnect.ts b/src/core/features/login/pages/reconnect/reconnect.ts index b34720cdd..4101ed7d7 100644 --- a/src/core/features/login/pages/reconnect/reconnect.ts +++ b/src/core/features/login/pages/reconnect/reconnect.ts @@ -209,7 +209,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy { // Go to the site initial page. this.page - ? await CoreNavigator.navigateToSitePath(this.page, { params: this.pageOptions }) + ? await CoreNavigator.navigateToSitePath(this.page, this.pageOptions) : await CoreNavigator.navigateToSiteHome(); } catch (error) { CoreLoginHelper.treatUserTokenError(this.siteUrl, error, this.username, password);