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
6 changes: 3 additions & 3 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ import { ActivitiesManagementComponent } from './modules/activities-management/p
import { ActivityListComponent } from './modules/activities-management/components/activity-list/activity-list.component';
import { CreateActivityComponent } from './modules/activities-management/components/create-activity/create-activity.component';
import { FilterProjectPipe } from './modules/shared/pipes/filter-project/filter-project.pipe';
import { SearchProjectComponent } from './modules/shared/components/search-project/search-project.component';
import { SearchComponent } from './modules/shared/components/search/search.component';
import { HomeComponent } from './modules/home/home.component';
import { LoginComponent } from './modules/login/login.component';
import { ActivityEffects } from './modules/activities-management/store/activity-management.effects';
import { ProjectEffects } from './modules/project-management/store/project.effects';
import { ProjectEffects } from './modules/customer-management/components/projects/components/store/project.effects';
import { TechnologyEffects } from './modules/shared/store/technology.effects';
import { ProjectTypeEffects } from './modules/customer-management/components/projects-type/store/project-type.effects';
import { reducers, metaReducers } from './reducers';
Expand Down Expand Up @@ -77,7 +77,7 @@ import { InjectTokenInterceptor } from './modules/shared/interceptors/inject.tok
HomeComponent,
LoginComponent,
FilterProjectPipe,
SearchProjectComponent,
SearchComponent,
CustomerComponent,
CustomerListComponent,
ManagementCustomerProjectsComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ describe('Activity Service', () => {
service.deleteActivity(activities[0].id).subscribe((activitiesInResponse) => {
expect(activitiesInResponse.filter((activity) => activity.id !== activities[0].id)).toEqual([activities[1]]);
});
const getActivitiesRequest = httpMock.expectOne(url);
expect(getActivitiesRequest.request.method).toBe('DELETE');
getActivitiesRequest.flush(activities);
const deleteActivitiesRequest = httpMock.expectOne(url);
expect(deleteActivitiesRequest.request.method).toBe('DELETE');
deleteActivitiesRequest.flush(activities);
});

