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 @@ -17,6 +17,7 @@ describe('InputProjectComponent', () => {
const state = {
projects: [{ id: '', name: '', project_type_id: '' }],
customerProjects: [{ id: '', name: '', project_type_id: '' }],
recentProjects: [],
isLoading: false,
message: '',
projectToEdit: undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ describe('ProjectListComponent', () => {
const state: ProjectState = {
projects: [project],
customerProjects: [project],
recentProjects: [],
isLoading: false,
message: '',
projectToEdit: undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ describe('ProjectService', () => {
getProjectsRequest.flush(projectsList);
});

it('recent projects are read using GET from url/recent', () => {
const projectsFoundSize = projectsList.length;
service.getRecentProjects().subscribe((projectsInResponse) => {
expect(projectsInResponse.length).toBe(projectsFoundSize);
});
const getProjectsRequest = httpMock.expectOne(`${service.url}/recent`);
expect(getProjectsRequest.request.method).toBe('GET');
getProjectsRequest.flush(projectsList);
});

it('create project using POST from url', () => {
const project: Project[] = [{ id: '1', name: 'ccc', description: 'xxx', project_type_id: '123' }];
service.url = 'projects';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export class ProjectService {
return this.http.get<Project[]>(this.url);
}

getRecentProjects(): Observable<Project[]> {
return this.http.get<Project[]>(`${this.url}/recent`);
}

createProject(projectData): Observable<any> {
return this.http.post<Project[]>(this.url, projectData);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ describe('Actions for Projects', () => {
expect(LoadCustomerProjectsFail.type).toEqual(actions.ProjectActionTypes.LOAD_CUSTOMER_PROJECTS_FAIL);
});

it('LoadRecentProjectsSuccess type is ProjectActionTypes.LOAD_RECENT_PROJECTS_SUCCESS', () => {
const action = new actions.LoadRecentProjectsSuccess([]);
expect(action.type).toEqual(actions.ProjectActionTypes.LOAD_RECENT_PROJECTS_SUCCESS);
});

it('LoadRecentProjectsFail type is ProjectActionTypes.LOAD_RECENT_PROJECTS_FAIL', () => {
const action = new actions.LoadRecentProjectsFail('error');
expect(action.type).toEqual(actions.ProjectActionTypes.LOAD_RECENT_PROJECTS_FAIL);
});

it('CreateProjectSuccess type is ProjectActionTypes.CREATE_PROJECT_SUCCESS', () => {
const createProjectSuccess = new actions.CreateProjectSuccess({
id: '1',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export enum ProjectActionTypes {
LOAD_CUSTOMER_PROJECTS = '[Projects] LOAD_CUSTOMER_PROJECTS',
LOAD_CUSTOMER_PROJECTS_SUCCESS = '[Projects] LOAD_CUSTOMER_PROJECTS_SUCCESS',
LOAD_CUSTOMER_PROJECTS_FAIL = '[Projects] LOAD_CUSTOMER_PROJECTS_FAIL',
LOAD_RECENT_PROJECTS_SUCCESS = '[Projects] LOAD_RECENT_PROJECTS_SUCCESS',
LOAD_RECENT_PROJECTS_FAIL = '[Projects] LOAD_RECENT_PROJECTS_FAIL',
CREATE_PROJECT = '[Projects] CREATE_PROJECT',
CREATE_PROJECT_SUCCESS = '[Projects] CREATE_PROJECT_SUCCESS',
CREATE_PROJECT_FAIL = '[Projects] CREATE_PROJECT_FAIL',
Expand Down Expand Up @@ -60,6 +62,16 @@ export class LoadCustomerProjectsFail implements Action {
constructor(public error: string) {}
}

export class LoadRecentProjectsSuccess implements Action {
readonly type = ProjectActionTypes.LOAD_RECENT_PROJECTS_SUCCESS;
constructor(readonly payload: Project[]) {}
}

export class LoadRecentProjectsFail implements Action {
public readonly type = ProjectActionTypes.LOAD_RECENT_PROJECTS_FAIL;
constructor(public error: string) {}
}

export class CreateProject implements Action {
public readonly type = ProjectActionTypes.CREATE_PROJECT;

Expand Down Expand Up @@ -150,6 +162,8 @@ export type ProjectActions =
| LoadCustomerProjects
| LoadCustomerProjectsSuccess
| LoadCustomerProjectsFail
| LoadRecentProjectsSuccess
| LoadRecentProjectsFail
| CreateProject
| CreateProjectSuccess
| CreateProjectFail
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,28 @@ describe('ProjectEffects', () => {
});
});

it('action type is LOAD_RECENT_PROJECTS_SUCCESS when service is executed sucessfully', async () => {
actions$ = of({ type: ProjectActionTypes.LOAD_PROJECTS });
const serviceSpy = spyOn(service, 'getRecentProjects');
serviceSpy.and.returnValue(of(projects));

effects.loadRecentProjects$.subscribe((action) => {
expect(action.type).toEqual(ProjectActionTypes.LOAD_RECENT_PROJECTS_SUCCESS);
});
});

it('action type is LOAD_RECENT_PROJECTS_FAIL when service fail in execution', async () => {
actions$ = of({ type: ProjectActionTypes.LOAD_PROJECTS });
const serviceSpy = spyOn(service, 'getRecentProjects');
serviceSpy.and.returnValue(throwError({ error: { message: 'fail!' } }));
spyOn(toastrService, 'error');

effects.loadRecentProjects$.subscribe((action) => {
expect(toastrService.error).toHaveBeenCalled();
expect(action.type).toEqual(ProjectActionTypes.LOAD_RECENT_PROJECTS_FAIL);
});
});

it('action type is UPDATE_PROJECT_SUCCESS when service is executed sucessfully', async () => {
actions$ = of({ type: ProjectActionTypes.UPDATE_PROJECT, project });
spyOn(toastrService, 'success');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@ export class ProjectEffects {
)
);

@Effect()
loadRecentProjects$: Observable<Action> = this.actions$.pipe(
ofType(actions.ProjectActionTypes.LOAD_PROJECTS),
mergeMap(() =>
this.projectService.getRecentProjects().pipe(
map((projects) => {
return new actions.LoadRecentProjectsSuccess(projects);
}),
catchError((error) => {
this.toastrService.error(error.error.message);
return of(new actions.LoadRecentProjectsFail(error));
})
)
)
);

@Effect()
createProject$: Observable<Action> = this.actions$.pipe(
ofType(actions.ProjectActionTypes.CREATE_PROJECT),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import { projectReducer, ProjectState } from './project.reducer';
describe('projectReducer', () => {
const initialState: ProjectState = {
projects: [{ id: 'id', name: 'name', project_type_id: '', status: 'inactive' }],
customerProjects: [], isLoading: false, message: '', projectToEdit: undefined
customerProjects: [],
recentProjects: [],
isLoading: false, message: '', projectToEdit: undefined
};
const archivedProject: Project = { id: '1', name: 'aaa', description: 'bbb', project_type_id: '123', status: 'inactive' };
const project: Project = { id: '1', name: 'aaa', description: 'bbb', project_type_id: '123', status: 'active' };
Expand Down Expand Up @@ -38,6 +40,23 @@ describe('projectReducer', () => {
expect(state.customerProjects).toEqual([]);
});

it('on LoadRecentProjectsSuccess, projectsFound are saved in the store', () => {
const projectsFound: Project[] = [{ id: '1', name: 'abc', description: 'xxx', status: 'active' }];
const newState = initialState;
newState.recentProjects = projectsFound;
const action = new actions.LoadRecentProjectsSuccess(projectsFound);
const state = projectReducer(initialState, action);
expect(state).toEqual(newState);
});

it('on LoadRecentProjectsFail, recentProjects equal []', () => {
const newState = initialState;
newState.recentProjects = [];
const action = new actions.LoadRecentProjectsFail('error');
const state = projectReducer(initialState, action);
expect(state).toEqual(newState);
});

it('on CreateProject, isLoading is true', () => {
const action = new actions.CreateProject(project);
const state = projectReducer(initialState, action);
Expand Down Expand Up @@ -74,6 +93,7 @@ describe('projectReducer', () => {
const currentState: ProjectState = {
projects: [project],
customerProjects: [project],
recentProjects: [project],
isLoading: false,
message: '',
projectToEdit: project,
Expand Down Expand Up @@ -124,6 +144,7 @@ describe('projectReducer', () => {
const currentState: ProjectState = {
projects: [project],
customerProjects: [project],
recentProjects: [project],
isLoading: false,
message: '',
projectToEdit: undefined,
Expand Down Expand Up @@ -158,6 +179,7 @@ describe('projectReducer', () => {
const currentState: ProjectState = {
projects: [project],
customerProjects: [archivedProject],
recentProjects: [project],
isLoading: false,
message: '',
projectToEdit: project,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Project } from '../../../../../shared/models';
export interface ProjectState {
projects: Project[];
customerProjects: Project[];
recentProjects: Project[];
isLoading: boolean;
message: string;
projectToEdit: Project;
Expand All @@ -12,6 +13,7 @@ export interface ProjectState {
export const initialState = {
projects: [],
customerProjects: [],
recentProjects: [],
isLoading: false,
message: '',
projectToEdit: undefined,
Expand Down Expand Up @@ -65,6 +67,21 @@ export const projectReducer = (state: ProjectState = initialState, action: Proje
};
}

case ProjectActionTypes.LOAD_RECENT_PROJECTS_SUCCESS:
return {
...state,
recentProjects: action.payload,
isLoading: false
};

case ProjectActionTypes.LOAD_RECENT_PROJECTS_FAIL: {
return {
...state,
recentProjects: [],
isLoading: false,
};
}

case ProjectActionTypes.CREATE_PROJECT: {
return {
...state,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ describe('ProjectSelectors', () => {
const projectState = {
projects: [],
customerProjects: [],
recentProjects: [],
isLoading: true,
message: '',
projectToEdit: { id: 'id', name: 'abc', description: 'xxx' },
Expand All @@ -25,6 +26,16 @@ describe('ProjectSelectors', () => {
expect(selectors.getProjects.projector(projectState)).toEqual(filteredProjects);
});

it('should select getRecentProjects', () => {
const projects = [
{ id: '1', name: 'abc', description: 'xxx', status: 'active' },
{ id: '2', name: 'abc', description: 'xxx', status: 'active' },
];
const projectState = { recentProjects: projects };

expect(selectors.getRecentProjects.projector(projectState)).toBe(projects);
});

it('should select getProjectsToEdit', () => {
const project = { id: 'id', name: 'abc', description: 'xxx' };
const projectState = { projectToEdit: project };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export const getProjects = createSelector(getProjectState, (state: ProjectState)
state?.projects.filter((item) => item.status !== 'inactive')
);

export const getRecentProjects = createSelector(getProjectState, (state: ProjectState) => state?.recentProjects);

export const getProjectToEdit = createSelector(getProjectState, (state: ProjectState) => state?.projectToEdit);

export const getIsLoading = createSelector(getProjectState, (state: ProjectState) => state?.isLoading);
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,26 @@
<div class="form-group row">
<label class="col-12 col-sm-2 col-form-label">Project:</label>
<div class="col-12 col-sm-10 autocomplete">
<ng-autocomplete
(selected)="onSelectedProject($event)"
(inputCleared)="onClearedComponent($event)"
formControlName="project_name"
[data]="listProjects"
[searchKeyword]="keyword"
[historyIdentifier]="projectKeyForLocalStorage"
notFoundText="No projects found"
placeHolder="Enter the project name"
[itemTemplate]="itemTemplate"
[notFoundTemplate]="notFoundTemplate"
[class.valid]="project_name.invalid"
>
</ng-autocomplete>

<ng-template #itemTemplate let-item>
<div class="d-flex container">
<div class="mr-auto p-2">
<span [innerHTML]="item.customer.name"></span> -
<strong><span [innerHTML]="item.name"></span></strong>
<ng-select
bindLabel="search_field"
bindValue="project_name"
placeholder="Enter the project name"
notFoundText="No projects found"
[items]="listProjectsShowed"
(search)="onClearedComponent($event)"
(change)="onSelectedProject($event)"
ngDefaultControl="project_name">

<ng-template ng-option-tmp let-item="item">
<div class="flex flex-wrap flex-row justify-between">
<div class="p-2 text-xs">
<span>{{item.customer.name}}</span> -
<strong><span>{{item.name}}</span></strong>
</div>
</div>
</div>
</ng-template>
</ng-template>
</ng-select>

<ng-template #notFoundTemplate let-notFound>
<div [innerHTML]="notFound"></div>
</ng-template>
<!-- <app-loading-bar *ngIf="(isLoading$ | async)"></app-loading-bar> -->
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { NgxMaterialTimepickerModule } from 'ngx-material-timepicker';

import { DATE_FORMAT } from 'src/environments/environment';
import { DATE_FORMAT_YEAR } from 'src/environments/environment';
import { Project } from '../../models';

describe('DetailsFieldsComponent', () => {
type Merged = TechnologyState & ProjectState & EntryState;
Expand All @@ -44,6 +45,7 @@ describe('DetailsFieldsComponent', () => {
projects: {
projects: [{ id: 'id', name: 'name', project_type_id: '', customer: { name: 'Juan', description: 'sadsa' } }],
customerProjects: [{ id: 'id', name: 'name', description: 'description', project_type_id: '123' }],
recentProjects: [{ id: 'id', name: 'name', customer: { name: 'Juan'} }],
isLoading: false,
message: '',
projectToEdit: undefined,
Expand Down Expand Up @@ -154,12 +156,22 @@ describe('DetailsFieldsComponent', () => {
});

it('onClearedComponent project id and name are set to empty', () => {
component.onClearedComponent(null);
const search = {term: ''};
component.onClearedComponent(search);

expect(component.project_id.value).toBe('');
expect(component.project_name.value).toBe('');
});

it('should change the listProjectsShowed to listProjects if search is not empty on onClearedComponent', () => {
const search = {term: 'Ioet Inc.'};
const listProjects: Project[] = [{ id: '1', name: 'abc', status: 'active' }];
component.listProjects = listProjects;
component.onClearedComponent(search);

expect(component.listProjectsShowed).toBe(component.listProjects);
});

it('onSelectedProject project id and name are set using event data', () => {
spyOn(component.entryForm, 'patchValue');

Expand Down
Loading