unread count 관련 처리.
This commit is contained in:
parent
d099bcb035
commit
33e6566eff
|
@ -137,7 +137,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewChecked {
|
|||
|
||||
this.userInfoListSubscription = this.store
|
||||
.pipe(
|
||||
select(AppStore.MessengerSelector.RoomSelector.userInfoList),
|
||||
select(AppStore.MessengerSelector.RoomSelector.selectUserinfolist),
|
||||
tap(userInfoList => {
|
||||
this.userInfoList = userInfoList;
|
||||
})
|
||||
|
|
|
@ -154,11 +154,7 @@ export class AppNotificationService {
|
|||
'Notification::eventProtocolService::ReadNotification',
|
||||
noti
|
||||
);
|
||||
this.store.dispatch(
|
||||
EventStore.readNotification({
|
||||
noti
|
||||
})
|
||||
);
|
||||
this.store.dispatch(EventStore.readNotification(noti));
|
||||
}
|
||||
break;
|
||||
case SSVC_TYPE_EVENT_CANCEL_NOTI:
|
||||
|
|
|
@ -133,7 +133,7 @@ export const readFailure = createAction(
|
|||
|
||||
export const readNotification = createAction(
|
||||
'[Messenger::Event] Read Notification',
|
||||
props<{ noti: ReadNotification }>()
|
||||
props<ReadNotification>()
|
||||
);
|
||||
|
||||
/** 대화 회수 */
|
||||
|
|
|
@ -32,10 +32,14 @@ import {
|
|||
ReadResponse,
|
||||
DelResponse,
|
||||
CancelResponse,
|
||||
EventType
|
||||
EventType,
|
||||
ReadNotification,
|
||||
SSVC_TYPE_EVENT_SEND_RES,
|
||||
SSVC_TYPE_EVENT_SEND_NOTI
|
||||
} from '@ucap-webmessenger/protocol-event';
|
||||
|
||||
import * as ChatStore from '@app/store/messenger/chat';
|
||||
import * as RoomStore from '@app/store/messenger/room';
|
||||
import * as SyncStore from '@app/store/messenger/sync';
|
||||
|
||||
import {
|
||||
|
@ -149,7 +153,7 @@ export class Effects {
|
|||
exhaustMap(req =>
|
||||
this.eventProtocolService.read(req).pipe(
|
||||
map((res: ReadResponse) => {
|
||||
return readNotification({ noti: res });
|
||||
return readNotification(res as ReadNotification);
|
||||
}),
|
||||
catchError(error => of(readFailure({ error })))
|
||||
)
|
||||
|
@ -161,14 +165,33 @@ export class Effects {
|
|||
() => {
|
||||
return this.actions$.pipe(
|
||||
ofType(readNotification),
|
||||
map(action => action.noti),
|
||||
tap(noti => {
|
||||
withLatestFrom(
|
||||
this.store.pipe(
|
||||
select((state: any) => state.messenger.room.roomInfo as RoomInfo)
|
||||
),
|
||||
this.store.pipe(
|
||||
select(
|
||||
(state: any) =>
|
||||
state.account.authentication.loginRes as LoginResponse
|
||||
)
|
||||
)
|
||||
),
|
||||
// map(([action, roomInfo]) => ([action.noti, roomInfo])),
|
||||
tap(([action, roomInfo, loginRes]) => {
|
||||
// 현재 오픈된 방에 대한 read noti/res 가 유입될 경우 roomUserList 의 lastReadSeq 를 갱신한다.
|
||||
if (roomInfo.roomSeq === action.roomSeq) {
|
||||
this.store.dispatch(RoomStore.updateRoomUserLastReadSeq(action));
|
||||
}
|
||||
|
||||
// noti/res 를 일으킨 주체가 본인이라면 현재 오픈된 방 여부에 상관없이 해당방에 대한 noReadCnt 를 초기화 한다.
|
||||
if (action.SENDER_SEQ === loginRes.userSeq) {
|
||||
this.store.dispatch(
|
||||
SyncStore.updateUnreadCount({
|
||||
roomSeq: noti.roomSeq,
|
||||
roomSeq: action.roomSeq,
|
||||
noReadCnt: 0
|
||||
})
|
||||
);
|
||||
}
|
||||
})
|
||||
);
|
||||
},
|
||||
|
@ -376,12 +399,24 @@ export class Effects {
|
|||
// opened room :: event add
|
||||
if (!!roomInfo && roomInfo.roomSeq === action.roomSeq) {
|
||||
this.store.dispatch(appendInfoList({ info: action.info }));
|
||||
|
||||
if (
|
||||
action.SVC_TYPE === SVC_TYPE_EVENT &&
|
||||
action.SSVC_TYPE === SSVC_TYPE_EVENT_SEND_NOTI
|
||||
) {
|
||||
this.store.dispatch(
|
||||
read({
|
||||
roomSeq: action.roomSeq,
|
||||
lastReadSeq: action.info.seq
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// not opened room :: unread count increased
|
||||
if (
|
||||
action.SVC_TYPE === SVC_TYPE_EVENT &&
|
||||
action.SSVC_TYPE === SSVC_TYPE_EVENT_INFO_RES
|
||||
action.SSVC_TYPE === SSVC_TYPE_EVENT_SEND_RES
|
||||
) {
|
||||
/**
|
||||
* 다른 디바이스에서 대화를 송신 할경우 RES 가 noti 로 유입될 수 있다.
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
ExitRequest,
|
||||
ExitResponse
|
||||
} from '@ucap-webmessenger/protocol-room';
|
||||
import { ReadNotification } from '@ucap-webmessenger/protocol-event';
|
||||
|
||||
export const info = createAction(
|
||||
'[Messenger::Room] Info',
|
||||
|
@ -60,6 +61,11 @@ export const updateOnlyAlarm = createAction(
|
|||
props<{ roomInfo: RoomInfo }>()
|
||||
);
|
||||
|
||||
export const updateRoomUserLastReadSeq = createAction(
|
||||
'[Messenger::Room] Update Room User Only LastReadSeq',
|
||||
props<ReadNotification>()
|
||||
);
|
||||
|
||||
export const update = createAction(
|
||||
'[Messenger::Room] Update',
|
||||
props<{ req: UpdateRequest }>()
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import { createReducer, on } from '@ngrx/store';
|
||||
import { initialState } from './state';
|
||||
import { infoSuccess, updateSuccess } from './actions';
|
||||
import { initialState, adapterUserInfo, adapterUserInfoShort } from './state';
|
||||
import {
|
||||
infoSuccess,
|
||||
updateSuccess,
|
||||
updateRoomUserLastReadSeq
|
||||
} from './actions';
|
||||
|
||||
import * as AuthenticationStore from '@app/store/account/authentication';
|
||||
import { UserInfo } from '@ucap-webmessenger/protocol-room';
|
||||
|
||||
export const reducer = createReducer(
|
||||
initialState,
|
||||
|
@ -10,8 +15,12 @@ export const reducer = createReducer(
|
|||
return {
|
||||
...state,
|
||||
roomInfo: action.roomInfo,
|
||||
userInfoList: action.userInfoList,
|
||||
userInfoShortList: action.userInfoShortList
|
||||
userInfoList: adapterUserInfo.addAll(action.userInfoList, {
|
||||
...state.userInfoList
|
||||
}),
|
||||
userInfoShortList: adapterUserInfoShort.addAll(action.userInfoShortList, {
|
||||
...state.userInfoShortList
|
||||
})
|
||||
};
|
||||
}),
|
||||
|
||||
|
@ -26,6 +35,23 @@ export const reducer = createReducer(
|
|||
};
|
||||
}),
|
||||
|
||||
on(updateRoomUserLastReadSeq, (state, action) => {
|
||||
const userSeq = action.SENDER_SEQ;
|
||||
|
||||
const userInfo: UserInfo = {
|
||||
...state.userInfoList.entities[userSeq],
|
||||
lastReadEventSeq: action.lastReadSeq
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
userInfoList: adapterUserInfo.updateOne(
|
||||
{ id: userSeq, changes: userInfo },
|
||||
{ ...state.userInfoList }
|
||||
)
|
||||
};
|
||||
}),
|
||||
|
||||
on(AuthenticationStore.logout, (state, action) => {
|
||||
return {
|
||||
...initialState
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { EntityState, createEntityAdapter } from '@ngrx/entity';
|
||||
import { Selector, createSelector } from '@ngrx/store';
|
||||
import {
|
||||
InfoRequest,
|
||||
|
@ -6,31 +7,71 @@ import {
|
|||
UserInfo
|
||||
} from '@ucap-webmessenger/protocol-room';
|
||||
|
||||
export interface UserInfoShortListState extends EntityState<UserInfoShort> {}
|
||||
export interface UserInfoListState extends EntityState<UserInfo> {}
|
||||
|
||||
export interface State {
|
||||
roomInfo: RoomInfo | null;
|
||||
userInfoShortList: UserInfoShort[] | null;
|
||||
userInfoList: UserInfo[] | null;
|
||||
userInfoShortList: UserInfoShortListState;
|
||||
userInfoList: UserInfoListState;
|
||||
}
|
||||
|
||||
export const adapterUserInfoShort = createEntityAdapter<UserInfoShort>({
|
||||
selectId: userInfo => userInfo.seq
|
||||
});
|
||||
export const adapterUserInfo = createEntityAdapter<UserInfo>({
|
||||
selectId: userInfo => userInfo.seq
|
||||
});
|
||||
|
||||
const userInfoShortListInitialState: UserInfoShortListState = adapterUserInfoShort.getInitialState(
|
||||
{}
|
||||
);
|
||||
const userInfoListInitialState: UserInfoListState = adapterUserInfo.getInitialState(
|
||||
{}
|
||||
);
|
||||
|
||||
export const initialState: State = {
|
||||
roomInfo: null,
|
||||
userInfoShortList: null,
|
||||
userInfoList: null
|
||||
userInfoShortList: userInfoShortListInitialState,
|
||||
userInfoList: userInfoListInitialState
|
||||
};
|
||||
|
||||
const {
|
||||
selectAll: ngeSelectAllUserInfoShort,
|
||||
selectEntities: ngeSelectEntitiesUserInfoShort,
|
||||
selectIds: ngeSelectIdsUserInfoShort,
|
||||
selectTotal: ngeSelectTotalUserInfoShort
|
||||
} = adapterUserInfoShort.getSelectors();
|
||||
const {
|
||||
selectAll: ngeSelectAllUserInfo,
|
||||
selectEntities: ngeSelectEntitiesUserInfo,
|
||||
selectIds: ngeSelectIdsUserInfo,
|
||||
selectTotal: ngeSelectTotalUserInfo
|
||||
} = adapterUserInfo.getSelectors();
|
||||
|
||||
export function selectors<S>(selector: Selector<any, State>) {
|
||||
const selectUserInfoShortList = createSelector(
|
||||
selector,
|
||||
(state: State) => state.userInfoShortList
|
||||
);
|
||||
|
||||
const selectUserInfoList = createSelector(
|
||||
selector,
|
||||
(state: State) => state.userInfoList
|
||||
);
|
||||
|
||||
return {
|
||||
roomInfo: createSelector(
|
||||
selector,
|
||||
(state: State) => state.roomInfo
|
||||
),
|
||||
userInfoShortList: createSelector(
|
||||
selector,
|
||||
(state: State) => state.userInfoShortList
|
||||
selectUserInfoShortList: createSelector(
|
||||
selectUserInfoShortList,
|
||||
ngeSelectAllUserInfoShort
|
||||
),
|
||||
userInfoList: createSelector(
|
||||
selector,
|
||||
(state: State) => state.userInfoList
|
||||
selectUserinfolist: createSelector(
|
||||
selectUserInfoList,
|
||||
ngeSelectAllUserInfo
|
||||
)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import {
|
|||
} from '@ucap-webmessenger/protocol-sync';
|
||||
import {
|
||||
RoomInfo,
|
||||
UserInfoShort,
|
||||
UserInfo as RoomUserInfo
|
||||
} from '@ucap-webmessenger/protocol-room';
|
||||
|
||||
|
|
|
@ -146,7 +146,12 @@
|
|||
</div>
|
||||
|
||||
<div class="time secondary-text">
|
||||
<ul>
|
||||
<li>{{ getUnreadCount(message) }}</li>
|
||||
<li>
|
||||
{{ message.sendDate | date: 'a hh:mm' }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
|
|
@ -223,6 +223,11 @@ $meBox-bg: #ffffff;
|
|||
word-wrap: break-word;
|
||||
white-space: nowrap;
|
||||
}
|
||||
&.me {
|
||||
.secondary-text {
|
||||
text-align: end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.message-row.me > .bubble {
|
||||
|
|
|
@ -12,10 +12,8 @@ import {
|
|||
EventType,
|
||||
InfoResponse
|
||||
} from '@ucap-webmessenger/protocol-event';
|
||||
import {
|
||||
LoginResponse,
|
||||
UserInfo
|
||||
} from '@ucap-webmessenger/protocol-authentication';
|
||||
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
||||
import { UserInfo } from '@ucap-webmessenger/protocol-room';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
|
||||
import { FileInfo } from '../models/file-info.json';
|
||||
|
@ -61,6 +59,9 @@ export class MessagesComponent implements OnInit {
|
|||
this.profileImageRoot || this.sessionVerInfo.profileRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* UserInfo getter
|
||||
*/
|
||||
getUserName(seq: number): string {
|
||||
if (!this.userInfos) {
|
||||
return '';
|
||||
|
@ -88,6 +89,17 @@ export class MessagesComponent implements OnInit {
|
|||
return '';
|
||||
}
|
||||
|
||||
getUnreadCount(message: Info): string | number {
|
||||
const unreadCnt = this.userInfos.filter(user => {
|
||||
if (message.senderSeq === user.seq) {
|
||||
// 본인 글은 unreadCount 에 포함하지 않는다.
|
||||
return false;
|
||||
}
|
||||
return user.lastReadEventSeq < message.seq;
|
||||
}).length;
|
||||
return unreadCnt === 0 ? '' : unreadCnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 정보성 Event 인지 판단.
|
||||
* @description 정보성 event 일 경우 프로필, 일시 를 표현하지 않는다.
|
||||
|
@ -106,7 +118,7 @@ export class MessagesComponent implements OnInit {
|
|||
return false;
|
||||
}
|
||||
|
||||
/** Date Splitter check */
|
||||
/** Date Splitter show check */
|
||||
getDateSplitter(curIndex: number): boolean {
|
||||
if (curIndex === 0) {
|
||||
return true;
|
||||
|
@ -141,6 +153,7 @@ export class MessagesComponent implements OnInit {
|
|||
this.save.emit(value);
|
||||
}
|
||||
|
||||
/** [Event] Context Menu */
|
||||
onContextMenuMessage(event: MouseEvent, message: Info) {
|
||||
this.contextMenu.emit({ event, message });
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user