From 7a703350c753e2f2e269734acabe6fa0f63d5a40 Mon Sep 17 00:00:00 2001 From: SkyZeroZx <73321943+SkyZeroZx@users.noreply.github.com> Date: Sun, 13 Oct 2024 12:38:49 -0500 Subject: [PATCH] feat(webauthn-angular): Add Login form with register form --- .../authenticator.component.html | 7 +-- .../components/login/login.component.html | 39 +++++++------ .../components/login/login.component.scss | 23 ++++++++ .../home/components/login/login.component.ts | 7 +++ .../register/register.component.html | 58 ++++++++++++------- .../components/register/register.component.ts | 22 +++++-- .../src/app/pages/home/home.component.ts | 4 +- .../src/app/services/auth/auth.service.ts | 22 ++++++- apps/webauthn-angular/src/styles.scss | 8 +-- 9 files changed, 131 insertions(+), 59 deletions(-) diff --git a/apps/webauthn-angular/src/app/pages/home/components/authenticator/authenticator.component.html b/apps/webauthn-angular/src/app/pages/home/components/authenticator/authenticator.component.html index b9bb8ff..9720c8d 100644 --- a/apps/webauthn-angular/src/app/pages/home/components/authenticator/authenticator.component.html +++ b/apps/webauthn-angular/src/app/pages/home/components/authenticator/authenticator.component.html @@ -3,9 +3,6 @@

{{ item.device }}

-
@@ -24,8 +21,8 @@
{{ item.credentialID }}
Public Key
-
- {{ item.credentialPublicKey | bufferToBase64}} +
+ {{ item.credentialPublicKey | bufferToBase64 }}
diff --git a/apps/webauthn-angular/src/app/pages/home/components/login/login.component.html b/apps/webauthn-angular/src/app/pages/home/components/login/login.component.html index be341ff..a8b9321 100644 --- a/apps/webauthn-angular/src/app/pages/home/components/login/login.component.html +++ b/apps/webauthn-angular/src/app/pages/home/components/login/login.component.html @@ -1,19 +1,22 @@ - -
-

Login

