feat: add Administration section to sidebar with role-gated Member/User nav
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -35,6 +35,16 @@
|
|||||||
{{ item.text }}
|
{{ item.text }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Administration (role-guarded) -->
|
||||||
|
<div class="nav-section" *ngIf="showAdminSection">
|
||||||
|
<h4>Administration</h4>
|
||||||
|
<button *ngFor="let item of adminNavItems" kendoButton
|
||||||
|
[fillMode]="item.active ? 'solid' : 'flat'" [themeColor]="item.active ? 'primary' : 'base'"
|
||||||
|
[svgIcon]="item.icon" class="nav-button" (click)="navigateTo(item.path)">
|
||||||
|
{{ item.text }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</kendo-drawer-content>
|
</kendo-drawer-content>
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Router, NavigationEnd } from '@angular/router';
|
import { Router, NavigationEnd, RouterModule } from '@angular/router';
|
||||||
import { LayoutModule } from '@progress/kendo-angular-layout';
|
import { LayoutModule } from '@progress/kendo-angular-layout';
|
||||||
import { ButtonsModule } from '@progress/kendo-angular-buttons';
|
import { ButtonsModule } from '@progress/kendo-angular-buttons';
|
||||||
import { IconsModule } from '@progress/kendo-angular-icons';
|
import { IconsModule } from '@progress/kendo-angular-icons';
|
||||||
import { SVGIcon, homeIcon, calendarIcon, userIcon } from '@progress/kendo-svg-icons';
|
import { SVGIcon, homeIcon, calendarIcon, userIcon, groupIcon } from '@progress/kendo-svg-icons';
|
||||||
import { LayoutService } from '../../../../layout/services/layout.service';
|
import { LayoutService } from '../../../../layout/services/layout.service';
|
||||||
|
import { AuthService, UserInfo } from '../../../../shared/services/auth.service';
|
||||||
import { Subject, takeUntil, filter } from 'rxjs';
|
import { Subject, takeUntil, filter } from 'rxjs';
|
||||||
|
|
||||||
interface NavItem {
|
interface NavItem {
|
||||||
@@ -20,6 +21,7 @@ interface NavItem {
|
|||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
RouterModule,
|
||||||
LayoutModule,
|
LayoutModule,
|
||||||
ButtonsModule,
|
ButtonsModule,
|
||||||
IconsModule
|
IconsModule
|
||||||
@@ -58,11 +60,19 @@ export class UserNavbarComponent implements OnInit, OnDestroy {
|
|||||||
{ text: 'Support', icon: this.supportIcon, path: '/user-portal/support' }
|
{ text: 'Support', icon: this.supportIcon, path: '/user-portal/support' }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public adminNavItems: NavItem[] = [
|
||||||
|
{ text: 'Members', icon: groupIcon, path: '/user-portal/admin/members' },
|
||||||
|
{ text: 'Users', icon: userIcon, path: '/user-portal/admin/users' },
|
||||||
|
];
|
||||||
|
|
||||||
|
public showAdminSection = false;
|
||||||
|
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public layoutService: LayoutService,
|
public layoutService: LayoutService,
|
||||||
private router: Router
|
private router: Router,
|
||||||
|
private authService: AuthService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@@ -78,6 +88,11 @@ export class UserNavbarComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
// Set initial active state
|
// Set initial active state
|
||||||
this.updateActiveStates(this.router.url);
|
this.updateActiveStates(this.router.url);
|
||||||
|
|
||||||
|
// Show Administration section for super_admin or secretary
|
||||||
|
this.authService.currentUser$.pipe(takeUntil(this.destroy$)).subscribe(user => {
|
||||||
|
this.showAdminSection = !!user?.roles?.some(r => r === 'super_admin' || r === 'secretary');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
@@ -92,11 +107,11 @@ export class UserNavbarComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
private updateActiveStates(currentUrl: string): void {
|
private updateActiveStates(currentUrl: string): void {
|
||||||
// Reset all active states
|
// Reset all active states
|
||||||
[...this.mainNavItems, ...this.managementNavItems, ...this.supportNavItems]
|
[...this.mainNavItems, ...this.managementNavItems, ...this.supportNavItems, ...this.adminNavItems]
|
||||||
.forEach(item => item.active = false);
|
.forEach(item => item.active = false);
|
||||||
|
|
||||||
// Set active state for current route
|
// Set active state for current route
|
||||||
const activeItem = [...this.mainNavItems, ...this.managementNavItems, ...this.supportNavItems]
|
const activeItem = [...this.mainNavItems, ...this.managementNavItems, ...this.supportNavItems, ...this.adminNavItems]
|
||||||
.find(item => currentUrl.startsWith(item.path));
|
.find(item => currentUrl.startsWith(item.path));
|
||||||
|
|
||||||
if (activeItem) {
|
if (activeItem) {
|
||||||
|
|||||||
@@ -79,29 +79,27 @@ export class UserPortalComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updatePageTitle(): void {
|
private updatePageTitle(): void {
|
||||||
const url = this.router.url;
|
const url = this.router.url;
|
||||||
const segments = url.split('/').filter(segment => segment);
|
const segments = url.split('/').filter(s => s);
|
||||||
|
const key = segments.length >= 3
|
||||||
if (segments.length >= 2) {
|
? `${segments[1]}/${segments[2]}` // e.g. 'admin/members'
|
||||||
const page = segments[1];
|
: segments[1] ?? '';
|
||||||
this.currentPageTitle = this.getPageTitle(page);
|
this.currentPageTitle = this.getPageTitle(key);
|
||||||
} else {
|
|
||||||
this.currentPageTitle = 'Dashboard';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getPageTitle(page: string): string {
|
private getPageTitle(page: string): string {
|
||||||
const titles: { [key: string]: string } = {
|
const titles: { [key: string]: string } = {
|
||||||
'dashboard': 'Dashboard',
|
'dashboard': 'Dashboard',
|
||||||
'transactions': 'Escrow Transactions',
|
'transactions': 'Escrow Transactions',
|
||||||
'tasks': 'Tasks & Todos',
|
'tasks': 'Tasks & Todos',
|
||||||
'contacts': 'Contacts',
|
'contacts': 'Contacts',
|
||||||
'documents': 'Documents',
|
'documents': 'Documents',
|
||||||
'messages': 'Messages',
|
'messages': 'Messages',
|
||||||
'settings': 'Settings'
|
'settings': 'Settings',
|
||||||
|
'admin/members': 'Member Management',
|
||||||
|
'admin/users': 'User Management',
|
||||||
};
|
};
|
||||||
|
return titles[page] ?? 'Dashboard';
|
||||||
return titles[page] || 'Dashboard';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleSidebar(): void {
|
toggleSidebar(): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user