diff --git a/src/app/modules/time-clock/components/entry-fields/entry-fields.component.html b/src/app/modules/time-clock/components/entry-fields/entry-fields.component.html index cfa427c84..272e9d57e 100644 --- a/src/app/modules/time-clock/components/entry-fields/entry-fields.component.html +++ b/src/app/modules/time-clock/components/entry-fields/entry-fields.component.html @@ -3,24 +3,39 @@
Activity
- - +
Ticket URI
- +
- + -
Description @@ -31,8 +46,8 @@ formControlName="description" class="form-control" id="NotesTextarea" - rows="2"> + rows="2" + >
- diff --git a/src/app/modules/time-clock/components/entry-fields/entry-fields.component.ts b/src/app/modules/time-clock/components/entry-fields/entry-fields.component.ts index 0b1e2f556..b119c4a59 100644 --- a/src/app/modules/time-clock/components/entry-fields/entry-fields.component.ts +++ b/src/app/modules/time-clock/components/entry-fields/entry-fields.component.ts @@ -1,12 +1,12 @@ -import {getActiveTimeEntry} from './../../store/entry.selectors'; -import {Component, OnInit} from '@angular/core'; -import {FormBuilder, FormGroup} from '@angular/forms'; -import {select, Store} from '@ngrx/store'; +import { getActiveTimeEntry } from './../../store/entry.selectors'; +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { select, Store } from '@ngrx/store'; -import {Activity, NewEntry} from '../../../shared/models'; -import {ProjectState} from '../../../customer-management/components/projects/components/store/project.reducer'; -import {TechnologyState} from '../../../shared/store/technology.reducers'; -import {ActivityState, allActivities, LoadActivities} from '../../../activities-management/store'; +import { Activity, NewEntry } from '../../../shared/models'; +import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer'; +import { TechnologyState } from '../../../shared/store/technology.reducers'; +import { ActivityState, allActivities, LoadActivities } from '../../../activities-management/store'; import * as entryActions from '../../store/entry.actions'; @@ -18,7 +18,6 @@ type Merged = TechnologyState & ProjectState & ActivityState; styleUrls: ['./entry-fields.component.scss'], }) export class EntryFieldsComponent implements OnInit { - entryForm: FormGroup; selectedTechnologies: string[] = []; activities: Activity[] = []; @@ -29,7 +28,7 @@ export class EntryFieldsComponent implements OnInit { this.entryForm = this.formBuilder.group({ description: '', uri: '', - activity_id: '-1' + activity_id: '-1', }); } @@ -58,6 +57,10 @@ export class EntryFieldsComponent implements OnInit { }); } + get activity_id() { + return this.entryForm.get('activity_id'); + } + setDataToUpdate(entryData: NewEntry) { if (entryData) { this.entryForm.patchValue({ @@ -73,17 +76,19 @@ export class EntryFieldsComponent implements OnInit { } } + entryFormIsValidate() { + return this.entryForm.valid; + } + onSubmit() { - this.store.dispatch(new entryActions.UpdateEntryRunning({...this.newData, ...this.entryForm.value})); + this.store.dispatch(new entryActions.UpdateEntryRunning({ ...this.newData, ...this.entryForm.value })); } onTechnologyAdded($event: string[]) { - this.store.dispatch(new entryActions.UpdateEntryRunning({...this.newData, technologies: $event}) - ); + this.store.dispatch(new entryActions.UpdateEntryRunning({ ...this.newData, technologies: $event })); } onTechnologyRemoved($event: string[]) { - this.store.dispatch(new entryActions.UpdateEntryRunning({...this.newData, technologies: $event})); + this.store.dispatch(new entryActions.UpdateEntryRunning({ ...this.newData, technologies: $event })); } - } diff --git a/src/app/modules/time-clock/pages/time-clock.component.spec.ts b/src/app/modules/time-clock/pages/time-clock.component.spec.ts index b77631a4c..5ff044c4b 100644 --- a/src/app/modules/time-clock/pages/time-clock.component.spec.ts +++ b/src/app/modules/time-clock/pages/time-clock.component.spec.ts @@ -8,12 +8,18 @@ import { ProjectState } from '../../customer-management/components/projects/comp import { ProjectListHoverComponent } from '../components'; import { FilterProjectPipe } from '../../shared/pipes'; import { AzureAdB2CService } from '../../login/services/azure.ad.b2c.service'; +import { EntryFieldsComponent } from '../components/entry-fields/entry-fields.component'; +import { ToastrService } from 'ngx-toastr'; describe('TimeClockComponent', () => { let component: TimeClockComponent; let fixture: ComponentFixture; let store: MockStore; let azureAdB2CService: AzureAdB2CService; + let injectedToastrService; + const toastrService = { + error: () => {}, + }; const state = { projects: { projects: [{ id: 'id', name: 'name', project_type_id: '' }], @@ -41,11 +47,12 @@ describe('TimeClockComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], - declarations: [TimeClockComponent, ProjectListHoverComponent, FilterProjectPipe], + declarations: [TimeClockComponent, ProjectListHoverComponent, FilterProjectPipe, EntryFieldsComponent], providers: [ FormBuilder, AzureAdB2CService, provideMockStore({ initialState: state }), + { provide: ToastrService, useValue: toastrService }, ], }).compileComponents(); store = TestBed.inject(MockStore); @@ -56,6 +63,7 @@ describe('TimeClockComponent', () => { component = fixture.componentInstance; fixture.detectChanges(); azureAdB2CService = TestBed.inject(AzureAdB2CService); + injectedToastrService = TestBed.inject(ToastrService); }); it('should be created', () => { @@ -78,11 +86,27 @@ describe('TimeClockComponent', () => { expect(azureAdB2CService.getName).toHaveBeenCalledTimes(0); }); - it('clockOut dispatch a StopTimeEntryRunning action', () => { + it('stopEntry dispatch a StopTimeEntryRunning action', () => { spyOn(store, 'dispatch'); + component.stopEntry(); + expect(store.dispatch).toHaveBeenCalledWith(new StopTimeEntryRunning('id')); + }); + + it('clockOut dispatch a StopTimeEntryRunning action', () => { + spyOn(store, 'dispatch'); + spyOn(component.entryFieldsComponent, 'entryFormIsValidate').and.returnValue(true); component.clockOut(); expect(store.dispatch).toHaveBeenCalledWith(new StopTimeEntryRunning('id')); }); + + it('clockOut set error Activity is required', () => { + spyOn(store, 'dispatch'); + spyOn(injectedToastrService, 'error'); + spyOn(component.entryFieldsComponent, 'entryFormIsValidate').and.returnValue(false); + component.clockOut(); + + expect(injectedToastrService.error).toHaveBeenCalled(); + }); }); diff --git a/src/app/modules/time-clock/pages/time-clock.component.ts b/src/app/modules/time-clock/pages/time-clock.component.ts index bf98bfee4..cd64153dc 100644 --- a/src/app/modules/time-clock/pages/time-clock.component.ts +++ b/src/app/modules/time-clock/pages/time-clock.component.ts @@ -2,23 +2,29 @@ import { getActiveTimeEntry } from './../store/entry.selectors'; import { StopTimeEntryRunning } from './../store/entry.actions'; import { Entry } from './../../shared/models/entry.model'; import { Store, select } from '@ngrx/store'; -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { AzureAdB2CService } from '../../login/services/azure.ad.b2c.service'; import { Subscription } from 'rxjs'; - +import { EntryFieldsComponent } from '../components/entry-fields/entry-fields.component'; +import { ToastrService } from 'ngx-toastr'; @Component({ selector: 'app-time-clock', templateUrl: './time-clock.component.html', styleUrls: ['./time-clock.component.scss'], }) export class TimeClockComponent implements OnInit { + @ViewChild(EntryFieldsComponent) + entryFieldsComponent: EntryFieldsComponent; username: string; areFieldsVisible = false; activeTimeEntry: Entry; actionsSubscription: Subscription; - constructor(private azureAdB2CService: AzureAdB2CService, private store: Store) { - } + constructor( + private azureAdB2CService: AzureAdB2CService, + private store: Store, + private toastrService: ToastrService + ) {} ngOnInit() { this.username = this.azureAdB2CService.isLogin() ? this.azureAdB2CService.getName() : ''; @@ -32,8 +38,17 @@ export class TimeClockComponent implements OnInit { }); } - clockOut() { + stopEntry() { this.store.dispatch(new StopTimeEntryRunning(this.activeTimeEntry.id)); this.areFieldsVisible = false; } + + clockOut() { + if (this.entryFieldsComponent.entryFormIsValidate()) { + this.stopEntry(); + } else { + this.entryFieldsComponent.entryForm.get('activity_id').markAsTouched(); + this.toastrService.error('Activity is required'); + } + } } diff --git a/src/app/modules/time-entries/pages/time-entries.component.ts b/src/app/modules/time-entries/pages/time-entries.component.ts index e2bf668f2..78baaee09 100644 --- a/src/app/modules/time-entries/pages/time-entries.component.ts +++ b/src/app/modules/time-entries/pages/time-entries.component.ts @@ -92,7 +92,7 @@ export class TimeEntriesComponent implements OnInit { openModal(item: any) { this.idToDelete = item.id; - this.message = `Are you sure you want to delete ${item.activity_name}`; + this.message = `Are you sure you want to delete ${item.activity_name}?`; this.showModal = true; } }