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'; @Component({ selector: 'app-employee-list', standalone: true, imports: [ CommonModule, MatCardModule, MatButtonModule, MatIconModule, MatProgressSpinnerModule, MatSnackBarModule, MatDividerModule, MatTooltipModule, MatMenuModule, MatTableModule, MatSortModule, MatFormFieldModule, MatInputModule, ], templateUrl: './table.component.html', 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 static readonly MAX_RETRIES = 3; private allEmployees: Employee[] = []; private searchSubject = new Subject(); public employees$: Observable = of([]); public isSearching = false; public readonly displayedColumns: string[] = ['name', 'actions']; public ngOnInit(): void { this.loadEmployees(); this.setupSearch(); } private loadEmployees(): void { 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); }); } private fetchEmployees(): Observable { return this.apiService.getAll().pipe( retry(TableComponent.MAX_RETRIES), catchError((error: HttpErrorResponse) => { console.error('Error fetching employees:', error); this.errorHandlerService.showErrorMessage( 'Failed to load employees. Please try again.', ); return of([]); }), ); } protected openDeleteDialogue(employee: Employee): void { this.matDialog .open(DeleteComponent, { data: employee }) .afterClosed() .subscribe((deleted: boolean) => { if (deleted) { this.employees$ = this.fetchEmployees(); } }); } protected showCreateEmployeeModal() { this.matDialog .open(CreateComponent) .afterClosed() .subscribe((created: boolean) => { if (created) { this.employees$ = this.fetchEmployees(); } }); } protected showEditEmployeeModal(employee: Employee) { this.matDialog .open(EditComponent, { data: employee }) .afterClosed() .subscribe((edited: boolean) => { if (edited) { this.employees$ = this.fetchEmployees(); } }); } protected openDetailModal(employee: Employee) { this.matDialog.open(DetailsComponent, { data: employee }); } protected filterEmployees(event: Event): void { const searchTerm = (event.target as HTMLInputElement).value.toLowerCase(); this.searchSubject.next(searchTerm); } }