diff --git a/projects/ucap-webmessenger-app/src/app/pages/account/components/login.page.component.html b/projects/ucap-webmessenger-app/src/app/pages/account/components/login.page.component.html index d661507a..ba2d664c 100644 --- a/projects/ucap-webmessenger-app/src/app/pages/account/components/login.page.component.html +++ b/projects/ucap-webmessenger-app/src/app/pages/account/components/login.page.component.html @@ -2,6 +2,8 @@
diff --git a/projects/ucap-webmessenger-app/src/app/pages/account/components/login.page.component.ts b/projects/ucap-webmessenger-app/src/app/pages/account/components/login.page.component.ts index 832e8340..bad075ab 100644 --- a/projects/ucap-webmessenger-app/src/app/pages/account/components/login.page.component.ts +++ b/projects/ucap-webmessenger-app/src/app/pages/account/components/login.page.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, OnDestroy } from '@angular/core'; import { Store, select } from '@ngrx/store'; @@ -7,20 +7,45 @@ import { Company } from '@ucap-webmessenger/api-external'; import * as AppStore from '@app/store'; import * as AuthenticationStore from '@app/store/account/authentication'; import * as CompanyStore from '@app/store/setting/company'; -import { Observable } from 'rxjs'; +import { Observable, Subscription } from 'rxjs'; import { Router } from '@angular/router'; +import { tap, map } from 'rxjs/operators'; +import { + DialogService, + AlertDialogComponent, + AlertDialogData, + AlertDialogResult +} from '@ucap-webmessenger/ui'; +import { StringUtil } from '@ucap-webmessenger/core'; @Component({ selector: 'app-page-account-login', templateUrl: './login.page.component.html', styleUrls: ['./login.page.component.scss'] }) -export class LoginPageComponent implements OnInit { +export class LoginPageComponent implements OnInit, OnDestroy { companyList$: Observable; - constructor(private store: Store, private router: Router) {} + loginFailureCount: Subscription; + + defatulLoginBtnText: string; + loginBtnText: string; + loginBtnEnable: boolean; + + timeChecker: any; + defatulWaitingTime: number; + waitingTime: number; + + constructor( + private store: Store, + private router: Router, + private dialogService: DialogService + ) {} ngOnInit(): void { + this.defatulLoginBtnText = 'LOGIN'; + this.defatulWaitingTime = 5 * 60; // sec + this.store.dispatch( CompanyStore.companyList({ companyGroupCode: 'LG' @@ -30,6 +55,80 @@ export class LoginPageComponent implements OnInit { this.companyList$ = this.store.pipe( select(AppStore.SettingSelector.CompanySelector.companyList) ); + + this.loginFailureCount = this.store + .pipe( + select(AppStore.AccountSelector.AuthenticationSelector.loginFailCount), + map(count => { + if (count > 0) { + if (count < 5) { + this.dialogService.open< + AlertDialogComponent, + AlertDialogData, + AlertDialogResult + >(AlertDialogComponent, { + width: '360px', + data: { + title: 'Alert', + html: `아이디 또는 패스워드가
일치하지 않습니다.` + } + }); + } + + if (count === 5) { + this.dialogService.open< + AlertDialogComponent, + AlertDialogData, + AlertDialogResult + >(AlertDialogComponent, { + width: '360px', + data: { + title: 'Alert', + html: `비밀번호 오류 횟수 초과입니다.
비밀번호를 확인하신 후
잠시 후 다시 시작해 주세요.` + } + }); + + this.timeChecker = setInterval(() => this.getCheckTime(), 1000); + } + return; + } else { + if (!!this.timeChecker) { + clearInterval(this.timeChecker); + } + this.waitingTime = this.defatulWaitingTime; + this.loginBtnText = this.defatulLoginBtnText; + this.loginBtnEnable = true; + } + }) + ) + .subscribe(); + } + + ngOnDestroy(): void { + if (!!this.loginFailureCount) { + this.loginFailureCount.unsubscribe(); + } + } + + getCheckTime() { + if (this.waitingTime <= 0) { + // reset. + if (!!this.timeChecker) { + clearInterval(this.timeChecker); + } + this.waitingTime = this.defatulWaitingTime; + this.loginBtnText = this.defatulLoginBtnText; + this.loginBtnEnable = true; + } else { + // wait. + this.waitingTime = this.waitingTime - 1; + + this.loginBtnText = `${StringUtil.zeroFill( + Math.floor(this.waitingTime / 60), + 2 + )}:${StringUtil.zeroFill(this.waitingTime % 60, 2)}`; + this.loginBtnEnable = false; + } } onLogin(value: { diff --git a/projects/ucap-webmessenger-app/src/app/store/account/authentication/actions.ts b/projects/ucap-webmessenger-app/src/app/store/account/authentication/actions.ts index 4ad59d61..b7b9849c 100644 --- a/projects/ucap-webmessenger-app/src/app/store/account/authentication/actions.ts +++ b/projects/ucap-webmessenger-app/src/app/store/account/authentication/actions.ts @@ -6,7 +6,7 @@ import { LoginResponse } from '@ucap-webmessenger/protocol-authentication'; import { LoginInfo } from '@app/types'; import { UserPasswordSetRequest, - UserPasswordSetResponse, + UserPasswordSetResponse } from '@ucap-webmessenger/protocol-service'; export const webLogin = createAction( @@ -43,6 +43,15 @@ export const loginFailure = createAction( props<{ error: any }>() ); +export const increaseLoginFailCount = createAction( + '[Account::Authentication] Increase Login Failure Count', + props() +); +export const initialLoginFailCount = createAction( + '[Account::Authentication] Initialize Login Failure Count', + props() +); + export const loginRedirect = createAction( '[Account::Authentication] Login Redirect' ); diff --git a/projects/ucap-webmessenger-app/src/app/store/account/authentication/effects.ts b/projects/ucap-webmessenger-app/src/app/store/account/authentication/effects.ts index d33291f4..331398e1 100644 --- a/projects/ucap-webmessenger-app/src/app/store/account/authentication/effects.ts +++ b/projects/ucap-webmessenger-app/src/app/store/account/authentication/effects.ts @@ -9,14 +9,14 @@ import { Actions, ofType, createEffect } from '@ngrx/effects'; import { PiService, Login2Response, - UserTermsActionResponse, + UserTermsActionResponse } from '@ucap-webmessenger/pi'; import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native'; import { DialogService, ConfirmDialogComponent, ConfirmDialogData, - ConfirmDialogResult, + ConfirmDialogResult } from '@ucap-webmessenger/ui'; import { @@ -35,12 +35,14 @@ import { changePassword, changePasswordFailure, changePasswordSuccess, + increaseLoginFailCount, + initialLoginFailCount } from './actions'; import { LoginInfo, KEY_LOGIN_INFO, EnvironmentsInfo, - KEY_ENVIRONMENTS_INFO, + KEY_ENVIRONMENTS_INFO } from '@app/types'; import { AppAuthenticationService } from '@app/services/authentication.service'; import { NGXLogger } from 'ngx-logger'; @@ -48,7 +50,7 @@ import { Store } from '@ngrx/store'; import { SessionStorageService } from '@ucap-webmessenger/web-storage'; import { ServiceProtocolService, - UserPasswordSetResponse, + UserPasswordSetResponse } from '@ucap-webmessenger/protocol-service'; @Injectable() @@ -62,17 +64,19 @@ export class Effects { .login2({ loginId: params.loginInfo.loginId, loginPw: params.loginInfo.loginPw, - companyCode: params.loginInfo.companyCode, + companyCode: params.loginInfo.companyCode }) .pipe( map((res: Login2Response) => { if ('success' !== res.status.toLowerCase()) { + this.store.dispatch(increaseLoginFailCount({})); return webLoginFailure({ error: 'Failed' }); } else { + this.store.dispatch(initialLoginFailCount({})); return webLoginSuccess({ loginInfo: params.loginInfo, rememberMe: params.rememberMe, - login2Response: res, + login2Response: res }); } }), @@ -147,8 +151,8 @@ export class Effects { width: '220px', data: { title: 'Logout', - message: 'Logout ?', - }, + message: 'Logout ?' + } }); return result.choice; @@ -177,7 +181,7 @@ export class Effects { token: loginRes.tokenString, deviceType: environmentsInfo.deviceType, localeCode: loginInfo.localeCode, - textOnly: 'true', + textOnly: 'true' }); const result = await this.dialogService.open< @@ -189,9 +193,9 @@ export class Effects { height: '500px', disableClose: true, data: { - title: '개인정보 동의', + title: '개인정보 동의' // html: `