From 8cdf91626a76f705e708824d60a3644cae48bac5 Mon Sep 17 00:00:00 2001 From: Sandro Castillo Date: Wed, 16 Dec 2020 08:45:47 -0500 Subject: [PATCH 1/9] TT-39 feat: allow switching among year --- .../month-picker/month-picker.component.html | 39 +++++++++--- .../month-picker/month-picker.component.ts | 63 ++++++++++++++++--- .../pages/time-entries.component.html | 2 +- .../pages/time-entries.component.ts | 14 +++-- tslint.json | 1 + 5 files changed, 96 insertions(+), 23 deletions(-) diff --git a/src/app/modules/shared/components/month-picker/month-picker.component.html b/src/app/modules/shared/components/month-picker/month-picker.component.html index 204ecb6d7..c5656aa4e 100644 --- a/src/app/modules/shared/components/month-picker/month-picker.component.html +++ b/src/app/modules/shared/components/month-picker/month-picker.component.html @@ -1,10 +1,31 @@ -
-
-
{{ month }}
-
+
+
+
+
+ +

+ {{selectedYearText}} +

+ +
+
+ +
+
+
+
+ +
+
+
+
+
diff --git a/src/app/modules/shared/components/month-picker/month-picker.component.ts b/src/app/modules/shared/components/month-picker/month-picker.component.ts index 1a404f058..d0e731fa7 100644 --- a/src/app/modules/shared/components/month-picker/month-picker.component.ts +++ b/src/app/modules/shared/components/month-picker/month-picker.component.ts @@ -1,4 +1,5 @@ import { Component, OnInit, Output, EventEmitter } from '@angular/core'; +import * as moment from 'moment'; @Component({ selector: 'app-month-picker', @@ -6,18 +7,62 @@ import { Component, OnInit, Output, EventEmitter } from '@angular/core'; styleUrls: ['./month-picker.component.scss'] }) export class MonthPickerComponent implements OnInit { - @Output() monthSelected = new EventEmitter(); - activeMonth: number; - months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; - constructor() { } + @Output() dateSelected = new EventEmitter<{ monthIndex: number; year: number; }>(); - ngOnInit(): void { - this.activeMonth = new Date().getMonth(); + selectedMonthMoment: moment.Moment; + selectedMonthIndex: number; + selectedYearMoment: moment.Moment; + selectedMonthYear: number; + + selectedYearText: string; + months: Array = []; + years: Array = []; + + constructor() { + this.selectedYearMoment = moment(); + this.selectedMonthMoment = moment(); + this.months = moment.months(); + this.selectedMonthIndex = this.selectedMonthMoment.month(); + this.selectedMonthYear = this.selectedYearMoment.year(); + this.updateYearText(); + } + + ngOnInit() { + this.selectDate(this.selectedMonthIndex, this.selectedMonthYear); + } + + updateYearText() { + this.selectedYearText = moment(this.selectedYearMoment).format('YYYY'); + } + + increment() { + this.selectedYearMoment = this.selectedYearMoment.add(1, 'year'); + this.updateYearText(); } - getMonth(month: number) { - this.monthSelected.emit(month + 1); - this.activeMonth = month; + decrement() { + this.selectedYearMoment = this.selectedYearMoment.subtract(1, 'year'); + this.updateYearText(); } + + selectMonth(index: number) { + this.selectedMonthMoment = moment().month(index); + this.selectedMonthIndex = this.selectedMonthMoment.month(); + this.selectedMonthYear = this.selectedYearMoment.year(); + this.selectDate(this.selectedMonthIndex, this.selectedMonthYear); + } + + isSelectedMonth(monthIndex: number) { + return ( + this.selectedMonthIndex === monthIndex && + this.selectedMonthYear === this.selectedYearMoment.year() + ); + } + + selectDate(monthIndex: number, year: number) { + this.dateSelected.emit({ monthIndex: monthIndex, year: year }); + } + } + diff --git a/src/app/modules/time-entries/pages/time-entries.component.html b/src/app/modules/time-entries/pages/time-entries.component.html index 8928eb656..8fabce8a2 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.html +++ b/src/app/modules/time-entries/pages/time-entries.component.html @@ -13,7 +13,7 @@
- +
diff --git a/src/app/modules/time-entries/pages/time-entries.component.ts b/src/app/modules/time-entries/pages/time-entries.component.ts index 9d564946c..11b924580 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.ts +++ b/src/app/modules/time-entries/pages/time-entries.component.ts @@ -8,6 +8,7 @@ import { SaveEntryEvent } from '../../shared/components/details-fields/save-entr import { Entry } from '../../shared/models'; import { DataSource } from '../../shared/models/data-source.model'; import * as entryActions from '../../time-clock/store/entry.actions'; +import * as moment from 'moment'; import { EntryState } from '../../time-clock/store/entry.reducer'; import { EntryActionTypes } from './../../time-clock/store/entry.actions'; import { getActiveTimeEntry, getTimeEntriesDataSource } from './../../time-clock/store/entry.selectors'; @@ -26,6 +27,9 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { entriesSubscription: Subscription; canMarkEntryAsWIP = true; timeEntriesDataSource$: Observable>; + selectedYearAsText: string; + selectedMonthIndex: number; + selectedMonthAsText: string; constructor(private store: Store, private toastrService: ToastrService, private actionsSubject$: ActionsSubject) { this.timeEntriesDataSource$ = this.store.pipe(delay(0), select(getTimeEntriesDataSource)); @@ -107,8 +111,7 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { const isEditingEntryEqualToActiveEntry = this.entryId === this.activeTimeEntry.id; const isStartDateGreaterThanActiveEntry = startDateAsLocalDate > activeEntryAsLocalDate; const isEndDateGreaterThanActiveEntry = endDateAsLocalDate > activeEntryAsLocalDate; - const isTimeEntryOverlapping = isStartDateGreaterThanActiveEntry || isEndDateGreaterThanActiveEntry; - if (!isEditingEntryEqualToActiveEntry && isTimeEntryOverlapping) { + if (!isEditingEntryEqualToActiveEntry && (isStartDateGreaterThanActiveEntry || isEndDateGreaterThanActiveEntry)){ this.toastrService.error('You are on the clock and this entry overlaps it, try with earlier times.'); } else { this.doSave(event); @@ -161,8 +164,11 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { this.showModal = false; } - getMonth(month: number) { - this.store.dispatch(new entryActions.LoadEntries(month)); + dateSelected(event: { monthIndex: number; year: number }) { + this.selectedYearAsText = event.year.toString(); + this.selectedMonthIndex = event.monthIndex; + this.selectedMonthAsText = moment().month(event.monthIndex).format('MMMM'); + this.store.dispatch(new entryActions.LoadEntries(event.monthIndex)); } openModal(item: any) { diff --git a/tslint.json b/tslint.json index 37c500fe1..eda9ad204 100644 --- a/tslint.json +++ b/tslint.json @@ -76,6 +76,7 @@ "no-redundant-jsdoc": true, "no-switch-case-fall-through": true, "no-var-requires": false, + "object-literal-shorthand": false, "object-literal-key-quotes": [ true, "as-needed" From e839109486a9b23c7f023e30b284f116981c1fb1 Mon Sep 17 00:00:00 2001 From: Sandro Castillo Date: Thu, 17 Dec 2020 09:08:07 -0500 Subject: [PATCH 2/9] TT-39 fix: resolve tests --- .../month-picker/month-picker.component.spec.ts | 10 ++++++---- .../time-entries/pages/time-entries.component.spec.ts | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts b/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts index c8d29053e..addc4b317 100644 --- a/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts +++ b/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts @@ -1,4 +1,5 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; +import { months } from 'moment'; import { MonthPickerComponent } from './month-picker.component'; @@ -23,10 +24,11 @@ describe('MonthPickerComponent', () => { expect(component).toBeTruthy(); }); - it('should emit activeMonth event', () => { + it('should emit monthIndex and year', () => { const month = 2; - spyOn(component.monthSelected, 'emit'); - component.getMonth(month); - expect(component.monthSelected.emit).toHaveBeenCalledWith(month + 1); + const year = 2020; + spyOn(component.dateSelected, 'emit'); + expect(component.dateSelected.emit({ monthIndex: month, year: year })); }); + }); diff --git a/src/app/modules/time-entries/pages/time-entries.component.spec.ts b/src/app/modules/time-entries/pages/time-entries.component.spec.ts index b2237ce1e..ce438d4ff 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.spec.ts +++ b/src/app/modules/time-entries/pages/time-entries.component.spec.ts @@ -18,6 +18,7 @@ import { TimeEntriesComponent } from './time-entries.component'; import { ActionsSubject } from '@ngrx/store'; import { EntryActionTypes } from './../../time-clock/store/entry.actions'; import { NgxMaterialTimepickerModule } from 'ngx-material-timepicker'; +import { months } from 'moment'; describe('TimeEntriesComponent', () => { type Merged = TechnologyState & ProjectState & EntryState; @@ -322,10 +323,11 @@ describe('TimeEntriesComponent', () => { expect(store.dispatch).toHaveBeenCalledWith(new entryActions.DeleteEntry('id')); }); - it('should get the entry List by Month', () => { + it('should get the entry List by Month and year', () => { const month = 1; + const year = 2020; spyOn(store, 'dispatch'); - component.getMonth(month); + component.dateSelected({monthIndex: month, year: 2020}); expect(store.dispatch).toHaveBeenCalledWith(new entryActions.LoadEntries(month)); }); From da55e06978b278590e477b4e666517ec56155c27 Mon Sep 17 00:00:00 2001 From: Sandro Castillo Date: Mon, 21 Dec 2020 16:42:47 -0500 Subject: [PATCH 3/9] TT-39 fix: creating test --- .../month-picker/month-picker.component.html | 51 ++++++++----------- .../month-picker/month-picker.component.scss | 4 +- .../month-picker/month-picker.component.ts | 7 ++- .../entry-fields/entry-fields.component.ts | 2 +- .../time-clock/services/entry.service.spec.ts | 6 ++- .../time-clock/services/entry.service.ts | 4 +- .../modules/time-clock/store/entry.actions.ts | 2 +- .../modules/time-clock/store/entry.effects.ts | 8 +-- .../time-clock/store/entry.reducer.spec.ts | 4 +- .../pages/time-entries.component.spec.ts | 14 ++--- .../pages/time-entries.component.ts | 13 +++-- 11 files changed, 63 insertions(+), 52 deletions(-) diff --git a/src/app/modules/shared/components/month-picker/month-picker.component.html b/src/app/modules/shared/components/month-picker/month-picker.component.html index c5656aa4e..9aaf57009 100644 --- a/src/app/modules/shared/components/month-picker/month-picker.component.html +++ b/src/app/modules/shared/components/month-picker/month-picker.component.html @@ -1,31 +1,22 @@ -
-
-
-
- -

- {{selectedYearText}} -

- -
-
- -
-
-
-
- -
-
-
-
-
+
+
+ +

+ {{selectedYearText}} +

+ +
+
+
+ +
+
\ No newline at end of file diff --git a/src/app/modules/shared/components/month-picker/month-picker.component.scss b/src/app/modules/shared/components/month-picker/month-picker.component.scss index f4123a4b3..8ee488704 100644 --- a/src/app/modules/shared/components/month-picker/month-picker.component.scss +++ b/src/app/modules/shared/components/month-picker/month-picker.component.scss @@ -21,5 +21,7 @@ @include highlight(); border-radius: 0.2em; text-decoration: underline; - } +.spacing { + padding: 0.1em; +} \ No newline at end of file diff --git a/src/app/modules/shared/components/month-picker/month-picker.component.ts b/src/app/modules/shared/components/month-picker/month-picker.component.ts index d0e731fa7..8041c9efc 100644 --- a/src/app/modules/shared/components/month-picker/month-picker.component.ts +++ b/src/app/modules/shared/components/month-picker/month-picker.component.ts @@ -1,3 +1,4 @@ +import { SubstractDatePipe } from './../../pipes/substract-date/substract-date.pipe'; import { Component, OnInit, Output, EventEmitter } from '@angular/core'; import * as moment from 'moment'; @@ -7,8 +8,10 @@ import * as moment from 'moment'; styleUrls: ['./month-picker.component.scss'] }) export class MonthPickerComponent implements OnInit { - - @Output() dateSelected = new EventEmitter<{ monthIndex: number; year: number; }>(); + @Output() dateSelected = new EventEmitter<{ + monthIndex: number; + year: number; + }>(); selectedMonthMoment: moment.Moment; selectedMonthIndex: number; 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 ebcc5531d..a8a762ffc 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 @@ -50,7 +50,7 @@ export class EntryFieldsComponent implements OnInit { ngOnInit(): void { this.store.dispatch(new LoadActivities()); - this.store.dispatch(new entryActions.LoadEntries(new Date().getMonth() + 1)); + this.store.dispatch(new entryActions.LoadEntries(12, 2020)); this.actionsSubject$ .pipe(filter((action: any) => action.type === ActivityManagementActionTypes.LOAD_ACTIVITIES_SUCCESS)) .subscribe((action) => { diff --git a/src/app/modules/time-clock/services/entry.service.spec.ts b/src/app/modules/time-clock/services/entry.service.spec.ts index 9979c2566..681fe51e0 100644 --- a/src/app/modules/time-clock/services/entry.service.spec.ts +++ b/src/app/modules/time-clock/services/entry.service.spec.ts @@ -54,11 +54,13 @@ describe('EntryService', () => { }); it('load all Entries', () => { + const year = new Date().getFullYear(); const month = new Date().getMonth(); + const timezoneOffset = new Date().getTimezoneOffset(); - service.loadEntries(month).subscribe(); + service.loadEntries(year, month).subscribe(); - const loadEntryRequest = httpMock.expectOne(`${service.baseUrl}?month=${month}&timezone_offset=${timezoneOffset}`); + const loadEntryRequest = httpMock.expectOne(`${service.baseUrl}?month=${month}&year=${year}&timezone_offset=${timezoneOffset}`); expect(loadEntryRequest.request.method).toBe('GET'); }); diff --git a/src/app/modules/time-clock/services/entry.service.ts b/src/app/modules/time-clock/services/entry.service.ts index 6f2a96ad2..25d64ea80 100644 --- a/src/app/modules/time-clock/services/entry.service.ts +++ b/src/app/modules/time-clock/services/entry.service.ts @@ -23,9 +23,9 @@ export class EntryService { return this.http.get(`${this.baseUrl}/running`); } - loadEntries(month): Observable { + loadEntries(year, month): Observable { const timezoneOffset = new Date().getTimezoneOffset(); - return this.http.get(`${this.baseUrl}?month=${month}&timezone_offset=${timezoneOffset}`); + return this.http.get(`${this.baseUrl}?month=${month}&year=${year}&timezone_offset=${timezoneOffset}`); } createEntry(entryData): Observable { diff --git a/src/app/modules/time-clock/store/entry.actions.ts b/src/app/modules/time-clock/store/entry.actions.ts index abdb9c75f..f58378ffa 100644 --- a/src/app/modules/time-clock/store/entry.actions.ts +++ b/src/app/modules/time-clock/store/entry.actions.ts @@ -99,7 +99,7 @@ export class LoadActiveEntryFail implements Action { export class LoadEntries implements Action { public readonly type = EntryActionTypes.LOAD_ENTRIES; - constructor(public month: number) { + constructor(public month: number, public year: number) { } } diff --git a/src/app/modules/time-clock/store/entry.effects.ts b/src/app/modules/time-clock/store/entry.effects.ts index 806ec9a19..ed98a5549 100644 --- a/src/app/modules/time-clock/store/entry.effects.ts +++ b/src/app/modules/time-clock/store/entry.effects.ts @@ -87,9 +87,10 @@ export class EntryEffects { @Effect() loadEntries$: Observable = this.actions$.pipe( ofType(actions.EntryActionTypes.LOAD_ENTRIES), - map((action: actions.LoadEntries) => action.month), - mergeMap((month) => - this.entryService.loadEntries(month).pipe( + // tslint:disable-next-line:no-unused-expression + map((action: actions.LoadEntries) => (action.month, action.year)), + mergeMap((month, year) => + this.entryService.loadEntries(month, year).pipe( map((entries) => new actions.LoadEntriesSuccess(entries)), catchError((error) => { this.toastrService.warning(`The data could not be loaded`); @@ -97,6 +98,7 @@ export class EntryEffects { }) ) ) + ); @Effect() diff --git a/src/app/modules/time-clock/store/entry.reducer.spec.ts b/src/app/modules/time-clock/store/entry.reducer.spec.ts index ecc683589..dafce2ee7 100644 --- a/src/app/modules/time-clock/store/entry.reducer.spec.ts +++ b/src/app/modules/time-clock/store/entry.reducer.spec.ts @@ -107,7 +107,9 @@ describe('entryReducer', () => { }); it('on LoadEntries, isLoading is true', () => { - const action = new actions.LoadEntries(new Date().getMonth() + 1); + const month = 12; + const year = 2020; + const action = new actions.LoadEntries(month, year); const state = entryReducer(initialState, action); expect(state.timeEntriesDataSource.isLoading).toEqual(true); }); diff --git a/src/app/modules/time-entries/pages/time-entries.component.spec.ts b/src/app/modules/time-entries/pages/time-entries.component.spec.ts index ce438d4ff..ca9d58d9a 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.spec.ts +++ b/src/app/modules/time-entries/pages/time-entries.component.spec.ts @@ -127,7 +127,8 @@ describe('TimeEntriesComponent', () => { })); it('when create time entries, the time entries should be queried', () => { - const currentMonth = new Date().getMonth() + 1; + const currentMonth = new Date().getMonth(); + const year = new Date().getFullYear(); const entryToSave = { entry: { project_id: 'project-id', @@ -142,7 +143,7 @@ describe('TimeEntriesComponent', () => { component.saveEntry(entryToSave); expect(store.dispatch).toHaveBeenCalledWith(new entryActions.CreateEntry(entryToSave.entry)); - expect(store.dispatch).toHaveBeenCalledWith(new entryActions.LoadEntries(currentMonth)); + expect(store.dispatch).toHaveBeenCalledWith(new entryActions.LoadEntries(currentMonth, year)); }); it('when creating a new entry, then entryId should be null', () => { @@ -324,11 +325,12 @@ describe('TimeEntriesComponent', () => { }); it('should get the entry List by Month and year', () => { - const month = 1; - const year = 2020; + const month = new Date().getMonth(); + const year = new Date().getFullYear(); + spyOn(store, 'dispatch'); - component.dateSelected({monthIndex: month, year: 2020}); - expect(store.dispatch).toHaveBeenCalledWith(new entryActions.LoadEntries(month)); + component.dateSelected({monthIndex: month, year: year}); + expect(store.dispatch).toHaveBeenCalledWith(new entryActions.LoadEntries(month + 1, year)); }); it('doSave when activeTimeEntry === null', waitForAsync(() => { diff --git a/src/app/modules/time-entries/pages/time-entries.component.ts b/src/app/modules/time-entries/pages/time-entries.component.ts index 11b924580..ae8e5d2c3 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.ts +++ b/src/app/modules/time-entries/pages/time-entries.component.ts @@ -1,3 +1,4 @@ +import { formatDate } from '@angular/common'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActionsSubject, select, Store } from '@ngrx/store'; import { ToastrService } from 'ngx-toastr'; @@ -31,6 +32,9 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { selectedMonthIndex: number; selectedMonthAsText: string; + currentMonth = new Date().getMonth(); + year = new Date().getFullYear(); + constructor(private store: Store, private toastrService: ToastrService, private actionsSubject$: ActionsSubject) { this.timeEntriesDataSource$ = this.store.pipe(delay(0), select(getTimeEntriesDataSource)); } @@ -40,7 +44,10 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { } ngOnInit(): void { - this.store.dispatch(new entryActions.LoadEntries(new Date().getMonth() + 1)); + + this.store.dispatch(new entryActions.LoadEntries(this.selectedMonthIndex, this.year)); + console.log('year', this.store.dispatch(new entryActions.LoadEntries(this.currentMonth, this.year))); + this.loadActiveEntry(); this.entriesSubscription = this.actionsSubject$.pipe( @@ -52,7 +59,6 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { ) ).subscribe((action) => { this.loadActiveEntry(); - this.store.dispatch(new entryActions.LoadEntries(new Date().getMonth() + 1)); }); } @@ -80,6 +86,7 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { this.canMarkEntryAsWIP = this.isEntryRunningEqualsToEntryToEdit(this.getEntryRunning(ds.data), this.entry) || this.isTheEntryToEditTheLastOne(ds.data); }); + console.log('entryId', this.entryId); } private isEntryRunningEqualsToEntryToEdit(entryRunning: Entry, entryToEdit: Entry) { @@ -168,7 +175,7 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { this.selectedYearAsText = event.year.toString(); this.selectedMonthIndex = event.monthIndex; this.selectedMonthAsText = moment().month(event.monthIndex).format('MMMM'); - this.store.dispatch(new entryActions.LoadEntries(event.monthIndex)); + this.store.dispatch(new entryActions.LoadEntries(event.monthIndex + 1, event.year)); } openModal(item: any) { From e23f6e8d5e38433be99e74173e24aeeaa3ca8347 Mon Sep 17 00:00:00 2001 From: Sandro Castillo Date: Tue, 22 Dec 2020 11:16:37 -0500 Subject: [PATCH 4/9] TT-39 fix: code coverage --- .../components/entry-fields/entry-fields.component.ts | 4 +++- src/app/modules/time-clock/store/entry.effects.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) 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 a8a762ffc..b799c4b6b 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 @@ -32,6 +32,8 @@ export class EntryFieldsComponent implements OnInit { newData; lastEntry; showTimeInbuttons = false; + month = new Date().getMonth(); + year = new Date().getFullYear(); constructor( private formBuilder: FormBuilder, @@ -50,7 +52,7 @@ export class EntryFieldsComponent implements OnInit { ngOnInit(): void { this.store.dispatch(new LoadActivities()); - this.store.dispatch(new entryActions.LoadEntries(12, 2020)); + this.store.dispatch(new entryActions.LoadEntries(this.month, this.year)); this.actionsSubject$ .pipe(filter((action: any) => action.type === ActivityManagementActionTypes.LOAD_ACTIVITIES_SUCCESS)) .subscribe((action) => { diff --git a/src/app/modules/time-clock/store/entry.effects.ts b/src/app/modules/time-clock/store/entry.effects.ts index ed98a5549..ea5973c4e 100644 --- a/src/app/modules/time-clock/store/entry.effects.ts +++ b/src/app/modules/time-clock/store/entry.effects.ts @@ -228,7 +228,7 @@ export class EntryEffects { ofType(actions.EntryActionTypes.UPDATE_CURRENT_OR_LAST_ENTRY), map((action: actions.UpdateCurrentOrLastEntry) => action.payload), switchMap((entry) => - this.entryService.loadEntries(new Date().getMonth() + 1).pipe( + this.entryService.loadEntries(new Date().getMonth() + 1, new Date().getFullYear()).pipe( map((entries) => { const lastEntry = entries[1]; const isStartTimeInLastEntry = moment(entry.start_date).isBefore(lastEntry.end_date); From 5582e153ea546fe3e14c70e8a88870c3dc69987c Mon Sep 17 00:00:00 2001 From: Sandro Castillo Date: Thu, 24 Dec 2020 11:31:22 -0500 Subject: [PATCH 5/9] TT-39 fix: resolve comments --- .../components/month-picker/month-picker.component.html | 4 ++-- .../components/month-picker/month-picker.component.scss | 5 ++++- .../components/month-picker/month-picker.component.spec.ts | 5 +++-- .../time-entries/pages/time-entries.component.spec.ts | 1 - src/app/modules/time-entries/pages/time-entries.component.ts | 2 -- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/app/modules/shared/components/month-picker/month-picker.component.html b/src/app/modules/shared/components/month-picker/month-picker.component.html index 9aaf57009..8bb7c7901 100644 --- a/src/app/modules/shared/components/month-picker/month-picker.component.html +++ b/src/app/modules/shared/components/month-picker/month-picker.component.html @@ -11,7 +11,7 @@
-
+
-
\ No newline at end of file +
diff --git a/src/app/modules/shared/components/month-picker/month-picker.component.scss b/src/app/modules/shared/components/month-picker/month-picker.component.scss index 8ee488704..fc1a00665 100644 --- a/src/app/modules/shared/components/month-picker/month-picker.component.scss +++ b/src/app/modules/shared/components/month-picker/month-picker.component.scss @@ -5,6 +5,9 @@ line-height: 1.2em; font-weight: bold; } +.content-months { + margin: 0; +} .month { background: $primary; @@ -24,4 +27,4 @@ } .spacing { padding: 0.1em; -} \ No newline at end of file +} diff --git a/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts b/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts index addc4b317..69ab642d3 100644 --- a/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts +++ b/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts @@ -25,8 +25,9 @@ describe('MonthPickerComponent', () => { }); it('should emit monthIndex and year', () => { - const month = 2; - const year = 2020; + const month = new Date().getMonth(); + const year = new Date().getFullYear(); + spyOn(component.dateSelected, 'emit'); expect(component.dateSelected.emit({ monthIndex: month, year: year })); }); diff --git a/src/app/modules/time-entries/pages/time-entries.component.spec.ts b/src/app/modules/time-entries/pages/time-entries.component.spec.ts index ca9d58d9a..2d83a344e 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.spec.ts +++ b/src/app/modules/time-entries/pages/time-entries.component.spec.ts @@ -18,7 +18,6 @@ import { TimeEntriesComponent } from './time-entries.component'; import { ActionsSubject } from '@ngrx/store'; import { EntryActionTypes } from './../../time-clock/store/entry.actions'; import { NgxMaterialTimepickerModule } from 'ngx-material-timepicker'; -import { months } from 'moment'; describe('TimeEntriesComponent', () => { type Merged = TechnologyState & ProjectState & EntryState; diff --git a/src/app/modules/time-entries/pages/time-entries.component.ts b/src/app/modules/time-entries/pages/time-entries.component.ts index ae8e5d2c3..62503d972 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.ts +++ b/src/app/modules/time-entries/pages/time-entries.component.ts @@ -46,7 +46,6 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { ngOnInit(): void { this.store.dispatch(new entryActions.LoadEntries(this.selectedMonthIndex, this.year)); - console.log('year', this.store.dispatch(new entryActions.LoadEntries(this.currentMonth, this.year))); this.loadActiveEntry(); @@ -86,7 +85,6 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { this.canMarkEntryAsWIP = this.isEntryRunningEqualsToEntryToEdit(this.getEntryRunning(ds.data), this.entry) || this.isTheEntryToEditTheLastOne(ds.data); }); - console.log('entryId', this.entryId); } private isEntryRunningEqualsToEntryToEdit(entryRunning: Entry, entryToEdit: Entry) { From d472a6364c57d7f416e453efa5323d4add654bc6 Mon Sep 17 00:00:00 2001 From: Sandro Castillo Date: Thu, 24 Dec 2020 13:30:31 -0500 Subject: [PATCH 6/9] TT-39 fix: code coverage --- .../month-picker/month-picker.component.spec.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts b/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts index 69ab642d3..4015f3554 100644 --- a/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts +++ b/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts @@ -1,5 +1,6 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { months } from 'moment'; +import * as moment from 'moment'; +import { NEVER } from 'rxjs'; import { MonthPickerComponent } from './month-picker.component'; @@ -32,4 +33,16 @@ describe('MonthPickerComponent', () => { expect(component.dateSelected.emit({ monthIndex: month, year: year })); }); + it('should add a year to current year', () => { + const year = moment().add(1, 'year').format('Y'); + expect(component.selectedYearMoment.add(1, 'year').format('Y')).toEqual(year); + expect(component.updateYearText).toBeTruthy(); + }); + + it('should subtract a year to current year', () => { + const year = moment().subtract(1, 'year').format('Y'); + expect(component.selectedYearMoment.subtract(1, 'year').format('Y')).toEqual(year); + expect(component.updateYearText).toBeTruthy(); + }); + }); From 42aea4bebfc4a2e5aae33d543754e886e4d68758 Mon Sep 17 00:00:00 2001 From: Sandro Castillo Date: Mon, 28 Dec 2020 16:07:26 -0500 Subject: [PATCH 7/9] TT-39 fix: testing increment() and decrement() --- .../month-picker.component.spec.ts | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts b/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts index 4015f3554..14f5f49ac 100644 --- a/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts +++ b/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts @@ -34,15 +34,27 @@ describe('MonthPickerComponent', () => { }); it('should add a year to current year', () => { - const year = moment().add(1, 'year').format('Y'); - expect(component.selectedYearMoment.add(1, 'year').format('Y')).toEqual(year); - expect(component.updateYearText).toBeTruthy(); + component.selectedYearMoment = moment(); + const incrementYear = moment().add(1, 'year').format('Y'); + spyOn(component, 'increment').and.callThrough(); + + component.increment(); + + expect(component.increment).toHaveBeenCalled(); + expect(component.selectedYearText).toEqual(incrementYear); + expect(component.selectedYearMoment.format('Y')).toEqual(incrementYear); }); + it('should subtract a year to current year', () => { - const year = moment().subtract(1, 'year').format('Y'); - expect(component.selectedYearMoment.subtract(1, 'year').format('Y')).toEqual(year); - expect(component.updateYearText).toBeTruthy(); + component.selectedYearMoment = moment(); + const decrementYear = moment().subtract(1, 'year').format('Y'); + spyOn(component, 'decrement').and.callThrough(); + + component.decrement(); + + expect(component.decrement).toHaveBeenCalled(); + expect(component.selectedYearMoment.format('Y')).toEqual(decrementYear); }); }); From fc2587ac8a9c4816c110d79ac368aaa6176b9ddf Mon Sep 17 00:00:00 2001 From: Guido Quezada Date: Tue, 29 Dec 2020 12:17:33 -0500 Subject: [PATCH 8/9] TT-39 fix: code refactor --- .../month-picker/month-picker.component.spec.ts | 10 ++++++++++ .../month-picker/month-picker.component.ts | 1 - .../entry-fields/entry-fields.component.ts | 4 +--- .../time-clock/services/entry.service.spec.ts | 2 +- .../modules/time-clock/services/entry.service.ts | 4 ++-- .../modules/time-clock/store/entry.effects.ts | 13 +++++++------ .../pages/time-entries.component.spec.ts | 2 +- .../time-entries/pages/time-entries.component.ts | 16 ++++++---------- tslint.json | 1 - 9 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts b/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts index 14f5f49ac..ea46623f0 100644 --- a/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts +++ b/src/app/modules/shared/components/month-picker/month-picker.component.spec.ts @@ -33,6 +33,7 @@ describe('MonthPickerComponent', () => { expect(component.dateSelected.emit({ monthIndex: month, year: year })); }); + it('should add a year to current year', () => { component.selectedYearMoment = moment(); const incrementYear = moment().add(1, 'year').format('Y'); @@ -57,4 +58,13 @@ describe('MonthPickerComponent', () => { expect(component.selectedYearMoment.format('Y')).toEqual(decrementYear); }); + + it('selectMonth should call selectDates', () => { + spyOn(component, 'selectDate'); + + component.selectMonth(8); + + expect(component.selectDate).toHaveBeenCalledWith(8, 2020); + }); + }); diff --git a/src/app/modules/shared/components/month-picker/month-picker.component.ts b/src/app/modules/shared/components/month-picker/month-picker.component.ts index 8041c9efc..902b13de9 100644 --- a/src/app/modules/shared/components/month-picker/month-picker.component.ts +++ b/src/app/modules/shared/components/month-picker/month-picker.component.ts @@ -1,4 +1,3 @@ -import { SubstractDatePipe } from './../../pipes/substract-date/substract-date.pipe'; import { Component, OnInit, Output, EventEmitter } from '@angular/core'; import * as moment from 'moment'; 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 b799c4b6b..d5327d8c1 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 @@ -32,8 +32,6 @@ export class EntryFieldsComponent implements OnInit { newData; lastEntry; showTimeInbuttons = false; - month = new Date().getMonth(); - year = new Date().getFullYear(); constructor( private formBuilder: FormBuilder, @@ -52,7 +50,7 @@ export class EntryFieldsComponent implements OnInit { ngOnInit(): void { this.store.dispatch(new LoadActivities()); - this.store.dispatch(new entryActions.LoadEntries(this.month, this.year)); + this.store.dispatch(new entryActions.LoadEntries(new Date().getMonth() + 1, new Date().getFullYear())); this.actionsSubject$ .pipe(filter((action: any) => action.type === ActivityManagementActionTypes.LOAD_ACTIVITIES_SUCCESS)) .subscribe((action) => { diff --git a/src/app/modules/time-clock/services/entry.service.spec.ts b/src/app/modules/time-clock/services/entry.service.spec.ts index 681fe51e0..ca2630120 100644 --- a/src/app/modules/time-clock/services/entry.service.spec.ts +++ b/src/app/modules/time-clock/services/entry.service.spec.ts @@ -58,7 +58,7 @@ describe('EntryService', () => { const month = new Date().getMonth(); const timezoneOffset = new Date().getTimezoneOffset(); - service.loadEntries(year, month).subscribe(); + service.loadEntries({ year, month }).subscribe(); const loadEntryRequest = httpMock.expectOne(`${service.baseUrl}?month=${month}&year=${year}&timezone_offset=${timezoneOffset}`); expect(loadEntryRequest.request.method).toBe('GET'); diff --git a/src/app/modules/time-clock/services/entry.service.ts b/src/app/modules/time-clock/services/entry.service.ts index 25d64ea80..2506b4a5b 100644 --- a/src/app/modules/time-clock/services/entry.service.ts +++ b/src/app/modules/time-clock/services/entry.service.ts @@ -23,9 +23,9 @@ export class EntryService { return this.http.get(`${this.baseUrl}/running`); } - loadEntries(year, month): Observable { + loadEntries(date): Observable { const timezoneOffset = new Date().getTimezoneOffset(); - return this.http.get(`${this.baseUrl}?month=${month}&year=${year}&timezone_offset=${timezoneOffset}`); + return this.http.get(`${this.baseUrl}?month=${date.month}&year=${date.year}&timezone_offset=${timezoneOffset}`); } createEntry(entryData): Observable { diff --git a/src/app/modules/time-clock/store/entry.effects.ts b/src/app/modules/time-clock/store/entry.effects.ts index ea5973c4e..58aa988ad 100644 --- a/src/app/modules/time-clock/store/entry.effects.ts +++ b/src/app/modules/time-clock/store/entry.effects.ts @@ -87,10 +87,9 @@ export class EntryEffects { @Effect() loadEntries$: Observable = this.actions$.pipe( ofType(actions.EntryActionTypes.LOAD_ENTRIES), - // tslint:disable-next-line:no-unused-expression - map((action: actions.LoadEntries) => (action.month, action.year)), - mergeMap((month, year) => - this.entryService.loadEntries(month, year).pipe( + map((action: actions.LoadEntries) => action), + mergeMap((date) => + this.entryService.loadEntries({ month: date.month, year: date.year }).pipe( map((entries) => new actions.LoadEntriesSuccess(entries)), catchError((error) => { this.toastrService.warning(`The data could not be loaded`); @@ -98,7 +97,6 @@ export class EntryEffects { }) ) ) - ); @Effect() @@ -228,7 +226,10 @@ export class EntryEffects { ofType(actions.EntryActionTypes.UPDATE_CURRENT_OR_LAST_ENTRY), map((action: actions.UpdateCurrentOrLastEntry) => action.payload), switchMap((entry) => - this.entryService.loadEntries(new Date().getMonth() + 1, new Date().getFullYear()).pipe( + this.entryService.loadEntries({ + month : new Date().getMonth() + 1, + year: new Date().getFullYear() + }).pipe( map((entries) => { const lastEntry = entries[1]; const isStartTimeInLastEntry = moment(entry.start_date).isBefore(lastEntry.end_date); diff --git a/src/app/modules/time-entries/pages/time-entries.component.spec.ts b/src/app/modules/time-entries/pages/time-entries.component.spec.ts index 2d83a344e..05168742e 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.spec.ts +++ b/src/app/modules/time-entries/pages/time-entries.component.spec.ts @@ -126,7 +126,7 @@ describe('TimeEntriesComponent', () => { })); it('when create time entries, the time entries should be queried', () => { - const currentMonth = new Date().getMonth(); + const currentMonth = new Date().getMonth() + 1; const year = new Date().getFullYear(); const entryToSave = { entry: { diff --git a/src/app/modules/time-entries/pages/time-entries.component.ts b/src/app/modules/time-entries/pages/time-entries.component.ts index 62503d972..6e86b6067 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.ts +++ b/src/app/modules/time-entries/pages/time-entries.component.ts @@ -1,4 +1,3 @@ -import { formatDate } from '@angular/common'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActionsSubject, select, Store } from '@ngrx/store'; import { ToastrService } from 'ngx-toastr'; @@ -32,9 +31,6 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { selectedMonthIndex: number; selectedMonthAsText: string; - currentMonth = new Date().getMonth(); - year = new Date().getFullYear(); - constructor(private store: Store, private toastrService: ToastrService, private actionsSubject$: ActionsSubject) { this.timeEntriesDataSource$ = this.store.pipe(delay(0), select(getTimeEntriesDataSource)); } @@ -44,9 +40,7 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { } ngOnInit(): void { - - this.store.dispatch(new entryActions.LoadEntries(this.selectedMonthIndex, this.year)); - + this.store.dispatch(new entryActions.LoadEntries(new Date().getMonth() + 1, new Date().getFullYear())); this.loadActiveEntry(); this.entriesSubscription = this.actionsSubject$.pipe( @@ -58,6 +52,7 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { ) ).subscribe((action) => { this.loadActiveEntry(); + this.store.dispatch(new entryActions.LoadEntries(this.selectedMonthIndex, new Date().getFullYear())); }); } @@ -116,7 +111,8 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { const isEditingEntryEqualToActiveEntry = this.entryId === this.activeTimeEntry.id; const isStartDateGreaterThanActiveEntry = startDateAsLocalDate > activeEntryAsLocalDate; const isEndDateGreaterThanActiveEntry = endDateAsLocalDate > activeEntryAsLocalDate; - if (!isEditingEntryEqualToActiveEntry && (isStartDateGreaterThanActiveEntry || isEndDateGreaterThanActiveEntry)){ + const isTimeEntryOverlapping = isStartDateGreaterThanActiveEntry || isEndDateGreaterThanActiveEntry; + if (!isEditingEntryEqualToActiveEntry && isTimeEntryOverlapping) { this.toastrService.error('You are on the clock and this entry overlaps it, try with earlier times.'); } else { this.doSave(event); @@ -171,9 +167,9 @@ export class TimeEntriesComponent implements OnInit, OnDestroy { dateSelected(event: { monthIndex: number; year: number }) { this.selectedYearAsText = event.year.toString(); - this.selectedMonthIndex = event.monthIndex; + this.selectedMonthIndex = event.monthIndex + 1; this.selectedMonthAsText = moment().month(event.monthIndex).format('MMMM'); - this.store.dispatch(new entryActions.LoadEntries(event.monthIndex + 1, event.year)); + this.store.dispatch(new entryActions.LoadEntries(this.selectedMonthIndex, event.year)); } openModal(item: any) { diff --git a/tslint.json b/tslint.json index eda9ad204..37c500fe1 100644 --- a/tslint.json +++ b/tslint.json @@ -76,7 +76,6 @@ "no-redundant-jsdoc": true, "no-switch-case-fall-through": true, "no-var-requires": false, - "object-literal-shorthand": false, "object-literal-key-quotes": [ true, "as-needed" From 881c5203fc778b96c3ecb93ed0c067884f4b0392 Mon Sep 17 00:00:00 2001 From: Guido Quezada Date: Tue, 29 Dec 2020 12:47:05 -0500 Subject: [PATCH 9/9] TT-39 fix: variable refactor --- .../month-picker/month-picker.component.ts | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/app/modules/shared/components/month-picker/month-picker.component.ts b/src/app/modules/shared/components/month-picker/month-picker.component.ts index 902b13de9..ccea2b70d 100644 --- a/src/app/modules/shared/components/month-picker/month-picker.component.ts +++ b/src/app/modules/shared/components/month-picker/month-picker.component.ts @@ -15,7 +15,7 @@ export class MonthPickerComponent implements OnInit { selectedMonthMoment: moment.Moment; selectedMonthIndex: number; selectedYearMoment: moment.Moment; - selectedMonthYear: number; + selectedYear: number; selectedYearText: string; months: Array = []; @@ -26,12 +26,12 @@ export class MonthPickerComponent implements OnInit { this.selectedMonthMoment = moment(); this.months = moment.months(); this.selectedMonthIndex = this.selectedMonthMoment.month(); - this.selectedMonthYear = this.selectedYearMoment.year(); + this.selectedYear = this.selectedYearMoment.year(); this.updateYearText(); } ngOnInit() { - this.selectDate(this.selectedMonthIndex, this.selectedMonthYear); + this.selectDate(this.selectedMonthIndex, this.selectedYear); } updateYearText() { @@ -48,23 +48,21 @@ export class MonthPickerComponent implements OnInit { this.updateYearText(); } - selectMonth(index: number) { - this.selectedMonthMoment = moment().month(index); - this.selectedMonthIndex = this.selectedMonthMoment.month(); - this.selectedMonthYear = this.selectedYearMoment.year(); - this.selectDate(this.selectedMonthIndex, this.selectedMonthYear); + selectMonth(monthIndex: number) { + this.selectedMonthIndex = monthIndex; + this.selectedYear = this.selectedYearMoment.year(); + this.selectDate(this.selectedMonthIndex, this.selectedYear); } isSelectedMonth(monthIndex: number) { return ( this.selectedMonthIndex === monthIndex && - this.selectedMonthYear === this.selectedYearMoment.year() + this.selectedYear === this.selectedYearMoment.year() ); } selectDate(monthIndex: number, year: number) { - this.dateSelected.emit({ monthIndex: monthIndex, year: year }); + this.dateSelected.emit({ monthIndex, year }); } - }