buddy & group list are implemented

This commit is contained in:
병준 박 2019-09-27 12:53:21 +09:00
parent 8d8b1e5c47
commit dff2e4e55f
25 changed files with 626 additions and 189 deletions

View File

@ -1,3 +1,4 @@
<ucap-group-expansion-panel <ucap-group-expansion-panel
[groupList]="groupList$ | async" [groupBuddyList]="groupBuddyList$ | async"
(selectBuddy)="onSelectBuddy($event)"
></ucap-group-expansion-panel> ></ucap-group-expansion-panel>

View File

@ -1,6 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable, combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
import { Store, select } from '@ngrx/store'; import { Store, select } from '@ngrx/store';
@ -8,6 +9,8 @@ import { ucapAnimations } from '@ucap-webmessenger/ui';
import { UserInfo, GroupDetailData } from '@ucap-webmessenger/protocol-sync'; import { UserInfo, GroupDetailData } from '@ucap-webmessenger/protocol-sync';
import * as AppStore from '@app/store'; import * as AppStore from '@app/store';
import * as ChatStore from '@app/store/messenger/chat';
import { NGXLogger } from 'ngx-logger';
@Component({ @Component({
selector: 'app-layout-chat-left-sidenav-group', selector: 'app-layout-chat-left-sidenav-group',
@ -16,13 +19,59 @@ import * as AppStore from '@app/store';
animations: ucapAnimations animations: ucapAnimations
}) })
export class GroupComponent implements OnInit { export class GroupComponent implements OnInit {
groupList$: Observable<GroupDetailData[]>; groupBuddyList$: Observable<
{ group: GroupDetailData; buddyList: UserInfo[] }[]
>;
constructor(private store: Store<any>) {} constructor(private store: Store<any>, private logger: NGXLogger) {}
ngOnInit() { ngOnInit() {
this.groupList$ = this.store.pipe( this.groupBuddyList$ = this.store
select(AppStore.MessengerSelector.SyncSelector.groupList) .pipe(
); select(AppStore.MessengerSelector.SyncSelector.groupListAndBuddyList)
)
.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 => {
return group.userSeqs.indexOf(buddy.seq) > -1;
});
groupBuddyList.push({
group,
buddyList
});
}
return groupBuddyList;
})
);
}
onSelectBuddy(buddy: UserInfo) {
this.store.dispatch(ChatStore.selectedRoom({ roomSeq: buddy.seq }));
} }
} }

View File

