Skip to content

Commit e681d1a

Browse files
authored
Merge pull request #142 from ioet/141-list-customers
fix: #142 read customers from API
2 parents 95823b3 + ff87824 commit e681d1a

File tree

11 files changed

+156
-32
lines changed

11 files changed

+156
-32
lines changed

src/app/modules/customer-management/components/customer-info/components/create-customer/create-customer.spec.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { MockStore, provideMockStore } from '@ngrx/store/testing';
55
import { CreateCustomerComponent } from './create-customer';
66
import { CustomerState, CreateCustomer } from 'src/app/modules/customer-management/store';
77
import * as models from 'src/app/modules/shared/models/index';
8+
import { LoadCustomers } from './../../../../store/customer-management.actions';
89

910
describe('CreateCustomerComponent', () => {
1011
let component: CreateCustomerComponent;
@@ -55,13 +56,14 @@ describe('CreateCustomerComponent', () => {
5556
expect(component.customerForm.reset).toHaveBeenCalled();
5657
});
5758

58-
it('onSubmit and dispatch CreateCustomer action', () => {
59+
it('onSubmit, dispatch CreateCustomer and LoadCustomers actions', () => {
5960
spyOn(store, 'dispatch');
6061

6162
component.onSubmit(customerData);
6263

63-
expect(store.dispatch).toHaveBeenCalledTimes(1);
64+
expect(store.dispatch).toHaveBeenCalledTimes(2);
6465
expect(store.dispatch).toHaveBeenCalledWith(new CreateCustomer(customerData));
66+
expect(store.dispatch).toHaveBeenCalledWith(new LoadCustomers());
6567
});
6668

6769
it('should call resetCustomerForm', () => {

src/app/modules/customer-management/components/customer-info/components/create-customer/create-customer.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { FormGroup, FormBuilder, Validators } from '@angular/forms';
33
import { Store, select } from '@ngrx/store';
44

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

99
@Component({
1010
selector: 'app-create-customer',
@@ -40,6 +40,7 @@ export class CreateCustomerComponent implements OnInit, OnDestroy {
4040

4141
onSubmit(customerData) {
4242
this.store.dispatch(new CreateCustomer(customerData));
43+
this.store.dispatch(new LoadCustomers());
4344
this.showAlert = true;
4445
}
4546

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,57 @@
1+
import { MockStore, provideMockStore } from '@ngrx/store/testing';
12
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
23

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

69
describe('CustomerTableListComponent', () => {
710
let component: CustomerListComponent;
811
let fixture: ComponentFixture<CustomerListComponent>;
12+
let store: MockStore<CustomerState>;
13+
let mockCustomerSelector;
14+
15+
16+
const state = {
17+
data: [{ tenant_id: 'id', name: 'name', description: 'description' }],
18+
isLoading: false,
19+
message: '',
20+
};
921

1022
beforeEach(async(() => {
1123
TestBed.configureTestingModule({
1224
imports: [NgxPaginationModule],
1325
declarations: [CustomerListComponent],
26+
providers: [provideMockStore({ initialState: state })],
1427
}).compileComponents();
1528
}));
1629

1730
beforeEach(() => {
1831
fixture = TestBed.createComponent(CustomerListComponent);
1932
component = fixture.componentInstance;
2033
fixture.detectChanges();
34+
35+
store = TestBed.inject(MockStore);
36+
store.setState(state);
37+
mockCustomerSelector = store.overrideSelector(allCustomers, state.data);
2138
});
2239

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

44+
it('onNgInit customers are loaded from store executing an action', () => {
45+
spyOn(store, 'dispatch');
46+
47+
component.ngOnInit();
48+
49+
expect(store.dispatch).toHaveBeenCalled();
50+
expect(component.customers).toEqual(state.data);
51+
});
52+
53+
afterEach(() => {
54+
fixture.destroy();
55+
});
56+
2757
});
Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,32 @@
1-
import { Component } from '@angular/core';
1+
import { Component, OnInit } from '@angular/core';
2+
import { Store, select } from '@ngrx/store';
3+
4+
import { allCustomers } from './../../../../store/customer-management.selectors';
5+
import { LoadCustomers } from './../../../../store/customer-management.actions';
6+
import { Customer } from './../../../../../shared/models/customer.model';
27
import { ITEMS_PER_PAGE } from 'src/environments/environment';
38

9+
410
@Component({
511
selector: 'app-customer-list',
612
templateUrl: './customer-list.component.html',
713
styleUrls: ['./customer-list.component.scss'],
814
})
9-
export class CustomerListComponent {
15+
export class CustomerListComponent implements OnInit {
16+
1017
initPage1 = 1;
1118
itemsPerPage = ITEMS_PER_PAGE;
1219

13-
customers = [
14-
{
15-
id: '1',
16-
name: 'GoSpace',
17-
},
18-
{
19-
id: '2',
20-
name: 'GruHub',
21-
},
22-
{
23-
id: '3',
24-
name: 'e&y',
25-
},
26-
{
27-
id: '4',
28-
name: 'Mido',
29-
},
30-
];
31-
32-
constructor() {}
20+
customers: Customer[] = [];
21+
22+
constructor(private store: Store<Customer>) {}
23+
24+
ngOnInit(): void {
25+
this.store.dispatch(new LoadCustomers());
26+
const customers$ = this.store.pipe(select(allCustomers));
27+
customers$.subscribe((response) => {
28+
this.customers = response;
29+
});
30+
}
3331

3432
}

src/app/modules/customer-management/services/customer.service.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Injectable } from '@angular/core';
2-
import { HttpClient, HttpHeaders } from '@angular/common/http';
2+
import { HttpClient } from '@angular/common/http';
33

44
import { environment } from './../../../../environments/environment';
55
import { AzureAdB2CService } from 'src/app/modules/login/services/azure.ad.b2c.service';
@@ -20,4 +20,8 @@ export class CustomerService {
2020
};
2121
return this.http.post(this.baseUrl, body);
2222
}
23+
24+
getCustomers(): Observable<any> {
25+
return this.http.get(this.baseUrl);
26+
}
2327
}

src/app/modules/customer-management/store/customer-management.actions.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,14 @@ describe('CustomerManagmentActions', () => {
2323
const createActivityFail = new actions.CreateCustomerFail('error');
2424
expect(createActivityFail.type).toEqual(actions.CustomerManagementActionTypes.CREATE_CUSTOMER_FAIL);
2525
});
26+
27+
it('LoadCustomersSuccess type is CustomerManagementActionTypes.LOAD_CUSTOMERS_SUCCESS', () => {
28+
const action = new actions.LoadCustomersSuccess([]);
29+
expect(action.type).toEqual(actions.CustomerManagementActionTypes.LOAD_CUSTOMERS_SUCCESS);
30+
});
31+
32+
it('LoadCustomersFail type is CustomerManagementActionTypes.LOAD_CUSTOMERS_FAIL', () => {
33+
const action = new actions.LoadCustomersFail('error');
34+
expect(action.type).toEqual(actions.CustomerManagementActionTypes.LOAD_CUSTOMERS_FAIL);
35+
});
2636
});

src/app/modules/customer-management/store/customer-management.actions.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,24 @@ export enum CustomerManagementActionTypes {
55
CREATE_CUSTOMER = '[CustomerManagement] CREATE_CUSTOMER',
66
CREATE_CUSTOMER_SUCCESS = '[CustomerManagement] CREATE_CUSTOMER_SUCCESS',
77
CREATE_CUSTOMER_FAIL = '[CustomerManagement] CREATE_CUSTOMER_FAIL',
8+
LOAD_CUSTOMERS = '[CustomerManagement] LOAD_CUSTOMERS',
9+
LOAD_CUSTOMERS_SUCCESS = '[CustomerManagement] LOAD_CUSTOMERS_SUCCESS',
10+
LOAD_CUSTOMERS_FAIL = '[CustomerManagement] LOAD_CUSTOMERS_FAIL',
11+
}
12+
13+
export class LoadCustomers implements Action {
14+
public readonly type = CustomerManagementActionTypes.LOAD_CUSTOMERS;
15+
}
16+
17+
export class LoadCustomersSuccess implements Action {
18+
readonly type = CustomerManagementActionTypes.LOAD_CUSTOMERS_SUCCESS;
19+
constructor(readonly payload: Customer[]) {}
20+
}
21+
22+
export class LoadCustomersFail implements Action {
23+
public readonly type = CustomerManagementActionTypes.LOAD_CUSTOMERS_FAIL;
24+
25+
constructor(public error: string) {}
826
}
927

1028
export class CreateCustomer implements Action {
@@ -25,4 +43,6 @@ export class CreateCustomerFail implements Action {
2543
constructor(public error: string) {}
2644
}
2745

28-
export type CustomerManagementActions = CreateCustomer | CreateCustomerSuccess | CreateCustomerFail;
46+
export type CustomerManagementActions =
47+
CreateCustomer | CreateCustomerSuccess | CreateCustomerFail |
48+
LoadCustomers | LoadCustomersFail | LoadCustomersSuccess;

src/app/modules/customer-management/store/customer-management.effects.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@ import { map, catchError, mergeMap } from 'rxjs/operators';
1111
export class CustomerEffects {
1212
constructor(private actions$: Actions, private customerService: CustomerService) {}
1313

14+
@Effect()
15+
loadCustomers$: Observable<Action> = this.actions$.pipe(
16+
ofType(actions.CustomerManagementActionTypes.LOAD_CUSTOMERS),
17+
mergeMap(() =>
18+
this.customerService.getCustomers().pipe(
19+
map((customers) => {
20+
return new actions.LoadCustomersSuccess(customers);
21+
}),
22+
catchError((error) => of(new actions.LoadCustomersFail(error)))
23+
)
24+
)
25+
);
26+
1427
@Effect()
1528
createCustomer$: Observable<Action> = this.actions$.pipe(
1629
ofType(actions.CustomerManagementActionTypes.CREATE_CUSTOMER),

src/app/modules/customer-management/store/customer-management.reducers.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,30 @@ describe('customerManagementReducer', () => {
66
const initialState: CustomerState = { data: [], isLoading: false, message: '' };
77
const customer: Customer = { name: 'aa', description: 'bb', tenant_id: 'cc' };
88

9+
it('on LoadCustomer, isLoading is true ', () => {
10+
const action = new actions.LoadCustomers();
11+
const state = customerManagementReducer(initialState, action);
12+
13+
expect(state.isLoading).toEqual(true);
14+
});
15+
16+
it('on LoadCustomerSucess, isLoading is false and state has data', () => {
17+
const data = [];
18+
const action = new actions.LoadCustomersSuccess(data);
19+
const state = customerManagementReducer(initialState, action);
20+
21+
expect(state.isLoading).toEqual(false);
22+
expect(state.data).toEqual(data);
23+
});
24+
25+
it('on LoadCustomerFail, isLoading is false and state has empty data', () => {
26+
const action = new actions.LoadCustomersFail('doh!!!');
27+
const state = customerManagementReducer(initialState, action);
28+
29+
expect(state.isLoading).toEqual(false);
30+
expect(state.data.length).toBe(0);
31+
});
32+
933
it('on CreateCustomer, isLoading is true ', () => {
1034
const action = new actions.CreateCustomer(customer);
1135
const state = customerManagementReducer(initialState, action);

src/app/modules/customer-management/store/customer-management.reducers.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,27 @@ export function customerManagementReducer(
1818
action: CustomerManagementActions
1919
): CustomerState {
2020
switch (action.type) {
21+
case CustomerManagementActionTypes.LOAD_CUSTOMERS: {
22+
return {
23+
...state,
24+
isLoading: true,
25+
};
26+
}
27+
case CustomerManagementActionTypes.LOAD_CUSTOMERS_SUCCESS: {
28+
return {
29+
...state,
30+
data: action.payload,
31+
isLoading: false,
32+
};
33+
}
34+
case CustomerManagementActionTypes.LOAD_CUSTOMERS_FAIL: {
35+
return {
36+
...state,
37+
data: [],
38+
isLoading: false,
39+
};
40+
}
41+
2142
case CustomerManagementActionTypes.CREATE_CUSTOMER: {
2243
return {
2344
...state,
@@ -28,7 +49,7 @@ export function customerManagementReducer(
2849
case CustomerManagementActionTypes.CREATE_CUSTOMER_SUCCESS: {
2950
return {
3051
...state,
31-
data: [action.payload],
52+
data: [...state.data, action.payload],
3253
isLoading: false,
3354
message: 'Customer created successfully!',
3455
};
@@ -42,8 +63,5 @@ export function customerManagementReducer(
4263
message: 'An error occurred, try again later.',
4364
};
4465
}
45-
46-
default:
47-
return state;
4866
}
4967
}

0 commit comments

Comments
 (0)