Skip to content

Commit fcfb957

Browse files
authored
Merge pull request #353 from ioet/284-show-current-working-time
fix: #285 display current working time in time-clock screen
2 parents f655c1e + bafefe6 commit fcfb957

File tree

5 files changed

+106
-15
lines changed

5 files changed

+106
-15
lines changed
Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
<h6 class="text-left"><strong>Summary</strong></h6>
22
<hr />
33
<div class="row pb-4">
4-
<div class="col-4">
4+
<div class="col-3">
5+
<h6>Current</h6>
6+
<h3>{{ currentWorkingTime }}</h3>
7+
</div>
8+
<div class="col-3">
59
<h6>Day</h6>
6-
<h3>{{ timeEntriesSummary.day | timeDetails }}</h3>
10+
<h3>{{ timeEntriesSummary?.day | timeDetails }}</h3>
711
</div>
8-
<div class="col-4">
12+
<div class="col-3">
913
<h6>Week</h6>
10-
<h3>{{ timeEntriesSummary.week | timeDetails }}</h3>
14+
<h3>{{ timeEntriesSummary?.week | timeDetails }}</h3>
1115
</div>
12-
<div class="col-4">
16+
<div class="col-3">
1317
<h6>Month</h6>
14-
<h3>{{ timeEntriesSummary.month | timeDetails }}</h3>
18+
<h3>{{ timeEntriesSummary?.month | timeDetails }}</h3>
1519
</div>
1620
</div>
Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,44 @@
1+
import { EntryState } from './../../store/entry.reducer';
12
import { TimeDetailsPipe } from './../../pipes/time-details.pipe';
2-
import { provideMockStore } from '@ngrx/store/testing';
3+
import { provideMockStore, MockStore } from '@ngrx/store/testing';
34
import { TimeEntriesSummary } from './../../models/time.entry.summary';
45
import { TimeDetails } from './../../models/time.entry.summary';
5-
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
6+
import { async, ComponentFixture, TestBed, tick, fakeAsync, discardPeriodicTasks } from '@angular/core/testing';
67

78
import { TimeEntriesSummaryComponent } from './time-entries-summary.component';
89

910
describe('TimeEntriesSummaryComponent', () => {
1011
let component: TimeEntriesSummaryComponent;
1112
let fixture: ComponentFixture<TimeEntriesSummaryComponent>;
12-
13+
let store: MockStore<EntryState>;
1314

1415
const emptyTimeDetails: TimeDetails = { hours: '--:--', minutes: '--:--', seconds: '--:--' };
1516
const emptyTimeEntriesSummary: TimeEntriesSummary = { day: emptyTimeDetails, week: emptyTimeDetails, month: emptyTimeDetails };
1617

18+
const timeTwoHoursBehind = new Date();
19+
timeTwoHoursBehind.setHours(timeTwoHoursBehind.getHours() - 2);
20+
21+
const timeEntry = {
22+
id: '123',
23+
start_date: timeTwoHoursBehind,
24+
end_date: null,
25+
activity_id: '123',
26+
technologies: ['react', 'redux'],
27+
comments: 'any comment',
28+
uri: 'custom uri',
29+
project_id: '123'
30+
};
31+
1732
const state = {
18-
entries: {
19-
timeEntriesSummary: emptyTimeEntriesSummary
20-
},
33+
active: timeEntry,
34+
entryList: [timeEntry],
35+
entries: [timeEntry],
36+
isLoading: false,
37+
message: '',
38+
createError: false,
39+
updateError: false,
40+
timeEntriesSummary: emptyTimeEntriesSummary,
41+
entriesForReport: [timeEntry],
2142
};
2243

2344
beforeEach(async(() => {
@@ -27,15 +48,38 @@ describe('TimeEntriesSummaryComponent', () => {
2748
],
2849
})
2950
.compileComponents();
51+
store = TestBed.inject(MockStore);
3052
}));
3153

3254
beforeEach(() => {
3355
fixture = TestBed.createComponent(TimeEntriesSummaryComponent);
3456
component = fixture.componentInstance;
3557
fixture.detectChanges();
58+
store.setState(state);
3659
});
3760

3861
it('should create', () => {
3962
expect(component).toBeTruthy();
4063
});
64+
65+
it('dispatches two actions on ngOnInit', () => {
66+
spyOn(store, 'dispatch');
67+
68+
component.ngOnInit();
69+
70+
expect(store.dispatch).toHaveBeenCalledTimes(2);
71+
});
72+
73+
it('runs the time on updateCurrentWorkingHours', fakeAsync(() => {
74+
component.updateCurrentWorkingHours(timeEntry);
75+
76+
tick(1100);
77+
fixture.detectChanges();
78+
79+
const elapsedTime = component.currentWorkingTime;
80+
const isElapsedTimeAtLeastTwoHours = elapsedTime.startsWith('02:00');
81+
expect(isElapsedTimeAtLeastTwoHours).toBe(true);
82+
discardPeriodicTasks();
83+
}));
84+
4185
});

