Skip to content

Commit 1da8393

Browse files
authored
Merge pull request #24 from ioet/add-delete-in-project-management
Add delete in project management
2 parents 0fcb6ec + 0099756 commit 1da8393

13 files changed

+254
-31
lines changed

src/app/app.module.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common';
22
import { BrowserModule } from '@angular/platform-browser';
33
import { NgModule } from '@angular/core';
44
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
5+
import { HttpClientModule } from '@angular/common/http';
56

67
import { AppRoutingModule } from './app-routing.module';
78

@@ -16,8 +17,7 @@ import { ProjectListComponent } from './components/shared/project-list/project-l
1617
import { CreateProjectComponent } from './components/shared/create-project/create-project.component';
1718
import { DetailsFieldsComponent } from './components/shared/details-fields/details-fields.component';
1819
import { ProjectListHoverComponent } from './components/shared/project-list-hover/project-list-hover.component';
19-
20-
20+
import { ModalComponent } from './components/shared/modal/modal.component';
2121
@NgModule({
2222
declarations: [
2323
AppComponent,
@@ -32,13 +32,15 @@ import { ProjectListHoverComponent } from './components/shared/project-list-hove
3232
TimeClockComponent,
3333
DetailsFieldsComponent,
3434
ProjectListHoverComponent,
35+
ModalComponent
3536
],
3637
imports: [
3738
CommonModule,
3839
BrowserModule,
3940
AppRoutingModule,
4041
FormsModule,
41-
ReactiveFormsModule
42+
ReactiveFormsModule,
43+
HttpClientModule
4244
],
4345
providers: [],
4446
bootstrap: [AppComponent]

src/app/components/options-sidebar/project-management/project-management.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<app-project-list class="item"
1212
[projects] = "projects"
1313
(editProject) = "editProject($event)"
14+
(deleteProject) = "deleteProject($event)"
1415
>
1516
</app-project-list>
1617
</div>

src/app/components/options-sidebar/project-management/project-management.component.spec.ts

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
1+
import { async, ComponentFixture, TestBed, inject } from '@angular/core/testing';
22

33
import { ProjectManagementComponent } from './project-management.component';
44
import { Project } from '../../../interfaces/project';
5+
import { ProjectService } from '../../../services/project.service';
6+
import { of } from 'rxjs';
57

68
describe('ProjectManagementComponent', () => {
79
let component: ProjectManagementComponent;
810
let fixture: ComponentFixture<ProjectManagementComponent>;
11+
let projectService: ProjectService;
12+
913
const projects: Project[] = [{
1014
id: 1,
1115
name: 'app 1',
@@ -29,9 +33,17 @@ describe('ProjectManagementComponent', () => {
2933
}
3034
];
3135

36+
const projectServiceStub = {
37+
getProjects() {
38+
const projectsMock = projects;
39+
return of(projectsMock);
40+
}
41+
};
42+
3243
beforeEach(async(() => {
3344
TestBed.configureTestingModule({
34-
declarations: [ ProjectManagementComponent ]
45+
declarations: [ ProjectManagementComponent ],
46+
providers: [ { provide: ProjectService, useValue: projectServiceStub }]
3547
})
3648
.compileComponents();
3749
}));
@@ -40,9 +52,18 @@ describe('ProjectManagementComponent', () => {
4052
fixture = TestBed.createComponent(ProjectManagementComponent);
4153
component = fixture.componentInstance;
4254
fixture.detectChanges();
55+
56+
projectService = TestBed.inject(ProjectService);
4357
component.projects = projects;
4458
});
4559

60+
61+
it('Service injected via inject(...) and TestBed.get(...) should be the same instance',
62+
inject([ProjectService], (injectService: ProjectService) => {
63+
expect(injectService).toBe(projectService);
64+
})
65+
);
66+
4667
it('should create', () => {
4768
expect(component).toBeTruthy();
4869
});
@@ -97,4 +118,34 @@ describe('ProjectManagementComponent', () => {
97118
component.cancelForm();
98119
expect(component.project).toBe(null);
99120
});
121+
122+
it('should call getProjects method on init', () => {
123+
const preojectServiceSpy = spyOn(projectService, 'getProjects').and.callThrough();
124+
const componentSpy = spyOn(component, 'getProjects').and.callThrough();
125+
126+
expect(preojectServiceSpy).not.toHaveBeenCalled();
127+
expect(componentSpy).not.toHaveBeenCalled();
128+
129+
component.ngOnInit();
130+
131+
expect(preojectServiceSpy).toHaveBeenCalledTimes(1);
132+
expect(componentSpy).toHaveBeenCalledTimes(1);
133+
});
134+
135+
136+
it('should call getProjects and return a list of projects', async(() => {
137+
138+
spyOn(projectService, 'getProjects').and.returnValue(of(projects));
139+
140+
component.ngOnInit();
141+
142+
expect(component.projects).toEqual(projects);
143+
}));
144+
145+
it('should delete a project #deleteProject', () => {
146+
const projectId = 1;
147+
148+
component.deleteProject(projectId);
149+
expect(component.projects.length).toEqual(2);
150+
});
100151
});

src/app/components/options-sidebar/project-management/project-management.component.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Component, OnInit } from '@angular/core';
22
import { Project } from '../../../interfaces/project';
3-
import { Input } from '@angular/core';
4-
import { Output, EventEmitter } from '@angular/core';
3+
import { ProjectService } from '../../../services/project.service';
4+
55
@Component({
66
selector: 'app-project-management',
77
templateUrl: './project-management.component.html',
@@ -13,14 +13,13 @@ export class ProjectManagementComponent implements OnInit {
1313

1414
project: Project;
1515

16-
projects: Project[] = [
17-
{ id: 1, name: 'GoSpace', details: 'Improve workspaces', status: 'Active', completed: false},
18-
{ id: 2, name: 'MidoPlay', details: 'Lottery', status: 'Inactive', completed: true}
19-
];
16+
projects: Project[] = [];
2017

21-
constructor() { }
18+
constructor(private projectService: ProjectService) {
19+
}
2220

2321
ngOnInit(): void {
22+
this.getProjects();
2423
}
2524

2625
updateProject(projectData): void {
@@ -44,7 +43,17 @@ export class ProjectManagementComponent implements OnInit {
4443
this.project = this.projects.filter((project) => project.id === projectId)[0];
4544
}
4645

46+
deleteProject(projectId): void {
47+
this.projects = this.projects.filter((project) => project.id !== projectId);
48+
}
49+
4750
cancelForm() {
4851
this.project = null;
4952
}
53+
54+
getProjects() {
55+
this.projectService.getProjects().subscribe(data => {
56+
this.projects = data;
57+
});
58+
}
5059
}

src/app/components/shared/modal/modal.component.css

Whitespace-only changes.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<div class="modal-dialog" role="document">
2+
<div class="modal-content" *ngIf="project">
3+
<div class="modal-header">
4+
<h5 class="modal-title" id="exampleModalLabel">Delete Project</h5>
5+
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
6+
<span aria-hidden="true">&times;</span>
7+
</button>
8+
</div>
9+
<div class="modal-body">
10+
Are you sure you want to delete {{project.name}} project?
11+
</div>
12+
<div class="modal-footer">
13+
<button #cancelDeleteModal type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
14+
<button (click)="removedProject(project.id)" type="button" class="btn btn-primary">Delete</button>
15+
</div>
16+
</div>
17+
</div>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { ModalComponent } from './modal.component';
4+
5+
describe('ModalComponent', () => {
6+
let component: ModalComponent;
7+
let fixture: ComponentFixture<ModalComponent>;
8+
9+
beforeEach(async(() => {
10+
TestBed.configureTestingModule({
11+
declarations: [ ModalComponent ]
12+
})
13+
.compileComponents();
14+
}));
15+
16+
beforeEach(() => {
17+
fixture = TestBed.createComponent(ModalComponent);
18+
component = fixture.componentInstance;
19+
fixture.detectChanges();
20+
});
21+
22+
it('should create', () => {
23+
expect(component).toBeTruthy();
24+
});
25+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
2+
import { Output, EventEmitter } from '@angular/core';
3+
import { Input } from '@angular/core';
4+
import { Project } from '../../../interfaces/project'
5+
@Component({
6+
selector: 'app-modal',
7+
templateUrl: './modal.component.html',
8+
styleUrls: ['./modal.component.css']
9+
})
10+
export class ModalComponent implements OnInit {
11+
12+
@Input() project: Project;
13+
@Output() removeProject = new EventEmitter();
14+
15+
@ViewChild('cancelDeleteModal') cancelDeleteModal: ElementRef;
16+
17+
constructor() { }
18+
19+
ngOnInit(): void {
20+
}
21+
22+
removedProject(projectId) {
23+
this.removeProject.emit(projectId);
24+
this.cancelDeleteModal.nativeElement.click();
25+
}
26+
}
Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,47 @@
11
<div class="card-body">
22
<h1 class="card-title">Project List</h1>
33
<div class="scroll">
4-
<div class="accordion" id="accordionExample">
5-
<div class="card" *ngFor="let project of projects; let rowIndex = index">
6-
<div class="card-header">
7-
<h2 class="mb-0">
8-
<a type="button" data-toggle="collapse" [attr.data-target]="'#row'+rowIndex" [attr.aria-controls]="'row'+rowIndex">
9-
{{project.name}}
10-
</a>
11-
<button (click)="editProject.emit(project.id)" class="btn btn-outline-primary float-right">edit</button>
12-
</h2>
13-
</div>
4+
<div class="accordion" id="accordionProject">
5+
<div *ngIf="projects?.length > 0; else notShow">
6+
<div class="card" *ngFor="let project of projects; let rowIndex = index">
7+
<div class="card-header">
8+
<h2 class="mb-0">
9+
<a type="button" data-toggle="collapse" [attr.data-target]="'#row'+rowIndex" [attr.aria-controls]="'row'+rowIndex">
10+
{{project.name}}
11+
</a>
12+
<div class="btn-group float-right" role="group" >
13+
<i (click)="editProject.emit(project.id)" class="far fa-edit btn btn-link"></i>
14+
<i (click)="openModal(project)" data-toggle="modal" data-target="#deleteModal" class="far fa-trash-alt btn btn-link"></i>
15+
</div>
16+
</h2>
17+
</div>
1418

15-
<div [id]="'row'+rowIndex" class="collapse" data-parent="#accordionExample">
16-
<div class="card-body">
17-
<h5>Details:</h5>
18-
<p>{{project.details}}</p>
19-
<h5>Status:</h5>
20-
<p>{{project.status}}</p>
21-
<h5>Completed project:</h5>
22-
<p>{{project.completed ? 'Yes' : 'No'}}</p>
19+
<div [id]="'row'+rowIndex" class="collapse" data-parent="#accordionProject">
20+
<div class="card-body">
21+
<h5>Details:</h5>
22+
<p>{{project.details}}</p>
23+
<h5>Status:</h5>
24+
<p>{{project.status}}</p>
25+
<h5>Completed project:</h5>
26+
<p>{{project.completed ? 'Yes' : 'No'}}</p>
27+
</div>
2328
</div>
2429
</div>
2530
</div>
31+
<ng-template #notShow>
32+
<div class="card">
33+
<div class="card-body">
34+
<h4 class="card-text">There is no any project.</h4>
35+
<h5 class="card-text">Please, create one.</h5>
36+
</div>
37+
</div>
38+
</ng-template>
2639
</div>
2740
</div>
2841
</div>
42+
43+
<app-modal *ngIf = "openDeleteModal" class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-hidden="true"
44+
[project] = "projectToDelete"
45+
(removeProject) = "removeProject($event)"
46+
>
47+
</app-modal>
Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Component, OnInit } from '@angular/core';
22
import { Input } from '@angular/core';
33
import { Output, EventEmitter } from '@angular/core';
4+
import { Project } from '../../../interfaces/project';
45

56
@Component({
67
selector: 'app-project-list',
@@ -9,11 +10,25 @@ import { Output, EventEmitter } from '@angular/core';
910
})
1011
export class ProjectListComponent implements OnInit {
1112

12-
@Input() projects: any[];
13+
@Input() projects: Project[] = [];
1314
@Output() editProject = new EventEmitter();
15+
@Output() deleteProject = new EventEmitter();
16+
17+
projectToDelete: Project;
18+
openDeleteModal: Boolean = false;
1419

1520
constructor() { }
1621

1722
ngOnInit(): void {
1823
}
24+
25+
openModal(projectData) {
26+
this.projectToDelete = projectData;
27+
this.openDeleteModal = true;
28+
}
29+
30+
removeProject(projectId) {
31+
this.deleteProject.emit(projectId);
32+
this.projectToDelete = null;
33+
}
1934
}

0 commit comments

Comments
 (0)