-
- - UserName - - +
- + + Password + + + +
+ + diff --git a/apps/webauthn-angular/src/app/pages/home/components/login/login.component.scss b/apps/webauthn-angular/src/app/pages/home/components/login/login.component.scss index e69de29..77b1266 100644 --- a/apps/webauthn-angular/src/app/pages/home/components/login/login.component.scss +++ b/apps/webauthn-angular/src/app/pages/home/components/login/login.component.scss @@ -0,0 +1,23 @@ +.login { + display: flex; + flex-direction: column; + gap: 1rem; + padding: 1rem; + + &__title { + text-align: center; + } + + &__form { + display: flex; + flex-direction: column; + gap: 1rem; + padding: 1rem; + } + + &__actions { + display: flex; + flex-direction: column; + gap: 1rem; + } +} diff --git a/apps/webauthn-angular/src/app/pages/home/components/login/login.component.ts b/apps/webauthn-angular/src/app/pages/home/components/login/login.component.ts index 3858998..724511b 100644 --- a/apps/webauthn-angular/src/app/pages/home/components/login/login.component.ts +++ b/apps/webauthn-angular/src/app/pages/home/components/login/login.component.ts @@ -36,14 +36,21 @@ export class LoginComponent { private readonly authService = inject(AuthService); private readonly snackBar = inject(MatSnackBar); private readonly formBuilder = inject(FormBuilder); + readonly isLoading = this.authService.isLoading; onLogin = output(); + onGoBack = output(); loginForm: FormGroup> = this.formBuilder.group({ username: ['', [Validators.required, Validators.minLength(5), Validators.maxLength(255)]], password: ['', [Validators.required, Validators.minLength(5), Validators.maxLength(128)]] }); + goBack() { + this.onGoBack.emit(); + this.loginForm.reset(); + } + login() { const { username, password } = this.loginForm.getRawValue(); this.authService.login(username, password).subscribe({ diff --git a/apps/webauthn-angular/src/app/pages/home/components/register/register.component.html b/apps/webauthn-angular/src/app/pages/home/components/register/register.component.html index 6a7ff72..158a7b5 100644 --- a/apps/webauthn-angular/src/app/pages/home/components/register/register.component.html +++ b/apps/webauthn-angular/src/app/pages/home/components/register/register.component.html @@ -1,26 +1,40 @@
+ + @if (!hasAccount()) { + + } @else { + + } + +
+ +

Sign In

- -
- - UserName - - - - Name - - - - Last Name - - - - Password - - - -
-
- + + + +
diff --git a/apps/webauthn-angular/src/app/pages/home/components/register/register.component.ts b/apps/webauthn-angular/src/app/pages/home/components/register/register.component.ts index d8fed4f..7336212 100644 --- a/apps/webauthn-angular/src/app/pages/home/components/register/register.component.ts +++ b/apps/webauthn-angular/src/app/pages/home/components/register/register.component.ts @@ -1,7 +1,8 @@ import { MAT_FORM_FIELD_CUSTOM } from '@/core/config'; import { TypedFormControls } from '@/core/interface/forms/forms.interface'; import { AuthService } from '@/services/auth'; -import { ChangeDetectionStrategy, Component, inject, output } from '@angular/core'; +import { NgTemplateOutlet } from '@angular/common'; +import { ChangeDetectionStrategy, Component, inject, output, signal } from '@angular/core'; import { FormBuilder, FormGroup, @@ -15,6 +16,7 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { MatSnackBar } from '@angular/material/snack-bar'; import { RegisterUser } from '@skyzerozx/shared-interfaces'; +import { LoginComponent } from '../login/login.component'; @Component({ selector: 'app-register', @@ -25,7 +27,9 @@ import { RegisterUser } from '@skyzerozx/shared-interfaces'; MatFormFieldModule, MatButtonModule, MatInputModule, - MatDialogModule + MatDialogModule, + NgTemplateOutlet, + LoginComponent ], templateUrl: './register.component.html', styleUrl: './register.component.scss', @@ -36,8 +40,10 @@ export class RegisterComponent { private readonly authService = inject(AuthService); private readonly snackBar = inject(MatSnackBar); private readonly formBuilder = inject(FormBuilder); + readonly isLoading = this.authService.isLoading; - onRegister = output(); + onClose = output(); + hasAccount = signal(false); registerForm: FormGroup> = this.formBuilder.group({ username: ['', [Validators.required, Validators.minLength(5), Validators.maxLength(255)]], @@ -46,11 +52,19 @@ export class RegisterComponent { lastName: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(255)]] }); + hideLogin() { + this.hasAccount.set(false); + } + + showLogin() { + this.hasAccount.set(true); + } + register() { this.authService.register(this.registerForm.getRawValue()).subscribe({ next: () => { this.snackBar.open('User Registration Success', 'OK'); - this.onRegister.emit(); + this.onClose.emit(); } }); } diff --git a/apps/webauthn-angular/src/app/pages/home/home.component.ts b/apps/webauthn-angular/src/app/pages/home/home.component.ts index af518ae..134f089 100644 --- a/apps/webauthn-angular/src/app/pages/home/home.component.ts +++ b/apps/webauthn-angular/src/app/pages/home/home.component.ts @@ -40,7 +40,7 @@ export class HomeComponent implements OnInit { switchMap(() => authenticators$), shareReplay(1) ); - console.log('Authenticators'); + return toSignal(refreshAuthenticators$, { initialValue: [] }); @@ -56,6 +56,6 @@ export class HomeComponent implements OnInit { disableClose: true }); - dialogRef.componentRef.instance.onRegister.subscribe(() => dialogRef.close()); + dialogRef.componentRef.instance.onClose.subscribe(() => dialogRef.close()); } } diff --git a/apps/webauthn-angular/src/app/services/auth/auth.service.ts b/apps/webauthn-angular/src/app/services/auth/auth.service.ts index 3607feb..737fdc4 100644 --- a/apps/webauthn-angular/src/app/services/auth/auth.service.ts +++ b/apps/webauthn-angular/src/app/services/auth/auth.service.ts @@ -1,4 +1,4 @@ -import { concatMap, tap } from 'rxjs'; +import { concatMap, finalize, tap } from 'rxjs'; import { jwtDecode } from 'jwt-decode'; import { HttpClient } from '@angular/common/http'; import { inject, Injectable, signal } from '@angular/core'; @@ -19,19 +19,35 @@ import { STORAGE_KEYS } from '../../core/constants'; export class AuthService { private readonly http = inject(HttpClient); private readonly userStorage = signal(this.decodeToken()); + private readonly _isLoading = signal(false); + + get isLoading() { + return this._isLoading.asReadonly(); + } register(registerUser: RegisterUser) { + this._isLoading.set(false); return this.http .post>(`${environment.API_URL}/users/register`, registerUser) - .pipe(concatMap(() => this.login(registerUser.username, registerUser.password))); + .pipe( + tap(() => this._isLoading.set(true)), + concatMap(() => this.login(registerUser.username, registerUser.password)), + finalize(() => this._isLoading.set(false)) + ); } login(username: string, password: string) { + this._isLoading.set(false); + return this.http .post< ResponseFormat >(`${environment.API_URL}/auth/login`, { username, password }) - .pipe(tap(({ data }) => this.saveUserStorage(data))); + .pipe( + tap(() => this._isLoading.set(true)), + tap(({ data }) => this.saveUserStorage(data)), + finalize(() => this._isLoading.set(false)) + ); } saveUserStorage({ token, user }: UserAuthenticated) { diff --git a/apps/webauthn-angular/src/styles.scss b/apps/webauthn-angular/src/styles.scss index 3cdf21d..5bd7fda 100644 --- a/apps/webauthn-angular/src/styles.scss +++ b/apps/webauthn-angular/src/styles.scss @@ -11,18 +11,16 @@ body { .register-dialog-container { width: 600px; - height: 600px; + @media (width <= 600px) { width: 400px; - height: 550px; } } .json-viewer-dialog-container { - width: 600px; - height: 560px; + width: 900px; + @media (width <= 600px) { width: 400px; - height: 530px; } }