Skip to content

Commit

Permalink
Communication: Add recents section to sidebar (#10033)
Browse files Browse the repository at this point in the history
  • Loading branch information
asliayk authored Dec 31, 2024
1 parent 63ff1fb commit 1fd1813
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
(onBrowsePressed)="openChannelOverviewDialog()"
(onDirectChatPressed)="openCreateOneToOneChatDialog()"
(onGroupChatPressed)="openCreateGroupChatDialog()"
[showAddOption]="CHANNEL_TYPE_SHOW_ADD_OPTION"
[channelTypeIcon]="CHANNEL_TYPE_ICON"
[sidebarItemAlwaysShow]="DEFAULT_SHOW_ALWAYS"
[collapseState]="DEFAULT_COLLAPSE_STATE"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { PageType, SortDirection } from 'app/shared/metis/metis.util';
import {
faBan,
faBookmark,
faClock,
faComment,
faComments,
faFile,
Expand All @@ -27,7 +28,7 @@ import {
} from '@fortawesome/free-solid-svg-icons';
import { ButtonType } from 'app/shared/components/button.component';
import { CourseWideSearchComponent, CourseWideSearchConfig } from 'app/overview/course-conversations/course-wide-search/course-wide-search.component';
import { AccordionGroups, ChannelAccordionShowAdd, ChannelTypeIcons, CollapseState, SidebarCardElement, SidebarData, SidebarItemShowAlways } from 'app/types/sidebar';
import { AccordionGroups, ChannelTypeIcons, CollapseState, SidebarCardElement, SidebarData, SidebarItemShowAlways } from 'app/types/sidebar';
import { CourseOverviewService } from 'app/overview/course-overview.service';
import { GroupChatCreateDialogComponent } from 'app/overview/course-conversations/dialogs/group-chat-create-dialog/group-chat-create-dialog.component';
import { defaultFirstLayerDialogOptions, defaultSecondLayerDialogOptions } from 'app/overview/course-conversations/other/conversation.util';
Expand All @@ -44,6 +45,7 @@ import { canCreateChannel } from 'app/shared/metis/conversations/conversation-pe

const DEFAULT_CHANNEL_GROUPS: AccordionGroups = {
favoriteChannels: { entityData: [] },
recents: { entityData: [] },
generalChannels: { entityData: [] },
exerciseChannels: { entityData: [] },
lectureChannels: { entityData: [] },
Expand All @@ -52,18 +54,6 @@ const DEFAULT_CHANNEL_GROUPS: AccordionGroups = {
savedPosts: { entityData: [] },
};

const CHANNEL_TYPE_SHOW_ADD_OPTION: ChannelAccordionShowAdd = {
generalChannels: true,
exerciseChannels: true,
examChannels: true,
groupChats: true,
directMessages: true,
favoriteChannels: false,
lectureChannels: true,
hiddenChannels: false,
savedPosts: false,
};

const CHANNEL_TYPE_ICON: ChannelTypeIcons = {
generalChannels: faMessage,
exerciseChannels: faList,
Expand All @@ -74,6 +64,7 @@ const CHANNEL_TYPE_ICON: ChannelTypeIcons = {
lectureChannels: faFile,
hiddenChannels: faBan,
savedPosts: faBookmark,
recents: faClock,
};

const DEFAULT_COLLAPSE_STATE: CollapseState = {
Expand All @@ -86,6 +77,7 @@ const DEFAULT_COLLAPSE_STATE: CollapseState = {
lectureChannels: true,
hiddenChannels: true,
savedPosts: true,
recents: true,
};

const DEFAULT_SHOW_ALWAYS: SidebarItemShowAlways = {
Expand All @@ -98,6 +90,7 @@ const DEFAULT_SHOW_ALWAYS: SidebarItemShowAlways = {
lectureChannels: false,
hiddenChannels: false,
savedPosts: true,
recents: true,
};

@Component({
Expand Down Expand Up @@ -135,7 +128,6 @@ export class CourseConversationsComponent implements OnInit, OnDestroy {
openThreadOnFocus = false;
selectedSavedPostStatus: null | SavedPostStatus = null;

readonly CHANNEL_TYPE_SHOW_ADD_OPTION = CHANNEL_TYPE_SHOW_ADD_OPTION;
readonly CHANNEL_TYPE_ICON = CHANNEL_TYPE_ICON;
readonly DEFAULT_COLLAPSE_STATE = DEFAULT_COLLAPSE_STATE;
protected readonly DEFAULT_SHOW_ALWAYS = DEFAULT_SHOW_ALWAYS;
Expand Down Expand Up @@ -409,8 +401,10 @@ export class CourseConversationsComponent implements OnInit, OnDestroy {
prepareSidebarData() {
this.metisConversationService.forceRefresh().subscribe({
complete: () => {
this.sidebarConversations = this.courseOverviewService.mapConversationsToSidebarCardElements(this.conversationsOfUser);
this.accordionConversationGroups = this.courseOverviewService.groupConversationsByChannelType(this.conversationsOfUser, this.messagingEnabled);
this.sidebarConversations = this.courseOverviewService.mapConversationsToSidebarCardElements(this.course!, this.conversationsOfUser);
this.accordionConversationGroups = this.courseOverviewService.groupConversationsByChannelType(this.course!, this.conversationsOfUser, this.messagingEnabled);
const currentConversations = this.sidebarConversations?.filter((item) => item.isCurrent) || [];
this.accordionConversationGroups.recents.entityData = currentConversations;
this.updateSidebarData();
},
});
Expand Down
76 changes: 59 additions & 17 deletions src/main/webapp/app/overview/course-overview.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { isGroupChatDTO } from 'app/entities/metis/conversation/group-chat.model
import { ConversationService } from 'app/shared/metis/conversations/conversation.service';
import { StudentExam } from 'app/entities/student-exam.model';
import { SavedPostStatusMap } from 'app/entities/metis/posting.model';
import { Course } from 'app/entities/course.model';

const DEFAULT_UNIT_GROUPS: AccordionGroups = {
future: { entityData: [] },
Expand Down Expand Up @@ -58,6 +59,7 @@ const GROUP_DECISION_MATRIX: Record<StartDateGroup, Record<EndDateGroup, TimeGro

const DEFAULT_CHANNEL_GROUPS: AccordionGroups = {
favoriteChannels: { entityData: [] },
recents: { entityData: [] },
generalChannels: { entityData: [] },
exerciseChannels: { entityData: [] },
lectureChannels: { entityData: [] },
Expand Down Expand Up @@ -169,20 +171,28 @@ export class CourseOverviewService {
return 'future';
}

getConversationGroup(conversation: ConversationDTO): ChannelGroupCategory {
if (conversation.isFavorite) {
return 'favoriteChannels';
}
getConversationGroup(conversation: ConversationDTO): ChannelGroupCategory[] {
const groups: ChannelGroupCategory[] = [];

if (conversation.isHidden) {
return 'hiddenChannels';
groups.push('hiddenChannels');
return groups;
}
if (isGroupChatDTO(conversation)) {
return 'groupChats';

if (conversation.isFavorite) {
groups.push('favoriteChannels');
}
if (isOneToOneChatDTO(conversation)) {
return 'directMessages';

if (isGroupChatDTO(conversation)) {
groups.push('groupChats');
} else if (isOneToOneChatDTO(conversation)) {
groups.push('directMessages');
} else {
const subTypeGroup = this.getCorrespondingChannelSubType(getAsChannelDTO(conversation)?.subType);
groups.push(subTypeGroup);
}
return this.getCorrespondingChannelSubType(getAsChannelDTO(conversation)?.subType);

return groups;
}

getCorrespondingChannelSubType(channelSubType: ChannelSubType | undefined): ChannelGroupCategory {
Expand Down Expand Up @@ -219,7 +229,7 @@ export class CourseOverviewService {
return groupedLectureGroups;
}

groupConversationsByChannelType(conversations: ConversationDTO[], messagingEnabled: boolean): AccordionGroups {
groupConversationsByChannelType(course: Course, conversations: ConversationDTO[], messagingEnabled: boolean): AccordionGroups {
const channelGroups = messagingEnabled ? { ...DEFAULT_CHANNEL_GROUPS, groupChats: { entityData: [] }, directMessages: { entityData: [] } } : DEFAULT_CHANNEL_GROUPS;
const groupedConversationGroups = cloneDeep(channelGroups) as AccordionGroups;

Expand Down Expand Up @@ -251,11 +261,21 @@ export class CourseOverviewService {
};

for (const conversation of conversations) {
const conversationGroup = this.getConversationGroup(conversation);
const conversationCardItem = this.mapConversationToSidebarCardElement(conversation);
groupedConversationGroups[conversationGroup].entityData.push(conversationCardItem);
const conversationGroups = this.getConversationGroup(conversation);
const conversationCardItem = this.mapConversationToSidebarCardElement(course, conversation);

for (const group of conversationGroups) {
groupedConversationGroups[group].entityData.push(conversationCardItem);
}
}

for (const group in groupedConversationGroups) {
groupedConversationGroups[group].entityData.sort((a, b) => {
const aIsFavorite = a.conversation?.isFavorite ? 1 : 0;
const bIsFavorite = b.conversation?.isFavorite ? 1 : 0;
return bIsFavorite - aIsFavorite;
});
}
return groupedConversationGroups;
}

Expand All @@ -273,8 +293,8 @@ export class CourseOverviewService {
return exams.map((exam, index) => this.mapExamToSidebarCardElement(exam, studentExams?.[index]));
}

mapConversationsToSidebarCardElements(conversations: ConversationDTO[]) {
return conversations.map((conversation) => this.mapConversationToSidebarCardElement(conversation));
mapConversationsToSidebarCardElements(course: Course, conversations: ConversationDTO[]) {
return conversations.map((conversation) => this.mapConversationToSidebarCardElement(course, conversation));
}

mapLectureToSidebarCardElement(lecture: Lecture): SidebarCardElement {
Expand Down Expand Up @@ -349,14 +369,36 @@ export class CourseOverviewService {
}
}

mapConversationToSidebarCardElement(conversation: ConversationDTO): SidebarCardElement {
mapConversationToSidebarCardElement(course: Course, conversation: ConversationDTO): SidebarCardElement {
let isCurrent = false;
const channelDTO = getAsChannelDTO(conversation);
const subTypeRefId = channelDTO?.subTypeReferenceId;
const now = dayjs();
const oneAndHalfWeekBefore = now.subtract(1.5, 'week');
const oneAndHalfWeekLater = now.add(1.5, 'week');
let relevantDate = null;
if (subTypeRefId && course.exercises && channelDTO?.subType === 'exercise') {
const exercise = course.exercises.find((exercise) => exercise.id === subTypeRefId);
const relevantDates = [exercise?.releaseDate, exercise?.dueDate].filter(Boolean);
isCurrent = relevantDates.some((date) => dayjs(date).isBetween(oneAndHalfWeekBefore, oneAndHalfWeekLater, 'day', '[]'));
} else if (subTypeRefId && course.lectures && channelDTO?.subType === 'lecture') {
const lecture = course.lectures.find((lecture) => lecture.id === subTypeRefId);
relevantDate = lecture?.startDate || null;
isCurrent = relevantDate ? dayjs(relevantDate).isBetween(oneAndHalfWeekBefore, oneAndHalfWeekLater, 'day', '[]') : false;
} else if (subTypeRefId && course.exams && channelDTO?.subType === 'exam') {
const exam = course.exams.find((exam) => exam.id === subTypeRefId);
relevantDate = exam?.startDate || null;
isCurrent = relevantDate ? dayjs(relevantDate).isBetween(oneAndHalfWeekBefore, oneAndHalfWeekLater, 'day', '[]') : false;
}

const conversationCardItem: SidebarCardElement = {
title: this.conversationService.getConversationName(conversation) ?? '',
id: conversation.id ?? '',
type: conversation.type,
icon: this.getChannelIcon(conversation),
conversation: conversation,
size: 'S',
isCurrent: isCurrent,
};
return conversationCardItem;
}
Expand Down
3 changes: 1 addition & 2 deletions src/main/webapp/app/shared/sidebar/sidebar.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { faCheckDouble, faFilter, faFilterCircleXmark, faHashtag, faPeopleGroup,
import { ActivatedRoute, Params } from '@angular/router';
import { Subscription, distinctUntilChanged } from 'rxjs';
import { ProfileService } from '../layouts/profiles/profile.service';
import { ChannelAccordionShowAdd, ChannelTypeIcons, CollapseState, SidebarCardSize, SidebarData, SidebarItemShowAlways, SidebarTypes } from 'app/types/sidebar';
import { ChannelTypeIcons, CollapseState, SidebarCardSize, SidebarData, SidebarItemShowAlways, SidebarTypes } from 'app/types/sidebar';
import { SidebarEventService } from './sidebar-event.service';
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { cloneDeep } from 'lodash-es';
Expand Down Expand Up @@ -33,7 +33,6 @@ export class SidebarComponent implements OnDestroy, OnChanges, OnInit {
@Input() sidebarData: SidebarData;
@Input() courseId?: number;
@Input() itemSelected?: boolean;
@Input() showAddOption?: ChannelAccordionShowAdd;
@Input() channelTypeIcon?: ChannelTypeIcons;
@Input() collapseState: CollapseState;
sidebarItemAlwaysShow = input.required<SidebarItemShowAlways>();
Expand Down
4 changes: 3 additions & 1 deletion src/main/webapp/app/types/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type AccordionGroups = Record<
>;
export type ChannelGroupCategory =
| 'favoriteChannels'
| 'recents'
| 'generalChannels'
| 'exerciseChannels'
| 'lectureChannels'
Expand All @@ -27,7 +28,6 @@ export type ChannelGroupCategory =
export type CollapseState = {
[key: string]: boolean;
} & (Record<TimeGroupCategory, boolean> | Record<ChannelGroupCategory, boolean> | Record<ExamGroupCategory, boolean> | Record<TutorialGroupCategory, boolean>);
export type ChannelAccordionShowAdd = Record<ChannelGroupCategory, boolean>;
export type ChannelTypeIcons = Record<ChannelGroupCategory, IconProp>;
export type SidebarItemShowAlways = {
[key: string]: boolean;
Expand Down Expand Up @@ -135,4 +135,6 @@ export interface SidebarCardElement {
* Set for Conversation. Will be removed after refactoring
*/
conversation?: ConversationDTO;

isCurrent?: boolean;
}
3 changes: 2 additions & 1 deletion src/main/webapp/i18n/de/student-dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@
"groupChats": "Gruppenchats",
"directMessages": "Direktnachrichten",
"filterConversationPlaceholder": "Konversationen filtern",
"setChannelAsRead": "Alle Kanäle als gelesen markieren"
"setChannelAsRead": "Alle Kanäle als gelesen markieren",
"recents": "Kürzliches"
},
"menu": {
"exercises": "Aufgaben",
Expand Down
3 changes: 2 additions & 1 deletion src/main/webapp/i18n/en/student-dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@
"groupChats": "Group Chats",
"directMessages": "Direct Messages",
"filterConversationPlaceholder": "Filter conversations",
"setChannelAsRead": "Mark all channels as read"
"setChannelAsRead": "Mark all channels as read",
"recents": "Recents"
},
"menu": {
"exercises": "Exercises",
Expand Down
Loading

0 comments on commit 1fd1813

Please sign in to comment.