diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts index d9bb9a1..0805e5e 100644 --- a/client/src/app/app-routing.module.ts +++ b/client/src/app/app-routing.module.ts @@ -4,16 +4,14 @@ import { NotFoundComponent } from './core/not-found/not-found.component'; import { ServerErrorComponent } from './core/server-error/server-error.component'; import { TestErrorComponent } from './core/test-error/test-error.component'; import { HomeComponent } from './home/home.component'; -import { ProductDetailsComponent } from './shop/product-details/product-details.component'; -import { ShopComponent } from './shop/shop.component'; const routes: Routes = [ - {path: '', component: HomeComponent}, - {path: 'test-error', component: TestErrorComponent}, - {path: 'server-error', component: ServerErrorComponent}, - {path: 'not-found', component: NotFoundComponent}, - {path: 'shop', loadChildren: ()=> import('./shop/shop.module').then(mod => mod.ShopModule)}, - {path: '**', redirectTo: '', pathMatch: 'full'} + {path: '', component: HomeComponent, data: {breadcrumb: 'Home'}}, + {path: 'test-error', component: TestErrorComponent, data: {breadcrumb: 'Test Errors'}}, + {path: 'server-error', component: ServerErrorComponent, data: {breadcrumb: 'Server Error'}}, + {path: 'not-found', component: NotFoundComponent, data: {breadcrumb: 'Not Found'}}, + {path: 'shop', loadChildren: ()=> import('./shop/shop.module').then(mod => mod.ShopModule), data: {breadcrumb: 'Shop'}}, + {path: '**', redirectTo: 'not-found', pathMatch: 'full'} ]; diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index c8a3fba..0581529 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html @@ -1,4 +1,5 @@ -
+ +
diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts index 4abdf78..cd64fa7 100644 --- a/client/src/app/core/core.module.ts +++ b/client/src/app/core/core.module.ts @@ -6,19 +6,25 @@ import { TestErrorComponent } from './test-error/test-error.component'; import { NotFoundComponent } from './not-found/not-found.component'; import { ServerErrorComponent } from './server-error/server-error.component'; import { ToastrModule } from 'ngx-toastr'; +import { SectionHeaderComponent } from './section-header/section-header.component'; +import { BreadcrumbModule } from 'xng-breadcrumb'; @NgModule({ - declarations: [NavBarComponent, TestErrorComponent, NotFoundComponent, ServerErrorComponent], + declarations: [NavBarComponent, TestErrorComponent, NotFoundComponent, ServerErrorComponent, SectionHeaderComponent], imports: [ CommonModule, RouterModule, + BreadcrumbModule, ToastrModule.forRoot({ positionClass: 'toast-bottom-right', preventDuplicates: true }) ], - exports: [NavBarComponent] + exports: [ + NavBarComponent, + SectionHeaderComponent + ] }) export class CoreModule { } diff --git a/client/src/app/core/interceptors/error.interceptor.ts b/client/src/app/core/interceptors/error.interceptor.ts index 391bf45..2ec41e4 100644 --- a/client/src/app/core/interceptors/error.interceptor.ts +++ b/client/src/app/core/interceptors/error.interceptor.ts @@ -6,7 +6,7 @@ import { HttpInterceptor } from '@angular/common/http'; import { catchError, Observable, throwError } from 'rxjs'; -import { Router } from '@angular/router'; +import { NavigationExtras, Router } from '@angular/router'; import { ToastrService } from 'ngx-toastr'; @Injectable() @@ -20,7 +20,12 @@ export class ErrorInterceptor implements HttpInterceptor { if (error){ if (error.status === 400){ - this.toastr.error(error.error.message, error.error.statusCode); + if (error.error.errors){ + //log('error thrown ' + error.error); + throw error.error; + } else { + this.toastr.error(error.error.message, error.error.statusCode); + } } if (error.status === 401){ @@ -32,7 +37,8 @@ export class ErrorInterceptor implements HttpInterceptor { } if (error.status === 500){ - this.router.navigateByUrl('/server-error'); + const navigationExtras: NavigationExtras = {state: {error: error.error}}; + this.router.navigateByUrl('/server-error', navigationExtras); } } return throwError(() => new Error(error)); diff --git a/client/src/app/core/section-header/section-header.component.html b/client/src/app/core/section-header/section-header.component.html new file mode 100644 index 0000000..e1ca757 --- /dev/null +++ b/client/src/app/core/section-header/section-header.component.html @@ -0,0 +1,14 @@ + +
+
+
+
+

{{breadcrumbs.length > 0 && breadcrumbs[breadcrumbs.length-1].label | titlecase}}

+
+
+ +
+
+
+
+
diff --git a/client/src/app/core/section-header/section-header.component.scss b/client/src/app/core/section-header/section-header.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/client/src/app/core/section-header/section-header.component.ts b/client/src/app/core/section-header/section-header.component.ts new file mode 100644 index 0000000..7c769d0 --- /dev/null +++ b/client/src/app/core/section-header/section-header.component.ts @@ -0,0 +1,19 @@ +import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { BreadcrumbService } from 'xng-breadcrumb'; + +@Component({ + selector: 'app-section-header', + templateUrl: './section-header.component.html', + styleUrls: ['./section-header.component.scss'] +}) +export class SectionHeaderComponent implements OnInit { + breadcrumb$: Observable; + + constructor(private bcService: BreadcrumbService) { } + + ngOnInit(): void { + this.breadcrumb$ = this.bcService.breadcrumbs$; + } + +} diff --git a/client/src/app/core/server-error/server-error.component.html b/client/src/app/core/server-error/server-error.component.html index 95017c1..d301fcb 100644 --- a/client/src/app/core/server-error/server-error.component.html +++ b/client/src/app/core/server-error/server-error.component.html @@ -1,3 +1,17 @@
-

Internal Server Error

+

Server Internal Error - Refreshing the page clears the exception

+ +
{{e.message}}
+

Note: if you are seeing this, this is not a client side error.

+

What's next?

+
    +
  1. Open Chrom Dev Tools
  2. +
  3. Inspect the Network Tab
  4. +
  5. Check the failing request
  6. +
  7. Examin the request URL. Is it correct?
  8. +
  9. Reproduce Error in Postman
  10. +
+

Following is the stack trace - This is where your investigation begins.

+ {{e.details}} +
diff --git a/client/src/app/core/server-error/server-error.component.ts b/client/src/app/core/server-error/server-error.component.ts index bc3f70f..d643d5f 100644 --- a/client/src/app/core/server-error/server-error.component.ts +++ b/client/src/app/core/server-error/server-error.component.ts @@ -1,4 +1,5 @@ import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; @Component({ selector: 'app-server-error', @@ -6,8 +7,12 @@ import { Component, OnInit } from '@angular/core'; styleUrls: ['./server-error.component.scss'] }) export class ServerErrorComponent implements OnInit { + e: any; - constructor() { } + constructor(private router: Router) { + const navigation = this.router.getCurrentNavigation(); + this.e = navigation?.extras?.state?.error; + } ngOnInit(): void { } diff --git a/client/src/app/core/test-error/test-error.component.html b/client/src/app/core/test-error/test-error.component.html index 0a413af..be6b557 100644 --- a/client/src/app/core/test-error/test-error.component.html +++ b/client/src/app/core/test-error/test-error.component.html @@ -3,4 +3,9 @@ +
+
    +
  • {{error}}
  • +
+
diff --git a/client/src/app/core/test-error/test-error.component.ts b/client/src/app/core/test-error/test-error.component.ts index 64a9955..8ca4ce8 100644 --- a/client/src/app/core/test-error/test-error.component.ts +++ b/client/src/app/core/test-error/test-error.component.ts @@ -9,6 +9,7 @@ import { environment } from 'src/environments/environment'; }) export class TestErrorComponent implements OnInit { baseURL = environment.apiUrl; + validationErrors: any; constructor(private http: HttpClient) { } @@ -49,7 +50,9 @@ export class TestErrorComponent implements OnInit { this.http.get(this.baseURL + 'products/five').subscribe( { next: (response) => { console.log(response); }, - error: (e: any) => { console.log(e); }, + error: (e: any) => { + //console.log(e.errors); + this.validationErrors = e.errors; }, complete: () => { console.log('complete'); } } ); diff --git a/client/src/app/shop/product-details/product-details.component.ts b/client/src/app/shop/product-details/product-details.component.ts index 05289ae..ddfa847 100644 --- a/client/src/app/shop/product-details/product-details.component.ts +++ b/client/src/app/shop/product-details/product-details.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { IProduct } from 'src/app/shared/models/product'; +import { BreadcrumbService } from 'xng-breadcrumb'; import { ShopService } from '../shop.service'; @Component({ @@ -11,7 +12,7 @@ import { ShopService } from '../shop.service'; export class ProductDetailsComponent implements OnInit { product: IProduct; - constructor(private shopService: ShopService, private activatedRoute: ActivatedRoute) { } + constructor(private shopService: ShopService, private activatedRoute: ActivatedRoute, private bcService: BreadcrumbService) { } ngOnInit(): void { this.loadProduct(); @@ -20,7 +21,10 @@ export class ProductDetailsComponent implements OnInit { loadProduct(){ this.shopService.getProduct(+this.activatedRoute.snapshot.paramMap.get('id')).subscribe( { - next: (product) => { this.product = product; }, + next: (product) => { + this.product = product; + this.bcService.set('@productDetails', product.name) + }, error: (e: any) => { console.log(e); }, complete: () => { console.log('complete'); } } diff --git a/client/src/app/shop/product-item/product-item.component.html b/client/src/app/shop/product-item/product-item.component.html index b1391b3..bf05c27 100644 --- a/client/src/app/shop/product-item/product-item.component.html +++ b/client/src/app/shop/product-item/product-item.component.html @@ -1,13 +1,13 @@
{{product.name}} +
+ + +
{{product.name}}
{{product.price | currency}} -
- - -
diff --git a/client/src/app/shop/product-item/product-item.component.scss b/client/src/app/shop/product-item/product-item.component.scss index e69de29..6839850 100644 --- a/client/src/app/shop/product-item/product-item.component.scss +++ b/client/src/app/shop/product-item/product-item.component.scss @@ -0,0 +1,4 @@ +.btn { + width: 30%; + height: 40px; +} diff --git a/client/src/app/shop/shop-routing.module.ts b/client/src/app/shop/shop-routing.module.ts index adb709a..f527c3b 100644 --- a/client/src/app/shop/shop-routing.module.ts +++ b/client/src/app/shop/shop-routing.module.ts @@ -1,12 +1,11 @@ import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; import { RouterModule, Routes } from '@angular/router'; import { ShopComponent } from './shop.component'; import { ProductDetailsComponent } from './product-details/product-details.component'; const routes: Routes = [ {path: '', component: ShopComponent}, - {path: ':id', component: ProductDetailsComponent}, + {path: ':id', component: ProductDetailsComponent, data: {breadcrumb: {alias: 'productDetails'}}}, ] @NgModule({ diff --git a/client/src/app/shop/shop.component.html b/client/src/app/shop/shop.component.html index 0975315..827ff71 100644 --- a/client/src/app/shop/shop.component.html +++ b/client/src/app/shop/shop.component.html @@ -1,5 +1,5 @@
-
+
Sort