Skip to content

Commit 422c25d

Browse files
committed
fix: #237 Move notification messages to ngrx effects
1 parent fd71606 commit 422c25d

23 files changed

+151
-266
lines changed
Lines changed: 2 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,24 @@
1-
import { HttpClient, HttpHandler } from '@angular/common/http';
21
import { async, TestBed, ComponentFixture } from '@angular/core/testing';
3-
import { of, Subscription } from 'rxjs';
4-
import { Activity } from '../../shared/models';
5-
import { ActivityService } from './../services/activity.service';
62
import { ActivitiesManagementComponent } from './activities-management.component';
7-
import { ActionsSubject } from '@ngrx/store';
8-
import { ActivityManagementActionTypes } from '../store';
9-
import { ToastrService, ToastrModule, IndividualConfig } from 'ngx-toastr';
103

114
describe('ActivitiesManagementComponent', () => {
125
let component: ActivitiesManagementComponent;
136
let fixture: ComponentFixture<ActivitiesManagementComponent>;
14-
let activityService: ActivityService;
15-
const activitiesFromApi: Activity[] = [{ id: '123', name: 'aaa', description: 'xxx' }];
16-
const toastrService = {
17-
success: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { },
18-
error: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { }
19-
};
20-
let injectedToastrService;
217

228
beforeEach(async(() => {
23-
const actionSub: ActionsSubject = new ActionsSubject();
249
TestBed.configureTestingModule({
25-
imports: [ToastrModule.forRoot()],
26-
declarations: [ActivitiesManagementComponent],
27-
providers: [ActivityService, HttpClient, HttpHandler,
28-
{ provide: ActionsSubject, useValue: actionSub },
29-
{ provide: ToastrService, useValue: toastrService }
30-
],
10+
imports: [],
11+
declarations: [ActivitiesManagementComponent]
3112
}).compileComponents();
3213
}));
3314

3415
beforeEach(() => {
3516
fixture = TestBed.createComponent(ActivitiesManagementComponent);
3617
component = fixture.componentInstance;
3718
fixture.detectChanges();
38-
injectedToastrService = TestBed.inject(ToastrService);
39-
console.log(injectedToastrService);
40-
activityService = TestBed.inject(ActivityService);
41-
spyOn(activityService, 'getActivities').and.returnValue(of(activitiesFromApi));
4219
});
4320

4421
it('should create the component', () => {
4522
expect(component).toBeTruthy();
4623
});
47-
48-
it('should call #setDataNotification with action #ngOnInit', () => {
49-
const actionSubject = TestBed.inject(ActionsSubject) as ActionsSubject;
50-
spyOn(component, 'setDataNotification');
51-
const action = {
52-
type: '[ActivityManagement] CREATE_ACTIVITY_SUCCESS',
53-
};
54-
actionSubject.next(action);
55-
56-
component.ngOnInit();
57-
expect(component.setDataNotification).toHaveBeenCalledWith(action.type);
58-
});
59-
60-
it('has a succesfull message on CREATE_ACTIVITY_SUCCESS', () => {
61-
spyOn(injectedToastrService, 'success');
62-
component.setDataNotification(ActivityManagementActionTypes.CREATE_ACTIVITY_SUCCESS);
63-
64-
expect(injectedToastrService.success).toHaveBeenCalled();
65-
});
66-
67-
it('has a succesfull message on UPDATE_ACTIVITY_SUCCESS', () => {
68-
spyOn(injectedToastrService, 'success');
69-
component.setDataNotification(ActivityManagementActionTypes.UPDATE_ACTIVITY_SUCCESS);
70-
71-
expect(injectedToastrService.success).toHaveBeenCalled();
72-
});
73-
74-
it('should destroy the subscription', () => {
75-
component.actionsSubscription = new Subscription();
76-
const subscription = spyOn(component.actionsSubscription, 'unsubscribe');
77-
78-
component.ngOnDestroy();
79-
80-
expect(subscription).toHaveBeenCalledTimes(1);
81-
});
82-
83-
it('#setDataNotification should show an success notification with DELETE_ACTIVITY_SUCCESS case', () => {
84-
spyOn(injectedToastrService, 'success').and.returnValue(of(activitiesFromApi));
85-
const actionSubject = TestBed.inject(ActionsSubject) as ActionsSubject;
86-
const action = {
87-
type: '[ActivityManagement] DELETE_ACTIVITY_SUCESS',
88-
};
89-
actionSubject.next(action);
90-
91-
component.setDataNotification(action.type);
92-
expect(injectedToastrService.success).toHaveBeenCalled();
93-
});
94-
95-
it('shows an error notification with CREATE_ACTIVITY_FAIL case', () => {
96-
spyOn(injectedToastrService, 'error');
97-
98-
component.setDataNotification(ActivityManagementActionTypes.CREATE_ACTIVITY_FAIL);
99-
100-
expect(injectedToastrService.error).toHaveBeenCalled();
101-
});
102-
103-
it('shows an error notification with UPDATE_ACTIVITY_FAIL case', () => {
104-
spyOn(injectedToastrService, 'error');
105-
106-
component.setDataNotification(ActivityManagementActionTypes.UPDATE_ACTIVITY_FAIL);
107-
108-
expect(injectedToastrService.error).toHaveBeenCalled();
109-
});
110-
111-
it('shows an error notification with DELETE_ACTIVITY_FAIL case', () => {
112-
spyOn(injectedToastrService, 'error');
113-
114-
component.setDataNotification(ActivityManagementActionTypes.DELETE_ACTIVITY_FAIL);
115-
116-
expect(injectedToastrService.error).toHaveBeenCalled();
117-
});
118-
119-
it('#setDataNotification should not show an error notification with incorrect action', () => {
120-
spyOn(injectedToastrService, 'success').and.returnValue(of(activitiesFromApi));
121-
const actionSubject = TestBed.inject(ActionsSubject) as ActionsSubject;
122-
const action = {
123-
type: '[ActivityManagement] TEST',
124-
};
125-
actionSubject.next(action);
126-
127-
component.setDataNotification(action.type);
128-
});
12924
});
Lines changed: 3 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,10 @@
1-
import { Component, OnInit, OnDestroy } from '@angular/core';
2-
import { ActionsSubject } from '@ngrx/store';
3-
import { Subscription } from 'rxjs';
4-
import { ActivityManagementActionTypes } from '../store';
5-
import { ToastrService } from 'ngx-toastr';
1+
import { Component } from '@angular/core';
62

