feat: add employee management and skill handling features
This commit is contained in:
		
					parent
					
						
							
								0bcc7d4684
							
						
					
				
			
			
				commit
				
					
						d86af94ac8
					
				
			
		
					 10 changed files with 277 additions and 65 deletions
				
			
		|  | @ -2,7 +2,7 @@ import { APP_INITIALIZER, ApplicationConfig, provideZoneChangeDetection } from ' | |||
| import { provideRouter } from '@angular/router'; | ||||
| 
 | ||||
| import { routes } from './app.routes'; | ||||
| import {KeycloakAngularModule, KeycloakBearerInterceptor, KeycloakService} from "keycloak-angular"; | ||||
| import { KeycloakAngularModule, KeycloakBearerInterceptor, KeycloakService } from "keycloak-angular"; | ||||
| import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; | ||||
| 
 | ||||
| export const initializeKeycloak = (keycloak: KeycloakService) => async () => | ||||
|  | @ -28,20 +28,20 @@ function initializeApp(keycloak: KeycloakService): () => Promise<boolean> { | |||
| 
 | ||||
| export const appConfig: ApplicationConfig = { | ||||
|   providers: [ | ||||
|         provideRouter(routes), | ||||
|         KeycloakAngularModule, | ||||
|         { | ||||
|           provide: APP_INITIALIZER, | ||||
|           useFactory: initializeApp, | ||||
|           multi: true, | ||||
|           deps: [KeycloakService] | ||||
|         }, | ||||
|         KeycloakService, | ||||
|         provideHttpClient(withInterceptorsFromDi()), | ||||
|         { | ||||
|           provide: HTTP_INTERCEPTORS, | ||||
|           useClass: KeycloakBearerInterceptor, | ||||
|           multi: true | ||||
|         } | ||||
|       ] | ||||
|     provideRouter(routes), | ||||
|     KeycloakAngularModule, | ||||
|     { | ||||
|       provide: APP_INITIALIZER, | ||||
|       useFactory: initializeApp, | ||||
|       multi: true, | ||||
|       deps: [KeycloakService] | ||||
|     }, | ||||
|     KeycloakService, | ||||
|     provideHttpClient(withInterceptorsFromDi()), | ||||
|     { | ||||
|       provide: HTTP_INTERCEPTORS, | ||||
|       useClass: KeycloakBearerInterceptor, | ||||
|       multi: true | ||||
|     } | ||||
|   ] | ||||
| }; | ||||
|  |  | |||
|  | @ -19,7 +19,8 @@ export const routes: Routes = [ | |||
|   }, | ||||
|   { | ||||
|     path: "mitarbeiterbearbeiten/:id", | ||||
|     component: MitarbeiterBearbeitenViewComponent | ||||
|     component: MitarbeiterBearbeitenViewComponent, | ||||
|     canActivate: [AuthGuard], | ||||
|   }, | ||||
|   { | ||||
|     path: "mitarbeiterdetails", | ||||
|  |  | |||
|  | @ -1 +1 @@ | |||
| <app-mitarbeiter-form></app-mitarbeiter-form> | ||||
| <app-mitarbeiter-form [(mitarbeiter)]="mitarbeiter"></app-mitarbeiter-form> | ||||
|  |  | |||
|  | @ -1,5 +1,8 @@ | |||
| import { Component } from '@angular/core'; | ||||
| import { MitarbeiterFormComponent } from '../mitarbeiter-form/mitarbeiter-form.component'; | ||||
| import { EmployeeResponseDTO } from '../../models/mitarbeiter'; | ||||
| import { EmployeeService } from '../../service/employee.service'; | ||||
| import { ActivatedRoute } from '@angular/router'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'app-mitarbeiter-bearbeiten-view', | ||||
|  | @ -9,5 +12,24 @@ import { MitarbeiterFormComponent } from '../mitarbeiter-form/mitarbeiter-form.c | |||
|   styleUrl: './mitarbeiter-bearbeiten-view.component.css' | ||||
| }) | ||||
| export class MitarbeiterBearbeitenViewComponent { | ||||
|   public mitarbeiter!: EmployeeResponseDTO; | ||||
| 
 | ||||
|   constructor(private employeeService: EmployeeService, private route: ActivatedRoute) { } | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
|     this.mitarbeiter = { | ||||
|       id: 0, | ||||
|       firstName: '', | ||||
|       lastName: '', | ||||
|       street: '', | ||||
|       phone: '', | ||||
|       skillSet: [], | ||||
|       postcode: '', | ||||
|       city: '', | ||||
|     } | ||||
|     this.employeeService.getEmployeeById(this.route.snapshot.params['id']).subscribe(employee => { | ||||
|       this.mitarbeiter = employee; | ||||
|       console.log(this.mitarbeiter); | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,49 +1,56 @@ | |||
| <div class="container"> | ||||
|   <button class="back-button">Back</button> | ||||
|   <div class="user-info"> | ||||
|     <div class="form-group"> | ||||
|       <label for="firstName">First Name</label> | ||||
|       <input type="text" id="firstName" placeholder="First Name"> | ||||
|     </div> | ||||
|     <div class="form-group"> | ||||
|       <label for="lastName">Last Name</label> | ||||
|       <input type="text" id="lastName" placeholder="Last Name"> | ||||
|     </div> | ||||
|     <div class="form-group"> | ||||
|       <label for="street">Street</label> | ||||
|       <input type="text" id="street" placeholder="Street"> | ||||
|     </div> | ||||
|     <div class="form-group"> | ||||
|       <label for="postcode">Postcode</label> | ||||
|       <input type="text" id="postcode" placeholder="Postcode"> | ||||
|     </div> | ||||
|     <div class="form-group"> | ||||
|       <label for="city">City</label> | ||||
|       <input type="text" id="city" placeholder="City"> | ||||
|     </div> | ||||
|     <div class="form-group"> | ||||
|       <label for="phone">Phone Number</label> | ||||
|       <input type="text" id="phone" placeholder="Phone Number"> | ||||
|     </div> | ||||
|   </div> | ||||
| <form [formGroup]="mitarbeiterForm"> | ||||
| 
 | ||||
|   <div class="skills-container"> | ||||
|     <h2>Skills</h2> | ||||
|     <ul class="skill-list"> | ||||
|       <li> | ||||
|         <span class="skill-name">Skill 1</span> | ||||
|           <button class="delete-skill-button"> | ||||
|   <div class="container"> | ||||
|     <button class="back-button">Back</button> | ||||
|     <div class="user-info"> | ||||
|       <div class="form-group"> | ||||
|         <label for="firstName">First Name</label> | ||||
|         <input type="text" id="firstName" placeholder="First Name" formControlName="firstName"> | ||||
|       </div> | ||||
|       <div class="form-group"> | ||||
|         <label for="lastName">Last Name</label> | ||||
|         <input type="text" id="lastName" placeholder="Last Name" formControlName="lastName"> | ||||
|       </div> | ||||
|       <div class="form-group"> | ||||
|         <label for="street">Street</label> | ||||
|         <input type="text" id="street" placeholder="Street" formControlName="street"> | ||||
|       </div> | ||||
|       <div class="form-group"> | ||||
|         <label for="postcode">Postcode</label> | ||||
|         <input type="text" id="postcode" placeholder="Postcode" formControlName="postcode"> | ||||
|       </div> | ||||
|       <div class="form-group"> | ||||
|         <label for="city">City</label> | ||||
|         <input type="text" id="city" placeholder="City" formControlName="city"> | ||||
|       </div> | ||||
|       <div class="form-group"> | ||||
|         <label for="phone">Phone Number</label> | ||||
|         <input type="text" id="phone" placeholder="Phone Number" formControlName="phone"> | ||||
|       </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="skills-container"> | ||||
|       <h2>Skills</h2> | ||||
|       <ul class="skill-list"> | ||||
|         @for (skill of mitarbeiter.skillSet; track skill) { | ||||
|         <li> | ||||
|           <span class="skill-name">{{skill.skill}}</span> | ||||
|           <button (click)="removeSkill(skill.id)" class="delete-skill-button"> | ||||
|             <img src="Delete-button.svg" alt="Delete"> | ||||
|           </button> | ||||
|       </li> | ||||
|     </ul> | ||||
|     <div class="skill-controls"> | ||||
|       <select> | ||||
|         <option value="">Option 1</option> | ||||
|         <option value="">Option 2</option> | ||||
|       </select> | ||||
|       <button class="add-skill-button">Add qualification</button> | ||||
|         </li> | ||||
|         } | ||||
|       </ul> | ||||
|       <div class="skill-controls"> | ||||
|         <select formControlName="newSkill"> | ||||
|           @for (skill of allSkills | async; track skill) { | ||||
|           <option value="{{skill.id}}">{{skill.skill}}</option> | ||||
|           } | ||||
|         </select> | ||||
|         <button (click)="addSkill()" class="add-skill-button">Add qualification</button> | ||||
|       </div> | ||||
|     </div> | ||||
|     <button (click)="submit()" class="save-button">Save</button> | ||||
|   </div> | ||||
|   <button class="save-button">Save</button> | ||||
| </div> | ||||
| 
 | ||||
| </form> | ||||
|  |  | |||
|  | @ -1,12 +1,72 @@ | |||
| import { Component } from '@angular/core'; | ||||
| import { Component, EventEmitter, Input, Output } from '@angular/core'; | ||||
| import { EmployeeNameAndSkillDataDTO, EmployeeRequestPutDTO, EmployeeResponseDTO } from '../../models/mitarbeiter'; | ||||
| import { AbstractControl, FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; | ||||
| import { HttpClient } from '@angular/common/http'; | ||||
| import { Router } from '@angular/router'; | ||||
| import { AsyncPipe, NgFor } from '@angular/common'; | ||||
| import { SkillService } from '../../service/skill.service'; | ||||
| import { QualificationGetDTO } from '../../models/skill'; | ||||
| import { Observable, of } from 'rxjs'; | ||||
| import { EmployeeService } from '../../service/employee.service'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'app-mitarbeiter-form', | ||||
|   standalone: true, | ||||
|   imports: [MitarbeiterFormComponent], | ||||
|   imports: [MitarbeiterFormComponent, ReactiveFormsModule, NgFor, AsyncPipe], | ||||
|   templateUrl: './mitarbeiter-form.component.html', | ||||
|   styleUrl: './mitarbeiter-form.component.css' | ||||
| }) | ||||
| export class MitarbeiterFormComponent { | ||||
|   @Input() mitarbeiter!: EmployeeResponseDTO; | ||||
|   @Output() mitarbeiterChange = new EventEmitter<EmployeeResponseDTO>(); | ||||
| 
 | ||||
|   public mitarbeiterForm!: FormGroup; | ||||
|   public allSkills: Observable<Array<QualificationGetDTO>> = of([]); | ||||
| 
 | ||||
|   constructor(public http: HttpClient, public router: Router, private employeeService: EmployeeService, private skillService: SkillService) { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   private setupForm() { | ||||
|     this.mitarbeiterForm = new FormGroup({ | ||||
|       lastName: new FormControl(this.mitarbeiter.lastName), | ||||
|       firstName: new FormControl(this.mitarbeiter.firstName), | ||||
|       street: new FormControl(this.mitarbeiter.street), | ||||
|       postcode: new FormControl(this.mitarbeiter.postcode), | ||||
|       city: new FormControl(this.mitarbeiter.city), | ||||
|       phone: new FormControl(this.mitarbeiter.phone), | ||||
|       newSkill: new FormControl(), | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   ngOnChanges(): void { | ||||
|     this.setupForm(); | ||||
|   } | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
|     this.allSkills = this.skillService.getAllSkills(); | ||||
|     this.setupForm(); | ||||
|   } | ||||
| 
 | ||||
|   removeSkill(id?: number) { | ||||
|     this.mitarbeiter.skillSet = this.mitarbeiter.skillSet?.filter(skill => skill.id !== id); | ||||
|   } | ||||
| 
 | ||||
|   addSkill() { | ||||
|     const id = Number(this.mitarbeiterForm.get("newSkill")?.value); | ||||
|     this.employeeService.addSkillToEmployee(id, this.mitarbeiter); | ||||
|   } | ||||
| 
 | ||||
|   submit() { | ||||
|     this.mitarbeiter.firstName = this.mitarbeiterForm.get("firstName")?.value; | ||||
|     this.mitarbeiter.lastName = this.mitarbeiterForm.get("lastName")?.value; | ||||
|     this.mitarbeiter.street = this.mitarbeiterForm.get("street")?.value; | ||||
|     this.mitarbeiter.postcode = this.mitarbeiterForm.get("postcode")?.value; | ||||
|     this.mitarbeiter.city = this.mitarbeiterForm.get("city")?.value; | ||||
|     this.mitarbeiter.phone = this.mitarbeiterForm.get("phone")?.value; | ||||
| 
 | ||||
|     console.log(this.mitarbeiterForm); | ||||
|     console.log(this.mitarbeiter); | ||||
|     this.mitarbeiterChange.emit(this.mitarbeiter); | ||||
|   } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										47
									
								
								src/app/models/mitarbeiter.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/app/models/mitarbeiter.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| import { QualificationGetDTO, QualificationPostDTO } from "./skill"; | ||||
| 
 | ||||
| export interface EmployeeRequestPutDTO { | ||||
|   lastName: string, | ||||
|   firstName: string, | ||||
|   street: string, | ||||
|   postcode: string, | ||||
|   city: string, | ||||
|   phone: string, | ||||
|   skillSet: Array<number>, | ||||
| } | ||||
| 
 | ||||
| export interface EmployeeResponseDTO { | ||||
|   id: number, | ||||
|   lastName: string, | ||||
|   firstName: string, | ||||
|   street: string, | ||||
|   postcode: string, | ||||
|   city: string, | ||||
|   phone: string, | ||||
|   skillSet?: Array<QualificationGetDTO>, | ||||
| } | ||||
| 
 | ||||
| export interface EmployeeRequestDTO { | ||||
|   lastName: string, | ||||
|   firstName: string, | ||||
|   street: string, | ||||
|   postcode: string, | ||||
|   city: string, | ||||
|   phone: string, | ||||
|   skillSet?: Array<number>, | ||||
| } | ||||
| 
 | ||||
| export interface EmployeeNameAndSkillDataDTO { | ||||
|   id: number, | ||||
|   lastName: string, | ||||
|   firstName: string, | ||||
|   skillSet: Array<QualificationPostDTO>, | ||||
| } | ||||
| 
 | ||||
| export interface EmployeeNameDataDTO { | ||||
|   id: number, | ||||
|   lastName: string, | ||||
|   firstName: string, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										12
									
								
								src/app/models/skill.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/app/models/skill.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| export interface QualificationGetDTO { | ||||
|   id: number, | ||||
|   skill: string, | ||||
| } | ||||
| 
 | ||||
| export interface QualificationPostDTO { | ||||
|   skill: string, | ||||
| } | ||||
| 
 | ||||
| export interface EmployeesForAQualificationDTO { | ||||
|   qualification: QualificationGetDTO, | ||||
| } | ||||
							
								
								
									
										43
									
								
								src/app/service/employee.service.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/app/service/employee.service.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,43 @@ | |||
| import { Injectable } from "@angular/core"; | ||||
| import { EmployeeRequestPutDTO, EmployeeResponseDTO } from "../models/mitarbeiter"; | ||||
| import { HttpClient } from "@angular/common/http"; | ||||
| import { Observable } from "rxjs"; | ||||
| import { SkillService } from "./skill.service"; | ||||
| 
 | ||||
| @Injectable({ | ||||
|   providedIn: 'root' | ||||
| }) | ||||
| export class EmployeeService { | ||||
|   constructor(private http: HttpClient) {} | ||||
| 
 | ||||
| 
 | ||||
|   responseDtoToPutDto(employee: EmployeeResponseDTO): EmployeeRequestPutDTO { | ||||
|     return { | ||||
|       firstName: employee.firstName, | ||||
|       lastName: employee.lastName, | ||||
|       street: employee.street, | ||||
|       postcode: employee.postcode, | ||||
|       city: employee.city, | ||||
|       phone: employee.phone, | ||||
|       skillSet: employee.skillSet?.map(skill => skill.id) || [], | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   getAllEmployees(): Observable<Array<EmployeeResponseDTO>> { | ||||
|     return this.http.get<Array<EmployeeResponseDTO>>(`${SkillService.BASE_URL}/employees`); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   getEmployeeById(id: number): Observable<EmployeeResponseDTO> { | ||||
|     return this.http.get<EmployeeResponseDTO>(`${SkillService.BASE_URL}/employees/${id}`); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   addSkillToEmployee(skillId: number, employee: EmployeeResponseDTO) { | ||||
|     let employeePut = this.responseDtoToPutDto(employee); | ||||
|     employeePut.skillSet.push(skillId); | ||||
| 
 | ||||
|     this.http.put(`${SkillService.BASE_URL}/employees/${employee.id}`, employeePut).subscribe(); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										20
									
								
								src/app/service/skill.service.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/app/service/skill.service.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| import { HttpClient } from "@angular/common/http"; | ||||
| import { Injectable } from "@angular/core"; | ||||
| import { QualificationGetDTO } from "../models/skill"; | ||||
| import { Observable } from "rxjs"; | ||||
| 
 | ||||
| @Injectable({ | ||||
|   providedIn: 'root' | ||||
| }) | ||||
| export class SkillService { | ||||
| 
 | ||||
|   public static readonly BASE_URL = "http://localhost:8089"; | ||||
| 
 | ||||
|   constructor(private http: HttpClient) { | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   getAllSkills(): Observable<Array<QualificationGetDTO>> { | ||||
|     return this.http.get<Array<QualificationGetDTO>>(`${SkillService.BASE_URL}/qualifications`); | ||||
|   } | ||||
| } | ||||
		Reference in a new issue