import { GroupProtocolService } from './../../../../../../ucap-webmessenger-protocol-group/src/lib/services/group-protocol.service'; import { Injectable } from '@angular/core'; import { Actions, ofType, createEffect } from '@ngrx/effects'; import { of } from 'rxjs'; import { catchError, exhaustMap, map, withLatestFrom, switchMap, tap } from 'rxjs/operators'; import { Store, select } from '@ngrx/store'; import { Dictionary } from '@ngrx/entity'; import { NGXLogger } from 'ngx-logger'; import { buddy2, buddy2Success, buddy2Failure, group2, group2Success, group2Failure, room, roomFailure, roomSuccess, updateRoomForNewEventMessage, refreshRoom, refreshRoomFailure, refreshRoomSuccess, createGroupAndBuddy, addBuddy, addBuddyFailure, delBuddy, delBuddyFailure, delBuddySuccess, updateBuddy, updateBuddySuccess, updateBuddyFailure, createGroup, createGroupSuccess, createGroupFailure, updateGroup, updateGroupFailure, updateGroupMember, delGroup, delGroupFailure, delGroupSuccess } from './actions'; import { SessionStorageService } from '@ucap-webmessenger/web-storage'; import { LoginInfo, KEY_LOGIN_INFO } from '@app/types'; import { SyncProtocolService, SSVC_TYPE_SYNC_BUDDY2_DATA, BuddyResponse, BuddyDetailData, SSVC_TYPE_SYNC_GROUP_DATA2, GroupDetailData, GroupResponse, UserInfo, SSVC_TYPE_SYNC_BUDDY2_RES, SSVC_TYPE_SYNC_GROUP_RES2, SSVC_TYPE_SYNC_ROOM_DATA, SSVC_TYPE_SYNC_ROOM_USER, SSVC_TYPE_SYNC_ROOM_USER2, SSVC_TYPE_SYNC_ROOM_RES, RoomData, RoomUserData, RoomUserDetailData, RoomResponse } from '@ucap-webmessenger/protocol-sync'; import { RoomInfo, UserInfoShort, 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 { LoginResponse } from '@ucap-webmessenger/protocol-authentication'; import { AddResponse as GroupAddResponse, UpdateResponse as GroupUpdateResponse, DelResponse as GroupDelResponse } from '@ucap-webmessenger/protocol-group'; import { BuddyProtocolService, AddResponse as BuddyAddResponse, DelResponse as BuddyDelResponse, UpdateResponse as BuddyUpdateResponse } from '@ucap-webmessenger/protocol-buddy'; import * as ChatStore from '@app/store/messenger/chat'; import * as RoomStore from '@app/store/messenger/room'; @Injectable() export class Effects { buddy2$ = createEffect( () => { let buddyList: UserInfo[]; return this.actions$.pipe( ofType(buddy2), tap(() => { buddyList = []; }), switchMap(req => { return this.syncProtocolService.buddy2(req).pipe( map(res => { switch (res.SSVC_TYPE) { case SSVC_TYPE_SYNC_BUDDY2_DATA: buddyList.push( ...(res as BuddyDetailData).buddyInfos.filter( v => v.isBuddy && v.isActive ) ); break; case SSVC_TYPE_SYNC_BUDDY2_RES: this.store.dispatch( buddy2Success({ buddyList, syncDate: (res as BuddyResponse).syncDate }) ); break; } }), catchError(error => of(buddy2Failure({ error }))) ); }) ); }, { dispatch: false } ); group2$ = createEffect( () => { let groupList: GroupDetailData[]; return this.actions$.pipe( ofType(group2), tap(() => { groupList = []; }), switchMap(req => { return this.syncProtocolService.group2(req).pipe( map(res => { switch (res.SSVC_TYPE) { case SSVC_TYPE_SYNC_GROUP_DATA2: if ((res as GroupDetailData).isActive) { groupList.push(res as GroupDetailData); } break; case SSVC_TYPE_SYNC_GROUP_RES2: this.store.dispatch( group2Success({ groupList, syncDate: (res as GroupResponse).syncDate }) ); break; } }), catchError(error => of(group2Failure({ error }))) ); }) ); }, { dispatch: false } ); room$ = createEffect( () => { let roomList: RoomInfo[]; let roomUserInfoMap: { [param: string]: { userInfoShortList: UserInfoShort[]; userInfoList: RoomUserInfo[]; }; }; return this.actions$.pipe( ofType(room), tap(() => { roomList = []; roomUserInfoMap = {}; }), switchMap(req => { return this.syncProtocolService.room(req).pipe( map(res => { switch (res.SSVC_TYPE) { case SSVC_TYPE_SYNC_ROOM_DATA: roomList.push( ...(res as RoomData).roomInfos.filter(v => v.isJoinRoom) ); break; case SSVC_TYPE_SYNC_ROOM_USER: { const roomUserData = res as RoomUserData; if (!roomUserInfoMap[roomUserData.roomSeq]) { roomUserInfoMap[roomUserData.roomSeq] = { userInfoList: [], userInfoShortList: [] }; } roomUserInfoMap[ roomUserData.roomSeq ].userInfoShortList.push(...roomUserData.userInfos); } break; case SSVC_TYPE_SYNC_ROOM_USER2: { const roomUserDetailData = res as RoomUserDetailData; if (!roomUserInfoMap[roomUserDetailData.roomSeq]) { roomUserInfoMap[roomUserDetailData.roomSeq] = { userInfoList: [], userInfoShortList: [] }; } roomUserInfoMap[ roomUserDetailData.roomSeq ].userInfoList.push(...roomUserDetailData.userInfos); } break; case SSVC_TYPE_SYNC_ROOM_RES: { this.store.dispatch( roomSuccess({ roomList, roomUserInfoMap, syncDate: (res as RoomResponse).syncDate }) ); } break; } }), catchError(error => of(roomFailure({ error }))) ); }) ); }, { dispatch: false } ); newEventMessageForRoomInfoList$ = createEffect( () => this.actions$.pipe( ofType(ChatStore.newEventMessage), withLatestFrom( this.store.pipe( select((state: any) => state.messenger.sync.room.ids as string[]) ), this.store.pipe( select((state: any) => state.messenger.sync.room.syncDate as string) ) ), tap(([action, roomSeqList, roomSyncDate]) => { const index = roomSeqList.findIndex( (roomSeq, i) => roomSeq === action.roomSeq ); if (-1 === index) { const loginInfo = this.sessionStorageService.get( KEY_LOGIN_INFO ); this.store.dispatch( room({ syncDate: roomSyncDate, localeCode: loginInfo.localeCode }) ); return; } this.store.dispatch(updateRoomForNewEventMessage(action)); }) ), { dispatch: false } ); openRoom$ = createEffect( () => this.actions$.pipe( ofType(ChatStore.openRoom), withLatestFrom( this.store.pipe( select( (state: any) => state.account.authentication.loginRes as LoginResponse ) ), this.store.pipe( select( (state: any) => state.messenger.sync.roomUser.entities as Dictionary< RoomUserDetailData > ) ), this.store.pipe( select( (state: any) => state.messenger.sync.roomUserShort.entities as Dictionary< RoomUserData > ) ) ), tap(([action, loginRes, roomUsers, roomUserShorts]) => { const userSeqList = [...action.userSeqList, loginRes.userSeq]; let roomSeq = null; for (const key in roomUsers) { if (roomUsers.hasOwnProperty(key)) { const element = roomUsers[key]; if (userSeqList.length === element.userInfos.length) { roomSeq = key; for (const roomUserInfo of element.userInfos) { if (-1 === userSeqList.indexOf(roomUserInfo.seq)) { roomSeq = null; break; } } } } } for (const key in roomUserShorts) { if (roomUserShorts.hasOwnProperty(key)) { const element = roomUserShorts[key]; if (userSeqList.length === element.userInfos.length) { roomSeq = key; for (const roomUserDetailData of element.userInfos) { if (-1 === userSeqList.indexOf(roomUserDetailData.seq)) { roomSeq = null; break; } } } } } this.logger.debug( 'openRoom', 'userSeqList', userSeqList, 'roomSeq', roomSeq ); if (!!roomSeq) { this.store.dispatch(ChatStore.selectedRoom({ roomSeq })); return; } this.store.dispatch( RoomStore.open({ req: { divCd: 'DivCode', userSeqs: userSeqList } }) ); }) ), { 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 } ); createGroup$ = createEffect(() => this.actions$.pipe( ofType(createGroup), map(action => action.groupName), exhaustMap(req => { return this.groupProtocolService .add({ groupName: req }) .pipe( map((res: GroupAddResponse) => { return createGroupSuccess(res); }), catchError(error => of(createGroupFailure({ error }))) ); }) ) ); createGroupAndBuddy$ = createEffect(() => this.actions$.pipe( ofType(createGroupAndBuddy), withLatestFrom( this.store.pipe( select( (state: any) => state.messenger.sync.buddy2.entities as Dictionary ) ) ), exhaustMap(([action, buddyList]) => { return this.groupProtocolService .add({ groupName: action.groupName }) .pipe( map((res: GroupAddResponse) => { return createGroupSuccess(res); }), tap(res => { if (!!action.trgtUserSeq && action.trgtUserSeq.length > 0) { // 그룹원으로 추가할 대상이 유입. // STEP 1 : 그룹원으로 등록될 대상중 Buddy 등록해야 하는 인원 수집. const addBuddyList: number[] = []; action.trgtUserSeq.forEach(item => { if (!buddyList[item]) { addBuddyList.push(item); } }); if (addBuddyList.length > 0) { this.store.dispatch(addBuddy({ userSeqs: addBuddyList })); } this.store.dispatch( updateGroup({ // 0: 동료그룹SEQ(n) groupSeq: res.groupSeq, groupName: res.groupName, userSeqs: action.trgtUserSeq }) ); } }), catchError(error => of(createGroupFailure({ error }))) ); }) ) ); updateGroupMember$ = createEffect( () => { return this.actions$.pipe( ofType(updateGroupMember), withLatestFrom( this.store.pipe( select( (state: any) => state.messenger.sync.buddy2.entities as Dictionary ) ), this.store.pipe( select( (state: any) => state.messenger.sync.group2.entities as Dictionary< GroupDetailData > ) ) ), tap(([action, buddyList, groupList]) => { // Add Buddy const addBuddyList: number[] = []; action.trgtUserSeq.forEach(item => { if (!buddyList[item]) { addBuddyList.push(item); } }); // Del Buddy let delBuddyInGroup: number[] = action.oldGroup.userSeqs.filter( v => action.trgtUserSeq.indexOf(v) < 0 ); // tslint:disable-next-line: no-shadowed-variable delBuddyInGroup = delBuddyInGroup.filter(delBuddy => { let exist = false; // tslint:disable-next-line: forin for (const key in groupList) { const group: GroupDetailData = groupList[key]; if ( group.seq !== action.oldGroup.seq && group.userSeqs.filter(v => v === delBuddy).length > 0 ) { exist = true; break; } } return !exist; }); if (addBuddyList.length > 0) { this.store.dispatch(addBuddy({ userSeqs: addBuddyList })); } if (delBuddyInGroup.length > 0) { // 즐겨찾기 해제. delBuddyInGroup.forEach(buddySeq => { this.buddyProtocolService .update({ seq: buddySeq, isFavorit: false }) .pipe(catchError(error => of(delBuddyFailure({ error })))); }); // 동료 삭제 this.store.dispatch(delBuddy({ userSeqs: delBuddyInGroup })); } this.logger.debug('group member update', action.trgtUserSeq); this.store.dispatch( updateGroup({ groupSeq: action.oldGroup.seq, groupName: action.oldGroup.name, userSeqs: action.trgtUserSeq }) ); }) ); }, { dispatch: false } ); delGroup$ = createEffect( () => { return this.actions$.pipe( ofType(delGroup), withLatestFrom( this.store.pipe( select( (state: any) => state.messenger.sync.group2.entities as Dictionary< GroupDetailData > ) ) ), map(([action, groupList]) => { // Del Buddy const trgtBuddys = action.group.userSeqs; // tslint:disable-next-line: no-shadowed-variable const delBuddyList = trgtBuddys.filter(delBuddy => { let exist = false; // tslint:disable-next-line: forin for (const key in groupList) { const group: GroupDetailData = groupList[key]; if ( group.seq !== action.group.seq && group.userSeqs.filter(v => v === delBuddy).length > 0 ) { exist = true; break; } } return !exist; }); if (delBuddyList.length > 0) { this.logger.debug('Del Buddy', delBuddyList); // 즐겨찾기 해제. delBuddyList.forEach(buddySeq => { this.buddyProtocolService .update({ seq: buddySeq, isFavorit: false }) .pipe(catchError(error => of(delBuddyFailure({ error })))); }); // 동료 삭제 this.store.dispatch(delBuddy({ userSeqs: delBuddyList })); } return action.group; }), tap(group => { this.groupProtocolService .del({ groupSeq: group.seq }) .pipe( map((res: GroupDelResponse) => { return delGroupSuccess(res); }), catchError(error => of(delGroupFailure({ error }))) ); }) ); }, { dispatch: false } ); addBuddy$ = createEffect(() => this.actions$.pipe( ofType(addBuddy), withLatestFrom( this.store.pipe( select((state: any) => state.messenger.sync.buddy2.syncDate as string) ) ), exhaustMap(([req, syncDate]) => this.buddyProtocolService.add(req).pipe( map((res: BuddyAddResponse) => { return buddy2({ syncDate }); }), catchError(error => of(addBuddyFailure({ error }))) ) ) ) ); delBuddy$ = createEffect(() => this.actions$.pipe( ofType(delBuddy), withLatestFrom( this.store.pipe( select((state: any) => state.messenger.sync.buddy2.syncDate as string) ) ), exhaustMap(([req, syncDate]) => this.buddyProtocolService.del(req).pipe( map((res: BuddyDelResponse) => { return delBuddySuccess(res); }), // map((res: BuddyDelResponse) => { // return buddy2({ // syncDate // }); // }), catchError(error => of(delBuddyFailure({ error }))) ) ) ) ); updateBuddy$ = createEffect(() => this.actions$.pipe( ofType(updateBuddy), exhaustMap(req => this.buddyProtocolService.update(req).pipe( map((res: BuddyUpdateResponse) => { return updateBuddySuccess(res); }), catchError(error => of(updateBuddyFailure({ error }))) ) ) ) ); updateGroup$ = createEffect(() => this.actions$.pipe( ofType(updateGroup), withLatestFrom( this.store.pipe( select((state: any) => state.messenger.sync.group2.syncDate as string) ) ), exhaustMap(([req, syncDate]) => this.groupProtocolService.update2(req).pipe( map((res: GroupUpdateResponse) => { return group2({ syncDate }); }), catchError(error => of(updateGroupFailure({ error }))) ) ) ) ); constructor( private actions$: Actions, private store: Store, private syncProtocolService: SyncProtocolService, private roomProtocolService: RoomProtocolService, private groupProtocolService: GroupProtocolService, private buddyProtocolService: BuddyProtocolService, private sessionStorageService: SessionStorageService, private logger: NGXLogger ) {} }