From 9f8cf14807be45ef5bd79e1ae69e47b588decc8d Mon Sep 17 00:00:00 2001 From: rubikscraft Date: Thu, 3 Mar 2022 15:44:22 +0100 Subject: [PATCH] Add ability to login --- frontend/package.json | 1 + frontend/src/app/api/user.service.ts | 12 ++++- .../components/header/header.component.html | 29 ++++++++++- .../components/header/header.component.scss | 12 +++++ .../app/components/header/header.component.ts | 48 +++++++++++++++++-- .../app/components/header/header.module.ts | 19 ++++++-- .../src/app/routes/login/login.component.ts | 26 +++++----- frontend/src/scss/fixes.scss | 6 +++ frontend/src/scss/index.scss | 1 + yarn.lock | 7 +++ 10 files changed, 138 insertions(+), 23 deletions(-) create mode 100644 frontend/src/scss/fixes.scss diff --git a/frontend/package.json b/frontend/package.json index 9657297..ccc1367 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,6 +27,7 @@ "class-transformer": "^0.5.1", "class-validator": "^0.13.2", "jwt-decode": "^3.1.2", + "ngx-auto-unsubscribe-decorator": "^1.0.0", "ngx-dropzone": "^3.1.0", "picsur-shared": "*", "rxjs": "~7.5.4", diff --git a/frontend/src/app/api/user.service.ts b/frontend/src/app/api/user.service.ts index e97eef1..5fa79bd 100644 --- a/frontend/src/app/api/user.service.ts +++ b/frontend/src/app/api/user.service.ts @@ -23,10 +23,18 @@ import { KeyService } from './key.service'; providedIn: 'root', }) export class UserService { - public get user() { + public get liveUser() { return this.userSubject; } + public get user() { + return this.userSubject.getValue(); + } + + public get isLoggedIn() { + return this.userSubject.getValue() !== null; + } + private userSubject = new BehaviorSubject(null); constructor(private api: ApiService, private key: KeyService) { @@ -74,6 +82,7 @@ export class UserService { const user = await this.extractUser(apikey); if (HasFailed(user)) { console.warn(user.getReason()); + await this.logout(); return; } @@ -82,6 +91,7 @@ export class UserService { const fetchedUser = await this.fetchUser(); if (HasFailed(fetchedUser)) { console.warn(fetchedUser.getReason()); + await this.logout(); return; } diff --git a/frontend/src/app/components/header/header.component.html b/frontend/src/app/components/header/header.component.html index bd5be6d..c04d7ae 100644 --- a/frontend/src/app/components/header/header.component.html +++ b/frontend/src/app/components/header/header.component.html @@ -2,9 +2,34 @@ - + Picsur + - + + + + + {{ user?.username }} + + + + + + +
+

{{ user?.username }}

+
+
+ +
+
diff --git a/frontend/src/app/components/header/header.component.scss b/frontend/src/app/components/header/header.component.scss index e0a4be0..da9ab21 100644 --- a/frontend/src/app/components/header/header.component.scss +++ b/frontend/src/app/components/header/header.component.scss @@ -6,12 +6,24 @@ align-items: center; } +.username { + margin-right: 1rem; +} + +.mat-menu-item[disabled] { + color: inherit; +} + img { height: 48px; width: 48px; border-radius: 20%; } +h2 { + margin: 0; +} + .text-link { color: inherit; text-decoration: inherit; diff --git a/frontend/src/app/components/header/header.component.ts b/frontend/src/app/components/header/header.component.ts index 2b0d378..118b7d3 100644 --- a/frontend/src/app/components/header/header.component.ts +++ b/frontend/src/app/components/header/header.component.ts @@ -1,15 +1,57 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; +import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator'; +import { EUser } from 'picsur-shared/dist/entities/user.entity'; +import { HasFailed } from 'picsur-shared/dist/types'; +import { UserService } from 'src/app/api/user.service'; +import { SnackBarType } from 'src/app/models/snack-bar-type'; +import { UtilService } from 'src/app/util/util.service'; @Component({ selector: 'app-header', templateUrl: './header.component.html', styleUrls: ['./header.component.scss'], }) -export class HeaderComponent { - constructor(private router: Router) {} +export class HeaderComponent implements OnInit { + private currentUser: EUser | null = null; + + public get user() { + return this.currentUser; + } + + public get isLoggedIn() { + return this.currentUser !== null; + } + + constructor( + private router: Router, + private userService: UserService, + private utilService: UtilService + ) {} + + ngOnInit(): void { + this.subscribeUser(); + } + + @AutoUnsubscribe() + subscribeUser() { + return this.userService.liveUser.subscribe((user) => { + console.log('user', user); + this.currentUser = user; + }); + } doLogin() { this.router.navigate(['/login']); } + + doLogout() { + const user = this.userService.logout(); + if (HasFailed(user)) { + this.utilService.showSnackBar(user.getReason(), SnackBarType.Error); + return; + } + + this.utilService.showSnackBar('Logout successful', SnackBarType.Success); + } } diff --git a/frontend/src/app/components/header/header.module.ts b/frontend/src/app/components/header/header.module.ts index db09fcb..2c2fa4f 100644 --- a/frontend/src/app/components/header/header.module.ts +++ b/frontend/src/app/components/header/header.module.ts @@ -4,12 +4,23 @@ import { HeaderComponent } from './header.component'; import { MatToolbarModule } from '@angular/material/toolbar'; import { MatButtonModule } from '@angular/material/button'; import { RouterModule } from '@angular/router'; +import { ApiModule } from 'src/app/api/api.module'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { UtilModule } from 'src/app/util/util.module'; @NgModule({ - imports: [CommonModule, MatToolbarModule, MatButtonModule, RouterModule], + imports: [ + CommonModule, + MatToolbarModule, + MatButtonModule, + RouterModule, + ApiModule, + MatIconModule, + MatMenuModule, + UtilModule, + ], declarations: [HeaderComponent], exports: [HeaderComponent], }) -export class HeaderModule { - -} +export class HeaderModule {} diff --git a/frontend/src/app/routes/login/login.component.ts b/frontend/src/app/routes/login/login.component.ts index 7e48208..503be38 100644 --- a/frontend/src/app/routes/login/login.component.ts +++ b/frontend/src/app/routes/login/login.component.ts @@ -1,8 +1,10 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; +import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator'; import { HasFailed } from 'picsur-shared/dist/types'; -import { Subscription } from 'rxjs'; import { UserService } from 'src/app/api/user.service'; +import { SnackBarType } from 'src/app/models/snack-bar-type'; +import { UtilService } from 'src/app/util/util.service'; import { LoginControl } from './login.model'; @Component({ @@ -10,23 +12,20 @@ import { LoginControl } from './login.model'; templateUrl: './login.component.html', styleUrls: ['./login.component.scss'], }) -export class LoginComponent implements OnInit, OnDestroy { - private userSubscription: Subscription; - +export class LoginComponent implements OnInit { model = new LoginControl(); loginFail = false; - constructor(private userService: UserService, private router: Router) {} + constructor( + private userService: UserService, + private router: Router, + private utilService: UtilService + ) {} ngOnInit(): void { - console.log('init'); - this.userSubscription = this.userService.user.subscribe((user) => { - console.log('sub', user); - }); - } - - ngOnDestroy(): void { - this.userSubscription.unsubscribe(); + if (this.userService.isLoggedIn) { + this.router.navigate(['/'], { replaceUrl: true }); + } } async onSubmit() { @@ -42,6 +41,7 @@ export class LoginComponent implements OnInit, OnDestroy { return; } + this.utilService.showSnackBar('Login successful', SnackBarType.Success); this.router.navigate(['/']); } } diff --git a/frontend/src/scss/fixes.scss b/frontend/src/scss/fixes.scss new file mode 100644 index 0000000..f6f5fc5 --- /dev/null +++ b/frontend/src/scss/fixes.scss @@ -0,0 +1,6 @@ +.mat-icon { + // Yes yes, !important is here, deal with it + // If someone wants to properly figure out why icons are escaping their 24px box, feel free to + height: initial !important; + width: initial !important; +} diff --git a/frontend/src/scss/index.scss b/frontend/src/scss/index.scss index 00096d5..e31bb84 100644 --- a/frontend/src/scss/index.scss +++ b/frontend/src/scss/index.scss @@ -1,2 +1,3 @@ @import "./personal.scss"; @import "./snackbar.scss"; +@import "./fixes.scss"; diff --git a/yarn.lock b/yarn.lock index a44ee01..ccc7284 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5582,6 +5582,13 @@ neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== +ngx-auto-unsubscribe-decorator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ngx-auto-unsubscribe-decorator/-/ngx-auto-unsubscribe-decorator-1.0.0.tgz#780830df3d5f43543b1bb9b6ed3fc9a4db5f60b4" + integrity sha512-bCXxWBE/AcmbxKSdYqNmjwDJXcUHbQvfCHGZvHiqqbGR7fwZRYMWPNxe4oiw5C+QIEYb+sOWWDOu2hQ2QhD0/w== + dependencies: + tslib "^2.1.0" + ngx-dropzone@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ngx-dropzone/-/ngx-dropzone-3.1.0.tgz#f2045a9ca90903fa96304f1b2aa33a922f14b15a"