Skip to content

Commit

Permalink
feat: show error notification when HTTP error response received
Browse files Browse the repository at this point in the history
  • Loading branch information
gultyayev committed May 5, 2021
1 parent 547a74a commit 75730d5
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 2 deletions.
16 changes: 14 additions & 2 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NgModule } from '@angular/core';
import { NgModule, Provider } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
Expand All @@ -11,11 +11,21 @@ import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { MatTooltipModule } from '@angular/material/tooltip';
import { ProductsModule } from './products/products.module';
import { HttpClientModule } from '@angular/common/http';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { MatBadgeModule } from '@angular/material/badge';
import { CartModule } from './cart/cart.module';
import { CONFIG_TOKEN } from './core/injection-tokens/config.token';
import { environment } from '../environments/environment';
import { ErrorPrintInterceptor } from './core/interceptors/error-print.interceptor';
import { MatSnackBarModule } from '@angular/material/snack-bar';

const interceptors: Provider[] = [
{
provide: HTTP_INTERCEPTORS,
useClass: ErrorPrintInterceptor,
multi: true,
},
];

@NgModule({
declarations: [AppComponent, HeaderComponent],
Expand All @@ -32,8 +42,10 @@ import { environment } from '../environments/environment';
CartModule,
HttpClientModule,
MatBadgeModule,
MatSnackBarModule,
],
providers: [
interceptors,
{
provide: CONFIG_TOKEN,
useValue: environment,
Expand Down
19 changes: 19 additions & 0 deletions src/app/core/interceptors/error-print.interceptor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { TestBed } from '@angular/core/testing';

import { ErrorPrintInterceptor } from './error-print.interceptor';

describe('ErrorPrintInterceptor', () => {
beforeEach(() =>
TestBed.configureTestingModule({
providers: [ErrorPrintInterceptor],
})
);

it('should be created', () => {
const interceptor: ErrorPrintInterceptor = TestBed.inject(
ErrorPrintInterceptor
);

expect(interceptor).toBeTruthy();
});
});
33 changes: 33 additions & 0 deletions src/app/core/interceptors/error-print.interceptor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Injectable } from '@angular/core';
import {
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpRequest,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { NotificationService } from '../notification.service';
import { tap } from 'rxjs/operators';

@Injectable()
export class ErrorPrintInterceptor implements HttpInterceptor {
constructor(private readonly notificationService: NotificationService) {}

intercept(
request: HttpRequest<unknown>,
next: HttpHandler
): Observable<HttpEvent<unknown>> {
return next.handle(request).pipe(
tap({
error: () => {
const url = new URL(request.url);

this.notificationService.showError(
`Request to "${url.pathname}" failed. Check the console for the details`,
0
);
},
})
);
}
}
16 changes: 16 additions & 0 deletions src/app/core/notification.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { NotificationService } from './notification.service';

describe('NotificationService', () => {
let service: NotificationService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(NotificationService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});
22 changes: 22 additions & 0 deletions src/app/core/notification.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';

@Injectable({
providedIn: 'root',
})
export class NotificationService {
constructor(private readonly snackBar: MatSnackBar) {}

/**
* Show message with an error
*
* @param text Error text message
* @param duration Duration to close after. 0 to close manually only
*/
showError(text: string, duration = 3000) {
this.snackBar.open(text, 'Dismiss', {
duration,
panelClass: 'shop-snackbar-error',
});
}
}
11 changes: 11 additions & 0 deletions src/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,14 @@ body {
// Fix vertical alignment for Firefox
line-height: 1 !important;
}

// snackbar styles
.shop-snackbar-error {
background-color: #ff0015;
color: white;

button {
color: white;
border: 1px solid;
}
}

0 comments on commit 75730d5

Please sign in to comment.