From bfcd3aedb92222670cd1b33c13443ff70f96db77 Mon Sep 17 00:00:00 2001 From: Rene Enriquez Date: Tue, 28 Apr 2020 15:58:32 -0500 Subject: [PATCH] fix: #151 clock out --- .../activity-list.component.spec.ts | 19 +- .../components/modal/modal.component.html | 4 +- .../components/modal/modal.component.spec.ts | 21 -- .../components/modal/modal.component.ts | 5 - src/app/modules/shared/models/entry.model.ts | 6 +- .../shared/store/technology.effects.ts | 2 +- .../entry-fields/entry-fields.component.html | 10 +- .../entry-fields.component.spec.ts | 3 - .../entry-fields/entry-fields.component.ts | 25 ++- .../project-list-hover.component.spec.ts | 18 +- .../project-list-hover.component.ts | 31 +-- .../pages/time-clock.component.html | 47 +++-- .../pages/time-clock.component.spec.ts | 198 +----------------- .../time-clock/pages/time-clock.component.ts | 128 ++--------- .../time-clock/services/entry.service.spec.ts | 36 +++- .../time-clock/services/entry.service.ts | 5 + .../modules/time-clock/store/entry.actions.ts | 23 +- .../modules/time-clock/store/entry.effects.ts | 14 ++ .../time-clock/store/entry.reducer.spec.ts | 51 +++-- .../modules/time-clock/store/entry.reducer.ts | 30 ++- .../time-clock/store/entry.selectors.ts | 10 +- .../pages/time-entries.component.spec.ts | 33 +-- .../pages/time-entries.component.ts | 35 ++-- 23 files changed, 277 insertions(+), 477 deletions(-) diff --git a/src/app/modules/activities-management/components/activity-list/activity-list.component.spec.ts b/src/app/modules/activities-management/components/activity-list/activity-list.component.spec.ts index 9ad71df66..5985db7fd 100644 --- a/src/app/modules/activities-management/components/activity-list/activity-list.component.spec.ts +++ b/src/app/modules/activities-management/components/activity-list/activity-list.component.spec.ts @@ -1,8 +1,9 @@ import { provideMockStore, MockStore } from '@ngrx/store/testing'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { allActivities } from './../../store/activity-management.selectors'; import { ActivityState } from './../../store/activity-management.reducers'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { DeleteActivity, SetActivityToEdit } from './../../store/activity-management.actions'; import { ActivityListComponent } from './activity-list.component'; describe('ActivityListComponent', () => { @@ -47,6 +48,22 @@ describe('ActivityListComponent', () => { expect(store.dispatch).toHaveBeenCalled(); }); + it('deleteActivity, dispatchs DeleteActivity action', () => { + spyOn(store, 'dispatch'); + + component.deleteActivity('id'); + + expect(store.dispatch).toHaveBeenCalledWith(new DeleteActivity('id')); + }); + + it('updateActivity, dispatchs SetActivityToEdit action', () => { + spyOn(store, 'dispatch'); + + component.updateActivity('id'); + + expect(store.dispatch).toHaveBeenCalledWith(new SetActivityToEdit('id')); + }); + it('onInit, activities field is populated with data from store', () => { component.ngOnInit(); diff --git a/src/app/modules/shared/components/modal/modal.component.html b/src/app/modules/shared/components/modal/modal.component.html index a8e5eb848..97d0c64f6 100644 --- a/src/app/modules/shared/components/modal/modal.component.html +++ b/src/app/modules/shared/components/modal/modal.component.html @@ -7,11 +7,11 @@ diff --git a/src/app/modules/shared/components/modal/modal.component.spec.ts b/src/app/modules/shared/components/modal/modal.component.spec.ts index 99a10a6a8..0d8d82a5d 100644 --- a/src/app/modules/shared/components/modal/modal.component.spec.ts +++ b/src/app/modules/shared/components/modal/modal.component.spec.ts @@ -22,25 +22,4 @@ describe('ModalComponent', () => { expect(component).toBeTruthy(); }); - it('should emit removeProject event #removedProject', () => { - const merged = { - id: '1', - name: 'app 4', - description: 'It is a good app', - project_type_id: '123', - completed: true, - project: 'ErnstYoung', - startDate: '2020-02-05T15:36:15.887Z', - endDate: '2020-02-05T18:36:15.887Z', - activity: 'development', - technologies: ['Angular', 'TypeScript'], - }; - - spyOn(component.removeList, 'emit'); - component.list = merged; - fixture.detectChanges(); - component.removeListById(merged.id); - expect(component.removeList.emit).toHaveBeenCalled(); - component.cancelDeleteModal.nativeElement.click(); - }); }); diff --git a/src/app/modules/shared/components/modal/modal.component.ts b/src/app/modules/shared/components/modal/modal.component.ts index 3e9449851..dae9ad620 100644 --- a/src/app/modules/shared/components/modal/modal.component.ts +++ b/src/app/modules/shared/components/modal/modal.component.ts @@ -24,9 +24,4 @@ export class ModalComponent implements OnInit { constructor() { } ngOnInit(): void { } - - removeListById(projectId: string) { - this.removeList.emit(projectId); - this.cancelDeleteModal.nativeElement.click(); - } } diff --git a/src/app/modules/shared/models/entry.model.ts b/src/app/modules/shared/models/entry.model.ts index bea6b229e..1f8c958c0 100644 --- a/src/app/modules/shared/models/entry.model.ts +++ b/src/app/modules/shared/models/entry.model.ts @@ -1,12 +1,12 @@ export interface Entry { id: string; - project: string; - startDate: string; - endDate: string; + start_date: Date; + end_date: Date; activity: string; technologies: string[]; comments?: string; uri?: string; + project_id?: string; } export interface NewEntry { diff --git a/src/app/modules/shared/store/technology.effects.ts b/src/app/modules/shared/store/technology.effects.ts index 6231e8488..cb081d92b 100644 --- a/src/app/modules/shared/store/technology.effects.ts +++ b/src/app/modules/shared/store/technology.effects.ts @@ -15,7 +15,7 @@ export class TechnologyEffects { ofType(actions.TechnologyActionTypes.FIND_TECHNOLOGIES), map((action: actions.FindTechnology) => action.payload), mergeMap((value) => - this.technologyService.getTechnologies(value).pipe( + this.technologyService.getTechnologies(value.toLowerCase()).pipe( map((technology) => { return new actions.FindTechnologySuccess(technology); }), diff --git a/src/app/modules/time-clock/components/entry-fields/entry-fields.component.html b/src/app/modules/time-clock/components/entry-fields/entry-fields.component.html index be279282a..94c40ef44 100644 --- a/src/app/modules/time-clock/components/entry-fields/entry-fields.component.html +++ b/src/app/modules/time-clock/components/entry-fields/entry-fields.component.html @@ -38,13 +38,17 @@ {{ item.name }} -
+
{{ technology }}
+
+ +
+
+ rows="3"> +
diff --git a/src/app/modules/time-clock/components/entry-fields/entry-fields.component.spec.ts b/src/app/modules/time-clock/components/entry-fields/entry-fields.component.spec.ts index 77fc9b534..4d6374baa 100644 --- a/src/app/modules/time-clock/components/entry-fields/entry-fields.component.spec.ts +++ b/src/app/modules/time-clock/components/entry-fields/entry-fields.component.spec.ts @@ -7,7 +7,6 @@ import { allTechnologies } from '../../../shared/store/technology.selectors'; import { EntryFieldsComponent } from './entry-fields.component'; import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer'; import { allProjects } from '../../../customer-management/components/projects/components/store/project.selectors'; -import { allEntries } from '../../store/entry.selectors'; import * as actions from '../../../shared/store/technology.actions'; import * as entryActions from '../../store/entry.actions'; @@ -18,7 +17,6 @@ describe('EntryFieldsComponent', () => { let store: MockStore; let mockTechnologySelector; let mockProjectsSelector; - let mockEntrySelector; let length; const state = { @@ -68,7 +66,6 @@ describe('EntryFieldsComponent', () => { store = TestBed.inject(MockStore); mockTechnologySelector = store.overrideSelector(allTechnologies, state.technologies); mockProjectsSelector = store.overrideSelector(allProjects, state.projects); - mockEntrySelector = store.overrideSelector(allEntries, state.entries); })); beforeEach(() => { diff --git a/src/app/modules/time-clock/components/entry-fields/entry-fields.component.ts b/src/app/modules/time-clock/components/entry-fields/entry-fields.component.ts index bdd9f4bf1..c862600b6 100644 --- a/src/app/modules/time-clock/components/entry-fields/entry-fields.component.ts +++ b/src/app/modules/time-clock/components/entry-fields/entry-fields.component.ts @@ -1,4 +1,5 @@ -import { Component, OnInit, ViewChild, ElementRef, Renderer2 } from '@angular/core'; +import { getActiveTimeEntry } from './../../store/entry.selectors'; +import { Component, OnInit, ViewChild, ElementRef, Renderer2, Output, EventEmitter } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { Store, select } from '@ngrx/store'; @@ -10,7 +11,6 @@ import { ProjectState } from '../../../customer-management/components/projects/c import { TechnologyState } from '../../../shared/store/technology.reducers'; import { LoadActivities, ActivityState, allActivities } from '../../../activities-management/store'; -import { allEntries } from '../../store/entry.selectors'; import * as entryActions from '../../store/entry.actions'; type Merged = TechnologyState & ProjectState & ActivityState; @@ -21,6 +21,7 @@ type Merged = TechnologyState & ProjectState & ActivityState; styleUrls: ['./entry-fields.component.scss'], }) export class EntryFieldsComponent implements OnInit { + @ViewChild('list') list: ElementRef; entryForm: FormGroup; technology: Technology; @@ -57,15 +58,17 @@ export class EntryFieldsComponent implements OnInit { this.activities = response; }); - const activeEntry$ = this.store.pipe(select(allEntries)); + const activeEntry$ = this.store.pipe(select(getActiveTimeEntry)); activeEntry$.subscribe((response) => { - this.activeEntry = response.active; - this.setDataToUpdate(this.activeEntry); - this.newData = { - id: this.activeEntry.id, - project_id: this.activeEntry.project_id, - uri: this.activeEntry.uri, - }; + if (response) { + this.activeEntry = response; + this.setDataToUpdate(this.activeEntry); + this.newData = { + id: this.activeEntry.id, + project_id: this.activeEntry.project_id, + uri: this.activeEntry.uri, + }; + } }); } @@ -92,7 +95,6 @@ export class EntryFieldsComponent implements OnInit { setTechnology(name: string) { const index = this.selectedTechnology.indexOf(name); - if (index > -1) { this.removeTag(index); } else if (this.selectedTechnology.length < 10) { @@ -111,4 +113,5 @@ export class EntryFieldsComponent implements OnInit { onSubmit() { this.store.dispatch(new entryActions.UpdateActiveEntry({ ...this.newData, ...this.entryForm.value })); } + } diff --git a/src/app/modules/time-clock/components/project-list-hover/project-list-hover.component.spec.ts b/src/app/modules/time-clock/components/project-list-hover/project-list-hover.component.spec.ts index 420b56ea2..51c49f6f2 100644 --- a/src/app/modules/time-clock/components/project-list-hover/project-list-hover.component.spec.ts +++ b/src/app/modules/time-clock/components/project-list-hover/project-list-hover.component.spec.ts @@ -6,7 +6,6 @@ import { ProjectListHoverComponent } from './project-list-hover.component'; import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer'; import { allProjects } from '../../../customer-management/components/projects/components/store/project.selectors'; import { FilterProjectPipe } from '../../../shared/pipes'; -import { NewEntry } from '../../../shared/models'; import * as action from '../../store/entry.actions'; describe('ProjectListHoverComponent', () => { @@ -54,22 +53,11 @@ describe('ProjectListHoverComponent', () => { expect(component).toBeTruthy(); }); - it('should set selectedId with Id and dispatch CreateEntry action', () => { + it('clock-in dispatchs a new action', () => { spyOn(store, 'dispatch'); - const id = 'P1'; - const entryData: NewEntry = { - project_id: id, - start_date: new Date().toISOString(), - }; - component.clockIn(id); - expect(store.dispatch).toHaveBeenCalledWith(new action.CreateEntry(entryData)); - expect(component.selectedId).toBe(id); - }); + component.clockIn('id'); - it('should emit showFields event', () => { - const id = 'P1'; - component.showFields.subscribe((showFields: boolean) => expect(showFields).toEqual(true)); - component.clockIn(id); + expect(store.dispatch).toHaveBeenCalledWith(new action.CreateEntry({project_id: 'id', start_date: new Date().toISOString() })); }); }); diff --git a/src/app/modules/time-clock/components/project-list-hover/project-list-hover.component.ts b/src/app/modules/time-clock/components/project-list-hover/project-list-hover.component.ts index bd70f87e4..95de4328d 100644 --- a/src/app/modules/time-clock/components/project-list-hover/project-list-hover.component.ts +++ b/src/app/modules/time-clock/components/project-list-hover/project-list-hover.component.ts @@ -1,20 +1,19 @@ -import { Component, OnInit, Output, EventEmitter } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { Store, select } from '@ngrx/store'; + +import { getActiveTimeEntry } from './../../store/entry.selectors'; import { Project } from 'src/app/modules/shared/models'; import { allProjects } from '../../../customer-management/components/projects/components/store/project.selectors'; import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer'; import * as actions from '../../../customer-management/components/projects/components/store/project.actions'; import * as entryActions from '../../store/entry.actions'; -import { selectActiveEntry } from '../../store/entry.selectors'; - @Component({ selector: 'app-project-list-hover', templateUrl: './project-list-hover.component.html', styleUrls: ['./project-list-hover.component.scss'], }) export class ProjectListHoverComponent implements OnInit { - @Output() showFields = new EventEmitter(); selectedId: string; listProjects: Project[] = []; @@ -24,7 +23,7 @@ export class ProjectListHoverComponent implements OnInit { keyword = 'name'; nameActiveProject: string; - constructor(private store: Store) {} + constructor(private store: Store) { } ngOnInit(): void { this.store.dispatch(new actions.LoadProjects()); @@ -33,15 +32,24 @@ export class ProjectListHoverComponent implements OnInit { projects$.subscribe((response) => { this.isLoading = response.isLoading; this.listProjects = response.projectList; + this.loadActiveTimeEntry(); }); - this.store.dispatch(new entryActions.LoadActiveEntry()); - const activeEntry$ = this.store.pipe(select(selectActiveEntry)); + } - activeEntry$.subscribe((response) => { - if (response) { - this.nameActiveProject = response.name; - this.showFields.emit(true); + private loadActiveTimeEntry() { + this.store.dispatch(new entryActions.LoadActiveEntry()); + const activeEntry$ = this.store.pipe(select(getActiveTimeEntry)); + activeEntry$.subscribe((activeEntry) => { + if (activeEntry) { + for (const project of this.listProjects) { + if (project.id === activeEntry.project_id) { + this.nameActiveProject = project.name; + break; + } + } + } else { + this.nameActiveProject = null; } }); } @@ -49,6 +57,5 @@ export class ProjectListHoverComponent implements OnInit { clockIn(id: string) { const newEntry = { project_id: id, start_date: new Date().toISOString() }; this.store.dispatch(new entryActions.CreateEntry(newEntry)); - this.selectedId = id; } } diff --git a/src/app/modules/time-clock/pages/time-clock.component.html b/src/app/modules/time-clock/pages/time-clock.component.html index 4e8a461a0..f993c54db 100644 --- a/src/app/modules/time-clock/pages/time-clock.component.html +++ b/src/app/modules/time-clock/pages/time-clock.component.html @@ -1,52 +1,53 @@
-