import { Component, ChangeDetectionStrategy, signal } from '@angular/core'; import { take } from 'rxjs/operators'; import { RouterLink } from '@angular/router'; import { TranslatePipe } from '../../i18n/translate.pipe'; import { LogoComponent } from '../logo/logo.component'; import { UiRuntimeFacade } from '../../facades/runtime/ui-runtime.facade'; import { LangRoutePipe } from '../../pipes/lang-route.pipe'; import { ConfigService } from '../../core/config/config.service'; import { StaticPageResolverService } from '../../core/config/static-page-resolver.service'; import { BootstrapConfig, FooterNavigationGroupConfig, NavigationConfig, NavigationItemConfig, FooterNavigationItemConfig } from '../../shared/models/config'; import { LanguageService } from '../../services/language.service'; interface FooterResolvedItem { id: string; label: string; route: string; } interface FooterResolvedGroup { id: string; title: string; items: FooterResolvedItem[]; } @Component({ selector: 'app-footer', imports: [TranslatePipe, LogoComponent, RouterLink, LangRoutePipe], templateUrl: './footer.component.html', styleUrls: ['./footer.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) export class FooterComponent { readonly footerGroups = signal([]); constructor( private readonly uiRuntime: UiRuntimeFacade, private readonly configService: ConfigService, private readonly staticPageResolver: StaticPageResolverService, private readonly languageService: LanguageService ) { this.configService.loadBootstrap().pipe(take(1)).subscribe({ next: bootstrap => { this.footerGroups.set(this.resolveFooterGroups(bootstrap)); }, error: () => { this.footerGroups.set([]); } }); } currentYear = new Date().getFullYear(); get brandName(): string { return this.uiRuntime.marketplaceName(); } get contactEmail(): string { return this.uiRuntime.contactEmail(); } private resolveFooterGroups(bootstrap: BootstrapConfig): FooterResolvedGroup[] { const footer = bootstrap.navigation?.footer ?? []; const lang = this.languageService.currentLanguage(); if (this.isGroupedFooter(footer)) { return footer .map((group, index) => this.resolveGroupFromConfig(group, bootstrap, lang, index)) .filter((group): group is FooterResolvedGroup => group != null && group.items.length > 0); } const items = (footer as NavigationItemConfig[]) .map(item => this.resolveLegacyItem(item, bootstrap, lang)) .filter((item): item is FooterResolvedItem => item != null); if (!items.length) { return []; } return [{ id: 'footer-group-default', title: '', items }]; } private resolveGroupFromConfig( group: FooterNavigationGroupConfig, bootstrap: BootstrapConfig, lang: string, index: number ): FooterResolvedGroup | null { const items = (group.items ?? []) .map(item => this.resolveGroupItem(item, bootstrap, lang)) .filter((item): item is FooterResolvedItem => item != null); if (!items.length) { return null; } return { id: `footer-group-${index}`, title: this.staticPageResolver.resolveFooterTitle(group.groupTitle, lang), items }; } private resolveGroupItem( item: FooterNavigationItemConfig, bootstrap: BootstrapConfig, lang: string ): FooterResolvedItem | null { if (item.visible === false) { return null; } if (item.type === 'staticPage' && item.key) { const staticPage = this.staticPageResolver.resolveByKeyFromBootstrap(bootstrap, item.key, lang); if (!staticPage) { return null; } return { id: `static-${item.key}`, label: staticPage.title, route: staticPage.route }; } const label = typeof item.label === 'string' ? item.label : this.staticPageResolver.resolveFooterTitle(item.label, lang); if (!item.route || !label) { return null; } return { id: `${item.type}-${label}`, label, route: item.route }; } private resolveLegacyItem(item: NavigationItemConfig, bootstrap: BootstrapConfig, lang: string): FooterResolvedItem | null { if (item.visible === false) { return null; } if (item.type === 'staticPage' && item.key) { const staticPage = this.staticPageResolver.resolveByKeyFromBootstrap(bootstrap, item.key, lang); if (!staticPage) { return null; } return { id: item.id, label: staticPage.title, route: staticPage.route }; } if (!item.route) { return null; } return { id: item.id, label: item.labelKey ?? item.id, route: item.route }; } private isGroupedFooter(footer: NavigationConfig['footer']): footer is FooterNavigationGroupConfig[] { return Array.isArray(footer) && footer.length > 0 && 'items' in footer[0]; } }