@ -42,6 +42,7 @@ export class LoginPageComponent implements OnInit {
AuthenticationStore.webLogin({ AuthenticationStore.webLogin({
loginInfo: { loginInfo: {
companyCode: value.companyCode, companyCode: value.companyCode,
companyGroupType: 'C',
loginId: value.loginId, loginId: value.loginId,
loginPw: value.loginPw loginPw: value.loginPw
}, },

View File

@ -4,10 +4,10 @@
</div> </div>
<div class="contents"> <div class="contents">
<app-layout-messenger-intro <app-layout-messenger-intro
*ngIf="!selectedChat" *ngIf="!(this.selectedChat$ | async)"
></app-layout-messenger-intro> ></app-layout-messenger-intro>
<app-layout-messenger-messages <app-layout-messenger-messages
*ngIf="selectedChat" *ngIf="!!(this.selectedChat$ | async)"
></app-layout-messenger-messages> ></app-layout-messenger-messages>
</div> </div>
<div class="right-side"> <div class="right-side">

View File

@ -1,5 +1,9 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { AuthenticationProtocolService } from '@ucap-webmessenger/protocol-authentication';
import { Store, select } from '@ngrx/store';
import * as AppSotre from '@app/store';
import { Observable } from 'rxjs';
@Component({ @Component({
selector: 'app-page-messenger-main', selector: 'app-page-messenger-main',
@ -7,14 +11,13 @@ import { AuthenticationProtocolService } from '@ucap-webmessenger/protocol-authe
styleUrls: ['./main.page.component.scss'] styleUrls: ['./main.page.component.scss']
}) })
export class MainPageComponent implements OnInit { export class MainPageComponent implements OnInit {
selectedChat: boolean; selectedChat$: Observable<number | null>;
constructor( constructor(private store: Store<any>) {}
private authenticationProtocolService: AuthenticationProtocolService
) {}
ngOnInit(): void { ngOnInit(): void {
// this.authenticationProtocolService.login({}); this.selectedChat$ = this.store.pipe(
this.selectedChat = true; select(AppSotre.MessengerSelector.ChatSelector.selectedRoom)
);
} }
} }

View File

@ -15,7 +15,12 @@ import { PublicApiService } from '@ucap-webmessenger/api-public';
import * as AppStore from '../store'; import * as AppStore from '../store';
import * as VersionInfoStore from '../store/setting/version-info'; import * as VersionInfoStore from '../store/setting/version-info';
import { LoginInfo, KEY_LOGIN_INFO } from '../types'; import {
LoginInfo,
KEY_LOGIN_INFO,
EnvironmentsInfo,
KEY_ENVIRONMENTS_INFO
} from '../types';
import { InnerProtocolService } from '@ucap-webmessenger/protocol-inner'; import { InnerProtocolService } from '@ucap-webmessenger/protocol-inner';
import { import {
AuthenticationProtocolService, AuthenticationProtocolService,
@ -41,64 +46,68 @@ export class AppMessengerResolver implements Resolve<void> {
state: RouterStateSnapshot state: RouterStateSnapshot
): void | Observable<void> | Promise<void> { ): void | Observable<void> | Promise<void> {
const loginInfo = this.sessionStorageService.get<LoginInfo>(KEY_LOGIN_INFO); const loginInfo = this.sessionStorageService.get<LoginInfo>(KEY_LOGIN_INFO);
const environmentsInfo = this.sessionStorageService.get<EnvironmentsInfo>(
KEY_ENVIRONMENTS_INFO
);
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
this.publicApiService resolve();
.versionInfo2({ // this.publicApiService
deviceType: loginInfo.deviceType, // .versionInfo2({
companyGroupType: 'C', // deviceType: environmentsInfo.deviceType,
companyCode: loginInfo.companyCode, // companyGroupType: loginInfo.companyGroupType,
loginId: loginInfo.loginId // companyCode: loginInfo.companyCode,
}) // loginId: loginInfo.loginId
.pipe( // })
take(1), // .pipe(
tap(versionInfo2Res => { // take(1),
this.store.dispatch(VersionInfoStore.fetchSuccess(versionInfo2Res)); // tap(versionInfo2Res => {
}), // this.store.dispatch(VersionInfoStore.fetchSuccess(versionInfo2Res));
mergeMap(versionInfo2Res => // }),
this.protocolService.connect(versionInfo2Res.serverIp) // mergeMap(versionInfo2Res =>
), // this.protocolService.connect(versionInfo2Res.serverIp)
mergeMap(() => this.innerProtocolService.conn({})), // ),
mergeMap(connRres => // mergeMap(() => this.innerProtocolService.conn({})),
this.authenticationProtocolService.login({ // mergeMap(connRres =>
loginId: loginInfo.loginId, // this.authenticationProtocolService.login({
loginPw: loginInfo.loginPw, // loginId: loginInfo.loginId,
deviceType: loginInfo.deviceType, // loginPw: loginInfo.loginPw,
deviceId: ' ', // deviceType: environmentsInfo.deviceType,
token: '', // deviceId: ' ',
localeCode: loginInfo.localeCode, // token: '',
pushId: ' ', // localeCode: loginInfo.localeCode,
companyCode: loginInfo.companyCode, // pushId: ' ',
passwordEncodingType: 1, // companyCode: loginInfo.companyCode,
clientVersion: '', // passwordEncodingType: 1,
reconnect: false, // clientVersion: '',
ip: 'localhost', // reconnect: false,
hostName: '', // ip: 'localhost',
ssoMode: SSOMode.AUTH, // hostName: '',
userSpecificInformation: 'PRO_000482', // ssoMode: SSOMode.AUTH,
productId: 'PRO_000482', // userSpecificInformation: 'PRO_000482',
productName: 'EZMessenger' // productId: 'PRO_000482',
}) // productName: 'EZMessenger'
), // })
map(loginRes => { // ),
this.store.dispatch( // map(loginRes => {
AuthenticationStore.loginSuccess({ // this.store.dispatch(
loginInfo: loginRes // AuthenticationStore.loginSuccess({
}) // loginInfo: loginRes
); // })
}), // );
catchError(err => { // }),
return throwError(err); // catchError(err => {
}) // return throwError(err);
) // })
.subscribe( // )
() => { // .subscribe(
resolve(); // () => {
}, // resolve();
err => { // },
reject(); // err => {
} // reject();
); // }
// );
}); });
} }
} }

View File

@ -1,14 +1,44 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { AppNotificationService } from './notification.service'; import { AppNotificationService } from './notification.service';
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { EnviromentUtilService } from '@ucap-webmessenger/util';
import { DeviceType } from '@ucap-webmessenger/core';
import { EnvironmentsInfo, KEY_ENVIRONMENTS_INFO } from '@app/types';
@Injectable() @Injectable()
export class AppService { export class AppService {
constructor(private appNotificationService: AppNotificationService) {} constructor(
private enviromentUtilService: EnviromentUtilService,
private sessionStorageService: SessionStorageService,
private appNotificationService: AppNotificationService
) {}
public postInit(): Promise<void> { public postInit(): Promise<void> {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
this.appNotificationService.subscribe(); try {
resolve(); let deviceType: DeviceType;
if (this.enviromentUtilService.nodeWebkit()) {
deviceType = DeviceType.PC;
} else if (this.enviromentUtilService.android()) {
deviceType = DeviceType.Android;
} else if (this.enviromentUtilService.ios()) {
deviceType = DeviceType.iOS;
} else {
deviceType = DeviceType.Web;
}
this.sessionStorageService.set<EnvironmentsInfo>(
KEY_ENVIRONMENTS_INFO,
{
deviceType
}
);
this.appNotificationService.subscribe();
resolve();
} catch (error) {
reject();
}
}); });
} }
} }

View File

