From 2e23d0290a5adf35a21efa2c99d5aeef52d8cd81 Mon Sep 17 00:00:00 2001 From: Roberto Mena <17350786+Angeluz-07@users.noreply.github.com> Date: Mon, 21 Dec 2020 13:04:32 -0500 Subject: [PATCH 1/5] TT-64 fix: set technologies as list when create time-entry (#592) --- .../project-list-hover/project-list-hover.component.ts | 1 + src/app/modules/time-clock/store/entry.effects.ts | 1 + 2 files changed, 2 insertions(+) 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 bd3ef5c49..6213e3ca7 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 @@ -88,6 +88,7 @@ export class ProjectListHoverComponent implements OnInit, OnDestroy { project_id: selectedProject, start_date: new Date().toISOString(), timezone_offset: new Date().getTimezoneOffset(), + technologies: [] }; this.store.dispatch(new entryActions.ClockIn(entry)); this.projectsForm.setValue( { project_id: `${customerName} - ${name}`, } ); diff --git a/src/app/modules/time-clock/store/entry.effects.ts b/src/app/modules/time-clock/store/entry.effects.ts index 6add71c00..806ec9a19 100644 --- a/src/app/modules/time-clock/store/entry.effects.ts +++ b/src/app/modules/time-clock/store/entry.effects.ts @@ -26,6 +26,7 @@ export class EntryEffects { project_id: action.idProjectSwitching, start_date: stopDateForEntry.toISOString(), timezone_offset: new Date().getTimezoneOffset(), + technologies: [] }; return new actions.ClockIn(entry); }), From 8b50d4fab39ab1e7b1abdc9a87a406c353408d71 Mon Sep 17 00:00:00 2001 From: PaulRC-ioet Date: Thu, 17 Dec 2020 18:14:28 -0500 Subject: [PATCH 2/5] TT-85 fix: fix overlapping seconds on time entries --- .../details-fields.component.spec.ts | 22 +++++++++++++++++-- .../details-fields.component.ts | 15 +++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/app/modules/shared/components/details-fields/details-fields.component.spec.ts b/src/app/modules/shared/components/details-fields/details-fields.component.spec.ts index e2516cd58..37b953585 100644 --- a/src/app/modules/shared/components/details-fields/details-fields.component.spec.ts +++ b/src/app/modules/shared/components/details-fields/details-fields.component.spec.ts @@ -76,6 +76,11 @@ describe('DetailsFieldsComponent', () => { description: '', technology: '', }; + const dateTest = moment().format('YYYY-MM-DD'); + const endHourTest = moment().format('HH:mm:ss'); + const endDateTest = new Date(`${dateTest}T${endHourTest.trim()}`); + const startHourTest = moment().subtract(3, 'hours').format('HH:mm:ss'); + const startDateTest = new Date(`${dateTest}T${startHourTest.trim()}`); beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ @@ -101,8 +106,8 @@ describe('DetailsFieldsComponent', () => { project_id: 'id', activity_id: '', uri: 'ticketUri', - start_date: null, - end_date: null, + start_date: startDateTest, + end_date: endDateTest, description: '', technologies: [], id: 'xyz' @@ -314,6 +319,19 @@ describe('DetailsFieldsComponent', () => { expect(component.saveEntry.emit).toHaveBeenCalledWith(data); }); + fit('onSubmit an entry without change hours, should not modify the start_date and end_date ', () => { + component.entryToEdit = {...entryToEdit, description: 'test', }; + fixture.componentInstance.ngOnChanges(); + + const startHourValue = moment().subtract(3, 'hours').format('HH:mm'); + const endHourValue = moment().format('HH:mm'); + + component.onSubmit(); + + expect(component.starDateValue).toEqual(startHourValue); + expect(component.endDateValue).toEqual(endHourValue); + }); + it('displays error message when the date selected is in the future', () => { spyOn(toastrServiceStub, 'error'); diff --git a/src/app/modules/shared/components/details-fields/details-fields.component.ts b/src/app/modules/shared/components/details-fields/details-fields.component.ts index 8f90c97aa..4e73900f0 100644 --- a/src/app/modules/shared/components/details-fields/details-fields.component.ts +++ b/src/app/modules/shared/components/details-fields/details-fields.component.ts @@ -42,6 +42,8 @@ export class DetailsFieldsComponent implements OnChanges, OnInit { activities: Activity[] = []; goingToWorkOnThis = false; shouldRestartEntry = false; + starDateValue; + endDateValue; constructor(private formBuilder: FormBuilder, private store: Store, private actionsSubject$: ActionsSubject, private toastrService: ToastrService) { @@ -139,6 +141,8 @@ export class DetailsFieldsComponent implements OnChanges, OnInit { uri: this.entryToEdit.uri, technology: '', }); + this.starDateValue = formatDate(get(this.entryToEdit, 'start_date', '00:00'), 'HH:mm', 'en'); + this.endDateValue = formatDate(get(this.entryToEdit, 'end_date', '00:00'), 'HH:mm', 'en'); } else { this.cleanForm(); } @@ -204,13 +208,20 @@ export class DetailsFieldsComponent implements OnChanges, OnInit { } const startDate = this.entryForm.value.start_date; const endDate = this.entryForm.value.end_date; + this.starDateValue = this.entryForm.value.start_hour === this.starDateValue ? + this.entryToEdit.start_date : + new Date(`${startDate}T${this.entryForm.value.start_hour.trim()}`).toISOString(); + this.endDateValue = this.entryForm.value.end_hour === this.endDateValue ? + this.entryToEdit.end_date : + new Date(`${endDate}T${this.entryForm.value.end_hour.trim()}`).toISOString(); + const entry = { project_id: this.entryForm.value.project_id, activity_id: this.entryForm.value.activity_id, technologies: get(this, 'selectedTechnologies', []), description: this.entryForm.value.description, - start_date: new Date(`${startDate}T${this.entryForm.value.start_hour.trim()}`).toISOString(), - end_date: new Date(`${endDate}T${this.entryForm.value.end_hour.trim()}`).toISOString(), + start_date: this.starDateValue, + end_date: this.endDateValue, uri: this.entryForm.value.uri, timezone_offset: new Date().getTimezoneOffset(), }; From 3155406e3c291a9dab1aeb0c2de182169a5b7edd Mon Sep 17 00:00:00 2001 From: PaulRC-ioet Date: Thu, 17 Dec 2020 18:23:44 -0500 Subject: [PATCH 3/5] TT-85 fix: correct word fit --- .../components/details-fields/details-fields.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/modules/shared/components/details-fields/details-fields.component.spec.ts b/src/app/modules/shared/components/details-fields/details-fields.component.spec.ts index 37b953585..4aa0d9224 100644 --- a/src/app/modules/shared/components/details-fields/details-fields.component.spec.ts +++ b/src/app/modules/shared/components/details-fields/details-fields.component.spec.ts @@ -319,7 +319,7 @@ describe('DetailsFieldsComponent', () => { expect(component.saveEntry.emit).toHaveBeenCalledWith(data); }); - fit('onSubmit an entry without change hours, should not modify the start_date and end_date ', () => { + it('onSubmit an entry without change hours, should not modify the start_date and end_date ', () => { component.entryToEdit = {...entryToEdit, description: 'test', }; fixture.componentInstance.ngOnChanges(); From 29da434ccba82d3d491f097aac1c19977c8a0a5e Mon Sep 17 00:00:00 2001 From: PaulRC-ioet Date: Fri, 18 Dec 2020 15:50:06 -0500 Subject: [PATCH 4/5] TT-85 fix: refactor start date and end date --- .../details-fields.component.ts | 54 +++++++++++++------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/src/app/modules/shared/components/details-fields/details-fields.component.ts b/src/app/modules/shared/components/details-fields/details-fields.component.ts index 4e73900f0..1a2c7b5b4 100644 --- a/src/app/modules/shared/components/details-fields/details-fields.component.ts +++ b/src/app/modules/shared/components/details-fields/details-fields.component.ts @@ -42,8 +42,6 @@ export class DetailsFieldsComponent implements OnChanges, OnInit { activities: Activity[] = []; goingToWorkOnThis = false; shouldRestartEntry = false; - starDateValue; - endDateValue; constructor(private formBuilder: FormBuilder, private store: Store, private actionsSubject$: ActionsSubject, private toastrService: ToastrService) { @@ -141,8 +139,6 @@ export class DetailsFieldsComponent implements OnChanges, OnInit { uri: this.entryToEdit.uri, technology: '', }); - this.starDateValue = formatDate(get(this.entryToEdit, 'start_date', '00:00'), 'HH:mm', 'en'); - this.endDateValue = formatDate(get(this.entryToEdit, 'end_date', '00:00'), 'HH:mm', 'en'); } else { this.cleanForm(); } @@ -201,36 +197,60 @@ export class DetailsFieldsComponent implements OnChanges, OnInit { this.closeModal?.nativeElement?.click(); } + startDateToSubmit(){ + const startDate = this.entryForm.value.start_date; + const initialStartDate = this.entryToEdit.start_date; + const updatedStartDate = new Date(`${startDate}T${this.entryForm.value.start_hour.trim()}`).toISOString(); + const initialStartHour = formatDate(get(this.entryToEdit, 'start_date', '00:00'), 'HH:mm', 'en'); + const updatedStartHour = this.entryForm.value.start_hour; + const startHourHasNotChanged = updatedStartHour === initialStartHour; + const result = startHourHasNotChanged ? initialStartDate : updatedStartDate; + return result; + } + + endDateToSubmit(){ + const endDate = this.entryForm.value.end_date; + const initialEndDate = this.entryToEdit.end_date; + const updatedEndDate = new Date(`${endDate}T${this.entryForm.value.end_hour.trim()}`).toISOString(); + const initialEndHour = formatDate(get(this.entryToEdit, 'end_date', '00:00'), 'HH:mm', 'en'); + const updatedEndHour = this.entryForm.value.end_hour; + const endDateHasNotChanged = updatedEndHour === initialEndHour; + const result = endDateHasNotChanged ? initialEndDate : updatedEndDate; + return result; + } + + timeEntryIsInTheFuture(){ + const startDate = this.entryForm.value.start_date; + const endDate = this.entryForm.value.end_date; + const isStartDateInTheFuture = moment(startDate).isAfter(moment()); + const isEndDateInTheFuture = moment(endDate).isAfter(moment()); + return isStartDateInTheFuture || isEndDateInTheFuture; + } + onSubmit() { if (this.entryForm.invalid) { this.toastrService.warning('Make sure to select a project and activity'); return; } - const startDate = this.entryForm.value.start_date; - const endDate = this.entryForm.value.end_date; - this.starDateValue = this.entryForm.value.start_hour === this.starDateValue ? - this.entryToEdit.start_date : - new Date(`${startDate}T${this.entryForm.value.start_hour.trim()}`).toISOString(); - this.endDateValue = this.entryForm.value.end_hour === this.endDateValue ? - this.entryToEdit.end_date : - new Date(`${endDate}T${this.entryForm.value.end_hour.trim()}`).toISOString(); + + const startDateToSubmit = this.startDateToSubmit(); + const endDateToSubmit = this.endDateToSubmit(); const entry = { project_id: this.entryForm.value.project_id, activity_id: this.entryForm.value.activity_id, technologies: get(this, 'selectedTechnologies', []), description: this.entryForm.value.description, - start_date: this.starDateValue, - end_date: this.endDateValue, + start_date: startDateToSubmit, + end_date: endDateToSubmit, uri: this.entryForm.value.uri, timezone_offset: new Date().getTimezoneOffset(), }; if (this.goingToWorkOnThis) { delete entry.end_date; } - const isStartDateInTheFuture = moment(startDate).isAfter(moment()); - const isEndDateInTheFuture = moment(endDate).isAfter(moment()); - if (isStartDateInTheFuture || isEndDateInTheFuture) { + + if (this.timeEntryIsInTheFuture()) { this.toastrService.error('You cannot start a time-entry in the future'); return; } From 85a4c931855d30da05b2d8db1c514b857cf6af26 Mon Sep 17 00:00:00 2001 From: PaulRC-ioet Date: Tue, 22 Dec 2020 11:25:08 -0500 Subject: [PATCH 5/5] TT-85 fix: refactor code and improve tests --- .../details-fields.component.spec.ts | 74 +++++++++++++++---- .../details-fields.component.ts | 14 ++-- 2 files changed, 64 insertions(+), 24 deletions(-) diff --git a/src/app/modules/shared/components/details-fields/details-fields.component.spec.ts b/src/app/modules/shared/components/details-fields/details-fields.component.spec.ts index 4aa0d9224..5d0e45571 100644 --- a/src/app/modules/shared/components/details-fields/details-fields.component.spec.ts +++ b/src/app/modules/shared/components/details-fields/details-fields.component.spec.ts @@ -76,11 +76,6 @@ describe('DetailsFieldsComponent', () => { description: '', technology: '', }; - const dateTest = moment().format('YYYY-MM-DD'); - const endHourTest = moment().format('HH:mm:ss'); - const endDateTest = new Date(`${dateTest}T${endHourTest.trim()}`); - const startHourTest = moment().subtract(3, 'hours').format('HH:mm:ss'); - const startDateTest = new Date(`${dateTest}T${startHourTest.trim()}`); beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ @@ -106,8 +101,8 @@ describe('DetailsFieldsComponent', () => { project_id: 'id', activity_id: '', uri: 'ticketUri', - start_date: startDateTest, - end_date: endDateTest, + start_date: null, + end_date: null, description: '', technologies: [], id: 'xyz' @@ -218,6 +213,7 @@ describe('DetailsFieldsComponent', () => { it('should emit saveEntry event', () => { spyOn(component.saveEntry, 'emit'); + component.entryToEdit = { ...entryToEdit }; component.entryForm.setValue({ project_id: 'p1', project_name: 'p-name', @@ -299,6 +295,7 @@ describe('DetailsFieldsComponent', () => { component.goingToWorkOnThis = true; spyOn(component.saveEntry, 'emit'); + component.entryToEdit = { ...entryToEdit }; component.entryForm.setValue({ ...formValues, start_date: '2020-06-11', end_date: '2020-06-11' }); component.onSubmit(); @@ -315,26 +312,71 @@ describe('DetailsFieldsComponent', () => { }, shouldRestartEntry: false }; - expect(component.saveEntry.emit).toHaveBeenCalledWith(data); }); - it('onSubmit an entry without change hours, should not modify the start_date and end_date ', () => { - component.entryToEdit = {...entryToEdit, description: 'test', }; + it('should not modify the start_date when start_hour has not been modified', () => { + const dateTest = moment().format('YYYY-MM-DD'); + const startHourTest = moment().subtract(3, 'hours').format('HH:mm:ss'); + const expectedStartDate = new Date(`${dateTest}T${startHourTest.trim()}`); + + component.entryToEdit = {...entryToEdit, start_date: expectedStartDate }; fixture.componentInstance.ngOnChanges(); - const startHourValue = moment().subtract(3, 'hours').format('HH:mm'); - const endHourValue = moment().format('HH:mm'); + component.entryForm.patchValue({ description: 'test' }); - component.onSubmit(); + expect(component.startDateToSubmit()).toEqual(expectedStartDate); + }); + + it('should modify the start_date when start_hour has been modified', () => { + const dateTest = moment().format('YYYY-MM-DD'); + const startHourTest = moment().format('HH:mm:ss'); + const startDate = new Date(`${dateTest}T${startHourTest.trim()}`); + + component.entryToEdit = {...entryToEdit, start_date: startDate }; + fixture.componentInstance.ngOnChanges(); + + const updatedStartDate = moment().subtract(1, 'hours'); + const updatedStartHour = updatedStartDate.format('HH:mm'); + component.entryForm.patchValue({start_hour: updatedStartHour}); + + const expectedStartDate = moment(updatedStartDate).seconds(0).millisecond(0).toISOString(); + expect(component.startDateToSubmit()).toEqual(expectedStartDate); + }); - expect(component.starDateValue).toEqual(startHourValue); - expect(component.endDateValue).toEqual(endHourValue); + it('should not modify the end_date when end_hour has not been modified', () => { + const dateTest = moment().format('YYYY-MM-DD'); + const endtHourTest = moment().subtract(3, 'hours').format('HH:mm:ss'); + const expectedEndDate = new Date(`${dateTest}T${endtHourTest.trim()}`); + + component.entryToEdit = {...entryToEdit, end_date: expectedEndDate }; + fixture.componentInstance.ngOnChanges(); + + component.entryForm.patchValue({ description: 'test' }); + + expect(component.endDateToSubmit()).toEqual(expectedEndDate); }); + it('should modify the end_date when end_hour has been modified', () => { + const dateTest = moment().format('YYYY-MM-DD'); + const endHourTest = moment().format('HH:mm:ss'); + const endDate = new Date(`${dateTest}T${endHourTest.trim()}`); + + component.entryToEdit = {...entryToEdit, end_date: endDate }; + fixture.componentInstance.ngOnChanges(); + + const updatedEndDate = moment().subtract(1, 'hours'); + const updatedEndHour = updatedEndDate.format('HH:mm'); + component.entryForm.patchValue({end_hour: updatedEndHour}); + + const expectedEndDate = moment(updatedEndDate).seconds(0).millisecond(0).toISOString(); + expect(component.endDateToSubmit()).toEqual(expectedEndDate); + }); + it('displays error message when the date selected is in the future', () => { spyOn(toastrServiceStub, 'error'); + component.entryToEdit = { ...entryToEdit }; const futureDate = moment().add(1, 'days').format(DATE_FORMAT_YEAR); component.entryForm.setValue({ ...formValues, start_date: futureDate, end_date: futureDate }); component.onSubmit(); @@ -345,6 +387,7 @@ describe('DetailsFieldsComponent', () => { it('when start_date is in the future and end_date is OK then throws an error', () => { spyOn(toastrServiceStub, 'error'); + component.entryToEdit = { ...entryToEdit }; const futureDate = moment().add(1, 'days').format(DATE_FORMAT_YEAR); const currentDate = moment().format(DATE_FORMAT_YEAR); component.entryForm.setValue({ ...formValues, start_date: futureDate, end_date: currentDate }); @@ -356,6 +399,7 @@ describe('DetailsFieldsComponent', () => { it('when start_date is OK and end_date is in the future then throws an error future', () => { spyOn(toastrServiceStub, 'error'); + component.entryToEdit = { ...entryToEdit }; const futureDate = moment().add(1, 'days').format(DATE_FORMAT_YEAR); const currentDate = moment().format(DATE_FORMAT_YEAR); component.entryForm.setValue({ ...formValues, start_date: currentDate, end_date: futureDate }); diff --git a/src/app/modules/shared/components/details-fields/details-fields.component.ts b/src/app/modules/shared/components/details-fields/details-fields.component.ts index 1a2c7b5b4..516395b74 100644 --- a/src/app/modules/shared/components/details-fields/details-fields.component.ts +++ b/src/app/modules/shared/components/details-fields/details-fields.component.ts @@ -219,14 +219,6 @@ export class DetailsFieldsComponent implements OnChanges, OnInit { return result; } - timeEntryIsInTheFuture(){ - const startDate = this.entryForm.value.start_date; - const endDate = this.entryForm.value.end_date; - const isStartDateInTheFuture = moment(startDate).isAfter(moment()); - const isEndDateInTheFuture = moment(endDate).isAfter(moment()); - return isStartDateInTheFuture || isEndDateInTheFuture; - } - onSubmit() { if (this.entryForm.invalid) { this.toastrService.warning('Make sure to select a project and activity'); @@ -250,7 +242,11 @@ export class DetailsFieldsComponent implements OnChanges, OnInit { delete entry.end_date; } - if (this.timeEntryIsInTheFuture()) { + const isStartDateInTheFuture = moment(startDateToSubmit).isAfter(moment()); + const isEndDateInTheFuture = moment(endDateToSubmit).isAfter(moment()); + const timeEntryIsInTheFuture = isStartDateInTheFuture || isEndDateInTheFuture; + + if (timeEntryIsInTheFuture) { this.toastrService.error('You cannot start a time-entry in the future'); return; }