Merge branch 'master' of https://labs.xtechnology.org/cshowalter/E-Commerce
This commit is contained in:
commit
3f0a50d2bd
@ -4,16 +4,14 @@ import { NotFoundComponent } from './core/not-found/not-found.component';
|
|||||||
import { ServerErrorComponent } from './core/server-error/server-error.component';
|
import { ServerErrorComponent } from './core/server-error/server-error.component';
|
||||||
import { TestErrorComponent } from './core/test-error/test-error.component';
|
import { TestErrorComponent } from './core/test-error/test-error.component';
|
||||||
import { HomeComponent } from './home/home.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 = [
|
const routes: Routes = [
|
||||||
{path: '', component: HomeComponent},
|
{path: '', component: HomeComponent, data: {breadcrumb: 'Home'}},
|
||||||
{path: 'test-error', component: TestErrorComponent},
|
{path: 'test-error', component: TestErrorComponent, data: {breadcrumb: 'Test Errors'}},
|
||||||
{path: 'server-error', component: ServerErrorComponent},
|
{path: 'server-error', component: ServerErrorComponent, data: {breadcrumb: 'Server Error'}},
|
||||||
{path: 'not-found', component: NotFoundComponent},
|
{path: 'not-found', component: NotFoundComponent, data: {breadcrumb: 'Not Found'}},
|
||||||
{path: 'shop', loadChildren: ()=> import('./shop/shop.module').then(mod => mod.ShopModule)},
|
{path: 'shop', loadChildren: ()=> import('./shop/shop.module').then(mod => mod.ShopModule), data: {breadcrumb: 'Shop'}},
|
||||||
{path: '**', redirectTo: '', pathMatch: 'full'}
|
{path: '**', redirectTo: 'not-found', pathMatch: 'full'}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<app-nav-bar></app-nav-bar>
|
<app-nav-bar></app-nav-bar>
|
||||||
<div class="container" style="margin-top: 140px;">
|
<app-section-header></app-section-header>
|
||||||
|
<div class="container">
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,19 +6,25 @@ import { TestErrorComponent } from './test-error/test-error.component';
|
|||||||
import { NotFoundComponent } from './not-found/not-found.component';
|
import { NotFoundComponent } from './not-found/not-found.component';
|
||||||
import { ServerErrorComponent } from './server-error/server-error.component';
|
import { ServerErrorComponent } from './server-error/server-error.component';
|
||||||
import { ToastrModule } from 'ngx-toastr';
|
import { ToastrModule } from 'ngx-toastr';
|
||||||
|
import { SectionHeaderComponent } from './section-header/section-header.component';
|
||||||
|
import { BreadcrumbModule } from 'xng-breadcrumb';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [NavBarComponent, TestErrorComponent, NotFoundComponent, ServerErrorComponent],
|
declarations: [NavBarComponent, TestErrorComponent, NotFoundComponent, ServerErrorComponent, SectionHeaderComponent],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
RouterModule,
|
RouterModule,
|
||||||
|
BreadcrumbModule,
|
||||||
ToastrModule.forRoot({
|
ToastrModule.forRoot({
|
||||||
positionClass: 'toast-bottom-right',
|
positionClass: 'toast-bottom-right',
|
||||||
preventDuplicates: true
|
preventDuplicates: true
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
exports: [NavBarComponent]
|
exports: [
|
||||||
|
NavBarComponent,
|
||||||
|
SectionHeaderComponent
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class CoreModule { }
|
export class CoreModule { }
|
||||||
|
@ -6,7 +6,7 @@ import {
|
|||||||
HttpInterceptor
|
HttpInterceptor
|
||||||
} from '@angular/common/http';
|
} from '@angular/common/http';
|
||||||
import { catchError, Observable, throwError } from 'rxjs';
|
import { catchError, Observable, throwError } from 'rxjs';
|
||||||
import { Router } from '@angular/router';
|
import { NavigationExtras, Router } from '@angular/router';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -20,8 +20,13 @@ export class ErrorInterceptor implements HttpInterceptor {
|
|||||||
if (error){
|
if (error){
|
||||||
|
|
||||||
if (error.status === 400){
|
if (error.status === 400){
|
||||||
|
if (error.error.errors){
|
||||||
|
//log('error thrown ' + error.error);
|
||||||
|
throw error.error;
|
||||||
|
} else {
|
||||||
this.toastr.error(error.error.message, error.error.statusCode);
|
this.toastr.error(error.error.message, error.error.statusCode);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (error.status === 401){
|
if (error.status === 401){
|
||||||
this.toastr.error(error.error.message, error.error.statusCode);
|
this.toastr.error(error.error.message, error.error.statusCode);
|
||||||
@ -32,7 +37,8 @@ export class ErrorInterceptor implements HttpInterceptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (error.status === 500){
|
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));
|
return throwError(() => new Error(error));
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
<ng-container *ngIf="(breadcrumb$ | async) as breadcrumbs">
|
||||||
|
<section *ngIf="breadcrumbs.length > 0 && breadcrumbs[breadcrumbs.length-1].label !== 'Home'" class="py-5" style="margin-top: 105px; background-color:#f5f5f5;">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row d-flex align-item-center">
|
||||||
|
<div class="col-9">
|
||||||
|
<h1>{{breadcrumbs.length > 0 && breadcrumbs[breadcrumbs.length-1].label | titlecase}}</h1>
|
||||||
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
<xng-breadcrumb></xng-breadcrumb>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</ng-container>
|
@ -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<any[]>;
|
||||||
|
|
||||||
|
constructor(private bcService: BreadcrumbService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.breadcrumb$ = this.bcService.breadcrumbs$;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,3 +1,17 @@
|
|||||||
<div class="container mt-5">
|
<div class="container mt-5">
|
||||||
<h1>Internal Server Error</h1>
|
<h4>Server Internal Error - Refreshing the page clears the exception</h4>
|
||||||
|
<ng-container *ngIf="e">
|
||||||
|
<h5 class="text-danger">{{e.message}}</h5>
|
||||||
|
<p class="font-weight-bold">Note: if you are seeing this, this is not a client side error.</p>
|
||||||
|
<p>What's next?</p>
|
||||||
|
<ol>
|
||||||
|
<li>Open Chrom Dev Tools</li>
|
||||||
|
<li>Inspect the Network Tab</li>
|
||||||
|
<li>Check the failing request</li>
|
||||||
|
<li>Examin the request URL. Is it correct?</li>
|
||||||
|
<li>Reproduce Error in Postman</li>
|
||||||
|
</ol>
|
||||||
|
<p>Following is the stack trace - This is where your investigation begins.</p>
|
||||||
|
<code class="mt-5" style="background-color: whitesmoke;">{{e.details}}</code>
|
||||||
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-server-error',
|
selector: 'app-server-error',
|
||||||
@ -6,8 +7,12 @@ import { Component, OnInit } from '@angular/core';
|
|||||||
styleUrls: ['./server-error.component.scss']
|
styleUrls: ['./server-error.component.scss']
|
||||||
})
|
})
|
||||||
export class ServerErrorComponent implements OnInit {
|
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 {
|
ngOnInit(): void {
|
||||||
}
|
}
|
||||||
|
@ -3,4 +3,9 @@
|
|||||||
<button (click)="get404Error()" class="btn btn-outline-primary me-3">Test 404 Error</button>
|
<button (click)="get404Error()" class="btn btn-outline-primary me-3">Test 404 Error</button>
|
||||||
<button (click)="get400Error()" class="btn btn-outline-primary me-3">Test 400 Error</button>
|
<button (click)="get400Error()" class="btn btn-outline-primary me-3">Test 400 Error</button>
|
||||||
<button (click)="get400ValidationError()" class="btn btn-outline-primary me-3">Test 400 Validation Error</button>
|
<button (click)="get400ValidationError()" class="btn btn-outline-primary me-3">Test 400 Validation Error</button>
|
||||||
|
<div class="row mt-5" *ngIf="validationErrors">
|
||||||
|
<ul class="text-danger">
|
||||||
|
<li *ngFor="let error of validationErrors">{{error}}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,6 +9,7 @@ import { environment } from 'src/environments/environment';
|
|||||||
})
|
})
|
||||||
export class TestErrorComponent implements OnInit {
|
export class TestErrorComponent implements OnInit {
|
||||||
baseURL = environment.apiUrl;
|
baseURL = environment.apiUrl;
|
||||||
|
validationErrors: any;
|
||||||
|
|
||||||
constructor(private http: HttpClient) { }
|
constructor(private http: HttpClient) { }
|
||||||
|
|
||||||
@ -49,7 +50,9 @@ export class TestErrorComponent implements OnInit {
|
|||||||
this.http.get(this.baseURL + 'products/five').subscribe(
|
this.http.get(this.baseURL + 'products/five').subscribe(
|
||||||
{
|
{
|
||||||
next: (response) => { console.log(response); },
|
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'); }
|
complete: () => { console.log('complete'); }
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { IProduct } from 'src/app/shared/models/product';
|
import { IProduct } from 'src/app/shared/models/product';
|
||||||
|
import { BreadcrumbService } from 'xng-breadcrumb';
|
||||||
import { ShopService } from '../shop.service';
|
import { ShopService } from '../shop.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -11,7 +12,7 @@ import { ShopService } from '../shop.service';
|
|||||||
export class ProductDetailsComponent implements OnInit {
|
export class ProductDetailsComponent implements OnInit {
|
||||||
product: IProduct;
|
product: IProduct;
|
||||||
|
|
||||||
constructor(private shopService: ShopService, private activatedRoute: ActivatedRoute) { }
|
constructor(private shopService: ShopService, private activatedRoute: ActivatedRoute, private bcService: BreadcrumbService) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.loadProduct();
|
this.loadProduct();
|
||||||
@ -20,7 +21,10 @@ export class ProductDetailsComponent implements OnInit {
|
|||||||
loadProduct(){
|
loadProduct(){
|
||||||
this.shopService.getProduct(+this.activatedRoute.snapshot.paramMap.get('id')).subscribe(
|
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); },
|
error: (e: any) => { console.log(e); },
|
||||||
complete: () => { console.log('complete'); }
|
complete: () => { console.log('complete'); }
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
<div class="card h-100 shadow-sm">
|
<div class="card h-100 shadow-sm">
|
||||||
<img src="{{product.pictureUrl}}" alt="{{product.name}}" class="img-fluid bg-light">
|
<img src="{{product.pictureUrl}}" alt="{{product.name}}" class="img-fluid bg-light">
|
||||||
|
<div class="d-flex align-items-center justify-content-center hover-overlay">
|
||||||
|
<button type="button" class="btn btn-sm btn-primary fa fa-shopping-cart me-2"></button>
|
||||||
|
<button routerLink="/shop/{{product.id}}" type="button" class="btn btn-sm btn-primary">View</button>
|
||||||
|
</div>
|
||||||
<div class="card-body d-flex flex-column">
|
<div class="card-body d-flex flex-column">
|
||||||
<a routerLink="/shop/{{product.id}}">
|
<a routerLink="/shop/{{product.id}}">
|
||||||
<h6 class="text-uppercase">{{product.name}}</h6>
|
<h6 class="text-uppercase">{{product.name}}</h6>
|
||||||
</a>
|
</a>
|
||||||
<span class="mb-2">{{product.price | currency}}</span>
|
<span class="mb-2">{{product.price | currency}}</span>
|
||||||
<div class="btn-group mt-auto">
|
|
||||||
<button type="button" class="btn btn-sm btn-outline-secondary fa fa-shopping-cart me-2"></button>
|
|
||||||
<button routerLink="/shop/{{product.id}}" type="button" class="btn btn-sm btn-outline-secondary">View</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
.btn {
|
||||||
|
width: 30%;
|
||||||
|
height: 40px;
|
||||||
|
}
|
@ -1,12 +1,11 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
import { ShopComponent } from './shop.component';
|
import { ShopComponent } from './shop.component';
|
||||||
import { ProductDetailsComponent } from './product-details/product-details.component';
|
import { ProductDetailsComponent } from './product-details/product-details.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{path: '', component: ShopComponent},
|
{path: '', component: ShopComponent},
|
||||||
{path: ':id', component: ProductDetailsComponent},
|
{path: ':id', component: ProductDetailsComponent, data: {breadcrumb: {alias: 'productDetails'}}},
|
||||||
]
|
]
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row mt-5">
|
||||||
<section class="col-3">
|
<section class="col-3">
|
||||||
<h5 class="text-warning ml-3">Sort</h5>
|
<h5 class="text-warning ml-3">Sort</h5>
|
||||||
<select class="form-select mb-3" style="width: 100%;" (change)="onSortSelected($event.target.value)">
|
<select class="form-select mb-3" style="width: 100%;" (change)="onSortSelected($event.target.value)">
|
||||||
|
@ -5,3 +5,18 @@
|
|||||||
|
|
||||||
/* Importing Datepicker SCSS file. */
|
/* Importing Datepicker SCSS file. */
|
||||||
@import "node_modules/ngx-bootstrap/datepicker/bs-datepicker";
|
@import "node_modules/ngx-bootstrap/datepicker/bs-datepicker";
|
||||||
|
|
||||||
|
.xng-breadcrumb-root {
|
||||||
|
padding: 8px 16px;
|
||||||
|
display: inline;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
label.xng-breadcrumb-trail {
|
||||||
|
margin-bottom: 0;
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
xng-breadcrumb-separator {
|
||||||
|
padding: 0 0;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user