@ -6,8 +6,7 @@ import {
SessionStorageService, SessionStorageService,
LocalStorageService LocalStorageService
} from '@ucap-webmessenger/web-storage'; } from '@ucap-webmessenger/web-storage';
import { EnviromentUtilService } from '@ucap-webmessenger/util'; import { LocaleCode } from '@ucap-webmessenger/core';
import { DeviceType, LocaleCode } from '@ucap-webmessenger/core';
import { LoginInfo, KEY_LOGIN_INFO } from '../types'; import { LoginInfo, KEY_LOGIN_INFO } from '../types';
@Injectable({ @Injectable({
@ -18,8 +17,7 @@ export class AppAuthenticationService {
constructor( constructor(
private sessionStorageService: SessionStorageService, private sessionStorageService: SessionStorageService,
private localStorageService: LocalStorageService, private localStorageService: LocalStorageService
private enviromentUtilService: EnviromentUtilService
) {} ) {}
authenticated(): boolean { authenticated(): boolean {
@ -28,24 +26,11 @@ export class AppAuthenticationService {
} }
login(loginInfo: LoginInfo, rememberMe: boolean) { login(loginInfo: LoginInfo, rememberMe: boolean) {
let deviceType: DeviceType;
loginInfo = { ...loginInfo, localeCode: LocaleCode.Korean }; loginInfo = { ...loginInfo, localeCode: LocaleCode.Korean };
if (this.enviromentUtilService.nodeWebkit()) {
deviceType = DeviceType.PC;
} else if (this.enviromentUtilService.android()) {
deviceType = DeviceType.Android;
} else if (this.enviromentUtilService.ios()) {
deviceType = DeviceType.iOS;
} else {
deviceType = DeviceType.Web;
}
this.sessionStorageService.set<LoginInfo>(KEY_LOGIN_INFO, { this.sessionStorageService.set<LoginInfo>(KEY_LOGIN_INFO, {
...loginInfo, ...loginInfo,
loginPw: CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(loginInfo.loginPw)), loginPw: CryptoJS.enc.Hex.stringify(CryptoJS.SHA256(loginInfo.loginPw))
deviceType
}); });
if (rememberMe) { if (rememberMe) {

View File

@ -1,18 +1,22 @@
import { Injectable, Inject } from '@angular/core'; import { Injectable, Inject } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { Actions, ofType, createEffect } from '@ngrx/effects'; import { of, throwError, EMPTY as empty } from 'rxjs';
import { of } from 'rxjs';
import { import {
catchError, catchError,
exhaustMap, exhaustMap,
map, map,
tap, tap,
take, take,
switchMap switchMap,
mergeMap,
skip,
concatMap
} from 'rxjs/operators'; } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions, ofType, createEffect } from '@ngrx/effects';
import { import {
PiService, PiService,
Login2Response, Login2Response,
@ -37,38 +41,265 @@ import {
webLoginSuccess, webLoginSuccess,
webLoginFailure webLoginFailure
} from './actions'; } from './actions';
import { LoginInfo } from '../../../types'; import {
LoginInfo,
EnvironmentsInfo,
KEY_ENVIRONMENTS_INFO
} from '../../../types';
import { AppAuthenticationService } from '../../../services/authentication.service'; import { AppAuthenticationService } from '../../../services/authentication.service';
import { NGXLogger } from 'ngx-logger';
import {
PublicApiService,
VersionInfo2Response
} from '@ucap-webmessenger/api-public';
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import * as VersionInfoStore from '@app/store/setting/version-info';
import { ProtocolService } from '@ucap-webmessenger/protocol';
import { InnerProtocolService } from '@ucap-webmessenger/protocol-inner';
import {
AuthenticationProtocolService,
SSOMode,
LoginResponse
} from '@ucap-webmessenger/protocol-authentication';
import CryptoJS from 'crypto-js';
@Injectable() @Injectable()
export class Effects { export class Effects {
webLogin$ = createEffect(() => // webLogin$ = createEffect(() =>
this.actions$.pipe( // this.actions$.pipe(
ofType(webLogin), // ofType(webLogin),
map(action => action), // map(action => action),
exhaustMap((params: { loginInfo: LoginInfo; rememberMe: boolean }) => // exhaustMap((params: { loginInfo: LoginInfo; rememberMe: boolean }) =>
this.piService // this.piService
.login2({ // .login2({
loginId: params.loginInfo.loginId, // loginId: params.loginInfo.loginId,
loginPw: params.loginInfo.loginPw, // loginPw: params.loginInfo.loginPw,
companyCode: params.loginInfo.companyCode // companyCode: params.loginInfo.companyCode
}) // })
.pipe( // .pipe(
map((res: Login2Response) => { // map((res: Login2Response) => {
if ('success' !== res.status.toLowerCase()) { // if ('success' !== res.status.toLowerCase()) {
return webLoginFailure({ error: 'Failed' }); // return webLoginFailure({ error: 'Failed' });
} else { // } else {
return webLoginSuccess({ // return webLoginSuccess({
loginInfo: params.loginInfo, // loginInfo: params.loginInfo,
rememberMe: params.rememberMe, // rememberMe: params.rememberMe,
login2Response: res // login2Response: res
}); // });
} // }
}), // }),
catchError(error => of(webLoginFailure({ error }))) // catchError(error => of(webLoginFailure({ error })))
) // )
) // )
) // )
// );
webLogin$ = createEffect(
() =>
this.actions$.pipe(
ofType(webLogin),
map(action => action),
switchMap(
(loginParams: { loginInfo: LoginInfo; rememberMe: boolean }) => {
const environmentsInfo = this.sessionStorageService.get<
EnvironmentsInfo
>(KEY_ENVIRONMENTS_INFO);
let login2Res: Login2Response;
let loginRes: LoginResponse;
let versionInfo2Res: VersionInfo2Response;
let encLoginPw: string;
return this.piService
.login2({
loginId: loginParams.loginInfo.loginId,
loginPw: loginParams.loginInfo.loginPw,
companyCode: loginParams.loginInfo.companyCode
})
.pipe(
concatMap(res => {
console.log('tap');
if ('success' !== res.status.toLowerCase()) {
return throwError('login2 failed');
}
login2Res = res;
return of(true);
}),
mergeMap(dd => {
console.log('checkForUpdates');
return this.nativeService.checkForUpdates();
}),
concatMap(update => {
if (update) {
return throwError('update process');
}
encLoginPw = CryptoJS.enc.Hex.stringify(
CryptoJS.SHA256(loginParams.loginInfo.loginPw)
);
return of(true);
}),
mergeMap(() =>
this.publicApiService.versionInfo2({
deviceType: environmentsInfo.deviceType,
companyGroupType: loginParams.loginInfo.companyGroupType,
companyCode: loginParams.loginInfo.companyCode,
loginId: loginParams.loginInfo.loginId
})
),
map(res => {
this.store.dispatch(VersionInfoStore.fetchSuccess(res));
versionInfo2Res = res;
return of(true);
}),
mergeMap(() =>
this.protocolService.connect(versionInfo2Res.serverIp)
),
mergeMap(() => this.innerProtocolService.conn({})),
mergeMap(() =>
this.authenticationProtocolService.login({
loginId: loginParams.loginInfo.loginId,
loginPw: encLoginPw,
deviceType: environmentsInfo.deviceType,
deviceId: ' ',
token: '',
localeCode: loginParams.loginInfo.localeCode,
pushId: ' ',
companyCode: loginParams.loginInfo.companyCode,
passwordEncodingType: 1,
clientVersion: '',
reconnect: false,
ip: 'localhost',
hostName: '',
ssoMode: SSOMode.AUTH,
userSpecificInformation: 'PRO_000482',
productId: 'PRO_000482',
productName: 'EZMessenger'
})
),
exhaustMap(async res => {
if (res.privateInformationAgree) {
return of(null);
}
loginRes = res;
const privacyTotalUrl = this.piService.privacyTotalUrl({
companyCode: res.companyCode,
userSeq: res.userSeq,
token: res.tokenString,
deviceType: environmentsInfo.deviceType,
localeCode: loginParams.loginInfo.localeCode,
textOnly: 'true'
});
const result = await this.dialogService.open<
ConfirmDialogComponent,
ConfirmDialogData,
ConfirmDialogResult
>(ConfirmDialogComponent, {
width: '100%',
height: '500px',
disableClose: true,
data: {
title: '개인정보 동의',
html: `<iframe id="ifm_privacy" src="${privacyTotalUrl}" style="width: 100%;height: 300px;" />`
}
});
if (!result.choice) {
console.log('privacy error');
throw new Error('privacy error');
}
return of(true);
}),
exhaustMap(proceed => {
if (null === proceed) {
return of(null);
}
return this.piService.userTermsAction({
userSeq: loginRes.userSeq,
token: loginRes.tokenString,
deviceType: environmentsInfo.deviceType
});
}),
exhaustMap(async () => {
this.logger.debug(
'loginRes.passwordExpired',
loginRes.passwordExpired
);
if (!loginRes.passwordExpired) {
return of(null);
}
const privacyTotalUrl = this.piService.privacyTotalUrl({
companyCode: loginRes.companyCode,
userSeq: loginRes.userSeq,
token: loginRes.tokenString,
deviceType: environmentsInfo.deviceType,
localeCode: loginParams.loginInfo.localeCode,
textOnly: 'true'
});
const result = await this.dialogService.open<
ConfirmDialogComponent,
ConfirmDialogData,
ConfirmDialogResult
>(ConfirmDialogComponent, {
width: '100%',
height: '500px',
disableClose: true,
data: {
title: '패스워드 변경',
html: `<iframe id="ifm_privacy" src="${privacyTotalUrl}" style="width: 100%;height: 300px;" />`
}
});
if (!result.choice) {
return throwError('privacy error');
}
return of(true);
}),
mergeMap(proceed => {
// 패스워드 변경
if (null === proceed) {
return of(null);
}
return this.piService.userTermsAction({
userSeq: loginRes.userSeq,
token: loginRes.tokenString,
deviceType: environmentsInfo.deviceType
});
}),
map(res => {
this.appAuthenticationService.login(
loginParams.loginInfo,
loginParams.rememberMe
);
this.store.dispatch(
loginSuccess({
loginInfo: loginRes
})
);
this.router.navigate(['/messenger']);
}),
catchError(error => {
return throwError(error);
})
);
}
),
catchError(error => {
this.store.dispatch(webLoginFailure({ error: error.message }));
return of(error);
})
),
{ dispatch: false }
); );
webLoginSuccess$ = createEffect( webLoginSuccess$ = createEffect(
@ -140,9 +371,16 @@ export class Effects {
constructor( constructor(
private actions$: Actions, private actions$: Actions,
private router: Router, private router: Router,
private store: Store<any>,
private piService: PiService, private piService: PiService,
private publicApiService: PublicApiService,
private protocolService: ProtocolService,
private innerProtocolService: InnerProtocolService,
private authenticationProtocolService: AuthenticationProtocolService,
private appAuthenticationService: AppAuthenticationService, private appAuthenticationService: AppAuthenticationService,
private dialogService: DialogService, private dialogService: DialogService,
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
private sessionStorageService: SessionStorageService,
private logger: NGXLogger
) {} ) {}
} }

View File

@ -28,62 +28,70 @@ import {
agreeFailure agreeFailure
} from './actions'; } from './actions';
import { SessionStorageService } from '@ucap-webmessenger/web-storage'; import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { LoginInfo, KEY_LOGIN_INFO } from '@app/types'; import {
LoginInfo,
KEY_LOGIN_INFO,
EnvironmentsInfo,
KEY_ENVIRONMENTS_INFO
} from '@app/types';
import { initSettings } from '@app/store/setting/init'; import { initSettings } from '@app/store/setting/init';
@Injectable() @Injectable()
export class Effects { export class Effects {
agreeConfirmation$ = createEffect(() => // agreeConfirmation$ = createEffect(() =>
this.actions$.pipe( // this.actions$.pipe(
ofType(loginSuccess), // ofType(loginSuccess),
exhaustMap(async params => { // exhaustMap(async params => {
if (params.loginInfo.privateInformationAgree) { // if (params.loginInfo.privateInformationAgree) {
return null; // return null;
} // }
const loginInfo = this.sessionStorageService.get<LoginInfo>( // const loginInfo = this.sessionStorageService.get<LoginInfo>(
KEY_LOGIN_INFO // KEY_LOGIN_INFO
); // );
// const environmentsInfo = this.sessionStorageService.get<
// EnvironmentsInfo
// >(KEY_ENVIRONMENTS_INFO);
const privacyTotalUrl = this.piService.privacyTotalUrl({ // const privacyTotalUrl = this.piService.privacyTotalUrl({
companyCode: params.loginInfo.companyCode, // companyCode: params.loginInfo.companyCode,
userSeq: params.loginInfo.userSeq, // userSeq: params.loginInfo.userSeq,
token: params.loginInfo.tokenString, // token: params.loginInfo.tokenString,
deviceType: loginInfo.deviceType, // deviceType: environmentsInfo.deviceType,
localeCode: loginInfo.localeCode, // localeCode: loginInfo.localeCode,
textOnly: 'true' // textOnly: 'true'
}); // });
const result = await this.dialogService.open< // const result = await this.dialogService.open<
ConfirmDialogComponent, // ConfirmDialogComponent,
ConfirmDialogData, // ConfirmDialogData,
ConfirmDialogResult // ConfirmDialogResult
>(ConfirmDialogComponent, { // >(ConfirmDialogComponent, {
width: '100%', // width: '100%',
height: '500px', // height: '500px',
disableClose: true, // disableClose: true,
data: { // data: {
title: '개인정보 동의', // title: '개인정보 동의',
html: `<iframe id="ifm_privacy" src="${privacyTotalUrl}" style="width: 100%;height: 300px;" />` // html: `<iframe id="ifm_privacy" src="${privacyTotalUrl}" style="width: 100%;height: 300px;" />`
} // }
}); // });
return { // return {
loginInfo: params.loginInfo, // loginInfo: params.loginInfo,
choice: result.choice // choice: result.choice
}; // };
}), // }),
map(params => { // map(params => {
if (!params) { // if (!params) {
return agreeConfirmationNotNeeded(); // return agreeConfirmationNotNeeded();
} // }
return params.choice // return params.choice
? agreeConfirmationYes({ loginInfo: params.loginInfo }) // ? agreeConfirmationYes({ loginInfo: params.loginInfo })
: agreeConfirmationNo(); // : agreeConfirmationNo();
}) // })
) // )
); // );
agreeConfirmationYes$ = createEffect(() => agreeConfirmationYes$ = createEffect(() =>
this.actions$.pipe( this.actions$.pipe(
@ -92,9 +100,13 @@ export class Effects {
const loginInfo = this.sessionStorageService.get<LoginInfo>( const loginInfo = this.sessionStorageService.get<LoginInfo>(
KEY_LOGIN_INFO KEY_LOGIN_INFO
); );
const environmentsInfo = this.sessionStorageService.get<
EnvironmentsInfo
>(KEY_ENVIRONMENTS_INFO);
return { return {
loginInfo, loginInfo,
environmentsInfo,
loginResponse: action.loginInfo loginResponse: action.loginInfo
}; };
}), }),
@ -103,7 +115,7 @@ export class Effects {
.userTermsAction({ .userTermsAction({
userSeq: params.loginResponse.userSeq, userSeq: params.loginResponse.userSeq,
token: params.loginResponse.tokenString, token: params.loginResponse.tokenString,
deviceType: params.loginInfo.deviceType deviceType: params.environmentsInfo.deviceType
}) })
.pipe( .pipe(
map((res: UserTermsActionResponse) => { map((res: UserTermsActionResponse) => {

View File

@ -0,0 +1,6 @@
import { createAction, props } from '@ngrx/store';
export const selectedRoom = createAction(
'[Messenger::Chat] selectedRoom',
props<{ roomSeq: number }>()
);

View File

@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import { Actions } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { NGXLogger } from 'ngx-logger';
@Injectable()
export class Effects {
constructor(
private actions$: Actions,
private store: Store<any>,
private logger: NGXLogger
) {}
}

View File

@ -0,0 +1,4 @@
export * from './actions';
export * from './effects';
export * from './reducers';
export * from './state';

View File

@ -0,0 +1,13 @@
import { createReducer, on } from '@ngrx/store';
import { initialState } from './state';
import { selectedRoom } from './actions';
export const reducer = createReducer(
initialState,
on(selectedRoom, (state, action) => {
return {
...state,
selectedRoom: action.roomSeq
};
})
);

View File

@ -0,0 +1,18 @@
import { Selector, createSelector } from '@ngrx/store';
export interface State {
selectedRoom: number | null;
}
export const initialState: State = {
selectedRoom: null
};
export function selectors<S>(selector: Selector<any, State>) {
return {
selectedRoom: createSelector(
selector,
(state: State) => state.selectedRoom
)
};
}

View File

@ -1,22 +1,31 @@
import { Type } from '@angular/core'; import { Type } from '@angular/core';
import { Action, combineReducers, Selector, createSelector } from '@ngrx/store'; import { Action, combineReducers, Selector, createSelector } from '@ngrx/store';
import * as ChatStore from './chat';
import * as SyncStore from './sync'; import * as SyncStore from './sync';
export interface State { export interface State {
chat: ChatStore.State;
sync: SyncStore.State; sync: SyncStore.State;
} }
export const effects: Type<any>[] = [SyncStore.Effects]; export const effects: Type<any>[] = [ChatStore.Effects, SyncStore.Effects];
export function reducers(state: State | undefined, action: Action) { export function reducers(state: State | undefined, action: Action) {
return combineReducers({ return combineReducers({
chat: ChatStore.reducer,
sync: SyncStore.reducer sync: SyncStore.reducer
})(state, action); })(state, action);
} }
export function selectors<S>(selector: Selector<any, State>) { export function selectors<S>(selector: Selector<any, State>) {
return { return {
ChatSelector: ChatStore.selectors(
createSelector(
selector,
(state: State) => state.chat
)
),
SyncSelector: SyncStore.selectors( SyncSelector: SyncStore.selectors(
createSelector( createSelector(
selector, selector,

View File

@ -33,6 +33,15 @@ export function selectors<S>(selector: Selector<any, State>) {
group2SyncDate: createSelector( group2SyncDate: createSelector(
selector, selector,
(state: State) => state.group2SyncDate (state: State) => state.group2SyncDate
),
groupListAndBuddyList: createSelector(
selector,
(state: State) => {
return {
groupList: state.groupList,
buddyList: state.buddyInfoList
};
}
) )
}; };
} }

View File

@ -8,12 +8,13 @@ import { catchError, exhaustMap, map, tap } from 'rxjs/operators';
import { regViewSuccess, regViewFailure } from './actions'; import { regViewSuccess, regViewFailure } from './actions';
import { initSettings } from '../init'; import { initSettings } from '../init';
import { OptionProtocolService } from '@ucap-webmessenger/protocol-option'; import { OptionProtocolService } from '@ucap-webmessenger/protocol-option';
import { loginSuccess } from '@app/store/account/authentication';
@Injectable() @Injectable()
export class Effects { export class Effects {
initSettings$ = createEffect(() => initSettings$ = createEffect(() =>
this.actions$.pipe( this.actions$.pipe(
ofType(initSettings), ofType(loginSuccess),
exhaustMap(() => exhaustMap(() =>
this.optionProtocolService.regView({}).pipe( this.optionProtocolService.regView({}).pipe(
map(res => regViewSuccess({ res })), map(res => regViewSuccess({ res })),

View File

@ -13,19 +13,29 @@ import {
AuthRequest AuthRequest
} from '@ucap-webmessenger/protocol-query'; } from '@ucap-webmessenger/protocol-query';
import { SessionStorageService } from '@ucap-webmessenger/web-storage'; import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { LoginInfo, KEY_LOGIN_INFO } from '@app/types'; import {
LoginInfo,
KEY_LOGIN_INFO,
EnvironmentsInfo,
KEY_ENVIRONMENTS_INFO
} from '@app/types';
import { loginSuccess } from '@app/store/account/authentication';
@Injectable() @Injectable()
export class Effects { export class Effects {
initSettings$ = createEffect(() => initSettings$ = createEffect(() =>
this.actions$.pipe( this.actions$.pipe(
ofType(initSettings), ofType(loginSuccess),
map(() => { map(() => {
const loginInfo = this.sessionStorageService.get<LoginInfo>( const loginInfo = this.sessionStorageService.get<LoginInfo>(
KEY_LOGIN_INFO KEY_LOGIN_INFO
); );
const environmentsInfo = this.sessionStorageService.get<
EnvironmentsInfo
>(KEY_ENVIRONMENTS_INFO);
return { return {
deviceType: loginInfo.deviceType deviceType: environmentsInfo.deviceType
} as AuthRequest; } as AuthRequest;
}), }),
exhaustMap(req => exhaustMap(req =>

View File

@ -0,0 +1,7 @@
import { DeviceType } from '@ucap-webmessenger/core';
export const KEY_ENVIRONMENTS_INFO = 'ucap::ENVIRONMENTS_INFO';
export interface EnvironmentsInfo {
deviceType?: DeviceType;
}

View File

@ -1 +1,2 @@
export * from './environment.type';
export * from './login-info.type'; export * from './login-info.type';

View File

@ -1,4 +1,4 @@
import { DeviceType, LocaleCode } from '@ucap-webmessenger/core'; import { LocaleCode } from '@ucap-webmessenger/core';
export const KEY_LOGIN_INFO = 'ucap::LOGIN_INFO'; export const KEY_LOGIN_INFO = 'ucap::LOGIN_INFO';
@ -6,7 +6,7 @@ export interface LoginInfo {
loginId?: string; loginId?: string;
loginPw?: string; loginPw?: string;
companyCode?: string; companyCode?: string;
deviceType?: DeviceType; companyGroupType?: string;
localeCode?: LocaleCode; localeCode?: LocaleCode;
encData?: string; encData?: string;
} }

View File

@ -10,6 +10,7 @@ import {
ProtocolStream ProtocolStream
} from '@ucap-webmessenger/protocol'; } from '@ucap-webmessenger/protocol';
import { UserInfo } from '../types/userInfo'; import { UserInfo } from '../types/userInfo';
import { EmployeeType } from '@ucap-webmessenger/protocol-room';
export interface BuddyInfo { export interface BuddyInfo {
// 사용자SEQ // 사용자SEQ
@ -82,7 +83,7 @@ export const decodeBuddyDetailData: ProtocolDecoder<BuddyDetailData> = (
const info = buddyinfo.split(BodyStringDivider); const info = buddyinfo.split(BodyStringDivider);
let i = 0; let i = 0;
buddyInfos.push({ buddyInfos.push({
seq: info[i], seq: Number(info[i]),
name: info[i++], name: info[i++],
profileImageFile: info[i++], profileImageFile: info[i++],
grade: info[i++], grade: info[i++],
@ -109,7 +110,7 @@ export const decodeBuddyDetailData: ProtocolDecoder<BuddyDetailData> = (
deptNameCn: info[i++], deptNameCn: info[i++],
isPrivacyAgree: info[i++] === 'Y' ? true : false, isPrivacyAgree: info[i++] === 'Y' ? true : false,
isValidLogin: info[i++] === 'Y' ? true : false, isValidLogin: info[i++] === 'Y' ? true : false,
employeeType: info[i++], employeeType: info[i++] as EmployeeType,
nickName: info[i++] nickName: info[i++]
}); });
}); });

View File

@ -1,8 +1,15 @@
<mat-accordion> <mat-accordion>
<mat-expansion-panel *ngFor="let group of groupList"> <mat-expansion-panel *ngFor="let groupBuddy of groupBuddyList">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> {{ group.name }} </mat-panel-title> <mat-panel-title> {{ groupBuddy.group.name }} </mat-panel-title>
<mat-panel-description> </mat-panel-description> <mat-panel-description> </mat-panel-description>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div
*ngFor="let buddy of groupBuddy.buddyList"
(click)="onClickBuddy(buddy)"
>
{{ buddy.name }}
</div>
</mat-expansion-panel> </mat-expansion-panel>
</mat-accordion> </mat-accordion>

View File

@ -1,6 +1,6 @@
import { Component, OnInit, Input } from '@angular/core'; import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { GroupDetailData } from '@ucap-webmessenger/protocol-sync'; import { GroupDetailData, UserInfo } from '@ucap-webmessenger/protocol-sync';
@Component({ @Component({
selector: 'ucap-group-expansion-panel', selector: 'ucap-group-expansion-panel',
@ -9,9 +9,16 @@ import { GroupDetailData } from '@ucap-webmessenger/protocol-sync';
}) })
export class ExpansionPanelComponent implements OnInit { export class ExpansionPanelComponent implements OnInit {
@Input() @Input()
groupList: GroupDetailData[]; groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] }[];
@Output()
selectBuddy = new EventEmitter<UserInfo>();
constructor() {} constructor() {}
ngOnInit() {} ngOnInit() {}
onClickBuddy(buddy: UserInfo) {
this.selectBuddy.emit(buddy);
}
} }