diff --git a/package-lock.json b/package-lock.json index 0e247a93..a9a94ee7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14104,7 +14104,8 @@ "tslib": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true }, "tslint": { "version": "5.15.0", diff --git a/projects/ucap-webmessenger-api-common/src/lib/apis/file-talk-save.ts b/projects/ucap-webmessenger-api-common/src/lib/apis/file-talk-save.ts index f3c01229..befcbb2c 100644 --- a/projects/ucap-webmessenger-api-common/src/lib/apis/file-talk-save.ts +++ b/projects/ucap-webmessenger-api-common/src/lib/apis/file-talk-save.ts @@ -6,25 +6,28 @@ import { APIDecoder, ParameterUtil, StatusCode, - JsonAnalization + JsonAnalization, + APIFormDataEncoder } from '@ucap-webmessenger/api'; import { JsonObject } from 'type-fest'; +import { FileUploadItem } from '../models/file-upload-item'; export interface FileTalkSaveRequest extends APIRequest { - userSeq: string; + userSeq: number; deviceType: DeviceType; token: string; - file?: File; + file: File; fileName?: string; + fileUploadItem: FileUploadItem; thumb?: File; voice?: boolean; voiceTime?: string; - roomId?: string; + roomSeq?: string; type?: string; } export interface FileTalkSaveResponse extends APIResponse { - roomID?: string; + roomSeq?: string; fileName?: string; fileExt?: string; fileType?: string; @@ -49,19 +52,21 @@ const fileTalkSaveEncodeMap = { thumb: 'thumb', voice: 'p_voice', voiceTime: 'p_voice_time', - roomId: 'p_room_id', + roomSeq: 'p_room_id', type: 'p_type' }; -export const encodeFileTalkSave: APIEncoder = ( +export const encodeFileTalkSave: APIFormDataEncoder = ( req: FileTalkSaveRequest ) => { const extraParams: any = {}; + + extraParams.userSeq = String(req.userSeq); if (!!req.voice) { extraParams.voice = req.voice ? 'Y' : 'N'; } - return ParameterUtil.encode(fileTalkSaveEncodeMap, req, extraParams); + return ParameterUtil.encodeFormData(fileTalkSaveEncodeMap, req, extraParams); }; export const decodeFileTalkSave: APIDecoder = ( @@ -71,7 +76,7 @@ export const decodeFileTalkSave: APIDecoder = ( const json: JsonObject | Error = JsonAnalization.receiveAnalization(res); return { statusCode: json.StatusCode, - roomID: json.RoomID, + roomSeq: json.RoomID, fileName: json.FileName, fileExt: json.FileExt, fileType: json.FileType, diff --git a/projects/ucap-webmessenger-api-common/src/lib/apis/file-talk-share.ts b/projects/ucap-webmessenger-api-common/src/lib/apis/file-talk-share.ts index d8677f7b..b867d935 100644 --- a/projects/ucap-webmessenger-api-common/src/lib/apis/file-talk-share.ts +++ b/projects/ucap-webmessenger-api-common/src/lib/apis/file-talk-share.ts @@ -4,32 +4,43 @@ import { APIResponse, APIEncoder, APIDecoder, - ParameterUtil + ParameterUtil, + JsonAnalization, + StatusCode } from '@ucap-webmessenger/api'; +import { JsonObject } from 'type-fest'; export interface FileTalkShareRequest extends APIRequest { userSeq: string; deviceType: DeviceType; token: string; attachmentsSeq?: string; - roomId?: string; + roomSeq?: string; synapKey?: string; } export interface FileTalkShareResponse extends APIResponse { - RoomID?: string; - FileName?: string; - FileExt?: string; - FileType?: string; - ThumbURL?: string; - AttSEQ?: string; - AttSize?: string; - AttRegDate?: string; - CompanyCode?: string; - SynapKey?: string; + roomSeq?: string; + fileName?: string; + fileExt?: string; + fileType?: string; + thumbnailUrl?: string; + attachmentSeq?: string; + attachmentSize?: string; + attachmentRegDate?: string; + companyCode?: string; + synapKey?: string; + returnJson?: any; } -const fileTalkShareEncodeMap = {}; +const fileTalkShareEncodeMap = { + userSeq: 'p_user_seq', + deviceType: 'p_device_type', + token: 'p_token', + attachmentsSeq: 'p_att_seq', + roomSeq: 'p_room_id', + synapKey: 'p_synap_key' +}; export const encodeFileTalkShare: APIEncoder = ( req: FileTalkShareRequest @@ -40,5 +51,26 @@ export const encodeFileTalkShare: APIEncoder = ( export const decodeFileTalkShare: APIDecoder = ( res: any ) => { - return {} as FileTalkShareResponse; + try { + const json: JsonObject | Error = JsonAnalization.receiveAnalization(res); + return { + statusCode: json.StatusCode, + roomSeq: json.RoomID, + fileName: json.FileName, + fileExt: json.FileExt, + fileType: json.FileType, + thumbnailUrl: json.ThumbURL, + attachmentSeq: json.AttSEQ, + attachmentSize: json.AttSize, + attachmentRegDate: json.AttRegDate, + companyCode: json.CompanyCode, + synapKey: json.SynapKey, + returnJson: res + } as FileTalkShareResponse; + } catch (e) { + return { + statusCode: StatusCode.Fail, + errorMessage: e + } as FileTalkShareResponse; + } }; diff --git a/projects/ucap-webmessenger-api-common/src/lib/apis/mass-talk-save.ts b/projects/ucap-webmessenger-api-common/src/lib/apis/mass-talk-save.ts index 3f8a4fa4..c7e23513 100644 --- a/projects/ucap-webmessenger-api-common/src/lib/apis/mass-talk-save.ts +++ b/projects/ucap-webmessenger-api-common/src/lib/apis/mass-talk-save.ts @@ -20,7 +20,7 @@ export interface MassTalkSaveRequest extends APIRequest { export interface MassTalkSaveResponse extends APIResponse { eventMassSeq?: string; - roomID?: string; + roomSeq?: string; regDate?: string; content?: string; returnJson?: any; @@ -51,7 +51,7 @@ export const decodeMassTalkSave: APIDecoder = ( content: json.Content, eventMassSeq: json.EventMassSeq, regDate: json.RegDate, - roomID: json.RoomID, + roomSeq: json.RoomID, returnJson: res } as MassTalkSaveResponse; } catch (e) { diff --git a/projects/ucap-webmessenger-api-common/src/lib/apis/trans-mass-talk-save.ts b/projects/ucap-webmessenger-api-common/src/lib/apis/trans-mass-talk-save.ts index e1b0ff46..d8eae853 100644 --- a/projects/ucap-webmessenger-api-common/src/lib/apis/trans-mass-talk-save.ts +++ b/projects/ucap-webmessenger-api-common/src/lib/apis/trans-mass-talk-save.ts @@ -4,8 +4,11 @@ import { APIResponse, APIEncoder, APIDecoder, - ParameterUtil + ParameterUtil, + JsonAnalization, + StatusCode } from '@ucap-webmessenger/api'; +import { JsonObject } from 'type-fest'; export interface TransMassTalkSaveRequest extends APIRequest { userSeq: string; @@ -13,20 +16,29 @@ export interface TransMassTalkSaveRequest extends APIRequest { token: string; original?: string; translation?: string; - roomId?: string; + roomSeq?: string; locale: string; } export interface TransMassTalkSaveResponse extends APIResponse { - EventTransSEQ?: string; - RoomID?: string; - RegDate?: string; - Locale?: string; - Original?: string; - Translation?: string; + roomSeq?: string; + registrationDate?: string; + translationSeq?: string; + locale?: string; + original?: string; + translation?: string; + returnJson?: any; } -const transMassTalkSaveEncodeMap = {}; +const transMassTalkSaveEncodeMap = { + userSeq: 'p_user_seq', + deviceType: 'p_device_type', + token: 'p_token', + original: 'p_original', + translation: 'p_translation', + roomSeq: 'p_room_id', + locale: 'p_locale' +}; export const encodeTransMassTalkSave: APIEncoder = ( req: TransMassTalkSaveRequest @@ -37,5 +49,22 @@ export const encodeTransMassTalkSave: APIEncoder = ( export const decodeTransMassTalkSave: APIDecoder = ( res: any ) => { - return {} as TransMassTalkSaveResponse; + try { + const json: JsonObject | Error = JsonAnalization.receiveAnalization(res); + return { + statusCode: json.StatusCode, + translationSeq: json.EventTransSEQ, + roomSeq: json.RoomID, + registrationDate: json.RegDate, + locale: json.Locale, + original: json.Original, + translation: json.Translation, + returnJson: res + } as TransMassTalkSaveResponse; + } catch (e) { + return { + statusCode: StatusCode.Fail, + errorMessage: e + } as TransMassTalkSaveResponse; + } }; diff --git a/projects/ucap-webmessenger-api-common/src/lib/apis/translation-save.ts b/projects/ucap-webmessenger-api-common/src/lib/apis/translation-save.ts index 5020d444..ecc77777 100644 --- a/projects/ucap-webmessenger-api-common/src/lib/apis/translation-save.ts +++ b/projects/ucap-webmessenger-api-common/src/lib/apis/translation-save.ts @@ -4,30 +4,42 @@ import { APIResponse, APIEncoder, APIDecoder, - ParameterUtil + ParameterUtil, + JsonAnalization, + StatusCode } from '@ucap-webmessenger/api'; +import { JsonObject } from 'type-fest'; export interface TranslationSaveRequest extends APIRequest { userSeq: string; deviceType: DeviceType; token: string; - roomId?: string; + roomSeq?: string; original?: string; srcLocale: string; destLocale: string; } export interface TranslationSaveResponse extends APIResponse { - EventTransSeq?: string; - RoomID?: string; - RegDate?: string; - SrcLocale?: string; - DestLocale?: string; - Original?: string; - Translation?: string; + translationSeq?: string; + roomSeq?: string; + registrationDate?: string; + srcLocale?: string; + destLocale?: string; + original?: string; + translation?: string; + returnJson?: any; } -const translationSaveEncodeMap = {}; +const translationSaveEncodeMap = { + userSeq: 'p_user_seq', + deviceType: 'p_device_type', + token: 'p_token', + roomSeq: 'p_room_id', + original: 'p_original', + srcLocale: 'p_src_locale', + destLocale: 'p_dest_locale' +}; export const encodeTranslationSave: APIEncoder = ( req: TranslationSaveRequest @@ -38,5 +50,23 @@ export const encodeTranslationSave: APIEncoder = ( export const decodeTranslationSave: APIDecoder = ( res: any ) => { - return {} as TranslationSaveResponse; + try { + const json: JsonObject | Error = JsonAnalization.receiveAnalization(res); + return { + statusCode: json.StatusCode, + translationSeq: json.EventTransSEQ, + roomSeq: json.RoomID, + registrationDate: json.RegDate, + srcLocale: json.SrcLocale, + destLocale: json.DestLocale, + original: json.Original, + translation: json.Translation, + returnJson: res + } as TranslationSaveResponse; + } catch (e) { + return { + statusCode: StatusCode.Fail, + errorMessage: e + } as TranslationSaveResponse; + } }; diff --git a/projects/ucap-webmessenger-api-common/src/lib/services/common-api.service.ts b/projects/ucap-webmessenger-api-common/src/lib/services/common-api.service.ts index fba37be7..46dfe58a 100644 --- a/projects/ucap-webmessenger-api-common/src/lib/services/common-api.service.ts +++ b/projects/ucap-webmessenger-api-common/src/lib/services/common-api.service.ts @@ -3,12 +3,11 @@ import { HttpClient, HttpEventType, HttpResponse, - HttpRequest, - HttpProgressEvent + HttpRequest } from '@angular/common/http'; import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { map, filter } from 'rxjs/operators'; import { _MODULE_CONFIG } from '../types/token'; import { ModuleConfig } from '../types/module-config'; @@ -115,21 +114,30 @@ export class CommonApiService { public fileTalkSave( req: FileTalkSaveRequest, fileTalkSaveUrl?: string - ): Observable { + ): Observable { + const asa = encodeFileTalkSave(req); + const httpReq = new HttpRequest( 'POST', !!fileTalkSaveUrl ? fileTalkSaveUrl : this.moduleConfig.urls.fileTalkSave, encodeFileTalkSave(req), - { reportProgress: true } + { reportProgress: true, responseType: 'text' as 'json' } ); + const progress = req.fileUploadItem.uploadStart(); + return this.httpClient.request(httpReq).pipe( - map(event => { + filter(event => { if (event instanceof HttpResponse) { - return decodeFileTalkSave(event); + return true; } else if (HttpEventType.UploadProgress === event.type) { - return event; + progress.next(Math.round((100 * event.loaded) / event.total)); } + return false; + }), + map((event: HttpResponse) => { + req.fileUploadItem.uploadComplete(); + return decodeFileTalkSave(event.body); }) ); } diff --git a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/chat.component.scss b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/chat.component.scss index 6ac50a90..f2825fce 100644 --- a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/chat.component.scss +++ b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/chat.component.scss @@ -1,14 +1,14 @@ -.current-head{ +.current-head { display: flex; justify-content: center; padding: 0 10px; height: 60px; - h3{ - display: inline-flex; - padding-left: 10px; + h3 { + display: inline-flex; + padding-left: 10px; align-items: center; } - .btn-box{ + .btn-box { height: 100%; margin-left: auto; display: inline-flex; @@ -24,41 +24,41 @@ padding: 0; font-size: 14px; border-bottom: 1px solid #dddddd; - .searchbox{ - width:100%; - height:100%; + .searchbox { + width: 100%; + height: 100%; } } -::ng-deep .searchbox{ - .mat-form-field{ - display:block; - .mat-form-field-wrapper{ +::ng-deep .searchbox { + .mat-form-field { + display: block; + .mat-form-field-wrapper { padding: 0; - padding-bottom:0 !important; + padding-bottom: 0 !important; height: 100%; - .mat-form-field-flex{ + .mat-form-field-flex { height: 59px; - padding:0 20px; + padding: 0 20px; align-items: center; - .mat-form-field-infix{ - width:100%; - font-size:14px; - border:none; + .mat-form-field-infix { + width: 100%; + font-size: 14px; + border: none; } - .mat-form-field-suffix{ - .mat-icon{ - line-height:24px; + .mat-form-field-suffix { + .mat-icon { + line-height: 24px; } } } } } - .mat-form-field-appearance-legacy{ - .mat-form-field-wrapper{ + .mat-form-field-appearance-legacy { + .mat-form-field-wrapper { padding: 0; } - .mat-form-field-underline{ - bottom:0; + .mat-form-field-underline { + bottom: 0; background-color: unset !important; } } @@ -76,4 +76,4 @@ .app-layout-chat-left-sidenav-chat-list-viewport { width: 100%; height: 100%; -} \ No newline at end of file +} diff --git a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.html b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.html index 041cf0cf..4b643ac4 100644 --- a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.html +++ b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.html @@ -81,7 +81,8 @@ fxFlex="1 1 auto" class="chat-content" #messageBoxContainer - ucapUiFileUploadFor + ucapFileUploadFor + [fileUploadQueue]="fileUploadQueue" (fileSelected)="onFileSelected($event)" (fileDragEnter)="onFileDragEnter($event)" (fileDragOver)="onFileDragOver()" @@ -109,16 +110,11 @@ -
-
- -
+
+
@@ -128,6 +124,7 @@ @@ -147,7 +144,7 @@ diff --git a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.scss b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.scss index 8907cb78..1a229e49 100644 --- a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.scss +++ b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.scss @@ -91,15 +91,16 @@ left: 0; width: 100%; height: 100%; - background-color: rgba(255, 255, 255, 0.95); + background-color: transparent; .file-drop-zone { position: absolute; + background-color: rgb(180, 180, 180); - top: 10%; - left: 10%; - width: 80%; - height: 80%; + top: calc(100% - 200px); + left: 20%; + width: 60%; + height: 200px; } } } diff --git a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.ts b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.ts index 2e481ec1..e6cf9e57 100644 --- a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.ts +++ b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/messages.component.ts @@ -2,10 +2,8 @@ import { Component, OnInit, OnDestroy, - AfterViewChecked, ViewChild, ElementRef, - AfterContentInit, AfterViewInit } from '@angular/core'; import { @@ -18,11 +16,12 @@ import { ConfirmDialogResult, AlertDialogComponent, AlertDialogData, - AlertDialogResult + AlertDialogResult, + FileUploadQueueComponent } from '@ucap-webmessenger/ui'; import { Store, select } from '@ngrx/store'; import { NGXLogger } from 'ngx-logger'; -import { Observable, Subscription } from 'rxjs'; +import { Observable, Subscription, forkJoin, of } from 'rxjs'; import { Info, EventType, @@ -44,7 +43,7 @@ import { UserSelectDialogType } from '@app/types'; import { RoomInfo, UserInfo, RoomType } from '@ucap-webmessenger/protocol-room'; -import { tap, take } from 'rxjs/operators'; +import { tap, take, map, catchError } from 'rxjs/operators'; import { FileInfo, FormComponent as UCapUiChatFormComponent @@ -52,7 +51,12 @@ import { import { KEY_VER_INFO } from '@app/types/ver-info.type'; import { VersionInfo2Response } from '@ucap-webmessenger/api-public'; import { MatMenuTrigger } from '@angular/material'; -import { CommonApiService } from '@ucap-webmessenger/api-common'; +import { + CommonApiService, + FileUploadItem, + FileTalkSaveRequest, + FileTalkSaveResponse +} from '@ucap-webmessenger/api-common'; import { CreateChatDialogComponent, CreateChatDialogData, @@ -65,6 +69,7 @@ import { } from '@app/layouts/common/dialogs/image-viewer.dialog.component'; import { CONST } from '@ucap-webmessenger/core'; import { PerfectScrollbarComponent } from 'ngx-perfect-scrollbar'; +import { StatusCode } from '@ucap-webmessenger/api'; @Component({ selector: 'app-layout-messenger-messages', @@ -86,6 +91,9 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit { @ViewChild('psChatContent', { static: true }) psChatContent: PerfectScrollbarComponent; + @ViewChild('fileUploadQueue', { static: true }) + fileUploadQueue: FileUploadQueueComponent; + environmentsInfo: EnvironmentsInfo; loginRes: LoginResponse; @@ -106,10 +114,6 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit { isCopyableMessage = isCopyable; isRecallableMessage = isRecallable; - fileDragOver = false; - files: File[]; - fileItems: DataTransferItemList; - /** Timer 대화방의 대화 삭제를 위한 interval */ interval: any; @@ -185,7 +189,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit { ); this.interval = setInterval(() => { - if (!!this.roomInfo.isTimeRoom) { + if (!!this.roomInfo && !!this.roomInfo.isTimeRoom) { this.store.dispatch(EventStore.infoIntervalClear({})); } }, 1000); @@ -369,8 +373,6 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit { onFileDragEnter(items: DataTransferItemList) { this.logger.debug('onFileDragEnter', items); - this.fileDragOver = true; - this.fileItems = items; } onFileDragOver() { @@ -379,17 +381,64 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit { onFileDragLeave() { this.logger.debug('onFileDragLeave'); - this.fileDragOver = false; } - onFileSelected(files: File[]) { - this.logger.debug('onFileSelected', files); - if (!this.files) { - this.files = []; - } - this.files.push(...files); + onFileSelected(fileUploadItems: FileUploadItem[]) { + this.logger.debug('onFileSelected', fileUploadItems); - this.fileDragOver = false; + const allObservables: Observable[] = []; + + for (const fileUploadItem of fileUploadItems) { + const req: FileTalkSaveRequest = { + userSeq: this.loginRes.userSeq, + deviceType: this.environmentsInfo.deviceType, + token: this.loginRes.tokenString, + roomSeq: this.roomInfo.roomSeq, + file: fileUploadItem.file, + fileName: fileUploadItem.file.name, + fileUploadItem + }; + + allObservables.push( + this.commonApiService + .fileTalkSave(req, this.sessionVerInfo.uploadUrl) + .pipe( + map(res => { + if (!res) { + return; + } + if (StatusCode.Success === res.statusCode) { + return res; + } else { + throw res; + } + }) + ) + ); + } + + forkJoin(allObservables) + .pipe(take(1)) + .subscribe( + resList => { + for (const res of resList) { + this.store.dispatch( + EventStore.send({ + senderSeq: this.loginRes.userSeq, + req: { + roomSeq: this.roomInfo.roomSeq, + eventType: EventType.File, + sentMessage: res.returnJson + } + }) + ); + } + }, + error => {}, + () => { + this.fileUploadQueue.onUploadComplete(); + } + ); } onContextMenuMessage(params: { event: MouseEvent; message: Info }) { diff --git a/projects/ucap-webmessenger-app/src/app/store/messenger/event/effects.ts b/projects/ucap-webmessenger-app/src/app/store/messenger/event/effects.ts index 02d449f1..6de918e6 100644 --- a/projects/ucap-webmessenger-app/src/app/store/messenger/event/effects.ts +++ b/projects/ucap-webmessenger-app/src/app/store/messenger/event/effects.ts @@ -65,7 +65,6 @@ import { cancel, cancelFailure, forward, - forwardFailure, forwardAfterRoomOpen, sendMass, sendMassFailure, @@ -418,7 +417,7 @@ export class Effects { send({ senderSeq: action.senderSeq, req: { - roomSeq: res.roomID, + roomSeq: res.roomSeq, eventType: EventType.MassText, sentMessage: res.returnJson } diff --git a/projects/ucap-webmessenger-ui-chat/src/lib/components/form.component.ts b/projects/ucap-webmessenger-ui-chat/src/lib/components/form.component.ts index 6f69bb1d..85a384e2 100644 --- a/projects/ucap-webmessenger-ui-chat/src/lib/components/form.component.ts +++ b/projects/ucap-webmessenger-ui-chat/src/lib/components/form.component.ts @@ -4,9 +4,12 @@ import { Output, EventEmitter, ViewChild, - ElementRef + ElementRef, + Input } from '@angular/core'; import { NgForm } from '@angular/forms'; +import { FileUploadItem } from '@ucap-webmessenger/api-common'; +import { FileUploadQueueComponent } from '@ucap-webmessenger/ui'; @Component({ selector: 'ucap-chat-form', @@ -14,11 +17,14 @@ import { NgForm } from '@angular/forms'; styleUrls: ['./form.component.scss'] }) export class FormComponent implements OnInit { + @Input() + fileUploadQueue: FileUploadQueueComponent; + @Output() send = new EventEmitter(); @Output() - sendFiles = new EventEmitter(); + sendFiles = new EventEmitter(); @ViewChild('replyForm', { static: false }) replyForm: NgForm; @@ -53,6 +59,13 @@ export class FormComponent implements OnInit { for (let i = 0; i < this.fileInput.nativeElement.files.length; i++) { files.push(this.fileInput.nativeElement.files.item(i)); } - this.sendFiles.emit(files); + + const fileUploadItems = FileUploadItem.fromFiles(files); + + if (!!this.fileUploadQueue) { + this.fileUploadQueue.onFileSelected(fileUploadItems); + } + + this.sendFiles.emit(fileUploadItems); } } diff --git a/projects/ucap-webmessenger-ui/src/lib/components/file-upload-queue.component.html b/projects/ucap-webmessenger-ui/src/lib/components/file-upload-queue.component.html index 106321ab..db5aa429 100644 --- a/projects/ucap-webmessenger-ui/src/lib/components/file-upload-queue.component.html +++ b/projects/ucap-webmessenger-ui/src/lib/components/file-upload-queue.component.html @@ -1,41 +1,31 @@ -
+
image
-
{{ file.name }}
-
+
{{ fileUploadItem.file.name }}
+
- + +
여기에 파일을 Drop하시면 업로드 됩니다.
-
-
- image -
-
+
diff --git a/projects/ucap-webmessenger-ui/src/lib/components/file-upload-queue.component.scss b/projects/ucap-webmessenger-ui/src/lib/components/file-upload-queue.component.scss index bc359aa5..d628a704 100644 --- a/projects/ucap-webmessenger-ui/src/lib/components/file-upload-queue.component.scss +++ b/projects/ucap-webmessenger-ui/src/lib/components/file-upload-queue.component.scss @@ -1,4 +1,4 @@ -.ucap-ui-file-upload-queue-container { +.ucap-file-upload-queue-container { width: 100%; height: 100%; } diff --git a/projects/ucap-webmessenger-ui/src/lib/components/file-upload-queue.component.ts b/projects/ucap-webmessenger-ui/src/lib/components/file-upload-queue.component.ts index 2393aa2a..7a3e8ae9 100644 --- a/projects/ucap-webmessenger-ui/src/lib/components/file-upload-queue.component.ts +++ b/projects/ucap-webmessenger-ui/src/lib/components/file-upload-queue.component.ts @@ -1,40 +1,108 @@ -import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { + Component, + OnInit, + Input, + Output, + EventEmitter, + ElementRef, + AfterViewInit +} from '@angular/core'; import { NGXLogger } from 'ngx-logger'; +import { FileUploadItem } from '@ucap-webmessenger/api-common'; @Component({ - selector: 'ucap-ui-file-upload-queue', + selector: 'ucap-file-upload-queue', templateUrl: './file-upload-queue.component.html', styleUrls: ['./file-upload-queue.component.scss'] }) -export class FileUploadQueueComponent implements OnInit { - @Output() - filesChange = new EventEmitter(); +export class FileUploadQueueComponent implements OnInit, AfterViewInit { + fileUploadItems: FileUploadItem[]; + uploadItems: DataTransferItem[]; - @Input() set files(files: File[]) { - this.uploadFiles = files; - this.uploadItems = undefined; + constructor( + private elementRef: ElementRef, + private logger: NGXLogger + ) {} + + ngOnInit() {} + + ngAfterViewInit(): void { + this.changeStyleDisplay(false); } - uploadFiles: File[]; - @Input() set items(items: DataTransferItemList) { + onDragEnter(items: DataTransferItemList): void { + if (!items || 0 === items.length) { + return; + } + const uploadItems: DataTransferItem[] = []; // tslint:disable-next-line: prefer-for-of for (let i = 0; i < items.length; i++) { uploadItems.push(items[i]); } this.uploadItems = [...uploadItems]; + this.changeStyleDisplay(true); } - uploadItems: DataTransferItem[]; - constructor(private logger: NGXLogger) {} - - ngOnInit() {} - - onClickClear(file: File) { - this.uploadFiles = this.uploadFiles.filter(f => { - return f.name !== file.name && f.path !== file.path; - }); - this.filesChange.emit(this.uploadFiles); + onDragLeave(): void { + this.changeStyleDisplay(false); } + + onDrop(fileUploadItems: FileUploadItem[]) { + if (!fileUploadItems || 0 === fileUploadItems.length) { + return; + } + this.fileUploadItems = fileUploadItems; + this.uploadItems = undefined; + } + + onFileSelected(fileUploadItems: FileUploadItem[]): void { + if (!fileUploadItems || 0 === fileUploadItems.length) { + return; + } + this.fileUploadItems = fileUploadItems; + this.uploadItems = undefined; + this.changeStyleDisplay(true); + } + + onUploadComplete(): void { + setTimeout(() => { + this.fileUploadItems = undefined; + this.changeStyleDisplay(false); + }, 1000); + } + + isEventInElement(event: DragEvent): boolean { + const rect = this.elementRef.nativeElement.getBoundingClientRect(); + // const rect: DOMRect = this.elementRef.nativeElement.getBoundingClientRect(); + + if ( + event.pageX >= rect.left && + event.pageX <= rect.left + rect.width && + event.pageY >= rect.top && + event.pageY <= rect.top + rect.height + ) { + return true; + } + return false; + } + + private changeStyleDisplay(show: boolean): void { + if (show || (!!this.fileUploadItems && 0 < this.fileUploadItems.length)) { + this.elementRef.nativeElement.style.display = ''; + } else { + this.elementRef.nativeElement.style.display = 'none'; + } + } + + // onClickClear(fileUploadItem: FileUploadItem) { + // this.fileUploadItems = this.fileUploadItems.filter(f => { + // return ( + // f.file.name !== fileUploadItem.file.name && + // f.file.path !== fileUploadItem.file.path + // ); + // }); + // this.filesChange.emit(this.fileUploadItems); + // } } diff --git a/projects/ucap-webmessenger-ui/src/lib/directives/file-upload-for.directive.ts b/projects/ucap-webmessenger-ui/src/lib/directives/file-upload-for.directive.ts index aac21200..62fb4c11 100644 --- a/projects/ucap-webmessenger-ui/src/lib/directives/file-upload-for.directive.ts +++ b/projects/ucap-webmessenger-ui/src/lib/directives/file-upload-for.directive.ts @@ -3,15 +3,22 @@ import { ElementRef, EventEmitter, HostListener, - Output + Output, + Input, + AfterViewInit } from '@angular/core'; import { NGXLogger } from 'ngx-logger'; +import { FileUploadQueueComponent } from '../components/file-upload-queue.component'; +import { FileUploadItem } from '@ucap-webmessenger/api-common'; @Directive({ - selector: 'input[ucapUiFileUploadFor], div[ucapUiFileUploadFor]' + selector: 'input[ucapFileUploadFor], div[ucapFileUploadFor]' }) -export class FileUploadForDirective { +export class FileUploadForDirective implements AfterViewInit { + @Input() + fileUploadQueue: FileUploadQueueComponent; + @Output() public fileDragEnter = new EventEmitter(); @@ -22,12 +29,14 @@ export class FileUploadForDirective { public fileDragLeave = new EventEmitter(); @Output() - public fileSelected = new EventEmitter(); + public fileSelected = new EventEmitter(); dragOver = false; constructor(private elementRef: ElementRef, private logger: NGXLogger) {} + ngAfterViewInit(): void {} + @HostListener('window:dragenter', ['$event']) public onDragEnter(event: DragEvent): any { if (!this.isFileDrag(event.dataTransfer)) { @@ -37,6 +46,9 @@ export class FileUploadForDirective { if (!this.dragOver) { this.fileDragEnter.emit(event.dataTransfer.items); this.dragOver = true; + if (!!this.fileUploadQueue) { + this.fileUploadQueue.onDragEnter(event.dataTransfer.items); + } } } @@ -46,7 +58,7 @@ export class FileUploadForDirective { return; } - if (this.isEventInElement(event)) { + if (this.fileUploadQueue.isEventInElement(event)) { event.dataTransfer.dropEffect = 'copy'; } else { event.dataTransfer.dropEffect = 'none'; @@ -63,13 +75,16 @@ export class FileUploadForDirective { if (event && event.pageX === 0 && event.pageY === 0) { this.fileDragLeave.emit(); this.dragOver = false; + if (!!this.fileUploadQueue) { + this.fileUploadQueue.onDragLeave(); + } } } @HostListener('change') public onChange(): any { const files = this.elementRef.nativeElement.files; - this.fileSelected.emit(files); + this.fileSelected.emit(FileUploadItem.fromFiles(files)); this.elementRef.nativeElement.value = ''; } @@ -79,11 +94,15 @@ export class FileUploadForDirective { return; } const files = event.dataTransfer.files; - this.fileSelected.emit(files); + const fileUploadItems = FileUploadItem.fromFiles(files); + this.fileSelected.emit(fileUploadItems); event.preventDefault(); event.stopPropagation(); this.elementRef.nativeElement.value = ''; this.dragOver = false; + if (!!this.fileUploadQueue) { + this.fileUploadQueue.onDrop(fileUploadItems); + } } private isFileDrag(dataTransfer: DataTransfer): boolean { @@ -101,18 +120,4 @@ export class FileUploadForDirective { return true; } - - private isEventInElement(event: DragEvent): boolean { - const rect: DOMRect = this.elementRef.nativeElement.getBoundingClientRect(); - - if ( - event.pageX >= rect.left && - event.pageX <= rect.left + rect.width && - event.pageY >= rect.top && - event.pageY <= rect.top + rect.height - ) { - return true; - } - return false; - } }