Skip to content
Closed
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
refactor: TTA-49 change date picker
  • Loading branch information
jimmyjaramillo committed Jun 14, 2022
commit 6a5a1bc4605826171e198c33b67c00aeff7b5d4c
12 changes: 12 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatInputModule } from '@angular/material/input';
import { MatIconModule } from '@angular/material/icon';
import { MatCardModule } from '@angular/material/card';
import { MatNativeDateModule } from '@angular/material/core';
import { MatMomentDateModule } from '@angular/material-moment-adapter';
import { NgxPaginationModule } from 'ngx-pagination';
import { AutocompleteLibModule } from 'angular-ng-autocomplete';
Expand Down Expand Up @@ -90,6 +93,9 @@ import { DarkModeComponent } from './modules/shared/components/dark-mode/dark-mo
import { SocialLoginModule, SocialAuthServiceConfig } from 'angularx-social-login';
import { GoogleLoginProvider } from 'angularx-social-login';
import { SearchUserComponent } from './modules/shared/components/search-user/search-user.component';
import { TimeRangeCustomComponent } from './modules/reports/components/time-range-custom/time-range-custom.component';
import { TimeRangeHeaderComponent } from './modules/reports/components/time-range-custom/time-range-header/time-range-header.component';
import { TimeRangePanelComponent } from './modules/reports/components/time-range-custom/time-range-panel/time-range-panel.component';

