import { computed, inject, Injectable, signal } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { NavigationEnd, Router } from '@angular/router'; import { filter } from 'rxjs'; import { SITE_CONFIG } from '../content/site-config'; import { otherLocale, type AppLocale } from '../i18n/locale'; import { LocaleService } from '../i18n/locale.service'; import { isAppRouteData } from '../routing/app-route-data'; import { type RouteId } from '../routing/route-ids'; import { routeCommands } from '../routing/route-paths'; import { FOOTER_NAV, PRIMARY_NAV, type NavItem } from './navigation'; export interface ResolvedNavItem { readonly routeId: RouteId; readonly label: string; readonly link: unknown[]; readonly children?: readonly ResolvedNavItem[]; } @Injectable({ providedIn: 'root' }) export class NavigationService { private readonly localeService = inject(LocaleService); private readonly router = inject(Router); private readonly activeRouteIdSignal = signal('home'); readonly activeRouteId = this.activeRouteIdSignal.asReadonly(); readonly cvHref = SITE_CONFIG.cvAssetPath; readonly contactLink = computed(() => this.link('contact')); readonly primaryNav = computed(() => this.resolveItems(PRIMARY_NAV, this.localeService.locale())); readonly footerNav = computed(() => this.resolveItems(FOOTER_NAV, this.localeService.locale())); constructor() { this.router.events .pipe( filter((event): event is NavigationEnd => event instanceof NavigationEnd), takeUntilDestroyed(), ) .subscribe(() => this.syncFromRouter()); this.syncFromRouter(); } link(routeId: RouteId, locale?: AppLocale): unknown[] { return routeCommands(routeId, locale ?? this.localeService.locale()); } alternateLocaleLink(): unknown[] { const targetLocale = otherLocale(this.localeService.locale()); const current = this.activeRouteId(); const routeId = current === 'notFound' ? 'home' : current; return routeCommands(routeId, targetLocale); } private resolveItems(items: readonly NavItem[], locale: AppLocale): ResolvedNavItem[] { return items.map((item) => ({ routeId: item.routeId, label: item.label[locale], link: routeCommands(item.routeId, locale), children: item.children ? this.resolveItems(item.children, locale) : undefined, })); } private syncFromRouter(): void { let snapshot = this.router.routerState.snapshot.root; while (snapshot.firstChild) { snapshot = snapshot.firstChild; } if (!isAppRouteData(snapshot.data)) { return; } this.localeService.setLocale(snapshot.data.locale); this.activeRouteIdSignal.set(snapshot.data.routeId); } }