Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { CreateCustomerComponent } from './create-customer';
import { CustomerState, CreateCustomer } from 'src/app/modules/customer-management/store';
import * as models from 'src/app/modules/shared/models/index';
import { LoadCustomers } from './../../../../store/customer-management.actions';

describe('CreateCustomerComponent', () => {
let component: CreateCustomerComponent;
Expand Down Expand Up @@ -55,13 +56,14 @@ describe('CreateCustomerComponent', () => {
expect(component.customerForm.reset).toHaveBeenCalled();
});

it('onSubmit and dispatch CreateCustomer action', () => {
it('onSubmit, dispatch CreateCustomer and LoadCustomers actions', () => {
spyOn(store, 'dispatch');

component.onSubmit(customerData);

expect(store.dispatch).toHaveBeenCalledTimes(1);
expect(store.dispatch).toHaveBeenCalledTimes(2);
expect(store.dispatch).toHaveBeenCalledWith(new CreateCustomer(customerData));
expect(store.dispatch).toHaveBeenCalledWith(new LoadCustomers());
});

it('should call resetCustomerForm', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { Store, select } from '@ngrx/store';

import { Subscription } from 'rxjs';
import { CustomerState, CreateCustomer } from 'src/app/modules/customer-management/store';
import { getStatusMessage } from 'src/app/modules/customer-management/store/customer-management.selectors';
import { CustomerState, CreateCustomer, LoadCustomers } from 'src/app/modules/customer-management/store';
import { getStatusMessage } from './../../../../store/customer-management.selectors';

@Component({
selector: 'app-create-customer',
Expand Down Expand Up @@ -40,6 +40,7 @@ export class CreateCustomerComponent implements OnInit, OnDestroy {

onSubmit(customerData) {
this.store.dispatch(new CreateCustomer(customerData));
this.store.dispatch(new LoadCustomers());
this.showAlert = true;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,57 @@
import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { CustomerListComponent } from './customer-list.component';
import { NgxPaginationModule } from 'ngx-pagination';
import { allCustomers } from './../../../../store/customer-management.selectors';
import { CustomerState } from 'src/app/modules/customer-management/store';

describe('CustomerTableListComponent', () => {
let component: CustomerListComponent;
let fixture: ComponentFixture<CustomerListComponent>;
let store: MockStore<CustomerState>;
let mockCustomerSelector;


const state = {
data: [{ tenant_id: 'id', name: 'name', description: 'description' }],
isLoading: false,
message: '',
};

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [NgxPaginationModule],
declarations: [CustomerListComponent],
providers: [provideMockStore({ initialState: state })],
}).compileComponents();
}));

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

store = TestBed.inject(MockStore);
store.setState(state);
mockCustomerSelector = store.overrideSelector(allCustomers, state.data);
});

it('component should be created', () => {
expect(component).toBeTruthy();
});

it('onNgInit customers are loaded from store executing an action', () => {
spyOn(store, 'dispatch');

component.ngOnInit();

expect(store.dispatch).toHaveBeenCalled();
expect(component.customers).toEqual(state.data);
});

afterEach(() => {
fixture.destroy();
});

});
Original file line number Diff line number Diff line change
@@ -1,34 +1,32 @@
import { Component } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { Store, select } from '@ngrx/store';

import { allCustomers } from './../../../../store/customer-management.selectors';
import { LoadCustomers } from './../../../../store/customer-management.actions';
import { Customer } from './../../../../../shared/models/customer.model';
import { ITEMS_PER_PAGE } from 'src/environments/environment';


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

initPage1 = 1;
itemsPerPage = ITEMS_PER_PAGE;

customers = [
{
id: '1',
name: 'GoSpace',
},
{
id: '2',
name: 'GruHub',
},
{
id: '3',
name: 'e&y',
},
{
id: '4',
name: 'Mido',
},
];

constructor() {}
customers: Customer[] = [];

constructor(private store: Store<Customer>) {}

ngOnInit(): void {
this.store.dispatch(new LoadCustomers());
const customers$ = this.store.pipe(select(allCustomers));
customers$.subscribe((response) => {
this.customers = response;
});
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { HttpClient } from '@angular/common/http';

import { environment } from './../../../../environments/environment';
import { AzureAdB2CService } from 'src/app/modules/login/services/azure.ad.b2c.service';
Expand All @@ -20,4 +20,8 @@ export class CustomerService {
};
return this.http.post(this.baseUrl, body);
}

getCustomers(): Observable<any> {
return this.http.get(this.baseUrl);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,14 @@ describe('CustomerManagmentActions', () => {
const createActivityFail = new actions.CreateCustomerFail('error');
expect(createActivityFail.type).toEqual(actions.CustomerManagementActionTypes.CREATE_CUSTOMER_FAIL);
});

it('LoadCustomersSuccess type is CustomerManagementActionTypes.LOAD_CUSTOMERS_SUCCESS', () => {
const action = new actions.LoadCustomersSuccess([]);
expect(action.type).toEqual(actions.CustomerManagementActionTypes.LOAD_CUSTOMERS_SUCCESS);
});

it('LoadCustomersFail type is CustomerManagementActionTypes.LOAD_CUSTOMERS_FAIL', () => {
const action = new actions.LoadCustomersFail('error');
expect(action.type).toEqual(actions.CustomerManagementActionTypes.LOAD_CUSTOMERS_FAIL);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,24 @@ export enum CustomerManagementActionTypes {
CREATE_CUSTOMER = '[CustomerManagement] CREATE_CUSTOMER',
CREATE_CUSTOMER_SUCCESS = '[CustomerManagement] CREATE_CUSTOMER_SUCCESS',
CREATE_CUSTOMER_FAIL = '[CustomerManagement] CREATE_CUSTOMER_FAIL',
LOAD_CUSTOMERS = '[CustomerManagement] LOAD_CUSTOMERS',
LOAD_CUSTOMERS_SUCCESS = '[CustomerManagement] LOAD_CUSTOMERS_SUCCESS',
LOAD_CUSTOMERS_FAIL = '[CustomerManagement] LOAD_CUSTOMERS_FAIL',
}

export class LoadCustomers implements Action {
public readonly type = CustomerManagementActionTypes.LOAD_CUSTOMERS;
}

export class LoadCustomersSuccess implements Action {
readonly type = CustomerManagementActionTypes.LOAD_CUSTOMERS_SUCCESS;
constructor(readonly payload: Customer[]) {}
}

export class LoadCustomersFail implements Action {
public readonly type = CustomerManagementActionTypes.LOAD_CUSTOMERS_FAIL;

constructor(public error: string) {}
}

export class CreateCustomer implements Action {
Expand All @@ -25,4 +43,6 @@ export class CreateCustomerFail implements Action {
constructor(public error: string) {}
}

export type CustomerManagementActions = CreateCustomer | CreateCustomerSuccess | CreateCustomerFail;
export type CustomerManagementActions =
CreateCustomer | CreateCustomerSuccess | CreateCustomerFail |
LoadCustomers | LoadCustomersFail | LoadCustomersSuccess;
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@ import { map, catchError, mergeMap } from 'rxjs/operators';
export class CustomerEffects {
constructor(private actions$: Actions, private customerService: CustomerService) {}

@Effect()
loadCustomers$: Observable<Action> = this.actions$.pipe(
ofType(actions.CustomerManagementActionTypes.LOAD_CUSTOMERS),
mergeMap(() =>
this.customerService.getCustomers().pipe(
map((customers) => {
return new actions.LoadCustomersSuccess(customers);
}),
catchError((error) => of(new actions.LoadCustomersFail(error)))
)
)
);

@Effect()
createCustomer$: Observable<Action> = this.actions$.pipe(
ofType(actions.CustomerManagementActionTypes.CREATE_CUSTOMER),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,30 @@ describe('customerManagementReducer', () => {
const initialState: CustomerState = { data: [], isLoading: false, message: '' };
const customer: Customer = { name: 'aa', description: 'bb', tenant_id: 'cc' };

it('on LoadCustomer, isLoading is true ', () => {
const action = new actions.LoadCustomers();
const state = customerManagementReducer(initialState, action);

expect(state.isLoading).toEqual(true);
});

it('on LoadCustomerSucess, isLoading is false and state has data', () => {
const data = [];
const action = new actions.LoadCustomersSuccess(data);
const state = customerManagementReducer(initialState, action);

expect(state.isLoading).toEqual(false);
expect(state.data).toEqual(data);
});

it('on LoadCustomerFail, isLoading is false and state has empty data', () => {
const action = new actions.LoadCustomersFail('doh!!!');
const state = customerManagementReducer(initialState, action);

expect(state.isLoading).toEqual(false);
expect(state.data.length).toBe(0);
});

it('on CreateCustomer, isLoading is true ', () => {
const action = new actions.CreateCustomer(customer);
const state = customerManagementReducer(initialState, action);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,27 @@ export function customerManagementReducer(
action: CustomerManagementActions
): CustomerState {
switch (action.type) {
case CustomerManagementActionTypes.LOAD_CUSTOMERS: {
return {
...state,
isLoading: true,
};
}
case CustomerManagementActionTypes.LOAD_CUSTOMERS_SUCCESS: {
return {
...state,
data: action.payload,
isLoading: false,
};
}
case CustomerManagementActionTypes.LOAD_CUSTOMERS_FAIL: {
return {
...state,
data: [],
isLoading: false,
};
}

case CustomerManagementActionTypes.CREATE_CUSTOMER: {
return {
...state,
Expand All @@ -28,7 +49,7 @@ export function customerManagementReducer(
case CustomerManagementActionTypes.CREATE_CUSTOMER_SUCCESS: {
return {
...state,
data: [action.payload],
data: [...state.data, action.payload],
isLoading: false,
message: 'Customer created successfully!',
};
Expand All @@ -42,8 +63,5 @@ export function customerManagementReducer(
message: 'An error occurred, try again later.',
};
}

default:
return state;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ export const getStatusMessage = createSelector(getCustomerState, (messageState)
return messageState.message;
}
});

export const allCustomers = createSelector(getCustomerState, (state: CustomerState) => {
return state.data;
});
2 changes: 1 addition & 1 deletion src/environments/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as keys from './keys';

export const environment = {
production: false,
timeTrackerApiUrl: 'https://tsheets-apim.azure-api.net',
timeTrackerApiUrl: 'https://timetracker-api.azurewebsites.net',
stackexchangeApiUrl: 'https://api.stackexchange.com',
};

Expand Down