Add error handling and snackbar notifications
Introduces error state management in LoadingService, displays error bar and snackbar notifications in the UI, and updates ScheduleComponent to use the new error handling. Also adds custom theming for error snackbar and progress bar.
This commit is contained in:
@@ -10,7 +10,8 @@ import { App } from './app';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
|
||||
import { HeaderComponent } from './header/header.component';
|
||||
@@ -60,7 +61,8 @@ import { Header2Component } from './header-2/header-2.component';
|
||||
MatIconModule,
|
||||
MatTabsModule,
|
||||
MatToolbarModule,
|
||||
MatProgressBarModule
|
||||
MatProgressBarModule,
|
||||
MatSnackBarModule
|
||||
],
|
||||
providers: [
|
||||
provideBrowserGlobalErrorListeners(),
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (loading$ | async) {
|
||||
@if (loadingService.error$ | async) {
|
||||
<div class="h-1 w-full" style="background-color: red;"></div>
|
||||
} @else if (loadingService.loading$ | async){
|
||||
<mat-progress-bar
|
||||
mode="indeterminate"
|
||||
class="h-1 w-full"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { LoadingService } from '../loading.service';
|
||||
|
||||
@Component({
|
||||
@@ -8,8 +8,5 @@ import { LoadingService } from '../loading.service';
|
||||
styleUrl: './header-2.component.css'
|
||||
})
|
||||
export class Header2Component {
|
||||
loading$;
|
||||
constructor(private loadingService: LoadingService) {
|
||||
this.loading$ = this.loadingService.loading$;
|
||||
}
|
||||
protected loadingService = inject(LoadingService)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,80 @@
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class LoadingService {
|
||||
private _loading = new BehaviorSubject<boolean>(false);
|
||||
readonly loading$ = this._loading.asObservable();
|
||||
private loadingSubject = new BehaviorSubject<boolean>(false);
|
||||
private errorSubject = new BehaviorSubject<boolean>(false);
|
||||
|
||||
show() {
|
||||
this._loading.next(true);
|
||||
public loading$ = this.loadingSubject.asObservable();
|
||||
public error$ = this.errorSubject.asObservable();
|
||||
|
||||
constructor(private snackBar: MatSnackBar) {}
|
||||
|
||||
show(): void {
|
||||
this.loadingSubject.next(true);
|
||||
this.errorSubject.next(false);
|
||||
}
|
||||
|
||||
hide() {
|
||||
this._loading.next(false);
|
||||
hide(): void {
|
||||
this.loadingSubject.next(false);
|
||||
this.errorSubject.next(false);
|
||||
}
|
||||
|
||||
showError(messageOrError?: string | HttpErrorResponse | any): void {
|
||||
this.loadingSubject.next(false);
|
||||
this.errorSubject.next(true);
|
||||
|
||||
if (!messageOrError) {
|
||||
return;
|
||||
}
|
||||
|
||||
const message = this.getErrorMessage(messageOrError);
|
||||
|
||||
const snackBarRef = this.snackBar.open(message, 'Schließen', {
|
||||
duration: 0,
|
||||
panelClass: ['error-snackbar'],
|
||||
horizontalPosition: 'center',
|
||||
verticalPosition: 'bottom'
|
||||
});
|
||||
|
||||
snackBarRef.afterDismissed().subscribe(() => {
|
||||
this.hide();
|
||||
});
|
||||
}
|
||||
|
||||
private getErrorMessage(error?: string | HttpErrorResponse | any): string {
|
||||
|
||||
if (typeof error === 'string') {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (error instanceof HttpErrorResponse) {
|
||||
|
||||
if (error.status === 0) {
|
||||
return 'Netzwerkfehler: Keine Verbindung zum Server möglich!';
|
||||
}
|
||||
|
||||
if (error.status >= 500) {
|
||||
return `Serverfehler (${error.status}): ${error.statusText || 'Interner Serverfehler'}`;
|
||||
}
|
||||
|
||||
if (error.status >= 400) {
|
||||
const errorMessage = error.error?.message || error.error?.error || error.statusText;
|
||||
return `Fehler (${error.status}): ${errorMessage}`;
|
||||
}
|
||||
|
||||
return `HTTP Fehler (${error.status}): ${error.statusText}`;
|
||||
}
|
||||
|
||||
if (error.message) {
|
||||
return error.message;
|
||||
}
|
||||
|
||||
return 'Ein unbekannter Fehler ist aufgetreten!';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Vorstellung } from '@infinimotion/model-frontend';
|
||||
import { Performance } from '../model/performance.model';
|
||||
import { MovieGroup } from '../model/movie-group.model';
|
||||
import { LoadingService } from '../loading.service';
|
||||
import { catchError, map, of, tap } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-schedule',
|
||||
@@ -47,14 +48,19 @@ export class ScheduleComponent implements OnInit {
|
||||
|
||||
loadPerformances() {
|
||||
this.loading.show();
|
||||
this.http.getPerformaces().subscribe({
|
||||
next: (data) => {
|
||||
this.performaces = Array.isArray(data) ? data : [data];
|
||||
this.http.getPerformaces().pipe(
|
||||
map(data => Array.isArray(data) ? data : [data]),
|
||||
tap(performaces => {
|
||||
this.performaces = performaces;
|
||||
this.assignPerformancesToDates();
|
||||
},
|
||||
error: (err) => console.error('Fehler beim Laden der Performances', err),
|
||||
complete: () => this.loading.hide()
|
||||
});
|
||||
this.loading.hide();
|
||||
}),
|
||||
catchError(err => {
|
||||
this.loading.showError(err);
|
||||
console.error('Fehler beim Laden der Vorstellung', err);
|
||||
return of([]);
|
||||
})
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
assignPerformancesToDates() {
|
||||
|
||||
Reference in New Issue
Block a user