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
fix: #238 Add_error_message_next_to_fields
  • Loading branch information
DiegoTinitana committed May 20, 2020
commit 0dcc8d6978146b75ffc5b26da7ece78156456c4b
Original file line number Diff line number Diff line change
@@ -1,31 +1,42 @@
<form [formGroup]="entryForm" (ngSubmit)="onSubmit()">
<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">Project</span>
<span class="input-group-text span-width">Project</span>
</div>
<select
data-toggle="tooltip"
title="{{ project_id.invalid && project_id.touched ? 'Project is required' : '' }}"
[class.is-invalid]="project_id.invalid && project_id.touched"
required
id="project_id"
class="form-control"
class="custom-select"
formControlName="project_id"
>
<option *ngFor="let project of listProjects" value="{{project.id}}">{{ project.name }}</option>
<option value="" selected="selected"></option>
<option *ngFor="let project of listProjects" value="{{ project.id }}">{{ 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>
</div>
<select
data-toggle="tooltip"
title="{{ activity_id.invalid && activity_id.touched ? 'Activity is required' : '' }}"
[class.is-invalid]="activity_id.invalid && activity_id.touched"
required
id="activity_id"
class="form-control"
class="custom-select"
formControlName="activity_id"
>
<option *ngFor="let activity of activities" value="{{activity.id}}">{{ activity.name }}</option>
<option value="" selected="selected"></option>
<option *ngFor="let activity of activities" value="{{ activity.id }}">{{ activity.name }}</option>
</select>
<div
class="invalid-feedback"
*ngIf="(activity_id.dirty || activity_id.touched) && activity_id.invalid && activity_id.errors.required"
></div>
</div>

<div class="input-group input-group-sm mb-3">
Expand Down Expand Up @@ -53,19 +64,21 @@
class="form-control"
aria-label="Small"
aria-describedby="inputGroup-sizing-sm"
[class.is-invalid]="start_date.invalid && start_date.touched || hoursValidation"
[class.is-invalid]="start_date.invalid && start_date.touched"
required
/>
<div class="input-group-prepend">
<span class="input-group-text span-width" id="inputGroup-sizing-sm">Start/Hour</span>
</div>
<input
data-toggle="tooltip"
title="{{ start_hour.invalid && start_hour.touched ? 'Start hour is required' : '' }}"
formControlName="start_hour"
id="start_hour"
type="text"
class="form-control"
aria-label="Small"
[class.is-invalid]="start_hour.invalid && start_hour.touched || hoursValidation"
[class.is-invalid]="start_hour.invalid && start_hour.touched"
required
aria-describedby="inputGroup-sizing-sm"
/>
Expand All @@ -88,29 +101,33 @@
<span class="input-group-text span-width" id="inputGroup-sizing-sm">End/Hour</span>
</div>
<input
data-toggle="tooltip"
title="{{ (end_hour.invalid && end_hour.touched) || errorDate ? 'End hour is required' : '' }}"
formControlName="end_hour"
type="text"
id="end_hour"
class="form-control"
aria-label="Small"
[class.is-invalid]="end_hour.invalid && end_hour.touched"
[class.is-invalid]="(end_hour.invalid && end_hour.touched) || errorDate"
required
aria-describedby="inputGroup-sizing-sm"
/>
</div>

<app-technologies (technologyAdded)="onTechnologiesUpdated($event)"
(technologyRemoved)="onTechnologiesUpdated($event)"
[selectedTechnologies]="selectedTechnologies">
<app-technologies
(technologyAdded)="onTechnologiesUpdated($event)"
(technologyRemoved)="onTechnologiesUpdated($event)"
[selectedTechnologies]="selectedTechnologies"
>
</app-technologies>

<div class="form-group text-left">
<label for="NotesTextarea">Description</label>
<textarea formControlName="description" class="form-control" id="NotesTextarea" rows="3"></textarea>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Save</button>
<button #closeModal type="button" class="btn btn-secondary" data-dismiss="modal">
<button type="submit" class="btn btn-primary" [disabled]="!entryForm.valid">Save</button>
<button #closeModal type="button" class="btn btn-secondary" data-dismiss="modal" (click)="close()">
Close
</button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ describe('DetailsFieldsComponent', () => {
});

it('should emit ngOnChange with new data', () => {
const childComponent = jasmine.createSpyObj('ChildComponent', ['closeModal']);
component.closeModal = childComponent;
const formValue = {
project_id: '',
activity_id: '',
Expand All @@ -157,13 +159,17 @@ describe('DetailsFieldsComponent', () => {
});

it('should call createError ', () => {
const childComponent = jasmine.createSpyObj('ChildComponent', ['closeModal']);
component.closeModal = childComponent;
mockEntriesCreateErrorSelector = store.overrideSelector(getCreateError, false);
spyOn(store, 'dispatch');
component.ngOnInit();
expect(store.dispatch).toHaveBeenCalledWith(new entryActions.CleanEntryCreateError(null));
});

it('should call updateError ', () => {
const childComponent = jasmine.createSpyObj('ChildComponent', ['closeModal']);
component.closeModal = childComponent;
mockEntriesUpdateErrorSelector = store.overrideSelector(getUpdateError, false);
spyOn(store, 'dispatch');
component.ngOnInit();
Expand All @@ -172,44 +178,25 @@ describe('DetailsFieldsComponent', () => {

it('should emit saveEntry event', () => {
spyOn(component.saveEntry, 'emit');
component.onSubmit();
const data = {
component.entryForm.setValue({
project_id: '',
activity_id: '',
technologies: [],
description: '',
start_date: 'T00:00',
end_date: 'T00:00',
uri: '',
};
expect(component.saveEntry.emit).toHaveBeenCalledWith(data);
});

it('should emit saveEntry without project and activite fields event', () => {
spyOn(component.saveEntry, 'emit');
component.entryForm.setValue({
project_id: 'id',
activity_id: 'fc5fab41-a21e-4155-9d05-511b956ebd05',
uri: '',
start_date: '',
end_date: '',
start_date: '2020-02-05',
end_date: '2020-02-05',
start_hour: '00:00',
end_hour: '00:00',
end_hour: '00:01',
description: '',
technology: '',
});
component.activities = [
{ id: 'fc5fab41-a21e-4155-9d05-511b956ebd05', tenant_id: 'ioet', name: 'activity1', description: '' },
];
component.onSubmit();
fixture.detectChanges();
const data = {
project_id: 'id',
activity_id: 'fc5fab41-a21e-4155-9d05-511b956ebd05',
project_id: '',
activity_id: '',
technologies: [],
description: '',
start_date: 'T00:00',
end_date: 'T00:00',
start_date: '2020-02-05T00:00',
end_date: '2020-02-05T00:01',
uri: '',
};
expect(component.saveEntry.emit).toHaveBeenCalledWith(data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import * as projectActions from '../../../customer-management/components/project
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 $ from 'jquery';
import 'bootstrap';
type Merged = TechnologyState & ProjectState & ActivityState & EntryState;

@Component({
Expand All @@ -35,22 +36,16 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
@Input() formType: string;
@Output() saveEntry = new EventEmitter();
@ViewChild('closeModal') closeModal: ElementRef;
@ViewChild('list') list: ElementRef;
entryForm: FormGroup;
selectedTechnologies: string[] = [];
isLoading = false;
listProjects: Project[] = [];
activities: Activity[] = [];
keyword = 'name';
showlist: boolean;
hoursValidation: boolean;
errorDate: boolean;

constructor(private formBuilder: FormBuilder, private store: Store<Merged>, private renderer: Renderer2) {
this.renderer.listen('window', 'click', (e: Event) => {
if (this.showlist && !this.list.nativeElement.contains(e.target)) {
this.showlist = false;
}
});
this.entryForm = this.formBuilder.group({
project_id: '',
activity_id: '',
Expand All @@ -62,10 +57,10 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
uri: '',
technology: '',
});
$('[data-toggle="tooltip"]').tooltip();
}

ngOnInit(): void {

this.store.dispatch(new projectActions.LoadProjects());
const projects$ = this.store.pipe(select(getProjects));
projects$.subscribe((response) => {
Expand Down Expand Up @@ -95,7 +90,6 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
}

ngOnChanges(): void {
this.hoursValidation = false;
if (this.entryToEdit) {
this.selectedTechnologies = this.entryToEdit.technologies;
this.entryForm.setValue({
Expand All @@ -110,21 +104,25 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
technology: '',
});
} else {
this.selectedTechnologies = [];
this.entryForm.setValue({
project_id: '',
activity_id: '',
description: '',
start_date: formatDate(new Date(), 'yyyy-MM-dd', 'en'),
start_hour: '00:00',
end_date: formatDate(new Date(), 'yyyy-MM-dd', 'en'),
end_hour: '00:00',
uri: '',
technology: '',
});
this.cleanForm();
}
}

cleanForm() {
this.selectedTechnologies = [];
this.entryForm.setValue({
project_id: '',
activity_id: '',
description: '',
start_date: formatDate(new Date(), 'yyyy-MM-dd', 'en'),
start_hour: '00:00',
end_date: formatDate(new Date(), 'yyyy-MM-dd', 'en'),
end_hour: '00:00',
uri: '',
technology: '',
});
}

onTechnologiesUpdated($event: string[]) {
this.selectedTechnologies = $event;
}
Expand Down Expand Up @@ -153,8 +151,14 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
}

closeEntryModal() {
this.close();
this.closeModal.nativeElement.click();
}

close() {
this.entryForm.reset();
this.closeModal?.nativeElement?.click();
this.errorDate = false;
this.cleanForm();
}

onSubmit() {
Expand All @@ -167,6 +171,12 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
end_date: `${this.entryForm.value.end_date}T${this.entryForm.value.end_hour}`,
uri: this.entryForm.value.uri,
};
this.saveEntry.emit(entry);

if (new Date(entry.start_date) < new Date(entry.end_date)) {
this.errorDate = false;
this.saveEntry.emit(entry);
} else {
this.errorDate = true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,4 @@ describe('ProjectListHoverComponent', () => {

expect(store.dispatch).toHaveBeenCalledWith(jasmine.any(UpdateActiveEntry));
});

});
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ describe('TimeEntriesComponent', () => {
};
mockEntriesSelector = store.overrideSelector(allEntries, [newEntry]);
component.ngOnInit();
expect(component.dataByMonth.length).toEqual(1);
expect(component.dataByMonth.length).toEqual(0);
}));

it('should call dataByMonth without new date in ngOnInit()', async(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class TimeEntriesComponent implements OnInit {
dataByMonth$.subscribe((response) => {
this.entryList = response;
this.dataByMonth = this.entryList.reduce((acc: any, entry: any) => {
if (new Date(entry.start_date).getMonth() === new Date().getMonth()) {
if (new Date(entry.start_date).getMonth() === new Date().getMonth() && entry.end_date) {
const item = { ...entry };
return [...acc, item];
}
Expand Down