import { of } from 'rxjs'; import { catchError, map, switchMap, exhaustMap, withLatestFrom, tap, debounceTime } from 'rxjs/operators'; import { Injectable } from '@angular/core'; import { Store, select } from '@ngrx/store'; import { Actions, ofType, createEffect } from '@ngrx/effects'; import { OpenResponse as CreateResponse, Open3Response as CreateTimerResponse, ExitResponse as DeleteResponse, ExitAllResponse as DeleteMultiResponse, UpdateResponse, InviteResponse, ExitForcingResponse, UpdateTimerSetResponse, InfoRequest } from '@ucap/protocol-room'; import { RoomProtocolService } from '@ucap/ng-protocol-room'; import { SyncProtocolService } from '@ucap/ng-protocol-sync'; import { LoginActions, LoginSelector } from '@ucap/ng-store-authentication'; import * as ChattingAction from '../Chatting/actions'; import { RoomSelector, ChattingSelector } from '../state'; import { rooms, room, roomFailure, inviteNotification, exitNotification, excludeUser, excludeUserSuccess, close, delSuccess, create, createSuccess, createFailure, createTimer, createTimerSuccess, createTimerFailure, del, delFailure, update, updateSuccess, updateFailure, open, openSuccess, closeSuccess, invite, inviteSuccess, inviteFailure, expel, expelSuccess, expelFailure, updateTimeRoomInterval, updateTimeRoomIntervalSuccess, updateTimeRoomIntervalFailure, rooms2Success, rooms2Failure, delMulti, delMultiSuccess, delMultiFailure, selectedRoom, room2Success, selectedRoomSuccess, clearSelectedRoom } from './actions'; import { LocaleCode } from '@ucap/core'; import { PresenceActions } from '@ucap/ng-store-organization'; import { I18nService } from '@ucap/ng-i18n'; @Injectable() export class Effects { sessionCreatedForRooms$ = createEffect(() => { return this.actions$.pipe( ofType(LoginActions.sessionCreated), map((action) => rooms({ localeCode: action.loginSession.localeCode })) ); }); selectedRoom$ = createEffect( () => { return this.actions$.pipe( ofType(selectedRoom), debounceTime(300), tap((action) => { const req: InfoRequest = { ...action, isDetail: false }; // retrieve room info this.roomProtocolService .info2(req) .pipe( map((res) => { let isJoinRoom = true; if (!res.roomInfo || !res.roomInfo.isJoinRoom) { isJoinRoom = false; } if (!!isJoinRoom) { this.store.dispatch( selectedRoomSuccess({ roomId: req.roomId, roomInfo2Res: res }) ); // Buddy Presence const targetUserInfos = req.isDetail ? res.roomUserInfo.userInfoList.map( (userInfo) => userInfo.seq + '' ) : res.roomUserInfo.userInfoShortList.map( (userInfo) => userInfo.seq + '' ); if (!!targetUserInfos && targetUserInfos.length > 0) { this.store.dispatch( PresenceActions.bulkInfo({ divCd: 'roomBulk', userSeqs: targetUserInfos }) ); } } else { // is not join room. so, redirect chat main. this.store.dispatch( clearSelectedRoom({ roomId: req.roomId }) ); } }), catchError((error) => of(roomFailure({ error }))) ) .subscribe(); // retrieve event info >> chatting.effect.selectedRoom$ }) ); }, { dispatch: false } ); selectedRoomSuccess$ = createEffect( () => { return this.actions$.pipe( ofType(selectedRoomSuccess), tap((action) => { // room info success reduce. this.store.dispatch( room2Success({ roomInfo: action.roomInfo2Res.roomInfo, roomUserInfo: action.roomInfo2Res.roomUserInfo }) ); }) ); }, { dispatch: false } ); rooms$ = createEffect(() => { return this.actions$.pipe( ofType(rooms), withLatestFrom(this.store.pipe(select(RoomSelector.roomsSyncDate))), switchMap(([action, syncDate]) => { // // CASE :: RoomUser Data 중 Detail data 만 수집. // return this.syncProtocolService // .room({ syncDate, localeCode: action.localeCode }) // .pipe( // map((res) => { // return roomsSuccess({ // roomList: res.roomList, // roomUserInfoMap: res.roomUserInfoMap, // syncDate: res.res.syncDate // }); // }), // catchError((error) => of(roomsFailure({ error }))) // ); // CASE :: RoomUser Data 중 Detail data, Short data 수집. return this.syncProtocolService .room2({ syncDate, localeCode: action.localeCode }) .pipe( map((res) => { return rooms2Success({ roomList: res.roomList, roomUserInfoMap: res.roomUserInfoMap, syncDate: res.res.syncDate }); }), catchError((error) => of(rooms2Failure({ error }))) ); }) ); }); room$ = createEffect(() => { return this.actions$.pipe( ofType(room), switchMap((action) => { const req = action.req; // // CASE :: RoomUser Data 중 Detail data 만 수집. // return this.roomProtocolService.info(req).pipe( // map((res) => // roomSuccess({ // roomInfo: res.roomInfo, // userInfoList: res.userInfoList // }) // ), // catchError((error) => of(roomFailure({ error }))) // ); // CASE :: RoomUser Data 중 Detail data, Short data 수집. return this.roomProtocolService.info2(req).pipe( map((res) => room2Success({ roomInfo: res.roomInfo, roomUserInfo: res.roomUserInfo }) ), catchError((error) => of(roomFailure({ error }))) ); }) ); }); create$ = createEffect( () => { return this.actions$.pipe( ofType(create), map((action) => action.req), exhaustMap((req) => { return this.roomProtocolService.open(req).pipe( map((res: CreateResponse) => { this.store.dispatch(createSuccess({ res })); // this.router.navigate( // [ // 'chat', // { // outlets: { content: 'chatroom' } // } // ], // { // queryParams: { roomId: res.roomId } // } // ); // if (!res.newRoom) { // } else { // } }), catchError((error) => of(createFailure({ error }))) ); }) ); }, { dispatch: false } ); createTimer$ = createEffect(() => this.actions$.pipe( ofType(createTimer), map((action) => action.req), exhaustMap((req) => { return this.roomProtocolService.open3(req).pipe( map((res: CreateTimerResponse) => { return createTimerSuccess({ res }); }), catchError((error) => of(createTimerFailure({ error }))) ); }) ) ); del$ = createEffect(() => this.actions$.pipe( ofType(del), map((action) => action.req), exhaustMap((req) => { return this.roomProtocolService.exit(req).pipe( switchMap((res: DeleteResponse) => [ // clear activeRoomId clearSelectedRoom({ roomId: res.roomId }), // close room, clear chatting close({ roomIds: [res.roomId] }), // clear room in rooms. delSuccess({ res }) ]), catchError((error) => of(delFailure({ error }))) ); }) ) ); delMulti$ = createEffect(() => this.actions$.pipe( ofType(delMulti), map((action) => action.req), withLatestFrom(this.store.pipe(select(ChattingSelector.activeRoomId))), exhaustMap(([req, activeRoomId]) => { const existActiveRoomId = req.roomIds.find( (roomId) => roomId === activeRoomId ); return this.roomProtocolService.exitAll(req).pipe( switchMap((res: DeleteMultiResponse) => { if (!!existActiveRoomId) { return [ // clear selected room clearSelectedRoom({ roomId: existActiveRoomId }), // close room, clear chatting close({ roomIds: res.roomIds }), // clear room in rooms. delMultiSuccess({ res }) ]; } else { return [ // close room, clear chatting close({ roomIds: res.roomIds }), // clear room in rooms. delMultiSuccess({ res }) ]; } }), catchError((error) => of(delMultiFailure({ error }))) ); }) ) ); update$ = createEffect(() => this.actions$.pipe( ofType(update), map((action) => action.req), exhaustMap((req) => { return this.roomProtocolService.update(req).pipe( map((res: UpdateResponse) => { return updateSuccess({ res }); }), catchError((error) => of(updateFailure({ error }))) ); }) ) ); excludeUser$ = createEffect(() => { return this.actions$.pipe( ofType(excludeUser), map((action) => excludeUserSuccess({ roomId: action.roomId, userSeqs: action.userSeqs }) ) ); }); open$ = createEffect(() => { return this.actions$.pipe( ofType(open), map((action) => openSuccess({ roomIds: [...action.roomIds] })) ); }); close$ = createEffect(() => { return this.actions$.pipe( ofType(close), map((action) => closeSuccess({ roomIds: [...action.roomIds] })) ); }); invite$ = createEffect(() => this.actions$.pipe( ofType(invite), exhaustMap((action) => { const req = action.req; const localeCode = action.localeCode; return this.roomProtocolService.invite(req).pipe( switchMap((res: InviteResponse) => { return [ inviteSuccess({ res }), room({ req: { roomId: req.roomId, isDetail: true, localeCode } }) ]; }), catchError((error) => of(inviteFailure({ error }))) ); }) ) ); expel$ = createEffect(() => this.actions$.pipe( ofType(expel), map((action) => action.req), exhaustMap((req) => { return this.roomProtocolService.exitForcing(req).pipe( map((res: ExitForcingResponse) => { return expelSuccess({ res }); }), catchError((error) => of(expelFailure({ error }))) ); }) ) ); updateTimeRoomInterval$ = createEffect(() => this.actions$.pipe( ofType(updateTimeRoomInterval), map((action) => action.req), exhaustMap((req) => { return this.roomProtocolService.updateTimerSet(req).pipe( map((res: UpdateTimerSetResponse) => { return updateTimeRoomIntervalSuccess({ res }); }), catchError((error) => of(updateTimeRoomIntervalFailure({ error }))) ); }) ) ); /** * @discription Call by notifications case in SSVC_TYPE_ROOM_INVITE_RES, SSVC_TYPE_ROOM_INVITE_NOTI * 1. roomlist 를 체크하여 없을경우 내가 초대된 경우라 간주하고 방 조회하여 갱신하지 않도록 한다.(첫 대화가 들어오면 그때 조회.) * 2. roomlist 를 체크하여 있을 경우 기존방에 다른 인원이 추가되었을 경우이므로 방 조회하여 갱신한다. */ inviteNotification$ = createEffect( () => { return this.actions$.pipe( ofType(inviteNotification), withLatestFrom(this.store.pipe(select(RoomSelector.rooms))), map(([action, roomList]) => { const roomId = action.noti.roomId; if (!!roomList && roomList.length > 0) { if (roomList.some((roomInfo) => roomId === roomInfo.roomId)) { this.store.dispatch( room({ req: { roomId, isDetail: true, localeCode: action.localeCode } }) ); } } }) ); }, { dispatch: false } ); exitNotification$ = createEffect(() => { return this.actions$.pipe( ofType(exitNotification), withLatestFrom(this.store.pipe(select(LoginSelector.loginRes))), switchMap(([action, loginRes]) => { if (loginRes.userSeq + '' === action.senderSeq + '') { return [ close({ roomIds: [action.roomId] }), clearSelectedRoom({ roomId: action.roomId }), delSuccess({ res: { roomId: action.roomId } }) ]; } else { return [ excludeUser({ roomId: action.roomId, userSeqs: [action.senderSeq] }) ]; } }) ); }); /******************************************************************* * [Chatting Action watching.] *******************************************************************/ addEventSuccess$ = createEffect( () => { return this.actions$.pipe( ofType(ChattingAction.addEventSuccess), withLatestFrom(this.store.pipe(select(RoomSelector.rooms))), map(([action, roomList]) => { const roomId = action.roomId; if (!roomList.find((roomInfo) => roomInfo.roomId === roomId)) { this.store.dispatch( rooms({ localeCode: this.i18nService.currentLng.toUpperCase() as LocaleCode }) ); } }) ); }, { dispatch: false } ); constructor( private actions$: Actions, private store: Store, private syncProtocolService: SyncProtocolService, private roomProtocolService: RoomProtocolService, private i18nService: I18nService ) {} }