Skip to content

Commit

Permalink
Added the busy feature [#539]
Browse files Browse the repository at this point in the history
 * Added a busy overlay to the root component.
  • Loading branch information
mcpierce authored and BRUCELLA2 committed Nov 22, 2020
1 parent e418431 commit f018b8f
Show file tree
Hide file tree
Showing 11 changed files with 254 additions and 3 deletions.
8 changes: 8 additions & 0 deletions comixed-web/src/app/app.component.html
@@ -1,2 +1,10 @@
<div *ngIf="busy"
class="cx-busy-overlay cx-width-100 cx-height-100">
<div class="cx-centered">
<mat-progress-spinner diameter="100"
mode="indeterminate"
color="accent"></mat-progress-spinner>
</div>
</div>
<cx-navigation-bar [user]="user"></cx-navigation-bar>
<router-outlet></router-outlet>
9 changes: 9 additions & 0 deletions comixed-web/src/app/app.component.scss
@@ -0,0 +1,9 @@
.cx-busy-overlay {
height: 100vh;
width: 100%;
background-color: rgba(0, 0, 0, 0.286);
z-index: 10;
top: 0;
left: 0;
position: fixed;
}
14 changes: 11 additions & 3 deletions comixed-web/src/app/app.component.spec.ts
Expand Up @@ -23,11 +23,19 @@ import { LoggerModule } from '@angular-ru/logger';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
import {
initialState as initialUserState,
USER_FEATURE_KEY
USER_FEATURE_KEY,
} from '@app/user/reducers/user.reducer';
import {
BUSY_FEATURE_KEY,
initialState as initialBusyState,
} from '@app/core/reducers/busy.reducer';

describe('AppComponent', () => {
const initialState = { [USER_FEATURE_KEY]: initialUserState };
const initialState = {
[USER_FEATURE_KEY]: initialUserState,
[BUSY_FEATURE_KEY]: initialBusyState,
};

let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let store: MockStore<any>;
Expand All @@ -36,7 +44,7 @@ describe('AppComponent', () => {
TestBed.configureTestingModule({
imports: [RouterTestingModule, LoggerModule.forRoot()],
declarations: [AppComponent],
providers: [provideMockStore({ initialState })]
providers: [provideMockStore({ initialState })],
}).compileComponents();

fixture = TestBed.createComponent(AppComponent);
Expand Down
5 changes: 5 additions & 0 deletions comixed-web/src/app/app.component.ts
Expand Up @@ -22,6 +22,7 @@ import { LoggerService } from '@angular-ru/logger';
import { selectUser } from '@app/user/selectors/user.selectors';
import { User } from '@app/user/models/user';
import { loadCurrentUser } from '@app/user/actions/user.actions';
import { selectBusyState } from '@app/core/selectors/busy.selectors';

@Component({
selector: 'cx-root',
Expand All @@ -30,13 +31,17 @@ import { loadCurrentUser } from '@app/user/actions/user.actions';
})
export class AppComponent implements OnInit {
user: User = null;
busy = false;

constructor(private logger: LoggerService, private store: Store<any>) {
this.logger.trace('Subscribing to user changes');
this.store.select(selectUser).subscribe(user => {
this.logger.debug('User updated:', user);
this.user = user;
});
this.store
.select(selectBusyState)
.subscribe(state => (this.busy = state.enabled));
}

ngOnInit(): void {
Expand Down
24 changes: 24 additions & 0 deletions comixed-web/src/app/core/actions/busy.actions.ts
@@ -0,0 +1,24 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { createAction, props } from '@ngrx/store';

export const setBusyState = createAction(
'[Busy] Set the busy state',
props<{ enabled: boolean }>()
);
8 changes: 8 additions & 0 deletions comixed-web/src/app/core/core.module.ts
Expand Up @@ -23,11 +23,19 @@ import { ConfirmationComponent } from './components/confirmation/confirmation.co
import { MatDialogModule } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { MatFormFieldModule } from '@angular/material/form-field';
import { StoreModule } from '@ngrx/store';
import {
BUSY_FEATURE_KEY,
reducer as busyReducer
} from '@app/core/reducers/busy.reducer';
import { EffectsModule } from '@ngrx/effects';

@NgModule({
declarations: [ConfirmationComponent],
imports: [
CommonModule,
StoreModule.forFeature(BUSY_FEATURE_KEY, busyReducer),
EffectsModule.forFeature([]),
MatSnackBarModule,
MatDialogModule,
MatIconModule,
Expand Down
29 changes: 29 additions & 0 deletions comixed-web/src/app/core/index.ts
Expand Up @@ -16,8 +16,37 @@
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { Params } from '@angular/router';
import { routerReducer, RouterReducerState } from '@ngrx/router-store';
import { ActionReducerMap } from '@ngrx/store';
import {
BUSY_FEATURE_KEY,
BusyState,
reducer as busyReducer
} from '@app/core/reducers/busy.reducer';

export { TokenService } from '@app/core/services/token.service';
export { AlertService } from '@app/core/services/alert.service';
export { ConfirmationService } from '@app/core/services/confirmation.service';

export { ApiResponse } from '@app/core/models/api-response';
export * from '@app/core/core.functions';
export { PageClickEvent } from '@app/core/models/event/page-click-event';

interface RouterStateUrl {
url: string;
params: Params;
queryParams: Params;
}

export interface CoreModuleState {
router: RouterReducerState<RouterStateUrl>;
[BUSY_FEATURE_KEY]: BusyState;
}

export type ModuleState = CoreModuleState;

export const reducers: ActionReducerMap<CoreModuleState> = {
router: routerReducer,
[BUSY_FEATURE_KEY]: busyReducer
};
64 changes: 64 additions & 0 deletions comixed-web/src/app/core/reducers/busy.reducer.spec.ts
@@ -0,0 +1,64 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { BusyState, initialState, reducer } from './busy.reducer';
import { setBusyState } from '@app/core/actions/busy.actions';

describe('Busy Reducer', () => {
let state: BusyState;

beforeEach(() => {
state = { ...initialState };
});

describe('the initial state', () => {
beforeEach(() => {
state = reducer({ ...state }, {} as any);
});

it('clears the enabled flag', () => {
expect(state.enabled).toBeFalsy();
});
});

describe('enabling busy mode', () => {
beforeEach(() => {
state = reducer(
{ ...state, enabled: false },
setBusyState({ enabled: true })
);
});

it('sets the enabled flag', () => {
expect(state.enabled).toBeTruthy();
});
});

describe('disabling busy mode', () => {
beforeEach(() => {
state = reducer(
{ ...state, enabled: true },
setBusyState({ enabled: false })
);
});

it('clears the enabled flag', () => {
expect(state.enabled).toBeFalsy();
});
});
});
36 changes: 36 additions & 0 deletions comixed-web/src/app/core/reducers/busy.reducer.ts
@@ -0,0 +1,36 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { createReducer, on } from '@ngrx/store';
import { setBusyState } from '../actions/busy.actions';

export const BUSY_FEATURE_KEY = 'busy_state';

export interface BusyState {
enabled: boolean;
}

export const initialState: BusyState = {
enabled: false
};

export const reducer = createReducer(
initialState,

on(setBusyState, (state, action) => ({ ...state, enabled: action.enabled }))
);
36 changes: 36 additions & 0 deletions comixed-web/src/app/core/selectors/busy.selectors.spec.ts
@@ -0,0 +1,36 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { BUSY_FEATURE_KEY, BusyState } from '../reducers/busy.reducer';
import { selectBusyState } from './busy.selectors';

describe('Busy Selectors', () => {
let state: BusyState;

beforeEach(() => {
state = { enabled: Math.random() > 0.5 };
});

it('should select the feature state', () => {
expect(
selectBusyState({
[BUSY_FEATURE_KEY]: state
})
).toEqual(state);
});
});
24 changes: 24 additions & 0 deletions comixed-web/src/app/core/selectors/busy.selectors.ts
@@ -0,0 +1,24 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { createFeatureSelector } from '@ngrx/store';
import { BUSY_FEATURE_KEY, BusyState } from '../reducers/busy.reducer';

export const selectBusyState = createFeatureSelector<BusyState>(
BUSY_FEATURE_KEY
);

0 comments on commit f018b8f

Please sign in to comment.