it('update activity using PUT from baseUrl', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@
></app-create-customer>
</div>
<div class="tab-pane fade mt-3" id="projects" role="tabpanel" aria-labelledby="projects-tab">
<app-create-project></app-create-project>
<div class="container mb-1">
<app-create-project></app-create-project>
<app-project-list></app-project-list>
</div>
</div>
<div class="tab-pane fade mt-3" id="projectsType" role="tabpanel" aria-labelledby="projects-type-tab">
<div class="container">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ export const projectTypeIdToEdit = createSelector(getProjectTypeState, (state: P
return state.projectTypeIdToEdit;
});

export const getProjectTypeById = createSelector(allProjectTypes, projectTypeIdToEdit, (projectType, projectTypeId) => {
if (projectType && projectTypeId) {
return projectType.find((activity) => {
return activity.id === projectTypeId;
});
export const getProjectTypeById = createSelector(
allProjectTypes,
projectTypeIdToEdit,
(projectTypes, projectTypeId) => {
if (projectTypes && projectTypeId) {
return projectTypes.find((projectType) => {
return projectType.id === projectTypeId;
});
}
}
});
);
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
<div class="container mb-1">
<form style="width: 600px;">
<div class="form-group">
<input type="text" class="form-control form-control-sm" id="" aria-describedby="" placeholder="Project name" />
<textarea
class="form-control form-control-sm mt-2"
id="exampleFormControlTextarea1"
rows="3"
placeholder="Description"
></textarea>
<select class="form-group custom-select custom-select-sm mt-2">
<option selected>Select project type</option>
<option value="1">a..</option>
<option value="2">b..</option>
</select>
<button type="submit" class="btn btn-sm btn-primary">Save</button>
<button type="submit" class="btn btn-sm btn-secondary mb-2 ml-2 mt-2">Cancel</button>
</div>
</form>
<hr />
<div class="row text-right">
<hr />
<div class="col-5 text-right">
<app-search-project></app-search-project>
<form style="width: 600px;" [formGroup]="projectForm" (ngSubmit)="onSubmit(projectForm.value)">
<div class="form-group">
<input
type="text"
class="form-control form-control-sm"
placeholder="Project name"
formControlName="name"
[class.is-invalid]="name.invalid && name.touched"
/>
<div class="text-danger" *ngIf="(name.dirty || name.touched) && name.invalid && name.errors.required">
Project name is required.
</div>
</div>
<app-project-list></app-project-list>
</div>
<textarea
class="form-control form-control-sm mt-2"
rows="3"
formControlName="description"
placeholder="Description"
></textarea>
<div class="form-group">
<select class="custom-select custom-select-sm mt-2" formControlName="project_type_id">
<option [value]="" disabled selected>Select project type</option>
<option *ngFor="let type of projectsTypes" [value]="type.id">{{ type.name }}</option>
</select>
</div>
<button type="submit" [disabled]="!projectForm.valid" class="btn btn-sm btn-primary">Save</button>
<button
type="reset"
[hidden]="!projectToEdit"
(click)="cancelButton()"
class="btn btn-sm btn-secondary mb-2 ml-2 mt-2"
>
Cancel
</button>
</form>
<hr />
Original file line number Diff line number Diff line change
@@ -1,24 +1,151 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { FormBuilder } from '@angular/forms';
import { Subscription } from 'rxjs';
import { CreateProjectComponent } from './create-project.component';
import { ProjectState } from '../store/project.reducer';
import { Project } from 'src/app/modules/shared/models';
import { getProjectToEdit } from '../store/project.selectors';
import { UpdateProject, CreateProject, ResetProjectToEdit } from '../store/project.actions';

describe('InputProjectComponent', () => {
let component: CreateProjectComponent;
let fixture: ComponentFixture<CreateProjectComponent>;
let store: MockStore<ProjectState>;
let getProjectToEditMock;

const state = {
projectList: [{ id: '', name: '', project_type_id: '' }],
isLoading: false,
message: '',
projectToEdit: undefined,
};

const project: Project = {
id: '1',
name: 'Test',
description: 'xxx',
project_type_id: '123',
};

const projectForm = {
name: 'Test',
description: 'xxx',
project_type_id: '123',
};

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [CreateProjectComponent],
providers: [FormBuilder, provideMockStore({ initialState: state })],
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(CreateProjectComponent);
component = fixture.componentInstance;
fixture.detectChanges();

store = TestBed.inject(MockStore);
store.setState(state);

component.projectToEditSubscription = new Subscription();
component.projectTypesSubscription = new Subscription();
});

afterEach(() => {
fixture.destroy();
});

it('component should be created', () => {
expect(component).toBeTruthy();
});

it('should destroy the subscriptions', () => {
component.projectToEditSubscription = new Subscription();
component.projectTypesSubscription = new Subscription();
const subscription = spyOn(component.projectToEditSubscription, 'unsubscribe');
const projectTypeSubscription = spyOn(component.projectTypesSubscription, 'unsubscribe');

component.ngOnDestroy();

expect(subscription).toHaveBeenCalledTimes(1);
expect(projectTypeSubscription).toHaveBeenCalledTimes(1);
});

it('should reset form #onSubmit and dispatch UpdateProject action', () => {
const currentState = {
data: [project],
isLoading: false,
message: '',
projectToEdit: project,
};

getProjectToEditMock = store.overrideSelector(getProjectToEdit, currentState.projectToEdit);
component.projectToEdit = getProjectToEditMock;

const projectUpdated = {
id: component.projectToEdit.id,
name: 'Test',
description: 'xxx',
project_type_id: '123',
};

component.projectToEditSubscription = new Subscription();
component.projectTypesSubscription = new Subscription();
spyOn(component.projectForm, 'reset');
spyOn(store, 'dispatch');
const subscription = spyOn(component.projectToEditSubscription, 'unsubscribe');
const projectTypeSubscription = spyOn(component.projectTypesSubscription, 'unsubscribe');

component.onSubmit(projectForm);
component.ngOnDestroy();

expect(subscription).toHaveBeenCalledTimes(1);
expect(projectTypeSubscription).toHaveBeenCalledTimes(1);

expect(component.projectForm.reset).toHaveBeenCalled();
expect(store.dispatch).toHaveBeenCalledTimes(1);
expect(store.dispatch).toHaveBeenCalledWith(new UpdateProject(projectUpdated));
});

it('should reset form onSubmit and dispatch CreateProject action', () => {
component.projectToEdit = undefined;

spyOn(component.projectForm, 'reset');
spyOn(store, 'dispatch');

component.onSubmit(project);

expect(component.projectForm.reset).toHaveBeenCalled();
expect(store.dispatch).toHaveBeenCalledTimes(1);
expect(store.dispatch).toHaveBeenCalledWith(new CreateProject(project));
});

it('should set data in projectForm', () => {
component.projectToEditSubscription = new Subscription();
component.projectTypesSubscription = new Subscription();
component.projectToEdit = project;

const subscription = spyOn(component.projectToEditSubscription, 'unsubscribe');
const projectTypeSubscription = spyOn(component.projectTypesSubscription, 'unsubscribe');
spyOn(component.projectForm, 'setValue');

component.setDataToUpdate(project);
component.ngOnDestroy();

expect(subscription).toHaveBeenCalledTimes(1);
expect(projectTypeSubscription).toHaveBeenCalledTimes(1);
expect(component.projectForm.setValue).toHaveBeenCalledTimes(1);
expect(component.projectForm.setValue).toHaveBeenCalledWith(projectForm);
});

it('should dispatch a ResetActivityToEdit action', () => {
spyOn(store, 'dispatch');

component.cancelButton();

expect(store.dispatch).toHaveBeenCalledTimes(1);
expect(store.dispatch).toHaveBeenCalledWith(new ResetProjectToEdit());
});
});
Original file line number Diff line number Diff line change
@@ -1,10 +1,89 @@
import { Component } from '@angular/core';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { Store, select } from '@ngrx/store';

