Skip to content

Commit 71b59cf

Browse files
authored
Merge pull request #77 from ioet/44-Save-activities-using-API
closes #44
2 parents 9ec795a + fd44e10 commit 71b59cf

16 files changed

+271
-119
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,8 @@
44
background-image: $background-gradient-items;
55
color: white;
66
}
7+
8+
.scroll {
9+
max-height: 400px;
10+
overflow-y: auto;
11+
}

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

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

5-
import { allActivities } from '../../store';
65
import { LoadActivities } from './../../store/activity-management.actions';
76
import { ActivityState } from './../../store/activity-management.reducers';
7+
import { allActivities } from '../../store';
88
import { Activity } from '../../../shared/models';
99

10-
@Component({selector: 'app-activity-list', templateUrl: './activity-list.component.html', styleUrls: ['./activity-list.component.scss']})
10+
@Component({
11+
selector: 'app-activity-list',
12+
templateUrl: './activity-list.component.html',
13+
styleUrls: ['./activity-list.component.scss'],
14+
})
1115
export class ActivityListComponent implements OnInit {
12-
13-
@Input()activities: Activity[] = [];
16+
activities: Activity[] = [];
1417
public isLoading: boolean;
1518

16-
constructor(private store: Store<ActivityState>) { }
19+
constructor(private store: Store<ActivityState>) {}
1720

1821
ngOnInit() {
1922
this.store.dispatch(new LoadActivities());
2023
const activities$ = this.store.pipe(select(allActivities));
2124

22-
activities$.subscribe(response => {
25+
activities$.subscribe((response) => {
2326
this.isLoading = response.isLoading;
2427
this.activities = response.data;
2528
});
2629
}
27-
2830
}

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

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,48 @@
11
import { FormBuilder } from '@angular/forms';
2-
import { async, TestBed } from '@angular/core/testing';
2+
import { async, TestBed, ComponentFixture } from '@angular/core/testing';
3+
import { provideMockStore, MockStore } from '@ngrx/store/testing';
34

45
import { CreateActivityComponent } from './create-activity.component';
6+
import { ActivityState, CreateActivity } from '../../store';
7+
import { Activity } from 'src/app/modules/shared/models';
58

69
describe('CreateActivityComponent', () => {
7-
810
let component: CreateActivityComponent;
11+
let fixture: ComponentFixture<CreateActivityComponent>;
12+
let store: MockStore<ActivityState>;
13+
14+
const state = { data: [{ id: 'id', name: 'name', description: 'description' }], isLoading: false, message: '' };
915

10-
const data = {
11-
name: '',
12-
description: ''
16+
const data: Activity[] = [
17+
{
18+
id: '1',
19+
name: 'Training',
20+
description: 'It is good for learning',
21+
},
22+
];
23+
24+
const activity: Activity = {
25+
id: '1',
26+
name: 'Training',
27+
description: 'It is good for learning',
1328
};
1429

1530
beforeEach(async(() => {
1631
TestBed.configureTestingModule({
17-
declarations: [ CreateActivityComponent],
18-
providers: [ FormBuilder ]
19-
});
20-
component = TestBed.createComponent(CreateActivityComponent).componentInstance;
32+
declarations: [CreateActivityComponent],
33+
providers: [FormBuilder, provideMockStore({ initialState: state })],
34+
}).compileComponents();
2135
}));
2236

37+
beforeEach(() => {
38+
fixture = TestBed.createComponent(CreateActivityComponent);
39+
component = fixture.componentInstance;
40+
fixture.detectChanges();
41+
42+
store = TestBed.inject(MockStore);
43+
store.setState(state);
44+
});
45+
2346
it('should create the component', () => {
2447
expect(component).toBeTruthy();
2548
});
@@ -48,4 +71,10 @@ describe('CreateActivityComponent', () => {
4871
expect(component.activityForm.get).toHaveBeenCalledWith('description');
4972
});
5073

74+
it('should dispatch createActivity action #onSubmit', () => {
75+
spyOn(store, 'dispatch');
76+
component.onSubmit(activity);
77+
expect(store.dispatch).toHaveBeenCalledTimes(1);
78+
expect(store.dispatch).toHaveBeenCalledWith(new CreateActivity(activity));
79+
});
5180
});

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

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { FormBuilder, Validators, FormGroup } from '@angular/forms';
2-
import { Component, Input } from '@angular/core';
2+
import { Component, Input, EventEmitter, Output } from '@angular/core';
3+
import { Store, select } from '@ngrx/store';
34
import { Activity } from '../../../shared/models';
5+
import { ActivityState } from './../../store/activity-management.reducers';
6+
import { CreateActivity, allActivities } from '../../store';
47

58
@Component({
69
selector: 'app-create-activity',
@@ -9,22 +12,18 @@ import { Activity } from '../../../shared/models';
912
})
1013
export class CreateActivityComponent {
1114
activityForm: FormGroup;
15+
isLoading: boolean;
1216

13-
@Input()
14-
activityToEdit: Activity;
15-
16-
constructor(private formBuilder: FormBuilder) {
17+
constructor(private formBuilder: FormBuilder, private store: Store<ActivityState>) {
1718
this.activityForm = this.formBuilder.group({
1819
name: ['', Validators.required],
1920
description: [''],
2021
});
2122
}
2223

2324
onSubmit(activityData) {
24-
// TODO: add proper interaction with API to save this info
25-
// see https://github.com/ioet/time-tracker-ui/issues/44
26-
console.log(activityData);
2725
this.activityForm.reset();
26+
this.store.dispatch(new CreateActivity(activityData));
2827
}
2928

3029
get name() {
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
<div class="parent">
2-
<app-create-activity class="item">
3-
</app-create-activity>
2+
<app-create-activity class="item"> </app-create-activity>
43

5-
<app-activity-list [activities]="activities" class="item">
6-
</app-activity-list>
4+
<app-activity-list class="item"> </app-activity-list>
75
</div>

src/app/modules/activities-management/pages/activities-management.component.spec.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ import { ActivitiesManagementComponent } from './activities-management.component
88
describe('ActivitiesManagementComponent', () => {
99
let component: ActivitiesManagementComponent;
1010
let activityService: ActivityService;
11-
const activitiesFromApi: Activity[] = [{id: '123', name: 'aaa', description: 'xxx'}];
11+
const activitiesFromApi: Activity[] = [{ id: '123', name: 'aaa', description: 'xxx' }];
1212

1313
beforeEach(async(() => {
1414
TestBed.configureTestingModule({
15-
declarations: [ ActivitiesManagementComponent],
16-
providers: [ ActivityService, HttpClient, HttpHandler ]
15+
declarations: [ActivitiesManagementComponent],
16+
providers: [ActivityService, HttpClient, HttpHandler],
1717
});
1818
component = TestBed.createComponent(ActivitiesManagementComponent).componentInstance;
1919
activityService = TestBed.inject(ActivityService);
@@ -23,9 +23,4 @@ describe('ActivitiesManagementComponent', () => {
2323
it('should create the component', () => {
2424
expect(component).toBeTruthy();
2525
});
26-
27-
it('should load activities', () => {
28-
component.ngOnInit();
29-
expect(component.activities).toBe(activitiesFromApi);
30-
});
3126
});

src/app/modules/activities-management/pages/activities-management.component.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,10 @@ import { Activity } from '../../shared/models';
55
@Component({
66
selector: 'app-activities-management',
77
templateUrl: './activities-management.component.html',
8-
styleUrls: ['./activities-management.component.scss']
8+
styleUrls: ['./activities-management.component.scss'],
99
})
1010
export class ActivitiesManagementComponent implements OnInit {
11+
constructor(private activityService: ActivityService) {}
1112

12-
constructor(private activityService: ActivityService) { }
13-
14-
activities: Activity[];
15-
16-
ngOnInit(): void {
17-
this.activityService.getActivities().subscribe( data => this.activities = data );
18-
}
13+
ngOnInit(): void {}
1914
}

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

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ describe('Activity Service', () => {
99
let httpMock: HttpTestingController;
1010

1111
const activities: Activity[] = [
12-
{ id: '1', name: 'aaa', description: 'xxx' },
13-
{ id: '2', name: 'bbb', description: 'yyy' }
12+
{ id: '1', name: 'aaa', description: 'xxx' },
13+
{ id: '2', name: 'bbb', description: 'yyy' },
1414
];
1515

1616
beforeEach(() => {
17-
TestBed.configureTestingModule({imports: [HttpClientTestingModule]});
17+
TestBed.configureTestingModule({ imports: [HttpClientTestingModule] });
1818
service = TestBed.inject(ActivityService);
1919
httpMock = TestBed.inject(HttpTestingController);
2020
});
@@ -23,22 +23,35 @@ describe('Activity Service', () => {
2323
httpMock.verify();
2424
});
2525

26-
it('services are ready to be used', inject([ HttpClientTestingModule, ActivityService ],
26+
it('services are ready to be used', inject(
27+
[HttpClientTestingModule, ActivityService],
2728
(httpClient: HttpClientTestingModule, activityService: ActivityService) => {
28-
expect(activityService).toBeTruthy();
29-
expect(httpClient).toBeTruthy();
30-
}));
29+
expect(activityService).toBeTruthy();
30+
expect(httpClient).toBeTruthy();
31+
}
32+
));
3133

3234
it('activities are read using GET from baseUrl', () => {
3335
const activitiesFoundSize = activities.length;
3436
service.baseUrl = 'foo';
35-
service
36-
.getActivities()
37-
.subscribe(activitiesInResponse => {
38-
expect(activitiesInResponse.length).toBe(activitiesFoundSize);
39-
});
37+
service.getActivities().subscribe((activitiesInResponse) => {
38+
expect(activitiesInResponse.length).toBe(activitiesFoundSize);
39+
});
4040
const getActivitiesRequest = httpMock.expectOne(service.baseUrl);
4141
expect(getActivitiesRequest.request.method).toBe('GET');
4242
getActivitiesRequest.flush(activities);
4343
});
44+
45+
it('create activity using POST from baseUrl', () => {
46+
const activity: Activity[] = [{ id: '1', name: 'ccc', description: 'xxx' }];
47+
48+
service.baseUrl = 'activities';
49+
50+
service.createActivity(activity).subscribe((response) => {
51+
expect(response.length).toBe(1);
52+
});
53+
const createActivitiesRequest = httpMock.expectOne(service.baseUrl);
54+
expect(createActivitiesRequest.request.method).toBe('POST');
55+
createActivitiesRequest.flush(activity);
56+
});
4457
});
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
11
import { Injectable } from '@angular/core';
2-
import { HttpClient } from '@angular/common/http';
2+
import { HttpClient, HttpHeaders } from '@angular/common/http';
33
import { Observable } from 'rxjs';
44

55
import { environment } from './../../../../environments/environment';
66
import { Activity } from '../../shared/models';
77

88
@Injectable({
9-
providedIn: 'root'
9+
providedIn: 'root',
1010
})
1111
export class ActivityService {
12-
1312
baseUrl = `${environment.timeTrackerApiUrl}/activities`;
1413

1514
constructor(private http: HttpClient) {}
1615

1716
getActivities(): Observable<Activity[]> {
1817
return this.http.get<Activity[]>(this.baseUrl);
1918
}
19+
20+
createActivity(activityData): Observable<any> {
21+
const body = {
22+
...activityData,
23+
tenant_id: '4225ab1e-1033-4a5f-8650-0dd4950f38c8',
24+
};
25+
26+
return this.http.post(this.baseUrl, body);
27+
}
2028
}
Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,28 @@
1-
import { LoadActivitiesFail } from './activity-management.actions';
1+
import { LoadActivitiesFail, CreateActivitySuccess, CreateActivityFail } from './activity-management.actions';
22
import { LoadActivitiesSuccess, ActivityManagementActionTypes } from './activity-management.actions';
33

44
describe('LoadActivitiesSuccess', () => {
5-
6-
it('LoadActivitiesSuccess type is ActivityManagementActionTypes.LoadActivitiesSuccess', () => {
5+
it('LoadActivitiesSuccess type is ActivityManagementActionTypes.LOAD_ACTIVITIES_SUCCESS', () => {
76
const loadActivitiesSuccess = new LoadActivitiesSuccess([]);
8-
expect(loadActivitiesSuccess.type).toEqual(ActivityManagementActionTypes.LoadActivitiesSuccess);
7+
expect(loadActivitiesSuccess.type).toEqual(ActivityManagementActionTypes.LOAD_ACTIVITIES_SUCCESS);
98
});
109

11-
it('LoadActivitiesFail type is ActivityManagementActionTypes.LoadActivitiesFail', () => {
10+
it('LoadActivitiesFail type is ActivityManagementActionTypes.LOAD_ACTIVITIES_FAIL', () => {
1211
const loadActivitiesFail = new LoadActivitiesFail('error');
13-
expect(loadActivitiesFail.type).toEqual(ActivityManagementActionTypes.LoadActivitiesFail);
12+
expect(loadActivitiesFail.type).toEqual(ActivityManagementActionTypes.LOAD_ACTIVITIES_FAIL);
13+
});
14+
15+
it('CreateActivitySuccess type is ActivityManagementActionTypes.CREATE_ACTIVITY_SUCCESS', () => {
16+
const createActivitySuccess = new CreateActivitySuccess({
17+
id: '1',
18+
name: 'Training',
19+
description: 'It is good for learning',
20+
});
21+
expect(createActivitySuccess.type).toEqual(ActivityManagementActionTypes.CREATE_ACTIVITY_SUCCESS);
1422
});
1523

24+
it('CreateActivityFail type is ActivityManagementActionTypes.CREATE_ACTIVITY_FAIL', () => {
25+
const createActivityFail = new CreateActivityFail('error');
26+
expect(createActivityFail.type).toEqual(ActivityManagementActionTypes.CREATE_ACTIVITY_FAIL);
27+
});
1628
});

0 commit comments

Comments
 (0)