diff --git a/src/main/webapp/app/overview/course-conversations/course-conversations.component.html b/src/main/webapp/app/overview/course-conversations/course-conversations.component.html index 90b2559fa81a..e4cd32cdbecb 100644 --- a/src/main/webapp/app/overview/course-conversations/course-conversations.component.html +++ b/src/main/webapp/app/overview/course-conversations/course-conversations.component.html @@ -29,10 +29,14 @@ [itemSelected]="conversationSelected" [courseId]="course.id" [sidebarData]="sidebarData" - (onPlusPressed)="onAccordionPlusButtonPressed($event)" + (onCreateChannelPressed)="openCreateChannelDialog()" + (onBrowsePressed)="openChannelOverviewDialog()" + (onDirectChatPressed)="openCreateOneToOneChatDialog()" + (onGroupChatPressed)="openCreateGroupChatDialog()" [showAddOption]="CHANNEL_TYPE_SHOW_ADD_OPTION" [channelTypeIcon]="CHANNEL_TYPE_ICON" [collapseState]="DEFAULT_COLLAPSE_STATE" + [inCommunication]="true" /> @if (course && !activeConversation && isCodeOfConductPresented) { diff --git a/src/main/webapp/app/overview/course-conversations/course-conversations.component.ts b/src/main/webapp/app/overview/course-conversations/course-conversations.component.ts index 2d56484f8a46..da7dd332f047 100644 --- a/src/main/webapp/app/overview/course-conversations/course-conversations.component.ts +++ b/src/main/webapp/app/overview/course-conversations/course-conversations.component.ts @@ -1,12 +1,12 @@ -import { Component, ElementRef, HostListener, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; +import { Component, ElementRef, EventEmitter, HostListener, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; import { ConversationDTO } from 'app/entities/metis/conversation/conversation.model'; import { Post } from 'app/entities/metis/post.model'; import { ActivatedRoute, Router } from '@angular/router'; import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; -import { EMPTY, Subject, Subscription, from, take, takeUntil } from 'rxjs'; -import { catchError } from 'rxjs/operators'; +import { EMPTY, Observable, Subject, Subscription, from, take, takeUntil } from 'rxjs'; +import { catchError, debounceTime, distinctUntilChanged } from 'rxjs/operators'; import { MetisConversationService } from 'app/shared/metis/metis-conversation.service'; -import { ChannelSubType, getAsChannelDTO } from 'app/entities/metis/conversation/channel.model'; +import { ChannelDTO, ChannelSubType, getAsChannelDTO } from 'app/entities/metis/conversation/channel.model'; import { MetisService } from 'app/shared/metis/metis.service'; import { Course, isMessagingEnabled } from 'app/entities/course.model'; import { PageType, SortDirection } from 'app/shared/metis/metis.util'; @@ -16,11 +16,12 @@ import { CourseWideSearchComponent, CourseWideSearchConfig } from 'app/overview/ import { AccordionGroups, ChannelAccordionShowAdd, ChannelTypeIcons, CollapseState, SidebarCardElement, SidebarData } 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 } from 'app/overview/course-conversations/other/conversation.util'; +import { defaultFirstLayerDialogOptions, defaultSecondLayerDialogOptions } from 'app/overview/course-conversations/other/conversation.util'; import { UserPublicInfoDTO } from 'app/core/user/user.model'; import { OneToOneChatCreateDialogComponent } from 'app/overview/course-conversations/dialogs/one-to-one-chat-create-dialog/one-to-one-chat-create-dialog.component'; -import { ChannelsOverviewDialogComponent } from 'app/overview/course-conversations/dialogs/channels-overview-dialog/channels-overview-dialog.component'; +import { ChannelAction, ChannelsOverviewDialogComponent } from 'app/overview/course-conversations/dialogs/channels-overview-dialog/channels-overview-dialog.component'; import { ProfileService } from 'app/shared/layouts/profiles/profile.service'; +import { ChannelsCreateDialogComponent } from 'app/overview/course-conversations/dialogs/channels-create-dialog/channels-create-dialog.component'; const DEFAULT_CHANNEL_GROUPS: AccordionGroups = { favoriteChannels: { entityData: [] }, @@ -114,7 +115,9 @@ export class CourseConversationsComponent implements OnInit, OnDestroy { faFilter = faFilter; faSearch = faSearch; - // MetisConversationService is created in course overview, so we can use it here + createChannelFn?: (channel: ChannelDTO) => Observable; + channelActions$ = new EventEmitter(); + constructor( private router: Router, private activatedRoute: ActivatedRoute, @@ -162,6 +165,16 @@ export class CourseConversationsComponent implements OnInit, OnDestroy { this.isServiceSetUp = true; this.isLoading = false; } + this.channelActions$ + .pipe( + debounceTime(500), + distinctUntilChanged((prev, curr) => prev.action === curr.action && prev.channel.id === curr.channel.id), + takeUntil(this.ngUnsubscribe), + ) + .subscribe((channelAction) => { + this.performChannelAction(channelAction); + }); + this.createChannelFn = (channel: ChannelDTO) => this.metisConversationService.createChannel(channel); }); this.profileSubscription = this.profileService.getProfileInfo()?.subscribe((profileInfo) => { @@ -170,6 +183,21 @@ export class CourseConversationsComponent implements OnInit, OnDestroy { }); } + performChannelAction(channelAction: ChannelAction) { + if (this.createChannelFn) { + this.createChannelFn(channelAction.channel) + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe({ + complete: () => { + this.prepareSidebarData(); + }, + error: (error) => { + console.error('Error creating channel:', error); + }, + }); + } + } + subscribeToQueryParameter() { this.activatedRoute.queryParams.pipe(take(1), takeUntil(this.ngUnsubscribe)).subscribe((queryParams) => { if (queryParams.conversationId) { @@ -270,8 +298,8 @@ export class CourseConversationsComponent implements OnInit, OnDestroy { storageId: 'conversation', groupedData: this.accordionConversationGroups, ungroupedData: this.sidebarConversations, - showAccordionAddOption: true, showAccordionLeadingIcon: true, + messagingEnabled: isMessagingEnabled(this.course), }; } @@ -284,16 +312,6 @@ export class CourseConversationsComponent implements OnInit, OnDestroy { this.courseOverviewService.setSidebarCollapseState('conversation', this.isCollapsed); } - onAccordionPlusButtonPressed(chatType: string) { - if (chatType === 'groupChats') { - this.openCreateGroupChatDialog(); - } else if (chatType === 'directMessages') { - this.openCreateOneToOneChatDialog(); - } else { - this.openChannelOverviewDialog(chatType); - } - } - openCreateGroupChatDialog() { const modalRef: NgbModalRef = this.modalService.open(GroupChatCreateDialogComponent, defaultFirstLayerDialogOptions); modalRef.componentInstance.course = this.course; @@ -332,8 +350,22 @@ export class CourseConversationsComponent implements OnInit, OnDestroy { }); } - openChannelOverviewDialog(groupKey: string) { - const subType = this.getChannelSubType(groupKey); + openCreateChannelDialog() { + const modalRef: NgbModalRef = this.modalService.open(ChannelsCreateDialogComponent, defaultSecondLayerDialogOptions); + modalRef.componentInstance.course = this.course; + modalRef.componentInstance.initialize(); + from(modalRef.result) + .pipe( + catchError(() => EMPTY), + takeUntil(this.ngUnsubscribe), + ) + .subscribe((channel: ChannelDTO) => { + this.channelActions$.emit({ action: 'create', channel }); + }); + } + + openChannelOverviewDialog() { + const subType = null; const modalRef: NgbModalRef = this.modalService.open(ChannelsOverviewDialogComponent, defaultFirstLayerDialogOptions); modalRef.componentInstance.course = this.course; modalRef.componentInstance.createChannelFn = subType === ChannelSubType.GENERAL ? this.metisConversationService.createChannel : undefined; @@ -363,22 +395,6 @@ export class CourseConversationsComponent implements OnInit, OnDestroy { }); } - getChannelSubType(groupKey: string) { - if (groupKey === 'exerciseChannels') { - return ChannelSubType.EXERCISE; - } - if (groupKey === 'generalChannels') { - return ChannelSubType.GENERAL; - } - if (groupKey === 'lectureChannels') { - return ChannelSubType.LECTURE; - } - if (groupKey === 'examChannels') { - return ChannelSubType.EXAM; - } - return ChannelSubType.GENERAL; - } - toggleChannelSearch() { this.channelSearchCollapsed = !this.channelSearchCollapsed; } diff --git a/src/main/webapp/app/overview/course-conversations/dialogs/channels-create-dialog/channels-create-dialog.component.html b/src/main/webapp/app/overview/course-conversations/dialogs/channels-create-dialog/channels-create-dialog.component.html index cd5b295812a3..e7c6413b8b22 100644 --- a/src/main/webapp/app/overview/course-conversations/dialogs/channels-create-dialog/channels-create-dialog.component.html +++ b/src/main/webapp/app/overview/course-conversations/dialogs/channels-create-dialog/channels-create-dialog.component.html @@ -1,5 +1,5 @@ @if (isInitialized) { -
+
} diff --git a/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-settings/conversation-settings.component.ts b/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-settings/conversation-settings.component.ts index 64cb3410ae78..9a9b9b56bb6e 100644 --- a/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-settings/conversation-settings.component.ts +++ b/src/main/webapp/app/overview/course-conversations/dialogs/conversation-detail-dialog/tabs/conversation-settings/conversation-settings.component.ts @@ -9,7 +9,7 @@ import { onError } from 'app/shared/util/global.utils'; import { EMPTY, Subject, from, takeUntil } from 'rxjs'; import { HttpErrorResponse } from '@angular/common/http'; import { AlertService } from 'app/core/util/alert.service'; -import { faTimes } from '@fortawesome/free-solid-svg-icons'; +import { faTrash } from '@fortawesome/free-solid-svg-icons'; import { canChangeChannelArchivalState, canDeleteChannel, canLeaveConversation } from 'app/shared/metis/conversations/conversation-permissions.utils'; import { GroupChatService } from 'app/shared/metis/conversations/group-chat.service'; import { isGroupChatDTO } from 'app/entities/metis/conversation/group-chat.model'; @@ -42,7 +42,7 @@ export class ConversationSettingsComponent implements OnInit, OnDestroy { private dialogErrorSource = new Subject(); dialogError$ = this.dialogErrorSource.asObservable(); - faTimes = faTimes; + readonly faTrash = faTrash; conversationAsChannel: ChannelDTO | undefined; canLeaveConversation: boolean; diff --git a/src/main/webapp/app/overview/course-conversations/dialogs/group-chat-create-dialog/group-chat-create-dialog.component.html b/src/main/webapp/app/overview/course-conversations/dialogs/group-chat-create-dialog/group-chat-create-dialog.component.html index d8e0e8a5aa1a..b84a700f6e35 100644 --- a/src/main/webapp/app/overview/course-conversations/dialogs/group-chat-create-dialog/group-chat-create-dialog.component.html +++ b/src/main/webapp/app/overview/course-conversations/dialogs/group-chat-create-dialog/group-chat-create-dialog.component.html @@ -1,5 +1,5 @@ @if (isInitialized) { -
+