diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 87d779e..00a38ec 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,5 +1,6 @@ import { Routes } from '@angular/router'; import { DashboardComponent } from '@app/views/dashboard/dashboard.component'; +import {QualificationsComponent} from '@app/views/qualifications/qualifications.component'; import { AuthService } from '@core/auth/auth.service'; import { EmployeeDetailComponent } from './views/employee-detail/employee-detail.component'; @@ -7,5 +8,6 @@ import { EmployeeDetailComponent } from './views/employee-detail/employee-detail export const routes: Routes = [ { path: '', component: DashboardComponent, title: 'Home' }, { path: 'employee/new', component: EmployeeDetailComponent, title: 'New Employee', canActivate: [AuthService] }, - { path: 'employee/:id', component: EmployeeDetailComponent, title: 'Edit Employee', canActivate: [AuthService] } + { path: 'employee/:id', component: EmployeeDetailComponent, title: 'Edit Employee', canActivate: [AuthService] }, + {path: 'qualifications', component: QualificationsComponent, title: 'Qualifications', canActivate: [AuthService]} ]; diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts index 3e08782..5fc8908 100644 --- a/src/app/header/header.component.ts +++ b/src/app/header/header.component.ts @@ -19,6 +19,7 @@ import {AuthService} from '@core/auth/auth.service'; TitleCasePipe, ], templateUrl: './header.component.html', + standalone: true, styleUrl: './header.component.scss' }) export class HeaderComponent implements OnInit { diff --git a/src/app/views/qualifications/qualifications.component.html b/src/app/views/qualifications/qualifications.component.html new file mode 100644 index 0000000..ef816aa --- /dev/null +++ b/src/app/views/qualifications/qualifications.component.html @@ -0,0 +1,54 @@ +
+
+ + Qualification + + + +
+ + + Id + {{qualification.id}} + + + Skill + +

{{qualification.skill}}

