diff --git a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/chat.component.html b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/chat.component.html index 2e6712f0..187f8359 100644 --- a/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/chat.component.html +++ b/projects/ucap-webmessenger-app/src/app/layouts/messenger/components/left-sidenav/chat.component.html @@ -1,3 +1,7 @@ - + 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 08bf7caa..1b1ce638 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 @@ -2,7 +2,7 @@ import { Component, OnInit, OnDestroy } from '@angular/core'; import { ucapAnimations } from '@ucap-webmessenger/ui'; import { NGXLogger } from 'ngx-logger'; import { Store, select } from '@ngrx/store'; -import { Subscription } from 'rxjs'; +import { Subscription, combineLatest } from 'rxjs'; import { RoomInfo, UserInfoShort, @@ -10,7 +10,11 @@ import { } from '@ucap-webmessenger/protocol-room'; import * as AppStore from '@app/store'; import * as ChatStore from '@app/store/messenger/chat'; -import { tap } from 'rxjs/operators'; +import { tap, map } from 'rxjs/operators'; +import { + RoomUserDetailData, + RoomUserData +} from '@ucap-webmessenger/protocol-sync'; @Component({ selector: 'app-layout-chat-left-sidenav-chat', @@ -20,24 +24,30 @@ import { tap } from 'rxjs/operators'; }) export class ChatComponent implements OnInit, OnDestroy { roomList: RoomInfo[]; - roomUserInfoMap: { - [param: string]: { - userInfoShortList: UserInfoShort[]; - userInfoList: RoomUserInfo[]; - }; - }; + roomUserList: RoomUserDetailData[]; + roomUserShortList: RoomUserData[]; roomSubscription: Subscription; constructor(private store: Store, private logger: NGXLogger) {} ngOnInit() { - this.roomSubscription = this.store + this.roomSubscription = combineLatest([ + this.store.pipe( + select(AppStore.MessengerSelector.SyncSelector.selectAllRoom) + ), + this.store.pipe( + select(AppStore.MessengerSelector.SyncSelector.selectAllRoomUser) + ), + this.store.pipe( + select(AppStore.MessengerSelector.SyncSelector.selectAllRoomUserShort) + ) + ]) .pipe( - select(AppStore.MessengerSelector.SyncSelector.room), - tap(room => { - this.roomList = room.roomList; - this.roomUserInfoMap = room.roomUserInfoMap; + tap(([room, roomUser, roomUserShort]) => { + this.roomList = room; + this.roomUserList = roomUser; + this.roomUserShortList = roomUserShort; }) ) .subscribe(); @@ -54,17 +64,22 @@ export class ChatComponent implements OnInit, OnDestroy { } getRoomUserList(roomInfo: RoomInfo): RoomUserInfo[] | UserInfoShort[] { - if ( - !!this.roomUserInfoMap[roomInfo.roomSeq].userInfoList && - 0 < this.roomUserInfoMap[roomInfo.roomSeq].userInfoList.length - ) { - return this.roomUserInfoMap[roomInfo.roomSeq].userInfoList; + if (!!this.roomUserList && 0 < this.roomUserList.length) { + const i = this.roomUserList.findIndex( + value => roomInfo.roomSeq === value.roomSeq + ); + if (-1 < i) { + return this.roomUserList[i].userInfos; + } } - if ( - !!this.roomUserInfoMap[roomInfo.roomSeq].userInfoShortList && - 0 < this.roomUserInfoMap[roomInfo.roomSeq].userInfoShortList.length - ) { - return this.roomUserInfoMap[roomInfo.roomSeq].userInfoShortList; + + if (!!this.roomUserShortList && 0 < this.roomUserShortList.length) { + const i = this.roomUserShortList.findIndex( + value => roomInfo.roomSeq === value.roomSeq + ); + if (-1 < i) { + return this.roomUserShortList[i].userInfos; + } } } } 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 7df6d991..a156a920 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 @@ -67,49 +67,31 @@ export class GroupComponent implements OnInit { select(AppStore.SettingSelector.CompanySelector.companyList) ); - this.groupBuddyList$ = this.store - .pipe( - select(AppStore.MessengerSelector.SyncSelector.groupListAndBuddyList) + this.groupBuddyList$ = combineLatest([ + this.store.pipe( + select(AppStore.MessengerSelector.SyncSelector.selectAllBuddy2) + ), + this.store.pipe( + select(AppStore.MessengerSelector.SyncSelector.selectAllGroup2) ) - .pipe( - map(groupListAndBuddyList => { - const groupList = groupListAndBuddyList.groupList - .slice() - .sort((a, b) => { - // 기본그룹은 제일 하단 - if (0 === a.seq) { - return 1; - } else if (0 === b.seq) { - return -1; - } else { - if (a.name > b.name) { - return 1; - } - if (b.name > a.name) { - return -1; - } - return 0; - } - }); - - const groupBuddyList: { - group: GroupDetailData; - buddyList: UserInfo[]; - }[] = []; - for (const group of groupList) { - const buddyList = groupListAndBuddyList.buddyList.filter(buddy => { + ]).pipe( + map(([buddyList, groupList]) => { + const groupBuddyList: { + group: GroupDetailData; + buddyList: UserInfo[]; + }[] = []; + for (const group of groupList) { + groupBuddyList.push({ + group, + buddyList: buddyList.filter(buddy => { return group.userSeqs.indexOf(buddy.seq) > -1; - }); + }) + }); + } - groupBuddyList.push({ - group, - buddyList - }); - } - - return groupBuddyList; - }) - ); + return groupBuddyList; + }) + ); } async onClickGroupMenu(menuType: string) { diff --git a/projects/ucap-webmessenger-app/src/app/resolvers/messenger.resolver.ts b/projects/ucap-webmessenger-app/src/app/resolvers/messenger.resolver.ts index d20fadb4..a60e36f2 100644 --- a/projects/ucap-webmessenger-app/src/app/resolvers/messenger.resolver.ts +++ b/projects/ucap-webmessenger-app/src/app/resolvers/messenger.resolver.ts @@ -135,13 +135,17 @@ export class AppMessengerResolver implements Resolve { }), withLatestFrom( this.store.pipe( - select(AppStore.MessengerSelector.SyncSelector.buddy2SyncDate) + select( + AppStore.MessengerSelector.SyncSelector.selectBuddy2SyncDate + ) ), this.store.pipe( - select(AppStore.MessengerSelector.SyncSelector.group2SyncDate) + select( + AppStore.MessengerSelector.SyncSelector.selectGroup2SyncDate + ) ), this.store.pipe( - select(AppStore.MessengerSelector.SyncSelector.roomSyncDate) + select(AppStore.MessengerSelector.SyncSelector.selectRoomSyncDate) ) ), map(([_, buddy2SyncDate, group2SyncDate, roomSyncDate]) => { 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 9ff0bda7..3d8565d2 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 @@ -208,15 +208,15 @@ export class Effects { ofType(ChatStore.newEventMessage), withLatestFrom( this.store.pipe( - select((state: any) => state.messenger.sync.roomList as RoomInfo[]) + select((state: any) => state.messenger.sync.room.ids as string[]) ), this.store.pipe( - select((state: any) => state.messenger.sync.roomSyncDate as string) + select((state: any) => state.messenger.sync.room.syncDate as string) ) ), - tap(([action, roomList, roomSyncDate]) => { - const index = roomList.findIndex( - (roomInfo, i) => roomInfo.roomSeq === action.roomSeq + tap(([action, roomSeqList, roomSyncDate]) => { + const index = roomSeqList.findIndex( + (roomSeq, i) => roomSeq === action.roomSeq ); if (-1 === index) { 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 88b8fbcc..32ac7b2a 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 @@ -1,62 +1,95 @@ import { createReducer, on } from '@ngrx/store'; -import { initialState } from './state'; +import { + initialState, + adapterBuddy2, + adapterGroup2, + adapterRoom, + adapterRoomUser, + adapterRoomUserShort +} from './state'; import { buddy2Success, group2Success, roomSuccess, updateRoomForNewEventMessage } from './actions'; - -import { RoomInfo } from '@ucap-webmessenger/protocol-room'; +import { + RoomUserDetailData, + RoomUserData +} from '@ucap-webmessenger/protocol-sync'; export const reducer = createReducer( initialState, on(buddy2Success, (state, action) => { return { ...state, - buddyInfoList: [...state.buddyInfoList, ...action.buddyList], - buddy2SyncDate: action.syncDate + buddy2: adapterBuddy2.addAll(action.buddyList, { + ...state.buddy2, + syncDate: action.syncDate + }) }; }), on(group2Success, (state, action) => { return { ...state, - groupList: [...state.groupList, ...action.groupList], - group2SyncDate: action.syncDate + group2: adapterGroup2.addAll(action.groupList, { + ...state.group2, + syncDate: action.syncDate + }) }; }), on(roomSuccess, (state, action) => { + const roomUserList: RoomUserDetailData[] = []; + const roomUserShortList: RoomUserData[] = []; + + for (const key in action.roomUserInfoMap) { + if (action.roomUserInfoMap.hasOwnProperty(key)) { + const element = action.roomUserInfoMap[key]; + if (!!element.userInfoList && 0 < element.userInfoList.length) { + roomUserList.push({ roomSeq: key, userInfos: element.userInfoList }); + } + if ( + !!element.userInfoShortList && + 0 < element.userInfoShortList.length + ) { + roomUserShortList.push({ + roomSeq: key, + userInfos: element.userInfoShortList + }); + } + } + } + return { ...state, - roomList: [...state.roomList, ...action.roomList], - roomUserInfoMap: { - ...state.roomUserInfoMap, - ...action.roomUserInfoMap - }, - roomSyncDate: action.syncDate + room: adapterRoom.addAll(action.roomList, { + ...state.room, + syncDate: action.syncDate + }), + roomUser: adapterRoomUser.addAll(roomUserList, { + ...state.roomUser + }), + roomUserShort: adapterRoomUserShort.addAll(roomUserShortList, { + ...state.roomUserShort + }) }; }), on(updateRoomForNewEventMessage, (state, action) => { - const roomList: RoomInfo[] = []; - - state.roomList.forEach((roomInfo, index) => { - if (roomInfo.roomSeq === action.roomSeq) { - roomList.push({ - ...roomInfo, - finalEventDate: action.info.sendDate, - finalEventMessage: action.info.sentMessage - }); - } else { - roomList.push(roomInfo); - } - }); + const roomInfo = { + ...state.room.entities[action.roomSeq], + finalEventDate: action.info.sendDate, + finalEventMessage: action.info.sentMessage + }; return { ...state, - roomList + room: adapterRoom.updateOne( + { id: action.roomSeq, changes: roomInfo }, + { ...state.room } + ) }; }) ); diff --git a/projects/ucap-webmessenger-app/src/app/store/messenger/sync/state.ts b/projects/ucap-webmessenger-app/src/app/store/messenger/sync/state.ts index 7f951390..015705cb 100644 --- a/projects/ucap-webmessenger-app/src/app/store/messenger/sync/state.ts +++ b/projects/ucap-webmessenger-app/src/app/store/messenger/sync/state.ts @@ -1,77 +1,194 @@ import { Selector, createSelector } from '@ngrx/store'; -import { UserInfo, GroupDetailData } from '@ucap-webmessenger/protocol-sync'; +import { EntityState, createEntityAdapter } from '@ngrx/entity'; +import { + UserInfo, + GroupDetailData, + RoomUserData, + RoomUserDetailData +} from '@ucap-webmessenger/protocol-sync'; import { RoomInfo, UserInfoShort, UserInfo as RoomUserInfo } from '@ucap-webmessenger/protocol-room'; -export interface State { - buddyInfoList: UserInfo[]; - buddy2SyncDate: string; - - groupList: GroupDetailData[]; - group2SyncDate: string; - - roomList: RoomInfo[]; - roomUserInfoMap: { - [param: string]: { - userInfoShortList: UserInfoShort[]; - userInfoList: RoomUserInfo[]; - }; - }; - roomSyncDate: string; +export interface Buddy2State extends EntityState { + syncDate: string; } +export interface Group2State extends EntityState { + syncDate: string; +} + +export interface RoomState extends EntityState { + syncDate: string; +} + +export interface RoomUserState extends EntityState {} + +export interface RoomUserShortState extends EntityState {} + +export interface State { + buddy2: Buddy2State; + group2: Group2State; + room: RoomState; + roomUser: RoomUserState; + roomUserShort: RoomUserShortState; +} + +export const adapterBuddy2 = createEntityAdapter({ + selectId: userInfo => userInfo.seq +}); +export const adapterGroup2 = createEntityAdapter({ + selectId: groupDetailData => groupDetailData.seq, + sortComparer: (a, b) => { + // 기본그룹은 제일 하단 + if (0 === a.seq) { + return 1; + } else if (0 === b.seq) { + return -1; + } else { + if (a.name > b.name) { + return 1; + } + if (b.name > a.name) { + return -1; + } + return 0; + } + } +}); +export const adapterRoom = createEntityAdapter({ + selectId: roomInfo => roomInfo.roomSeq, + sortComparer: (a, b) => { + return ( + new Date(b.finalEventDate).getTime() - + new Date(a.finalEventDate).getTime() + ); + } +}); +export const adapterRoomUser = createEntityAdapter({ + selectId: roomUserDetailData => roomUserDetailData.roomSeq +}); +export const adapterRoomUserShort = createEntityAdapter({ + selectId: roomUserData => roomUserData.roomSeq +}); + +const buddy2InitialState: Buddy2State = adapterBuddy2.getInitialState({ + syncDate: '' +}); +const group2InitialState: Group2State = adapterGroup2.getInitialState({ + syncDate: '' +}); +const roomInitialState: RoomState = adapterRoom.getInitialState({ + syncDate: '' +}); +const roomUserInitialState: RoomUserState = adapterRoomUser.getInitialState({}); +const roomUserShortInitialState: RoomUserShortState = adapterRoomUserShort.getInitialState( + {} +); + export const initialState: State = { - buddyInfoList: [], - buddy2SyncDate: '', - groupList: [], - group2SyncDate: '', - roomList: [], - roomUserInfoMap: {}, - roomSyncDate: '' + buddy2: buddy2InitialState, + group2: group2InitialState, + room: roomInitialState, + roomUser: roomUserInitialState, + roomUserShort: roomUserShortInitialState }; +const { + selectAll: ngeSelectAllBuddy2, + selectEntities: ngeSelectEntitiesBuddy2, + selectIds: ngeSelectIdsBuddy2, + selectTotal: ngeSelectTotalBuddy2 +} = adapterBuddy2.getSelectors(); + +const { + selectAll: ngeSelectAllGroup2, + selectEntities: ngeSelectEntitiesGroup2, + selectIds: ngeSelectIdsGroup2, + selectTotal: ngeSelectTotalGroup2 +} = adapterGroup2.getSelectors(); + +const { + selectAll: ngeSelectAllRoom, + selectEntities: ngeSelectEntitiesRoom, + selectIds: ngeSelectIdsRoom, + selectTotal: ngeSelectTotalRoom +} = adapterRoom.getSelectors(); + +const { + selectAll: ngeSelectAllRoomUser, + selectEntities: ngeSelectEntitiesRoomUser, + selectIds: ngeSelectIdsRoomUser, + selectTotal: ngeSelectTotalRoomUser +} = adapterRoomUser.getSelectors(); + +const { + selectAll: ngeSelectAllRoomUserShort, + selectEntities: ngeSelectEntitiesRoomUserShort, + selectIds: ngeSelectIdsRoomUserShort, + selectTotal: ngeSelectTotalRoomUserShort +} = adapterRoomUserShort.getSelectors(); + export function selectors(selector: Selector) { + const selectBuddy2 = createSelector( + selector, + (state: State) => state.buddy2 + ); + + const selectGroup2 = createSelector( + selector, + (state: State) => state.group2 + ); + + const selectRoom = createSelector( + selector, + (state: State) => state.room + ); + + const selectRoomUser = createSelector( + selector, + (state: State) => state.roomUser + ); + + const selectRoomUserShort = createSelector( + selector, + (state: State) => state.roomUserShort + ); + return { - buddyInfoList: createSelector( - selector, - (state: State) => state.buddyInfoList + selectAllBuddy2: createSelector( + selectBuddy2, + ngeSelectAllBuddy2 ), - buddy2SyncDate: createSelector( - selector, - (state: State) => state.buddy2SyncDate + selectBuddy2SyncDate: createSelector( + selectBuddy2, + buddy2State => buddy2State.syncDate ), - groupList: createSelector( - selector, - (state: State) => state.groupList + selectAllGroup2: createSelector( + selectGroup2, + ngeSelectAllGroup2 ), - group2SyncDate: createSelector( - selector, - (state: State) => state.group2SyncDate + selectGroup2SyncDate: createSelector( + selectGroup2, + group2State => group2State.syncDate ), - groupListAndBuddyList: createSelector( - selector, - (state: State) => { - return { - groupList: state.groupList, - buddyList: state.buddyInfoList - }; - } + selectAllRoom: createSelector( + selectRoom, + ngeSelectAllRoom ), - room: createSelector( - selector, - (state: State) => { - return { - roomList: state.roomList, - roomUserInfoMap: state.roomUserInfoMap - }; - } + selectRoomSyncDate: createSelector( + selectRoom, + roomState => roomState.syncDate ), - roomSyncDate: createSelector( - selector, - (state: State) => state.roomSyncDate + selectAllRoomUser: createSelector( + selectRoomUser, + ngeSelectAllRoomUser + ), + selectAllRoomUserShort: createSelector( + selectRoomUserShort, + ngeSelectAllRoomUserShort ) }; }