Skip to content

Commit

Permalink
UI auth improvements (#121)
Browse files Browse the repository at this point in the history
  • Loading branch information
matt-goldman authored Nov 16, 2023
1 parent 5c0b2a0 commit 2e08e19
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 20 deletions.
4 changes: 3 additions & 1 deletion Src/WebUI/ClientApp/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.css"
],
"scripts": []
"scripts": [
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
]
},
"configurations": {
"production": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ <h4>Use a local account to log in.</h4>
<div class="text-danger"></div>
<div class="form-group">
<label for="username"></label>
<input id="username" class="form-control" placeholder="User Name"/>
<input id="username" class="form-control" placeholder="User Name" [disabled]="isBusy" />
<!-- <span asp-validation-for="Input.Email" class="text-danger"></span> -->
</div>
<div class="form-group">
<label for="password"></label>
<input id="password" type="password" class="form-control" placeholder="Password"/>
<input id="password" type="password" class="form-control" placeholder="Password" [disabled]="isBusy"/>
<!-- <span asp-validation-for="Input.Password" class="text-danger"></span> -->
</div>
<!-- <div class="form-group">
Expand All @@ -23,7 +23,10 @@ <h4>Use a local account to log in.</h4>
</div>
</div> -->
<div class="form-group">
<button type="submit" class="btn btn-primary" (click)="loginClicked()">Log in</button>
<button type="submit" class="btn btn-primary" (click)="loginClicked()" type="button" [disabled]="isBusy">
<span *ngIf="isBusy" class="spinner-grow spinner-grow-sm" aria-hidden="true"></span>
{{ buttonText }}
</button>
</div>
<div class="form-group">
<p>
Expand All @@ -33,3 +36,10 @@ <h4>Use a local account to log in.</h4>
</section>
</div>
</div>
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<div id="loginFailedToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-body">
{{ toastMessage }}
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ActivatedRoute, Router } from '@angular/router';
import { ApplicationPaths, ReturnUrlType } from '../api-authorization.constants';
import {RegisterComponent} from "../register/register.component";

declare var bootstrap: any;

