Skip to content

Commit

Permalink
SHIBUI-1031 Added state and service for admin users
Browse files Browse the repository at this point in the history
  • Loading branch information
rmathis committed Dec 11, 2018
1 parent 1440ee5 commit 289e4c1
Show file tree
Hide file tree
Showing 8 changed files with 467 additions and 0 deletions.
141 changes: 141 additions & 0 deletions ui/src/app/user/admin/action/collection.action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { Action } from '@ngrx/store';
import { Update } from '@ngrx/entity';
import { Admin } from '../model/admin';

export enum AdminCollectionActionTypes {
SELECT_ADMIN_REQUEST = '[Admin Collection] Select Admin Request',
SELECT_ADMIN_SUCCESS = '[Admin Collection] Select Admin Success',
SELECT_ADMIN_FAIL = '[Admin Collection] Select Admin Fail',

UPDATE_ADMIN_REQUEST = '[Admin Collection] Update Admin Request',
UPDATE_ADMIN_SUCCESS = '[Admin Collection] Update Admin Success',
UPDATE_ADMIN_FAIL = '[Admin Collection] Update Admin Fail',

LOAD_ADMIN_REQUEST = '[Admin Collection] Load Admin Request',
LOAD_ADMIN_SUCCESS = '[Admin Collection] Load Admin Success',
LOAD_ADMIN_ERROR = '[Admin Collection] Load Admin Error',

ADD_ADMIN_REQUEST = '[Admin Collection] Add Admin Request',
ADD_ADMIN_SUCCESS = '[Admin Collection] Add Admin Success',
ADD_ADMIN_FAIL = '[Admin Collection] Add Admin Fail',

REMOVE_ADMIN_REQUEST = '[Admin Collection] Remove Admin Request',
REMOVE_ADMIN_SUCCESS = '[Admin Collection] Remove Admin Success',
REMOVE_ADMIN_FAIL = '[Admin Collection] Remove Admin Fail',

CLEAR_ADMINS = '[Admin Collection] Clear Admins'

}

export class SelectAdmin implements Action {
readonly type = AdminCollectionActionTypes.SELECT_ADMIN_REQUEST;

constructor(public payload: string) { }
}

export class SelectAdminSuccess implements Action {
readonly type = AdminCollectionActionTypes.SELECT_ADMIN_SUCCESS;

constructor(public payload: Admin) { }
}

export class SelectAdminFail implements Action {
readonly type = AdminCollectionActionTypes.SELECT_ADMIN_FAIL;

constructor(public payload: Error) { }
}

export class LoadAdminRequest implements Action {
readonly type = AdminCollectionActionTypes.LOAD_ADMIN_REQUEST;

constructor() { }
}

export class LoadAdminSuccess implements Action {
readonly type = AdminCollectionActionTypes.LOAD_ADMIN_SUCCESS;

constructor(public payload: Admin[]) { }
}

export class LoadAdminError implements Action {
readonly type = AdminCollectionActionTypes.LOAD_ADMIN_ERROR;

constructor(public payload: any) { }
}

export class UpdateAdminRequest implements Action {
readonly type = AdminCollectionActionTypes.UPDATE_ADMIN_REQUEST;

constructor(public payload: Admin) { }
}

export class UpdateAdminSuccess implements Action {
readonly type = AdminCollectionActionTypes.UPDATE_ADMIN_SUCCESS;

constructor(public payload: Update<Admin>) { }
}

export class UpdateAdminFail implements Action {
readonly type = AdminCollectionActionTypes.UPDATE_ADMIN_FAIL;

constructor(public payload: Admin) { }
}

export class AddAdminRequest implements Action {
readonly type = AdminCollectionActionTypes.ADD_ADMIN_REQUEST;

constructor(public payload: Admin) { }
}

export class AddAdminSuccess implements Action {
readonly type = AdminCollectionActionTypes.ADD_ADMIN_SUCCESS;

constructor(public payload: Admin) { }
}

export class AddAdminFail implements Action {
readonly type = AdminCollectionActionTypes.ADD_ADMIN_FAIL;

constructor(public payload: any) { }
}

export class RemoveAdminRequest implements Action {
readonly type = AdminCollectionActionTypes.REMOVE_ADMIN_REQUEST;

constructor(public payload: string) { }
}

