format code and improve readability across files (#47)
Reviewed-on: http://git.simonis.lol/angular/ems-frontend/pulls/47 Co-authored-by: Jan-Marlon Leibl <jleibl@proton.me> Co-committed-by: Jan-Marlon Leibl <jleibl@proton.me>
This commit is contained in:
committed by
Hop In, I Have Puppies AND WiFi

parent
88d9a1a534
commit
545c6194e4
@ -1,4 +1,4 @@
|
||||
import {Qualification} from "../qualification/Qualification";
|
||||
import { Qualification } from '../qualification/Qualification';
|
||||
|
||||
export class Employee {
|
||||
constructor(
|
||||
@ -9,7 +9,6 @@ export class Employee {
|
||||
public postcode?: string,
|
||||
public city?: string,
|
||||
public phone?: string,
|
||||
public skillSet?: Qualification[]
|
||||
) {
|
||||
}
|
||||
public skillSet?: Qualification[],
|
||||
) {}
|
||||
}
|
||||
|
@ -5,74 +5,98 @@
|
||||
<div class="flex gap-x-4">
|
||||
<mat-form-field class="!w-full">
|
||||
<mat-label>First Name</mat-label>
|
||||
<input matInput formControlName="firstName" required>
|
||||
<input matInput formControlName="firstName" required />
|
||||
<mat-hint>Enter the first name</mat-hint>
|
||||
<mat-error *ngIf="errors['firstName']">{{errors['firstName']}}</mat-error>
|
||||
<mat-error *ngIf="errors['firstName']">{{
|
||||
errors["firstName"]
|
||||
}}</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="!w-full">
|
||||
<mat-label>Last Name</mat-label>
|
||||
<input matInput formControlName="lastName" required>
|
||||
<input matInput formControlName="lastName" required />
|
||||
<mat-hint>Enter the last name</mat-hint>
|
||||
<mat-error *ngIf="errors['lastName']">{{errors['lastName']}}</mat-error>
|
||||
<mat-error *ngIf="errors['lastName']">{{
|
||||
errors["lastName"]
|
||||
}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<mat-form-field class="!w-full">
|
||||
<mat-label>Street</mat-label>
|
||||
<input matInput formControlName="street" required>
|
||||
<input matInput formControlName="street" required />
|
||||
<mat-hint>Enter the street address</mat-hint>
|
||||
<mat-error *ngIf="errors['street']">{{errors['street']}}</mat-error>
|
||||
<mat-error *ngIf="errors['street']">{{ errors["street"] }}</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<div class="flex gap-x-4">
|
||||
<mat-form-field class="!w-full">
|
||||
<mat-label>City</mat-label>
|
||||
<input matInput formControlName="city" required>
|
||||
<input matInput formControlName="city" required />
|
||||
<mat-hint>Enter the city</mat-hint>
|
||||
<mat-error *ngIf="errors['city']">{{errors['city']}}</mat-error>
|
||||
<mat-error *ngIf="errors['city']">{{ errors["city"] }}</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="!w-1/2">
|
||||
<mat-label>Postcode</mat-label>
|
||||
<input matInput formControlName="postcode" minlength="5" maxlength="5" type="number" required>
|
||||
<input
|
||||
matInput
|
||||
formControlName="postcode"
|
||||
minlength="5"
|
||||
maxlength="5"
|
||||
type="number"
|
||||
required
|
||||
/>
|
||||
<mat-hint>Enter postcode</mat-hint>
|
||||
<mat-error *ngIf="errors['postcode']">{{errors['postcode']}}</mat-error>
|
||||
<mat-error *ngIf="errors['postcode']">{{
|
||||
errors["postcode"]
|
||||
}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<mat-form-field class="!w-full">
|
||||
<mat-label>Phone</mat-label>
|
||||
<input matInput formControlName="phone" required>
|
||||
<input matInput formControlName="phone" required />
|
||||
<mat-hint>Enter the phone number</mat-hint>
|
||||
<mat-error *ngIf="errors['phone']">{{errors['phone']}}</mat-error>
|
||||
<mat-error *ngIf="errors['phone']">{{ errors["phone"] }}</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="!w-full">
|
||||
<mat-label>Qualifications</mat-label>
|
||||
<mat-hint>Select the qualifications</mat-hint>
|
||||
<mat-select formControlName="qualifications" multiple>
|
||||
<mat-option *ngFor="let qualification of qualifications" [value]="qualification.id">
|
||||
{{qualification.skill}}
|
||||
<mat-option
|
||||
*ngFor="let qualification of qualifications"
|
||||
[value]="qualification.id"
|
||||
>
|
||||
{{ qualification.skill }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="errors['qualifications']">{{errors['qualifications']}}</mat-error>
|
||||
<mat-error *ngIf="errors['qualifications']">{{
|
||||
errors["qualifications"]
|
||||
}}</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-dialog-actions align="end" class="!px-0 !mb-0 flex flex-col sm:flex-row w-full gap-3">
|
||||
<button mat-button
|
||||
mat-dialog-close
|
||||
class="text-sm md:text-base hover:bg-gray-100 py-2 px-6 rounded-md w-full sm:flex-1">
|
||||
<mat-dialog-actions
|
||||
align="end"
|
||||
class="!px-0 !mb-0 flex flex-col sm:flex-row w-full gap-3"
|
||||
>
|
||||
<button
|
||||
mat-button
|
||||
mat-dialog-close
|
||||
class="text-sm md:text-base hover:bg-gray-100 py-2 px-6 rounded-md w-full sm:flex-1"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button mat-flat-button
|
||||
color="primary"
|
||||
type="submit"
|
||||
class="!ml-0 text-sm md:text-base py-2 px-6 rounded-md w-full sm:flex-1">
|
||||
<button
|
||||
mat-flat-button
|
||||
color="primary"
|
||||
type="submit"
|
||||
class="!ml-0 text-sm md:text-base py-2 px-6 rounded-md w-full sm:flex-1"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</mat-dialog-content>
|
||||
|
@ -1,23 +1,29 @@
|
||||
import {Component, inject, OnInit} from '@angular/core';
|
||||
import {AbstractControl, FormBuilder, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
|
||||
import {MatFormField, MatHint, MatLabel} from "@angular/material/form-field";
|
||||
import {MatError, MatInput} from "@angular/material/input";
|
||||
import {MatButton} from "@angular/material/button";
|
||||
import { Component, inject, OnInit } from '@angular/core';
|
||||
import {
|
||||
AbstractControl,
|
||||
FormBuilder,
|
||||
FormGroup,
|
||||
ReactiveFormsModule,
|
||||
Validators,
|
||||
} from '@angular/forms';
|
||||
import { MatFormField, MatHint, MatLabel } from '@angular/material/form-field';
|
||||
import { MatError, MatInput } from '@angular/material/input';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import {
|
||||
MatDialogActions,
|
||||
MatDialogClose,
|
||||
MatDialogContent,
|
||||
MatDialogRef,
|
||||
MatDialogTitle
|
||||
} from "@angular/material/dialog";
|
||||
import {Employee} from "../Employee";
|
||||
import EmployeeApiService from "../../services/employee-api.service";
|
||||
import {NgForOf, NgIf} from "@angular/common";
|
||||
import {MatOption} from "@angular/material/core";
|
||||
import {MatSelect} from "@angular/material/select";
|
||||
import QualificationService from "../../services/qualification.service";
|
||||
import {Qualification} from "../../qualification/Qualification";
|
||||
import {debounceTime} from "rxjs";
|
||||
MatDialogTitle,
|
||||
} from '@angular/material/dialog';
|
||||
import { Employee } from '../Employee';
|
||||
import EmployeeApiService from '../../services/employee-api.service';
|
||||
import { NgForOf, NgIf } from '@angular/common';
|
||||
import { MatOption } from '@angular/material/core';
|
||||
import { MatSelect } from '@angular/material/select';
|
||||
import QualificationService from '../../services/qualification.service';
|
||||
import { Qualification } from '../../qualification/Qualification';
|
||||
import { debounceTime } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-create-employee',
|
||||
@ -36,11 +42,11 @@ import {debounceTime} from "rxjs";
|
||||
MatSelect,
|
||||
NgForOf,
|
||||
MatError,
|
||||
MatHint
|
||||
MatHint,
|
||||
],
|
||||
templateUrl: './create.component.html',
|
||||
standalone: true,
|
||||
styleUrl: './create.component.css'
|
||||
styleUrl: './create.component.css',
|
||||
})
|
||||
export class CreateComponent implements OnInit {
|
||||
employeeForm!: FormGroup;
|
||||
@ -49,17 +55,17 @@ export class CreateComponent implements OnInit {
|
||||
dialogRef: MatDialogRef<CreateComponent> = inject(MatDialogRef);
|
||||
qualificationService: QualificationService = inject(QualificationService);
|
||||
qualifications: Qualification[] = [];
|
||||
errorMsgs: { [key: string]: string } = {
|
||||
errorMsgs: Record<string, string> = {
|
||||
firstName: 'First name is required',
|
||||
lastName: 'Last name is required',
|
||||
street: 'Street is required',
|
||||
postcode: 'Postcode must be 5 characters long',
|
||||
city: 'City is required',
|
||||
phone: 'Phone is required',
|
||||
qualifications: 'Qualifications are required'
|
||||
}
|
||||
qualifications: 'Qualifications are required',
|
||||
};
|
||||
|
||||
errors: { [key: string]: string } = {}
|
||||
errors: Record<string, string> = {};
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadQualifications();
|
||||
@ -70,7 +76,7 @@ export class CreateComponent implements OnInit {
|
||||
postcode: ['', [Validators.required, this.validatePostcode]],
|
||||
city: ['', Validators.required],
|
||||
phone: ['', Validators.required],
|
||||
qualifications: [[]]
|
||||
qualifications: [[]],
|
||||
});
|
||||
|
||||
Object.keys(this.employeeForm.controls).forEach((controlName: string) => {
|
||||
@ -82,9 +88,9 @@ export class CreateComponent implements OnInit {
|
||||
}
|
||||
|
||||
loadQualifications() {
|
||||
this.qualificationService.getAll().subscribe(
|
||||
qualifications => this.qualifications = qualifications
|
||||
);
|
||||
this.qualificationService
|
||||
.getAll()
|
||||
.subscribe((qualifications) => (this.qualifications = qualifications));
|
||||
}
|
||||
|
||||
submit() {
|
||||
@ -95,7 +101,7 @@ export class CreateComponent implements OnInit {
|
||||
const formValue = this.employeeForm.value;
|
||||
const employeeData = {
|
||||
...formValue,
|
||||
skillSet: formValue.qualifications
|
||||
skillSet: formValue.qualifications,
|
||||
};
|
||||
|
||||
this.employeeService.create(employeeData as Employee).subscribe();
|
||||
@ -111,7 +117,7 @@ export class CreateComponent implements OnInit {
|
||||
validatePostcode(control: AbstractControl) {
|
||||
const postcode = control.value as number;
|
||||
if (postcode.toString().length !== 5) {
|
||||
return {invalidPostcode: true};
|
||||
return { invalidPostcode: true };
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -1,31 +1,48 @@
|
||||
<h2 mat-dialog-title class="text-xl md:text-2xl font-semibold text-gray-800 mb-3 md:mb-4">Delete Employee</h2>
|
||||
<h2
|
||||
mat-dialog-title
|
||||
class="text-xl md:text-2xl font-semibold text-gray-800 mb-3 md:mb-4"
|
||||
>
|
||||
Delete Employee
|
||||
</h2>
|
||||
|
||||
<mat-dialog-content class="!px-3 md:!px-6">
|
||||
<div class="w-full min-w-[280px] md:min-w-[400px] space-y-4 md:space-y-6">
|
||||
<div class="bg-amber-50 p-3 md:p-4 rounded-lg border border-amber-200">
|
||||
<div class="flex items-start space-x-2 md:space-x-3">
|
||||
<mat-icon class="text-amber-600 text-xl md:text-2xl !w-8 !h-8">warning</mat-icon>
|
||||
<mat-icon class="text-amber-600 text-xl md:text-2xl !w-8 !h-8"
|
||||
>warning</mat-icon
|
||||
>
|
||||
<div>
|
||||
<p class="text-gray-800 font-medium text-sm md:text-base">
|
||||
Are you sure you want to delete {{employee.firstName}} {{employee.lastName}}?
|
||||
Are you sure you want to delete {{ employee.firstName }}
|
||||
{{ employee.lastName }}?
|
||||
</p>
|
||||
<p class="text-gray-600 mt-1 text-xs md:text-sm">
|
||||
This action cannot be undone.
|
||||
</p>
|
||||
<p class="text-gray-600 mt-1 text-xs md:text-sm">This action cannot be undone.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-dialog-actions align="end" class="!px-0 !mb-0 flex flex-col sm:flex-row w-full gap-3">
|
||||
<button mat-button
|
||||
[mat-dialog-close]="false"
|
||||
class="text-sm md:text-base hover:bg-gray-100 py-2 px-6 rounded-md w-full sm:flex-1">
|
||||
<mat-dialog-actions
|
||||
align="end"
|
||||
class="!px-0 !mb-0 flex flex-col sm:flex-row w-full gap-3"
|
||||
>
|
||||
<button
|
||||
mat-button
|
||||
[mat-dialog-close]="false"
|
||||
class="text-sm md:text-base hover:bg-gray-100 py-2 px-6 rounded-md w-full sm:flex-1"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button mat-flat-button
|
||||
color="warn"
|
||||
(click)="deleteEmployee(employee.id ?? 0)"
|
||||
mat-dialog-close
|
||||
class="!ml-0 text-sm md:text-base py-2 px-6 rounded-md w-full sm:flex-1"
|
||||
cdkFocusInitial>
|
||||
<button
|
||||
mat-flat-button
|
||||
color="warn"
|
||||
(click)="deleteEmployee(employee.id ?? 0)"
|
||||
mat-dialog-close
|
||||
class="!ml-0 text-sm md:text-base py-2 px-6 rounded-md w-full sm:flex-1"
|
||||
cdkFocusInitial
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
|
@ -1,15 +1,16 @@
|
||||
import {Component, Inject, inject} from '@angular/core';
|
||||
import {Employee} from "../Employee";
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { Employee } from '../Employee';
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialogActions,
|
||||
MatDialogClose,
|
||||
MatDialogContent, MatDialogRef,
|
||||
MatDialogTitle
|
||||
} from "@angular/material/dialog";
|
||||
import {MatButton} from "@angular/material/button";
|
||||
import {MatIcon} from "@angular/material/icon";
|
||||
import EmployeeApiService from "../../services/employee-api.service";
|
||||
MatDialogContent,
|
||||
MatDialogRef,
|
||||
MatDialogTitle,
|
||||
} from '@angular/material/dialog';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import EmployeeApiService from '../../services/employee-api.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-delete-employee',
|
||||
@ -19,11 +20,11 @@ import EmployeeApiService from "../../services/employee-api.service";
|
||||
MatDialogActions,
|
||||
MatButton,
|
||||
MatDialogClose,
|
||||
MatIcon
|
||||
MatIcon,
|
||||
],
|
||||
templateUrl: './delete.component.html',
|
||||
standalone: true,
|
||||
styleUrl: './delete.component.css'
|
||||
styleUrl: './delete.component.css',
|
||||
})
|
||||
export class DeleteComponent {
|
||||
private apiService: EmployeeApiService = inject(EmployeeApiService);
|
||||
|
@ -1,21 +1,32 @@
|
||||
<h2 mat-dialog-title class="text-2xl font-semibold text-gray-800 mb-4">Employee Details</h2>
|
||||
<h2 mat-dialog-title class="text-2xl font-semibold text-gray-800 mb-4">
|
||||
Employee Details
|
||||
</h2>
|
||||
|
||||
<mat-dialog-content class="!px-4 sm:!px-6">
|
||||
<div class="w-full min-w-[280px] sm:min-w-[500px] space-y-6 sm:space-y-8">
|
||||
<div class="flex flex-col sm:flex-row items-center sm:items-start text-center sm:text-left space-y-4 sm:space-y-0 sm:space-x-4">
|
||||
<div class="h-20 w-20 sm:h-16 sm:w-16 rounded-full bg-blue-100 flex items-center justify-center flex-shrink-0">
|
||||
<div
|
||||
class="flex flex-col sm:flex-row items-center sm:items-start text-center sm:text-left space-y-4 sm:space-y-0 sm:space-x-4"
|
||||
>
|
||||
<div
|
||||
class="h-20 w-20 sm:h-16 sm:w-16 rounded-full bg-blue-100 flex items-center justify-center flex-shrink-0"
|
||||
>
|
||||
<span class="text-blue-600 text-2xl sm:text-xl font-medium">
|
||||
{{ employee.firstName?.charAt(0) ?? '' }}{{ employee.lastName?.charAt(0) ?? '' }}
|
||||
{{ employee.firstName?.charAt(0) ?? ""
|
||||
}}{{ employee.lastName?.charAt(0) ?? "" }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-xl font-medium text-gray-900">{{ employee.firstName }} {{ employee.lastName }}</h3>
|
||||
<h3 class="text-xl font-medium text-gray-900">
|
||||
{{ employee.firstName }} {{ employee.lastName }}
|
||||
</h3>
|
||||
<p class="text-gray-500">ID: {{ employee.id }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3 sm:space-y-4">
|
||||
<h4 class="text-lg font-medium text-gray-900 mb-2 sm:mb-3">Contact Information</h4>
|
||||
<h4 class="text-lg font-medium text-gray-900 mb-2 sm:mb-3">
|
||||
Contact Information
|
||||
</h4>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div class="space-y-1">
|
||||
<p class="text-sm text-gray-500">Phone</p>
|
||||
@ -45,11 +56,15 @@
|
||||
</div>
|
||||
|
||||
<div class="space-y-3 sm:space-y-4">
|
||||
<h4 class="text-lg font-medium text-gray-900 mb-2 sm:mb-3">Qualifications</h4>
|
||||
<h4 class="text-lg font-medium text-gray-900 mb-2 sm:mb-3">
|
||||
Qualifications
|
||||
</h4>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@for (skill of employee.skillSet; track skill.id) {
|
||||
<div class="bg-blue-50 text-blue-700 px-3 py-1 rounded-full text-sm font-medium">
|
||||
{{skill.skill}}
|
||||
<div
|
||||
class="bg-blue-50 text-blue-700 px-3 py-1 rounded-full text-sm font-medium"
|
||||
>
|
||||
{{ skill.skill }}
|
||||
</div>
|
||||
} @empty {
|
||||
<p class="text-gray-500 italic">No qualifications added</p>
|
||||
@ -60,9 +75,11 @@
|
||||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions align="end" class="!px-4 sm:!px-6 !py-4 !mt-4 border-t">
|
||||
<button mat-button
|
||||
(click)="closeModal()"
|
||||
class="text-sm md:text-base hover:bg-gray-100 py-2 px-6 rounded-md w-full">
|
||||
<button
|
||||
mat-button
|
||||
(click)="closeModal()"
|
||||
class="text-sm md:text-base hover:bg-gray-100 py-2 px-6 rounded-md w-full"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
|
@ -1,20 +1,20 @@
|
||||
import {Component, inject} from '@angular/core';
|
||||
import {MAT_DIALOG_DATA, MatDialogActions, MatDialogContent, MatDialogTitle} from "@angular/material/dialog";
|
||||
import {Employee} from "../Employee";
|
||||
import {MatButton} from "@angular/material/button";
|
||||
import {DialogRef} from "@angular/cdk/dialog";
|
||||
import { Component, inject } from '@angular/core';
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialogActions,
|
||||
MatDialogContent,
|
||||
MatDialogTitle,
|
||||
} from '@angular/material/dialog';
|
||||
import { Employee } from '../Employee';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { DialogRef } from '@angular/cdk/dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'app-details',
|
||||
imports: [
|
||||
MatDialogTitle,
|
||||
MatDialogContent,
|
||||
MatButton,
|
||||
MatDialogActions
|
||||
],
|
||||
imports: [MatDialogTitle, MatDialogContent, MatButton, MatDialogActions],
|
||||
templateUrl: './details.component.html',
|
||||
standalone: true,
|
||||
styleUrl: './details.component.css'
|
||||
styleUrl: './details.component.css',
|
||||
})
|
||||
export class DetailsComponent {
|
||||
employee: Employee = inject(MAT_DIALOG_DATA);
|
||||
|
@ -5,74 +5,98 @@
|
||||
<div class="flex gap-x-4">
|
||||
<mat-form-field class="!w-full">
|
||||
<mat-label>First Name</mat-label>
|
||||
<input matInput formControlName="firstName" required>
|
||||
<input matInput formControlName="firstName" required />
|
||||
<mat-hint>Enter the first name</mat-hint>
|
||||
<mat-error *ngIf="errors['firstName']">{{errors['firstName']}}</mat-error>
|
||||
<mat-error *ngIf="errors['firstName']">{{
|
||||
errors["firstName"]
|
||||
}}</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="!w-full">
|
||||
<mat-label>Last Name</mat-label>
|
||||
<input matInput formControlName="lastName" required>
|
||||
<input matInput formControlName="lastName" required />
|
||||
<mat-hint>Enter the last name</mat-hint>
|
||||
<mat-error *ngIf="errors['lastName']">{{errors['lastName']}}</mat-error>
|
||||
<mat-error *ngIf="errors['lastName']">{{
|
||||
errors["lastName"]
|
||||
}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<mat-form-field class="!w-full">
|
||||
<mat-label>Street</mat-label>
|
||||
<input matInput formControlName="street" required>
|
||||
<input matInput formControlName="street" required />
|
||||
<mat-hint>Enter the street address</mat-hint>
|
||||
<mat-error *ngIf="errors['street']">{{errors['street']}}</mat-error>
|
||||
<mat-error *ngIf="errors['street']">{{ errors["street"] }}</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<div class="flex gap-x-4">
|
||||
<mat-form-field class="!w-full">
|
||||
<mat-label>City</mat-label>
|
||||
<input matInput formControlName="city" required>
|
||||
<input matInput formControlName="city" required />
|
||||
<mat-hint>Enter the city</mat-hint>
|
||||
<mat-error *ngIf="errors['city']">{{errors['city']}}</mat-error>
|
||||
<mat-error *ngIf="errors['city']">{{ errors["city"] }}</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="!w-1/2">
|
||||
<mat-label>Postcode</mat-label>
|
||||
<input matInput formControlName="postcode" minlength="5" maxlength="5" type="number" required>
|
||||
<input
|
||||
matInput
|
||||
formControlName="postcode"
|
||||
minlength="5"
|
||||
maxlength="5"
|
||||
type="number"
|
||||
required
|
||||
/>
|
||||
<mat-hint>Enter postcode</mat-hint>
|
||||
<mat-error *ngIf="errors['postcode']">{{errors['postcode']}}</mat-error>
|
||||
<mat-error *ngIf="errors['postcode']">{{
|
||||
errors["postcode"]
|
||||
}}</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<mat-form-field class="!w-full">
|
||||
<mat-label>Phone</mat-label>
|
||||
<input matInput formControlName="phone" required>
|
||||
<input matInput formControlName="phone" required />
|
||||
<mat-hint>Enter phone number</mat-hint>
|
||||
<mat-error *ngIf="errors['phone']">{{errors['phone']}}</mat-error>
|
||||
<mat-error *ngIf="errors['phone']">{{ errors["phone"] }}</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="!w-full">
|
||||
<mat-label>Qualifications</mat-label>
|
||||
<mat-select formControlName="qualifications" multiple>
|
||||
<mat-option *ngFor="let qualification of qualifications" [value]="qualification.id">
|
||||
{{qualification.skill}}
|
||||
<mat-option
|
||||
*ngFor="let qualification of qualifications"
|
||||
[value]="qualification.id"
|
||||
>
|
||||
{{ qualification.skill }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-hint>Select qualifications</mat-hint>
|
||||
<mat-error *ngIf="errors['qualifications']">{{errors['qualifications']}}</mat-error>
|
||||
<mat-error *ngIf="errors['qualifications']">{{
|
||||
errors["qualifications"]
|
||||
}}</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-dialog-actions align="end" class="!px-0 !mb-0 flex flex-col sm:flex-row w-full gap-3">
|
||||
<button mat-button
|
||||
mat-dialog-close
|
||||
class="text-sm md:text-base hover:bg-gray-100 py-2 px-6 rounded-md w-full sm:flex-1">
|
||||
<mat-dialog-actions
|
||||
align="end"
|
||||
class="!px-0 !mb-0 flex flex-col sm:flex-row w-full gap-3"
|
||||
>
|
||||
<button
|
||||
mat-button
|
||||
mat-dialog-close
|
||||
class="text-sm md:text-base hover:bg-gray-100 py-2 px-6 rounded-md w-full sm:flex-1"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button mat-flat-button
|
||||
color="primary"
|
||||
type="submit"
|
||||
class="!ml-0 text-sm md:text-base py-2 px-6 rounded-md w-full sm:flex-1">
|
||||
<button
|
||||
mat-flat-button
|
||||
color="primary"
|
||||
type="submit"
|
||||
class="!ml-0 text-sm md:text-base py-2 px-6 rounded-md w-full sm:flex-1"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</mat-dialog-content>
|
||||
|
@ -1,23 +1,29 @@
|
||||
import {Component, inject, OnInit} from '@angular/core';
|
||||
import {AbstractControl, FormBuilder, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
|
||||
import { Component, inject, OnInit } from '@angular/core';
|
||||
import {
|
||||
AbstractControl,
|
||||
FormBuilder,
|
||||
FormGroup,
|
||||
ReactiveFormsModule,
|
||||
Validators,
|
||||
} from '@angular/forms';
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialogActions,
|
||||
MatDialogClose,
|
||||
MatDialogContent,
|
||||
MatDialogRef,
|
||||
MatDialogTitle
|
||||
} from "@angular/material/dialog";
|
||||
import {NgForOf, NgIf} from "@angular/common";
|
||||
import {MatFormField, MatHint} from "@angular/material/form-field";
|
||||
import {MatError, MatInput, MatLabel} from "@angular/material/input";
|
||||
import {MatButton} from "@angular/material/button";
|
||||
import {Employee} from "../Employee";
|
||||
import EmployeeApiService from "../../services/employee-api.service";
|
||||
import QualificationService from "../../services/qualification.service";
|
||||
import {Qualification} from "../../qualification/Qualification";
|
||||
import {MatOption, MatSelect} from "@angular/material/select";
|
||||
import {debounceTime} from "rxjs";
|
||||
MatDialogTitle,
|
||||
} from '@angular/material/dialog';
|
||||
import { NgForOf, NgIf } from '@angular/common';
|
||||
import { MatFormField, MatHint } from '@angular/material/form-field';
|
||||
import { MatError, MatInput, MatLabel } from '@angular/material/input';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
import { Employee } from '../Employee';
|
||||
import EmployeeApiService from '../../services/employee-api.service';
|
||||
import QualificationService from '../../services/qualification.service';
|
||||
import { Qualification } from '../../qualification/Qualification';
|
||||
import { MatOption, MatSelect } from '@angular/material/select';
|
||||
import { debounceTime } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit',
|
||||
@ -40,7 +46,7 @@ import {debounceTime} from "rxjs";
|
||||
],
|
||||
templateUrl: './edit.component.html',
|
||||
standalone: true,
|
||||
styleUrl: './edit.component.css'
|
||||
styleUrl: './edit.component.css',
|
||||
})
|
||||
export class EditComponent implements OnInit {
|
||||
employeeForm!: FormGroup;
|
||||
@ -50,17 +56,17 @@ export class EditComponent implements OnInit {
|
||||
dialogRef: MatDialogRef<EditComponent> = inject(MatDialogRef);
|
||||
employee: Employee = inject(MAT_DIALOG_DATA);
|
||||
qualifications: Qualification[] = [];
|
||||
errorMsgs: { [key: string]: string } = {
|
||||
errorMsgs: Record<string, string> = {
|
||||
firstName: 'First name is required',
|
||||
lastName: 'Last name is required',
|
||||
street: 'Street is required',
|
||||
postcode: 'Postcode must be 5 characters long',
|
||||
city: 'City is required',
|
||||
phone: 'Phone is required',
|
||||
qualifications: 'Qualifications are required'
|
||||
}
|
||||
qualifications: 'Qualifications are required',
|
||||
};
|
||||
|
||||
errors: { [key: string]: string } = {}
|
||||
errors: Record<string, string> = {};
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadQualifications();
|
||||
@ -68,10 +74,13 @@ export class EditComponent implements OnInit {
|
||||
firstName: [this.employee.firstName, Validators.required],
|
||||
lastName: [this.employee.lastName, Validators.required],
|
||||
street: [this.employee.street, Validators.required],
|
||||
postcode: [this.employee.postcode, [Validators.required, this.validatePostcode]],
|
||||
postcode: [
|
||||
this.employee.postcode,
|
||||
[Validators.required, this.validatePostcode],
|
||||
],
|
||||
city: [this.employee.city, Validators.required],
|
||||
phone: [this.employee.phone, Validators.required],
|
||||
qualifications: [this.employee.skillSet?.map(skill => skill.id) ?? []]
|
||||
qualifications: [this.employee.skillSet?.map((skill) => skill.id) ?? []],
|
||||
});
|
||||
|
||||
Object.keys(this.employeeForm.controls).forEach((controlName: string) => {
|
||||
@ -83,9 +92,9 @@ export class EditComponent implements OnInit {
|
||||
}
|
||||
|
||||
loadQualifications() {
|
||||
this.qualificationService.getAll().subscribe(
|
||||
qualifications => this.qualifications = qualifications
|
||||
);
|
||||
this.qualificationService
|
||||
.getAll()
|
||||
.subscribe((qualifications) => (this.qualifications = qualifications));
|
||||
}
|
||||
|
||||
submit() {
|
||||
@ -102,10 +111,12 @@ export class EditComponent implements OnInit {
|
||||
const formValue = this.employeeForm.value;
|
||||
const employeeData = {
|
||||
...formValue,
|
||||
skillSet: formValue.qualifications
|
||||
skillSet: formValue.qualifications,
|
||||
};
|
||||
|
||||
this.employeeService.update(employeeData as Employee, this.employee.id).subscribe();
|
||||
this.employeeService
|
||||
.update(employeeData as Employee, this.employee.id)
|
||||
.subscribe();
|
||||
this.dialogRef.close(true);
|
||||
}
|
||||
|
||||
@ -118,7 +129,7 @@ export class EditComponent implements OnInit {
|
||||
validatePostcode(control: AbstractControl) {
|
||||
const postcode = control.value as number;
|
||||
if (postcode.toString().length !== 5) {
|
||||
return {invalidPostcode: true};
|
||||
return { invalidPostcode: true };
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -1,113 +1,163 @@
|
||||
<section class="!space-y-6 mb-6">
|
||||
@defer {
|
||||
@if (employees$ | async; as employees) {
|
||||
<div class="!space-y-6">
|
||||
<div class="!flex !justify-between !items-center">
|
||||
<div class="!flex !items-center !gap-4">
|
||||
<h2 class="!text-2xl !font-semibold !text-gray-900 !shrink-0">Employee Directory</h2>
|
||||
<mat-form-field class="!m-0" subscriptSizing="dynamic">
|
||||
<mat-icon matPrefix class="!text-gray-400 !mr-2">search</mat-icon>
|
||||
<input matInput
|
||||
type="text"
|
||||
placeholder="Search employees..."
|
||||
(keyup)="filterEmployees($event)">
|
||||
<div matSuffix class="!w-[24px] !h-[24px] !ml-2 !flex !items-center !justify-center">
|
||||
<mat-progress-spinner [diameter]="20" mode="indeterminate"
|
||||
[class.!opacity-0]="!isSearching"
|
||||
[class.!opacity-100]="isSearching"
|
||||
class="!transition-opacity"></mat-progress-spinner>
|
||||
@if (employees$ | async; as employees) {
|
||||
<div class="!space-y-6">
|
||||
<div class="!flex !justify-between !items-center">
|
||||
<div class="!flex !items-center !gap-4">
|
||||
<h2 class="!text-2xl !font-semibold !text-gray-900 !shrink-0">
|
||||
Employee Directory
|
||||
</h2>
|
||||
<mat-form-field class="!m-0" subscriptSizing="dynamic">
|
||||
<mat-icon matPrefix class="!text-gray-400 !mr-2">search</mat-icon>
|
||||
<input
|
||||
matInput
|
||||
type="text"
|
||||
placeholder="Search employees..."
|
||||
(keyup)="filterEmployees($event)"
|
||||
/>
|
||||
<div
|
||||
matSuffix
|
||||
class="!w-[24px] !h-[24px] !ml-2 !flex !items-center !justify-center"
|
||||
>
|
||||
<mat-progress-spinner
|
||||
[diameter]="20"
|
||||
mode="indeterminate"
|
||||
[class.!opacity-0]="!isSearching"
|
||||
[class.!opacity-100]="isSearching"
|
||||
class="!transition-opacity"
|
||||
></mat-progress-spinner>
|
||||
</div>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</mat-form-field>
|
||||
<button
|
||||
mat-flat-button
|
||||
color="primary"
|
||||
class="!bg-blue-600 !text-white !shrink-0"
|
||||
(click)="showCreateEmployeeModal()"
|
||||
>
|
||||
<mat-icon class="!mr-2">add</mat-icon>
|
||||
Add Employee
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@if (employees) {
|
||||
<div class="!overflow-x-auto !rounded-lg !bg-gray-50 !p-4">
|
||||
<table mat-table [dataSource]="employees" matSort class="!w-full">
|
||||
<ng-container matColumnDef="name">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
class="!text-left !w-full"
|
||||
>
|
||||
Name
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let employee" class="!py-4">
|
||||
<div class="!flex !items-center">
|
||||
<div
|
||||
class="!h-10 !w-10 !rounded-full !bg-blue-100 !flex !items-center !justify-center !mr-3"
|
||||
>
|
||||
<span class="!text-blue-600 !font-medium">
|
||||
{{ employee.firstName[0] }}{{ employee.lastName[0] }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="text-blue-600 hover:underline cursor-pointer"
|
||||
[matTooltip]="'View Employee details'"
|
||||
(click)="openDetailModal(employee)"
|
||||
(keydown.enter)="openDetailModal(employee)"
|
||||
>
|
||||
{{ employee.lastName }}, {{ employee.firstName }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th
|
||||
mat-header-cell
|
||||
*matHeaderCellDef
|
||||
class="!text-right !w-[120px]"
|
||||
>
|
||||
Actions
|
||||
</th>
|
||||
<td
|
||||
mat-cell
|
||||
*matCellDef="let employee"
|
||||
class="!text-right !py-4 !whitespace-nowrap"
|
||||
>
|
||||
<div class="!flex !justify-end !items-center !gap-1">
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
[matTooltip]="'Edit employee'"
|
||||
(click)="showEditEmployeeModal(employee)"
|
||||
>
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
color="warn"
|
||||
[matTooltip]="'Delete employee'"
|
||||
(click)="openDeleteDialogue(employee)"
|
||||
>
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
||||
</table>
|
||||
</div>
|
||||
} @else {
|
||||
<mat-card class="!text-center !py-8">
|
||||
<mat-card-content>
|
||||
<mat-icon class="!w-8 !h-8 !text-gray-400 !mb-4">people</mat-icon>
|
||||
<p class="!text-gray-600">No employees found</p>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
}
|
||||
</div>
|
||||
<button mat-flat-button color="primary" class="!bg-blue-600 !text-white !shrink-0"
|
||||
(click)="showCreateEmployeeModal()">
|
||||
<mat-icon class="!mr-2">add</mat-icon>
|
||||
Add Employee
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@if (employees) {
|
||||
<div class="!overflow-x-auto !rounded-lg !bg-gray-50 !p-4">
|
||||
<table mat-table [dataSource]="employees" matSort class="!w-full">
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef class="!text-left !w-full"> Name</th>
|
||||
<td mat-cell *matCellDef="let employee" class="!py-4">
|
||||
<div class="!flex !items-center">
|
||||
<div class="!h-10 !w-10 !rounded-full !bg-blue-100 !flex !items-center !justify-center !mr-3">
|
||||
<span class="!text-blue-600 !font-medium">
|
||||
{{ employee.firstName[0] }}{{ employee.lastName[0] }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<a class="!text-blue-600 hover:!underline cursor-pointer"
|
||||
[matTooltip]="'Click to view Employee details'" (click)="openDetailModal(employee)">
|
||||
{{ employee.lastName }}, {{ employee.firstName }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef class="!text-right !w-[120px]"> Actions</th>
|
||||
<td mat-cell *matCellDef="let employee" class="!text-right !py-4 !whitespace-nowrap">
|
||||
<div class="!flex !justify-end !items-center !gap-1">
|
||||
<button mat-icon-button color="primary" [matTooltip]="'Edit employee'"
|
||||
(click)="showEditEmployeeModal(employee)">
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button color="warn" [matTooltip]="'Delete employee'"
|
||||
(click)="openDeleteDialogue(employee)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
</table>
|
||||
</div>
|
||||
} @else {
|
||||
<mat-card class="!text-center !py-8">
|
||||
<mat-card-content>
|
||||
<mat-icon class="!w-8 !h-8 !text-gray-400 !mb-4">people</mat-icon>
|
||||
<p class="!text-gray-600">No employees found</p>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
} @placeholder {
|
||||
<div class="!space-y-6">
|
||||
<div class="!animate-pulse">
|
||||
<div class="!flex !justify-between !items-center !mb-8">
|
||||
<div class="!h-8 !bg-gray-200 !rounded !w-1/4"></div>
|
||||
<div class="!h-10 !bg-gray-200 !rounded !w-32"></div>
|
||||
</div>
|
||||
<div class="!bg-gray-50 !p-4 !rounded-lg">
|
||||
<div class="!space-y-4">
|
||||
<div class="!h-10 !bg-gray-200 !rounded"></div>
|
||||
@for (i of [1, 2, 3]; track i) {
|
||||
<div class="!h-16 !bg-white !rounded-lg !shadow-sm"></div>
|
||||
}
|
||||
<div class="!space-y-6">
|
||||
<div class="!animate-pulse">
|
||||
<div class="!flex !justify-between !items-center !mb-8">
|
||||
<div class="!h-8 !bg-gray-200 !rounded !w-1/4"></div>
|
||||
<div class="!h-10 !bg-gray-200 !rounded !w-32"></div>
|
||||
</div>
|
||||
<div class="!bg-gray-50 !p-4 !rounded-lg">
|
||||
<div class="!space-y-4">
|
||||
<div class="!h-10 !bg-gray-200 !rounded"></div>
|
||||
@for (i of [1, 2, 3]; track i) {
|
||||
<div class="!h-16 !bg-white !rounded-lg !shadow-sm"></div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
} @error {
|
||||
<div class="bg-red-50 p-3 md:p-4 rounded-lg border border-red-200">
|
||||
<div class="flex items-start space-x-2 md:space-x-3">
|
||||
<mat-icon class="text-red-600 text-xl md:text-2xl !w-8 !h-8">error</mat-icon>
|
||||
<div>
|
||||
<p class="text-gray-800 font-medium text-sm md:text-base">There was an error loading the employees.</p>
|
||||
<p class="text-gray-600 mt-1 text-xs md:text-sm">Please try refreshing the page.</p>
|
||||
<div class="bg-red-50 p-3 md:p-4 rounded-lg border border-red-200">
|
||||
<div class="flex items-start space-x-2 md:space-x-3">
|
||||
<mat-icon class="text-red-600 text-xl md:text-2xl !w-8 !h-8"
|
||||
>error</mat-icon
|
||||
>
|
||||
<div>
|
||||
<p class="text-gray-800 font-medium text-sm md:text-base">
|
||||
There was an error loading the employees.
|
||||
</p>
|
||||
<p class="text-gray-600 mt-1 text-xs md:text-sm">
|
||||
Please try refreshing the page.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
} @loading {
|
||||
<div class="!flex !justify-center !items-center !py-12">
|
||||
<mat-spinner diameter="48" class="!text-blue-600"></mat-spinner>
|
||||
</div>
|
||||
<div class="!flex !justify-center !items-center !py-12">
|
||||
<mat-spinner diameter="48" class="!text-blue-600"></mat-spinner>
|
||||
</div>
|
||||
}
|
||||
</section>
|
||||
</section>
|
||||
|
@ -1,28 +1,36 @@
|
||||
import {Component, inject, OnInit} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {catchError, debounceTime, distinctUntilChanged, Observable, of, retry, Subject} from 'rxjs';
|
||||
import {HttpErrorResponse} from '@angular/common/http';
|
||||
import {Employee} from '../Employee';
|
||||
import { Component, inject, OnInit } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import {
|
||||
catchError,
|
||||
debounceTime,
|
||||
distinctUntilChanged,
|
||||
Observable,
|
||||
of,
|
||||
retry,
|
||||
Subject,
|
||||
} from 'rxjs';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Employee } from '../Employee';
|
||||
|
||||
import {MatCardModule} from '@angular/material/card';
|
||||
import {MatButtonModule} from '@angular/material/button';
|
||||
import {MatIconModule} from '@angular/material/icon';
|
||||
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
|
||||
import {MatSnackBarModule} from '@angular/material/snack-bar';
|
||||
import {MatDividerModule} from '@angular/material/divider';
|
||||
import {MatTooltipModule} from '@angular/material/tooltip';
|
||||
import {MatMenuModule} from '@angular/material/menu';
|
||||
import {MatTableModule} from '@angular/material/table';
|
||||
import {MatSortModule} from '@angular/material/sort';
|
||||
import {MatDialog} from "@angular/material/dialog";
|
||||
import {DeleteComponent} from "../delete/delete.component";
|
||||
import EmployeeApiService from "../../services/employee-api.service";
|
||||
import {CreateComponent} from "../create/create.component";
|
||||
import {EditComponent} from "../edit/edit.component";
|
||||
import {DetailsComponent} from "../details/details.component";
|
||||
import {MatFormFieldModule} from "@angular/material/form-field";
|
||||
import {MatInputModule} from "@angular/material/input";
|
||||
import {ErrorHandlerService} from "../../services/error.handler.service";
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { DeleteComponent } from '../delete/delete.component';
|
||||
import EmployeeApiService from '../../services/employee-api.service';
|
||||
import { CreateComponent } from '../create/create.component';
|
||||
import { EditComponent } from '../edit/edit.component';
|
||||
import { DetailsComponent } from '../details/details.component';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { ErrorHandlerService } from '../../services/error.handler.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-employee-list',
|
||||
@ -43,12 +51,13 @@ import {ErrorHandlerService} from "../../services/error.handler.service";
|
||||
MatInputModule,
|
||||
],
|
||||
templateUrl: './table.component.html',
|
||||
styleUrl: './table.component.css'
|
||||
styleUrl: './table.component.css',
|
||||
})
|
||||
export class TableComponent implements OnInit {
|
||||
private readonly apiService: EmployeeApiService = inject(EmployeeApiService);
|
||||
private readonly matDialog: MatDialog = inject(MatDialog);
|
||||
private readonly errorHandlerService: ErrorHandlerService = inject(ErrorHandlerService);
|
||||
private readonly errorHandlerService: ErrorHandlerService =
|
||||
inject(ErrorHandlerService);
|
||||
|
||||
private static readonly MAX_RETRIES = 3;
|
||||
|
||||
@ -64,27 +73,27 @@ export class TableComponent implements OnInit {
|
||||
}
|
||||
|
||||
private loadEmployees(): void {
|
||||
this.fetchEmployees().subscribe(employees => {
|
||||
this.fetchEmployees().subscribe((employees) => {
|
||||
this.allEmployees = employees;
|
||||
this.employees$ = of(employees);
|
||||
});
|
||||
}
|
||||
|
||||
private setupSearch(): void {
|
||||
this.searchSubject.pipe(
|
||||
debounceTime(300),
|
||||
distinctUntilChanged()
|
||||
).subscribe(searchTerm => {
|
||||
this.isSearching = true;
|
||||
setTimeout(() => {
|
||||
const filteredEmployees = this.allEmployees.filter(employee =>
|
||||
employee.firstName?.toLowerCase().includes(searchTerm) ||
|
||||
employee.lastName?.toLowerCase().includes(searchTerm)
|
||||
);
|
||||
this.employees$ = of(filteredEmployees);
|
||||
this.isSearching = false;
|
||||
}, 150);
|
||||
});
|
||||
this.searchSubject
|
||||
.pipe(debounceTime(300), distinctUntilChanged())
|
||||
.subscribe((searchTerm) => {
|
||||
this.isSearching = true;
|
||||
setTimeout(() => {
|
||||
const filteredEmployees = this.allEmployees.filter(
|
||||
(employee) =>
|
||||
employee.firstName?.toLowerCase().includes(searchTerm) ||
|
||||
employee.lastName?.toLowerCase().includes(searchTerm),
|
||||
);
|
||||
this.employees$ = of(filteredEmployees);
|
||||
this.isSearching = false;
|
||||
}, 150);
|
||||
});
|
||||
}
|
||||
|
||||
private fetchEmployees(): Observable<Employee[]> {
|
||||
@ -92,14 +101,17 @@ export class TableComponent implements OnInit {
|
||||
retry(TableComponent.MAX_RETRIES),
|
||||
catchError((error: HttpErrorResponse) => {
|
||||
console.error('Error fetching employees:', error);
|
||||
this.errorHandlerService.showErrorMessage('Failed to load employees. Please try again.');
|
||||
this.errorHandlerService.showErrorMessage(
|
||||
'Failed to load employees. Please try again.',
|
||||
);
|
||||
return of([]);
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
protected openDeleteDialogue(employee: Employee): void {
|
||||
this.matDialog.open(DeleteComponent, {data: employee})
|
||||
this.matDialog
|
||||
.open(DeleteComponent, { data: employee })
|
||||
.afterClosed()
|
||||
.subscribe((deleted: boolean) => {
|
||||
if (deleted) {
|
||||
@ -109,7 +121,8 @@ export class TableComponent implements OnInit {
|
||||
}
|
||||
|
||||
protected showCreateEmployeeModal() {
|
||||
this.matDialog.open(CreateComponent)
|
||||
this.matDialog
|
||||
.open(CreateComponent)
|
||||
.afterClosed()
|
||||
.subscribe((created: boolean) => {
|
||||
if (created) {
|
||||
@ -119,7 +132,8 @@ export class TableComponent implements OnInit {
|
||||
}
|
||||
|
||||
protected showEditEmployeeModal(employee: Employee) {
|
||||
this.matDialog.open(EditComponent, {data: employee})
|
||||
this.matDialog
|
||||
.open(EditComponent, { data: employee })
|
||||
.afterClosed()
|
||||
.subscribe((edited: boolean) => {
|
||||
if (edited) {
|
||||
@ -129,7 +143,7 @@ export class TableComponent implements OnInit {
|
||||
}
|
||||
|
||||
protected openDetailModal(employee: Employee) {
|
||||
this.matDialog.open(DetailsComponent, {data: employee});
|
||||
this.matDialog.open(DetailsComponent, { data: employee });
|
||||
}
|
||||
|
||||
protected filterEmployees(event: Event): void {
|
||||
|
Reference in New Issue
Block a user