diff --git a/src/app/modules/shared/pipes/substract-date/substract-date.pipe.spec.ts b/src/app/modules/shared/pipes/substract-date/substract-date.pipe.spec.ts index a9ec16b14..b2db647e2 100644 --- a/src/app/modules/shared/pipes/substract-date/substract-date.pipe.spec.ts +++ b/src/app/modules/shared/pipes/substract-date/substract-date.pipe.spec.ts @@ -15,6 +15,15 @@ describe('SubstractDatePipe', () => { expect(diff).toBe('02:20'); }); + it('returns the date diff using hh:mm:ss for a diff < 1 min when displaySeconds is true', () => { + const fromDate = new Date('2011-04-11T10:22:40Z'); + const substractDate = new Date('2011-04-11T10:20:30Z'); + + const diff = new SubstractDatePipe().transform(fromDate, substractDate, true); + + expect(diff).toBe('00:02:10'); + }); + it('returns the date diff including seconds if difference is less than a minute', () => { const fromDate = new Date('2011-04-11T10:20:40Z'); const substractDate = new Date('2011-04-11T10:20:30Z'); diff --git a/src/app/modules/shared/pipes/substract-date/substract-date.pipe.ts b/src/app/modules/shared/pipes/substract-date/substract-date.pipe.ts index 8791d3741..6ca03db08 100644 --- a/src/app/modules/shared/pipes/substract-date/substract-date.pipe.ts +++ b/src/app/modules/shared/pipes/substract-date/substract-date.pipe.ts @@ -6,7 +6,7 @@ import * as moment from 'moment'; }) export class SubstractDatePipe implements PipeTransform { - transform(fromDate: Date, substractDate: Date): string { + transform(fromDate: Date, substractDate: Date, displaySeconds: boolean = false): string { if (fromDate === null || substractDate === null ) { return '--:--'; @@ -16,7 +16,7 @@ export class SubstractDatePipe implements PipeTransform { let endDate = moment(fromDate, 'YYYY-MM-DD HH:mm:ss'); let duration: moment.Duration = moment.duration(endDate.diff(startDate)); - if (duration.asSeconds() > 60) { + if (duration.asSeconds() > 60 && !displaySeconds) { endDate = endDate.add(1, 'minute').startOf('minute'); duration = moment.duration(endDate.diff(startDate)); return `${ this.formatTime(duration.hours())}:${this.formatTime(duration.minutes()) }`; diff --git a/src/app/modules/time-clock/components/time-entries-summary/time-entries-summary.component.ts b/src/app/modules/time-clock/components/time-entries-summary/time-entries-summary.component.ts index d8e56404e..9150d0128 100644 --- a/src/app/modules/time-clock/components/time-entries-summary/time-entries-summary.component.ts +++ b/src/app/modules/time-clock/components/time-entries-summary/time-entries-summary.component.ts @@ -91,7 +91,7 @@ export class TimeEntriesSummaryComponent implements OnInit, OnDestroy { this.timeInterval = interval(1000).pipe( takeUntil(this.destroyed$) ).subscribe(() => { - this.currentWorkingTime = new SubstractDatePipe().transform(new Date(), new Date(entry.start_date)); + this.currentWorkingTime = new SubstractDatePipe().transform(new Date(), new Date(entry.start_date), true); }); } } diff --git a/src/app/modules/time-clock/pages/time-clock.component.spec.ts b/src/app/modules/time-clock/pages/time-clock.component.spec.ts index 5ff044c4b..218d1eea1 100644 --- a/src/app/modules/time-clock/pages/time-clock.component.spec.ts +++ b/src/app/modules/time-clock/pages/time-clock.component.spec.ts @@ -1,5 +1,5 @@ import { FormBuilder } from '@angular/forms'; -import { StopTimeEntryRunning } from './../store/entry.actions'; +import { StopTimeEntryRunning, EntryActionTypes, LoadEntriesSummary } from './../store/entry.actions'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { HttpClientTestingModule } from '@angular/common/http/testing'; import { provideMockStore, MockStore } from '@ngrx/store/testing'; @@ -8,6 +8,7 @@ import { ProjectState } from '../../customer-management/components/projects/comp import { ProjectListHoverComponent } from '../components'; import { FilterProjectPipe } from '../../shared/pipes'; import { AzureAdB2CService } from '../../login/services/azure.ad.b2c.service'; +import { ActionsSubject } from '@ngrx/store'; import { EntryFieldsComponent } from '../components/entry-fields/entry-fields.component'; import { ToastrService } from 'ngx-toastr'; @@ -16,10 +17,13 @@ describe('TimeClockComponent', () => { let fixture: ComponentFixture; let store: MockStore; let azureAdB2CService: AzureAdB2CService; + const actionSub: ActionsSubject = new ActionsSubject(); + let injectedToastrService; const toastrService = { error: () => {}, }; + const state = { projects: { projects: [{ id: 'id', name: 'name', project_type_id: '' }], @@ -52,6 +56,7 @@ describe('TimeClockComponent', () => { FormBuilder, AzureAdB2CService, provideMockStore({ initialState: state }), + { provide: ActionsSubject, useValue: actionSub }, { provide: ToastrService, useValue: toastrService }, ], }).compileComponents(); @@ -70,6 +75,34 @@ describe('TimeClockComponent', () => { expect(component).toBeTruthy(); }); + it('on STOP_TIME_ENTRY_RUNNING_SUCCESS summaries are reloaded', () => { + const actionSubject = TestBed.inject(ActionsSubject) as ActionsSubject; + const action = { + type: EntryActionTypes.STOP_TIME_ENTRY_RUNNING_SUCCESS + }; + spyOn(store, 'dispatch'); + + actionSubject.next(action); + + expect(store.dispatch).toHaveBeenCalledWith(new LoadEntriesSummary()); + }); + + it('register reloadSummaries on ngOnInit', () => { + spyOn(component, 'reloadSummariesOnClockOut'); + + component.ngOnInit(); + + expect(component.reloadSummariesOnClockOut).toHaveBeenCalled(); + }); + + it('unsubscribe clockOutSubscription onDestroy', () => { + spyOn(component.clockOutSubscription, 'unsubscribe'); + + component.ngOnDestroy(); + + expect(component.clockOutSubscription.unsubscribe).toHaveBeenCalled(); + }); + it('onInit checks if isLogin and gets the userName', () => { spyOn(azureAdB2CService, 'isLogin').and.returnValue(true); spyOn(azureAdB2CService, 'getName').and.returnValue('Name'); diff --git a/src/app/modules/time-clock/pages/time-clock.component.ts b/src/app/modules/time-clock/pages/time-clock.component.ts index cd64153dc..8d1bf8f50 100644 --- a/src/app/modules/time-clock/pages/time-clock.component.ts +++ b/src/app/modules/time-clock/pages/time-clock.component.ts @@ -1,8 +1,9 @@ +import { filter } from 'rxjs/operators'; import { getActiveTimeEntry } from './../store/entry.selectors'; -import { StopTimeEntryRunning } from './../store/entry.actions'; +import { StopTimeEntryRunning, EntryActionTypes, LoadEntriesSummary } from './../store/entry.actions'; import { Entry } from './../../shared/models/entry.model'; -import { Store, select } from '@ngrx/store'; -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Store, select, ActionsSubject } from '@ngrx/store'; +import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core'; import { AzureAdB2CService } from '../../login/services/azure.ad.b2c.service'; import { Subscription } from 'rxjs'; import { EntryFieldsComponent } from '../components/entry-fields/entry-fields.component'; @@ -12,20 +13,26 @@ import { ToastrService } from 'ngx-toastr'; templateUrl: './time-clock.component.html', styleUrls: ['./time-clock.component.scss'], }) -export class TimeClockComponent implements OnInit { +export class TimeClockComponent implements OnInit, OnDestroy { @ViewChild(EntryFieldsComponent) entryFieldsComponent: EntryFieldsComponent; username: string; areFieldsVisible = false; activeTimeEntry: Entry; - actionsSubscription: Subscription; + clockOutSubscription: Subscription; + constructor( private azureAdB2CService: AzureAdB2CService, private store: Store, - private toastrService: ToastrService + private toastrService: ToastrService, + private actionsSubject$: ActionsSubject ) {} + ngOnDestroy(): void { + this.clockOutSubscription.unsubscribe(); + } + ngOnInit() { this.username = this.azureAdB2CService.isLogin() ? this.azureAdB2CService.getName() : ''; this.store.pipe(select(getActiveTimeEntry)).subscribe((activeTimeEntry) => { @@ -36,6 +43,20 @@ export class TimeClockComponent implements OnInit { this.areFieldsVisible = false; } }); + + this.reloadSummariesOnClockOut(); + + } + + reloadSummariesOnClockOut() { + this.clockOutSubscription = this.actionsSubject$.pipe( + filter((action) => ( + action.type === EntryActionTypes.STOP_TIME_ENTRY_RUNNING_SUCCESS + ) + ) + ).subscribe( (action) => { + this.store.dispatch(new LoadEntriesSummary()); + }); } stopEntry() {