diff --git a/bun.lockb b/bun.lockb
index 505d200..a60e455 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/package.json b/package.json
index 39047c9..788cc2a 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"keycloak-angular": "^16.1.0",
"rxjs": "~7.8.1",
"tailwind": "4.0.0",
+ "tailwindcss": "^3.4.17",
"tslib": "^2.8.1",
"zone.js": "~0.15.0"
},
@@ -31,12 +32,14 @@
"@angular/cli": "^19.0.5",
"@angular/compiler-cli": "^19.0.4",
"@types/jasmine": "~5.1.5",
+ "autoprefixer": "^10.4.20",
"jasmine-core": "~5.2.0",
"karma": "~6.4.4",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.1",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
+ "postcss": "^8.4.49",
"typescript": "~5.5.4"
}
}
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 6a164d6..e824d2e 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,2 +1,5 @@
+
+ {{ title }}
+
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index fdeeb79..db3e8f5 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -10,5 +10,5 @@ import {RouterOutlet} from '@angular/router';
styleUrl: './app.component.css'
})
export class AppComponent {
- title = 'lf10StarterNew';
+ title = 'Employee Management System';
}
diff --git a/src/app/employee-list/employee-list.component.css b/src/app/employee-list/employee-list.component.css
index e69de29..7563a61 100644
--- a/src/app/employee-list/employee-list.component.css
+++ b/src/app/employee-list/employee-list.component.css
@@ -0,0 +1,73 @@
+:host ::ng-deep {
+ .mat-mdc-card {
+ --mdc-elevated-card-container-color: transparent;
+ @apply !shadow-none !rounded-xl;
+ }
+
+ .mat-mdc-button-base {
+ --mat-mdc-button-persistent-ripple-color: currentColor;
+ @apply !rounded-lg;
+ }
+
+ .mat-mdc-progress-spinner {
+ --mdc-circular-progress-active-indicator-color: #2563eb;
+ }
+
+ .mdc-data-table__header-cell {
+ @apply !text-gray-600 !font-semibold !text-sm !py-4 !px-6;
+ }
+
+ .mat-mdc-table {
+ @apply !bg-transparent !border-separate !border-spacing-y-2;
+
+ .mat-mdc-row {
+ @apply !bg-white !rounded-xl !shadow-sm !transition-all !duration-200;
+
+ &:hover {
+ @apply !bg-gray-50 !shadow-md !transform !scale-[1.01];
+ }
+
+ .mat-mdc-cell {
+ @apply !border-b-0 !py-4 !px-6 first:!rounded-l-xl last:!rounded-r-xl;
+ }
+ }
+
+ .mat-mdc-header-row {
+ @apply !bg-transparent;
+
+ .mat-mdc-header-cell {
+ @apply !border-b-0;
+ }
+ }
+ }
+
+ .mat-mdc-menu-panel {
+ @apply !rounded-xl !shadow-lg;
+ }
+
+ .mat-mdc-menu-item {
+ @apply !rounded-lg !mx-1 !my-0.5;
+ }
+
+ .mdc-button {
+ @apply !font-medium;
+
+ &.mat-primary {
+ @apply !bg-blue-600 !text-white hover:!bg-blue-700;
+ }
+
+ &.mat-warn {
+ @apply !bg-red-600 !text-white hover:!bg-red-700;
+ }
+ }
+
+ .mat-mdc-snack-bar-container {
+ &.error-snackbar {
+ @apply !rounded-xl;
+
+ .mdc-snackbar__surface {
+ @apply !bg-red-50 !text-red-900 !border !border-red-100;
+ }
+ }
+ }
+}
diff --git a/src/app/employee-list/employee-list.component.html b/src/app/employee-list/employee-list.component.html
index 217b9d0..ff1fa54 100644
--- a/src/app/employee-list/employee-list.component.html
+++ b/src/app/employee-list/employee-list.component.html
@@ -1,9 +1,94 @@
-
LF10-Starter
-Wenn Sie in der EmployeeListComponent.ts ein gültiges Bearer-Token eintragen, sollten hier die Namen der in der Datenbank gespeicherten Mitarbeiter angezeigt werden!
-
- @for(e of employees$ | async; track e.id) {
-
- {{e.lastName }}, {{e.firstName}}
-
+
+ @defer {
+ @if (employees$ | async; as employees) {
+
+
+
Employee Directory
+
+ add
+ Add Employee
+
+
+
+ @if (employees) {
+
+
+
+ Name
+
+
+
+
+ {{employee.firstName[0]}}{{employee.lastName[0]}}
+
+
+
+
+ {{employee.lastName}}, {{employee.firstName}}
+
+
+
+
+
+
+
+ Actions
+
+
+ edit
+
+
+ delete
+
+
+
+
+
+
+
+
+ } @else {
+
+
+ people_outline
+ No employees found
+
+
+ }
+
+ }
+ } @placeholder {
+
+
+
+
+
+
+ @for(i of [1,2,3]; track i) {
+
+ }
+
+
+
+
+ } @error {
+
+
+
+
error_outline
+
+
Error loading employees
+
Please try refreshing the page.
+
+
+
+
+ } @loading (minimum 500ms) {
+
+
+
}
-
+
diff --git a/src/app/employee-list/employee-list.component.ts b/src/app/employee-list/employee-list.component.ts
index 8c167b8..fa346a2 100644
--- a/src/app/employee-list/employee-list.component.ts
+++ b/src/app/employee-list/employee-list.component.ts
@@ -1,25 +1,74 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
-import {Observable, of} from "rxjs";
-import {HttpClient, HttpHeaders} from "@angular/common/http";
-import {Employee} from "../Employee";
+import { Observable, catchError, of, retry } from 'rxjs';
+import { HttpClient, 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 { MatSnackBar, 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';
@Component({
selector: 'app-employee-list',
- imports: [CommonModule],
- templateUrl: './employee-list.component.html',
standalone: true,
+ imports: [
+ CommonModule,
+ MatCardModule,
+ MatButtonModule,
+ MatIconModule,
+ MatProgressSpinnerModule,
+ MatSnackBarModule,
+ MatDividerModule,
+ MatTooltipModule,
+ MatMenuModule,
+ MatTableModule,
+ MatSortModule
+ ],
+ templateUrl: './employee-list.component.html',
+ host: {
+ class: 'block w-full p-6'
+ },
styleUrl: './employee-list.component.css'
})
export class EmployeeListComponent {
- employees$: Observable;
+ private static readonly EMPLOYEES_ENDPOINT = 'http://localhost:8089/employees';
+ private static readonly MAX_RETRIES = 3;
+ public employees$: Observable;
+ public readonly displayedColumns: string[] = ['name', 'actions'];
- constructor(private http: HttpClient) {
- this.employees$ = of([]);
- this.fetchData();
+ constructor(
+ private readonly httpClient: HttpClient,
+ private readonly snackBar: MatSnackBar
+ ) {
+ this.employees$ = this.fetchEmployees();
}
- fetchData() {
- this.employees$ = this.http.get('http://localhost:8089/employees');
+ private fetchEmployees(): Observable {
+ return this.httpClient.get(
+ EmployeeListComponent.EMPLOYEES_ENDPOINT,
+ ).pipe(
+ retry(EmployeeListComponent.MAX_RETRIES),
+ catchError((error: HttpErrorResponse) => {
+ console.error('Error fetching employees:', error);
+ this.showErrorMessage('Failed to load employees. Please try again.');
+ return of([]);
+ })
+ );
+ }
+
+ private showErrorMessage(message: string): void {
+ this.snackBar.open(message, 'Close', {
+ duration: 5000,
+ horizontalPosition: 'end',
+ verticalPosition: 'bottom',
+ panelClass: ['!bg-red-50', '!text-red-900', '!border', '!border-red-100']
+ });
}
}
diff --git a/src/app/services/auth-guard.service.ts b/src/app/services/auth-guard.service.ts
index 2d65472..eded0c4 100644
--- a/src/app/services/auth-guard.service.ts
+++ b/src/app/services/auth-guard.service.ts
@@ -16,6 +16,7 @@ export class AuthGuardService {
return false;
}
+
return true;
}
}
diff --git a/src/app/services/auth.service.spec.ts b/src/app/services/auth.service.spec.ts
new file mode 100644
index 0000000..f1251ca
--- /dev/null
+++ b/src/app/services/auth.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { AuthService } from './auth.service';
+
+describe('AuthService', () => {
+ let service: AuthService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ service = TestBed.inject(AuthService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/src/styles.css b/src/styles.css
index 7e7239a..6df3509 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -1,4 +1,6 @@
-/* You can add global styles to this file, and also import other style files */
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..03231e9
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,11 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: [
+ './src/**/*.{html,ts,css,scss,sass,less,styl}',
+ ],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+}
+