diff --git a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/chat.component.ts b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/chat.component.ts index a40630eb..82779d78 100644 --- a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/chat.component.ts +++ b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/chat.component.ts @@ -39,7 +39,11 @@ export class ChatComponent implements OnInit, OnDestroy { private store: Store, private logger: NGXLogger, private sessionStorageService: SessionStorageService - ) {} + ) { + this.sessionVerinfo = this.sessionStorageService.get( + KEY_VER_INFO + ); + } ngOnInit() { this.roomSubscription = combineLatest([ diff --git a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/group.component.ts b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/group.component.ts index 4dd59dec..3434ba34 100644 --- a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/group.component.ts +++ b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/group.component.ts @@ -61,7 +61,9 @@ export class GroupComponent implements OnInit, OnDestroy { loginRes: LoginResponse; loginResSubscription: Subscription; - sessionVerinfo: VersionInfo2Response; + sessionVerinfo = this.sessionStorageService.get( + KEY_VER_INFO + ); constructor( private store: Store, @@ -72,9 +74,6 @@ export class GroupComponent implements OnInit, OnDestroy { ngOnInit() { const loginInfo = this.sessionStorageService.get(KEY_LOGIN_INFO); - this.sessionVerinfo = this.sessionStorageService.get( - KEY_VER_INFO - ); this.companyCode = loginInfo.companyCode; this.loginResSubscription = this.store diff --git a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/organization.component.html b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/organization.component.html index 4683d146..995c7140 100644 --- a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/organization.component.html +++ b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/organization.component.html @@ -9,7 +9,7 @@
+ [userInfo]="userInfo" [checkable]="true" [sessionVerinfo]="sessionVerinfo">
diff --git a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/organization.component.ts b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/organization.component.ts index 5a7be66b..06cecc51 100644 --- a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/organization.component.ts +++ b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/organization.component.ts @@ -16,6 +16,8 @@ import * as QueryStore from '@app/store/messenger/query'; import { SessionStorageService } from '@ucap-webmessenger/web-storage'; import { LoginInfo, KEY_LOGIN_INFO } from '@app/types'; import { take, map, switchMap } from 'rxjs/operators'; +import { VersionInfo2Response } from '@ucap-webmessenger/api-public'; +import { KEY_VER_INFO } from '@app/types/ver-info.type'; @Component({ selector: 'app-layout-chat-left-sidenav-organization', @@ -29,6 +31,9 @@ export class OrganizationComponent implements OnInit { selectedDepartmentStatus$: Observable; loginInfo = this.sessionStorageService.get(KEY_LOGIN_INFO); + sessionVerinfo = this.sessionStorageService.get( + KEY_VER_INFO + ); constructor( private store: Store, 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 35f3b5ae..68fd6ebe 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 @@ -42,7 +42,9 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewChecked { roomInfoSubscription: Subscription; userInfoList$: Observable; eventListProcessing$: Observable; - sessionVerInfo: VersionInfo2Response; + sessionVerInfo = this.sessionStorageService.get( + KEY_VER_INFO + ); constructor( private store: Store, @@ -52,9 +54,6 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewChecked { ngOnInit() { const loginInfo = this.sessionStorageService.get(KEY_LOGIN_INFO); - this.sessionVerInfo = this.sessionStorageService.get( - KEY_VER_INFO - ); this.loginResSubscription = this.store .pipe( diff --git a/projects/ucap-webmessenger-app/src/app/store/messenger/event/actions.ts b/projects/ucap-webmessenger-app/src/app/store/messenger/event/actions.ts index 9edd9bc8..eab3cb8c 100644 --- a/projects/ucap-webmessenger-app/src/app/store/messenger/event/actions.ts +++ b/projects/ucap-webmessenger-app/src/app/store/messenger/event/actions.ts @@ -8,7 +8,8 @@ import { SendNotification, ReadNotification, CancelNotification, - DelNotification + DelNotification, + ReadRequest } from '@ucap-webmessenger/protocol-event'; export const info = createAction( @@ -69,6 +70,24 @@ export const sendFailure = createAction( props<{ error: any }>() ); +export const read = createAction( + '[Messenger::Event] read', + props() +); + +export const readSuccess = createAction( + '[Messenger::Event] read Success', + props<{ + infoList: Info[]; + res: InfoResponse; + }>() +); + +export const readFailure = createAction( + '[Messenger::Event] read Failure', + props<{ error: any }>() +); + export const sendNotification = createAction( '[Messenger::Event] Send Notification', props<{ noti: SendNotification }>() 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 4dcaf2bc..a367fdfc 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 @@ -22,10 +22,12 @@ import { EventProtocolService, SSVC_TYPE_EVENT_INFO_DATA, SSVC_TYPE_EVENT_INFO_RES, - SendResponse + SendResponse, + ReadResponse } from '@ucap-webmessenger/protocol-event'; import * as ChatStore from '@app/store/messenger/chat'; +import * as SyncStore from '@app/store/messenger/sync'; import { info, @@ -40,10 +42,15 @@ import { readNotification, cancelNotification, delNotification, - recallInfoList + recallInfoList, + read, + readFailure } from './actions'; import { SessionStorageService } from '@ucap-webmessenger/web-storage'; import { RoomInfo } from '@ucap-webmessenger/protocol-room'; +import { refreshRoom } from '../sync'; +import { LoginInfo, KEY_LOGIN_INFO } from '@app/types'; +import { Dictionary } from '@ngrx/entity'; @Injectable() export class Effects { @@ -77,12 +84,28 @@ export class Effects { infoList.push(...(res as InfoData).infoList); break; case SSVC_TYPE_EVENT_INFO_RES: - this.store.dispatch( - infoSuccess({ - infoList, - res: res as InfoResponse - }) - ); + { + this.store.dispatch( + infoSuccess({ + infoList, + res: res as InfoResponse + }) + ); + + if (req.baseSeq === 0) { + // 최초 이벤트 목록 조회시 SSVC_TYPE_EVENT_READ_REQ 수행. + const maxSeq = Math.max.apply( + Math, + infoList.map(v => v.seq) + ); + this.store.dispatch( + read({ + roomSeq: req.roomSeq, + lastReadSeq: Number(maxSeq) + }) + ); + } + } break; } }), @@ -94,6 +117,28 @@ export class Effects { { dispatch: false } ); + read$ = createEffect( + () => { + return this.actions$.pipe( + ofType(read), + switchMap(req => { + return this.eventProtocolService.read(req).pipe( + map((res: ReadResponse) => { + this.store.dispatch( + SyncStore.updateUnreadCount({ + roomSeq: res.roomSeq, + noReadCnt: 0 + }) + ); + }), + catchError(error => of(readFailure({ error }))) + ); + }) + ); + }, + { dispatch: false } + ); + send$ = createEffect(() => this.actions$.pipe( ofType(send), @@ -166,13 +211,32 @@ export class Effects { withLatestFrom( this.store.pipe( select((state: any) => state.messenger.room.roomInfo as RoomInfo) + ), + this.store.pipe( + select( + (state: any) => + state.messenger.sync.room.entities as Dictionary + ) ) ), - tap(([action, roomInfo]) => { + tap(([action, roomInfo, trgtRoomInfos]) => { + // opened room :: event add if (!!roomInfo && roomInfo.roomSeq === action.roomSeq) { this.store.dispatch(appendInfoList({ info: action.info })); } + // not opened room :: unread count increased + if (!roomInfo || roomInfo.roomSeq !== action.roomSeq) { + const noReadCnt = trgtRoomInfos[action.roomSeq].noReadCnt; + this.store.dispatch( + SyncStore.updateUnreadCount({ + roomSeq: action.roomSeq, + noReadCnt: noReadCnt + 1 + }) + ); + } + + // 대화 > 리스트 :: finalEventMessage refresh this.store.dispatch(ChatStore.newEventMessage(action)); }) ); @@ -201,13 +265,24 @@ export class Effects { ) ), tap(([action, roomInfo]) => { + // 현재 방이 오픈되어 있으면 방내용 갱신 if (!!roomInfo && roomInfo.roomSeq === action.noti.roomSeq) { this.logger.debug('cancelNotification$', action, roomInfo); this.store.dispatch( recallInfoList({ eventSeq: action.noti.eventSeq }) ); - // this.store.dispatch(ChatStore.newEventMessage(action)); } + // 대화 > 리스트의 항목 갱신 + const loginInfo = this.sessionStorageService.get( + KEY_LOGIN_INFO + ); + this.store.dispatch( + SyncStore.refreshRoom({ + roomSeq: action.noti.roomSeq, + isDetail: true, + localeCode: loginInfo.localeCode + }) + ); }) ); }, diff --git a/projects/ucap-webmessenger-app/src/app/store/messenger/sync/actions.ts b/projects/ucap-webmessenger-app/src/app/store/messenger/sync/actions.ts index b30d35ea..62a94ced 100644 --- a/projects/ucap-webmessenger-app/src/app/store/messenger/sync/actions.ts +++ b/projects/ucap-webmessenger-app/src/app/store/messenger/sync/actions.ts @@ -10,7 +10,8 @@ import { import { RoomInfo, UserInfoShort, - UserInfo as RoomUserInfo + UserInfo as RoomUserInfo, + InfoRequest } from '@ucap-webmessenger/protocol-room'; import { Info } from '@ucap-webmessenger/protocol-event'; @@ -75,3 +76,28 @@ export const updateRoomForNewEventMessage = createAction( info: Info; }>() ); + +export const refreshRoom = createAction( + '[Messenger::Sync] refresh room in sync', + props() +); +export const refreshRoomSuccess = createAction( + '[Messenger::Sync] refresh room in sync Success', + props<{ + roomInfo: RoomInfo; + userInfoShortList: UserInfoShort[]; + userInfoList: RoomUserInfo[]; + }>() +); +export const refreshRoomFailure = createAction( + '[Messenger::Sync] refresh room in sync Failure', + props<{ error: any }>() +); + +export const updateUnreadCount = createAction( + '[Messenger::Sync] Update unread count', + props<{ + roomSeq: string; + noReadCnt?: number; + }>() +); diff --git a/projects/ucap-webmessenger-app/src/app/store/messenger/sync/effects.ts b/projects/ucap-webmessenger-app/src/app/store/messenger/sync/effects.ts index 7cd4fab0..f5bdfd32 100644 --- a/projects/ucap-webmessenger-app/src/app/store/messenger/sync/effects.ts +++ b/projects/ucap-webmessenger-app/src/app/store/messenger/sync/effects.ts @@ -26,7 +26,10 @@ import { room, roomFailure, roomSuccess, - updateRoomForNewEventMessage + updateRoomForNewEventMessage, + refreshRoom, + refreshRoomFailure, + refreshRoomSuccess } from './actions'; import { SessionStorageService } from '@ucap-webmessenger/web-storage'; @@ -54,7 +57,15 @@ import { regViewSuccess } from '@app/store/messenger/option'; import { RoomInfo, UserInfoShort, - UserInfo as RoomUserInfo + UserInfo as RoomUserInfo, + RoomProtocolService, + SSVC_TYPE_ROOM_INFO_ROOM, + SSVC_TYPE_ROOM_INFO_USER, + SSVC_TYPE_ROOM_INFO_USER2, + InfoData, + UserShortData, + UserData, + SSVC_TYPE_ROOM_INFO_RES } from '@ucap-webmessenger/protocol-room'; import { LoginInfo, KEY_LOGIN_INFO } from '@app/types'; @@ -328,10 +339,56 @@ export class Effects { { dispatch: false } ); + refreshRoom$ = createEffect( + () => { + let roomInfo: RoomInfo; + let userInfoShortList: UserInfoShort[]; + let userInfoList: RoomUserInfo[]; + + return this.actions$.pipe( + ofType(refreshRoom), + tap(() => { + roomInfo = null; + userInfoShortList = []; + userInfoList = []; + }), + switchMap(req => { + return this.roomProtocolService.info(req).pipe( + map(res => { + switch (res.SSVC_TYPE) { + case SSVC_TYPE_ROOM_INFO_ROOM: + roomInfo = (res as InfoData).roomInfo; + break; + case SSVC_TYPE_ROOM_INFO_USER: + userInfoShortList.push(...(res as UserShortData).userInfos); + break; + case SSVC_TYPE_ROOM_INFO_USER2: + userInfoList.push(...(res as UserData).userInfos); + break; + case SSVC_TYPE_ROOM_INFO_RES: + this.store.dispatch( + refreshRoomSuccess({ + roomInfo, + userInfoShortList, + userInfoList + }) + ); + break; + } + }), + catchError(error => of(refreshRoomFailure({ error }))) + ); + }) + ); + }, + { dispatch: false } + ); + constructor( private actions$: Actions, private store: Store, private syncProtocolService: SyncProtocolService, + private roomProtocolService: RoomProtocolService, private sessionStorageService: SessionStorageService, private logger: NGXLogger ) {} diff --git a/projects/ucap-webmessenger-app/src/app/store/messenger/sync/reducers.ts b/projects/ucap-webmessenger-app/src/app/store/messenger/sync/reducers.ts index eda7bd71..85f00ebf 100644 --- a/projects/ucap-webmessenger-app/src/app/store/messenger/sync/reducers.ts +++ b/projects/ucap-webmessenger-app/src/app/store/messenger/sync/reducers.ts @@ -11,7 +11,9 @@ import { buddy2Success, group2Success, roomSuccess, - updateRoomForNewEventMessage + updateRoomForNewEventMessage, + refreshRoomSuccess, + updateUnreadCount } from './actions'; import { RoomUserDetailData, @@ -113,6 +115,52 @@ export const reducer = createReducer( }; }), + on(refreshRoomSuccess, (state, action) => { + const roomUserList: RoomUserDetailData[] = []; + const roomUserShortList: RoomUserData[] = []; + + if (action.userInfoList) { + roomUserList.push({ + roomSeq: action.roomInfo.roomSeq, + userInfos: action.userInfoList + }); + } + if (action.userInfoShortList) { + roomUserShortList.push({ + roomSeq: action.roomInfo.roomSeq, + userInfos: action.userInfoShortList + }); + } + + return { + ...state, + room: adapterRoom.upsertOne(action.roomInfo, { + ...state.room + }), + roomUser: adapterRoomUser.upsertMany(roomUserList, { + ...state.roomUser + }), + roomUserShort: adapterRoomUserShort.upsertMany(roomUserShortList, { + ...state.roomUserShort + }) + }; + }), + + on(updateUnreadCount, (state, action) => { + const roomInfo: RoomInfo = { + ...state.room.entities[action.roomSeq], + noReadCnt: action.noReadCnt + }; + + return { + ...state, + room: adapterRoom.updateOne( + { id: action.roomSeq, changes: roomInfo }, + { ...state.room } + ) + }; + }), + on(AuthenticationStore.logout, (state, action) => { return { ...initialState diff --git a/projects/ucap-webmessenger-ui-room/src/lib/components/list-item.component.ts b/projects/ucap-webmessenger-ui-room/src/lib/components/list-item.component.ts index 5975c2c3..409e037a 100644 --- a/projects/ucap-webmessenger-ui-room/src/lib/components/list-item.component.ts +++ b/projects/ucap-webmessenger-ui-room/src/lib/components/list-item.component.ts @@ -8,11 +8,7 @@ import { import { NGXLogger } from 'ngx-logger'; import { VersionInfo2Response } from '@ucap-webmessenger/api-public'; import { EventType } from '@ucap-webmessenger/protocol-event'; -import { - FileInfo, - StickerInfo, - MassTextInfo -} from '@ucap-webmessenger/ui-chat'; +import { FileInfo, StickerInfo } from '@ucap-webmessenger/ui-chat'; import { FileType } from '@ucap-webmessenger/protocol-file'; import { LoginResponse, @@ -43,51 +39,7 @@ export class ListItemComponent implements OnInit { if (this.roomInfo.isTimeRoom) { this.finalEventMessage = '비밀 대화방입니다.'; } else { - try { - switch (this.roomInfo.finalEventType) { - case EventType.File: - { - let msg = 'Attach File'; - const contentJson: FileInfo = JSON.parse( - this.roomInfo.finalEventMessage - ); - if (contentJson.FileType === FileType.File) { - msg = '첨부파일'; - } else if (contentJson.FileType === FileType.Image) { - msg = '이미지'; - } else if (contentJson.FileType === FileType.Video) { - msg = '동영상'; - } - this.finalEventMessage = msg; - } - break; - case EventType.Sticker: - { - let msg = '스티커'; - const contentJson: StickerInfo = JSON.parse( - this.roomInfo.finalEventMessage - ); - if (contentJson.chat) { - msg += ' ' + contentJson.chat; - } - this.finalEventMessage = msg; - } - break; - case EventType.MassText: - { - const contentJson: MassTextInfo = JSON.parse( - this.roomInfo.finalEventMessage - ); - this.finalEventMessage = contentJson.Content; - } - break; - default: - this.finalEventMessage = this.roomInfo.finalEventMessage; - } - } catch (e) { - this.logger.error(e); - this.finalEventMessage = this.roomInfo.finalEventMessage; - } + this.finalEventMessage = this.roomInfo.finalEventMessage; } }