Spaces:
Running
Running
// error-handler.service.ts (YENİ DOSYA) | |
// Path: /flare-ui/src/app/services/error-handler.service.ts | |
import { ErrorHandler, Injectable, Injector } from '@angular/core'; | |
import { MatSnackBar } from '@angular/material/snack-bar'; | |
import { Router } from '@angular/router'; | |
import { HttpErrorResponse } from '@angular/common/http'; | |
interface FlareError { | |
error: string; | |
message: string; | |
details?: any; | |
request_id?: string; | |
timestamp?: string; | |
user_action?: string; | |
} | |
({ | |
providedIn: 'root' | |
}) | |
export class GlobalErrorHandler implements ErrorHandler { | |
constructor(private injector: Injector) {} | |
handleError(error: Error | HttpErrorResponse): void { | |
// Get services lazily to avoid circular dependency | |
const snackBar = this.injector.get(MatSnackBar); | |
const router = this.injector.get(Router); | |
console.error('Global error caught:', error); | |
// Handle HTTP errors | |
if (error instanceof HttpErrorResponse) { | |
this.handleHttpError(error, snackBar, router); | |
} else { | |
// Handle client-side errors | |
this.handleClientError(error, snackBar); | |
} | |
} | |
private handleHttpError(error: HttpErrorResponse, snackBar: MatSnackBar, router: Router): void { | |
const flareError = error.error as FlareError; | |
// Race condition error (409) | |
if (error.status === 409 && flareError.error === 'RaceConditionError') { | |
const snackBarRef = snackBar.open( | |
flareError.message || 'The data was modified by another user. Please refresh and try again.', | |
'Refresh', | |
{ | |
duration: 0, | |
panelClass: ['error-snackbar', 'race-condition-snackbar'] | |
} | |
); | |
snackBarRef.onAction().subscribe(() => { | |
window.location.reload(); | |
}); | |
// Show additional info if available | |
if (flareError.details?.last_update_user) { | |
console.info(`Last updated by: ${flareError.details.last_update_user} at ${flareError.details.last_update_date}`); | |
} | |
return; | |
} | |
// Authentication error (401) | |
if (error.status === 401) { | |
snackBar.open( | |
'Your session has expired. Please login again.', | |
'Login', | |
{ | |
duration: 5000, | |
panelClass: ['error-snackbar'] | |
} | |
).onAction().subscribe(() => { | |
router.navigate(['/login']); | |
}); | |
return; | |
} | |
// Validation error (422) | |
if (error.status === 422 && flareError.details) { | |
const fieldErrors = flareError.details | |
.map((d: any) => `${d.field}: ${d.message}`) | |
.join('\n'); | |
snackBar.open( | |
flareError.message || 'Validation failed. Please check your input.', | |
'Close', | |
{ | |
duration: 8000, | |
panelClass: ['error-snackbar', 'validation-snackbar'] | |
} | |
); | |
console.error('Validation errors:', flareError.details); | |
return; | |
} | |
// Not found error (404) | |
if (error.status === 404) { | |
snackBar.open( | |
flareError.message || 'The requested resource was not found.', | |
'Close', | |
{ | |
duration: 5000, | |
panelClass: ['error-snackbar'] | |
} | |
); | |
return; | |
} | |
// Server errors (5xx) | |
if (error.status >= 500) { | |
const message = flareError.message || 'A server error occurred. Please try again later.'; | |
const requestId = flareError.request_id; | |
snackBar.open( | |
requestId ? `${message} (Request ID: ${requestId})` : message, | |
'Close', | |
{ | |
duration: 8000, | |
panelClass: ['error-snackbar', 'server-error-snackbar'] | |
} | |
); | |
return; | |
} | |
// Generic HTTP error | |
snackBar.open( | |
flareError.message || `HTTP Error ${error.status}: ${error.statusText}`, | |
'Close', | |
{ | |
duration: 6000, | |
panelClass: ['error-snackbar'] | |
} | |
); | |
} | |
private handleClientError(error: Error, snackBar: MatSnackBar): void { | |
// Check if it's a network error | |
if (error.message.includes('NetworkError') || error.message.includes('Failed to fetch')) { | |
snackBar.open( | |
'Network connection error. Please check your internet connection.', | |
'Retry', | |
{ | |
duration: 0, | |
panelClass: ['error-snackbar', 'network-error-snackbar'] | |
} | |
).onAction().subscribe(() => { | |
window.location.reload(); | |
}); | |
return; | |
} | |
// Generic client error | |
snackBar.open( | |
'An unexpected error occurred. Please refresh the page.', | |
'Refresh', | |
{ | |
duration: 6000, | |
panelClass: ['error-snackbar'] | |
} | |
).onAction().subscribe(() => { | |
window.location.reload(); | |
}); | |
} | |
} | |
// Error interceptor for consistent error format | |
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; | |
import { Observable, throwError } from 'rxjs'; | |
import { catchError } from 'rxjs/operators'; | |
() | |
export class ErrorInterceptor implements HttpInterceptor { | |
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { | |
return next.handle(req).pipe( | |
catchError((error: HttpErrorResponse) => { | |
// Log request details for debugging | |
console.error('HTTP Error:', { | |
url: req.url, | |
method: req.method, | |
status: error.status, | |
error: error.error, | |
requestId: error.headers.get('X-Request-ID') | |
}); | |
// Re-throw to be handled by global error handler | |
return throwError(() => error); | |
}) | |
); | |
} | |
} | |