All files root.component.ts

100% Statements 28/28
75% Branches 3/4
100% Functions 10/10
100% Lines 28/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128                                                1x 8x   8x   8x   8x   8x   8x           8x     8x     8x                 8x     8x     8x     8x   8x 9x         1x               2x 1x   1x                 2x 2x         1x         1x         1x                   8x 8x       8x      
import { AfterContentInit, ChangeDetectionStrategy, Component, DestroyRef, HostBinding, inject, OnInit } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { Meta, Title } from '@angular/platform-browser';
import { AppServiceWorkerService } from '@app/client-service-worker';
import { chatbotAction, chatbotSelector, IChatbotState } from '@app/client-store-chatbot';
import { routerAction } from '@app/client-store-router';
import { ISidebarState, sidebarAction, sidebarSelector } from '@app/client-store-sidebar';
import { IThemeState, themeAction, themeSelector } from '@app/client-store-theme';
import { WEB_CLIENT_APP_ENV } from '@app/client-util';
import { Store } from '@ngrx/store';
import { map } from 'rxjs';
 
interface ILogoRef {
  dark: 'assets/svg/logo.svg';
  light: 'assets/svg/logo-light.svg';
}
 
@Component({
  selector: 'app-root',
  templateUrl: './root.component.html',
  styleUrls: ['./root.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  standalone: false,
})
export class AppRootComponent implements OnInit, AfterContentInit {
  private readonly destroyRef = inject(DestroyRef);
 
  private readonly title = inject(Title);
 
  private readonly meta = inject(Meta);
 
  private readonly sw = inject(AppServiceWorkerService);
 
  public readonly store = inject(Store<IChatbotState & ISidebarState & IThemeState>);
 
  private readonly env = inject(WEB_CLIENT_APP_ENV);
 
  /**
   * Defines if UI should use alternative dark material theme.
   * This must be a flag. HostBinding should not use async pipes.
   */
  @HostBinding('class.unicorn-dark-theme') public darkTheme = false;
 
  /** Sets text size that is inherited by all child views. */
  @HostBinding('class.mat-body-1') public matBody = true;
 
  /** The name of the application. */
  public readonly appName = this.env.appName;
 
  /** Logo references. */
  private readonly logoRef: ILogoRef = {
    dark: 'assets/svg/logo.svg',
    light: 'assets/svg/logo-light.svg',
  };
 
  /** Application release version. */
  public readonly version = this.env.meta.version;
 
  /** Sidebar state stream. */
  public readonly sidebarOpen$ = this.store.select(sidebarSelector.sidebarOpen);
 
  /** Chatbot state stream. */
  public readonly chatbotOpen$ = this.store.select(chatbotSelector.chatbotOpen);
 
  /** Theme state stream. */
  public readonly darkThemeEnabled$ = this.store.select(themeSelector.darkThemeEnabled);
 
  public readonly logoSrc$ = this.darkThemeEnabled$.pipe(
    map(darkThemeEnabled => (darkThemeEnabled ? this.logoRef.light : this.logoRef.dark)),
  );
 
  /** Sidebar toggle. */
  public toggleSidebar(): void {
    this.store.dispatch(sidebarAction.toggle());
  }
 
  /**
   * Chatbot toggle.
   * @param event Next state.
   */
  public toggleChatbot(event: boolean): void {
    if (event) {
      this.store.dispatch(chatbotAction.open());
    } else {
      this.store.dispatch(chatbotAction.close());
    }
  }
 
  /**
   * Dark theme toggle.
   * @param darkThemeEnabled Dark theme state.
   */
  public toggleTheme(darkThemeEnabled: boolean): void {
    this.darkTheme = darkThemeEnabled;
    this.store.dispatch(themeAction.toggleDarkTheme());
  }
 
  /** Navigation button click handler. */
  public navButtonClick(): void {
    this.store.dispatch(sidebarAction.close({ payload: { navigate: false } }));
  }
 
  /** Navigate back handler. */
  public navigateBack(): void {
    this.store.dispatch(routerAction.back());
  }
 
  /** Navigate forward handler. */
  public navigateForward(): void {
    this.store.dispatch(routerAction.forward());
  }
 
  /**
   * Lifecycle hook called on component initialization.
   * When called does the following:
   * - sets the document title;
   * - sets the document description;
   */
  public ngOnInit(): void {
    this.title.setTitle(this.env.appName);
    this.meta.updateTag({ description: this.env.description });
  }
 
  public ngAfterContentInit(): void {
    void this.sw.subscribeToUpdates$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe();
  }
}