feat: set up HttpErrorInterceptor for error handling and integrated ErrorNotificationService; created and implemented ToastNotificationService for user notifications
This commit is contained in:
parent
13a087cfb0
commit
839df9e3ff
9 changed files with 122 additions and 31 deletions
|
|
@ -17,6 +17,8 @@ import { firebaseConfig } from './environments/config';
|
|||
import * as Sentry from '@sentry/angular';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { HttpErrorInterceptor } from './interceptors/http-interceptor';
|
||||
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
|
||||
export function createTranslateLoader(http: HttpClient) {
|
||||
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
|
||||
|
|
@ -61,5 +63,10 @@ export const appConfig: ApplicationConfig = {
|
|||
deps: [Sentry.TraceService],
|
||||
multi: true,
|
||||
},
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: HttpErrorInterceptor,
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { firstValueFrom, map } from 'rxjs';
|
|||
import { TaskService } from '../../services/task.service';
|
||||
import { ApiService } from '../../services/api.service';
|
||||
import { TaskUpdateService } from '../../services/task-update.service';
|
||||
import { ToastNotificationService } from '../../services/toast-notification.servic';
|
||||
|
||||
@Component({
|
||||
selector: 'app-add-task',
|
||||
|
|
@ -53,6 +54,7 @@ export class AddTaskComponent implements OnInit {
|
|||
private apiService: ApiService,
|
||||
private authService: AuthService,
|
||||
private taskUpdateService: TaskUpdateService,
|
||||
private toastNotificationService: ToastNotificationService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router
|
||||
) {}
|
||||
|
|
@ -379,6 +381,7 @@ export class AddTaskComponent implements OnInit {
|
|||
|
||||
this.apiService.saveNewTask(taskWithoutId).subscribe({
|
||||
next: (response) => {
|
||||
this.toastNotificationService.createTaskSuccessToast();
|
||||
this.taskUpdateService.notifyTaskUpdate();
|
||||
this.removeTaskData(ngForm);
|
||||
this.closeOverlay();
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { TaskService } from '../../services/task.service';
|
|||
import { LoadingSpinnerComponent } from '../../shared/components/loading-spinner/loading-spinner.component';
|
||||
import { finalize, Subject, takeUntil } from 'rxjs';
|
||||
import { TaskUpdateService } from '../../services/task-update.service';
|
||||
import { ToastNotificationService } from '../../services/toast-notification.servic';
|
||||
|
||||
@Component({
|
||||
selector: 'app-board',
|
||||
|
|
@ -46,6 +47,7 @@ export class BoardComponent {
|
|||
private taskService: TaskService,
|
||||
private apiService: ApiService,
|
||||
private taskUpdateService: TaskUpdateService,
|
||||
private toastNotificationService: ToastNotificationService,
|
||||
private router: Router
|
||||
) {}
|
||||
|
||||
|
|
@ -140,6 +142,7 @@ export class BoardComponent {
|
|||
handleItemDropped(taskId: string, status: string): void {
|
||||
this.apiService.updateTaskStatus(taskId, status).subscribe({
|
||||
next: () => {
|
||||
this.toastNotificationService.taskStatusUpdatedToast();
|
||||
this.updateTaskStatus(taskId, status);
|
||||
},
|
||||
error: (error) => console.error('Error updating task:', error),
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import { TranslateModule } from '@ngx-translate/core';
|
|||
import { LoadingDialogComponent } from './loading-dialog/loading-dialog.component';
|
||||
import { OverlayService } from '../../services/overlay.service';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { ErrorHandlingService } from '../../services/error-handling.service';
|
||||
import { TokenService } from '../../services/token.service';
|
||||
|
||||
@Component({
|
||||
|
|
|
|||
28
src/app/interceptors/http-interceptor.ts
Normal file
28
src/app/interceptors/http-interceptor.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
HttpEvent,
|
||||
HttpInterceptor,
|
||||
HttpHandler,
|
||||
HttpRequest,
|
||||
HttpErrorResponse,
|
||||
} from '@angular/common/http';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
import { ErrorNotificationService } from '../services/error-notification.service';
|
||||
|
||||
@Injectable()
|
||||
export class HttpErrorInterceptor implements HttpInterceptor {
|
||||
constructor(private errorNotificationService: ErrorNotificationService) {}
|
||||
|
||||
intercept(
|
||||
req: HttpRequest<any>,
|
||||
next: HttpHandler
|
||||
): Observable<HttpEvent<any>> {
|
||||
return next.handle(req).pipe(
|
||||
catchError((error: HttpErrorResponse) => {
|
||||
this.errorNotificationService.handleHttpError(error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,8 +9,8 @@ import {
|
|||
} from 'rxjs';
|
||||
import { ApiService } from './api.service';
|
||||
import { TokenService } from './token.service';
|
||||
import { ErrorHandlingService } from './error-handling.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { ToastNotificationService } from './toast-notification.servic';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
|
|
@ -21,7 +21,7 @@ export class AuthService {
|
|||
constructor(
|
||||
private apiService: ApiService,
|
||||
private tokenService: TokenService,
|
||||
private errorHandlingService: ErrorHandlingService,
|
||||
private toastNotificationService: ToastNotificationService,
|
||||
private router: Router
|
||||
) {
|
||||
this.currentUserIdSubject.next(this.tokenService.getUserId());
|
||||
|
|
@ -40,10 +40,9 @@ export class AuthService {
|
|||
this.tokenService.storeAuthToken(token, storage);
|
||||
this.tokenService.storeUserId(userId, storage);
|
||||
this.currentUserIdSubject.next(userId);
|
||||
this.errorHandlingService.loginSuccessToast();
|
||||
this.toastNotificationService.loginSuccessToast();
|
||||
} catch (error) {
|
||||
console.error('Login failed:', error);
|
||||
this.errorHandlingService.handleHttpError(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,11 +53,10 @@ export class AuthService {
|
|||
this.tokenService.deleteAuthToken();
|
||||
this.tokenService.deleteUserId();
|
||||
this.currentUserIdSubject.next(null);
|
||||
this.errorHandlingService.logoutSuccessToast();
|
||||
this.toastNotificationService.logoutSuccessToast();
|
||||
this.router.navigate(['/logout']);
|
||||
} catch (error) {
|
||||
console.error('Logout failed:', error);
|
||||
this.errorHandlingService.handleHttpError(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { ToastrService } from 'ngx-toastr';
|
|||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ErrorHandlingService {
|
||||
export class ErrorNotificationService {
|
||||
constructor(private toastr: ToastrService) {}
|
||||
|
||||
handleHttpError(error: unknown): void {
|
||||
|
|
@ -28,36 +28,23 @@ export class ErrorHandlingService {
|
|||
errorMessage = 'The requested resource was not found.';
|
||||
break;
|
||||
case 500:
|
||||
errorMessage = 'Server error: Please try again later.';
|
||||
errorMessage =
|
||||
'Server error: Please try again later. If the issue persists, please contact support.';
|
||||
break;
|
||||
case 408:
|
||||
errorMessage =
|
||||
'Request timed out. Please check your connection and try again.';
|
||||
break;
|
||||
default:
|
||||
errorMessage = `Unknown error: ${error.statusText || error.message}`;
|
||||
errorMessage =
|
||||
error.error?.message ||
|
||||
`Unknown error: ${error.statusText || error.message}`;
|
||||
break;
|
||||
}
|
||||
} else if (error instanceof Error) {
|
||||
errorMessage = `${error.message || error.toString()}`;
|
||||
errorMessage = `Network error: ${error.message || error.toString()}`;
|
||||
}
|
||||
|
||||
this.toastr.error(errorMessage, 'Error');
|
||||
}
|
||||
|
||||
loginSuccessToast(): void {
|
||||
this.toastr.success(
|
||||
'You have successfully logged in.',
|
||||
'Login Successful',
|
||||
{
|
||||
timeOut: 3000,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
logoutSuccessToast(): void {
|
||||
this.toastr.info(
|
||||
'You have successfully logged out. Have a nice day!',
|
||||
'Logout Successful',
|
||||
{
|
||||
timeOut: 3000,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
63
src/app/services/toast-notification.servic.ts
Executable file
63
src/app/services/toast-notification.servic.ts
Executable file
|
|
@ -0,0 +1,63 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ToastNotificationService {
|
||||
constructor(private toastr: ToastrService) {}
|
||||
|
||||
// Auth
|
||||
loginSuccessToast(): void {
|
||||
this.createSuccessToast(
|
||||
'You have successfully logged in.',
|
||||
'Login Successful'
|
||||
);
|
||||
}
|
||||
|
||||
logoutSuccessToast(): void {
|
||||
this.createInfoToast(
|
||||
'You have successfully logged out. Have a nice day!',
|
||||
'Logout Successful'
|
||||
);
|
||||
}
|
||||
|
||||
// Tasks
|
||||
createTaskSuccessToast(): void {
|
||||
this.createSuccessToast('Task created successfully!', 'Task Created');
|
||||
}
|
||||
|
||||
deleteTaskSuccessToast(): void {
|
||||
this.createSuccessToast('Task deleted successfully!', 'Task Deleted');
|
||||
}
|
||||
|
||||
taskStatusUpdatedToast(): void {
|
||||
this.createInfoToast('Task successfully moved!', 'Task Moved');
|
||||
}
|
||||
|
||||
// Helperfunctions
|
||||
|
||||
createSuccessToast(message: string, title: string = 'Success'): void {
|
||||
this.toastr.success(message, title, {
|
||||
timeOut: 3000,
|
||||
positionClass: 'toast-top-right',
|
||||
progressBar: true,
|
||||
});
|
||||
}
|
||||
|
||||
createErrorToast(message: string, title: string = 'Error'): void {
|
||||
this.toastr.error(message, title, {
|
||||
timeOut: 3000,
|
||||
positionClass: 'toast-top-right',
|
||||
progressBar: true,
|
||||
});
|
||||
}
|
||||
|
||||
createInfoToast(message: string, title: string = 'Info'): void {
|
||||
this.toastr.info(message, title, {
|
||||
timeOut: 3000,
|
||||
positionClass: 'toast-top-right',
|
||||
progressBar: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ import { AuthService } from '../../../../services/auth.service';
|
|||
import { map } from 'rxjs';
|
||||
import { ApiService } from '../../../../services/api.service';
|
||||
import { TaskUpdateService } from '../../../../services/task-update.service';
|
||||
import { ToastNotificationService } from '../../../../services/toast-notification.servic';
|
||||
|
||||
@Component({
|
||||
selector: 'app-task-overlay',
|
||||
|
|
@ -35,6 +36,7 @@ export class TaskOverlayComponent implements OnInit {
|
|||
private authService: AuthService,
|
||||
private apiService: ApiService,
|
||||
private taskUpdateService: TaskUpdateService,
|
||||
private toastNotificationService: ToastNotificationService,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute
|
||||
) {}
|
||||
|
|
@ -123,6 +125,7 @@ export class TaskOverlayComponent implements OnInit {
|
|||
deleteTask(taskId: string) {
|
||||
this.apiService.deleteTaskById(taskId).subscribe({
|
||||
next: (task) => {
|
||||
this.toastNotificationService.deleteTaskSuccessToast();
|
||||
this.taskUpdateService.notifyTaskUpdate();
|
||||
},
|
||||
error: (err) => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue