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 @@ -30,7 +30,7 @@
<ng-template #itemTemplate let-item>
<div class="d-flex container">
<div class="mr-auto p-2">
<span [innerHTML]="item.customer_name"></span> -
<span [innerHTML]="item.customer.name"></span> -
<strong><span [innerHTML]="item.name"></span></strong>
</div>
</div>
Expand Down Expand Up @@ -149,9 +149,7 @@
<div class="form-group row" *ngIf="!goingToWorkOnThis">
<label class="col-12 col-sm-2">Total Hours:</label>
<div class="col-12 col-sm-4">
<span class="border-tag"
[class.border-tag--disabled]="!(project_id.value && project_name.value)"
>
<span class="border-tag" [class.border-tag--disabled]="!(project_id.value && project_name.value)">
{{ this.getTimeDifference() }}
</span>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ describe('DetailsFieldsComponent', () => {
let formValues;
const actionSub: ActionsSubject = new ActionsSubject();
const toastrServiceStub = {
error: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { },
warning: (message?: string, title?: string, override?: Partial<IndividualConfig>) => { }
error: (message?: string, title?: string, override?: Partial<IndividualConfig>) => {},
warning: (message?: string, title?: string, override?: Partial<IndividualConfig>) => {},
};

const state = {
projects: {
projects: [{ id: 'id', name: 'name', project_type_id: '' }],
projects: [{ id: 'id', name: 'name', project_type_id: '', customer: { name: 'Juan', description: 'sadsa' } }],
customerProjects: [{ id: 'id', name: 'name', description: 'description', project_type_id: '123' }],
isLoading: false,
message: '',
Expand All @@ -53,10 +53,30 @@ describe('DetailsFieldsComponent', () => {
isLoading: false,
},
activities: {
data: [{ id: 'fc5fab41-a21e-4155-9d05-511b956ebd05', tenant_id: 'ioet', deleted: null, name: 'abc', status: 'active' },
{ id: 'fc5fab41-a21e-4155-9d05-511b956ebd07', tenant_id: 'ioet_1', deleted: null, name: 'def', status: 'active' },
{ id: 'fc5fab41-a21e-4155-9d05-511b956ebd08', tenant_id: 'ioet_2', deleted: null, name: 'ghi', status: 'inactive' },
{ id: 'fc5fab41-a21e-4155-9d05-511b956ebd09', tenant_id: 'ioet_3', deleted: null, name: 'jkl', status: 'active' }],
data: [
{ id: 'fc5fab41-a21e-4155-9d05-511b956ebd05', tenant_id: 'ioet', deleted: null, name: 'abc', status: 'active' },
{
id: 'fc5fab41-a21e-4155-9d05-511b956ebd07',
tenant_id: 'ioet_1',
deleted: null,
name: 'def',
status: 'active',
},
{
id: 'fc5fab41-a21e-4155-9d05-511b956ebd08',
tenant_id: 'ioet_2',
deleted: null,
name: 'ghi',
status: 'inactive',
},
{
id: 'fc5fab41-a21e-4155-9d05-511b956ebd09',
tenant_id: 'ioet_3',
deleted: null,
name: 'jkl',
status: 'active',
},
],
isLoading: false,
message: 'Data fetch successfully!',
activityIdToEdit: '',
Expand All @@ -82,22 +102,24 @@ describe('DetailsFieldsComponent', () => {

const mockCurrentDate = '2020-12-01T12:00:00';

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [DetailsFieldsComponent, TechnologiesComponent],
providers: [
provideMockStore({ initialState: state }),
{ provide: ActionsSubject, useValue: actionSub },
{ provide: ToastrService, useValue: toastrServiceStub }
],
imports: [FormsModule, ReactiveFormsModule, AutocompleteLibModule, NgxMaterialTimepickerModule],
}).compileComponents();
store = TestBed.inject(MockStore);
mockTechnologySelector = store.overrideSelector(allTechnologies, state.technologies);
mockProjectsSelector = store.overrideSelector(getCustomerProjects, state.projects);
mockEntriesUpdateErrorSelector = store.overrideSelector(getUpdateError, state.Entries.updateError);
mockEntriesCreateErrorSelector = store.overrideSelector(getCreateError, state.Entries.createError);
}));
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [DetailsFieldsComponent, TechnologiesComponent],
providers: [
provideMockStore({ initialState: state }),
{ provide: ActionsSubject, useValue: actionSub },
{ provide: ToastrService, useValue: toastrServiceStub },
],
imports: [FormsModule, ReactiveFormsModule, AutocompleteLibModule, NgxMaterialTimepickerModule],
}).compileComponents();
store = TestBed.inject(MockStore);
mockTechnologySelector = store.overrideSelector(allTechnologies, state.technologies);
mockProjectsSelector = store.overrideSelector(getCustomerProjects, state.projects);
mockEntriesUpdateErrorSelector = store.overrideSelector(getUpdateError, state.Entries.updateError);
mockEntriesCreateErrorSelector = store.overrideSelector(getCreateError, state.Entries.createError);
})
);

beforeEach(() => {
fixture = TestBed.createComponent(DetailsFieldsComponent);
Expand All @@ -110,7 +132,7 @@ describe('DetailsFieldsComponent', () => {
end_date: null,
description: '',
technologies: [],
id: 'xyz'
id: 'xyz',
};
formValues = {
project_id: 'id',
Expand Down Expand Up @@ -143,7 +165,7 @@ describe('DetailsFieldsComponent', () => {

component.onSelectedProject({ id: 'id', search_field: 'foo' });

expect(component.entryForm.patchValue).toHaveBeenCalledWith({ project_id: 'id', project_name: 'foo', });
expect(component.entryForm.patchValue).toHaveBeenCalledWith({ project_id: 'id', project_name: 'foo' });
});

it('if form is invalid then saveEntry is not emited', () => {
Expand All @@ -154,23 +176,22 @@ describe('DetailsFieldsComponent', () => {
expect(component.saveEntry.emit).toHaveBeenCalledTimes(0);
});

[
{ actionType: EntryActionTypes.CREATE_ENTRY_SUCCESS },
{ actionType: EntryActionTypes.UPDATE_ENTRY_SUCCESS },
].map((param) => {
it(`cleanForm after an action type ${param.actionType} is received`, () => {
const actionSubject = TestBed.inject(ActionsSubject) as ActionsSubject;
const action = {
type: param.actionType,
};
spyOn(component, 'cleanForm');
[{ actionType: EntryActionTypes.CREATE_ENTRY_SUCCESS }, { actionType: EntryActionTypes.UPDATE_ENTRY_SUCCESS }].forEach(
(param) => {
it(`cleanForm after an action type ${param.actionType} is received`, () => {
const actionSubject = TestBed.inject(ActionsSubject) as ActionsSubject;
const action = {
type: param.actionType,
};
spyOn(component, 'cleanForm');

component.ngOnInit();
actionSubject.next(action);
component.ngOnInit();
actionSubject.next(action);

expect(component.cleanForm).toHaveBeenCalled();
});
});
expect(component.cleanForm).toHaveBeenCalled();
});
}
);

it('on cleanFieldsForm the project_id and project_name should be kept', () => {
const entryFormValueExpected = {
Expand All @@ -196,7 +217,7 @@ describe('DetailsFieldsComponent', () => {
component.ngOnChanges();
expect(component.shouldRestartEntry).toBeFalse();
expect(component.entryForm.value).toEqual(initialData);
component.activities$.subscribe(item => {
component.activities$.subscribe((item) => {
expect(item.length).not.toBe(null);
expect(item.length).toBe(3);
});
Expand Down Expand Up @@ -224,15 +245,15 @@ describe('DetailsFieldsComponent', () => {

const activitiesParams = [
{ select_activity_id: 'fc5fab41-a21e-4155-9d05-511b956ebd07', expected_size_activities: 3, title: 'active' },
{ select_activity_id: 'fc5fab41-a21e-4155-9d05-511b956ebd08', expected_size_activities: 4, title: 'inactive' }
{ select_activity_id: 'fc5fab41-a21e-4155-9d05-511b956ebd08', expected_size_activities: 4, title: 'inactive' },
];
activitiesParams.map(param => {
activitiesParams.forEach((param) => {
it(`should emit ngOnChange to set ${param.expected_size_activities} activities for select (${param.title} time entry clicked)`, () => {
component.entryToEdit = { ...entryToEdit, activity_id: param.select_activity_id };
spyOn(component.entryForm, 'patchValue');
component.ngOnChanges();

component.activities$.subscribe(items => {
component.activities$.subscribe((items) => {
expect(items.length).toBe(param.expected_size_activities);
});
});
Expand All @@ -241,7 +262,7 @@ describe('DetailsFieldsComponent', () => {
it('selectActiveActivities should return 3 active activities', () => {
const activeActivities = component.selectActiveActivities();

activeActivities.subscribe(item => {
activeActivities.subscribe((item) => {
expect(item.length).not.toBe(null);
expect(item.length).toBe(3);
});
Expand Down Expand Up @@ -293,7 +314,7 @@ describe('DetailsFieldsComponent', () => {
uri: '',
timezone_offset: new Date().getTimezoneOffset(),
},
shouldRestartEntry: false
shouldRestartEntry: false,
};

expect(component.saveEntry.emit).toHaveBeenCalledWith(data);
Expand Down Expand Up @@ -328,9 +349,10 @@ describe('DetailsFieldsComponent', () => {

component.onGoingToWorkOnThisChange({ currentTarget: { checked: false } });

expect(component.entryForm.patchValue).toHaveBeenCalledWith(
{ end_date: '2020-12-30', end_hour: formatDate(new Date(), 'HH:mm', 'en'), }
);
expect(component.entryForm.patchValue).toHaveBeenCalledWith({
end_date: '2020-12-30',
end_hour: formatDate(new Date(), 'HH:mm', 'en'),
});
});

it('when creating a new entry, then the new entry should be marked as not run', () => {
Expand Down Expand Up @@ -390,7 +412,7 @@ describe('DetailsFieldsComponent', () => {
uri: 'ticketUri',
timezone_offset: new Date().getTimezoneOffset(),
},
shouldRestartEntry: false
shouldRestartEntry: false,
};

expect(component.saveEntry.emit).toHaveBeenCalledWith(data);
Expand Down Expand Up @@ -486,12 +508,12 @@ describe('DetailsFieldsComponent', () => {
spyOn(component.projectSelected, 'emit');
const item = {
id: 'id',
search_field: 'TimeTracker'
search_field: 'TimeTracker',
};
component.onSelectedProject(item);

const data: ProjectSelectedEvent = {
projectId: 'id'
projectId: 'id',
};
expect(component.projectSelected.emit).toHaveBeenCalledWith(data);
});
Expand Down Expand Up @@ -531,8 +553,9 @@ describe('DetailsFieldsComponent', () => {
it('on the input with id #start_date we could get the id and max value', () => {
fixture.detectChanges();
const expectedDate = moment(new Date()).format(DATE_FORMAT_YEAR);
const startDateInput: HTMLInputElement = fixture.debugElement.
nativeElement.querySelector(`input[id="start_date"],input[max="${component.getCurrentDate()}"]`);
const startDateInput: HTMLInputElement = fixture.debugElement.nativeElement.querySelector(
`input[id="start_date"],input[max="${component.getCurrentDate()}"]`
);

expect(startDateInput.id).toEqual('start_date');
expect(startDateInput.max).toEqual(expectedDate);
Expand Down Expand Up @@ -569,7 +592,7 @@ describe('DetailsFieldsComponent', () => {
expectedTimeDiff: '00:00',
},
];
diffParams.map((param) => {
diffParams.forEach((param) => {
it(`if [start_date, start_hour] and [end_date, end_hour] diff is ${param.case}`, () => {
component.entryForm.setValue({ ...formValues, ...param.entryDates });
const timeDiff = component.getTimeDifference();
Expand All @@ -579,8 +602,13 @@ describe('DetailsFieldsComponent', () => {
});

it('should find an activity with given id & status: inactive', () => {

const expectedActivity = { id: 'fc5fab41-a21e-4155-9d05-511b956ebd08', tenant_id: 'ioet_2', deleted: null, name: 'ghi', status: 'inactive' };
const expectedActivity = {
id: 'fc5fab41-a21e-4155-9d05-511b956ebd08',
tenant_id: 'ioet_2',
deleted: null,
name: 'ghi',
status: 'inactive',
};

component.entryToEdit = { ...entryToEdit, activity_id: 'fc5fab41-a21e-4155-9d05-511b956ebd08' };
spyOn(component.entryForm, 'patchValue');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import * as moment from 'moment';
import { ToastrService } from 'ngx-toastr';
import { filter, map, mergeMap } from 'rxjs/operators';
import { getCreateError, getUpdateError } from 'src/app/modules/time-clock/store/entry.selectors';
import { ActivityState, allActiveActivities, allActivities, LoadActivities } from '../../../activities-management/store';
import {
ActivityState,
allActiveActivities,
allActivities,
LoadActivities,
} from '../../../activities-management/store';
import * as projectActions from '../../../customer-management/components/projects/components/store/project.actions';
import { ProjectState } from '../../../customer-management/components/projects/components/store/project.reducer';
import { getProjects } from '../../../customer-management/components/projects/components/store/project.selectors';
Expand Down Expand Up @@ -73,7 +78,7 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
this.listProjects = [];
projects.forEach((project) => {
const projectWithSearchField = { ...project };
projectWithSearchField.search_field = `${project.customer_name} - ${project.name}`;
projectWithSearchField.search_field = `${project.customer.name} - ${project.name}`;
this.listProjects.push(projectWithSearchField);
});
}
Expand Down Expand Up @@ -162,13 +167,16 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {

this.activities$ = this.store.pipe(
select(allActiveActivities),
mergeMap(activeActivities => this.store.pipe(
select(allActivities),
map(activities => this.findInactiveActivity(activities) !== undefined
? [...activeActivities, this.findInactiveActivity(activities)]
: activeActivities
mergeMap((activeActivities) =>
this.store.pipe(
select(allActivities),
map((activities) =>
this.findInactiveActivity(activities) !== undefined
? [...activeActivities, this.findInactiveActivity(activities)]
: activeActivities
)
)
))
)
);
} else {
this.cleanForm();
Expand Down Expand Up @@ -204,8 +212,8 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
}

findInactiveActivity(activities) {
return activities.find(activity => activity.status === 'inactive' &&
activity.id === this.entryToEdit.activity_id
return activities.find(
(activity) => activity.status === 'inactive' && activity.id === this.entryToEdit.activity_id
);
}

Expand Down
5 changes: 2 additions & 3 deletions src/app/modules/shared/models/project.model.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import { Customer } from '../models';
export interface Project {
id?: string;
customer_id?: string;
customer_name?: string;
customer?: Customer;
name: string;
description?: string;
project_type_id?: string;
search_field?: string;
status?: any;
}

export interface ProjectUI {
id?: string;
customer_id?: string;
customer_name?: string;
name?: string;
description?: string;
project_type_id?: string;
Expand Down
Loading