Skip to content

Commit f02c596

Browse files
committed
#67 adding required ngrx interactions to remove an activity
1 parent c197040 commit f02c596

File tree

8 files changed

+135
-39
lines changed

8 files changed

+135
-39
lines changed

src/app/modules/activities-management/components/activity-list/activity-list.component.spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ describe('ActivityListComponent', () => {
99
let component: ActivityListComponent;
1010
let fixture: ComponentFixture<ActivityListComponent>;
1111
let mockActivitiesSelector;
12+
const activityToDelete = { id: '1', name: 'X', description: 'ABC'};
1213

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

@@ -36,6 +37,35 @@ describe('ActivityListComponent', () => {
3637
expect(component).toBeTruthy();
3738
});
3839

40+
it('showModal is true onSelectActivityToDelete', () => {
41+
component.onSelectActivityToDelete(activityToDelete);
42+
43+
expect(component.showModal).toBeTruthy();
44+
});
45+
46+
it('selectedActivity is propulated onSelectActivityToDelete', () => {
47+
component.onSelectActivityToDelete(activityToDelete);
48+
49+
expect(component.selectedActivity).toEqual(activityToDelete);
50+
});
51+
52+
it('deleteActivity is dispatched onConfirmDeleteActivity', () => {
53+
spyOn(store, 'dispatch');
54+
component.selectedActivity = activityToDelete;
55+
56+
component.onConfirmDeleteActivity();
57+
58+
expect(store.dispatch).toHaveBeenCalled();
59+
});
60+
61+
it('showModal is false and selectedProject is null onConfirmDeleteActivity', () => {
62+
component.selectedActivity = activityToDelete;
63+
component.onConfirmDeleteActivity();
64+
65+
expect(component.showModal).toBeFalsy();
66+
expect(component.selectedActivity).toBe(null);
67+
});
68+
3969
it('onInit, LoadActivities action is dispatched', () => {
4070
spyOn(store, 'dispatch');
4171

src/app/modules/activities-management/components/activity-list/activity-list.component.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Component } from '@angular/core';
33
import { Store, select } from '@ngrx/store';
44

55
import { allActivities } from '../../store';
6-
import { LoadActivities } from './../../store/activity-management.actions';
6+
import { LoadActivities, DeleteActivity } from './../../store/activity-management.actions';
77
import { ActivityState } from './../../store/activity-management.reducers';
88
import { Activity } from '../../../shared/models';
99

@@ -13,16 +13,28 @@ export class ActivityListComponent implements OnInit {
1313
@Input()activities: Activity[] = [];
1414
public isLoading: boolean;
1515

16+
showModal: boolean;
17+
selectedActivity: Activity;
18+
1619
constructor(private store: Store<ActivityState>) { }
1720

1821
ngOnInit() {
1922
this.store.dispatch(new LoadActivities());
2023
const activities$ = this.store.pipe(select(allActivities));
21-
2224
activities$.subscribe(response => {
2325
this.isLoading = response.isLoading;
2426
this.activities = response.data;
2527
});
2628
}
2729

30+
onSelectActivityToDelete(activityToDelete: Activity) {
31+
this.showModal = true;
32+
this.selectedActivity = activityToDelete;
33+
}
34+
35+
onConfirmDeleteActivity() {
36+
this.showModal = false;
37+
this.store.dispatch(new DeleteActivity(this.selectedActivity.id));
38+
this.selectedActivity = null;
39+
}
2840
}

src/app/modules/activities-management/services/activity.service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,8 @@ export class ActivityService {
1717
getActivities(): Observable<Activity[]> {
1818
return this.http.get<Activity[]>(this.baseUrl);
1919
}
20+
21+
deleteActivity(acitivityId) {
22+
throw new Error('Method not implemented.');
23+
}
2024
}
Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
1-
import { LoadActivitiesFail } from './activity-management.actions';
1+
import { LoadActivitiesFail, DeleteActivity } from './activity-management.actions';
22
import { LoadActivitiesSuccess, ActivityManagementActionTypes } from './activity-management.actions';
33

44
describe('LoadActivitiesSuccess', () => {
55

6-
it('LoadActivitiesSuccess type is ActivityManagementActionTypes.LoadActivitiesSuccess', () => {
6+
it('LoadActivitiesSuccess type is LOAD_ACTIVITIES_SUCCESS', () => {
77
const loadActivitiesSuccess = new LoadActivitiesSuccess([]);
8-
expect(loadActivitiesSuccess.type).toEqual(ActivityManagementActionTypes.LoadActivitiesSuccess);
8+
expect(loadActivitiesSuccess.type).toEqual(ActivityManagementActionTypes.LOAD_ACTIVITIES_SUCCESS);
99
});
1010

11-
it('LoadActivitiesFail type is ActivityManagementActionTypes.LoadActivitiesFail', () => {
11+
it('LoadActivitiesFail type is LOAD_ACTIVITIES_FAIL', () => {
1212
const loadActivitiesFail = new LoadActivitiesFail('error');
13-
expect(loadActivitiesFail.type).toEqual(ActivityManagementActionTypes.LoadActivitiesFail);
13+
expect(loadActivitiesFail.type).toEqual(ActivityManagementActionTypes.LOAD_ACTIVITIES_FAIL);
14+
});
15+
16+
it('action DeleteActivity type is DELETE_ACTIVITY', () => {
17+
const action = new DeleteActivity('1');
18+
expect(action.type).toEqual(ActivityManagementActionTypes.DELETE_ACTIVITY);
1419
});
1520

1621
});

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

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,41 @@ import { Action } from '@ngrx/store';
33
import { Activity } from './../../shared/models/activity.model';
44

55
export enum ActivityManagementActionTypes {
6-
LoadActivities = '[ActivityManagement] Load Activities',
7-
LoadActivitiesSuccess = '[ActivityManagement] Load Activities Successs',
8-
LoadActivitiesFail = '[ActivityManagement] Load Activities Fail',
6+
LOAD_ACTIVITIES = '[ActivityManagement] Load Activities',
7+
LOAD_ACTIVITIES_SUCCESS = '[ActivityManagement] Load Activities Successs',
8+
LOAD_ACTIVITIES_FAIL = '[ActivityManagement] Load Activities Fail',
9+
DELETE_ACTIVITY = '[ActivityManagement] Delete Activity',
10+
DELETE_ACTIVITY_SUCCESS = '[ActivityManagement] Delete Activity Success',
911
}
1012

13+
export class DeleteActivity implements Action {
14+
public readonly type = ActivityManagementActionTypes.DELETE_ACTIVITY;
15+
16+
constructor(public activityId: string) { }
17+
}
18+
19+
export class DeleteActivitySuccess implements Action {
20+
public readonly type = ActivityManagementActionTypes.DELETE_ACTIVITY_SUCCESS;
21+
22+
constructor(public activityId: string) { }
23+
}
1124

1225
export class LoadActivities implements Action {
13-
public readonly type = ActivityManagementActionTypes.LoadActivities;
26+
public readonly type = ActivityManagementActionTypes.LOAD_ACTIVITIES;
1427
}
1528

1629
export class LoadActivitiesSuccess implements Action {
17-
public readonly type = ActivityManagementActionTypes.LoadActivitiesSuccess;
30+
public readonly type = ActivityManagementActionTypes.LOAD_ACTIVITIES_SUCCESS;
1831

1932
constructor(public payload: Activity[]) { }
2033
}
2134

2235
export class LoadActivitiesFail implements Action {
23-
public readonly type = ActivityManagementActionTypes.LoadActivitiesFail;
36+
public readonly type = ActivityManagementActionTypes.LOAD_ACTIVITIES_FAIL;
2437

2538
constructor(public error) { }
2639
}
2740

28-
export type ActivityManagementActions = LoadActivities | LoadActivitiesSuccess | LoadActivitiesFail;
41+
export type ActivityManagementActions
42+
= DeleteActivitySuccess | DeleteActivity |
43+
LoadActivities | LoadActivitiesSuccess | LoadActivitiesFail;
Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,32 @@
1-
import { Injectable } from '@angular/core';
2-
import { Actions, Effect, ofType } from '@ngrx/effects';
3-
import { Action } from '@ngrx/store';
4-
import { Observable, of } from 'rxjs';
5-
import { catchError, map, mergeMap } from 'rxjs/operators';
1+
import {Injectable} from '@angular/core';
2+
import {Actions, Effect, ofType} from '@ngrx/effects';
3+
import {Action} from '@ngrx/store';
4+
import {Observable, of} from 'rxjs';
5+
import {catchError, map, mergeMap} from 'rxjs/operators';
66

7-
import { ActivityManagementActionTypes, LoadActivitiesSuccess, LoadActivitiesFail } from './activity-management.actions';
8-
import { Activity } from './../../shared/models/activity.model';
9-
import { ActivityService } from './../services/activity.service';
7+
import {ActivityManagementActionTypes, LoadActivitiesSuccess, LoadActivitiesFail} from './activity-management.actions';
8+
import {Activity} from './../../shared/models/activity.model';
9+
import {ActivityService} from './../services/activity.service';
1010

1111
@Injectable()
1212
export class ActivityEffects {
1313

14-
constructor(private actions$: Actions, private activityService: ActivityService) { }
14+
constructor(private actions$: Actions, private activityService: ActivityService) {}
1515

1616
@Effect()
17-
getActivities$: Observable<Action> = this.actions$.pipe(
18-
ofType(ActivityManagementActionTypes.LoadActivities),
19-
mergeMap(() =>
20-
this.activityService.getActivities().pipe(
21-
map((activities: Activity[]) => {
22-
return new LoadActivitiesSuccess(activities);
23-
}),
24-
catchError((error) =>
25-
of(new LoadActivitiesFail(error)))
26-
)
27-
));
17+
getActivities$: Observable < Action > = this
18+
.actions$
19+
.pipe(ofType(ActivityManagementActionTypes.LOAD_ACTIVITIES),
20+
mergeMap(() => this.activityService.getActivities().pipe(map((activities: Activity[]) => {
21+
return new LoadActivitiesSuccess(activities);
22+
}), catchError((error) => of(new LoadActivitiesFail(error))))));
23+
24+
// TODO: implement the proper code to delete an activity
25+
// @Effect()
26+
// deleteActivity$: Observable < Action > = this
27+
// .actions$
28+
// .pipe(ofType(ActivityManagementActionTypes.DELETE_ACTIVITY),
29+
// mergeMap(() => this.activityService.deleteActivity().pipe(map((activities: Activity[]) => {
30+
// return new LoadActivitiesSuccess(activities);
31+
// }), catchError((error) => of(new LoadActivitiesFail(error))))));
2832
}

src/app/modules/activities-management/store/activity-management.reducers.spec.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import { NavbarComponent } from './../../shared/components/navbar/navbar.component';
12
import { Activity } from './../../shared/models/activity.model';
2-
import { LoadActivitiesFail, LoadActivities } from './activity-management.actions';
3+
import { LoadActivitiesFail, LoadActivities, DeleteActivity } from './activity-management.actions';
34
import { LoadActivitiesSuccess } from './activity-management.actions';
45
import { activityManagementReducer, ActivityState } from './activity-management.reducers';
56

@@ -31,4 +32,13 @@ describe('activityManagementReducer', () => {
3132
expect(state.message).toEqual('Something went wrong fetching activities!');
3233
});
3334

35+
it('on DeleteActivity, message equal to Activity removed successfully!', () => {
36+
const activityToDeleteId = '1';
37+
const action = new DeleteActivity(activityToDeleteId);
38+
39+
const state = activityManagementReducer(initialState, action);
40+
41+
expect(state.message).toEqual('Activity removed successfully!');
42+
});
43+
3444
});

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

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,41 @@ const initialState: ActivityState = {
1313
message: ''
1414
};
1515

16-
export function activityManagementReducer(state = initialState, action: ActivityManagementActions): ActivityState {
16+
export function activityManagementReducer(state: ActivityState = initialState, action: ActivityManagementActions): ActivityState {
1717

1818
switch (action.type) {
19-
case(ActivityManagementActionTypes.LoadActivities): {
19+
case(ActivityManagementActionTypes.DELETE_ACTIVITY): {
20+
return {
21+
...state,
22+
message: 'Activity removed successfully!'
23+
};
24+
}
25+
26+
case(ActivityManagementActionTypes.DELETE_ACTIVITY_SUCCESS): {
27+
const stateWithDeletedActivity = initialState;
28+
stateWithDeletedActivity.data = state.data.filter(activity => activity.id !== action.activityId);
29+
return {
30+
...stateWithDeletedActivity,
31+
message: 'Activity removed successfully!'
32+
};
33+
}
34+
35+
case(ActivityManagementActionTypes.LOAD_ACTIVITIES): {
2036
return {
2137
...state,
2238
isLoading: true
2339
};
2440
}
2541

26-
case ActivityManagementActionTypes.LoadActivitiesSuccess: {
42+
case ActivityManagementActionTypes.LOAD_ACTIVITIES_SUCCESS: {
2743
return {
2844
...state,
2945
data: action.payload,
3046
isLoading: false,
3147
message: 'Data fetch successfully!'
3248
};
3349
}
34-
case ActivityManagementActionTypes.LoadActivitiesFail: {
50+
case ActivityManagementActionTypes.LOAD_ACTIVITIES_FAIL: {
3551
return { data: [], isLoading: false, message: 'Something went wrong fetching activities!' };
3652
}
3753
}

0 commit comments

Comments
 (0)