Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<form [formGroup]="entryForm" (ngSubmit)="onSubmit()">
<label><input id='isEntryRunning' type="checkbox" (change)="onIsRunningChange($event)" [checked]="isEntryRunning"> I am working on
this</label>

<div class="input-group input-group-sm mb-3">

<div class="input-group-prepend">
<span class="input-group-text span-width">Project</span>
</div>
Expand All @@ -11,13 +15,14 @@
formControlName="project_id"
>
<option value="" selected="selected"></option>
<option *ngFor="let project of listProjects" value="{{ project.id }}">{{ project.customer_name }} - {{ project.name }}</option>
<option *ngFor="let project of listProjects" value="{{ project.id }}">{{ project.customer_name }}
- {{ project.name }}</option>
</select>
</div>

<div class="input-group input-group-sm mb-3">
<div class="input-group-prepend">
<span class="input-group-text span-width" id="inputGroup-sizing-sm">Activity</span>
<span class="input-group-text span-width">Activity</span>
</div>
<select
[class.is-invalid]="activity_id.invalid && activity_id.touched"
Expand All @@ -37,7 +42,7 @@

<div class="input-group input-group-sm mb-3">
<div class="input-group-prepend">
<span class="input-group-text span-width" id="inputGroup-sizing-sm">Ticket</span>
<span class="input-group-text span-width">Ticket</span>
</div>
<input
formControlName="uri"
Expand All @@ -51,7 +56,7 @@

<div class="input-group input-group-sm mb-3">
<div class="input-group-prepend">
<span class="input-group-text span-width" id="inputGroup-sizing-sm">Date</span>
<span class="input-group-text span-width">Date</span>
</div>
<input
formControlName="entry_date"
Expand All @@ -66,11 +71,11 @@
</div>
<div class="input-group input-group-sm mb-3">
<div class="input-group-prepend">
<span class="input-group-text span-width" id="inputGroup-sizing-sm">Time in</span>
<span class="input-group-text span-width">Time in</span>
</div>
<input
[clearIfNotMatch]="true"
[showMaskTyped] = "true"
[clearIfNotMatch]="true"
[showMaskTyped]="true"
[dropSpecialCharacters]="false"
matInput
mask="Hh:m0"
Expand All @@ -83,12 +88,13 @@
required
aria-describedby="inputGroup-sizing-sm"
/>
<div class="input-group-prepend">
<span class="input-group-text span-width" id="inputGroup-sizing-sm">Time out</span>
<div class="input-group-prepend" *ngIf="!isEntryRunning">
<span class="input-group-text span-width">Time out</span>
</div>
<input
[clearIfNotMatch]="true"
[showMaskTyped] = "true"
*ngIf="!isEntryRunning"
[clearIfNotMatch]="true"
[showMaskTyped]="true"
[dropSpecialCharacters]="false"
matInput
mask="Hh:m0"
Expand All @@ -112,11 +118,12 @@

<div class="form-group text-left">
<label for="NotesTextarea">Description</label>
<textarea maxlength="1500" formControlName="description" class="form-control" id="NotesTextarea" rows="3"></textarea>
<textarea maxlength="1500" formControlName="description" class="form-control" id="NotesTextarea"
rows="3"></textarea>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" [disabled]="!entryForm.valid">Save</button>
<button #closeModal type="button" class="btn btn-secondary" data-dismiss="modal" >
<button #closeModal type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { TechnologiesComponent } from './../technologies/technologies.component'
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { provideMockStore, MockStore } from '@ngrx/store/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { formatDate } from '@angular/common';
import { DatePipe, formatDate } from '@angular/common';

