migration from plain state to ngrx entity

This commit is contained in:
병준 박 2019-10-11 11:58:03 +09:00
parent 90dee1da8b
commit bdfddc079e
7 changed files with 309 additions and 154 deletions

View File

@ -1,3 +1,7 @@
<ucap-room-list-item *ngFor="let room of roomList" [roomInfo]="room" [roomUserInfo]="getRoomUserList(room)" <ucap-room-list-item
(click)="onSelectedRoom(room)"> *ngFor="let room of roomList"
[roomInfo]="room"
[roomUserInfo]="getRoomUserList(room)"
(click)="onSelectedRoom(room)"
>
</ucap-room-list-item> </ucap-room-list-item>

View File

@ -2,7 +2,7 @@ import { Component, OnInit, OnDestroy } from '@angular/core';
import { ucapAnimations } from '@ucap-webmessenger/ui'; import { ucapAnimations } from '@ucap-webmessenger/ui';
import { NGXLogger } from 'ngx-logger'; import { NGXLogger } from 'ngx-logger';
import { Store, select } from '@ngrx/store'; import { Store, select } from '@ngrx/store';
import { Subscription } from 'rxjs'; import { Subscription, combineLatest } from 'rxjs';
import { import {
RoomInfo, RoomInfo,
UserInfoShort, UserInfoShort,
@ -10,7 +10,11 @@ import {
} from '@ucap-webmessenger/protocol-room'; } from '@ucap-webmessenger/protocol-room';
import * as AppStore from '@app/store'; import * as AppStore from '@app/store';
import * as ChatStore from '@app/store/messenger/chat'; 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({ @Component({
selector: 'app-layout-chat-left-sidenav-chat', selector: 'app-layout-chat-left-sidenav-chat',
@ -20,24 +24,30 @@ import { tap } from 'rxjs/operators';
}) })
export class ChatComponent implements OnInit, OnDestroy { export class ChatComponent implements OnInit, OnDestroy {
roomList: RoomInfo[]; roomList: RoomInfo[];
roomUserInfoMap: { roomUserList: RoomUserDetailData[];
[param: string]: { roomUserShortList: RoomUserData[];
userInfoShortList: UserInfoShort[];
userInfoList: RoomUserInfo[];
};
};
roomSubscription: Subscription; roomSubscription: Subscription;
constructor(private store: Store<any>, private logger: NGXLogger) {} constructor(private store: Store<any>, private logger: NGXLogger) {}
ngOnInit() { 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( .pipe(
select(AppStore.MessengerSelector.SyncSelector.room), tap(([room, roomUser, roomUserShort]) => {
tap(room => { this.roomList = room;
this.roomList = room.roomList; this.roomUserList = roomUser;
this.roomUserInfoMap = room.roomUserInfoMap; this.roomUserShortList = roomUserShort;
}) })
) )
.subscribe(); .subscribe();
@ -54,17 +64,22 @@ export class ChatComponent implements OnInit, OnDestroy {
} }
getRoomUserList(roomInfo: RoomInfo): RoomUserInfo[] | UserInfoShort[] { getRoomUserList(roomInfo: RoomInfo): RoomUserInfo[] | UserInfoShort[] {
if ( if (!!this.roomUserList && 0 < this.roomUserList.length) {
!!this.roomUserInfoMap[roomInfo.roomSeq].userInfoList && const i = this.roomUserList.findIndex(
0 < this.roomUserInfoMap[roomInfo.roomSeq].userInfoList.length value => roomInfo.roomSeq === value.roomSeq
) { );
return this.roomUserInfoMap[roomInfo.roomSeq].userInfoList; if (-1 < i) {
return this.roomUserList[i].userInfos;
}
}
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;
} }
if (
!!this.roomUserInfoMap[roomInfo.roomSeq].userInfoShortList &&
0 < this.roomUserInfoMap[roomInfo.roomSeq].userInfoShortList.length
) {
return this.roomUserInfoMap[roomInfo.roomSeq].userInfoShortList;
} }
} }
} }

View File

