import { Component, OnInit, OnDestroy, Output, EventEmitter, ViewChild, Input, AfterViewChecked } from '@angular/core'; import { Observable, Subscription, merge } from 'rxjs'; import { Store, select } from '@ngrx/store'; import { NGXLogger } from 'ngx-logger'; import { VersionInfo2Response } from '@ucap-webmessenger/api-public'; import { SessionStorageService } from '@ucap-webmessenger/web-storage'; import { DialogService, AlertDialogComponent, AlertDialogResult, AlertDialogData } from '@ucap-webmessenger/ui'; import { LoginResponse, RoleCode } from '@ucap-webmessenger/protocol-authentication'; import { KEY_LOGIN_RES_INFO } from '@app/types/login-res-info.type'; import { MessageApiService, MessageType, MessageList, MessageSearchType, MessageDetailInfo } from '@ucap-webmessenger/api-message'; import { MessageStatusCode } from '@ucap-webmessenger/api'; import { ContentType } from '@ucap-webmessenger/api-message'; import { FormGroup, FormBuilder } from '@angular/forms'; import { MatTabGroup, MatSelectChange, MatRadioChange } from '@angular/material'; import { MessageDetailDialogComponent, MessageDetailDialogResult, MessageDetailDialogData } from '../../dialogs/message/message-detail.dialog.component'; import { EnvironmentsInfo, KEY_ENVIRONMENTS_INFO, KEY_VER_INFO } from '@app/types'; import * as AppStore from '@app/store'; import * as MessageStore from '@app/store/messenger/message'; import { TranslateService } from '@ngx-translate/core'; import { MessageWriteDialogComponent, MessageWriteDialogResult, MessageWriteDialogData } from '../../dialogs/message/message-write.dialog.component'; import { UserInfo } from '@ucap-webmessenger/protocol-sync'; import { EmployeeType } from '@ucap-webmessenger/protocol-room'; export interface MessageTypeData { displayName: string; name: string; } @Component({ selector: 'app-layout-chat-left-sidenav-message', templateUrl: './message.component.html', styleUrls: ['./message.component.scss'] }) export class MessageBoxComponent implements OnInit, OnDestroy, AfterViewChecked { @Input() isVisible = false; @Output() doRefreshUnReadCount = new EventEmitter(); @ViewChild('tabs', { static: false }) tabs: MatTabGroup; isInitTabs = false; fgSearch: FormGroup; fgSearchType: FormGroup; loginRes: LoginResponse; sessionVerinfo: VersionInfo2Response; environmentsInfo: EnvironmentsInfo; messageRetrieveList$: Observable; messageSendList$: Observable; messageReservationList$: Observable; messageSearchList$: Observable; messageDetailInfo: Subscription; currentTabIndex = 0; defaultPageSize = 1000; // default currentTotalCount = 0; currentPage = 0; ContentType = ContentType; MessageType = MessageType; MessageSearchType = MessageSearchType; isSearch = false; messageTypeList: MessageTypeData[] = []; langChangeSubscription: Subscription; constructor( private store: Store, private formBuilder: FormBuilder, private sessionStorageService: SessionStorageService, private dialogService: DialogService, private translateService: TranslateService, private messageApiService: MessageApiService, private logger: NGXLogger ) { this.loginRes = this.sessionStorageService.get( KEY_LOGIN_RES_INFO ); this.sessionVerinfo = this.sessionStorageService.get( KEY_VER_INFO ); this.environmentsInfo = this.sessionStorageService.get( KEY_ENVIRONMENTS_INFO ); } ngOnInit() { this.fgSearch = this.formBuilder.group({ searchInput: null }); this.fgSearchType = this.formBuilder.group({ searchMessageType: [MessageType.All], searchMessageSearchType: [MessageSearchType.Name] }); this.messageRetrieveList$ = this.store.pipe( select(AppStore.MessengerSelector.MessageSelector.selectAllReceiveList) ); this.messageSendList$ = this.store.pipe( select(AppStore.MessengerSelector.MessageSelector.selectAllSendList) ); this.messageReservationList$ = this.store.pipe( select( AppStore.MessengerSelector.MessageSelector.selectAllReservationList ) ); this.messageSearchList$ = this.store.pipe( select(AppStore.MessengerSelector.MessageSelector.selectAllSearchList) ); this.messageDetailInfo = this.store .pipe( select(AppStore.MessengerSelector.MessageSelector.detailMessageInfo) ) .subscribe(async info => { if (!!info && info.responseCode === MessageStatusCode.Success) { // Badge Refresh in case Receive Message.. if (info.msgInfo.type === MessageType.Receive) { this.doRefreshUnReadCount.emit(); // Clear Receive Message New Badge.. this.store.dispatch( MessageStore.clearNewFlagReceiveMessage({ msgId: info.msgInfo.msgId }) ); } // detail view.. const result = await this.dialogService.open< MessageDetailDialogComponent, MessageDetailDialogData, MessageDetailDialogResult >(MessageDetailDialogComponent, { width: '600px', hasBackdrop: false, data: { detail: info, loginRes: this.loginRes, environmentsInfo: this.environmentsInfo } }); if (!!result) { // Clear detail Info in state this.store.dispatch(MessageStore.detailMessageClear({})); switch (result.returnType) { case 'DEL': // 단건 삭제. this.doMessageDelete([result.messageInfo]); break; case 'CANCEL_RESERVATION': // 단건 발송취소(예약) this.doMessageCancelReservation(result.messageInfo); break; case 'REPLY': // 답장 this.doMessageReply(result.messageInfo); break; case 'UPDATE': // 예약 수정 this.getRetrieveMessage(MessageType.Reservation, 0); break; } } } else if ( !!info && info.responseCode === MessageStatusCode.Fail_Cancelled_Msg ) { this.dialogService.open< AlertDialogComponent, AlertDialogData, AlertDialogResult >(AlertDialogComponent, { width: '360px', data: { title: this.translateService.instant('message.errors.label'), message: this.translateService.instant( 'message.errors.cancelledMessage' ) } }); } }); // 초기 검색은 수신함. this.getRetrieveMessage(MessageType.Receive, 0); if (!!this.tabs) { this.tabs.realignInkBar(); } this.setMessageTypeData(); this.langChangeSubscription = merge( this.translateService.onLangChange, this.translateService.onDefaultLangChange, this.translateService.onTranslationChange ).subscribe(() => { this.setMessageTypeData(); }); } ngAfterViewChecked(): void { if (!!this.tabs && !this.isInitTabs && this.isVisible) { this.isInitTabs = true; this.tabs.realignInkBar(); } } ngOnDestroy(): void { if (!!this.messageDetailInfo) { this.messageDetailInfo.unsubscribe(); } if (!!this.langChangeSubscription) { this.langChangeSubscription.unsubscribe(); } } onSelectedIndexTab(value: number) { this.tabs.selectedIndex = value; } onSelectedIndexChange(value: number) { this.currentTabIndex = value; let messageType: MessageType; switch (value) { case 0: // Recieve messageType = MessageType.Receive; break; case 1: // Send messageType = MessageType.Send; break; case 2: // Reservation messageType = MessageType.Reservation; break; } this.getRetrieveMessage(messageType, 0); } /** 쪽지 검색 관련 */ onChangeSelection(event: MatSelectChange) { this.getSearchMessage( event.value, this.fgSearchType.get('searchMessageSearchType').value, this.fgSearch.get('searchInput').value ); } onChangeSearchType(event: MatRadioChange) { this.getSearchMessage( this.fgSearchType.get('searchMessageType').value, event.value, this.fgSearch.get('searchInput').value ); } onKeyDownEnter(event: KeyboardEvent, search: string) { event.preventDefault(); event.stopPropagation(); if (!search || search.trim().length === 0) { return; } this.getSearchMessage( MessageType.All, MessageSearchType.Name, search.trim() ); } getSearchMessage( messageType: MessageType, searchType: MessageSearchType, searchStr: string ) { this.isSearch = true; this.store.dispatch( MessageStore.searchMessage({ messageType, searchType, searchStr }) ); } onClickSearchCancel() { this.isSearch = false; this.store.dispatch(MessageStore.clearSearchMessage({})); // this.getRetrieveMessage(MessageType.Receive, 0); } /** 쪽지 타입별 조회 */ getRetrieveMessage(messageType: MessageType, trgtPageIndex: number) { this.store.dispatch( MessageStore.retrieveMessage({ messageType }) ); } /** 쪽지 상세보기 */ onClickDetail(message: MessageList) { this.store.dispatch( MessageStore.detailMessage({ messageType: message.type, msgId: message.msgId }) ); } /** 쪽지(수신,발신) 삭제 */ doMessageDelete(messageInfo: MessageDetailInfo[]): void { const msgList: { msgId: number }[] = []; messageInfo.forEach(info => msgList.push({ msgId: info.msgId })); this.store.dispatch( MessageStore.deleteMessage({ messageType: messageInfo[0].type, msgList }) ); } /** 쪽지(예약) 삭제 */ doMessageCancelReservation(messageInfo: MessageDetailInfo): void { this.store.dispatch( MessageStore.cancelReservationMessage({ messageType: messageInfo.type, msgId: messageInfo.msgId }) ); } doMessageReply(messageInfo: MessageDetailInfo): void { this.dialogService.open< MessageWriteDialogComponent, MessageWriteDialogData, MessageWriteDialogResult >(MessageWriteDialogComponent, { width: '600px', height: '600px', disableClose: true, hasBackdrop: false, data: { loginRes: this.loginRes, environmentsInfo: this.environmentsInfo, receiverList: [this.convertDetailReceivertoUserInfo(messageInfo)] } }); } private setMessageTypeData() { const messageTypeData = this.translateService.instant('message.type'); const messageTypeList: MessageTypeData[] = []; for (const key in messageTypeData) { if (messageTypeData.hasOwnProperty(key)) { let name = 'A'; switch (key) { case 'messageTypeAll': name = MessageType.All; break; case 'messageTypeReceiving': name = MessageType.Receive; break; case 'messageTypeOutgoing': name = MessageType.Send; break; case 'messageTypeReservation': name = MessageType.Reservation; break; } messageTypeList.push({ displayName: messageTypeData[key], name }); } } this.messageTypeList = messageTypeList; } private convertDetailReceivertoUserInfo(base: MessageDetailInfo): UserInfo { return { seq: base.sendUserSeq, name: base.sendUserName, profileImageFile: '', grade: '', intro: '', companyCode: '', hpNumber: '', lineNumber: '', email: '', isMobile: false, deptName: '', isFavorit: false, isBuddy: false, isActive: false, roleCd: RoleCode.Self, employeeNum: '', madn: '', hardSadn: '', fmcSadn: '', nameEn: '', nameCn: '', gradeEn: '', gradeCn: '', deptNameEn: '', deptNameCn: '', isPrivacyAgree: false, isValidLogin: false, employeeType: EmployeeType.Regular, nickName: '', order: '' }; } }