diff --git a/frontend/src/app/core/state/in-app-notifications/in-app-notifications.actions.ts b/frontend/src/app/core/state/in-app-notifications/in-app-notifications.actions.ts index 1aeda581f9..284b26c560 100644 --- a/frontend/src/app/core/state/in-app-notifications/in-app-notifications.actions.ts +++ b/frontend/src/app/core/state/in-app-notifications/in-app-notifications.actions.ts @@ -18,3 +18,8 @@ export const notificationCountIncreased = action( '[IAN] The backend sent a notification count that was higher than the last known', props<{ origin:string, count:number }>(), ); + +export const centerUpdatedInPlace = action( + '[IAN] The notification center updated the notification list without a full page refresh', + props<{ origin:string }>(), +); diff --git a/frontend/src/app/features/in-app-notifications/center/menu/menu.component.ts b/frontend/src/app/features/in-app-notifications/center/menu/menu.component.ts index 56a700c571..33677b28d2 100644 --- a/frontend/src/app/features/in-app-notifications/center/menu/menu.component.ts +++ b/frontend/src/app/features/in-app-notifications/center/menu/menu.component.ts @@ -96,7 +96,7 @@ export class IanMenuComponent implements OnInit { map(([byProject, byReason]) => [ ...this.baseMenuItems.map((baseMenuItem) => ({ ...baseMenuItem, - count: byReason.reduce((a, b) => a + (b.count || 0), 0), + count: byProject.reduce((a, b) => a + (b.count || 0), 0), })), { title: this.I18n.t('js.notifications.menu.by_reason'), diff --git a/frontend/src/app/features/in-app-notifications/center/state/ian-center.service.ts b/frontend/src/app/features/in-app-notifications/center/state/ian-center.service.ts index 011d09947b..69bafdb92b 100644 --- a/frontend/src/app/features/in-app-notifications/center/state/ian-center.service.ts +++ b/frontend/src/app/features/in-app-notifications/center/state/ian-center.service.ts @@ -23,6 +23,7 @@ import { markNotificationsAsRead, notificationsMarkedRead, notificationCountIncreased, + centerUpdatedInPlace, } from 'core-app/core/state/in-app-notifications/in-app-notifications.actions'; import { InAppNotification } from 'core-app/core/state/in-app-notifications/in-app-notification.model'; import { IanCenterQuery } from 'core-app/features/in-app-notifications/center/state/ian-center.query'; @@ -186,6 +187,7 @@ export class IanCenterService extends UntilDestroyedMixin { text: this.I18n.t('js.notifications.center.new_notifications.link_text'), target: () => { this.store.update({ activeCollection: collection }); + this.actions$.dispatch(centerUpdatedInPlace({ origin: this.id })); }, }, }); diff --git a/frontend/src/app/features/work-packages/routing/wp-view-base/state/wp-single-view.service.ts b/frontend/src/app/features/work-packages/routing/wp-view-base/state/wp-single-view.service.ts index fcc73b0125..7090ec93e1 100644 --- a/frontend/src/app/features/work-packages/routing/wp-view-base/state/wp-single-view.service.ts +++ b/frontend/src/app/features/work-packages/routing/wp-view-base/state/wp-single-view.service.ts @@ -12,6 +12,7 @@ import { ApiV3ListFilter } from 'core-app/core/apiv3/paths/apiv3-list-resource.i import { markNotificationsAsRead, notificationsMarkedRead, + centerUpdatedInPlace, } from 'core-app/core/state/in-app-notifications/in-app-notifications.actions'; import { ActionsService } from 'core-app/core/state/actions/actions.service'; import { @@ -86,4 +87,12 @@ export class WpSingleViewService { private reloadOnNotificationRead() { this.reload(); } + + /** + * Reload after notifications were successfully marked as read + */ + @EffectCallback(centerUpdatedInPlace) + private reloadOnCenterUpdate() { + this.reload(); + } } diff --git a/frontend/src/global_styles/openproject/_mixins.sass b/frontend/src/global_styles/openproject/_mixins.sass index a4fe5c898b..22c75b9980 100644 --- a/frontend/src/global_styles/openproject/_mixins.sass +++ b/frontend/src/global_styles/openproject/_mixins.sass @@ -265,6 +265,7 @@ $scrollbar-size: 10px font-weight: bold background: #00A3FF color: white + flex-shrink: 0 @mixin show-on-focus position: absolute