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
Expand Up @@ -99,7 +99,7 @@ describe('EntryFieldsComponent', () => {
it('should dispatch UpdateActiveEntry action #onSubmit', () => {
spyOn(store, 'dispatch');
component.onSubmit();
expect(store.dispatch).toHaveBeenCalledWith(new entryActions.UpdateActiveEntry(entry));
expect(store.dispatch).toHaveBeenCalledWith(new entryActions.UpdateEntryRunning(entry));
});

it('when a technology is added, then dispatch UpdateActiveEntry', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,16 @@ export class EntryFieldsComponent implements OnInit {
}

onSubmit() {
this.store.dispatch(new entryActions.UpdateActiveEntry({...this.newData, ...this.entryForm.value}));
this.store.dispatch(new entryActions.UpdateEntryRunning({...this.newData, ...this.entryForm.value}));
}

onTechnologyAdded($event: string[]) {
this.store.dispatch(new entryActions.UpdateActiveEntry({...this.newData, technologies: $event})
this.store.dispatch(new entryActions.UpdateEntryRunning({...this.newData, technologies: $event})
);
}

onTechnologyRemoved($event: string[]) {
this.store.dispatch(new entryActions.UpdateActiveEntry({...this.newData, technologies: $event}));
this.store.dispatch(new entryActions.UpdateEntryRunning({...this.newData, technologies: $event}));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {ProjectListHoverComponent} from './project-list-hover.component';
import {ProjectState} from '../../../customer-management/components/projects/components/store/project.reducer';
import {getCustomerProjects} from '../../../customer-management/components/projects/components/store/project.selectors';
import {FilterProjectPipe} from '../../../shared/pipes';
import {CreateEntry, UpdateActiveEntry} from '../../store/entry.actions';
import {CreateEntry, UpdateEntryRunning} from '../../store/entry.actions';
import {AutocompleteLibModule} from 'angular-ng-autocomplete';

describe('ProjectListHoverComponent', () => {
Expand Down Expand Up @@ -65,13 +65,13 @@ describe('ProjectListHoverComponent', () => {
expect(store.dispatch).toHaveBeenCalledWith(jasmine.any(CreateEntry));
});

it('dispatchs a UpdateEntry action when activeEntry is not null', () => {
it('dispatchs a UpdateEntryRunning action when activeEntry is not null', () => {
const entry = {id: '123', project_id: 'p1', start_date: new Date().toISOString()};
component.activeEntry = entry;
spyOn(store, 'dispatch');

component.clockIn();

expect(store.dispatch).toHaveBeenCalledWith(jasmine.any(UpdateActiveEntry));
expect(store.dispatch).toHaveBeenCalledWith(jasmine.any(UpdateEntryRunning));
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,12 @@ export class ProjectListHoverComponent implements OnInit {
const selectedProject = this.projectsForm.get('project_id').value;
if (this.activeEntry) {
const entry = { id: this.activeEntry.id, project_id: selectedProject };
this.store.dispatch(new entryActions.UpdateActiveEntry(entry));
this.store.dispatch(new entryActions.UpdateEntryRunning(entry));
} else {
const newEntry = { project_id: selectedProject, start_date: new Date().toISOString() };
this.store.dispatch(new entryActions.CreateEntry(newEntry));
}
this.store.dispatch(new entryActions.LoadEntries(new Date().getMonth() + 1 ));
this.loadActiveTimeEntry();
}

}
2 changes: 1 addition & 1 deletion src/app/modules/time-clock/services/entry.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ describe('EntryService', () => {
it('update an entry using PUT', () => {
const updatedEntry = {foo: 'bar', id: 'id'};

service.updateActiveEntry(updatedEntry).subscribe();
service.updateEntry(updatedEntry).subscribe();

const updateEntryRequest = httpMock.expectOne(`${service.baseUrl}/id`);
expect(updateEntryRequest.request.method).toBe('PUT');
Expand Down
2 changes: 1 addition & 1 deletion src/app/modules/time-clock/services/entry.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class EntryService {
return this.http.post(this.baseUrl, entryData);
}

updateActiveEntry(entryData): Observable<any> {
updateEntry(entryData): Observable<any> {
const {id} = entryData;
return this.http.put(`${this.baseUrl}/${id}`, entryData);
}
Expand Down
23 changes: 17 additions & 6 deletions src/app/modules/time-clock/store/entry.actions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,31 @@ describe('Actions for Entries', () => {
expect(deleteEntryFail.type).toEqual(actions.EntryActionTypes.DELETE_ENTRY_FAIL);
});

it('UpdateActiveEntrySuccess type is EntryActionTypes.UDPATE_ACTIVE_ENTRY_SUCCESS', () => {
const updateActiveEntrySuccess = new actions.UpdateActiveEntrySuccess({
it('UpdateEntrySuccess type is EntryActionTypes.UDPATE_ENTRY_SUCCESS', () => {
const updateActiveEntrySuccess = new actions.UpdateEntrySuccess({
id: '1',
start_date: new Date(),
end_date: new Date(),
activity_id: '',
technologies: ['abc', 'abc'],
});
expect(updateActiveEntrySuccess.type).toEqual(actions.EntryActionTypes.UPDATE_ACTIVE_ENTRY_SUCCESS);
expect(updateActiveEntrySuccess.type).toEqual(actions.EntryActionTypes.UPDATE_ENTRY_SUCCESS);
});

it('UpdateActiveEntryFail type is EntryActionTypes.UDPATE_ACTIVE_ENTRY_FAIL', () => {
const updateActiveEntryFail = new actions.UpdateActiveEntryFail('error');
expect(updateActiveEntryFail.type).toEqual(actions.EntryActionTypes.UPDATE_ACTIVE_ENTRY_FAIL);
it('UpdateEntryFail type is EntryActionTypes.UDPATE_ENTRY_FAIL', () => {
const updateActiveEntryFail = new actions.UpdateEntryFail('error');
expect(updateActiveEntryFail.type).toEqual(actions.EntryActionTypes.UPDATE_ENTRY_FAIL);
});

it('UpdateActiveEntry type is EntryActionTypes.UDPATE_ENTRY_FAIL', () => {
const action = new actions.UpdateEntryRunning({
id: '1',
start_date: new Date(),
end_date: new Date(),
activity_id: '',
technologies: ['abc', 'abc'],
});
expect(action.type).toEqual(actions.EntryActionTypes.UPDATE_ENTRY_RUNNING);
});

it('LoadEntriesByTimeRange type is EntryActionTypes.LOAD_ENTRIES_BY_TIME_RANGE', () => {
Expand Down
32 changes: 20 additions & 12 deletions src/app/modules/time-clock/store/entry.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ export enum EntryActionTypes {
CREATE_ENTRY = '[Entry] CREATE_ENTRY',
CREATE_ENTRY_SUCCESS = '[Entry] CREATE_ENTRY_SUCCESS',
CREATE_ENTRY_FAIL = '[Entry] CREATE_ENTRY_FAIL',
UPDATE_ACTIVE_ENTRY = '[Entry] UPDATE_ACTIVE_ENTRY',
UPDATE_ACTIVE_ENTRY_SUCCESS = '[Entry] UPDATE_ACTIVE_ENTRY_SUCCESS',
UPDATE_ACTIVE_ENTRY_FAIL = '[Entry] UPDATE_ACTIVE_ENTRY_FAIL',
UPDATE_ENTRY_RUNNING = '[Entry] UPDATE_ENTRY_RUNNING',
UPDATE_ENTRY = '[Entry] UPDATE_ENTRY',
UPDATE_ENTRY_SUCCESS = '[Entry] UPDATE_ENTRY_SUCCESS',
UPDATE_ENTRY_FAIL = '[Entry] UPDATE_ENTRY_FAIL',
DELETE_ENTRY = '[Entry] DELETE_ENTRY',
DELETE_ENTRY_SUCCESS = '[Entry] DELETE_ENTRY_SUCCESS',
DELETE_ENTRY_FAIL = '[Entry] DELETE_ENTRY_FAIL',
Expand Down Expand Up @@ -112,20 +113,26 @@ export class DeleteEntryFail implements Action {

constructor(public error: string) {}
}
export class UpdateActiveEntry implements Action {
public readonly type = EntryActionTypes.UPDATE_ACTIVE_ENTRY;

export class UpdateEntryRunning implements Action {
public readonly type = EntryActionTypes.UPDATE_ENTRY_RUNNING;
constructor(public payload) {}
}

export class UpdateActiveEntrySuccess implements Action {
public readonly type = EntryActionTypes.UPDATE_ACTIVE_ENTRY_SUCCESS;
export class UpdateEntry implements Action {
public readonly type = EntryActionTypes.UPDATE_ENTRY;

constructor(public payload) {}
}

export class UpdateEntrySuccess implements Action {
public readonly type = EntryActionTypes.UPDATE_ENTRY_SUCCESS;

constructor(public payload: Entry) {}
}

export class UpdateActiveEntryFail implements Action {
public readonly type = EntryActionTypes.UPDATE_ACTIVE_ENTRY_FAIL;
export class UpdateEntryFail implements Action {
public readonly type = EntryActionTypes.UPDATE_ENTRY_FAIL;

constructor(public error: string) {}
}
Expand Down Expand Up @@ -186,9 +193,10 @@ export type EntryActions =
| CreateEntry
| CreateEntrySuccess
| CreateEntryFail
| UpdateActiveEntry
| UpdateActiveEntrySuccess
| UpdateActiveEntryFail
| UpdateEntryRunning
| UpdateEntry
| UpdateEntrySuccess
| UpdateEntryFail
| DeleteEntry
| DeleteEntrySuccess
| DeleteEntryFail
Expand Down
27 changes: 25 additions & 2 deletions src/app/modules/time-clock/store/entry.effects.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { INFO_SAVED_SUCCESSFULLY } from './../../shared/messages';
import {TestBed} from '@angular/core/testing';
import {provideMockActions} from '@ngrx/effects/testing';
import {EntryEffects} from './entry.effects';
import {Observable, of, throwError} from 'rxjs';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {ToastrModule} from 'ngx-toastr';
import { ToastrModule, ToastrService } from 'ngx-toastr';
import {Action} from '@ngrx/store';
import {DatePipe} from '@angular/common';
import {EntryActionTypes} from './entry.actions';
Expand All @@ -15,6 +16,7 @@ describe('TimeEntryActionEffects', () => {
let actions$: Observable<Action>;
let effects: EntryEffects;
let service;
let toastrService;

beforeEach(() => {
TestBed.configureTestingModule({
Expand All @@ -28,6 +30,7 @@ describe('TimeEntryActionEffects', () => {
});
effects = TestBed.inject(EntryEffects);
service = TestBed.inject(EntryService);
toastrService = TestBed.inject(ToastrService);
});

it('should be created', async () => {
Expand Down Expand Up @@ -95,7 +98,27 @@ describe('TimeEntryActionEffects', () => {
serviceSpy.and.returnValue(of(activeEntry));

effects.loadActiveEntry$.subscribe(action => {
expect(action.type).toEqual(EntryActionTypes.UPDATE_ACTIVE_ENTRY);
expect(action.type).toEqual(EntryActionTypes.UPDATE_ENTRY);
});
});

it('display a success message on UPDATE_ENTRY', async () => {
const activeEntry = {};
actions$ = of({type: EntryActionTypes.UPDATE_ENTRY, activeEntry});
spyOn(toastrService, 'success');

effects.updateEntry$.subscribe(action => {
expect(toastrService.success).toHaveBeenCalledWith(INFO_SAVED_SUCCESSFULLY);
});
});

it('does not display any message on UPDATE_ENTRY_RUNNING', async () => {
const activeEntry = {};
actions$ = of({type: EntryActionTypes.UPDATE_ENTRY_RUNNING, activeEntry});
spyOn(toastrService, 'success');

effects.updateEntry$.subscribe(action => {
expect(toastrService.success).toHaveBeenCalledTimes(0);
});
});

Expand Down
31 changes: 24 additions & 7 deletions src/app/modules/time-clock/store/entry.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class EntryEffects {
} else {
const endDate = new Date(activeEntry.start_date);
endDate.setHours(23, 59, 59);
return new actions.UpdateActiveEntry({id: activeEntry.id, end_date: endDate.toISOString()});
return new actions.UpdateEntry({id: activeEntry.id, end_date: endDate.toISOString()});
}
}
}),
Expand Down Expand Up @@ -113,18 +113,35 @@ export class EntryEffects {
);

@Effect()
updateActiveEntry$: Observable<Action> = this.actions$.pipe(
ofType(actions.EntryActionTypes.UPDATE_ACTIVE_ENTRY),
map((action: actions.UpdateActiveEntry) => action.payload),
updateEntry$: Observable<Action> = this.actions$.pipe(
ofType(actions.EntryActionTypes.UPDATE_ENTRY),
map((action: actions.UpdateEntry) => action.payload),
mergeMap((entry) =>
this.entryService.updateActiveEntry(entry).pipe(
this.entryService.updateEntry(entry).pipe(
map((entryResponse) => {
this.toastrService.success(INFO_SAVED_SUCCESSFULLY);
return new actions.UpdateActiveEntrySuccess(entryResponse);
return new actions.UpdateEntrySuccess(entryResponse);
}),
catchError((error) => {
this.toastrService.error(error.error.message);
return of(new actions.UpdateActiveEntryFail(error));
return of(new actions.UpdateEntryFail(error));
})
)
)
);

@Effect()
updateEntryRunning$: Observable<Action> = this.actions$.pipe(
ofType(actions.EntryActionTypes.UPDATE_ENTRY_RUNNING),
map((action: actions.UpdateEntry) => action.payload),
mergeMap((entry) =>
this.entryService.updateEntry(entry).pipe(
map((entryResponse) => {
return new actions.UpdateEntrySuccess(entryResponse);
}),
catchError((error) => {
this.toastrService.error(error.error.message);
return of(new actions.UpdateEntryFail(error));
})
)
)
Expand Down
6 changes: 3 additions & 3 deletions src/app/modules/time-clock/store/entry.reducer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,14 @@ describe('entryReducer', () => {
});

it('on UpdateActiveEntry, isLoading is true', () => {
const action = new actions.UpdateActiveEntry(newEntry);
const action = new actions.UpdateEntry(newEntry);
const state = entryReducer(initialState, action);

expect(state.isLoading).toEqual(true);
});

it('on UpdateActiveEntrySuccess, loading is false', () => {
const action = new actions.UpdateActiveEntrySuccess(entry);
const action = new actions.UpdateEntrySuccess(entry);

const state = entryReducer(initialState, action);

Expand All @@ -187,7 +187,7 @@ describe('entryReducer', () => {
});

it('on UpdateActiveEntryFail, active to be null', () => {
const action = new actions.UpdateActiveEntryFail('error');
const action = new actions.UpdateEntryFail('error');
const state = entryReducer(initialState, action);

expect(state.active).toBe(null);
Expand Down
6 changes: 3 additions & 3 deletions src/app/modules/time-clock/store/entry.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,14 @@ export const entryReducer = (state: EntryState = initialState, action: EntryActi
};
}

case EntryActionTypes.UPDATE_ACTIVE_ENTRY: {
case EntryActionTypes.UPDATE_ENTRY: {
return {
...state,
isLoading: true,
};
}

case EntryActionTypes.UPDATE_ACTIVE_ENTRY_SUCCESS: {
case EntryActionTypes.UPDATE_ENTRY_SUCCESS: {
const entryList = [...state.entryList];
const index = entryList.findIndex((entry) => entry.id === action.payload.id);
entryList[index] = action.payload;
Expand All @@ -161,7 +161,7 @@ export const entryReducer = (state: EntryState = initialState, action: EntryActi
};
}

case EntryActionTypes.UPDATE_ACTIVE_ENTRY_FAIL: {
case EntryActionTypes.UPDATE_ENTRY_FAIL: {
return {
...state,
active: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class TimeEntriesComponent implements OnInit {
doSave(entry) {
if (this.entryId) {
entry.id = this.entryId;
this.store.dispatch(new entryActions.UpdateActiveEntry(entry));
this.store.dispatch(new entryActions.UpdateEntry(entry));
} else {
this.store.dispatch(new entryActions.CreateEntry(entry));
}
Expand Down