// The main responsibility of this component is to handle the user's login process.
// This is the starting point for the login process. Any component that needs to authenticate
Expand All @@ -18,6 +19,10 @@ export class LoginComponent implements OnInit{

constructor(private authService: AuthorizeService, private router: Router, private activatedRoute: ActivatedRoute) { }

isBusy: boolean = false;
buttonText: string = 'Login';
toastMessage: string = '';

ngOnInit(): void {

console.log("Login component initialized. Attempting refresh...");
Expand All @@ -39,7 +44,8 @@ export class LoginComponent implements OnInit{

loginClicked() {

// todo: show that something is happening (https://github.com/SSWConsulting/Northwind365/issues/105)
this.isBusy = true;
this.buttonText = 'Logging in...';

let username = (<HTMLInputElement>document.getElementById("username")).value;
let password = (<HTMLInputElement>document.getElementById("password")).value;
Expand All @@ -54,12 +60,18 @@ export class LoginComponent implements OnInit{

if (result == AuthenticationResult.Success) {
console.log("Login successful");
this.toastMessage = '✅ Login successful! Sending you back where you came from...';
this.showToast();

let returnUrl = this.getReturnUrl();

await this.router.navigate([returnUrl]);
} else {
// handle failure
this.isBusy = false;
this.buttonText = 'Login';
this.toastMessage = '⚠️ Login failed. Please check your credentials and try again.';
this.showToast();
}
});

Expand All @@ -69,4 +81,10 @@ export class LoginComponent implements OnInit{
return this.activatedRoute.snapshot.queryParams[ReturnUrlType] || '/';
}

showToast() {
const toastRef = document.getElementById("loginFailedToast");
const toast = bootstrap.Toast.getOrCreateInstance(toastRef);
toast.show();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,15 @@ export class LogoutComponent implements OnInit {

ngOnInit() {
this.authorizeService.logout();
this.router.navigate(["/"]);

// todo: show a nice "you have been logged out" message (https://github.com/SSWConsulting/Northwind365/issues/106)


this.router.navigate(
["/"],
{
queryParams: {
loggedOut: true,
},
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,29 @@ <h4>Create a new account.</h4>
<div class="text-danger"></div>
<div class="form-group">
<label for="username">User Name</label>
<input id="username" class="form-control" />
<input id="username" class="form-control" [disabled]="isBusy" />
<!-- <span asp-validation-for="Input.Email" class="text-danger"></span>-->
</div>
<div class="form-group">
<label for="password">Password</label>
<input id="password" class="form-control" type="password" />
<input id="password" class="form-control" type="password" [disabled]="isBusy" />
<!-- <span asp-validation-for="Input.Password" class="text-danger"></span>-->
</div>
<div class="form-group">
<label for="confirmPassword">Confirm Password</label>
<input id="confirmPassword" class="form-control" type="password" />
<input id="confirmPassword" class="form-control" type="password" [disabled]="isBusy" />
<!-- <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>-->
</div>
<button (click)="registerClicked()" class="btn btn-primary">Register</button>
<button (click)="registerClicked()" class="btn btn-primary" type="button" [disabled]="isBusy">
<span *ngIf="isBusy" class="spinner-grow spinner-grow-sm" aria-hidden="true"></span>
{{ buttonText }}
</button>
</div>
</div>
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<div id="statusToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-body">
{{ notificationMessage}}
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Component } from '@angular/core';
import { AuthenticationResult, AuthorizeService, NetCore8LoginModel } from '../authorize.service';
import { ApplicationPaths } from '../api-authorization.constants';
import { ApplicationPaths, ReturnUrlType } from '../api-authorization.constants';
import { ActivatedRoute, Router } from '@angular/router';

declare var bootstrap: any;

@Component({
selector: 'app-register',
Expand All @@ -9,11 +12,18 @@ import { ApplicationPaths } from '../api-authorization.constants';
})
export class RegisterComponent {

constructor(private authService: AuthorizeService) { }
constructor(private authService: AuthorizeService, private router: Router, private activatedRoute: ActivatedRoute) { }

isBusy: boolean = false;

notificationMessage: string = '';

buttonText: string = 'Register';

registerClicked() {

// todo: show that something is happening (https://github.com/SSWConsulting/Northwind365/issues/107)
this.isBusy = true;
this.buttonText = 'Registering...';

let username = (<HTMLInputElement>document.getElementById("username")).value;
let password = (<HTMLInputElement>document.getElementById("password")).value;
Expand All @@ -27,19 +37,56 @@ export class RegisterComponent {
console.log(result);

if (result == AuthenticationResult.Success) {
console.log("Registration successful");
console.log("Redirecting to: " + ApplicationPaths.Login);

window.location.href = ApplicationPaths.Login;
this.notificationMessage = "✅ Registration successful! Logging you in...";
this.showToast();

this.authService.handleLogin(registerModel)
.subscribe(async (result: AuthenticationResult) => {
console.log(result);

if (result == AuthenticationResult.Success) {
this.notificationMessage = "✅ Login successful! Redirecting...";
this.showToast();

let returnUrl = this.getReturnUrl();

await this.router.navigate([returnUrl]);

// todo: Automatically log the user in, capture additional info from the form, and populate their profile, then redirect home instead of to the login page. (https://github.com/SSWConsulting/Northwind365/issues/108)
} else {
// handle failure
console.log("Login failed")

this.notificationMessage = "⚠️ Could not automatically log you in. Please navigate to the login page.";
this.showToast();

this.isBusy = false;
this.buttonText = 'Register';
}
});

} else {
// handle failure
console.log("Registration failed")

this.notificationMessage = "⚠️ Registration failed. Please try again.";
this.showToast();

this.isBusy = false;
this.buttonText = 'Register';
}
});

}

getReturnUrl(): string {
return this.activatedRoute.snapshot.queryParams[ReturnUrlType] || '/';
}

showToast() {
const toastRef = document.getElementById("statusToast");
const toast = bootstrap.Toast.getOrCreateInstance(toastRef);
toast.show();
}

}
7 changes: 7 additions & 0 deletions Src/WebUI/ClientApp/src/app/home/home.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,10 @@ <h2>Heading</h2>
</div>
</div>
</div>
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<div id="logoutToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-body">
ℹ️ You have been logged out.
</div>
</div>
</div>
25 changes: 23 additions & 2 deletions Src/WebUI/ClientApp/src/app/home/home.component.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,28 @@
import { Component } from "@angular/core";
import { Component, OnInit } from "@angular/core";
import { ActivatedRoute } from "@angular/router";

declare var bootstrap: any;

@Component({
templateUrl: "./home.component.html",
styleUrls: ["./home.component.css"]
})
export class HomeComponent { }
export class HomeComponent implements OnInit
{
constructor(private route: ActivatedRoute) { }

ngOnInit(): void {
this.route.queryParams.subscribe(params => {
if (params["loggedOut"] === "true") {
this.showLoggedOutToast();
}
});
}

showLoggedOutToast() {
const toastRef = document.getElementById("logoutToast");
const toast = bootstrap.Toast.getOrCreateInstance(toastRef);
toast.show();
}

}

0 comments on commit 2e08e19

Please sign in to comment.