dvbooking/admin/src/app/components/menu/menu.ts
2025-11-20 09:30:35 +01:00

83 lines
2.5 KiB
TypeScript

import { Component, inject, input } from '@angular/core';
import { Router, RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
import { SafeHtmlPipe } from '../../pipes/safe-html-pipe';
export interface MenuItem {
id?: string;
menuText: string;
targetUrl?: string;
onClick?: (event: MouseEvent, item: MenuItem) => void;
roles?: string[];
children?: MenuItem[];
getStyleClass?: (item: MenuItem) => string;
isActive?: (item: MenuItem, router: Router) => boolean;
svgIcon?: string;
}
@Component({
selector: 'app-menu',
imports: [CommonModule, RouterModule, SafeHtmlPipe],
templateUrl: './menu.html',
styleUrl: './menu.css',
})
export class Menu {
title = input<string>();
// Use the input() function instead of the @Input() decorator.
// input.required makes sure that the menuItems array is always passed.
menuItems = input.required<MenuItem[]>();
// You can also provide a default value with input().
// In a real app, this would likely come from an authentication service.
userRoles = input<string[]>(['admin', 'user']);
// Use inject() for dependency injection instead of the constructor.
private router = inject(Router);
isItemVisible(item: MenuItem): boolean {
if (!item.roles || item.roles.length === 0) {
return true;
}
// Access the value of the signal by calling it as a function: this.userRoles()
return item.roles.some(role => this.userRoles().includes(role));
}
handleItemClick(event: MouseEvent, item: MenuItem): void {
if (item.onClick) {
item.onClick(event, item);
} else if (item.targetUrl) {
this.router.navigate([item.targetUrl]);
}
}
getItemStyleClass(item: MenuItem): string {
return item.getStyleClass ? item.getStyleClass(item) : '';
}
isItemActive(item: MenuItem): boolean {
if (item.isActive) {
return item.isActive(item, this.router);
}
if (item.targetUrl) {
// router.isActive is a boolean check, perfect for this use case.
return this.router.isActive(item.targetUrl, {
paths: 'exact',
queryParams: 'exact',
fragment: 'ignored',
matrixParams: 'ignored'
});
}
return false;
}
// Helper function to determine if a dropdown should be open by default
isSubMenuActive(item: MenuItem): boolean {
if (!item.children) {
return false;
}
// Recursively check if any child or grandchild is active
return item.children.some(child => this.isItemActive(child) || this.isSubMenuActive(child));
}
}