import { TechnologyState } from '../../store/technology.reducers';
import { allTechnologies } from '../../store/technology.selectors';
Expand All @@ -22,21 +22,23 @@ describe('DetailsFieldsComponent', () => {
let mockProjectsSelector;
let mockEntriesUpdateErrorSelector;
let mockEntriesCreateErrorSelector;
let entryToEdit;
let formValues;

const state = {
projects: {
projects: [{ id: 'id', name: 'name', project_type_id: '' }],
customerProjects: [{ id: 'id', name: 'name', description: 'description', project_type_id: '123' }],
projects: [{id: 'id', name: 'name', project_type_id: ''}],
customerProjects: [{id: 'id', name: 'name', description: 'description', project_type_id: '123'}],
isLoading: false,
message: '',
projectToEdit: undefined,
},
technologies: {
technologyList: { items: [{ name: 'java' }] },
technologyList: {items: [{name: 'java'}]},
isLoading: false,
},
activities: {
data: [{ id: 'fc5fab41-a21e-4155-9d05-511b956ebd05', tenant_id: 'ioet', deleted: null, name: 'abc' }],
data: [{id: 'fc5fab41-a21e-4155-9d05-511b956ebd05', tenant_id: 'ioet', deleted: null, name: 'abc'}],
isLoading: false,
message: 'Data fetch successfully!',
activityIdToEdit: '',
Expand All @@ -61,7 +63,7 @@ describe('DetailsFieldsComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [DetailsFieldsComponent, TechnologiesComponent],
providers: [provideMockStore({ initialState: state })],
providers: [provideMockStore({initialState: state})],
imports: [FormsModule, ReactiveFormsModule],
}).compileComponents();
store = TestBed.inject(MockStore);
Expand All @@ -74,28 +76,17 @@ describe('DetailsFieldsComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(DetailsFieldsComponent);
component = fixture.componentInstance;
});

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

it('should emit ngOnChange without data', () => {
component.entryToEdit = null;
component.ngOnChanges();
expect(component.entryForm.value).toEqual(initialData);
});

it('should emit ngOnChange with new data', () => {
const entryToEdit = {
entryToEdit = {
project_id: '',
activity_id: '',
uri: 'ticketUri',
start_date: null,
end_date: null,
description: '',
technologies: [],
id: 'xyz'
};
const formValue = {
formValues = {
project_id: '',
activity_id: '',
uri: 'ticketUri',
Expand All @@ -105,9 +96,24 @@ describe('DetailsFieldsComponent', () => {
description: '',
technology: '',
};
});

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

it('should emit ngOnChange without data', () => {
component.entryToEdit = null;
component.ngOnChanges();
expect(component.entryForm.value).toEqual(initialData);
});

it('should emit ngOnChange with new data', () => {
component.entryToEdit = entryToEdit;

component.ngOnChanges();
expect(component.entryForm.value).toEqual(formValue);

expect(component.entryForm.value).toEqual(formValues);
});

it('should emit ngOnChange with new data', () => {
Expand Down Expand Up @@ -170,4 +176,79 @@ describe('DetailsFieldsComponent', () => {
};
expect(component.saveEntry.emit).toHaveBeenCalledWith(data);
});

it('when the current entry is not running, then the end hour input should be rendered', () => {
component.isEntryRunning = false;
fixture.detectChanges();

const endHourInput = fixture.debugElement.nativeElement.querySelector('#end_hour');
expect(endHourInput).toBeDefined();
});

it('when the current entry is running, then the end hour input should not be rendered', () => {
component.isEntryRunning = true;
fixture.detectChanges();

const endHourInput = fixture.debugElement.nativeElement.querySelector('#end_hour');
expect(endHourInput).toBeNull();
});

it('when creating a new entry, then the new entry should be marked as not running', () => {
component.entryToEdit = null;

expect(component.isEntryRunning).toBeFalse();
});

it('when editing entry that is currently running, then the entry should be marked as running', () => {
component.entryToEdit = {...entryToEdit, running: true};

fixture.componentInstance.ngOnChanges();

expect(component.isEntryRunning).toBeTrue();
});

it('when editing entry that already finished, then the entry should not be marked as running', () => {
component.entryToEdit = {...entryToEdit, running: false};

fixture.componentInstance.ngOnChanges();

expect(component.isEntryRunning).toBeFalse();
});

it('when editing entry that already finished, then the entry should not be marked as running', () => {
component.entryToEdit = {...entryToEdit, running: false};

fixture.componentInstance.ngOnChanges();

expect(component.isEntryRunning).toBeFalse();
});

it('when submitting a entry that is currently running, the end date should not be sent ', () => {
component.isEntryRunning = true;
spyOn(component.saveEntry, 'emit');

component.entryForm.setValue({...formValues, entry_date: '2020-06-11'});
component.onSubmit();
const data = {
project_id: '',
activity_id: '',
technologies: [],
description: '',
start_date: '2020-06-11T00:00',
uri: 'ticketUri',
};
expect(component.saveEntry.emit).toHaveBeenCalledWith(data);
});

it('when disabling current entry is running, then the end hour should be set to the current time', () => {
const datePipe: DatePipe = new DatePipe('en');
const currentTime = datePipe.transform(new Date(), 'HH:mm');

const checkIsEntryRunning: Element = fixture.debugElement.nativeElement.querySelector('#isEntryRunning');
checkIsEntryRunning.dispatchEvent(new Event('change'));
fixture.detectChanges();

const endHourInput: HTMLInputElement = fixture.debugElement.nativeElement.querySelector('#end_hour');
expect(endHourInput.value).toEqual(currentTime);
});
});
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
import {
Component,
OnChanges,
OnInit,
Input,
Output,
EventEmitter,
ViewChild,
ElementRef,
} from '@angular/core';
import { Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild, } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { Store, select } from '@ngrx/store';
import { select, Store } from '@ngrx/store';
import { formatDate } from '@angular/common';

import { Project, Activity } from '../../models';
import { Activity, Entry, Project } from '../../models';
import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer';
import { TechnologyState } from '../../store/technology.reducers';
import { LoadActivities, ActivityState, allActivities } from '../../../activities-management/store';
import { ActivityState, allActivities, LoadActivities } from '../../../activities-management/store';
import { getProjects } from '../../../customer-management/components/projects/components/store/project.selectors';
import * as projectActions from '../../../customer-management/components/projects/components/store/project.actions';
import { EntryState } from '../../../time-clock/store/entry.reducer';
import * as entryActions from '../../../time-clock/store/entry.actions';
import { getUpdateError, getCreateError } from 'src/app/modules/time-clock/store/entry.selectors';
import { getCreateError, getUpdateError } from 'src/app/modules/time-clock/store/entry.selectors';

type Merged = TechnologyState & ProjectState & ActivityState & EntryState;

@Component({
Expand All @@ -29,7 +21,7 @@ type Merged = TechnologyState & ProjectState & ActivityState & EntryState;
styleUrls: ['./details-fields.component.scss'],
})
export class DetailsFieldsComponent implements OnChanges, OnInit {
@Input() entryToEdit;
@Input() entryToEdit: Entry;
@Input() formType: string;
@Output() saveEntry = new EventEmitter();
@ViewChild('closeModal') closeModal: ElementRef;
Expand All @@ -38,8 +30,7 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
isLoading = false;
listProjects: Project[] = [];
activities: Activity[] = [];
keyword = 'name';
showlist: boolean;
isEntryRunning = false;

constructor(private formBuilder: FormBuilder, private store: Store<Merged>) {
this.entryForm = this.formBuilder.group({
Expand Down Expand Up @@ -84,6 +75,7 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
}

ngOnChanges(): void {
this.isEntryRunning = this.entryToEdit ? this.entryToEdit.running : false;
if (this.entryToEdit) {
this.selectedTechnologies = this.entryToEdit.technologies;
this.entryForm.setValue({
Expand Down Expand Up @@ -156,6 +148,16 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
end_date: `${entryDate}T${this.entryForm.value.end_hour.trim()}`,
uri: this.entryForm.value.uri,
};
if (this.isEntryRunning) {
delete entry.end_date;
}
this.saveEntry.emit(entry);
}

onIsRunningChange(event: any) {
this.isEntryRunning = event.currentTarget.checked;
if (!this.isEntryRunning) {
this.entryForm.patchValue({end_hour: formatDate(new Date(), 'HH:mm', 'en')});
}
}
}
2 changes: 2 additions & 0 deletions src/app/modules/shared/models/entry.model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface Entry {
running?: boolean;
id: string;
start_date: Date;
end_date: Date;
Expand All @@ -8,6 +9,7 @@ export interface Entry {
uri?: string;
project_id?: string;
owner_email?: string;
description?: string;
}

export interface NewEntry {
Expand Down
1 change: 0 additions & 1 deletion src/app/modules/time-clock/pipes/time-details.pipe.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { TimeDetails } from './../models/time.entry.summary';
import { TimeDetailsPipe } from './time-details.pipe';

describe('TimeDetailsPipe', () => {
Expand Down
Loading