Feature: Employee Edit - Function, Layout, Style
This commit is contained in:
parent
f6664e1d8a
commit
d4ec632053
3 changed files with 131 additions and 59 deletions
|
@ -2,47 +2,56 @@
|
||||||
<div class="employee-detail__info-view">
|
<div class="employee-detail__info-view">
|
||||||
<div class="employee-detail__info-view__base">
|
<div class="employee-detail__info-view__base">
|
||||||
<h2>Info</h2>
|
<h2>Info</h2>
|
||||||
<mat-form-field>
|
<div class="employee-detail__info-view__base__content">
|
||||||
<mat-label>First Name</mat-label>
|
<mat-form-field>
|
||||||
<input matInput formControlName="firstName">
|
<mat-label>First Name</mat-label>
|
||||||
</mat-form-field>
|
<input matInput formControlName="firstName" required>
|
||||||
<mat-form-field>
|
<mat-error>First Name can not be Empty</mat-error>
|
||||||
<mat-label>Last Name</mat-label>
|
</mat-form-field>
|
||||||
<input matInput formControlName="lastName">
|
<mat-form-field>
|
||||||
</mat-form-field>
|
<mat-label>Last Name</mat-label>
|
||||||
<mat-form-field>
|
<input matInput formControlName="lastName" required>
|
||||||
<mat-label>Postcode</mat-label>
|
<mat-error>Last Name can not be Empty</mat-error>
|
||||||
<mat-icon matSuffix>money</mat-icon>
|
</mat-form-field>
|
||||||
<input matInput formControlName="postcode">
|
<mat-form-field>
|
||||||
</mat-form-field>
|
<mat-label>Postcode</mat-label>
|
||||||
<mat-form-field>
|
<mat-icon matSuffix>money</mat-icon>
|
||||||
<mat-label>City</mat-label>
|
<input matInput formControlName="postcode" required minlength="5" maxlength="5">
|
||||||
<mat-icon matSuffix>location_city</mat-icon>
|
<mat-error>Postcode has to be exactly 5 long</mat-error>
|
||||||
<input matInput formControlName="city">
|
</mat-form-field>
|
||||||
</mat-form-field>
|
<mat-form-field>
|
||||||
<mat-form-field>
|
<mat-label>City</mat-label>
|
||||||
<mat-label>Street</mat-label>
|
<mat-icon matSuffix>location_city</mat-icon>
|
||||||
<mat-icon matSuffix>house</mat-icon>
|
<input matInput formControlName="city" required>
|
||||||
<input matInput formControlName="street">
|
<mat-error>City can not be Empty</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Phone</mat-label>
|
<mat-label>Street</mat-label>
|
||||||
<mat-icon matSuffix>phone</mat-icon>
|
<mat-icon matSuffix>house</mat-icon>
|
||||||
<input matInput formControlName="phone">
|
<input matInput formControlName="street" required>
|
||||||
</mat-form-field>
|
<mat-error>Street can not be Empty</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label>Phone</mat-label>
|
||||||
|
<mat-icon matSuffix>phone</mat-icon>
|
||||||
|
<input matInput formControlName="phone" required>
|
||||||
|
<mat-error>Phone can not be Empty</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="employee-detail__info-view__skills">
|
<div class="employee-detail__info-view__skills">
|
||||||
<h2>Skills</h2>
|
<h2>Skills</h2>
|
||||||
<div class="employee-detail__info-view__skills__action-row">
|
<div class="employee-detail__info-view__skills__action-row">
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-label>Skill</mat-label>
|
<mat-label>Skill</mat-label>
|
||||||
<mat-select [disabled]="!($unusedSkills | async)?.length">
|
<mat-select #skillSelect [disabled]="!($unusedSkills | async)?.length">
|
||||||
@for (skill of ($unusedSkills|async); track skill) {
|
@for (skill of ($unusedSkills|async); track skill) {
|
||||||
<mat-option [value]="skill.skill">{{skill.skill}}</mat-option>
|
<mat-option [value]="skill">{{skill.skill}}</mat-option>
|
||||||
}
|
}
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-fab class="shadowless">
|
<button mat-fab class="shadowless" (click)="onAddSkill(skillSelect)">
|
||||||
<mat-icon>add</mat-icon>
|
<mat-icon>add</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -59,8 +68,8 @@
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container matColumnDef="action">
|
<ng-container matColumnDef="action">
|
||||||
<th mat-header-cell *matHeaderCellDef></th>
|
<th mat-header-cell *matHeaderCellDef></th>
|
||||||
<td mat-cell *matCellDef="let row">
|
<td mat-cell *matCellDef="let skill">
|
||||||
<button mat-mini-fab class="warn shadowless">
|
<button mat-mini-fab class="warn shadowless" (click)="onRemoveSkill(skill)">
|
||||||
<mat-icon>delete</mat-icon>
|
<mat-icon>delete</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -3,11 +3,18 @@
|
||||||
.employee-detail {
|
.employee-detail {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1rem;
|
gap: 4rem;
|
||||||
|
|
||||||
|
// Calculate Height and Spacing based on the Form Fields
|
||||||
|
$inner-form-height: 56px;
|
||||||
|
$form-height: 75.5px;
|
||||||
|
$inner-form-spacing: 4.5px;
|
||||||
|
$form-conter-padding: calc(($form-height + $inner-form-spacing - $inner-form-height) / 2);
|
||||||
|
$form-conter-padding-fab: calc(($form-conter-padding - $inner-form-spacing) / 2);
|
||||||
|
|
||||||
&__info-view {
|
&__info-view {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 2rem;
|
gap: 4rem;
|
||||||
|
|
||||||
>* {
|
>* {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
@ -19,8 +26,14 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
input {
|
&__content {
|
||||||
font-size: var(--mat-sys-body-large-size);
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $inner-form-spacing;
|
||||||
|
|
||||||
|
input {
|
||||||
|
font-size: var(--mat-sys-body-large-size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,38 +50,34 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: var(--mat-sys-body-large-size);
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr {
|
tr {
|
||||||
height: 76px;
|
|
||||||
|
|
||||||
td.mat-column-skill {
|
td.mat-column-skill {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-top: 28px;
|
justify-self: center;
|
||||||
padding-bottom: 28px;
|
padding: $form-conter-padding 0;
|
||||||
|
|
||||||
|
p {
|
||||||
|
display: flex;
|
||||||
|
height: $inner-form-height;
|
||||||
|
margin: 0;
|
||||||
|
align-items: center;
|
||||||
|
font-size: var(--mat-sys-body-large-size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
td.mat-column-action {
|
td.mat-column-action {
|
||||||
width: 0;
|
width: 0;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
padding-left: 24px;
|
padding-right: 8px; // Half the difference to the Width of a FAB
|
||||||
padding-right: 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:first-of-type {
|
&:first-of-type {
|
||||||
height: 66px;
|
|
||||||
|
|
||||||
td.mat-column-skill {
|
td.mat-column-skill {
|
||||||
padding-top: 0;
|
padding-top: $inner-form-spacing;
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
td.mat-column-action {
|
td.mat-column-action {
|
||||||
padding-top: 10px;
|
padding-bottom: $form-conter-padding-fab;
|
||||||
vertical-align: unset;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,11 @@ import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatIcon } from '@angular/material/icon';
|
import { MatIcon } from '@angular/material/icon';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelect, MatSelectModule } from '@angular/material/select';
|
||||||
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
||||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||||
import { Employee, EmployeeService, Qualification, QualificationService } from '@core/ems';
|
import { Employee, EmployeeService, NewEmployee, Qualification, QualificationService, UpdatedEmployee } from '@core/ems';
|
||||||
|
import { NotificationService, NotificationType } from '@core/notification/notification.service';
|
||||||
import { map, Observable } from 'rxjs';
|
import { map, Observable } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -32,13 +33,15 @@ export class EmployeeDetailComponent {
|
||||||
employeeForm: FormGroup;
|
employeeForm: FormGroup;
|
||||||
skillsDataSource: MatTableDataSource<Qualification> = new MatTableDataSource<Qualification>([]);
|
skillsDataSource: MatTableDataSource<Qualification> = new MatTableDataSource<Qualification>([]);
|
||||||
skillsDisplayedColumns = ['skill', 'action'];
|
skillsDisplayedColumns = ['skill', 'action'];
|
||||||
$unusedSkills: Observable<Array<Qualification> | undefined>;
|
$unusedSkills: Observable<Array<Qualification>>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
private employeeService: EmployeeService,
|
private employeeService: EmployeeService,
|
||||||
private qualificationService: QualificationService,
|
private qualificationService: QualificationService,
|
||||||
private formBuilder: FormBuilder
|
private formBuilder: FormBuilder,
|
||||||
|
private notificationService: NotificationService
|
||||||
) {
|
) {
|
||||||
const idParam = this.route.snapshot.paramMap.get('id');
|
const idParam = this.route.snapshot.paramMap.get('id');
|
||||||
this.isNewEmployee = idParam == null;
|
this.isNewEmployee = idParam == null;
|
||||||
|
@ -74,10 +77,61 @@ export class EmployeeDetailComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onCreate() {
|
onCreate() {
|
||||||
|
if (!this.employeeForm.valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const employee: NewEmployee = this.employeeForm.value;
|
||||||
|
employee.skillSet = this.skillsDataSource.data.map((qualification) => qualification.id);
|
||||||
|
this.employeeService.createEmployee({ requestBody: employee }).subscribe((response) => {
|
||||||
|
this.notificationService.publish(`${response.firstName} ${response.lastName} was created`, NotificationType.Information);
|
||||||
|
this.router.navigate(['']);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSave() {
|
onSave() {
|
||||||
|
if (!this.employeeForm.valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = this.employeeForm.value.id;
|
||||||
|
const employee: UpdatedEmployee = this.employeeForm.value;
|
||||||
|
employee.skillSet = this.skillsDataSource.data.map((qualification) => qualification.id);
|
||||||
|
|
||||||
|
if (employee.skillSet.length == 0) {
|
||||||
|
this.employeeService.getAllEmployeeQualifications({ id }).subscribe((result) => {
|
||||||
|
result.skillSet?.forEach((skill) => {
|
||||||
|
this.employeeService.removeQualificationFromEmployee({ employeeId: id, qualificationId: skill.id }).subscribe(() => { });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.employeeService.updateEmployee({ id: id, requestBody: employee }).subscribe((response) => {
|
||||||
|
this.notificationService.publish(`${response.firstName} ${response.lastName} was updated`, NotificationType.Information);
|
||||||
|
this.router.navigate(['']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onAddSkill(select: MatSelect) {
|
||||||
|
if (select.value == undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const newSkill = select.value as Qualification;
|
||||||
|
|
||||||
|
const skills = this.skillsDataSource.data;
|
||||||
|
skills.push(newSkill);
|
||||||
|
this.skillsDataSource.data = skills;
|
||||||
|
|
||||||
|
this.$unusedSkills = this.$unusedSkills.pipe(
|
||||||
|
map((skills) => skills.filter(skill => skill.id != newSkill.id))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemoveSkill(skill: Qualification) {
|
||||||
|
const skills = this.skillsDataSource.data;
|
||||||
|
this.skillsDataSource.data = skills.filter(filterSkill => filterSkill.id != skill.id);
|
||||||
|
this.$unusedSkills = this.$unusedSkills.pipe(
|
||||||
|
map(skills => [...skills, skill])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue