diff --git a/src/app/modules/time-entries/pages/time-entries.component.spec.ts b/src/app/modules/time-entries/pages/time-entries.component.spec.ts
index d2fd0028e..00d6ded42 100644
--- a/src/app/modules/time-entries/pages/time-entries.component.spec.ts
+++ b/src/app/modules/time-entries/pages/time-entries.component.spec.ts
@@ -16,6 +16,7 @@ import { allEntries } from '../../time-clock/store/entry.selectors';
import * as entryActions from '../../time-clock/store/entry.actions';
import { TechnologiesComponent } from '../../shared/components/technologies/technologies.component';
import { TimeEntriesSummaryComponent } from '../../time-clock/components/time-entries-summary/time-entries-summary.component';
+import { SubstractDatePipe } from '../../shared/pipes/substract-date/substract-date.pipe';
describe('TimeEntriesComponent', () => {
type Merged = TechnologyState & ProjectState & EntryState;
@@ -26,48 +27,14 @@ describe('TimeEntriesComponent', () => {
let mockProjectsSelector;
let mockEntriesSelector;
let injectedToastrService;
+ let state;
+ let entry;
const toastrService = {
error: () => {
},
};
- const state = {
- projects: {
- projects: [{id: 'abc', customer_id: 'customerId', name: '', description: '', project_type_id: 'id'}],
- customerProjects: [{id: 'id', name: 'name', description: 'description', project_type_id: '123'}],
- isLoading: false,
- message: '',
- projectToEdit: undefined,
- },
- activities: {
- data: [{id: 'id', name: 'name', description: 'description'}],
- isLoading: false,
- message: 'message',
- },
- technologies: {
- technologyList: {items: [{name: 'test'}]},
- isLoading: false,
- },
- entries: {
- entryList: [],
- active: {
- start_date: new Date('2019-01-01T15:36:15.887Z'),
- id: 'active-entry',
- }
- },
- };
-
- const entry = {
- id: 'entry_1',
- project_id: 'abc',
- start_date: new Date('2020-02-05T15:36:15.887Z'),
- end_date: new Date('2020-02-05T18:36:15.887Z'),
- activity_id: 'development',
- technologies: ['Angular', 'TypeScript'],
- comments: 'No comments',
- uri: 'EY-25',
- };
beforeEach(async(() => {
TestBed.configureTestingModule({
@@ -79,6 +46,7 @@ describe('TimeEntriesComponent', () => {
TimeEntriesComponent,
TechnologiesComponent,
TimeEntriesSummaryComponent,
+ SubstractDatePipe
],
providers: [provideMockStore({initialState: state}),
{provide: ToastrService, useValue: toastrService},
@@ -86,6 +54,41 @@ describe('TimeEntriesComponent', () => {
imports: [FormsModule, ReactiveFormsModule],
}).compileComponents();
store = TestBed.inject(MockStore);
+ entry = {
+ id: 'entry_1',
+ project_id: 'abc',
+ start_date: new Date('2020-02-05T15:36:15.887Z'),
+ end_date: new Date('2020-02-05T18:36:15.887Z'),
+ activity_id: 'development',
+ technologies: ['Angular', 'TypeScript'],
+ comments: 'No comments',
+ uri: 'EY-25',
+ };
+ state = {
+ projects: {
+ projects: [{ id: 'abc', customer_id: 'customerId', name: '', description: '', project_type_id: 'id' }],
+ customerProjects: [{ id: 'id', name: 'name', description: 'description', project_type_id: '123' }],
+ isLoading: false,
+ message: '',
+ projectToEdit: undefined,
+ },
+ activities: {
+ data: [{ id: 'id', name: 'name', description: 'description' }],
+ isLoading: false,
+ message: 'message',
+ },
+ technologies: {
+ technologyList: { items: [{ name: 'test' }] },
+ isLoading: false,
+ },
+ entries: {
+ entryList: [],
+ active: {
+ start_date: new Date('2019-01-01T15:36:15.887Z'),
+ id: 'active-entry',
+ }
+ },
+ };
mockTechnologySelector = store.overrideSelector(allTechnologies, state.technologies);
mockProjectsSelector = store.overrideSelector(getProjects, state.projects.projects);
mockEntriesSelector = store.overrideSelector(allEntries, state.entries.entryList);
@@ -193,6 +196,28 @@ describe('TimeEntriesComponent', () => {
expect(component.entryId).toBe(null);
});
+ it('given an empty list of entries when creating a new entry it can be marked as WIP ', () => {
+ state.entries.entryList = [];
+ component.newEntry();
+ expect(component.canMarkEntryAsWIP).toBe(true);
+ });
+
+ it('given an list of entries having an entry running when creating a new entry it cannot be marked as WIP ', () => {
+ state.entries.entryList = [{...entry, running: true}];
+ mockEntriesSelector = store.overrideSelector(allEntries, state.entries.entryList);
+
+ component.newEntry();
+ expect(component.canMarkEntryAsWIP).toBe(false);
+ });
+
+ it('given an list of entries not having an entry running when creating a new entry it can be marked as WIP ', () => {
+ state.entries.entryList = [{...entry, running: false}];
+ mockEntriesSelector = store.overrideSelector(allEntries, state.entries.entryList);
+
+ component.newEntry();
+ expect(component.canMarkEntryAsWIP).toBe(true);
+ });
+
it('should set entry and entryid to with data', () => {
component.dataByMonth = [entry];
component.editEntry('entry_1');
@@ -200,6 +225,36 @@ describe('TimeEntriesComponent', () => {
expect(component.entryId).toBe('entry_1');
});
+ it('given an list of entries having an entry running when editing a different entry it cannot be marked as WIP ', () => {
+ const anEntryId = '1';
+ const anotherEntryId = '2';
+ state.entries.entryList = [{...entry, running: true, id: anEntryId}];
+ mockEntriesSelector = store.overrideSelector(allEntries, state.entries.entryList);
+
+ component.editEntry(anotherEntryId);
+ expect(component.canMarkEntryAsWIP).toBe(false);
+ });
+
+ it('given an list of entries having no entries running when editing a different entry it cannot be marked as WIP', () => {
+ const anEntryId = '1';
+ const anotherEntryId = '2';
+ state.entries.entryList = [{...entry, running: false, id: anEntryId}];
+ mockEntriesSelector = store.overrideSelector(allEntries, state.entries.entryList);
+
+ component.editEntry(anotherEntryId);
+ expect(component.canMarkEntryAsWIP).toBe(false);
+ });
+
+ it('given an list of entries having an entry running when editing the last entry it can be marked as WIP ', () => {
+ const anEntryId = '1';
+ const anotherEntryId = '2';
+ state.entries.entryList = [{...entry, running: true, id: anEntryId}, {...entry, running: false, id: anotherEntryId}];
+ mockEntriesSelector = store.overrideSelector(allEntries, state.entries.entryList);
+
+ component.editEntry(anEntryId);
+ expect(component.canMarkEntryAsWIP).toBe(true);
+ });
+
it('displays an error when start date of entry is > than active entry start date', () => {
const newEntry = {
entry: {
@@ -221,7 +276,7 @@ describe('TimeEntriesComponent', () => {
});
it('should dispatch an action when entry is going to be saved', () => {
- component.entry = { start_date: new Date(), id: '1234', technologies: []};
+ component.entry = {start_date: new Date(), id: '1234', technologies: []};
const newEntry = {
entry: {
project_id: 'p-id',
@@ -310,7 +365,7 @@ describe('TimeEntriesComponent', () => {
}));
it('when event contains should restart as true, then a restart Entry action should be triggered', () => {
- component.entry = { start_date: new Date(), id: '1234', technologies: []};
+ component.entry = {start_date: new Date(), id: '1234', technologies: []};
const entryToSave = {
entry: {
id: '123',
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 fa61eefc2..c7335bcc2 100644
--- a/src/app/modules/time-entries/pages/time-entries.component.ts
+++ b/src/app/modules/time-entries/pages/time-entries.component.ts
@@ -9,7 +9,7 @@ import { allEntries } from '../../time-clock/store/entry.selectors';
import { select, Store, ActionsSubject } from '@ngrx/store';
import * as entryActions from '../../time-clock/store/entry.actions';
import { SaveEntryEvent } from '../../shared/components/details-fields/save-entry-event';
-import { Subscription} from 'rxjs';
+import { Subscription } from 'rxjs';
@Component({
selector: 'app-time-entries',
@@ -25,6 +25,7 @@ export class TimeEntriesComponent implements OnInit, OnDestroy {
message: string;
idToDelete: string;
entriesSubscription: Subscription;
+ canMarkEntryAsWIP = true;
constructor(private store: Store
, private toastrService: ToastrService, private actionsSubject$: ActionsSubject) {
}
@@ -57,11 +58,46 @@ export class TimeEntriesComponent implements OnInit, OnDestroy {
newEntry() {
this.entry = null;
this.entryId = null;
+ this.store.pipe(select(allEntries)).subscribe(entries => {
+ this.canMarkEntryAsWIP = !this.isThereAnEntryRunning(entries);
+ });
+ }
+
+ private getEntryRunning(entries: Entry[]) {
+ const runningEntry: Entry = entries.find(entry => entry.running === true);
+ return runningEntry;
+ }
+
+ private isThereAnEntryRunning(entries: Entry[]) {
+ return !!this.getEntryRunning(entries);
}
editEntry(entryId: string) {
this.entryId = entryId;
this.entry = this.dataByMonth.find((entry) => entry.id === entryId);
+ this.store.pipe(select(allEntries)).subscribe(entries => {
+ this.canMarkEntryAsWIP = this.isEntryRunningEqualsToEntryToEdit(this.getEntryRunning(entries), this.entry)
+ || this.isEntryToEditTheLastOne(entries);
+
+ });
+ }
+
+ private isEntryRunningEqualsToEntryToEdit(entryRunning: Entry, entryToEdit: Entry) {
+ if (entryRunning && entryToEdit) {
+ return entryRunning.id === entryToEdit.id;
+ } else {
+ return false;
+ }
+ }
+
+
+ private isEntryToEditTheLastOne(entries: Entry[]) {
+ if (entries && entries.length > 0) {
+ const lastEntry = entries[0];
+ return lastEntry.id === this.entryId;
+ } else {
+ return false;
+ }
}
saveEntry(event: SaveEntryEvent): void {
@@ -115,5 +151,4 @@ export class TimeEntriesComponent implements OnInit, OnDestroy {
this.message = `Are you sure you want to delete ${item.activity_name}?`;
this.showModal = true;
}
-
}