Skip to content

Commit 3276054

Browse files
jase156kevinjlope
andauthored
feat: TT-279 angular calendar implementation (#703)
* fix: TT-258 modificate atribute star_date to view time in * feat: TT-279 Implement calendar view * fix: TT-279 Fix the comparison if var is null * fix: TT-279 fix visual errors * fix: TT-279 delete unnecessary imports * fix: TT-279 Remove bold style Co-authored-by: Kevin Lopez <[email protected]>
1 parent 56bb4e0 commit 3276054

16 files changed

+1299
-72
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
"@ngrx/store": "^10.0.1",
3232
"@ngrx/store-devtools": "^10.0.1",
3333
"@types/datatables.net-buttons": "^1.4.3",
34+
"angular-calendar": "^0.28.24",
35+
"date-fns": "^2.22.1",
3436
"angular-datatables": "^9.0.2",
3537
"bootstrap": "^4.4.1",
3638
"datatables.net": "^1.10.21",

src/app/app.module.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import { MatInputModule } from '@angular/material/input';
1616
import { MatMomentDateModule } from '@angular/material-moment-adapter';
1717
import { NgxPaginationModule } from 'ngx-pagination';
1818
import { AutocompleteLibModule } from 'angular-ng-autocomplete';
19+
import { CalendarModule, DateAdapter } from 'angular-calendar';
20+
import { adapterFactory } from 'angular-calendar/date-adapters/date-fns';
1921

2022
import { AppRoutingModule } from './app-routing.module';
2123
import { AppComponent } from './app.component';
@@ -81,6 +83,7 @@ import { NgxMaterialTimepickerModule } from 'ngx-material-timepicker';
8183
// tslint:disable-next-line: max-line-length
8284
import { TechnologyReportTableComponent } from './modules/technology-report/components/technology-report-table/technology-report-table.component';
8385
import { TechnologyReportComponent } from './modules/technology-report/pages/technology-report.component';
86+
import { CalendarComponent } from './modules/time-entries/components/calendar/calendar.component';
8487

8588
const maskConfig: Partial<IConfig> = {
8689
validation: false,
@@ -133,6 +136,7 @@ const maskConfig: Partial<IConfig> = {
133136
UsersListComponent,
134137
TechnologyReportComponent,
135138
TechnologyReportTableComponent,
139+
CalendarComponent,
136140
],
137141
imports: [
138142
NgxMaskModule.forRoot(maskConfig),
@@ -171,6 +175,10 @@ const maskConfig: Partial<IConfig> = {
171175
UserEffects,
172176
]),
173177
ToastrModule.forRoot(),
178+
CalendarModule.forRoot({
179+
provide: DateAdapter,
180+
useFactory: adapterFactory,
181+
}),
174182
],
175183
providers: [
176184
{

src/app/modules/shared/components/month-picker/month-picker.component.spec.ts

Lines changed: 203 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
22
import * as moment from 'moment';
3-
import { NEVER } from 'rxjs';
3+
import { CookieService } from 'ngx-cookie-service';
4+
import { FeatureToggle } from 'src/environments/enum';
45

56
import { MonthPickerComponent } from './month-picker.component';
67

78
describe('MonthPickerComponent', () => {
89
let component: MonthPickerComponent;
910
let fixture: ComponentFixture<MonthPickerComponent>;
11+
let cookieService: CookieService;
1012
beforeEach(waitForAsync(() => {
1113
TestBed.configureTestingModule({
1214
declarations: [ MonthPickerComponent ]
@@ -16,6 +18,7 @@ describe('MonthPickerComponent', () => {
1618

1719
beforeEach(() => {
1820
fixture = TestBed.createComponent(MonthPickerComponent);
21+
cookieService = TestBed.inject(CookieService);
1922
component = fixture.componentInstance;
2023
fixture.detectChanges();
2124
});
@@ -73,4 +76,203 @@ describe('MonthPickerComponent', () => {
7376
expect(component.monthEnable(monthFuture)).toBeTrue();
7477
});
7578

79+
it('call cookieService.get() when component was create', () => {
80+
spyOn(cookieService, 'get');
81+
82+
component.ngOnInit();
83+
84+
expect(cookieService.get).toHaveBeenCalledWith(FeatureToggle.TIME_TRACKER_CALENDAR);
85+
});
86+
87+
it('set true in isFeatureToggleCalendarActive when component was create', () => {
88+
const expectCookieValue = true;
89+
spyOn(cookieService, 'get').and.returnValue(`${ expectCookieValue }`);
90+
91+
component.ngOnInit();
92+
93+
expect(component.isFeatureToggleCalendarActive).toEqual(expectCookieValue);
94+
});
95+
96+
it('set false in isFeatureToggleCalendarActive when component was create', () => {
97+
const expectCookieValue = false;
98+
spyOn(cookieService, 'get').and.returnValue(`${ expectCookieValue }`);
99+
100+
component.ngOnInit();
101+
102+
expect(component.isFeatureToggleCalendarActive).toEqual(expectCookieValue);
103+
});
104+
105+
it('set false in isFeatureToggleCalendarActive when cookie does not exist', () => {
106+
const expectCookieValue = false;
107+
spyOn(cookieService, 'get');
108+
109+
component.ngOnInit();
110+
111+
expect(component.isFeatureToggleCalendarActive).toEqual(expectCookieValue);
112+
});
113+
114+
it('call refresData when updating the value of selectedDate', () => {
115+
const fakeSelectedDate: moment.Moment = moment(new Date());
116+
spyOn(component, 'refreshDate');
117+
118+
component.selectedDate = fakeSelectedDate;
119+
120+
expect(component.refreshDate).toHaveBeenCalledWith(fakeSelectedDate);
121+
});
122+
123+
it('not set value of selectedDate in selectedDateMoment when isFeatureToggleCalendarActive is false', () => {
124+
const fakeSelectedDate: moment.Moment = moment(new Date('2021-07-05'));
125+
component.isFeatureToggleCalendarActive = false;
126+
127+
component.refreshDate(fakeSelectedDate);
128+
129+
expect(component.selectedDateMoment).not.toEqual(fakeSelectedDate);
130+
});
131+
132+
it('set value of selectedDate in selectedDateMoment when isFeatureToggleCalendarActive is true', () => {
133+
const fakeSelectedDate: moment.Moment = moment(new Date('2021-07-05'));
134+
component.isFeatureToggleCalendarActive = true;
135+
136+
component.refreshDate(fakeSelectedDate);
137+
138+
expect(component.selectedDateMoment).toEqual(fakeSelectedDate);
139+
});
140+
141+
142+
it('set current Month index in selectedMonthIndex when isFeatureToggleCalendarActive is false', () => {
143+
const fakeSelectedDate: moment.Moment = moment(new Date('2021-07-05'));
144+
const currentDate: moment.Moment = moment(new Date());
145+
component.isFeatureToggleCalendarActive = false;
146+
147+
component.refreshDate(fakeSelectedDate);
148+
149+
expect(component.selectedMonthIndex).toEqual(currentDate.month());
150+
});
151+
152+
it('set month of selectedDate in selectedMonthIndex when isFeatureToggleCalendarActive is true', () => {
153+
const fakeSelectedDate: moment.Moment = moment(new Date('2021-07-05'));
154+
component.isFeatureToggleCalendarActive = true;
155+
156+
component.refreshDate(fakeSelectedDate);
157+
158+
expect(component.selectedMonthIndex).toEqual(fakeSelectedDate.month());
159+
});
160+
161+
it('set current year as a text in selectedYearText when isFeatureToggleCalendarActive is false', () => {
162+
const fakeSelectedDate: moment.Moment = moment(new Date('2020-07-05'));
163+
const currentDate: number = moment(new Date()).year();
164+
component.isFeatureToggleCalendarActive = false;
165+
166+
component.refreshDate(fakeSelectedDate);
167+
168+
expect(component.selectedYearText).toEqual(`${currentDate}`);
169+
});
170+
171+
it('set year as a text of selectedDate in selectedYearText when isFeatureToggleCalendarActive is true', () => {
172+
const fakeSelectedDate: moment.Moment = moment(new Date('1999-07-05'));
173+
const expectedYear = '1999';
174+
component.isFeatureToggleCalendarActive = true;
175+
176+
component.refreshDate(fakeSelectedDate);
177+
178+
expect(component.selectedYearText).toEqual(expectedYear);
179+
});
180+
181+
it('set current year in selectedYear when isFeatureToggleCalendarActive is false', () => {
182+
const fakeSelectedDate: moment.Moment = moment(new Date('2020-07-05'));
183+
const currentDate: number = moment(new Date()).year();
184+
component.isFeatureToggleCalendarActive = false;
185+
186+
component.refreshDate(fakeSelectedDate);
187+
188+
expect(component.selectedYear).toEqual(currentDate);
189+
});
190+
191+
it('set year as a text of selectedDate in selectedYear when isFeatureToggleCalendarActive is true', () => {
192+
const fakeSelectedDate: moment.Moment = moment(new Date('1999-07-05'));
193+
const expectedYear = 1999;
194+
component.isFeatureToggleCalendarActive = true;
195+
196+
component.refreshDate(fakeSelectedDate);
197+
198+
expect(component.selectedYear).toEqual(expectedYear);
199+
});
200+
201+
it('not true in showArrowNext when isFeatureToggleCalendarActive is false', () => {
202+
const fakeSelectedDate: moment.Moment = moment(new Date('1999-07-05'));
203+
component.isFeatureToggleCalendarActive = false;
204+
205+
component.refreshDate(fakeSelectedDate);
206+
207+
expect(component.showArrowNext).not.toEqual(true);
208+
});
209+
210+
it('false in showArrowNext when isFeatureToggleCalendarActive is false', () => {
211+
const fakeSelectedDate: moment.Moment = moment(new Date('1999-07-05'));
212+
component.isFeatureToggleCalendarActive = false;
213+
214+
component.refreshDate(fakeSelectedDate);
215+
216+
expect(component.showArrowNext).toEqual(false);
217+
});
218+
219+
it('set true in showArrowNext when isFeatureToggleCalendarActive is true', () => {
220+
const fakeSelectedDate: moment.Moment = moment(new Date('1999-07-05'));
221+
component.isFeatureToggleCalendarActive = true;
222+
223+
component.refreshDate(fakeSelectedDate);
224+
225+
expect(component.showArrowNext).toEqual(true);
226+
});
227+
228+
it('set false in showArrowNext when isFeatureToggleCalendarActive is true', () => {
229+
const fakeSelectedDate: moment.Moment = moment(new Date()).add(1, 'month');
230+
component.isFeatureToggleCalendarActive = true;
231+
232+
component.refreshDate(fakeSelectedDate);
233+
234+
expect(component.showArrowNext).toEqual(false);
235+
});
236+
237+
it('isSelectedMonth returns true when isFeatureToggleCalendarActive is true', () => {
238+
const fakeSelectedDate: moment.Moment = moment(new Date('2021-07-06'));
239+
const expectedReturn = true;
240+
const fakeFeatureToggleValue = true;
241+
component.selectedMonthIndex = fakeSelectedDate.month();
242+
component.selectedYear = fakeSelectedDate.year();
243+
component.selectedDateMoment = fakeSelectedDate;
244+
component.isFeatureToggleCalendarActive = fakeFeatureToggleValue;
245+
246+
const response = component.isSelectedMonth(fakeSelectedDate.month());
247+
248+
expect(response).toEqual(expectedReturn);
249+
});
250+
251+
it('isSelectedMonth returns false when isFeatureToggleCalendarActive is true and the months are not the same', () => {
252+
const fakeSelectedDate: moment.Moment = moment(new Date('2021-07-06'));
253+
const expectedReturn = false;
254+
const fakeFeatureToggleValue = true;
255+
component.selectedMonthIndex = fakeSelectedDate.month();
256+
component.selectedYear = fakeSelectedDate.year();
257+
component.selectedDateMoment = fakeSelectedDate;
258+
component.isFeatureToggleCalendarActive = fakeFeatureToggleValue;
259+
260+
const response = component.isSelectedMonth(fakeSelectedDate.add(1, 'month').month());
261+
262+
expect(response).toEqual(expectedReturn);
263+
});
264+
265+
it('isSelectedMonth returns false when isFeatureToggleCalendarActive is true and the years are not the same', () => {
266+
const fakeSelectedDate: moment.Moment = moment(new Date('2021-07-06'));
267+
const expectedReturn = false;
268+
const fakeFeatureToggleValue = true;
269+
component.selectedMonthIndex = fakeSelectedDate.month();
270+
component.selectedYear = fakeSelectedDate.year();
271+
component.selectedDateMoment = fakeSelectedDate.add(1, 'year');
272+
component.isFeatureToggleCalendarActive = fakeFeatureToggleValue;
273+
274+
const response = component.isSelectedMonth(fakeSelectedDate.month());
275+
276+
expect(response).toEqual(expectedReturn);
277+
});
76278
});

src/app/modules/shared/components/month-picker/month-picker.component.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
1-
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
1+
import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core';
22
import * as moment from 'moment';
3+
import { CookieService } from 'ngx-cookie-service';
4+
import { FeatureToggle } from 'src/environments/enum';
35

46
@Component({
57
selector: 'app-month-picker',
68
templateUrl: './month-picker.component.html',
79
styleUrls: ['./month-picker.component.scss']
810
})
911
export class MonthPickerComponent implements OnInit {
12+
@Input()
13+
set selectedDate(selectedDateMoment: moment.Moment){
14+
this.refreshDate(selectedDateMoment);
15+
}
1016
@Output() dateSelected = new EventEmitter<{
1117
monthIndex: number;
1218
year: number;
@@ -21,7 +27,9 @@ export class MonthPickerComponent implements OnInit {
2127
currentYear = new Date().getFullYear();
2228
showArrowNext = false;
2329
monthCurrent = moment().month();
24-
constructor() {
30+
selectedDateMoment: moment.Moment = moment();
31+
isFeatureToggleCalendarActive: boolean;
32+
constructor(private cookiesService: CookieService) {
2533
this.selectedYearMoment = moment();
2634
this.selectedMonthMoment = moment();
2735
this.months = moment.months();
@@ -31,9 +39,20 @@ export class MonthPickerComponent implements OnInit {
3139
}
3240

3341
ngOnInit() {
42+
this.isFeatureToggleCalendarActive = (this.cookiesService.get(FeatureToggle.TIME_TRACKER_CALENDAR) === 'true');
3443
this.selectDate(this.selectedMonthIndex, this.selectedYear);
3544
}
3645

46+
refreshDate(newDate: moment.Moment){
47+
if (this.isFeatureToggleCalendarActive){
48+
this.selectedDateMoment = newDate;
49+
this.selectedMonthIndex = this.selectedDateMoment.month();
50+
this.selectedYearText = moment(this.selectedDateMoment).format('YYYY');
51+
this.selectedYear = this.selectedDateMoment.year();
52+
this.showArrowNext = this.selectedYear < this.currentYear;
53+
}
54+
}
55+
3756
changeYear(changeAction: string) {
3857
this.selectedYearMoment[changeAction](1, 'year');
3958
this.selectedYearText = moment(this.selectedYearMoment).format('YYYY');
@@ -56,6 +75,12 @@ export class MonthPickerComponent implements OnInit {
5675
);
5776
}
5877
isSelectedMonth(monthIndex: number) {
78+
if (this.isFeatureToggleCalendarActive) {
79+
return (
80+
this.selectedMonthIndex === monthIndex &&
81+
this.selectedYear === this.selectedDateMoment.year()
82+
);
83+
}
5984
return (
6085
this.selectedMonthIndex === monthIndex &&
6186
this.selectedYear === this.selectedYearMoment.year()

src/app/modules/shared/pipes/substract-date/substract-date.pipe.spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,40 @@ describe('SubstractDatePipe', () => {
5959

6060
expect(diff).toBe('--:--');
6161
});
62+
63+
it('returns 0 if fromDate is null when call transformInMinutes', () => {
64+
const fromDate = null;
65+
const substractDate = new Date('2011-04-11T08:00:30Z');
66+
67+
const diffInMinutes = new SubstractDatePipe().transformInMinutes(fromDate, substractDate);
68+
69+
expect(diffInMinutes).toBe(0);
70+
});
71+
72+
it('returns 0 if substractDate is null when call transformInMinutes', () => {
73+
const fromDate = new Date('2011-04-11T08:00:30Z');
74+
const substractDate = null;
75+
76+
const diffInMinutes = new SubstractDatePipe().transformInMinutes(fromDate, substractDate);
77+
78+
expect(diffInMinutes).toBe(0);
79+
});
80+
81+
it('returns the date diff in minutes when call transformInMinutes', () => {
82+
[
83+
{ endDate: '2021-04-11T10:20:00Z', startDate: '2021-04-11T08:00:00Z', expectedDiff: 140 },
84+
{ endDate: '2021-04-11T17:40:00Z', startDate: '2021-04-11T17:10:00Z', expectedDiff: 30 },
85+
{ endDate: '2021-04-11T18:18:00Z', startDate: '2021-04-11T18:00:00Z', expectedDiff: 18 },
86+
{ endDate: '2021-04-12T12:18:00Z', startDate: '2021-04-11T10:00:00Z', expectedDiff: 1578 },
87+
{ endDate: '2021-04-12T10:01:00Z', startDate: '2021-04-12T10:00:00Z', expectedDiff: 1 },
88+
{ endDate: '2021-04-11T11:27:00Z', startDate: '2021-04-11T10:03:00Z', expectedDiff: 84 },
89+
].forEach(({ startDate, endDate, expectedDiff }) => {
90+
const fromDate = new Date(endDate);
91+
const substractDate = new Date(startDate);
92+
93+
const diffInMinutes = new SubstractDatePipe().transformInMinutes(fromDate, substractDate);
94+
95+
expect(diffInMinutes).toBe(expectedDiff);
96+
});
97+
});
6298
});

src/app/modules/shared/pipes/substract-date/substract-date.pipe.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,17 @@ export class SubstractDatePipe implements PipeTransform {
4141
formatTime(time: number): string {
4242
return new NumberFormatter(time).getAsAtLeastTwoDigitString();
4343
}
44+
45+
transformInMinutes(fromDate: Date, substractDate: Date): number{
46+
47+
if (!fromDate || !substractDate) {
48+
return 0;
49+
}
50+
51+
const startDate = moment(substractDate);
52+
const endDate = moment(fromDate);
53+
const duration = this.getTimeDifference(startDate, endDate);
54+
55+
return duration.asMinutes();
56+
}
4457
}

0 commit comments

Comments
 (0)