@ -67,43 +67,25 @@ export class GroupComponent implements OnInit {
select(AppStore.SettingSelector.CompanySelector.companyList) select(AppStore.SettingSelector.CompanySelector.companyList)
); );
this.groupBuddyList$ = this.store this.groupBuddyList$ = combineLatest([
.pipe( this.store.pipe(
select(AppStore.MessengerSelector.SyncSelector.groupListAndBuddyList) select(AppStore.MessengerSelector.SyncSelector.selectAllBuddy2)
),
this.store.pipe(
select(AppStore.MessengerSelector.SyncSelector.selectAllGroup2)
) )
.pipe( ]).pipe(
map(groupListAndBuddyList => { map(([buddyList, groupList]) => {
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: { const groupBuddyList: {
group: GroupDetailData; group: GroupDetailData;
buddyList: UserInfo[]; buddyList: UserInfo[];
}[] = []; }[] = [];
for (const group of groupList) { for (const group of groupList) {
const buddyList = groupListAndBuddyList.buddyList.filter(buddy => {
return group.userSeqs.indexOf(buddy.seq) > -1;
});
groupBuddyList.push({ groupBuddyList.push({
group, group,
buddyList buddyList: buddyList.filter(buddy => {
return group.userSeqs.indexOf(buddy.seq) > -1;
})
}); });
} }

View File

@ -135,13 +135,17 @@ export class AppMessengerResolver implements Resolve<void> {
}), }),
withLatestFrom( withLatestFrom(
this.store.pipe( this.store.pipe(
select(AppStore.MessengerSelector.SyncSelector.buddy2SyncDate) select(
AppStore.MessengerSelector.SyncSelector.selectBuddy2SyncDate
)
), ),
this.store.pipe( this.store.pipe(
select(AppStore.MessengerSelector.SyncSelector.group2SyncDate) select(
AppStore.MessengerSelector.SyncSelector.selectGroup2SyncDate
)
), ),
this.store.pipe( this.store.pipe(
select(AppStore.MessengerSelector.SyncSelector.roomSyncDate) select(AppStore.MessengerSelector.SyncSelector.selectRoomSyncDate)
) )
), ),
map(([_, buddy2SyncDate, group2SyncDate, roomSyncDate]) => { map(([_, buddy2SyncDate, group2SyncDate, roomSyncDate]) => {

View File

@ -208,15 +208,15 @@ export class Effects {
ofType(ChatStore.newEventMessage), ofType(ChatStore.newEventMessage),
withLatestFrom( withLatestFrom(
this.store.pipe( 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( 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]) => { tap(([action, roomSeqList, roomSyncDate]) => {
const index = roomList.findIndex( const index = roomSeqList.findIndex(
(roomInfo, i) => roomInfo.roomSeq === action.roomSeq (roomSeq, i) => roomSeq === action.roomSeq
); );
if (-1 === index) { if (-1 === index) {

View File

@ -1,62 +1,95 @@
import { createReducer, on } from '@ngrx/store'; import { createReducer, on } from '@ngrx/store';
import { initialState } from './state'; import {
initialState,
adapterBuddy2,
adapterGroup2,
adapterRoom,
adapterRoomUser,
adapterRoomUserShort
} from './state';
import { import {
buddy2Success, buddy2Success,
group2Success, group2Success,
roomSuccess, roomSuccess,
updateRoomForNewEventMessage updateRoomForNewEventMessage
} from './actions'; } from './actions';
import {
import { RoomInfo } from '@ucap-webmessenger/protocol-room'; RoomUserDetailData,
RoomUserData
} from '@ucap-webmessenger/protocol-sync';
export const reducer = createReducer( export const reducer = createReducer(
initialState, initialState,
on(buddy2Success, (state, action) => { on(buddy2Success, (state, action) => {
return { return {
...state, ...state,
buddyInfoList: [...state.buddyInfoList, ...action.buddyList], buddy2: adapterBuddy2.addAll(action.buddyList, {
buddy2SyncDate: action.syncDate ...state.buddy2,
syncDate: action.syncDate
})
}; };
}), }),
on(group2Success, (state, action) => { on(group2Success, (state, action) => {
return { return {
...state, ...state,
groupList: [...state.groupList, ...action.groupList], group2: adapterGroup2.addAll(action.groupList, {
group2SyncDate: action.syncDate ...state.group2,
syncDate: action.syncDate
})
}; };
}), }),
on(roomSuccess, (state, action) => { 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 { return {
...state, ...state,
roomList: [...state.roomList, ...action.roomList], room: adapterRoom.addAll(action.roomList, {
roomUserInfoMap: { ...state.room,
...state.roomUserInfoMap, syncDate: action.syncDate
...action.roomUserInfoMap }),
}, roomUser: adapterRoomUser.addAll(roomUserList, {
roomSyncDate: action.syncDate ...state.roomUser
}),
roomUserShort: adapterRoomUserShort.addAll(roomUserShortList, {
...state.roomUserShort
})
}; };
}), }),
on(updateRoomForNewEventMessage, (state, action) => { on(updateRoomForNewEventMessage, (state, action) => {
const roomList: RoomInfo[] = []; const roomInfo = {
...state.room.entities[action.roomSeq],
state.roomList.forEach((roomInfo, index) => {
if (roomInfo.roomSeq === action.roomSeq) {
roomList.push({
...roomInfo,
finalEventDate: action.info.sendDate, finalEventDate: action.info.sendDate,
finalEventMessage: action.info.sentMessage finalEventMessage: action.info.sentMessage
}); };
} else {
roomList.push(roomInfo);
}
});
return { return {
...state, ...state,
roomList room: adapterRoom.updateOne(
{ id: action.roomSeq, changes: roomInfo },
{ ...state.room }
)
}; };
}) })
); );

View File

@ -1,77 +1,194 @@
import { Selector, createSelector } from '@ngrx/store'; 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 { import {
RoomInfo, RoomInfo,
UserInfoShort, UserInfoShort,
UserInfo as RoomUserInfo UserInfo as RoomUserInfo
} from '@ucap-webmessenger/protocol-room'; } from '@ucap-webmessenger/protocol-room';
export interface State { export interface Buddy2State extends EntityState<UserInfo> {
buddyInfoList: UserInfo[]; syncDate: string;
buddy2SyncDate: string;
groupList: GroupDetailData[];
group2SyncDate: string;
roomList: RoomInfo[];
roomUserInfoMap: {
[param: string]: {
userInfoShortList: UserInfoShort[];
userInfoList: RoomUserInfo[];
};
};
roomSyncDate: string;
} }
export interface Group2State extends EntityState<GroupDetailData> {
syncDate: string;
}
export interface RoomState extends EntityState<RoomInfo> {
syncDate: string;
}
export interface RoomUserState extends EntityState<RoomUserDetailData> {}
export interface RoomUserShortState extends EntityState<RoomUserData> {}
export interface State {
buddy2: Buddy2State;
group2: Group2State;
room: RoomState;
roomUser: RoomUserState;
roomUserShort: RoomUserShortState;
}
export const adapterBuddy2 = createEntityAdapter<UserInfo>({
selectId: userInfo => userInfo.seq
});
export const adapterGroup2 = createEntityAdapter<GroupDetailData>({
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<RoomInfo>({
selectId: roomInfo => roomInfo.roomSeq,
sortComparer: (a, b) => {
return (
new Date(b.finalEventDate).getTime() -
new Date(a.finalEventDate).getTime()
);
}
});
export const adapterRoomUser = createEntityAdapter<RoomUserDetailData>({
selectId: roomUserDetailData => roomUserDetailData.roomSeq
});
export const adapterRoomUserShort = createEntityAdapter<RoomUserData>({
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 = { export const initialState: State = {
buddyInfoList: [], buddy2: buddy2InitialState,
buddy2SyncDate: '', group2: group2InitialState,
groupList: [], room: roomInitialState,
group2SyncDate: '', roomUser: roomUserInitialState,
roomList: [], roomUserShort: roomUserShortInitialState
roomUserInfoMap: {},
roomSyncDate: ''
}; };
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<S>(selector: Selector<any, State>) { export function selectors<S>(selector: Selector<any, State>) {
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 { return {
buddyInfoList: createSelector( selectAllBuddy2: createSelector(
selector, selectBuddy2,
(state: State) => state.buddyInfoList ngeSelectAllBuddy2
), ),
buddy2SyncDate: createSelector( selectBuddy2SyncDate: createSelector(
selector, selectBuddy2,
(state: State) => state.buddy2SyncDate buddy2State => buddy2State.syncDate
), ),
groupList: createSelector( selectAllGroup2: createSelector(
selector, selectGroup2,
(state: State) => state.groupList ngeSelectAllGroup2
), ),
group2SyncDate: createSelector( selectGroup2SyncDate: createSelector(
selector, selectGroup2,
(state: State) => state.group2SyncDate group2State => group2State.syncDate
), ),
groupListAndBuddyList: createSelector( selectAllRoom: createSelector(
selector, selectRoom,
(state: State) => { ngeSelectAllRoom
return {
groupList: state.groupList,
buddyList: state.buddyInfoList
};
}
), ),
room: createSelector( selectRoomSyncDate: createSelector(
selector, selectRoom,
(state: State) => { roomState => roomState.syncDate
return {
roomList: state.roomList,
roomUserInfoMap: state.roomUserInfoMap
};
}
), ),
roomSyncDate: createSelector( selectAllRoomUser: createSelector(
selector, selectRoomUser,
(state: State) => state.roomSyncDate ngeSelectAllRoomUser
),
selectAllRoomUserShort: createSelector(
selectRoomUserShort,
ngeSelectAllRoomUserShort
) )
}; };
} }