Add ability to login
This commit is contained in:
parent
e0230b26ae
commit
9f8cf14807
|
@ -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",
|
||||
|
|
|
@ -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<EUser | null>(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,34 @@
|
|||
<a [routerLink]="['/']" class="svg-logo">
|
||||
<img src="/assets/image/logo/picsur.svg" alt="Picsur" />
|
||||
</a>
|
||||
<a [routerLink]="['/']" class="text-link">
|
||||
<a [routerLink]="['/']" class="text-link d-none d-sm-block">
|
||||
<span>Picsur</span>
|
||||
</a>
|
||||
|
||||
<span class="spacer"></span>
|
||||
<button mat-stroked-button (click)="doLogin()">Login</button>
|
||||
|
||||
<button *ngIf="!isLoggedIn" mat-stroked-button (click)="doLogin()">
|
||||
Login
|
||||
</button>
|
||||
|
||||
<span *ngIf="isLoggedIn" class="username d-none d-sm-block">
|
||||
{{ user?.username }}
|
||||
</span>
|
||||
<button *ngIf="isLoggedIn" mat-icon-button [matMenuTriggerFor]="menu">
|
||||
<mat-icon>account_circle</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-menu #menu="matMenu" xPosition="before">
|
||||
<ng-template matMenuContent>
|
||||
<span mat-menu-item disabled>
|
||||
<div class="centered">
|
||||
<h2>{{ user?.username }}</h2>
|
||||
</div>
|
||||
</span>
|
||||
<button mat-menu-item (click)="doLogout()">
|
||||
<mat-icon>logout</mat-icon>
|
||||
<span>Logout</span>
|
||||
</button>
|
||||
</ng-template>
|
||||
</mat-menu>
|
||||
</mat-toolbar>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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(['/']);
|
||||
}
|
||||
}
|
||||
|
|
6
frontend/src/scss/fixes.scss
Normal file
6
frontend/src/scss/fixes.scss
Normal file
|
@ -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;
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
@import "./personal.scss";
|
||||
@import "./snackbar.scss";
|
||||
@import "./fixes.scss";
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue