대화방 내 강퇴기능 구현

This commit is contained in:
leejinho 2019-12-10 12:38:20 +09:00
parent 7060e3a7af
commit d11e47a272
7 changed files with 204 additions and 33 deletions

View File

@ -5,6 +5,7 @@
[userInfo]="userInfo"
[presence]="getStatusBulkInfo(userInfo) | async"
[sessionVerinfo]="sessionVerinfo"
(contextmenu)="onContextMenuRoomUser($event, userInfo)"
(openProfile)="onClickOpenProfile($event)"
>
</ucap-profile-user-list-item>
@ -23,3 +24,22 @@
</button>
</div>
</div>
<div
style="visibility: hidden; position: fixed"
[style.left]="roomUserContextMenuPosition.x"
[style.top]="roomUserContextMenuPosition.y"
#roomUserContextMenuTrigger="matMenuTrigger"
[matMenuTriggerFor]="roomUserContextMenu"
></div>
<mat-menu
#roomUserContextMenu="matMenu"
[hasBackdrop]="false"
(ucapClickOutside)="roomUserContextMenuTrigger.closeMenu()"
>
<ng-template matMenuContent let-buddy="buddy">
<button mat-menu-item (click)="onClickContextMenu('FORCING_EXIT', buddy)">
대화방 퇴장
</button>
</ng-template>
</mat-menu>

View File

