Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Subscription } from 'rxjs';
import { LoadActiveEntry, EntryActionTypes, UpdateEntry } from './../../store/entry.actions';
import { ActivityManagementActionTypes } from './../../../activities-management/store/activity-management.actions';
import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
import {MockStore, provideMockStore} from '@ngrx/store/testing';
import { FormsModule, ReactiveFormsModule, FormBuilder } from '@angular/forms';

import {TechnologyState} from '../../../shared/store/technology.reducers';
import {allTechnologies} from '../../../shared/store/technology.selectors';
import {EntryFieldsComponent} from './entry-fields.component';
Expand Down Expand Up @@ -135,9 +135,7 @@ describe('EntryFieldsComponent', () => {
};

spyOn(component.entryForm, 'patchValue');

component.setDataToUpdate(entry);

expect(component.entryForm.patchValue).toHaveBeenCalledTimes(1);
expect(component.entryForm.patchValue).toHaveBeenCalledWith(
{
Expand All @@ -156,6 +154,7 @@ describe('EntryFieldsComponent', () => {
start_date : moment().format(DATE_FORMAT_YEAR),
start_hour : moment().format('HH:mm')
};

component.newData = mockEntry;
component.activeEntry = mockEntry ;
component.setDataToUpdate(mockEntry);
Expand Down Expand Up @@ -412,4 +411,18 @@ describe('EntryFieldsComponent', () => {
expect(component.selectedTechnologies).toBe(initialTechnologies);
});

it('calls unsubscribe on ngDestroy', () => {
component.loadActivitiesSubscription = new Subscription();
component.loadActiveEntrySubscription = new Subscription();
component.actionSetDateSubscription = new Subscription();
spyOn(component.loadActivitiesSubscription, 'unsubscribe');
spyOn(component.loadActiveEntrySubscription, 'unsubscribe');
spyOn(component.actionSetDateSubscription, 'unsubscribe');

component.ngOnDestroy();

expect(component.loadActivitiesSubscription.unsubscribe).toHaveBeenCalled();
expect(component.loadActiveEntrySubscription.unsubscribe).toHaveBeenCalled();
expect(component.actionSetDateSubscription.unsubscribe).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { ActivityManagementActionTypes } from './../../../activities-management/store/activity-management.actions';
import { EntryActionTypes, LoadActiveEntry } from './../../store/entry.actions';
import { filter } from 'rxjs/operators';
import { Component, OnInit } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { Store, ActionsSubject, select } from '@ngrx/store';
import { Activity, NewEntry } from '../../../shared/models';
import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer';
import { TechnologyState } from '../../../shared/store/technology.reducers';
import { ActivityState, LoadActivities } from '../../../activities-management/store';

import * as entryActions from '../../store/entry.actions';
import { get } from 'lodash';
import * as moment from 'moment';
import { ToastrService } from 'ngx-toastr';
import { formatDate } from '@angular/common';
import { getTimeEntriesDataSource } from '../../store/entry.selectors';
import { DATE_FORMAT } from 'src/environments/environment';
import { Subscription } from 'rxjs';

type Merged = TechnologyState & ProjectState & ActivityState;

Expand All @@ -24,14 +24,17 @@ type Merged = TechnologyState & ProjectState & ActivityState;
templateUrl: './entry-fields.component.html',
styleUrls: ['./entry-fields.component.scss'],
})
export class EntryFieldsComponent implements OnInit {
export class EntryFieldsComponent implements OnInit, OnDestroy {
entryForm: FormGroup;
selectedTechnologies: string[] = [];
activities: Activity[] = [];
activeEntry;
newData;
lastEntry;
showTimeInbuttons = false;
loadActivitiesSubscription: Subscription;
loadActiveEntrySubscription: Subscription;
actionSetDateSubscription: Subscription;

constructor(
private formBuilder: FormBuilder,
Expand All @@ -48,17 +51,16 @@ export class EntryFieldsComponent implements OnInit {
});
}

ngOnInit(): void {
ngOnInit(): void {
this.store.dispatch(new LoadActivities());
this.store.dispatch(new entryActions.LoadEntries(new Date().getMonth() + 1, new Date().getFullYear()));
this.actionsSubject$
this.loadActivitiesSubscription = this.actionsSubject$
.pipe(filter((action: any) => action.type === ActivityManagementActionTypes.LOAD_ACTIVITIES_SUCCESS))
.subscribe((action) => {
this.activities = action.payload;
this.store.dispatch(new LoadActiveEntry());
});

this.actionsSubject$
this.loadActiveEntrySubscription = this.actionsSubject$
.pipe(
filter(
(action: any) =>
Expand All @@ -76,8 +78,7 @@ export class EntryFieldsComponent implements OnInit {
this.store.dispatch(new entryActions.LoadEntriesSummary());
}
});

this.actionsSubject$
this.actionSetDateSubscription = this.actionsSubject$
.pipe(filter((action: any) => action.type === EntryActionTypes.LOAD_ACTIVE_ENTRY_SUCCESS))
.subscribe((action) => {
this.activeEntry = action.payload;
Expand All @@ -90,17 +91,14 @@ export class EntryFieldsComponent implements OnInit {
start_date: this.activeEntry.start_date,
start_hour: formatDate(this.activeEntry.start_date, 'HH:mm', 'en'),
};
});
});
}

get activity_id() {
return this.entryForm.get('activity_id');
}

get start_hour() {
return this.entryForm.get('start_hour');
}

setDataToUpdate(entryData: NewEntry) {
if (entryData) {
this.entryForm.patchValue({
Expand Down Expand Up @@ -174,4 +172,10 @@ export class EntryFieldsComponent implements OnInit {
onTechnologyRemoved($event: string[]) {
this.store.dispatch(new entryActions.UpdateEntryRunning({ ...this.newData, technologies: $event }));
}

ngOnDestroy(): void {
this.loadActivitiesSubscription.unsubscribe();
this.loadActiveEntrySubscription.unsubscribe();
this.actionSetDateSubscription.unsubscribe();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { provideMockStore, MockStore } from '@ngrx/store/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { AutocompleteLibModule } from 'angular-ng-autocomplete';
import { Subscription } from 'rxjs';
import { Subscription, of } from 'rxjs';
import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer';
import { getCustomerProjects } from '../../../customer-management/components/projects/components/store/project.selectors';
import { FilterProjectPipe } from '../../../shared/pipes';
Expand Down Expand Up @@ -100,11 +100,17 @@ describe('ProjectListHoverComponent', () => {

it('calls unsubscribe on ngDestroy', () => {
component.updateEntrySubscription = new Subscription();
component.projectsSubscription = new Subscription();
component.activeEntrySubscription = new Subscription();
spyOn(component.updateEntrySubscription, 'unsubscribe');
spyOn(component.projectsSubscription, 'unsubscribe');
spyOn(component.activeEntrySubscription, 'unsubscribe');

component.ngOnDestroy();

expect(component.updateEntrySubscription.unsubscribe).toHaveBeenCalled();
expect(component.projectsSubscription.unsubscribe).toHaveBeenCalled();
expect(component.activeEntrySubscription.unsubscribe).toHaveBeenCalled();
});

it('sets customer name and project name on setSelectedProject', () => {
Expand All @@ -115,10 +121,9 @@ describe('ProjectListHoverComponent', () => {
component.setSelectedProject();

expect(component.projectsForm.setValue)
.toHaveBeenCalledWith({ project_id: 'customer - xyz'});
.toHaveBeenCalledWith({ project_id: 'customer - xyz'});
});


// TODO Fix this test since it is throwing this error
// Expected spy dispatch to have been called with:
// [CreateEntry({ payload: Object({ project_id: '1', start_date: '2020-07-27T22:30:26.743Z', timezone_offset: 300 }),
Expand All @@ -140,5 +145,4 @@ describe('ProjectListHoverComponent', () => {
// })
// );
// });

});
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { FormBuilder, FormGroup } from '@angular/forms';
import { ActionsSubject, select, Store } from '@ngrx/store';
import { ToastrService } from 'ngx-toastr';
import { Observable, Subscription } from 'rxjs';
import { delay, filter } from 'rxjs/operators';
import { delay, filter, map } from 'rxjs/operators';
import { Project } from 'src/app/modules/shared/models';
import * as actions from '../../../customer-management/components/projects/components/store/project.actions';
import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer';
Expand All @@ -17,25 +17,26 @@ import { getActiveTimeEntry } from './../../store/entry.selectors';
styleUrls: ['./project-list-hover.component.scss'],
})
export class ProjectListHoverComponent implements OnInit, OnDestroy {

keyword = 'search_field';
listProjects: Project[] = [];
activeEntry;
projectsForm: FormGroup;
showClockIn: boolean;
updateEntrySubscription: Subscription;
isLoading$: Observable<boolean>;
projectsSubscription: Subscription;
activeEntrySubscription: Subscription;

constructor(private formBuilder: FormBuilder, private store: Store<ProjectState>,
private actionsSubject$: ActionsSubject, private toastrService: ToastrService) {
this.projectsForm = this.formBuilder.group({ project_id: null, });
this.isLoading$ = this.store.pipe(delay(0), select(getIsLoading));
}

ngOnInit(): void {
ngOnInit(): void {
this.store.dispatch(new actions.LoadProjects());
const projects$ = this.store.pipe(select(getProjects));
projects$.subscribe((projects) => {
this.projectsSubscription = projects$.subscribe((projects) => {
this.listProjects = [];
projects.forEach((project) => {
const projectWithSearchField = {...project};
Expand All @@ -45,7 +46,6 @@ export class ProjectListHoverComponent implements OnInit, OnDestroy {
);
this.loadActiveTimeEntry();
});

this.updateEntrySubscription = this.actionsSubject$.pipe(
filter((action: any) => (
action.type === EntryActionTypes.UPDATE_ENTRY_SUCCESS
Expand All @@ -55,13 +55,12 @@ export class ProjectListHoverComponent implements OnInit, OnDestroy {
this.activeEntry = action.payload;
this.setSelectedProject();
});

}

loadActiveTimeEntry() {
this.store.dispatch(new entryActions.LoadActiveEntry());
const activeEntry$ = this.store.pipe(select(getActiveTimeEntry));
activeEntry$.subscribe((activeEntry) => {
this.activeEntrySubscription = activeEntry$.subscribe((activeEntry) => {
this.activeEntry = activeEntry;
if (activeEntry) {
this.showClockIn = false;
Expand All @@ -72,13 +71,12 @@ export class ProjectListHoverComponent implements OnInit, OnDestroy {
}
});
}

setSelectedProject() {
this.listProjects.forEach( (project) => {
if (project.id === this.activeEntry.project_id) {
this.projectsForm.setValue(
{ project_id: `${project.customer_name} - ${project.name}`, }
);
);
}
});
}
Expand Down Expand Up @@ -110,6 +108,8 @@ export class ProjectListHoverComponent implements OnInit, OnDestroy {
}

ngOnDestroy(): void {
this.projectsSubscription.unsubscribe();
this.activeEntrySubscription.unsubscribe();
this.updateEntrySubscription.unsubscribe();
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { of } from 'rxjs';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check if is using of?

import { FormBuilder } from '@angular/forms';
import { StopTimeEntryRunning, EntryActionTypes, LoadEntriesSummary } from './../store/entry.actions';
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
Expand Down Expand Up @@ -95,12 +96,14 @@ describe('TimeClockComponent', () => {
expect(component.reloadSummariesOnClockOut).toHaveBeenCalled();
});

it('unsubscribe clockOutSubscription onDestroy', () => {
it('unsubscribe clockOutSubscription, storeSubscription onDestroy', () => {
spyOn(component.clockOutSubscription, 'unsubscribe');
spyOn(component.storeSubscription, 'unsubscribe');

component.ngOnDestroy();

expect(component.clockOutSubscription.unsubscribe).toHaveBeenCalled();
expect(component.storeSubscription.unsubscribe).toHaveBeenCalled();
});

it('onInit checks if isLogin and gets the userName', () => {
Expand Down
24 changes: 14 additions & 10 deletions src/app/modules/time-clock/pages/time-clock.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ActionsSubject, select, Store } from '@ngrx/store';
import { ToastrService } from 'ngx-toastr';
import { Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';

import { filter, map } from 'rxjs/operators';
import { threadId } from 'worker_threads';
import { AzureAdB2CService } from '../../login/services/azure.ad.b2c.service';
import { EntryFieldsComponent } from '../components/entry-fields/entry-fields.component';
import { Entry } from './../../shared/models/entry.model';
Expand All @@ -20,7 +22,7 @@ export class TimeClockComponent implements OnInit, OnDestroy {
areFieldsVisible = false;
activeTimeEntry: Entry;
clockOutSubscription: Subscription;

storeSubscription: Subscription;

constructor(
private azureAdB2CService: AzureAdB2CService,
Expand All @@ -29,23 +31,17 @@ export class TimeClockComponent implements OnInit, OnDestroy {
private actionsSubject$: ActionsSubject
) {}

ngOnDestroy(): void {
this.clockOutSubscription.unsubscribe();
}

ngOnInit() {
ngOnInit(): void {
this.username = this.azureAdB2CService.isLogin() ? this.azureAdB2CService.getName() : '';
this.store.pipe(select(getActiveTimeEntry)).subscribe((activeTimeEntry) => {
this.storeSubscription = this.store.pipe(select(getActiveTimeEntry)).subscribe((activeTimeEntry) => {
this.activeTimeEntry = activeTimeEntry;
if (this.activeTimeEntry) {
this.areFieldsVisible = true;
} else {
this.areFieldsVisible = false;
}
});

this.reloadSummariesOnClockOut();

}

reloadSummariesOnClockOut() {
Expand All @@ -72,4 +68,12 @@ export class TimeClockComponent implements OnInit, OnDestroy {
this.toastrService.error('Activity is required');
}
}

ngOnDestroy(): void {
this.clockOutSubscription.unsubscribe();
this.storeSubscription.unsubscribe();
}

}