export class RemoveAdminSuccess implements Action {
readonly type = AdminCollectionActionTypes.REMOVE_ADMIN_SUCCESS;

constructor(public payload: string) { }
}

export class RemoveAdminFail implements Action {
readonly type = AdminCollectionActionTypes.REMOVE_ADMIN_FAIL;

constructor(public error: Error) { }
}

export class ClearAdmins implements Action {
readonly type = AdminCollectionActionTypes.CLEAR_ADMINS;
}


export type AdminCollectionActionsUnion =
| LoadAdminRequest
| LoadAdminSuccess
| LoadAdminError
| AddAdminRequest
| AddAdminSuccess
| AddAdminFail
| RemoveAdminRequest
| RemoveAdminSuccess
| RemoveAdminFail
| SelectAdmin
| SelectAdminSuccess
| SelectAdminFail
| UpdateAdminRequest
| UpdateAdminSuccess
| UpdateAdminFail
| ClearAdmins;
63 changes: 63 additions & 0 deletions ui/src/app/user/admin/effect/collection.effect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Injectable } from '@angular/core';
import { Effect, Actions, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { switchMap, map } from 'rxjs/operators';

import * as fromAdmin from '../reducer';
import {
LoadAdminRequest,
AdminCollectionActionTypes,
LoadAdminSuccess,
UpdateAdminRequest,
UpdateAdminSuccess,
RemoveAdminRequest,
RemoveAdminSuccess
} from '../action/collection.action';
import { AdminService } from '../service/admin.service';


/* istanbul ignore next */
@Injectable()
export class AdminCollectionEffects {

@Effect()
loadAdminRequest$ = this.actions$.pipe(
ofType<LoadAdminRequest>(AdminCollectionActionTypes.LOAD_ADMIN_REQUEST),
switchMap(() => this.adminService.query().pipe(
map(users => new LoadAdminSuccess(users))
))
);

@Effect()
updateAdminRequest$ = this.actions$.pipe(
ofType<UpdateAdminRequest>(AdminCollectionActionTypes.UPDATE_ADMIN_REQUEST),
map(action => action.payload),
switchMap(changes => this.adminService.update(changes).pipe(
map(user => new UpdateAdminSuccess({
id: changes.resourceId,
changes
}))
))
);

@Effect()
removeAdminRequest$ = this.actions$.pipe(
ofType<RemoveAdminRequest>(AdminCollectionActionTypes.REMOVE_ADMIN_REQUEST),
map(action => action.payload),
switchMap(id => this.adminService.remove(id).pipe(
map(user => new RemoveAdminSuccess(id))
))
);

@Effect()
removeAdminSuccessReload$ = this.actions$.pipe(
ofType<RemoveAdminSuccess>(AdminCollectionActionTypes.REMOVE_ADMIN_SUCCESS),
map(action => new LoadAdminRequest())
);

constructor(
private actions$: Actions,
private adminService: AdminService,
private store: Store<fromAdmin.State>
) { }
}
9 changes: 9 additions & 0 deletions ui/src/app/user/admin/model/admin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { User } from '../../../core/model/user';

export interface Admin extends User {
createdDate?: string;
updatedDate?: string;
resourceId: string;

email: string;
}
83 changes: 83 additions & 0 deletions ui/src/app/user/admin/reducer/collection.reducer.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { reducer, initialState as snapshot } from './collection.reducer';
import * as fromAdmin from './collection.reducer';
import {
AdminCollectionActionTypes,
LoadAdminSuccess,
UpdateAdminSuccess,
RemoveAdminSuccess
} from '../action/collection.action';
import { Admin } from '../model/admin';

let users = <Admin[]>[
{
resourceId: 'abc',
role: 'SUPER_ADMIN',
email: 'foo@bar.com',
name: {
first: 'Jane',
last: 'Doe'
}
},
{
resourceId: 'def',
role: 'DELEGATED_ADMIN',
email: 'bar@baz.com',
name: {
first: 'John',
last: 'Doe'
}
}
];

describe('Admin Collection Reducer', () => {
describe('undefined action', () => {
it('should return the default state', () => {
const result = reducer(snapshot, {} as any);

expect(result).toEqual(snapshot);
});
});

describe(`${AdminCollectionActionTypes.LOAD_ADMIN_SUCCESS}`, () => {
it('should add the loaded filters to the collection', () => {
spyOn(fromAdmin.adapter, 'addAll').and.callThrough();
const action = new LoadAdminSuccess(users);
const result = reducer(snapshot, action);
expect(fromAdmin.adapter.addAll).toHaveBeenCalled();
});
});

describe(`${AdminCollectionActionTypes.UPDATE_ADMIN_SUCCESS}`, () => {
it('should update the filter in the collection', () => {
spyOn(fromAdmin.adapter, 'updateOne').and.callThrough();
const update = {
id: 'abc',
changes: { role: 'DELEGATED_ADMIN' }
};
const action = new UpdateAdminSuccess(update);
const result = reducer(snapshot, action);
expect(fromAdmin.adapter.updateOne).toHaveBeenCalled();
});
});

describe(`${AdminCollectionActionTypes.REMOVE_ADMIN_SUCCESS}`, () => {
it('should set saving to false', () => {
const action = new RemoveAdminSuccess('abc');
expect(reducer(snapshot, action).saving).toBe(false);
});
});

describe('selector methods', () => {
describe('getSelectedAdminId', () => {
it('should return the state selectedAdminId', () => {
expect(fromAdmin.getSelectedAdminId(snapshot)).toBe(snapshot.selectedAdminId);
});
});

describe('getError', () => {
it('should return the state saving', () => {
expect(fromAdmin.getIsSaving(snapshot)).toBe(snapshot.saving);
});
});
});
});
54 changes: 54 additions & 0 deletions ui/src/app/user/admin/reducer/collection.reducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
import { Admin } from '../model/admin';
import { AdminCollectionActionsUnion, AdminCollectionActionTypes } from '../action/collection.action';

export interface CollectionState extends EntityState<Admin> {
selectedAdminId: string | null;
saving: boolean;
}

export const adapter: EntityAdapter<Admin> = createEntityAdapter<Admin>({
selectId: (model: Admin) => model.resourceId
});

export const initialState: CollectionState = adapter.getInitialState({
selectedAdminId: null,
saving: false
});

export function reducer(state = initialState, action: AdminCollectionActionsUnion): CollectionState {
switch (action.type) {
case AdminCollectionActionTypes.LOAD_ADMIN_SUCCESS: {
let s = adapter.addAll(action.payload, {
...state,
selectedAdminId: state.selectedAdminId
});
return s;
}
case AdminCollectionActionTypes.UPDATE_ADMIN_SUCCESS: {
return adapter.updateOne(action.payload, {
...state,
saving: false
});
}
case AdminCollectionActionTypes.REMOVE_ADMIN_SUCCESS: {
return adapter.removeOne(action.payload, {
...state,
saving: false
});
}

default: {
return state;
}
}
}

export const getSelectedAdminId = (state: CollectionState) => state.selectedAdminId;
export const getIsSaving = (state: CollectionState) => state.saving;
export const {
selectIds: selectAdminIds,
selectEntities: selectAdminEntities,
selectAll: selectAllAdmins,
selectTotal: selectAdminTotal
} = adapter.getSelectors();
33 changes: 33 additions & 0 deletions ui/src/app/user/admin/reducer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { createSelector, createFeatureSelector } from '@ngrx/store';
import * as fromRoot from '../../../core/reducer';
import * as fromCollection from './collection.reducer';

export interface AdminState {
collection: fromCollection.CollectionState;
}

export const reducers = {
collection: fromCollection.reducer
};

export interface State extends fromRoot.State {
'admin': AdminState;
}

export const getCollectionFromStateFn = (state: AdminState) => state.collection;

export const getAdminState = createFeatureSelector<AdminState>('admin');

/*
* Select pieces of Admin Collection
*/
export const getCollectionState = createSelector(getAdminState, getCollectionFromStateFn);
export const getAllAdmins = createSelector(getCollectionState, fromCollection.selectAllAdmins);
export const getCollectionSaving = createSelector(getCollectionState, fromCollection.getIsSaving);

export const getAdminEntities = createSelector(getCollectionState, fromCollection.selectAdminEntities);
export const getSelectedAdminId = createSelector(getCollectionState, fromCollection.getSelectedAdminId);
export const getSelectedAdmin = createSelector(getAdminEntities, getSelectedAdminId, (entities, selectedId) => {
return selectedId && entities[selectedId];
});
export const getAdminIds = createSelector(getCollectionState, fromCollection.selectAdminIds);
Loading

0 comments on commit 289e4c1

Please sign in to comment.