Skip to content
This repository has been archived by the owner on Jan 24, 2023. It is now read-only.

Commit

Permalink
Improve the logout experience (#4439)
Browse files Browse the repository at this point in the history
* Add support for including breaking changes in the changelog

* Improve the logout experience

* Fix unit tests
  • Loading branch information
nwmac committed Jul 10, 2020
1 parent 05b2b1a commit 53f6ca5
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { Store } from '@ngrx/store';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { createBasicStoreModule } from '@stratosui/store/testing';

import { CoreTestingModule } from '../../../test-framework/core-test.modules';
import { SharedModule } from '../../shared/shared.module';
import { CoreModule } from '../core.module';
import { RouteModule } from './../../app.routing';
import { LogOutDialogComponent } from './log-out-dialog.component';

describe('LogOutDialogComponent', () => {
let component: LogOutDialogComponent;
let fixture: ComponentFixture<LogOutDialogComponent>;
let element: HTMLElement;
let store: any;
let router: any;

class MatDialogRefMock {
}
Expand All @@ -30,6 +32,8 @@ describe('LogOutDialogComponent', () => {
],
imports: [
CoreModule,
RouterTestingModule,
RouteModule,
SharedModule,
MatDialogModule,
NoopAnimationsModule,
Expand All @@ -42,7 +46,7 @@ describe('LogOutDialogComponent', () => {

beforeEach(() => {
fixture = TestBed.createComponent(LogOutDialogComponent);
store = TestBed.get(Store);
router = TestBed.get(Router);
component = fixture.componentInstance;
fixture.detectChanges();
element = fixture.nativeElement;
Expand All @@ -52,8 +56,8 @@ describe('LogOutDialogComponent', () => {
expect(component).toBeTruthy();
});

it('should dispatch logout action after countdown', fakeAsync(() => {
const spy = spyOn(store, 'dispatch');
it('should naivgate after countdown', fakeAsync(() => {
const spy = spyOn(router, 'navigate');

component.data = {
expiryDate: Date.now() + 1000,
Expand All @@ -65,6 +69,7 @@ describe('LogOutDialogComponent', () => {
expect(spy).not.toHaveBeenCalled();
tick(1500);
expect(spy).toHaveBeenCalled();
expect(spy).toHaveBeenCalledWith(['/login/logout']);
}));

afterEach(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { Component, Inject, OnDestroy, OnInit, Optional } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { Router } from '@angular/router';
import { interval, Subscription } from 'rxjs';
import { tap } from 'rxjs/operators';

import { Logout } from '../../../../store/src/actions/auth.actions';
import { GeneralEntityAppState } from '../../../../store/src/app-state';

@Component({
selector: 'app-log-out-dialog',
templateUrl: './log-out-dialog.component.html',
Expand All @@ -16,7 +13,8 @@ export class LogOutDialogComponent implements OnInit, OnDestroy {
constructor(
public dialogRef: MatDialogRef<LogOutDialogComponent>,
@Optional() @Inject(MAT_DIALOG_DATA) public data: any,
private store: Store<GeneralEntityAppState>) { }
private router: Router
) { }

private autoLogout: Subscription;
private countDown: number;
Expand All @@ -33,7 +31,7 @@ export class LogOutDialogComponent implements OnInit, OnDestroy {
this.countDown = this.calcCountdown();
if (this.countDown <= 0) {
this.autoLogout.unsubscribe();
this.store.dispatch(new Logout());
this.router.navigate(['/login/logout']);
} else {
this.percentage = ((this.countdownTotal - this.countDown) / this.countdownTotal) * 100;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CoreModule } from '../../core/core.module';
import { SharedModule } from '../../shared/shared.module';
import { LoginPageComponent } from './login-page/login-page.component';
import { LoginRoutingModule } from './login.routing';
import { LogoutPageComponent } from './logout-page/logout-page.component';


@NgModule({
Expand All @@ -13,7 +14,8 @@ import { LoginRoutingModule } from './login.routing';
LoginRoutingModule
],
declarations: [
LoginPageComponent
LoginPageComponent,
LogoutPageComponent
]
})
export class LoginModule { }
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { LoginPageComponent } from './login-page/login-page.component';
import { LogoutPageComponent } from './logout-page/logout-page.component';

const loginRoutes: Routes = [
{ path: '', component: LoginPageComponent, }
{ path: '', component: LoginPageComponent, },
{ path: 'logout', component: LogoutPageComponent, }
];

@NgModule({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<app-intro-screen id="app-login-page" class="logout">
<mat-card class="logout__card">
<app-stratos-title></app-stratos-title>
<div class="logout__body" *ngIf="error$ | async; else loading">
<div class="logout__msg">An error occurred logging out</div>
<button (click)="reload()" color="primary" mat-raised-button mat-button>Reload</button>
</div>
<ng-template #loading>
<div class="logout__body">
<div class="logout__msg">Logging out</div>
<div id="logout__loading" class="logout__loading">
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>
</div>
</ng-template>
</mat-card>
</app-intro-screen>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.logout {
&__card {
padding: 0;
width: 300px;
}
&__body {
padding: 24px;
text-align: center;
}
&__msg {
font-size: 18px;
padding-bottom: 20px;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { CommonModule } from '@angular/common';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CoreModule } from '@angular/flex-layout';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { RouterTestingModule } from '@angular/router/testing';
import { StoreModule } from '@ngrx/store';

import { appReducers } from '../../../../../store/src/reducers.module';
import { SharedModule } from '../../../public-api';
import { LogoutPageComponent } from './logout-page.component';

describe('LogoutPageComponent', () => {
let component: LogoutPageComponent;
let fixture: ComponentFixture<LogoutPageComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ LogoutPageComponent ],
imports: [
CommonModule,
CoreModule,
SharedModule,
RouterTestingModule,
NoopAnimationsModule,
StoreModule.forRoot(
appReducers
)
]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(LogoutPageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { Logout } from '../../../../../store/src/actions/auth.actions';
import { AppState } from '../../../../../store/src/app-state';

@Component({
selector: 'app-logout-page',
templateUrl: './logout-page.component.html',
styleUrls: ['./logout-page.component.scss']
})
export class LogoutPageComponent implements OnInit {

public error$: Observable<boolean>;

constructor(private store: Store<AppState>) {
this.error$ = this.store.select(s => s.auth).pipe(
map(auth => auth.error)
);
}

ngOnInit() {
// Dispatch the logout action after 1 second - give the logging out screen time to show
setTimeout(() => {
this.store.dispatch(new Logout());
}, 1000)
}

reload() {
window.location.assign(window.location.origin);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import * as moment from 'moment';
import { Observable } from 'rxjs';
import { map, startWith } from 'rxjs/operators';

import { Logout } from '../../../../../store/src/actions/auth.actions';
import { ToggleSideNav } from '../../../../../store/src/actions/dashboard-actions';
import { AddRecentlyVisitedEntityAction } from '../../../../../store/src/actions/recently-visited.actions';
import { AppState } from '../../../../../store/src/app-state';
Expand Down Expand Up @@ -142,7 +141,7 @@ export class PageHeaderComponent implements OnDestroy, AfterViewInit {
}

logout() {
this.store.dispatch(new Logout());
this.router.navigate(['/login/logout']);
}

public toggleSidenav() {
Expand Down
6 changes: 6 additions & 0 deletions src/frontend/packages/store/src/reducers/auth.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
LOGIN_FAILED,
LOGIN_SUCCESS,
LoginFailed,
LOGOUT_FAILED,
RESET_AUTH,
SESSION_INVALID,
SESSION_VERIFIED,
Expand All @@ -12,6 +13,7 @@ import { RouterActions, RouterNav } from '../actions/router.actions';
import { GET_SYSTEM_INFO_SUCCESS } from '../actions/system.actions';
import { AuthOnlyAppState } from '../app-state';
import { SessionData } from '../types/auth.types';
import { LogoutFailed } from './../actions/auth.actions';
import { RouterRedirect } from './routing.reducer';

export interface AuthUser {
Expand Down Expand Up @@ -51,6 +53,10 @@ export function authReducer(state: AuthState = defaultState, action): AuthState
case LOGIN_FAILED:
const loginFailed = action as LoginFailed;
return { ...state, error: true, errorResponse: loginFailed.error, loggingIn: false, loggedIn: false };
case LOGOUT_FAILED:
const logoutFailed = action as LogoutFailed;
console.error(logoutFailed.error);
return { ...state, loggingIn: false, loggedIn: true, error: true, errorResponse: logoutFailed.error };
case VERIFY_SESSION:
return { ...state, error: false, errorResponse: undefined, verifying: true };
case SESSION_VERIFIED:
Expand Down

0 comments on commit 53f6ca5

Please sign in to comment.