Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: TT-296 add scroll to the current time in calendar component
  • Loading branch information
PieritoAlva95 committed Aug 6, 2021
commit 4d61233de7c488e8442c5d236fccbf1f63dc6975
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
</div>
</div>

<div [ngSwitch]="calendarView">
<div class="switch-calendar-view" [ngSwitch]="calendarView" #scrollContainer>
<mwl-calendar-month-view
*ngSwitchCase="CalendarViewEnum.Month"
[viewDate]="currentDate"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,29 @@
@return darken(saturate(adjust-hue($text-color, 6), 46.19), 40.98);
}

.switch-calendar-view {
height: calc(100vh - 320px);
overflow-y: auto;
}

::-webkit-scrollbar {
width: 5px;
}

::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 5px;
}

::-webkit-scrollbar-thumb {
background: transparent;
}

::-webkit-scrollbar-thumb:hover {
background: #888;
border-radius: 5px;
}

.container-time-entries {
margin: 2px;
div.time-entries {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { CalendarEvent, CalendarView } from 'angular-calendar';
import { differenceInMinutes, startOfDay, startOfHour } from 'date-fns';
import * as moment from 'moment';
import { Observable, of } from 'rxjs';
import { Entry } from 'src/app/modules/shared/models';
Expand All @@ -14,40 +15,41 @@ describe('CalendarComponent', () => {
let fakeEntry: Entry;
let fakeEntryRunning: Entry;

beforeEach(waitForAsync( () => {
TestBed.configureTestingModule({
declarations: [ CalendarComponent ]
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [CalendarComponent],
}).compileComponents();

currentDate = moment();
fakeEntry = {
id: 'entry_1',
project_id: 'abc',
project_name: 'Time-tracker',
start_date: new Date('2020-02-05T15:36:15.887Z'),
end_date: new Date('2020-02-05T18:36:15.887Z'),
customer_name: 'ioet Inc.',
activity_id: 'development',
technologies: ['Angular', 'TypeScript'],
description: 'No comments',
uri: 'EY-25',
};
fakeEntryRunning = {
id: 'entry_1',
project_id: 'abc',
project_name: 'Time-tracker',
start_date: new Date('2020-02-05T15:36:15.887Z'),
end_date: null,
customer_name: 'ioet Inc.',
activity_id: 'development',
technologies: ['Angular', 'TypeScript'],
description: 'No comments',
uri: 'EY-25',
};

jasmine.clock().mockDate(currentDate.toDate());
})
.compileComponents();

currentDate = moment();
fakeEntry = {
id: 'entry_1',
project_id: 'abc',
project_name: 'Time-tracker',
start_date: new Date('2020-02-05T15:36:15.887Z'),
end_date: new Date('2020-02-05T18:36:15.887Z'),
customer_name: 'ioet Inc.',
activity_id: 'development',
technologies: ['Angular', 'TypeScript'],
description: 'No comments',
uri: 'EY-25',
};
fakeEntryRunning = {
id: 'entry_1',
project_id: 'abc',
project_name: 'Time-tracker',
start_date: new Date('2020-02-05T15:36:15.887Z'),
end_date: null,
customer_name: 'ioet Inc.',
activity_id: 'development',
technologies: ['Angular', 'TypeScript'],
description: 'No comments',
uri: 'EY-25',
};

jasmine.clock().mockDate(currentDate.toDate());
}));
);

beforeEach(() => {
fixture = TestBed.createComponent(CalendarComponent);
Expand Down Expand Up @@ -83,11 +85,11 @@ describe('CalendarComponent', () => {
end: fakeEntry.end_date,
title: fakeEntry.description,
id: fakeEntry.id,
meta: fakeEntry
meta: fakeEntry,
};
const fakeDatasource = {
isLoading: false,
data: [fakeEntry]
data: [fakeEntry],
};
const fakeTimeEntries = of(fakeDatasource);
const expectedtimeEntriesAsEvent = [fakeTimeEntryAsEvent];
Expand All @@ -104,11 +106,11 @@ describe('CalendarComponent', () => {
end: fakeEntryRunning.end_date,
title: fakeEntryRunning.description,
id: fakeEntryRunning.id,
meta: fakeEntryRunning
meta: fakeEntryRunning,
};
const fakeDatasource = {
isLoading: false,
data: [fakeEntryRunning]
data: [fakeEntryRunning],
};
const fakeTimeEntries = of(fakeDatasource);
const expectedtimeEntriesAsEvent = [fakeTimeEntryAsEvent];
Expand Down Expand Up @@ -141,7 +143,7 @@ describe('CalendarComponent', () => {
end: fakeEntry.end_date,
title: fakeEntry.description,
id: fakeEntry.id,
meta: fakeEntry
meta: fakeEntry,
};
const fakeValueEmit = {
id: fakeEntry.id,
Expand All @@ -159,7 +161,7 @@ describe('CalendarComponent', () => {
end: fakeEntry.end_date,
title: fakeEntry.description,
id: fakeEntry.id,
meta: fakeEntry
meta: fakeEntry,
};
const fakeValueEmit = {
timeEntry: fakeEntry,
Expand Down Expand Up @@ -195,6 +197,13 @@ describe('CalendarComponent', () => {
expect(component.calendarView).toEqual(fakeCalendarView);
});

it('set srcoll to current time marker in calendarView when is call scrollToCurrentTimeMarker', () => {
const fakeCalendarView: CalendarView = CalendarView.Week;
spyOn(component, 'scrollToCurrentTimeMarker');
component.changeCalendarView(fakeCalendarView);
expect(component.scrollToCurrentTimeMarker).toHaveBeenCalled();
});

it('set false in nextDateDisabled when call navigationEnable and calendarView != Month and currentDate + 1 day is not greater to initialDate', () => {
component.currentDate = moment().subtract(2, 'day').toDate();
component.initialDate = moment().toDate();
Expand Down
102 changes: 66 additions & 36 deletions src/app/modules/time-entries/components/calendar/calendar.component.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import {
CalendarEvent,
CalendarView,
} from 'angular-calendar';
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
Input,
OnInit,
Output,
ViewChild,
} from '@angular/core';
import { CalendarEvent, CalendarView } from 'angular-calendar';
import { Observable } from 'rxjs';
import * as moment from 'moment';
import { DataSource } from '../../../shared/models/data-source.model';
import { Entry } from 'src/app/modules/shared/models';
import { map } from 'rxjs/operators';
import { SubstractDatePipe } from 'src/app/modules/shared/pipes/substract-date/substract-date.pipe';
import { differenceInMinutes, startOfDay, startOfHour } from 'date-fns';

@Component({
selector: 'app-calendar',
templateUrl: './calendar.component.html',
styleUrls: ['./calendar.component.scss'],
})
export class CalendarComponent implements OnInit {
@Input() set timeEntries$(timeEntries: Observable<DataSource<Entry>>){
readonly DEFAULT_HEADER_HEIGHT = 52;
readonly VARIATION_HEIGHT: number = 2;

@ViewChild('scrollContainer') scrollContainer: ElementRef<HTMLElement>;

@Input() set timeEntries$(timeEntries: Observable<DataSource<Entry>>) {
this.castEntryToCalendarEvent(timeEntries);
}
@Input() calendarView: CalendarView = CalendarView.Month;
Expand All @@ -25,7 +37,7 @@ export class CalendarComponent implements OnInit {
@Output() viewModal: EventEmitter<any> = new EventEmitter<string>();
@Output() deleteTimeEntry: EventEmitter<any> = new EventEmitter<string>();
@Output() changeDate: EventEmitter<any> = new EventEmitter<{
date: Date
date: Date;
}>();

initialDate: Date;
Expand All @@ -34,97 +46,115 @@ export class CalendarComponent implements OnInit {
timeEntriesAsEvent: CalendarEvent[];
nextDateDisabled: boolean;

constructor() {
constructor(private referenceChangeDetector: ChangeDetectorRef) {
this.initialDate = new Date();
this.previusDate = new Date();
this.isToday = false;
this.timeEntriesAsEvent = [];
this.nextDateDisabled = true;
}
}

ngOnInit(): void {
this.isToday = this.isVisibleForCurrentDate();
this.navigationEnable(this.calendarView);
}

get CalendarViewEnum(): typeof CalendarView{
get CalendarViewEnum(): typeof CalendarView {
return CalendarView;
}

scrollToCurrentTimeMarker() {
console.log('Si entro');
if (this.calendarView === CalendarView.Week || CalendarView.Day) {
console.log(`Calendar View ${this.calendarView}`);
const minutesSinceStartOfDay = differenceInMinutes(startOfHour(this.currentDate), startOfDay(this.currentDate));
const headerHeight = this.calendarView === CalendarView.Week ? this.DEFAULT_HEADER_HEIGHT : 0;
this.scrollContainer.nativeElement.scrollTop = minutesSinceStartOfDay * this.VARIATION_HEIGHT + headerHeight;
}
}

castEntryToCalendarEvent(timeEntries$: Observable<DataSource<Entry>>) {
timeEntries$.pipe(
map((timeEntriesDatasorce) => timeEntriesDatasorce.data.map(
(timeEntries) => ({
start: new Date(timeEntries.start_date),
end: timeEntries.end_date ? new Date(timeEntries.end_date) : null ,
title: timeEntries.description,
id: timeEntries.id,
meta: timeEntries
} as CalendarEvent)
timeEntries$
.pipe(
map((timeEntriesDatasorce) =>
timeEntriesDatasorce.data.map(
(timeEntries) =>
({
start: new Date(timeEntries.start_date),
end: timeEntries.end_date ? new Date(timeEntries.end_date) : null,
title: timeEntries.description,
id: timeEntries.id,
meta: timeEntries,
} as CalendarEvent)
)
)
)
)
.subscribe((timeEntriesAsEvent) => {
.subscribe((timeEntriesAsEvent) => {
this.timeEntriesAsEvent = [...timeEntriesAsEvent].reverse();
});
});
}

handleEditEvent(timeEntryAsEvent: CalendarEvent): void {
this.viewModal.emit( {
id: timeEntryAsEvent.id
this.viewModal.emit({
id: timeEntryAsEvent.id,
});
}

handleDeleteEvent(timeEntryAsEvent: CalendarEvent): void {
this.deleteTimeEntry.emit({
timeEntry: timeEntryAsEvent.meta
timeEntry: timeEntryAsEvent.meta,
});
}

handleChangeDateEvent(): void{
handleChangeDateEvent(): void {
const date = this.currentDate;
this.isToday = this.isVisibleForCurrentDate();
this.navigationEnable(this.calendarView);
this.changeDate.emit({date});
this.changeDate.emit({ date });
}

changeCalendarView(calendarView: CalendarView){
changeCalendarView(calendarView: CalendarView) {
this.calendarView = calendarView;
this.scrollContainer.nativeElement.scrollTop = 0;
if (this.calendarView !== CalendarView.Month) {
this.referenceChangeDetector.detectChanges();
this.scrollToCurrentTimeMarker();
}
}

navigationEnable(calendarView: CalendarView){
navigationEnable(calendarView: CalendarView) {
let enable = false;
const currentDate = moment(this.currentDate);
const initialDate = moment(this.initialDate);
if (calendarView === CalendarView.Month){
if (calendarView === CalendarView.Month) {
if (currentDate.month() === initialDate.month() && currentDate.year() === initialDate.year()) {
enable = true;
}
}
currentDate.add(1, 'day');
if (currentDate > initialDate){
if (currentDate > initialDate) {
enable = true;
}
this.nextDateDisabled = enable;
}

getTimeWork(startDate: Date, endDate: Date): number{
if (!endDate){
getTimeWork(startDate: Date, endDate: Date): number {
if (!endDate) {
return 30;
}
return new SubstractDatePipe().transformInMinutes( endDate , startDate);
return new SubstractDatePipe().transformInMinutes(endDate, startDate);
}

timeIsGreaterThan(startDate: Date, endDate: Date, timeRange: number ): boolean{
timeIsGreaterThan(startDate: Date, endDate: Date, timeRange: number): boolean {
const timeWorkInMinutes = this.getTimeWork(startDate, endDate);
return timeWorkInMinutes > timeRange;
}

isVisibleForCurrentView(currentCalendarView: CalendarView, desiredView: CalendarView ): boolean{
isVisibleForCurrentView(currentCalendarView: CalendarView, desiredView: CalendarView): boolean {
return currentCalendarView === desiredView;
}

isVisibleForCurrentDate(): boolean{
isVisibleForCurrentDate(): boolean {
const currentDate: Date = new Date(this.currentDate);
const initialDate: Date = new Date(this.initialDate);
return currentDate.setHours(0, 0, 0, 0) === initialDate.setHours(0, 0, 0, 0);
Expand Down