73
@Component({
84
selector: 'app-activities-management',
95
templateUrl: './activities-management.component.html',
106
styleUrls: ['./activities-management.component.scss'],
117
})
12-
export class ActivitiesManagementComponent implements OnInit, OnDestroy {
13-
actionsSubscription: Subscription;
14-
15-
constructor(private actionsSubject$: ActionsSubject, private toastrService: ToastrService) {}
16-
17-
ngOnInit() {
18-
this.actionsSubscription = this.actionsSubject$.subscribe((action) => {
19-
this.setDataNotification(action.type);
20-
});
21-
}
22-
23-
ngOnDestroy() {
24-
this.actionsSubscription.unsubscribe();
25-
}
26-
27-
setDataNotification(action: any) {
28-
switch (action) {
29-
case ActivityManagementActionTypes.CREATE_ACTIVITY_SUCCESS: {
30-
this.toastrService.success('The activity has been saved successfully.');
31-
break;
32-
}
33-
case ActivityManagementActionTypes.UPDATE_ACTIVITY_SUCCESS: {
34-
this.toastrService.success('The activity has been saved successfully.');
35-
break;
36-
}
37-
case ActivityManagementActionTypes.DELETE_ACTIVITY_SUCCESS: {
38-
this.toastrService.success('The activity has been removed successfully.');
39-
break;
40-
}
41-
case ActivityManagementActionTypes.CREATE_ACTIVITY_FAIL: {
42-
this.toastrService.error('An unexpected error happened, please try again later.');
43-
break;
44-
}
45-
case ActivityManagementActionTypes.UPDATE_ACTIVITY_FAIL: {
46-
this.toastrService.error('An unexpected error happened, please try again later.');
47-
break;
48-
}
49-
case ActivityManagementActionTypes.DELETE_ACTIVITY_FAIL : {
50-
this.toastrService.error('An unexpected error happened, please try again later.');
51-
break;
52-
}
53-
}
54-
}
8+
export class ActivitiesManagementComponent {
9+
constructor() {}
5510
}

src/app/modules/activities-management/store/activity-management.effects.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
1+
import { INFO_SAVED_SUCCESSFULLY, INFO_DELETE_SUCCESSFULLY, UNEXPECTED_ERROR } from '../../shared/messages';
12
import { Injectable } from '@angular/core';
23
import { Actions, Effect, ofType } from '@ngrx/effects';
34
import { Action } from '@ngrx/store';
45
import { Observable, of } from 'rxjs';
56
import { catchError, map, mergeMap } from 'rxjs/operators';
7+
import { ToastrService } from 'ngx-toastr';
68

79
import * as actions from './activity-management.actions';
810
import { Activity } from './../../shared/models/activity.model';
911
import { ActivityService } from './../services/activity.service';
1012

1113
@Injectable()
1214
export class ActivityEffects {
13-
constructor(private actions$: Actions, private activityService: ActivityService) {}
15+
constructor(
16+
private actions$: Actions,
17+
private activityService: ActivityService,
18+
private toastrService: ToastrService
19+
) {}
1420

1521
@Effect()
1622
getActivities$: Observable<Action> = this.actions$.pipe(
@@ -32,9 +38,13 @@ export class ActivityEffects {
3238
mergeMap((activity) =>
3339
this.activityService.createActivity(activity).pipe(
3440
map((activityData) => {
41+
this.toastrService.success(INFO_SAVED_SUCCESSFULLY);
3542
return new actions.CreateActivitySuccess(activityData);
3643
}),
37-
catchError((error) => of(new actions.CreateActivityFail(error)))
44+
catchError((error) => {
45+
this.toastrService.error(UNEXPECTED_ERROR);
46+
return of(new actions.CreateActivityFail(error));
47+
})
3848
)
3949
)
4050
);
@@ -46,9 +56,13 @@ export class ActivityEffects {
4656
mergeMap((activityId) =>
4757
this.activityService.deleteActivity(activityId).pipe(
4858
map(() => {
59+
this.toastrService.success(INFO_DELETE_SUCCESSFULLY);
4960
return new actions.DeleteActivitySuccess(activityId);
5061
}),
51-
catchError((error) => of(new actions.DeleteActivityFail(error)))
62+
catchError((error) => {
63+
this.toastrService.error(UNEXPECTED_ERROR);
64+
return of(new actions.DeleteActivityFail(error));
65+
})
5266
)
5367
)
5468
);
@@ -60,9 +74,13 @@ export class ActivityEffects {
6074
mergeMap((activity) =>
6175
this.activityService.updateActivity(activity).pipe(
6276
map((activityData) => {
77+
this.toastrService.success(INFO_SAVED_SUCCESSFULLY);
6378
return new actions.UpdateActivitySuccess(activityData);
6479
}),
65-
catchError((error) => of(new actions.UpdateActivityFail(error)))
80+
catchError((error) => {
81+
this.toastrService.error(UNEXPECTED_ERROR);
82+
return of(new actions.UpdateActivityFail(error));
83+
})
6684
)
6785
)
6886
);

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

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,11 @@ import { CreateCustomerComponent } from './create-customer';
66
import { CustomerState, CreateCustomer } from 'src/app/modules/customer-management/store';
77
import { ResetCustomerToEdit, UpdateCustomer } from './../../../../store/customer-management.actions';
88
import { Customer } from 'src/app/modules/shared/models';
9-
import { ToastrService, IndividualConfig } from 'ngx-toastr';
109

1110
describe('CreateCustomerComponent', () => {
1211
let component: CreateCustomerComponent;
1312
let fixture: ComponentFixture<CreateCustomerComponent>;
1413
let store: MockStore<CustomerState>;
15-
const toastrService = {
16-
success: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { },
17-
error: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { }
18-
};
1914

2015
const state = {
2116
data: [],
@@ -35,8 +30,7 @@ describe('CreateCustomerComponent', () => {
3530
declarations: [CreateCustomerComponent],
3631
providers: [
3732
FormBuilder,
38-
provideMockStore({ initialState: state }),
39-
{ provide: ToastrService, useValue: toastrService },
33+
provideMockStore({ initialState: state })
4034
],
4135
}).compileComponents();
4236

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
} from 'src/app/modules/customer-management/store';
1414
import { LoadProjectTypes } from '../../../projects-type/store';
1515
import { LoadCustomerProjects } from '../../../projects/components/store/project.actions';
16-
import { ToastrService } from 'ngx-toastr';
1716

1817
@Component({
1918
selector: 'app-create-customer',
@@ -28,8 +27,7 @@ export class CreateCustomerComponent implements OnInit, OnDestroy {
2827
customerToEdit: Customer;
2928
editSubscription: Subscription;
3029

31-
constructor(private formBuilder: FormBuilder, private store: Store<CustomerState>,
32-
private toastrService: ToastrService) {
30+
constructor(private formBuilder: FormBuilder, private store: Store<CustomerState>) {
3331
this.customerForm = this.formBuilder.group({
3432
name: ['', Validators.required],
3533
description: ['', Validators.required],
@@ -61,7 +59,6 @@ export class CreateCustomerComponent implements OnInit, OnDestroy {
6159
} else {
6260
this.store.dispatch(new CreateCustomer(customerData));
6361
}
64-
this.toastrService.success('Customer information saved successfully');
6562
this.areTabsActive = true;
6663
this.changeValueAreTabsActives.emit(this.areTabsActive);
6764
}

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

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { ToastrService, IndividualConfig } from 'ngx-toastr';
21
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
32
import { MockStore, provideMockStore } from '@ngrx/store/testing';
43

@@ -21,18 +20,14 @@ describe('CustomerTableListComponent', () => {
2120
customerId: ''
2221
};
2322

24-
const toastrService = {
25-
success: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { },
26-
error: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { }
27-
};
23+
2824

2925
beforeEach(async(() => {
3026
TestBed.configureTestingModule({
3127
imports: [NgxPaginationModule],
3228
declarations: [CustomerListComponent],
3329
providers: [
34-
provideMockStore({ initialState: state }),
35-
{ provide: ToastrService, useValue: toastrService },
30+
provideMockStore({ initialState: state })
3631
],
3732
}).compileComponents();
3833
}));

src/app/modules/customer-management/components/customer-info/components/customer-list/customer-list.component.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { allCustomers } from './../../../../store/customer-management.selectors'
66
import { LoadCustomers, DeleteCustomer, SetCustomerToEdit } from './../../../../store/customer-management.actions';
77
import { Customer } from './../../../../../shared/models/customer.model';
88
import { ITEMS_PER_PAGE } from 'src/environments/environment';
9-
import { ToastrService } from 'ngx-toastr';
109

1110
@Component({
1211
selector: 'app-customer-list',
@@ -22,7 +21,7 @@ export class CustomerListComponent implements OnInit, OnDestroy {
2221
customers: Customer[] = [];
2322
customerSubscription: Subscription;
2423

25-
constructor(private store: Store<Customer>, private toastrService: ToastrService) { }
24+
constructor(private store: Store<Customer>) { }
2625

2726
ngOnInit(): void {
2827
this.store.dispatch(new LoadCustomers());
@@ -44,6 +43,5 @@ export class CustomerListComponent implements OnInit, OnDestroy {
4443

4544
deleteCustomer(customerId: string) {
4645
this.store.dispatch(new DeleteCustomer(customerId));
47-
this.toastrService.success('Customer has been deleted');
4846
}
4947
}

src/app/modules/customer-management/components/projects-type/components/create-project-type/create-project-type.component.spec.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { ToastrService, IndividualConfig } from 'ngx-toastr';
21
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
32
import { FormBuilder } from '@angular/forms';
43
import { provideMockStore, MockStore } from '@ngrx/store/testing';
@@ -39,18 +38,12 @@ describe('InputProjectTypeComponent', () => {
3938
description: 'It is good for learning',
4039
};
4140

42-
const toastrService = {
43-
success: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { },
44-
error: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { }
45-
};
46-
4741
beforeEach(async(() => {
4842
TestBed.configureTestingModule({
4943
declarations: [CreateProjectTypeComponent],
5044
providers: [
5145
FormBuilder,
52-
provideMockStore({ initialState: state }),
53-
{ provide: ToastrService, useValue: toastrService },
46+
provideMockStore({ initialState: state })
5447
],
5548
}).compileComponents();
5649
}));

0 commit comments

Comments
 (0)