Implemented basic error handling. Login works, but we don't have a route to go to, so kinda buggy. Will cleanup in Libraries story.
This commit is contained in:
parent
8fba679788
commit
3f8a4d7866
7 changed files with 106 additions and 26 deletions
59
src/app/_interceptors/error.interceptor.ts
Normal file
59
src/app/_interceptors/error.interceptor.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import {
|
||||||
|
HttpRequest,
|
||||||
|
HttpHandler,
|
||||||
|
HttpEvent,
|
||||||
|
HttpInterceptor
|
||||||
|
} from '@angular/common/http';
|
||||||
|
import { Observable, throwError } from 'rxjs';
|
||||||
|
import { NavigationExtras, Router } from '@angular/router';
|
||||||
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
import { catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ErrorInterceptor implements HttpInterceptor {
|
||||||
|
|
||||||
|
constructor(private router: Router, private toastr: ToastrService) {}
|
||||||
|
|
||||||
|
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
||||||
|
return next.handle(request).pipe(
|
||||||
|
catchError(error => {
|
||||||
|
if (error) {
|
||||||
|
console.error('error:', error);
|
||||||
|
switch (error.status) {
|
||||||
|
case 400:
|
||||||
|
if (error.error.errors) {
|
||||||
|
// Validation error
|
||||||
|
const modalStateErrors = [];
|
||||||
|
for (const key in error.error.errors) {
|
||||||
|
if (error.error.errors[key]) {
|
||||||
|
modalStateErrors.push(error.error.errors[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw modalStateErrors.flat();
|
||||||
|
} else {
|
||||||
|
this.toastr.error(error.statusText === 'OK' ? error.error : error.statusText, error.status);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 401:
|
||||||
|
// if statement is due to http/2 spec issue: https://github.com/angular/angular/issues/23334
|
||||||
|
this.toastr.error(error.statusText === 'OK' ? 'Unauthorized' : error.statusText, error.status);
|
||||||
|
break;
|
||||||
|
case 404:
|
||||||
|
this.router.navigateByUrl('/not-found');
|
||||||
|
break;
|
||||||
|
case 500:
|
||||||
|
const navigationExtras: NavigationExtras = {state: {error: error.error}};
|
||||||
|
this.router.navigateByUrl('/server-error', navigationExtras);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.toastr.error('Something unexpected went wrong.');
|
||||||
|
console.log(error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return throwError(error);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,7 @@ import { NavHeaderComponent } from './nav-header/nav-header.component';
|
||||||
import { JwtInterceptor } from './_interceptors/jwt.interceptor';
|
import { JwtInterceptor } from './_interceptors/jwt.interceptor';
|
||||||
import { UserLoginComponent } from './user-login/user-login.component';
|
import { UserLoginComponent } from './user-login/user-login.component';
|
||||||
import { ToastrModule } from 'ngx-toastr';
|
import { ToastrModule } from 'ngx-toastr';
|
||||||
|
import { ErrorInterceptor } from './_interceptors/error.interceptor';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
|
@ -32,6 +33,7 @@ import { ToastrModule } from 'ngx-toastr';
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
{provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true},
|
||||||
{provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}
|
{provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,22 @@
|
||||||
<ng-container *ngIf="firstTimeFlow">
|
<ng-container *ngIf="firstTimeFlow">
|
||||||
<!-- NOTE: We don't need a first time user flow. We just need a simple component to register a new admin. Once registered, we can put them on admin/ route -->
|
<!-- NOTE: We don't need a first time user flow. We just need a simple component to register a new admin. Once registered, we can put them on admin/ route -->
|
||||||
<p>Please create an admin account for yourself to start your reading journey.</p>
|
<p>Please create an admin account for yourself to start your reading journey.</p>
|
||||||
<form [formGroup]="registerForm" (ngSubmit)="register()" class="form-inline mt-2 mt-md-0">
|
<form [formGroup]="registerForm" (ngSubmit)="register()">
|
||||||
<label>Username:
|
<div class="form-group">
|
||||||
<input class="form-control mr-sm-2" formControlName="username" type="text">
|
<label>Username</label>
|
||||||
</label>
|
<input class="form-control" formControlName="username" type="text">
|
||||||
|
</div>
|
||||||
|
|
||||||
<label>Password:
|
<div class="form-group">
|
||||||
<input class="form-control mr-sm-2" formControlName="password" type="password">
|
<label>Password</label>
|
||||||
</label>
|
<input class="form-control" formControlName="password" type="password">
|
||||||
|
</div>
|
||||||
|
|
||||||
<button class="btn btn-primary my-2 my-sm-0" type="submit">Register</button>
|
<button class="btn btn-primary" type="submit">Register</button>
|
||||||
</form>
|
</form>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container *ngIf="!firstTimeFlow">
|
<ng-container *ngIf="!firstTimeFlow && (this.accountService.currentUser$ | async) == null">
|
||||||
<app-user-login></app-user-login>
|
<app-user-login></app-user-login>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
import { MemberService } from '../member.service';
|
import { MemberService } from '../member.service';
|
||||||
|
|
@ -20,7 +21,7 @@ export class HomeComponent implements OnInit {
|
||||||
password: new FormControl('', [Validators.required])
|
password: new FormControl('', [Validators.required])
|
||||||
});
|
});
|
||||||
|
|
||||||
constructor(public accountService: AccountService, private memberService: MemberService) {
|
constructor(public accountService: AccountService, private memberService: MemberService, private router: Router) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|
@ -37,7 +38,9 @@ export class HomeComponent implements OnInit {
|
||||||
|
|
||||||
console.log('Registering: ', this.model);
|
console.log('Registering: ', this.model);
|
||||||
this.accountService.register(this.model).subscribe(resp => {
|
this.accountService.register(this.model).subscribe(resp => {
|
||||||
console.log('success', resp);
|
this.router.navigateByUrl('/libraries');
|
||||||
|
}, err => {
|
||||||
|
console.log('validation errors from interceptor', err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,23 @@
|
||||||
<div class="container">
|
<div class="mx-auto" style="width: 200px;">
|
||||||
<div class="card" style="width: 18rem;">
|
<div class="card p-3" style="width: 18rem;">
|
||||||
<h3 class="card-title text-center">Login</h3>
|
<h3 class="card-title text-center">Login</h3>
|
||||||
<div class="card-text">
|
<div class="card-text">
|
||||||
<form [formGroup]="loginForm" (ngSubmit)="login()" class="form-inline mt-2 mt-md-0">
|
<form [formGroup]="loginForm" (ngSubmit)="login()">
|
||||||
<label>Username:
|
<div class="form-group">
|
||||||
<input class="form-control mr-sm-2" formControlName="username" type="text">
|
<label>Username</label>
|
||||||
</label>
|
<input class="form-control" formControlName="username" type="text">
|
||||||
|
</div>
|
||||||
|
|
||||||
<label>Password:
|
<div class="form-group">
|
||||||
<input class="form-control mr-sm-2" formControlName="password" type="password">
|
<label>Password</label>
|
||||||
</label>
|
<input class="form-control" formControlName="password" type="password">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pull-right">
|
||||||
|
<button class="btn btn-secondary mr-3" type="button" (click)="cancel()">Cancel</button>
|
||||||
|
<button class="btn btn-primary" type="submit">Login</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button class="btn btn-primary my-2 my-sm-0" type="submit">Login</button>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import { AccountService } from '../_services/account.service';
|
||||||
})
|
})
|
||||||
export class UserLoginComponent implements OnInit {
|
export class UserLoginComponent implements OnInit {
|
||||||
|
|
||||||
model: any = {};
|
model: any = {username: '', password: ''};
|
||||||
loginForm: FormGroup = new FormGroup({
|
loginForm: FormGroup = new FormGroup({
|
||||||
username: new FormControl('', [Validators.required]),
|
username: new FormControl('', [Validators.required]),
|
||||||
password: new FormControl('', [Validators.required])
|
password: new FormControl('', [Validators.required])
|
||||||
|
|
@ -22,12 +22,19 @@ export class UserLoginComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
login() {
|
login() {
|
||||||
|
this.model = {username: this.loginForm.get('username')?.value, password: this.loginForm.get('password')?.value};
|
||||||
this.accountService.login(this.model).subscribe(user => {
|
this.accountService.login(this.model).subscribe(user => {
|
||||||
console.log('success', user);
|
|
||||||
if (user) {
|
if (user) {
|
||||||
|
this.loginForm.reset();
|
||||||
this.router.navigateByUrl('/libraries');
|
this.router.navigateByUrl('/libraries');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cancel() {
|
||||||
|
this.loginForm.reset();
|
||||||
|
// Goes back to previous router state (using back in history)
|
||||||
|
//this.router.p
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
"target": "es2015",
|
"target": "es2015",
|
||||||
"module": "es2020",
|
"module": "es2020",
|
||||||
"lib": [
|
"lib": [
|
||||||
|
"es2019",
|
||||||
"es2018",
|
"es2018",
|
||||||
"dom"
|
"dom"
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue