diff --git a/frontend/src/app/layout/main-layout/layout.component.html b/frontend/src/app/layout/main-layout/layout.component.html index e0ec047..1ec156f 100644 --- a/frontend/src/app/layout/main-layout/layout.component.html +++ b/frontend/src/app/layout/main-layout/layout.component.html @@ -1,5 +1,4 @@
-
+ class="transform h-full z-20 overflow-y-auto fixed md:relative flex flex-col">
@if (!isCollapsed && !isDesktopCollapsed) { -
Logo
+
LOGO
} @if (!isCollapsed && !showMobileMenu) { @@ -58,15 +57,44 @@
  • + +
    + +
    +
    + + {{ item.name }} +
    +
    +
  • +
+
    +
  • +
    diff --git a/frontend/src/app/layout/main-layout/layout.component.ts b/frontend/src/app/layout/main-layout/layout.component.ts index f7afb6e..c711d32 100644 --- a/frontend/src/app/layout/main-layout/layout.component.ts +++ b/frontend/src/app/layout/main-layout/layout.component.ts @@ -9,15 +9,23 @@ import { import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { Router, RouterOutlet } from '@angular/router'; +import { SuccessDtoApiModel } from '../../api'; import { BackgroundPatternService, ThemeService } from '../../shared/service'; +import { AuthService } from '../../shared/service/auth.service'; -interface MenuItem { +interface TopMenuItem { name: string; icon: SafeHtml; route: string; active?: boolean; } +interface BottomMenuItem { + name: string; + icon: SafeHtml; + action?: () => void; +} + @Component({ selector: 'app-layout', standalone: true, @@ -31,7 +39,7 @@ export class LayoutComponent implements OnInit { public isDesktopCollapsed: boolean = false; public showMobileMenu: boolean = false; public userHasInteracted: boolean = false; - public menuItems: MenuItem[] = [ + public menuItems: TopMenuItem[] = [ { name: 'Dashboard', route: '/dashboard', @@ -41,6 +49,16 @@ export class LayoutComponent implements OnInit { `), }, ]; + public bottomMenuItems: BottomMenuItem[] = [ + { + name: 'Logout', + action: () => this.signout(), + icon: this.sanitizer + .bypassSecurityTrustHtml(` + + `), + }, + ]; public mainContent: { 'background-image': string } | null = null; public navigation: { 'background-image': string } | null = null; @@ -49,7 +67,8 @@ export class LayoutComponent implements OnInit { private readonly router: Router, private readonly backgroundPatternService: BackgroundPatternService, private readonly themeService: ThemeService, - private readonly el: ElementRef + private readonly el: ElementRef, + private readonly authService: AuthService ) {} public ngOnInit(): void { @@ -122,8 +141,8 @@ export class LayoutComponent implements OnInit { this.isDesktopCollapsed = !this.isDesktopCollapsed; } - public setActive(item: MenuItem): void { - this.menuItems.forEach((menu: MenuItem) => { + public setActive(item: TopMenuItem): void { + this.menuItems.forEach((menu: TopMenuItem) => { menu.active = false; }); item.active = true; @@ -132,8 +151,18 @@ export class LayoutComponent implements OnInit { private setActiveItemBasedOnRoute(): void { const url = this.router.url; - this.menuItems.forEach((item: MenuItem) => { + this.menuItems.forEach((item: TopMenuItem) => { item.active = url.startsWith(item.route); }); } + + private signout(): void { + this.authService.signout().subscribe((response: SuccessDtoApiModel) => { + if (response.success) { + this.router.navigate(['/welcome'], { + queryParams: { signedOut: true }, + }); + } + }); + } } diff --git a/frontend/src/app/pages/register-root/register-root.component.ts b/frontend/src/app/pages/register-root/register-root.component.ts index 3793149..d96f063 100644 --- a/frontend/src/app/pages/register-root/register-root.component.ts +++ b/frontend/src/app/pages/register-root/register-root.component.ts @@ -25,7 +25,7 @@ import { ButtonModule } from 'primeng/button'; import { CheckboxModule } from 'primeng/checkbox'; import { InputTextModule } from 'primeng/inputtext'; import { PasswordModule } from 'primeng/password'; -import { delay, finalize, tap } from 'rxjs'; +import { delay, finalize, takeWhile, tap } from 'rxjs'; import { Configuration, @@ -78,6 +78,7 @@ export class RegisterRootComponent implements OnInit { public verified: InputSignal = input(false); public login: InputSignal = input(false); public email: InputSignal = input(''); + public signedOut: InputSignal = input(true); public form!: FormGroup; public rememberMe: FormControl = new FormControl(false); public isSigninSignal: WritableSignal = signal(false); @@ -107,30 +108,10 @@ export class RegisterRootComponent implements OnInit { this.clearRouteParams(); } }); - const rememberMe = this.localStorageService.getItem('remember-me'); - - if (rememberMe) { - this.authService - .status() - .pipe(delay(1500)) - .subscribe({ - next: (response: SuccessDtoApiModel) => { - if (response.success) { - this.router.navigate(['/dashboard']); - } else { - this.displaySkeleton.set(false); - } - }, - error: () => { - this.displaySkeleton.set(false); - }, - }); - } else { - this.displaySkeleton.set(false); - } } public ngOnInit(): void { + this.autologin(); this.setBackground(); this.initializeForm(); this.setupValueChanges(); @@ -141,6 +122,30 @@ export class RegisterRootComponent implements OnInit { } } + public autologin(): void { + const rememberMe = this.localStorageService.getItem('remember-me'); + + if (rememberMe && !this.signedOut()) { + this.authService + .status() + .pipe( + delay(1500), + takeWhile((response: SuccessDtoApiModel) => response.success, true), + tap({ + next: (response: SuccessDtoApiModel) => { + if (response.success) { + this.router.navigate(['/dashboard']); + } + }, + finalize: () => this.displaySkeleton.set(false), + }) + ) + .subscribe(); + } else { + this.displaySkeleton.set(false); + } + } + public setBackground(): void { const theme = this.themeService.getTheme(); let opacity: number;