@ -3,7 +3,8 @@ import {
OnInit,
OnDestroy,
Output,
EventEmitter
EventEmitter,
ViewChild
} from '@angular/core';
import { Subscription } from 'rxjs';
import { Store, select } from '@ngrx/store';
@ -13,11 +14,16 @@ import * as AppStore from '@app/store';
import * as SyncStore from '@app/store/messenger/sync';
import * as RoomStore from '@app/store/messenger/room';
import { UserInfo } from '@ucap-webmessenger/protocol-room';
import { UserInfo, RoomInfo } from '@ucap-webmessenger/protocol-room';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { KEY_VER_INFO } from '@app/types/ver-info.type';
import { DialogService } from '@ucap-webmessenger/ui';
import {
DialogService,
ConfirmDialogComponent,
ConfirmDialogResult,
ConfirmDialogData
} from '@ucap-webmessenger/ui';
import {
SelectGroupDialogComponent,
SelectGroupDialogResult,
@ -32,6 +38,7 @@ import {
import { UserSelectDialogType } from '@app/types';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { KEY_LOGIN_RES_INFO } from '@app/types/login-res-info.type';
import { MatMenuTrigger, MatDialog } from '@angular/material';
@Component({
selector: 'app-layout-chat-right-drawer-room-user-list',
@ -42,6 +49,13 @@ export class RoomUserListComponent implements OnInit, OnDestroy {
@Output()
openProfile = new EventEmitter<UserInfo>();
@ViewChild('roomUserContextMenuTrigger', { static: true })
roomUserContextMenuTrigger: MatMenuTrigger;
roomUserContextMenuPosition = { x: '0px', y: '0px' };
roomInfo: RoomInfo;
roomInfoSubscription: Subscription;
userInfoList: UserInfo[];
userInfoListSubscription: Subscription;
@ -51,7 +65,8 @@ export class RoomUserListComponent implements OnInit, OnDestroy {
constructor(
private store: Store<any>,
private sessionStorageService: SessionStorageService,
private dialogService: DialogService
private dialogService: DialogService,
private dialogRef: MatDialog
) {
this.loginRes = this.sessionStorageService.get<LoginResponse>(
KEY_LOGIN_RES_INFO
@ -72,12 +87,35 @@ export class RoomUserListComponent implements OnInit, OnDestroy {
})
)
.subscribe();
this.roomInfoSubscription = this.store
.pipe(
select(AppStore.MessengerSelector.RoomSelector.roomInfo),
tap(roomInfo => {
this.roomInfo = roomInfo;
this.clearView();
})
)
.subscribe();
}
ngOnDestroy(): void {
if (!!this.userInfoListSubscription) {
this.userInfoListSubscription.unsubscribe();
}
if (!!this.roomInfoSubscription) {
this.roomInfoSubscription.unsubscribe();
}
}
clearView() {
if (
!!this.roomUserContextMenuTrigger &&
this.roomUserContextMenuTrigger.menuOpen
) {
this.roomUserContextMenuTrigger.closeMenu();
}
this.dialogRef.closeAll();
}
getStatusBulkInfo(buddy: UserInfo) {
@ -173,4 +211,51 @@ export class RoomUserListComponent implements OnInit, OnDestroy {
}
}
}
onContextMenuRoomUser(event: MouseEvent, buddy: UserInfo) {
event.preventDefault();
event.stopPropagation();
if (buddy.seq === this.loginRes.userSeq) {
return;
}
this.roomUserContextMenuPosition.x = event.clientX + 'px';
this.roomUserContextMenuPosition.y = event.clientY + 'px';
this.roomUserContextMenuTrigger.menu.focusFirstItem('mouse');
this.roomUserContextMenuTrigger.menuData = { buddy };
this.roomUserContextMenuTrigger.openMenu();
}
async onClickContextMenu(type: string, buddy: UserInfo) {
switch (type) {
case 'FORCING_EXIT':
{
const result = await this.dialogService.open<
ConfirmDialogComponent,
ConfirmDialogData,
ConfirmDialogResult
>(ConfirmDialogComponent, {
data: {
title: '강제 퇴장',
html: `${buddy.name} 님을 대화방에서 퇴장 시키겠습니까?`
}
});
if (!!result && !!result.choice && result.choice) {
this.store.dispatch(
RoomStore.exitForcing({
req: {
roomSeq: this.roomInfo.roomSeq,
senderSeq: this.loginRes.userSeq,
type: 'A',
userSeqs: [buddy.seq]
}
})
);
}
}
break;
}
}
}

View File

@ -40,7 +40,8 @@ import {
SSVC_TYPE_ROOM_UPD_RES,
SSVC_TYPE_ROOM_EXIT_FORCING_RES,
SSVC_TYPE_ROOM_EXIT_RES,
SSVC_TYPE_ROOM_INVITE_RES
SSVC_TYPE_ROOM_INVITE_RES,
ExitForcingResponse
} from '@ucap-webmessenger/protocol-room';
import {
StatusProtocolService,
@ -413,14 +414,14 @@ export class AppNotificationService {
case SSVC_TYPE_ROOM_EXIT_FORCING_RES:
{
// 내가 강퇴 진행.
const noti = notiOrRes as ExitForcingNotification;
const res = notiOrRes as ExitForcingResponse;
this.logger.debug(
'Notification::roomProtocolService::ExitForcingNotification',
noti
'Notification::roomProtocolService::ExitForcingNotification RES',
res
);
this.store.dispatch(
RoomStore.exitForcingNotificationRes({
noti
RoomStore.exitForcingSuccess({
res
})
);
}
@ -430,11 +431,11 @@ export class AppNotificationService {
// 내가 강퇴 됨.
const noti = notiOrRes as ExitForcingNotification;
this.logger.debug(
'Notification::roomProtocolService::ExitForcingNotification',
'Notification::roomProtocolService::ExitForcingNotification NOTI',
noti
);
this.store.dispatch(
RoomStore.exitForcingNotificationNoti({
RoomStore.exitForcingNotification({
noti
})
);

View File

@ -19,7 +19,9 @@ import {
InviteRequest,
InviteResponse,
UpdateTimerSetRequest,
UpdateTimerSetResponse
UpdateTimerSetResponse,
ExitForcingRequest,
ExitForcingResponse
} from '@ucap-webmessenger/protocol-room';
import { ReadNotification } from '@ucap-webmessenger/protocol-event';
@ -27,7 +29,6 @@ export const info = createAction(
'[Messenger::Room] Info',
props<InfoRequest>()
);
export const infoSuccess = createAction(
'[Messenger::Room] Info Success',
props<{
@ -36,7 +37,6 @@ export const infoSuccess = createAction(
userInfoList: UserInfo[];
}>()
);
export const infoFailure = createAction(
'[Messenger::Room] Info Failure',
props<{ error: any }>()
@ -52,17 +52,26 @@ export const exitNotification = createAction(
props<{ noti: ExitNotification }>()
);
export const exitForcingNotificationRes = createAction(
'[Messenger::Room] Exit Forcing Notification // Do Forcing',
props<{ noti: ExitForcingNotification }>()
export const exitForcing = createAction(
'[Messenger::Room] Exit Forcing',
props<{ req: ExitForcingRequest }>()
);
export const exitForcingNotificationNoti = createAction(
'[Messenger::Room] Exit Forcing Notification // Forcing Me',
export const exitForcingSuccess = createAction(
'[Messenger::Room] Exit Forcing Success',
props<{ res: ExitForcingResponse }>()
);
export const exitForcingFailure = createAction(
'[Messenger::Room] Exit Forcing Failure',
props<{ error: any }>()
);
export const exitForcingNotification = createAction(
'[Messenger::Room] Exit Forcing Notification // Forcing Me',
props<{ noti: ExitForcingNotification }>()
);
export const updateFontNotification = createAction(
'[Messenger::Room] Update Font Notification',
'[Messenger::Room] Update Font Notification',
props<{ noti: UpdateFontNotification }>()
);

View File

@ -33,7 +33,8 @@ import {
Open3Response,
RoomType,
InviteResponse,
UpdateTimerSetResponse
UpdateTimerSetResponse,
ExitForcingResponse
} from '@ucap-webmessenger/protocol-room';
import * as ChatStore from '@app/store/messenger/chat';
@ -63,7 +64,10 @@ import {
inviteFailure,
updateTimeRoomInterval,
updateTimeRoomIntervalSuccess,
updateTimeRoomIntervalFailure
updateTimeRoomIntervalFailure,
exitForcing,
exitForcingFailure,
exitForcingSuccess
} from './actions';
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { LoginInfo, KEY_LOGIN_INFO } from '@app/types';
@ -285,6 +289,21 @@ export class Effects {
)
);
exitForcing$ = createEffect(() =>
this.actions$.pipe(
ofType(exitForcing),
map(action => action.req),
exhaustMap(req => {
return this.roomProtocolService.exitForcing(req).pipe(
map((res: ExitForcingResponse) => {
return exitForcingSuccess({ res });
}),
catchError(error => of(exitForcingFailure({ error })))
);
})
)
);
inviteNotification$ = createEffect(
() => {
return this.actions$.pipe(

View File

@ -472,6 +472,7 @@ export class Effects {
{ dispatch: false }
);
// 대화상대 초대 성공 후 처리.
inviteSuccess$ = createEffect(() =>
this.actions$.pipe(
ofType(RoomStore.inviteSuccess),
@ -502,10 +503,45 @@ export class Effects {
)
);
exitForcingNotificationRes$ = createEffect(
// 대화상대 강제퇴장 수행 후 처리.
// exitForcingNotificationRes$ = createEffect(
// () => {
// return this.actions$.pipe(
// ofType(RoomStore.exitForcingNotificationRes),
// withLatestFrom(
// this.store.pipe(
// select((state: any) => state.messenger.room.roomInfo as RoomInfo)
// ),
// this.store.pipe(
// select((state: any) => state.messenger.sync.room.syncDate as string)
// )
// ),
// tap(([action, roomInfo, roomSyncDate]) => {
// if (!!roomInfo && roomInfo.roomSeq === action.noti.roomSeq) {
// this.store.dispatch(
// ChatStore.selectedRoom({ roomSeq: action.noti.roomSeq })
// );
// }
// const loginInfo = this.sessionStorageService.get<LoginInfo>(
// KEY_LOGIN_INFO
// );
// this.store.dispatch(
// room({
// syncDate: roomSyncDate,
// localeCode: loginInfo.localeCode
// })
// );
// })
// );
// },
// { dispatch: false }
// );
exitForcingSuccess$ = createEffect(
() => {
return this.actions$.pipe(
ofType(RoomStore.exitForcingNotificationRes),
ofType(RoomStore.exitForcingSuccess),
withLatestFrom(
this.store.pipe(
select((state: any) => state.messenger.room.roomInfo as RoomInfo)
@ -515,9 +551,9 @@ export class Effects {
)
),
tap(([action, roomInfo, roomSyncDate]) => {
if (!!roomInfo && roomInfo.roomSeq === action.noti.roomSeq) {
if (!!roomInfo && roomInfo.roomSeq === action.res.roomSeq) {
this.store.dispatch(
ChatStore.selectedRoom({ roomSeq: action.noti.roomSeq })
ChatStore.selectedRoom({ roomSeq: action.res.roomSeq })
);
}
@ -536,10 +572,11 @@ export class Effects {
},
{ dispatch: false }
);
exitForcingNotificationNoti$ = createEffect(
// 대화방에서 강제퇴장 받은 후 처리.
exitForcingNotification$ = createEffect(
() => {
return this.actions$.pipe(
ofType(RoomStore.exitForcingNotificationNoti),
ofType(RoomStore.exitForcingNotification),
withLatestFrom(
this.store.pipe(
select((state: any) => state.messenger.room.roomInfo as RoomInfo)

View File

@ -85,7 +85,7 @@ export interface ExitForcingRequest extends ProtocolRequest {
userSeqs: number[];
}
export interface ExitForcingResponse extends ProtocolRequest {
export interface ExitForcingResponse extends ProtocolResponse {
// 대화방SEQ(s)
roomSeq: string;
// 강퇴요청타입(s)
@ -135,9 +135,9 @@ export const decodeExitForcing: ProtocolDecoder<ExitForcingResponse> = (
userSeqs
} as ExitForcingResponse);
};
export const decodeExitForcingNotification: ProtocolDecoder<
ExitForcingNotification
> = (message: ProtocolMessage) => {
export const decodeExitForcingNotification: ProtocolDecoder<ExitForcingNotification> = (
message: ProtocolMessage
) => {
let userSeqs: number[] = [];
if (message.bodyList.length > 3) {
userSeqs = message.bodyList.slice(3);