From e3f1c929d4f2cdf4522110b74e5dfc5c5d76962c Mon Sep 17 00:00:00 2001 From: Asli Aykan <56061820+asliayk@users.noreply.github.com> Date: Fri, 15 Nov 2024 20:37:56 +0100 Subject: [PATCH] Communication: Add unread message notification icon to sidebar accordion (#9737) --- .../overview/course-overview.component.html | 2 +- .../sidebar-accordion.component.html | 3 +++ .../sidebar-accordion.component.scss | 19 +++++++++++++++++++ .../sidebar-accordion.component.ts | 15 +++++++++++++++ .../sidebar-card-item.component.scss | 1 + .../sidebar-accordion.component.spec.ts | 16 ++++++++++++---- 6 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/main/webapp/app/overview/course-overview.component.html b/src/main/webapp/app/overview/course-overview.component.html index 5fac3f273643..c19fe24185bd 100644 --- a/src/main/webapp/app/overview/course-overview.component.html +++ b/src/main/webapp/app/overview/course-overview.component.html @@ -259,7 +259,7 @@ [id]="sidebarItem.testId ?? ''" [ngClass]="{ 'guided-tour': sidebarItem.guidedTour, - newMessage: !communicationRouteLoaded && hasUnreadMessages && sidebarItem.title === 'Communication', + newMessage: hasUnreadMessages && sidebarItem.title === 'Communication', collapsed: isNavbarCollapsed, }" jhiOrionFilter diff --git a/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.html b/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.html index a3ec25c5b6d6..92d7b034e785 100644 --- a/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.html +++ b/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.html @@ -14,6 +14,9 @@ ({{ (groupedData[groupKey].entityData | searchFilter: ['title', 'type'] : searchValue)?.length }})
+ @if (totalUnreadMessagesPerGroup[groupKey] > 0 && collapseState[groupKey]) { + {{ totalUnreadMessagesPerGroup[groupKey] }} + }
diff --git a/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.scss b/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.scss index 78788a1fb334..61f8e82f8193 100644 --- a/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.scss +++ b/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.scss @@ -5,3 +5,22 @@ hr { border-top-color: var(--overview-light-border-color); } + +.unread-count { + background-color: var(--bs-primary); + color: var(--bs-white); + border-radius: 50%; + font-size: 0.6rem; + width: 1.1rem; + height: 1.1rem; + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + white-space: nowrap; +} + +.icon-container { + display: flex; + align-items: center; +} diff --git a/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.ts b/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.ts index 030cdbb879ec..26f65e5258fa 100644 --- a/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.ts +++ b/src/main/webapp/app/shared/sidebar/sidebar-accordion/sidebar-accordion.component.ts @@ -27,6 +27,7 @@ export class SidebarAccordionComponent implements OnChanges, OnInit { readonly faChevronRight = faChevronRight; readonly faFile = faFile; + totalUnreadMessagesPerGroup: { [key: string]: number } = {}; ngOnInit() { this.expandGroupWithSelectedItem(); @@ -39,6 +40,7 @@ export class SidebarAccordionComponent implements OnChanges, OnInit { } else { this.setStoredCollapseState(); } + this.calculateUnreadMessagesOfGroup(); } setStoredCollapseState() { @@ -67,6 +69,19 @@ export class SidebarAccordionComponent implements OnChanges, OnInit { } } + calculateUnreadMessagesOfGroup(): void { + if (!this.groupedData) { + this.totalUnreadMessagesPerGroup = {}; + return; + } + + Object.keys(this.groupedData).forEach((groupKey) => { + this.totalUnreadMessagesPerGroup[groupKey] = this.groupedData[groupKey].entityData + .filter((item: SidebarCardElement) => item.conversation?.unreadMessagesCount) + .reduce((sum, item) => sum + (item.conversation?.unreadMessagesCount || 0), 0); + }); + } + toggleGroupCategoryCollapse(groupCategoryKey: string) { this.collapseState[groupCategoryKey] = !this.collapseState[groupCategoryKey]; localStorage.setItem('sidebar.accordion.collapseState.' + this.storageId + '.byCourse.' + this.courseId, JSON.stringify(this.collapseState)); diff --git a/src/main/webapp/app/shared/sidebar/sidebar-card-item/sidebar-card-item.component.scss b/src/main/webapp/app/shared/sidebar/sidebar-card-item/sidebar-card-item.component.scss index 64f4e5a920c0..8f36ede446dc 100644 --- a/src/main/webapp/app/shared/sidebar/sidebar-card-item/sidebar-card-item.component.scss +++ b/src/main/webapp/app/shared/sidebar/sidebar-card-item/sidebar-card-item.component.scss @@ -12,6 +12,7 @@ border-radius: 50%; font-size: 0.6rem; width: 1.1rem; + min-width: 1.1rem; height: 1.1rem; display: flex; justify-content: center; diff --git a/src/test/javascript/spec/component/shared/sidebar/sidebar-accordion.component.spec.ts b/src/test/javascript/spec/component/shared/sidebar/sidebar-accordion.component.spec.ts index 9e7fe5427253..54015cb0ff41 100644 --- a/src/test/javascript/spec/component/shared/sidebar/sidebar-accordion.component.spec.ts +++ b/src/test/javascript/spec/component/shared/sidebar/sidebar-accordion.component.spec.ts @@ -39,22 +39,23 @@ describe('SidebarAccordionComponent', () => { component.groupedData = { current: { - entityData: [{ title: 'Title 1', type: 'Type A', id: 1, size: 'M' }], + entityData: [{ title: 'Title 1', type: 'Type A', id: 1, size: 'M', conversation: { unreadMessagesCount: 1 } }], }, past: { - entityData: [{ title: 'Title 2', type: 'Type B', id: 2, size: 'M' }], + entityData: [{ title: 'Title 2', type: 'Type B', id: 2, size: 'M', conversation: { unreadMessagesCount: 0 } }], }, future: { - entityData: [{ title: 'Title 3', type: 'Type C', id: 3, size: 'M' }], + entityData: [{ title: 'Title 3', type: 'Type C', id: 3, size: 'M', conversation: { unreadMessagesCount: 1 } }], }, noDate: { - entityData: [{ title: 'Title 4', type: 'Type D', id: 4, size: 'M' }], + entityData: [{ title: 'Title 4', type: 'Type D', id: 4, size: 'M', conversation: { unreadMessagesCount: 0 } }], }, }; component.routeParams = { exerciseId: 3 }; component.collapseState = { current: false, dueSoon: false, past: false, future: true, noDate: true }; fixture.componentRef.setInput('sidebarItemAlwaysShow', { current: false, dueSoon: false, past: false, future: false, noDate: false }); fixture.detectChanges(); + component.calculateUnreadMessagesOfGroup(); }); afterEach(() => { @@ -144,4 +145,11 @@ describe('SidebarAccordionComponent', () => { component.expandGroupWithSelectedItem(); expect(component.collapseState['future']).toBeFalse(); }); + + it('should calculate unread messages of each group correctly', () => { + expect(component.totalUnreadMessagesPerGroup['current']).toBe(1); + expect(component.totalUnreadMessagesPerGroup['past']).toBe(0); + expect(component.totalUnreadMessagesPerGroup['future']).toBe(1); + expect(component.totalUnreadMessagesPerGroup['noDate']).toBe(0); + }); });