diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 0d17e184f..1259e009a 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -57,6 +57,7 @@ import { CustomerEffects } from './modules/customer-management/store/customer-ma import { EntryEffects } from './modules/time-clock/store/entry.effects'; import { InjectTokenInterceptor } from './modules/shared/interceptors/inject.token.interceptor'; import { SubstractDatePipe } from './modules/shared/pipes/substract-date/substract-date.pipe'; +import {TechnologiesComponent} from './modules/shared/components/technologies/technologies.component'; @NgModule({ declarations: [ @@ -92,6 +93,7 @@ import { SubstractDatePipe } from './modules/shared/pipes/substract-date/substra CreateProjectTypeComponent, EntryFieldsComponent, SubstractDatePipe, + TechnologiesComponent, ], imports: [ CommonModule, diff --git a/src/app/modules/shared/components/technologies/technologies.component.html b/src/app/modules/shared/components/technologies/technologies.component.html new file mode 100644 index 000000000..8db025a33 --- /dev/null +++ b/src/app/modules/shared/components/technologies/technologies.component.html @@ -0,0 +1,36 @@ +
+
+ Technology +
+ +
+ +
LOADING...
+
+
+ {{ item.name }} +
+
+
+
+ {{ technology }} + +
+
+
+ +
+ + + diff --git a/src/app/modules/shared/components/technologies/technologies.component.scss b/src/app/modules/shared/components/technologies/technologies.component.scss new file mode 100644 index 000000000..0661cba95 --- /dev/null +++ b/src/app/modules/shared/components/technologies/technologies.component.scss @@ -0,0 +1,49 @@ +@import '../../../../../styles/colors.scss'; + +.technologies-dropdown-container { + box-shadow: 0 3px 8px 0 rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.08); + margin: 0 0 2rem 6rem; + max-height: 7.5rem; + overflow-y: auto; + + .technologies-dropdown-item { + cursor: pointer; + font-size: 0.8rem; + margin-bottom: 0.1rem; + padding: 0.2rem 0.5rem; + + &:hover { + opacity: 0.7; + background-color: #efefef; + } + } +} + +.selected-technologies-container { + margin: 0.5rem 0 0.5rem 6rem; +} + +.selected-technology { + background-color: $modal-button-secondary; + color: #ffffff; + border-radius: 0.2rem; + box-shadow: 2px 2px 5px 0px rgba(0, 0, 0, 0.75); + font-size: 0.8rem; + padding: 0.1rem 1rem 0.2rem 1.5rem; + position: relative; + margin: 0 0.5rem 0.5rem 0; + + &:hover { + opacity: 0.8; + } + + i { + cursor: pointer; + } +} + +.span-width { + width: 6rem; + background-image: $background-pantone; + color: white; +} diff --git a/src/app/modules/shared/components/technologies/technologies.component.spec.ts b/src/app/modules/shared/components/technologies/technologies.component.spec.ts new file mode 100644 index 000000000..468e21124 --- /dev/null +++ b/src/app/modules/shared/components/technologies/technologies.component.spec.ts @@ -0,0 +1,89 @@ +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; +import {MockStore, provideMockStore} from '@ngrx/store/testing'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; + +import {TechnologyState} from '../../store/technology.reducers'; +import {allTechnologies} from '../../store/technology.selectors'; +import {TechnologiesComponent} from './technologies.component'; +import * as actions from '../../store/technology.actions'; +import {ProjectState} from '../../../customer-management/components/projects/components/store/project.reducer'; + +describe('Technologies component', () => { + let component: TechnologiesComponent; + let fixture: ComponentFixture; + let store: MockStore; + let mockTechnologySelector; + + const state = { + technologies: { + technologyList: {items: [{name: 'java'}]}, + isLoading: false, + } + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [TechnologiesComponent], + providers: [provideMockStore({initialState: state})], + imports: [FormsModule, ReactiveFormsModule], + }).compileComponents(); + store = TestBed.inject(MockStore); + mockTechnologySelector = store.overrideSelector(allTechnologies, state.technologies); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TechnologiesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('when a new technology is added, it should be added to the selectedTechnologies list', () => { + const name = 'ngrx'; + component.selectedTechnologies = ['java', 'javascript']; + component.selectedTechnologies.indexOf(name); + length = component.selectedTechnologies.length; + component.addTechnology(name); + expect(component.selectedTechnologies.length).toBe(3); + }); + + it('when the max number of technologies is reached, then adding technologies is not allowed', () => { + const name = 'ngrx'; + component.selectedTechnologies = [ + 'java', + 'javascript', + 'angular', + 'angular-ui', + 'typescript', + 'scss', + 'bootstrap', + 'jasmine', + 'karma', + 'github', + ]; + length = component.selectedTechnologies.length; + component.addTechnology(name); + expect(component.selectedTechnologies.length).toBe(10); + }); + + it('when a technology is removed, then it should be removed from the technologies list', () => { + const index = 1; + component.selectedTechnologies = ['java', 'angular']; + component.removeTechnology(index); + expect(component.selectedTechnologies.length).toBe(1); + }); + + it('when querying technologies, then a FindTechnology action should be dispatched', () => { + const query = 'react'; + const target = {value: query}; + const event = new InputEvent('input'); + spyOnProperty(event, 'target').and.returnValue(target); + spyOn(store, 'dispatch'); + component.queryTechnologies(event); + + expect(store.dispatch).toHaveBeenCalledWith(new actions.FindTechnology(query)); + }); +}); diff --git a/src/app/modules/shared/components/technologies/technologies.component.ts b/src/app/modules/shared/components/technologies/technologies.component.ts new file mode 100644 index 000000000..98a74c8c9 --- /dev/null +++ b/src/app/modules/shared/components/technologies/technologies.component.ts @@ -0,0 +1,72 @@ +import {Component, ElementRef, EventEmitter, Input, OnInit, Output, Renderer2, ViewChild} from '@angular/core'; +import * as actions from '../../store/technology.actions'; +import {select, Store} from '@ngrx/store'; +import {TechnologyState} from '../../store/technology.reducers'; +import {allTechnologies} from '../../store/technology.selectors'; +import {Technology} from '../../models'; + + +@Component({ + selector: 'app-technologies', + templateUrl: './technologies.component.html', + styleUrls: ['./technologies.component.scss'] +}) +export class TechnologiesComponent implements OnInit { + private readonly MAX_NUM_TECHNOLOGIES = 10; + private readonly MIN_QUERY_LENGTH = 2; + public query = ''; + showList = false; + isLoading = false; + technology: Technology; + + @Input() + selectedTechnologies: string[] = []; + @ViewChild('technologiesDropdown') list: ElementRef; + @Output() + technologyRemoved: EventEmitter = new EventEmitter(); + @Output() + technologyAdded: EventEmitter = new EventEmitter(); + + constructor(private store: Store, private renderer: Renderer2) { + this.renderer.listen('window', 'click', (e: Event) => { + if (this.showList && !this.list.nativeElement.contains(e.target)) { + this.showList = false; + } + }); + } + + queryTechnologies(event: Event) { + const inputElement: HTMLInputElement = (event.target) as HTMLInputElement; + const query: string = inputElement.value; + if (query.length >= this.MIN_QUERY_LENGTH) { + this.showList = true; + this.store.dispatch(new actions.FindTechnology(query)); + } + } + + ngOnInit(): void { + const technologies$ = this.store.pipe(select(allTechnologies)); + technologies$.subscribe((response) => { + this.isLoading = response.isLoading; + const filteredItems = response.technologyList.items.filter(item => !this.selectedTechnologies.includes(item.name)); + this.technology = {items: filteredItems}; + }); + } + + addTechnology(name: string) { + const index = this.selectedTechnologies.indexOf(name); + if (index > -1) { + this.removeTechnology(index); + } else if (this.selectedTechnologies.length < this.MAX_NUM_TECHNOLOGIES) { + this.selectedTechnologies = [...this.selectedTechnologies, name]; + this.technologyAdded.emit(this.selectedTechnologies); + this.showList = false; + this.query = ''; + } + } + + removeTechnology(index: number) { + this.selectedTechnologies = this.selectedTechnologies.filter((item) => item !== this.selectedTechnologies[index]); + this.technologyRemoved.emit(this.selectedTechnologies); + } +} 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 6fa810d91..e843ccb66 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 @@ -1,7 +1,7 @@
- Activity + Activity
-
- -
-
- Technology -
- -
- -
LOADING...
-
-
- {{ item.name }} -
-
-
-
- {{ technology }} - -
-
- -
- +
+ +
diff --git a/src/app/modules/time-clock/components/entry-fields/entry-fields.component.scss b/src/app/modules/time-clock/components/entry-fields/entry-fields.component.scss index c26089d15..59300c381 100644 --- a/src/app/modules/time-clock/components/entry-fields/entry-fields.component.scss +++ b/src/app/modules/time-clock/components/entry-fields/entry-fields.component.scss @@ -1,14 +1,5 @@ @import '../../../../../styles/colors.scss'; -@mixin tagTechnology() { - background-color: $modal-button-secondary; - color: #ffffff; - - &:hover { - opacity: 0.8; - } -} - .span-width { width: 6rem; background-image: $background-pantone; @@ -29,47 +20,6 @@ color: white; } -.technology-content { - box-shadow: 0 3px 8px 0 rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.08); - margin: 0 0 2rem 6rem; - max-height: 7.5rem; - overflow-y: auto; - - .technology-list { - cursor: pointer; - font-size: 0.8rem; - margin-bottom: 0.1rem; - padding: 0.2rem 0.5rem; - - &:hover { - opacity: 0.7; - } - } - - .active { - background-color: #efefef; - } -} - -.tags-content { - margin: 2rem 0; - - div { - @include tagTechnology(); - - border-radius: 0.2rem; - box-shadow: 2px 2px 5px 0px rgba(0, 0, 0, 0.75); - font-size: 0.8rem; - padding: 0.1rem 1rem 0.2rem 1.5rem; - position: relative; - margin: 0 0.5rem 0.5rem 0; - - i { - cursor: pointer; - } - } -} - .ng-autocomplete { width: 100%; } diff --git a/src/app/modules/time-clock/components/entry-fields/entry-fields.component.spec.ts b/src/app/modules/time-clock/components/entry-fields/entry-fields.component.spec.ts index e8143ea49..13a6d4ba6 100644 --- a/src/app/modules/time-clock/components/entry-fields/entry-fields.component.spec.ts +++ b/src/app/modules/time-clock/components/entry-fields/entry-fields.component.spec.ts @@ -1,13 +1,12 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { provideMockStore, MockStore } from '@ngrx/store/testing'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; - -import { TechnologyState } from '../../../shared/store/technology.reducers'; -import { allTechnologies } from '../../../shared/store/technology.selectors'; -import { EntryFieldsComponent } from './entry-fields.component'; -import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer'; -import { getCustomerProjects } from '../../../customer-management/components/projects/components/store/project.selectors'; -import * as actions from '../../../shared/store/technology.actions'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; +import {MockStore, provideMockStore} from '@ngrx/store/testing'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; + +import {TechnologyState} from '../../../shared/store/technology.reducers'; +import {allTechnologies} from '../../../shared/store/technology.selectors'; +import {EntryFieldsComponent} from './entry-fields.component'; +import {ProjectState} from '../../../customer-management/components/projects/components/store/project.reducer'; +import {getCustomerProjects} from '../../../customer-management/components/projects/components/store/project.selectors'; import * as entryActions from '../../store/entry.actions'; describe('EntryFieldsComponent', () => { @@ -17,22 +16,21 @@ describe('EntryFieldsComponent', () => { let store: MockStore; let mockTechnologySelector; let mockProjectsSelector; - let length; 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: 'Training 2' }], + data: [{id: 'fc5fab41-a21e-4155-9d05-511b956ebd05', tenant_id: 'ioet', deleted: null, name: 'Training 2'}], isLoading: false, message: 'Data fetch successfully!', activityIdToEdit: '', @@ -46,7 +44,6 @@ describe('EntryFieldsComponent', () => { uri: 'abc', }, entryList: [], - isLoading: false, message: '', }, }; @@ -56,13 +53,12 @@ describe('EntryFieldsComponent', () => { project_id: 'project-id-15', description: 'description for active entry', uri: 'abc', - technology: '', }; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [EntryFieldsComponent], - providers: [provideMockStore({ initialState: state })], + providers: [provideMockStore({initialState: state})], imports: [FormsModule, ReactiveFormsModule], }).compileComponents(); store = TestBed.inject(MockStore); @@ -93,95 +89,32 @@ describe('EntryFieldsComponent', () => { expect(component.entryForm.patchValue).toHaveBeenCalledTimes(1); expect(component.entryForm.patchValue).toHaveBeenCalledWith( - { description: entryDataForm.description, uri: entryDataForm.uri, }); - expect(component.selectedTechnology).toEqual([]); + {description: entryDataForm.description, uri: entryDataForm.uri}); + expect(component.selectedTechnologies).toEqual([]); }); - it('should dispatch FindTechnology action #getTechnologies', () => { - const value = 'java'; + it('should dispatch UpdateActiveEntry action #onSubmit', () => { spyOn(store, 'dispatch'); - length = value.length; - component.getTechnologies(value); - - expect(component.showlist).toBe(true); - expect(store.dispatch).toHaveBeenCalledWith(new actions.FindTechnology(value)); + component.onSubmit(); + expect(store.dispatch).toHaveBeenCalledWith(new entryActions.UpdateActiveEntry(entry)); }); - it('should NOT dispatch FindTechnology action #getTechnologies', () => { - const value = 'j'; + it('when a technology is added, then dispatch UpdateActiveEntry', () => { + const addedTechnologies = ['react']; spyOn(store, 'dispatch'); - length = value.length; - component.getTechnologies(value); - expect(store.dispatch).not.toHaveBeenCalledWith(new actions.FindTechnology(value)); - }); + component.onTechnologyAdded(addedTechnologies); + expect(store.dispatch).toHaveBeenCalled(); - it('should add a new tag #setTechnology', () => { - spyOn(store, 'dispatch'); - const name = 'ngrx'; - component.selectedTechnology = ['java', 'javascript']; - component.selectedTechnology.indexOf(name); - length = component.selectedTechnology.length; - - const newEntry = { - id: 'id-15', - project_id: 'project-id-15', - uri: 'abc', - }; - - component.setTechnology(name); - expect(component.selectedTechnology.length).toBe(3); - expect(store.dispatch).toHaveBeenCalledWith( - new entryActions.UpdateActiveEntry({ ...newEntry, technologies: component.selectedTechnology }) - ); }); - it('should NOT add a new tag #setTechnology', () => { - const name = 'ngrx'; - component.selectedTechnology = [ - 'java', - 'javascript', - 'angular', - 'angular-ui', - 'typescript', - 'scss', - 'bootstrap', - 'jasmine', - 'karme', - 'github', - ]; - component.selectedTechnology.indexOf(name); - length = component.selectedTechnology.length; - component.setTechnology(name); - expect(component.selectedTechnology.length).toBe(10); - }); + it('when a technology is removed, then dispatch UpdateActiveEntry', () => { + const addedTechnologies = ['react']; - it('should call the removeTag function #setTechnology', () => { - const name = 'java'; - component.selectedTechnology = ['java', 'javascript']; - const index = component.selectedTechnology.indexOf(name); - spyOn(component, 'removeTag'); - component.setTechnology(name); - expect(component.removeTag).toHaveBeenCalledWith(index); - }); - - it('should dispatch UpdateActiveEntry action #removeTag function', () => { spyOn(store, 'dispatch'); - const index = 1; - const newEntry = { - id: 'id-15', - project_id: 'project-id-15', - uri: 'abc', - }; - component.selectedTechnology = ['java', 'angular']; - const technologies = component.selectedTechnology.filter((item) => item !== component.selectedTechnology[index]); - component.removeTag(index); - expect(store.dispatch).toHaveBeenCalledWith(new entryActions.UpdateActiveEntry({ ...newEntry, technologies })); - }); - it('should dispatch UpdateActiveEntry action #onSubmit', () => { - spyOn(store, 'dispatch'); - component.onSubmit(); - expect(store.dispatch).toHaveBeenCalledWith(new entryActions.UpdateActiveEntry(entry)); + component.onTechnologyAdded(addedTechnologies); + expect(store.dispatch).toHaveBeenCalled(); + }); }); 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 301e62e8b..25125d997 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,15 +1,12 @@ -import { getActiveTimeEntry } from './../../store/entry.selectors'; -import { Component, OnInit, ViewChild, ElementRef, Renderer2 } from '@angular/core'; -import { FormBuilder, FormGroup } from '@angular/forms'; -import { Store, select } 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 { Technology, Activity, NewEntry } from '../../../shared/models'; -import { allTechnologies } from '../../../shared/store/technology.selectors'; -import * as actions from '../../../shared/store/technology.actions'; - -import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer'; -import { TechnologyState } from '../../../shared/store/technology.reducers'; -import { LoadActivities, ActivityState, allActivities } 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'; @@ -22,38 +19,20 @@ type Merged = TechnologyState & ProjectState & ActivityState; }) export class EntryFieldsComponent implements OnInit { - @ViewChild('list') list: ElementRef; entryForm: FormGroup; - technology: Technology; - selectedTechnology: string[] = []; - isLoading = false; + selectedTechnologies: string[] = []; activities: Activity[] = []; - keyword = 'name'; - showlist: boolean; activeEntry; newData; - constructor(private formBuilder: FormBuilder, private store: Store, private renderer: Renderer2) { - this.renderer.listen('window', 'click', (e: Event) => { - if (this.showlist && !this.list.nativeElement.contains(e.target)) { - this.showlist = false; - } - }); + constructor(private formBuilder: FormBuilder, private store: Store) { this.entryForm = this.formBuilder.group({ description: '', - uri: '', - technology: '', + uri: '' }); } ngOnInit(): void { - const technologies$ = this.store.pipe(select(allTechnologies)); - technologies$.subscribe((response) => { - this.isLoading = response.isLoading; - const filteredItems = response.technologyList.items.filter(item => !this.selectedTechnology.includes(item.name)); - this.technology = { items: filteredItems }; - }); - this.store.dispatch(new LoadActivities()); const activities$ = this.store.pipe(select(allActivities)); activities$.subscribe((response) => { @@ -81,41 +60,24 @@ export class EntryFieldsComponent implements OnInit { uri: entryData.uri, }); if (entryData.technologies) { - this.selectedTechnology = entryData.technologies; + this.selectedTechnologies = entryData.technologies; } else { - this.selectedTechnology = []; + this.selectedTechnologies = []; } } } - getTechnologies(value) { - if (value.length >= 2) { - this.showlist = true; - this.store.dispatch(new actions.FindTechnology(value)); - } - } - - setTechnology(name: string) { - const index = this.selectedTechnology.indexOf(name); - if (index > -1) { - this.removeTag(index); - } else if (this.selectedTechnology.length < 10) { - this.selectedTechnology = [...this.selectedTechnology, name]; - this.store.dispatch( - new entryActions.UpdateActiveEntry({ ...this.newData, technologies: this.selectedTechnology }) - ); - this.showlist = false; - this.entryForm.get('technology').reset(); - } + onSubmit() { + this.store.dispatch(new entryActions.UpdateActiveEntry({...this.newData, ...this.entryForm.value})); } - removeTag(index: number) { - const technologies = this.selectedTechnology.filter((item) => item !== this.selectedTechnology[index]); - this.store.dispatch(new entryActions.UpdateActiveEntry({ ...this.newData, technologies })); + onTechnologyAdded($event: string[]) { + this.store.dispatch(new entryActions.UpdateActiveEntry({...this.newData, technologies: $event}) + ); } - onSubmit() { - this.store.dispatch(new entryActions.UpdateActiveEntry({ ...this.newData, ...this.entryForm.value })); + onTechnologyRemoved($event: string[]) { + this.store.dispatch(new entryActions.UpdateActiveEntry({...this.newData, technologies: $event})); } } diff --git a/src/app/modules/time-clock/components/project-list-hover/project-list-hover.component.ts b/src/app/modules/time-clock/components/project-list-hover/project-list-hover.component.ts index 341dd2a37..7b3d98d3d 100644 --- a/src/app/modules/time-clock/components/project-list-hover/project-list-hover.component.ts +++ b/src/app/modules/time-clock/components/project-list-hover/project-list-hover.component.ts @@ -1,13 +1,13 @@ -import { getProjects } from './../../../customer-management/components/projects/components/store/project.selectors'; -import { Component, OnInit } from '@angular/core'; -import { Store, select } from '@ngrx/store'; +import {getProjects} from './../../../customer-management/components/projects/components/store/project.selectors'; +import {Component, OnInit} from '@angular/core'; +import {Store, select} from '@ngrx/store'; -import { getActiveTimeEntry } from './../../store/entry.selectors'; -import { Project } from 'src/app/modules/shared/models'; -import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer'; +import {getActiveTimeEntry} from './../../store/entry.selectors'; +import {Project} from 'src/app/modules/shared/models'; +import {ProjectState} from '../../../customer-management/components/projects/components/store/project.reducer'; import * as actions from '../../../customer-management/components/projects/components/store/project.actions'; import * as entryActions from '../../store/entry.actions'; -import { ToastrService } from 'ngx-toastr'; +import {ToastrService} from 'ngx-toastr'; @Component({ selector: 'app-project-list-hover', @@ -15,16 +15,14 @@ import { ToastrService } from 'ngx-toastr'; styleUrls: ['./project-list-hover.component.scss'], }) export class ProjectListHoverComponent implements OnInit { - - selectedId: string; listProjects: Project[] = []; - filterProjects = ''; showButton = ''; keyword = 'name'; nameActiveProject: string; activeEntry; - constructor(private store: Store, private toastr: ToastrService) { } + constructor(private store: Store, private toastr: ToastrService) { + } ngOnInit(): void { this.store.dispatch(new actions.LoadProjects()); @@ -59,7 +57,7 @@ export class ProjectListHoverComponent implements OnInit { const entry = {id: this.activeEntry.id, project_id: id}; this.store.dispatch(new entryActions.UpdateActiveEntry(entry)); } else { - const newEntry = { project_id: id, start_date: new Date().toISOString() }; + const newEntry = {project_id: id, start_date: new Date().toISOString()}; this.store.dispatch(new entryActions.CreateEntry(newEntry)); this.toastr.success('You just clocked-in'); }