import { Subject, of, Observable, forkJoin } from 'rxjs'; import { takeUntil, map, catchError, take } from 'rxjs/operators'; import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, Input, ViewChild, ElementRef } from '@angular/core'; import { Store, select } from '@ngrx/store'; import { Dictionary } from '@ngrx/entity'; import { RoomInfo } from '@ucap/protocol-room'; import { SendRequest as SendEventRequest, EventType } from '@ucap/protocol-event'; import { LoginResponse } from '@ucap/protocol-authentication'; import { ChattingActions } from '@ucap/ng-store-chat'; import { LoginSelector, ConfigurationSelector } from '@ucap/ng-store-authentication'; import { StickerFilesInfo, KEY_STICKER_HISTORY } from '@ucap/ng-core'; import { AlertDialogComponent, AlertDialogData, AlertDialogResult } from '@ucap/ng-ui'; import { I18nService } from '@ucap/ng-i18n'; import { LogService } from '@ucap/ng-logger'; import { MatDialog } from '@angular/material/dialog'; import { TranslationSaveResponse, MassTalkSaveRequest, FileTalkSaveResponse, FileTalkSaveRequest } from '@ucap/api-common'; import { environment } from '@environments'; import { LocalStorageService } from '@ucap/ng-web-storage'; import { CommonApiService } from '@ucap/ng-api-common'; import { LoginSession } from '@app/models/login-session'; import { AppAuthenticationService } from '@app/services/app-authentication.service'; import { StatusCode, FileUploadItem } from '@ucap/api'; import { AppFileService } from '@app/services/app-file.service'; import { VersionInfo2Response } from '@ucap/api-public'; import { FileUploadSelectorComponent } from '@app/ucap/chat/components/file-upload.selector.component'; import { FileUtil } from '@ucap/core'; import { AppChatService } from '@app/services/app-chat.service'; export enum SelectorType { EMPTY = '', STICKER = 'STICKER', TRANSLATION = 'TRANSLATION', FILEUPLOAD = 'FILEUPLOAD', EMAILSENDER = 'EMAILSENDER' } @Component({ selector: 'app-sections-chat-form', templateUrl: './form.section.component.html', styleUrls: ['./form.section.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) export class FormSectionComponent implements OnInit, OnDestroy { @Input() set roomId(roomId: string) { this._roomId = roomId; } get roomId(): string { return this._roomId; } // tslint:disable-next-line: variable-name _roomId: string; versionInfo2Res: VersionInfo2Response; loginSession: LoginSession; loginRes: LoginResponse; currentRoomInfo: RoomInfo; selectorType: SelectorType = SelectorType.EMPTY; /** About Sticker */ selectedSticker: StickerFilesInfo; /** About Translation */ translationSimpleview = false; translationPreview = false; destLocale = 'en'; // default English :: en translationPreviewInfo: { previewInfo: TranslationSaveResponse | null; translationType: EventType.Translation | EventType.MassTranslation; }; @ViewChild('messageInput', { static: false }) messageInput: ElementRef; @ViewChild('fileInput', { static: false }) fileInput: ElementRef; @ViewChild('fileUploadSelector', { static: false }) fileUploadSelector: FileUploadSelectorComponent; SelectorType = SelectorType; private ngOnDestroySubject: Subject; constructor( private appFileService: AppFileService, private appChatService: AppChatService, private store: Store, private i18nService: I18nService, private dialog: MatDialog, private localStorageService: LocalStorageService, private logService: LogService, private appAuthenticationService: AppAuthenticationService, private commonApiService: CommonApiService, private changeDetectorRef: ChangeDetectorRef ) {} ngOnInit(): void { this.ngOnDestroySubject = new Subject(); this.store .pipe( takeUntil(this.ngOnDestroySubject), select(ConfigurationSelector.versionInfo2Response) ) .subscribe((versionInfo2Res) => { this.versionInfo2Res = versionInfo2Res; }); this.store .pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes)) .subscribe((loginRes) => { this.loginRes = loginRes; }); this.appAuthenticationService .getLoginSession$() .pipe(takeUntil(this.ngOnDestroySubject)) .subscribe((loginSession) => (this.loginSession = loginSession)); this.store .pipe( takeUntil(this.ngOnDestroySubject), select( (state: any) => state.chat.room.rooms.entities as Dictionary ) ) .subscribe((rooms) => { if (!!this.roomId) { this.currentRoomInfo = rooms[this.roomId]; this.changeDetectorRef.detectChanges(); } }); } ngOnDestroy(): void { if (!!this.ngOnDestroySubject) { this.ngOnDestroySubject.complete(); } } /** About Selector */ onOpenSelector(type: SelectorType): void { this.selectorType = type; this.changeDetectorRef.detectChanges(); } clearSelector(): void { this.selectorType = SelectorType.EMPTY; this.selectedSticker = null; this.changeDetectorRef.detectChanges(); } /** Element Handling */ focus(clearField: boolean = true): void { if (!!this.messageInput) { if (!!clearField) { this.messageInput.nativeElement.value = ''; this.clearSelector(); } this.messageInput.nativeElement.focus(); } } onChangeFileInput(): void { const self = this; const fileList = this.fileInput.nativeElement.files; this.appFileService .validUploadFile(fileList, this.versionInfo2Res?.fileAllowSize) .then((result) => { if (!result) { self.fileInput.nativeElement.value = ''; return; } else { // selector open self.onOpenSelector(SelectorType.FILEUPLOAD); // FileuploadItem Init. & FileSelector Init. const fileUploadItems = FileUploadItem.fromFiles(fileList); if (!!self.fileUploadSelector) { self.fileUploadSelector.onFileSelected(fileUploadItems); } self.fileInput.nativeElement.value = ''; // File Upload.. self.appChatService .sendMessageOfAttachFile( self.loginRes, self.loginSession.deviceType, self.currentRoomInfo.roomId, fileUploadItems ) .then((success) => { if (!!success) { self.clearSelector(); if (!!self.fileUploadSelector) { self.fileUploadSelector.onUploadComplete(); } } }) .catch((err) => { alert(err); if (!!self.fileUploadSelector) { self.fileUploadSelector.onUploadComplete(); } }); } }) .catch((err) => { self.fileInput.nativeElement.value = ''; self.logService.error(`validUploadFile ${err}`); }); } onKeydown(event: KeyboardEvent) { if (event.key === 'PageUp' || event.key === 'PageDown') { event.preventDefault(); return false; } else if (event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); this.send(); } } onSelectedSticker(stickerInfo: StickerFilesInfo) { this.selectedSticker = stickerInfo; this.focus(false); } async send() { const roomId = this.currentRoomInfo.roomId; const userSeq = this.loginRes.userSeq; let message = this.messageInput.nativeElement.value; if (!!message || message.trim().length > 0) { message = message.replace(/\t/g, ' '); } // Empty Check. if (!this.selectedSticker) { try { if (!message || message.trim().length === 0) { const result = await this.dialog.open< AlertDialogComponent, AlertDialogData, AlertDialogResult >(AlertDialogComponent, { data: { title: this.i18nService.t('errors.label'), message: this.i18nService.t('errors.inputChatMessage') }, panelClass: '' }); return; } } catch (e) { this.logService.debug(e); } } if ( this.selectorType === SelectorType.TRANSLATION && this.destLocale.trim().length > 0 ) { /** CASE : Translation */ // 번역할 대화 없이 스티커만 전송할 경우. if (!message || message.trim().length === 0) { this.appChatService.sendMessageOfSticker( userSeq, roomId, this.selectedSticker, message ); this.clearSelector(); } else { this.appChatService.sendMessageOfTranslate( this.loginRes, this.loginSession.deviceType, this.destLocale, roomId, message, this.selectedSticker ); } } else if (!!this.selectedSticker) { /** CASE : Sticker */ this.appChatService.sendMessageOfSticker( userSeq, roomId, this.selectedSticker, message ); this.clearSelector(); } else if ( message.trim().length > environment.productConfig.chat.masstextLength ) { /** CASE : MASS TEXT */ this.appChatService.sendMessageOfMassText( this.loginRes, this.loginSession.deviceType, roomId, message ); } else { /** CASE : Normal Text */ this.appChatService.sendMessageOfNormal(userSeq, roomId, message); } this.focus(); } }