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:
Joseph Milazzo 2020-12-15 09:46:15 -06:00
parent 8fba679788
commit 3f8a4d7866
7 changed files with 106 additions and 26 deletions

View 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);
})
);
}
}

View file

@ -12,6 +12,7 @@ import { NavHeaderComponent } from './nav-header/nav-header.component';
import { JwtInterceptor } from './_interceptors/jwt.interceptor';
import { UserLoginComponent } from './user-login/user-login.component';
import { ToastrModule } from 'ngx-toastr';
import { ErrorInterceptor } from './_interceptors/error.interceptor';
@NgModule({
declarations: [
@ -32,6 +33,7 @@ import { ToastrModule } from 'ngx-toastr';
}),
],
providers: [
{provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true},
{provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}
],
bootstrap: [AppComponent]

View file

@ -4,20 +4,22 @@
<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 -->
<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">
<label>Username:
<input class="form-control mr-sm-2" formControlName="username" type="text">
</label>
<form [formGroup]="registerForm" (ngSubmit)="register()">
<div class="form-group">
<label>Username</label>
<input class="form-control" formControlName="username" type="text">
</div>
<div class="form-group">
<label>Password</label>
<input class="form-control" formControlName="password" type="password">
</div>
<label>Password:
<input class="form-control mr-sm-2" formControlName="password" type="password">
</label>
<button class="btn btn-primary my-2 my-sm-0" type="submit">Register</button>
<button class="btn btn-primary" type="submit">Register</button>
</form>
</ng-container>
<ng-container *ngIf="!firstTimeFlow">
<ng-container *ngIf="!firstTimeFlow && (this.accountService.currentUser$ | async) == null">
<app-user-login></app-user-login>
</ng-container>

View file

@ -1,5 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { Observable } from 'rxjs';
import { take } from 'rxjs/operators';
import { MemberService } from '../member.service';
@ -20,7 +21,7 @@ export class HomeComponent implements OnInit {
password: new FormControl('', [Validators.required])
});
constructor(public accountService: AccountService, private memberService: MemberService) {
constructor(public accountService: AccountService, private memberService: MemberService, private router: Router) {
}
ngOnInit(): void {
@ -37,7 +38,9 @@ export class HomeComponent implements OnInit {
console.log('Registering: ', this.model);
this.accountService.register(this.model).subscribe(resp => {
console.log('success', resp);
this.router.navigateByUrl('/libraries');
}, err => {
console.log('validation errors from interceptor', err);
});
}

View file

@ -1,17 +1,23 @@
<div class="container">
<div class="card" style="width: 18rem;">
<div class="mx-auto" style="width: 200px;">
<div class="card p-3" style="width: 18rem;">
<h3 class="card-title text-center">Login</h3>
<div class="card-text">
<form [formGroup]="loginForm" (ngSubmit)="login()" class="form-inline mt-2 mt-md-0">
<label>Username:
<input class="form-control mr-sm-2" formControlName="username" type="text">
</label>
<label>Password:
<input class="form-control mr-sm-2" formControlName="password" type="password">
</label>
<button class="btn btn-primary my-2 my-sm-0" type="submit">Login</button>
<form [formGroup]="loginForm" (ngSubmit)="login()">
<div class="form-group">
<label>Username</label>
<input class="form-control" formControlName="username" type="text">
</div>
<div class="form-group">
<label>Password</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>
</form>
</div>

View file

@ -10,7 +10,7 @@ import { AccountService } from '../_services/account.service';
})
export class UserLoginComponent implements OnInit {
model: any = {};
model: any = {username: '', password: ''};
loginForm: FormGroup = new FormGroup({
username: new FormControl('', [Validators.required]),
password: new FormControl('', [Validators.required])
@ -22,12 +22,19 @@ export class UserLoginComponent implements OnInit {
}
login() {
this.model = {username: this.loginForm.get('username')?.value, password: this.loginForm.get('password')?.value};
this.accountService.login(this.model).subscribe(user => {
console.log('success', user);
if (user) {
this.loginForm.reset();
this.router.navigateByUrl('/libraries');
}
});
}
cancel() {
this.loginForm.reset();
// Goes back to previous router state (using back in history)
//this.router.p
}
}

View file

@ -17,6 +17,7 @@
"target": "es2015",
"module": "es2020",
"lib": [
"es2019",
"es2018",
"dom"
]