Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
fix: #364 stop current working time
  • Loading branch information
enriquezrene committed Jun 9, 2020
commit 7daab28d41a4236c7f6e255bc518acd7df2cbb17
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class ProjectEffects {
mergeMap((project) =>
this.projectService.createProject(project).pipe(
map((projectData) => {
this.toastrService.success(INFO_DELETE_SUCCESSFULLY);
this.toastrService.success(INFO_SAVED_SUCCESSFULLY);
return new actions.CreateProjectSuccess(projectData);
}),
catchError((error) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,7 @@ export class ProjectListHoverComponent implements OnInit {
this.store.dispatch(new entryActions.CreateEntry(newEntry));
}
this.store.dispatch(new entryActions.LoadEntries(new Date().getMonth() + 1 ));
this.loadActiveTimeEntry();
}

}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { interval } from 'rxjs';
import { EntryActionTypes } from './../../store/entry.actions';
import { EntryState } from './../../store/entry.reducer';
import { TimeDetailsPipe } from './../../pipes/time-details.pipe';
import { provideMockStore, MockStore } from '@ngrx/store/testing';
Expand All @@ -6,6 +8,7 @@ import { TimeDetails } from './../../models/time.entry.summary';
import { async, ComponentFixture, TestBed, tick, fakeAsync, discardPeriodicTasks } from '@angular/core/testing';

import { TimeEntriesSummaryComponent } from './time-entries-summary.component';
import { ActionsSubject } from '@ngrx/store';

describe('TimeEntriesSummaryComponent', () => {
let component: TimeEntriesSummaryComponent;
Expand All @@ -17,6 +20,7 @@ describe('TimeEntriesSummaryComponent', () => {

const timeTwoHoursBehind = new Date();
timeTwoHoursBehind.setHours(timeTwoHoursBehind.getHours() - 2);
const actionSub: ActionsSubject = new ActionsSubject();

const timeEntry = {
id: '123',
Expand Down Expand Up @@ -44,8 +48,7 @@ describe('TimeEntriesSummaryComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ TimeEntriesSummaryComponent, TimeDetailsPipe ],
providers: [provideMockStore({ initialState: state })
],
providers: [provideMockStore({ initialState: state }), { provide: ActionsSubject, useValue: actionSub }],
})
.compileComponents();
store = TestBed.inject(MockStore);
Expand All @@ -62,6 +65,64 @@ describe('TimeEntriesSummaryComponent', () => {
expect(component).toBeTruthy();
});


const params = [
{ actionType: EntryActionTypes.LOAD_ACTIVE_ENTRY_FAIL },
{ actionType: EntryActionTypes.STOP_TIME_ENTRY_RUNNING_SUCCESS },
{ actionType: EntryActionTypes.CREATE_ENTRY_SUCCESS },
];

params.map((param) => {
it(`calls blankCurrentWorkingTime when ${param.actionType}`, () => {
const actionSubject = TestBed.inject(ActionsSubject) as ActionsSubject;
const action = {
type: param.actionType,
};
spyOn(component, 'blankCurrentWorkingTime');

actionSubject.next(action);

expect(component.blankCurrentWorkingTime).toHaveBeenCalled();
});
});

it('sets destroyed to false when timeInterval is not null', () => {
spyOn(component.destroyed$, 'next');
component.timeInterval = interval(1).subscribe();

component.updateCurrentWorkingHours(timeEntry);

expect(component.destroyed$.next).toHaveBeenCalledWith(false);
});

it('does not change currentWorkingTime if entry is null', () => {
const initialWorkingTime = 'foo';
component.currentWorkingTime = initialWorkingTime;

component.updateCurrentWorkingHours(null);

expect(component.currentWorkingTime).toBe(initialWorkingTime);
});

it('sets --:-- to currentWorkingTime', () => {
component.blankCurrentWorkingTime();

expect(component.currentWorkingTime).toBe('--:--');
});

it('calls updateCurrentWorkingHours when LOAD_ACTIVE_ENTRY_SUCCESS', () => {
const actionSubject = TestBed.inject(ActionsSubject) as ActionsSubject;
const action = {
type: EntryActionTypes.LOAD_ACTIVE_ENTRY_SUCCESS,
payload: timeEntry
};
spyOn(component, 'updateCurrentWorkingHours');

actionSubject.next(action);

expect(component.updateCurrentWorkingHours).toHaveBeenCalledWith(timeEntry);
});

it('dispatches two actions on ngOnInit', () => {
spyOn(store, 'dispatch');

Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,75 @@
import { filter, takeUntil } from 'rxjs/operators';
import { SubstractDatePipe } from './../../../shared/pipes/substract-date/substract-date.pipe';
import { interval } from 'rxjs';
import { interval, Subscription, Subject } from 'rxjs';
import { Entry } from './../../../shared/models/entry.model';
import { getEntriesSummary, getActiveTimeEntry } from './../../store/entry.selectors';
import { getEntriesSummary } from './../../store/entry.selectors';
import { TimeEntriesSummary } from '../../models/time.entry.summary';
import { LoadEntriesSummary, LoadActiveEntry } from './../../store/entry.actions';
import { LoadEntriesSummary, LoadActiveEntry, EntryActionTypes } from './../../store/entry.actions';
import { EntryState } from './../../store/entry.reducer';
import { Store, select } from '@ngrx/store';
import { Component, OnInit } from '@angular/core';
import { Store, select, ActionsSubject } from '@ngrx/store';
import { Component, OnInit, OnDestroy } from '@angular/core';

@Component({
selector: 'app-time-entries-summary',
templateUrl: './time-entries-summary.component.html',
styleUrls: ['./time-entries-summary.component.css']
})
export class TimeEntriesSummaryComponent implements OnInit {
export class TimeEntriesSummaryComponent implements OnInit, OnDestroy {

timeEntriesSummary: TimeEntriesSummary;
currentWorkingTime: string;
destroyed$ = new Subject<boolean>();

constructor(private store: Store<EntryState>) { }
loadActiveEntry: Subscription;
loadActiveEntryLost: Subscription;
stopEntry: Subscription;
startEntry: Subscription;
timeInterval;

constructor(private store: Store<EntryState>, private actionsSubject$: ActionsSubject) { }

ngOnDestroy(): void {
this.loadActiveEntry.unsubscribe();
this.loadActiveEntryLost.unsubscribe();
this.stopEntry.unsubscribe();
this.startEntry.unsubscribe();
}

ngOnInit(): void {
this.store.dispatch(new LoadActiveEntry());
const activeTimeEntry$ = this.store.pipe(select(getActiveTimeEntry));
activeTimeEntry$.subscribe((response) => {
if (response) {
this.updateCurrentWorkingHours(response);
}

this.loadActiveEntryLost = this.actionsSubject$.pipe(
filter((action: any) => (
action.type === EntryActionTypes.LOAD_ACTIVE_ENTRY_FAIL
))
).subscribe(() => {
this.blankCurrentWorkingTime();
});

this.loadActiveEntry = this.actionsSubject$.pipe(
filter((action: any) => (
action.type === EntryActionTypes.LOAD_ACTIVE_ENTRY_SUCCESS
))
).subscribe((action) => {
this.updateCurrentWorkingHours(action.payload);
});

this.stopEntry = this.actionsSubject$.pipe(
filter((action: any) => (
action.type === EntryActionTypes.STOP_TIME_ENTRY_RUNNING_SUCCESS
))
).subscribe(() => {
this.destroyed$.next(true);
this.blankCurrentWorkingTime();
});

this.startEntry = this.actionsSubject$.pipe(
filter((action: any) => (
action.type === EntryActionTypes.CREATE_ENTRY_SUCCESS
))
).subscribe(() => {
this.store.dispatch(new LoadActiveEntry());
this.blankCurrentWorkingTime();
});

this.store.dispatch(new LoadEntriesSummary());
Expand All @@ -36,13 +79,20 @@ export class TimeEntriesSummaryComponent implements OnInit {
});
}

blankCurrentWorkingTime() {
this.currentWorkingTime = '--:--';
}

updateCurrentWorkingHours(entry: Entry) {
const timeInterval = interval(1000);
timeInterval.subscribe(() => {
this.currentWorkingTime =
new SubstractDatePipe()
.transform(new Date(), new Date(entry.start_date));
});
if (this.timeInterval) {
this.destroyed$.next(false);
}
if (entry) {
this.timeInterval = interval(1000).pipe(
takeUntil(this.destroyed$)
).subscribe(() => {
this.currentWorkingTime = new SubstractDatePipe().transform(new Date(), new Date(entry.start_date));
});
}
}
}
2 changes: 1 addition & 1 deletion src/app/modules/time-clock/store/entry.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export class StopTimeEntryRunning implements Action {

export class StopTimeEntryRunningSuccess implements Action {
public readonly type = EntryActionTypes.STOP_TIME_ENTRY_RUNNING_SUCCESS;
constructor(readonly payload: string) {}
constructor(readonly payload) {}
}

export class StopTimeEntryRunningFail implements Action {
Expand Down
4 changes: 2 additions & 2 deletions src/app/modules/time-clock/store/entry.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ export class EntryEffects {
map((action: actions.StopTimeEntryRunning) => action.payload),
mergeMap((timeEntryId) =>
this.entryService.stopEntryRunning(timeEntryId).pipe(
map(() => {
map((response) => {
this.toastrService.success('You clocked-out successfully');
return new actions.StopTimeEntryRunningSuccess(timeEntryId);
return new actions.StopTimeEntryRunningSuccess(response);
}),
catchError((error) => {
this.toastrService.error(error.error.message);
Expand Down