src/app/modules/time-clock/components/time-entries-summary/time-entries-summary.component.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import { getEntriesSummary } from './../../store/entry.selectors';
1+
import { SubstractDatePipe } from './../../../shared/pipes/substract-date/substract-date.pipe';
2+
import { interval } from 'rxjs';
3+
import { Entry } from './../../../shared/models/entry.model';
4+
import { getEntriesSummary, getActiveTimeEntry } from './../../store/entry.selectors';
25
import { TimeEntriesSummary } from '../../models/time.entry.summary';
3-
import { LoadEntriesSummary } from './../../store/entry.actions';
6+
import { LoadEntriesSummary, LoadActiveEntry } from './../../store/entry.actions';
47
import { EntryState } from './../../store/entry.reducer';
58
import { Store, select } from '@ngrx/store';
69
import { Component, OnInit } from '@angular/core';
@@ -13,15 +16,33 @@ import { Component, OnInit } from '@angular/core';
1316
export class TimeEntriesSummaryComponent implements OnInit {
1417

1518
timeEntriesSummary: TimeEntriesSummary;
19+
currentWorkingTime: string;
1620

1721
constructor(private store: Store<EntryState>) { }
1822

1923
ngOnInit(): void {
24+
this.store.dispatch(new LoadActiveEntry());
25+
const activeTimeEntry$ = this.store.pipe(select(getActiveTimeEntry));
26+
activeTimeEntry$.subscribe((response) => {
27+
if (response) {
28+
this.updateCurrentWorkingHours(response);
29+
}
30+
});
31+
2032
this.store.dispatch(new LoadEntriesSummary());
2133
const timeEntriesSummary$ = this.store.pipe(select(getEntriesSummary));
2234
timeEntriesSummary$.subscribe((response) => {
2335
this.timeEntriesSummary = response;
2436
});
2537
}
2638

39+
40+
updateCurrentWorkingHours(entry: Entry) {
41+
const timeInterval = interval(1000);
42+
timeInterval.subscribe(() => {
43+
this.currentWorkingTime =
44+
new SubstractDatePipe()
45+
.transform(new Date(), new Date(entry.start_date));
46+
});
47+
}
2748
}

src/app/modules/time-clock/pipes/time-details.pipe.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { TimeDetails } from './../models/time.entry.summary';
12
import { TimeDetailsPipe } from './time-details.pipe';
23

34
describe('TimeDetailsPipe', () => {
@@ -10,4 +11,21 @@ describe('TimeDetailsPipe', () => {
1011
const pipe = new TimeDetailsPipe();
1112
expect(pipe.formatAsTwoDigit('5')).toBe('05');
1213
});
14+
15+
it('returns the same data if number has 2 digits', () => {
16+
const pipe = new TimeDetailsPipe();
17+
expect(pipe.formatAsTwoDigit('15')).toBe('15');
18+
});
19+
20+
it('formats hour in expected format', () => {
21+
const timeDetails = { hours: '1', minutes: '9', seconds: '00'};
22+
const pipe = new TimeDetailsPipe();
23+
expect('01:09').toBe(pipe.transform(timeDetails));
24+
});
25+
26+
it('returns --:-- when timeDetails is null', () => {
27+
const timeDetails = null;
28+
const pipe = new TimeDetailsPipe();
29+
expect('--:--').toBe(pipe.transform(timeDetails));
30+
});
1331
});

src/app/modules/time-clock/pipes/time-details.pipe.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ import { Pipe, PipeTransform } from '@angular/core';
77
export class TimeDetailsPipe implements PipeTransform {
88

99
transform(value: TimeDetails): string {
10-
return `${this.formatAsTwoDigit(value.hours)}:${this.formatAsTwoDigit(value.minutes)}` ;
10+
if (value) {
11+
return `${this.formatAsTwoDigit(value.hours)}:${this.formatAsTwoDigit(value.minutes)}`;
12+
} else {
13+
return '--:--';
14+
}
1115
}
1216

1317
formatAsTwoDigit(time: string): string {

0 commit comments

Comments
 (0)