+
+ + Skill + + Skill can't be empty + +
+ + +
+ + + + @if (!isEditing(qualification.id)) { + + + } @else { + + + } + + + + +
+
+ diff --git a/src/app/views/qualifications/qualifications.component.scss b/src/app/views/qualifications/qualifications.component.scss new file mode 100644 index 0000000..915d8e8 --- /dev/null +++ b/src/app/views/qualifications/qualifications.component.scss @@ -0,0 +1,48 @@ +.qualifications{ + &__action-row{ + display: flex; + gap: 1rem; + + mat-form-field:first-of-type{ + flex-grow: 1; + } + } + + &__view{ + tr{ + display: flex; + width: 100%; + height: fit-content; + + .mat-column-id{ + width: 4rem; + } + + .mat-column-skill{ + flex-grow: 1; + + form{ + display: none; + padding-top: 0.25rem; + } + + &.edit{ + p{ + display: none; + } + + form{ + display: block; + } + } + } + + .mat-column-actions{ + display: flex; + gap: 1rem; + padding: 0; + padding-top: 0.25rem; + } + } + } +} \ No newline at end of file diff --git a/src/app/views/qualifications/qualifications.component.ts b/src/app/views/qualifications/qualifications.component.ts new file mode 100644 index 0000000..3860079 --- /dev/null +++ b/src/app/views/qualifications/qualifications.component.ts @@ -0,0 +1,159 @@ +import {Component} from '@angular/core'; +import {FormBuilder, FormGroup, ReactiveFormsModule} from '@angular/forms'; +import {MatButtonModule} from '@angular/material/button'; +import {MatDialog} from '@angular/material/dialog'; +import {MatFormFieldModule} from '@angular/material/form-field'; +import {MatIcon} from '@angular/material/icon'; +import {MatInputModule} from '@angular/material/input'; +import {MatSelectModule} from '@angular/material/select'; +import {MatTableDataSource, MatTableModule} from '@angular/material/table'; +import {DeleteModelComponent} from '@app/delete-model/delete-model.component'; +import { + EmployeeQualifications, + EmployeeService, + Qualification, + QualificationEmployees, + QualificationService, + RemoveQualificationFromEmployeeResponse +} from '@core/ems'; +import {NotificationService, NotificationType} from '@core/notification/notification.service'; +import {forkJoin, Observable} from 'rxjs'; + +@Component({ + selector: 'app-qualifications', + imports: [ + MatIcon, + MatButtonModule, + MatInputModule, + MatSelectModule, + MatTableModule, + MatFormFieldModule, + ReactiveFormsModule + ], + templateUrl: './qualifications.component.html', + standalone: true, + styleUrl: './qualifications.component.scss' +}) +export class QualificationsComponent { + qualificationDataSource: MatTableDataSource = new MatTableDataSource([]); + qualificationsDisplayedColumns = ['id', 'skill', 'actions']; + + qualificationSkillFormGroups: Map = new Map(); + qualificationEdits: Map = new Map(); + + constructor( + private qualificationService: QualificationService, + private employeeService: EmployeeService, + protected formBuilder: FormBuilder, + private notifications: NotificationService, + private dialog: MatDialog + ) { + this.qualificationService.getAllQualifications().subscribe((qualifications) => { + this.qualificationDataSource = new MatTableDataSource(qualifications); + }); + } + + getSkillFormGroup(skill: Qualification): FormGroup { + + let formGroup = this.qualificationSkillFormGroups.get(skill.id); + if (formGroup == undefined) { + formGroup = this.formBuilder.group(skill); + this.qualificationSkillFormGroups.set(skill.id, formGroup); + } + return formGroup; + } + + save() { + + } + + + isEditing(id: number): boolean { + const editing = this.qualificationEdits.get(id); + if (editing == undefined) { + return false; + } + return editing; + } + + startEdit(id: number) { + this.qualificationEdits.set(id, true); + } + + endEdit(oldQualification: Qualification, save: boolean) { + + const qualificationFormGroup = this.qualificationSkillFormGroups.get(oldQualification.id); + if (qualificationFormGroup == undefined) { + return; + } + const qualification: Qualification = qualificationFormGroup.value; + + if (!save) { + qualificationFormGroup.setValue(oldQualification); + this.qualificationEdits.set(oldQualification.id, false); + return; + } + + if (qualificationFormGroup.invalid) { + return; + } + + this.qualificationService.updateQualification({ + id: oldQualification.id, + requestBody: { + skill: qualification.skill + } + }).subscribe(() => { + const data = this.qualificationDataSource.data; + const i = data.indexOf(oldQualification); + data[i] = qualification; + this.qualificationDataSource.data = data; + + this.qualificationEdits.set(oldQualification.id, false); + this.notifications.publish(`Saved ${qualification.skill}`, NotificationType.Information); + }); + } + + onDelete(qualification: Qualification) { + const dialogRef = this.dialog.open(DeleteModelComponent, { + data: { + title: `Delete ${qualification.skill}`, + description: `Do you really want to delete ${qualification.skill}?`, + cancel: 'No', + ok: 'Yes', + } + }); + + dialogRef.afterClosed().subscribe((accepted: boolean) => { + if (!accepted) { + return; + } + this.qualificationService.getAllQualificationEmployees({id: qualification.id}).subscribe((employees: QualificationEmployees) => { + const requests: Array> = []; + for (const employee of employees.employees) { + requests.push(this.employeeService.removeQualificationFromEmployee({ + employeeId: employee.id, + qualificationId: qualification.id + })); + } + forkJoin(requests).subscribe((employeesQualifications: Array)=>{ + for (const employee of employeesQualifications){ + if (employee.skillSet?.map((q)=>q.id).includes(qualification.id)){ + this.notifications.publish(`Could not remove ${qualification.skill} from ${employee.firstName} ${employee.lastName}`, NotificationType.Error); + return; + } + } + this.qualificationService.deleteQualification({id: qualification.id}).subscribe(() => { + const data = this.qualificationDataSource.data; + const i = data.indexOf(qualification); + if (i != -1) { + data.splice(i, 1); + this.qualificationDataSource.data = data; + } + this.notifications.publish(`Deleted ${qualification.skill}`, NotificationType.Information); + }); + }); + }); + }); + } +}