500 lines
16 KiB
TypeScript
Raw Normal View History

2019-11-26 17:54:37 +09:00
import { Component, OnInit, Inject, ViewChild } from '@angular/core';
import {
MatDialogRef,
MAT_DIALOG_DATA,
MatSelectionList,
MatSelectionListChange,
MatDrawer
2019-11-26 17:54:37 +09:00
} from '@angular/material';
import { Observable, combineLatest, of } from 'rxjs';
import { Store, select } from '@ngrx/store';
import { map, catchError, take } from 'rxjs/operators';
import * as AppStore from '@app/store';
import * as SyncStore from '@app/store/messenger/sync';
import {
DialogService,
ConfirmDialogComponent,
ConfirmDialogData,
ConfirmDialogResult,
SnackBarService,
AlertDialogComponent,
AlertDialogResult,
AlertDialogData
2019-11-26 17:54:37 +09:00
} from '@ucap-webmessenger/ui';
import { GroupDetailData, UserInfo } from '@ucap-webmessenger/protocol-sync';
import {
DetailResponse,
MessageType,
DetailContent,
DetailReceiver,
ContentType,
MessageDetailInfo,
MessageApiService,
RetrieveResourceFileRequest,
CancelRequest
2019-11-26 17:54:37 +09:00
} from '@ucap-webmessenger/api-message';
import { DeviceType, MimeUtil, FileUtil } from '@ucap-webmessenger/core';
2019-11-26 17:54:37 +09:00
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { NGXLogger } from 'ngx-logger';
import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
import { MessageStatusCode } from '@ucap-webmessenger/api';
2019-11-26 17:54:37 +09:00
export interface MessageDetailDialogData {
detail: DetailResponse;
loginRes: LoginResponse;
}
// tslint:disable-next-line: no-empty-interface
export interface MessageDetailDialogResult {
returnType: string;
messageInfo?: MessageDetailInfo;
cancelUserSeqs?: number[];
}
export interface DownloadQueueForMessage extends DetailContent {
downloadType: string;
}
2019-11-26 17:54:37 +09:00
@Component({
selector: 'app-layout-messenger-message-detail',
templateUrl: './message-detail.dialog.component.html',
styleUrls: ['./message-detail.dialog.component.scss']
})
export class MessageDetailDialogComponent implements OnInit {
messageDetail: DetailResponse;
messageInfo: MessageDetailInfo;
contents: DetailContent[] = [];
attachFile: DetailContent[] = [];
receivers: DetailReceiver[] = [];
isExpiredAttachFile = true;
MessageType = MessageType;
ContentType = ContentType;
downloadProgress = false;
downloadQueue: DownloadQueueForMessage[] = [];
downloadFail: DownloadQueueForMessage[] = [];
@ViewChild('rightDrawer', { static: true }) rightDrawer: MatDrawer;
@ViewChild('unReadUsers', { static: false }) unReadUsers: MatSelectionList;
2019-11-26 17:54:37 +09:00
constructor(
public dialogRef: MatDialogRef<
MessageDetailDialogData,
MessageDetailDialogResult
>,
@Inject(MAT_DIALOG_DATA) public data: MessageDetailDialogData,
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
2019-11-26 17:54:37 +09:00
private messageApiService: MessageApiService,
private snackBarService: SnackBarService,
2019-11-26 17:54:37 +09:00
private logger: NGXLogger,
private store: Store<any>,
private dialogService: DialogService
) {}
ngOnInit(): void {
this.messageDetail = this.data.detail;
this.messageInfo = this.messageDetail.msgInfo;
if (
!!this.messageDetail.contents &&
this.messageDetail.contents.length > 0
) {
this.messageDetail.contents.forEach(cont => {
if (cont.resType !== ContentType.AttachFile) {
this.contents.push(cont);
} else if (cont.resType === ContentType.AttachFile) {
if (cont.activeYn) {
this.isExpiredAttachFile = false;
}
this.attachFile.push(cont);
}
});
}
// contents 내 이미지 Thumnail 파일 정보 수집.
this.getThumbImage();
this.receivers = this.messageDetail.recvList.sort((a, b) =>
a.userName < b.userName ? -1 : a.userName > b.userName ? 1 : 0
);
}
getSendReceiverNames(): string {
if (this.messageInfo.type === MessageType.Receive) {
return this.messageInfo.sendUserName;
} else {
return this.receivers.map(user => user.userName).join(',');
}
}
getReadUserCount(readYn: boolean): number {
return this.receivers.filter(user => user.readYn === readYn).length;
2019-11-26 17:54:37 +09:00
}
getFileStatusIcon(file: DetailContent) {
const downloading =
this.downloadQueue.filter(dq => dq.resSeq === file.resSeq).length > 0;
const error =
this.downloadFail.filter(df => df.resSeq === file.resSeq).length > 0;
if (error) {
return 'mdi-window-close';
} else if (downloading) {
return ['mdi-spin', 'mdi-loading'];
} else {
return 'mdi-attachment';
}
}
getThumbImage(): void {
this.contents.forEach(content => {
if (content.resType === ContentType.Image) {
this.messageApiService
.retrieveResourceFile({
userSeq: this.data.loginRes.userSeq,
deviceType: DeviceType.PC,
tokenKey: this.data.loginRes.tokenString,
type: this.messageInfo.type,
msgId: this.messageInfo.msgId,
resUrl: content.thumbnailUrl
} as RetrieveResourceFileRequest)
.pipe(
take(1),
map(async rawBlob => {
const reader = new FileReader();
reader.readAsDataURL(rawBlob);
reader.onloadend = () => {
content.imageSrc = reader.result;
};
})
)
.subscribe();
}
});
}
// /**
// * @deprecated
// */
// downloadAttachFile(attachFile: DetailContent): void {
// this.messageApiService
// .retrieveResourceFile({
// userSeq: this.data.loginRes.userSeq,
// deviceType: DeviceType.PC,
// tokenKey: this.data.loginRes.tokenString,
// type: this.messageInfo.type,
// msgId: this.messageInfo.msgId,
// resUrl: attachFile.resUrl
// } as RetrieveResourceFileRequest)
// .pipe(
// take(1),
// map(async rawBlob => {
// const mimeType = MimeUtil.getMimeFromExtension(
// FileUtil.getExtension(attachFile.resContent)
// );
// const blob = rawBlob.slice(0, rawBlob.size, mimeType);
// FileUtil.fromBlobToBuffer(blob)
// .then(buffer => {
// this.nativeService
// .saveFile(buffer, attachFile.resContent, mimeType)
// .then(result => {
// if (!!result) {
// if (this.downloadFail.length > 0) {
// this.downloadFail = this.downloadFail.filter(
// df => df.resSeq !== attachFile.resSeq
// );
// }
// this.snackBarService.open(
// `파일이 경로[${result}]에 저장되었습니다.`,
// '',
// {
// duration: 3000,
// verticalPosition: 'bottom'
// }
// );
// } else {
// this.snackBarService.open('파일 저장에 실패하였습니다.');
// }
// })
// .catch(reason => {
// this.snackBarService.open('파일 저장에 실패하였습니다.');
// });
// })
// .catch(reason => {
// this.logger.error('download', reason);
// });
// })
// )
// .subscribe();
// }
downloadAttachFileSingle(attachFile: DetailContent): void {
if (!this.downloadProgress) {
this.downloadProgress = true;
this.downloadQueue = [{ ...attachFile, downloadType: 'SINGLE' }];
this.downloadFail = [];
if (!!this.downloadQueue && this.downloadQueue.length > 0) {
this.downloadAttachFileByQueue();
}
} else {
if (
this.downloadQueue.filter(dq => dq.resSeq === attachFile.resSeq)
.length === 0
) {
this.downloadQueue.push({ ...attachFile, downloadType: 'SINGLE' });
}
}
}
downloadAttachFileAll(): void {
if (!this.downloadProgress) {
this.downloadProgress = true;
this.downloadQueue = [];
this.downloadFail = [];
this.attachFile.forEach(file =>
this.downloadQueue.push({ ...file, downloadType: '' })
);
if (!!this.downloadQueue && this.downloadQueue.length > 0) {
this.downloadAttachFileByQueue();
}
} else {
this.dialogService.open<
AlertDialogComponent,
AlertDialogData,
AlertDialogResult
>(AlertDialogComponent, {
data: {
title: '',
html: `다운로드가 진행중입니다.`
}
});
}
}
downloadAttachFileByQueue(): void {
const attachFile = this.downloadQueue[0];
this.messageApiService
.retrieveResourceFile({
2019-11-26 17:54:37 +09:00
userSeq: this.data.loginRes.userSeq,
deviceType: DeviceType.PC,
tokenKey: this.data.loginRes.tokenString,
type: this.messageInfo.type,
msgId: this.messageInfo.msgId,
resUrl: attachFile.resUrl
} as RetrieveResourceFileRequest)
.pipe(
take(1),
map(async rawBlob => {
const mimeType = MimeUtil.getMimeFromExtension(
FileUtil.getExtension(attachFile.resContent)
);
const blob = rawBlob.slice(0, rawBlob.size, mimeType);
FileUtil.fromBlobToBuffer(blob)
.then(buffer => {
this.nativeService
.saveFile(buffer, attachFile.resContent, mimeType)
.then(result => {
if (!!result) {
if (
!!attachFile.downloadType &&
attachFile.downloadType === 'SINGLE'
) {
attachFile.downloadType = result;
}
if (this.downloadQueue.length > 1) {
this.downloadQueue = this.downloadQueue.slice(1);
} else {
this.downloadQueue = [];
}
} else {
throw new Error('response Error');
}
})
.catch(reason => {
this.downloadFail.push(this.downloadQueue[0]);
if (this.downloadQueue.length > 1) {
this.downloadQueue = this.downloadQueue.slice(1);
} else {
this.downloadQueue = [];
}
});
})
.catch(reason => {
this.downloadFail.push(this.downloadQueue[0]);
if (this.downloadQueue.length > 1) {
this.downloadQueue = this.downloadQueue.slice(1);
} else {
this.downloadQueue = [];
}
})
.finally(() => {
if (this.downloadQueue.length > 0) {
// 재귀
this.downloadAttachFileByQueue();
} else {
if (this.downloadFail.length > 0) {
// 일부 혹은 전부 실패.
let errMsg = '';
if (
!!attachFile.downloadType &&
attachFile.downloadType === 'SINGLE'
) {
// single :: fail
errMsg = '파일 저장에 실패하였습니다.';
} else {
// all
errMsg = '일부 저장중 오류가 발생하였습니다.';
}
this.snackBarService.open(errMsg, '확인', {
duration: 8000,
verticalPosition: 'bottom'
});
} else {
// 성공종료.
if (
!!attachFile.downloadType &&
attachFile.downloadType.length > 0
) {
// single :: success
this.snackBarService.open(
`파일이 경로[${attachFile.downloadType}]에 저장되었습니다.`,
'',
{
duration: 3000,
verticalPosition: 'bottom'
}
);
} else {
// all
this.snackBarService.open('모두 저장하였습니다.', '', {
duration: 3000,
verticalPosition: 'bottom'
});
}
}
this.downloadProgress = false;
}
});
})
)
.subscribe();
}
async onClickMessageMenu(menuType: string) {
switch (menuType) {
case 'MESSAGE_READ':
{
this.rightDrawer.open();
}
break;
case 'MESSAGE_CANCEL':
{
const result = await this.dialogService.open<
ConfirmDialogComponent,
ConfirmDialogData,
ConfirmDialogResult
>(ConfirmDialogComponent, {
data: {
title: '발송취소',
html: `예약발송을 취소 하시겠습니까?<br/>취소하면 목록에서도 영구 삭제됩니다.`
}
});
if (!!result && !!result.choice && result.choice) {
this.dialogRef.close({
returnType: 'CANCEL_RESERVATION',
messageInfo: this.messageInfo
});
}
}
break;
case 'MESSAGE_DEL':
{
const result = await this.dialogService.open<
ConfirmDialogComponent,
ConfirmDialogData,
ConfirmDialogResult
>(ConfirmDialogComponent, {
data: {
title: '삭제',
message: '선택한 쪽지를 삭제하시겠습니까?'
}
});
if (!!result && !!result.choice && result.choice) {
this.dialogRef.close({
returnType: 'DEL',
messageInfo: this.messageInfo
});
}
}
break;
}
}
async cancelSendMessageForUsers() {
if (
!!this.unReadUsers &&
this.unReadUsers.selectedOptions.selected.length > 0
) {
const result = await this.dialogService.open<
ConfirmDialogComponent,
ConfirmDialogData,
ConfirmDialogResult
>(ConfirmDialogComponent, {
data: {
title: '발송 취소',
message:
'발송 취소를 하시면 받는 사람의 쪽지함에서 쪽지가 삭제됩니다.'
}
});
if (!!result && !!result.choice && result.choice) {
const cancelUserSeqs: number[] = [];
const recvUserList: { userSeq: number }[] = [];
this.unReadUsers.selectedOptions.selected.forEach(selected => {
cancelUserSeqs.push(selected.value);
recvUserList.push({ userSeq: selected.value });
});
this.messageApiService
.cancelMessage({
userSeq: this.data.loginRes.userSeq,
deviceType: DeviceType.PC,
tokenKey: this.data.loginRes.tokenString,
type: this.messageInfo.type,
msgId: this.messageInfo.msgId,
recvUserList
} as CancelRequest)
.pipe(
map(async res => {
if (res.responseCode === MessageStatusCode.Success) {
this.receivers = this.receivers.filter(
user => cancelUserSeqs.indexOf(user.userSeq) < 0
);
this.rightDrawer.close();
} else {
this.logger.error('message cancel user Error!');
}
}),
catchError(error => of(this.logger.error(error)))
)
.subscribe();
}
2019-11-26 17:54:37 +09:00
}
}
onClickConfirm(): void {
this.dialogRef.close({
returnType: 'CLOSE'
});
2019-11-26 17:54:37 +09:00
}
}