const maskConfig: Partial<IConfig> = {
validation: false,
Expand Down Expand Up @@ -146,6 +152,9 @@ const maskConfig: Partial<IConfig> = {
CalendarComponent,
DropdownComponent,
DarkModeComponent,
TimeRangeCustomComponent,
TimeRangeHeaderComponent,
TimeRangePanelComponent,
],
imports: [
NgxMaskModule.forRoot(maskConfig),
Expand All @@ -165,6 +174,9 @@ const maskConfig: Partial<IConfig> = {
NgxMaterialTimepickerModule,
UiSwitchModule,
DragDropModule,
MatIconModule,
MatCardModule,
MatNativeDateModule,
StoreModule.forRoot(reducers, {
metaReducers,
}),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<form (ngSubmit)="onSubmit()" class="date-range-form">
<label class="col-form-label my-1">Select your Date Range:</label>
<mat-form-field appearance="fill">
<mat-label>Enter a date range</mat-label>
<mat-date-range-input [formGroup]="range" [rangePicker]="picker">
<input matStartDate formControlName="start" placeholder="Start date" />
<input matEndDate formControlName="end" placeholder="End date" />
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-date-range-picker
#picker
[calendarHeaderComponent]="TimeRangeHeader"
></mat-date-range-picker>
</mat-form-field>
<div class="col-12 col-md-2 my-1">
<button type="submit" class="btn btn-primary">Search</button>
</div>
</form>



Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
:host {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}

.date-range-form{
display: flex;
justify-content: space-between;
width: 100%;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import { SimpleChange } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
import * as moment from 'moment';
import { IndividualConfig, ToastrService } from 'ngx-toastr';
import { EntryState } from 'src/app/modules/time-clock/store/entry.reducer';
import * as entryActions from '../../../time-clock/store/entry.actions';


import { TimeRangeCustomComponent } from './time-range-custom.component';

describe('TimeRangeCustomComponent', () => {
let component: TimeRangeCustomComponent;
let fixture: ComponentFixture<TimeRangeCustomComponent>;
let store: MockStore<EntryState>;
const toastrServiceStub = {
error: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { }
};

const timeEntry = {
id: '123',
start_date: new Date(),
end_date: new Date(),
activity_id: '123',
technologies: ['react', 'redux'],
comments: 'any comment',
uri: 'custom uri',
project_id: '123'
};

const state = {
active: timeEntry,
entryList: [timeEntry],
isLoading: false,
message: '',
createError: false,
updateError: false,
timeEntriesSummary: null,
entriesForReport: [timeEntry],
};

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [FormsModule, ReactiveFormsModule],
declarations: [ TimeRangeCustomComponent ],
providers: [
provideMockStore({ initialState: state }),
{ provide: ToastrService, useValue: toastrServiceStub }
],
})
.compileComponents();
store = TestBed.inject(MockStore);
});

beforeEach(() => {
fixture = TestBed.createComponent(TimeRangeCustomComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('setInitialDataOnScreen on ngOnInit', () => {
spyOn(component, 'setInitialDataOnScreen');

component.ngOnInit();

expect(component.setInitialDataOnScreen).toHaveBeenCalled();
});

it('LoadEntriesByTimeRange action is triggered when start date is before end date', () => {
const yesterday = moment(new Date()).subtract(1, 'days');
const today = moment(new Date());
spyOn(store, 'dispatch');
component.range.controls.start.setValue(yesterday);
component.range.controls.end.setValue(today);

component.onSubmit();

expect(store.dispatch).toHaveBeenCalledWith(new entryActions.LoadEntriesByTimeRange({
start_date: yesterday.startOf('day'),
end_date: today.endOf('day')
}));
});

it('shows an error when the end date is before the start date', () => {
spyOn(toastrServiceStub, 'error');
const yesterday = moment(new Date()).subtract(1, 'days');
const today = moment(new Date());
spyOn(store, 'dispatch');
component.range.controls.start.setValue(today);
component.range.controls.end.setValue(yesterday);

component.onSubmit();

expect(toastrServiceStub.error).toHaveBeenCalled();
});

it('setInitialDataOnScreen sets dates in form', () => {
spyOn(component.range.controls.start, 'setValue');
spyOn(component.range.controls.end, 'setValue');

component.setInitialDataOnScreen();

expect(component.range.controls.start.setValue).toHaveBeenCalled();
expect(component.range.controls.end.setValue).toHaveBeenCalled();

});

it('triggers onSubmit to set initial data', () => {
spyOn(component, 'onSubmit');

component.setInitialDataOnScreen();

expect(component.onSubmit).toHaveBeenCalled();
});

it('When the ngOnChanges method is called, the onSubmit method is called', () => {
const userId = 'abcd';
spyOn(component, 'onSubmit');

component.ngOnChanges({userId: new SimpleChange(null, userId, false)});

expect(component.onSubmit).toHaveBeenCalled();
});

it('When the ngOnChanges method is the first change, the onSubmit method is not called', () => {
const userId = 'abcd';
spyOn(component, 'onSubmit');

component.ngOnChanges({userId: new SimpleChange(null, userId, true)});

expect(component.onSubmit).not.toHaveBeenCalled();
});

afterEach(() => {
fixture.destroy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { OnChanges, SimpleChanges, Component, OnInit, Input } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { TimeRangeHeaderComponent } from './time-range-header/time-range-header.component';
import { DATE_FORMAT } from 'src/environments/environment';
import { formatDate } from '@angular/common';
import {Store} from '@ngrx/store';
import {EntryState} from '../../../time-clock/store/entry.reducer';
import { ToastrService } from 'ngx-toastr';

import * as entryActions from '../../../time-clock/store/entry.actions';
import * as moment from 'moment';


@Component({
selector: 'app-time-range-custom',
templateUrl: './time-range-custom.component.html',
styleUrls: ['./time-range-custom.component.scss']
})
export class TimeRangeCustomComponent implements OnInit, OnChanges {
@Input() userId: string;

readonly TimeRangeHeader = TimeRangeHeaderComponent;

range = new FormGroup({
start: new FormControl(),
end: new FormControl(),
});

constructor(private store: Store<EntryState>, private toastrService: ToastrService) {
}
ngOnInit(): void {
this.setInitialDataOnScreen();
}

ngOnChanges(changes: SimpleChanges){
if (!changes.userId.firstChange){
this.onSubmit();
}
}

setInitialDataOnScreen() {
this.range.setValue({
start: formatDate(moment().startOf('isoWeek').format('l'), DATE_FORMAT, 'en'),
end: formatDate(moment().format('l'), DATE_FORMAT, 'en')
});
this.onSubmit();
}

onSubmit() {
const startDate = moment(this.range.getRawValue().start).startOf('day');
const endDate = moment(this.range.getRawValue().end).endOf('day');
if (endDate.isBefore(startDate)) {
this.toastrService.error('The end date should be after the start date');
} else {
this.store.dispatch(new entryActions.LoadEntriesByTimeRange({
start_date: moment(this.range.getRawValue().start).startOf('day'),
end_date: moment(this.range.getRawValue().end).endOf('day'),
}, this.userId));
}
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<app-time-range-panel></app-time-range-panel>

<div class="time-range-header">
<button
mat-icon-button
class="time-range-double-arrow"
(click)="previousClicked('year')"
>
<mat-icon>keyboard_arrow_left</mat-icon>
<mat-icon>keyboard_arrow_left</mat-icon>
</button>
<button mat-icon-button class="time-range-month" (click)="previousClicked('month')">
<mat-icon>keyboard_arrow_left</mat-icon>
</button>

<span class="time-range-header-label">{{ periodLabel }}</span>

<button mat-icon-button class="time-range-month-next" (click)="nextClicked('month')">
<mat-icon>keyboard_arrow_right</mat-icon>
</button>
<button
mat-icon-button
class="time-range-double-arrow time-range-double-arrow-next"
(click)="nextClicked('year')"
>
<mat-icon>keyboard_arrow_right</mat-icon>
<mat-icon>keyboard_arrow_right</mat-icon>
</button>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.time-range-header {
display: flex;
align-items: center;
padding: 0.5em;
}

.time-range-header-label {
flex: 1;
height: 1em;
font-weight: 500;
text-align: center;
}

.time-range-double-arrow .mat-icon {
margin: -22%;
}
Loading