import { ProjectState } from '../store/project.reducer';
import * as actions from '../store/project.actions';
import { getProjectToEdit } from '../store/project.selectors';
import { Project, ProjectType } from 'src/app/modules/shared/models';
import { allProjectTypes, ProjectTypeState } from '../../../projects-type/store';
import { Subscription } from 'rxjs';

@Component({
selector: 'app-create-project',
templateUrl: './create-project.component.html',
styleUrls: ['./create-project.component.scss'],
})
export class CreateProjectComponent {
constructor() {}
export class CreateProjectComponent implements OnInit, OnDestroy {
projectForm;
projectToEdit: Project;
projectsTypes: ProjectType[] = [];

projectTypesSubscription: Subscription;
projectToEditSubscription: Subscription;
constructor(
private formBuilder: FormBuilder,
private store: Store<ProjectState>,
private projectTypeStore: Store<ProjectTypeState>
) {
this.projectForm = this.formBuilder.group({
name: ['', Validators.required],
description: [''],
project_type_id: [''],
});
}

ngOnInit() {
const projectToEditSubscription = this.store.pipe(select(getProjectToEdit));
projectToEditSubscription.subscribe((project) => {
this.projectToEdit = project;
this.setDataToUpdate(this.projectToEdit);
});

const projectTypesSubscription = this.projectTypeStore.pipe(select(allProjectTypes));
projectTypesSubscription.subscribe((projectsType) => {
this.projectsTypes = projectsType;
});
}

ngOnDestroy() {
this.projectToEditSubscription.unsubscribe();
this.projectTypesSubscription.unsubscribe();
}

onSubmit(formData) {
this.projectForm.reset();
if (this.projectToEdit) {
const projectData = { id: this.projectToEdit.id, ...formData };
this.store.dispatch(new actions.UpdateProject(projectData));
} else {
this.store.dispatch(new actions.CreateProject(formData));
}
}

get name() {
return this.projectForm.get('name');
}

get description() {
return this.projectForm.get('description');
}

get project_type_id() {
return this.projectForm.get('project_type_id');
}

setDataToUpdate(projectData: Project) {
if (projectData) {
this.projectForm.setValue({
name: projectData.name,
description: projectData.description,
project_type_id: projectData.project_type_id,
});
}
}

cancelButton() {
this.store.dispatch(new actions.ResetProjectToEdit());
}
}
Loading