diff --git a/src/app/administration/layout/logged-user/logged-user.component.scss b/src/app/administration/layout/logged-user/logged-user.component.scss index 112e126..5aadf0f 100644 --- a/src/app/administration/layout/logged-user/logged-user.component.scss +++ b/src/app/administration/layout/logged-user/logged-user.component.scss @@ -36,6 +36,7 @@ transition: all 150ms; padding-top: 80px; background: $backColorMediumDark; + border: 2.5px solid $backColor; color: $foreColor; transition: all 150ms; opacity: 0; diff --git a/src/app/administration/layout/nav-bar/menu-builder.ts b/src/app/administration/layout/nav-bar/menu-builder.ts index 175021b..a6cbbd2 100644 --- a/src/app/administration/layout/nav-bar/menu-builder.ts +++ b/src/app/administration/layout/nav-bar/menu-builder.ts @@ -1,16 +1,49 @@ -import { faCalendarDays, faClock, faTicket } from '@fortawesome/free-solid-svg-icons'; +import { faCalendarDay, faCalendarDays, faClock, faTicket } from '@fortawesome/free-solid-svg-icons'; import { MenuItem, MenuSubItem } from './menu-items'; import { IconDefinition } from '@fortawesome/angular-fontawesome'; +import { inject } from '@angular/core'; +import { AuthService } from 'src/app/services/auth.service'; +import { AdminModeService } from 'src/app/services/adminMode.service'; export class MenuBuilder { - constructor() { } + readonly #auth = inject(AuthService); + readonly #adminMode = inject(AdminModeService); - build(): MenuItem[] { + #defaultMenu: MenuItem[] = [ + this.#getMenuItem('My events', 'my-events', faCalendarDay, () => this.getSubItemsByPath('my-events')), + ].filter(o => o); + + ticketsMenuItem: MenuItem = this.#getMenuItem('Tickets', 'tickets', faTicket, () => this.getSubItemsByPath('tickets')); + ticketGroupsMenuItem: MenuItem = this.#getMenuItem('Ticket groups', 'ticket_groups', faClock, () => this.getSubItemsByPath('ticket_groups')); + eventsMenuItem: MenuItem = this.#getMenuItem('Events', 'events', faCalendarDays, () => this.getSubItemsByPath('events')); + #adminMenu: MenuItem[] = [ + this.ticketsMenuItem, + this.ticketGroupsMenuItem, + this.eventsMenuItem, + ]; + + build(currentUrl: string = ''): MenuItem[] { + if (this.#adminMode.status()) { + // user is admin and should have access to all things + return this.#adminMenu.filter(o => o); + } + + // user has restricted access + let menu: MenuItem[] = []; + + // add menu item when user opened some page defaultly not in menu + for (let i = 0; i < this.#adminMenu.length; i++) { + const menuItem = this.#adminMenu[i]; + if (currentUrl.startsWith(`/${menuItem.link}`)) { + menu.push(menuItem); + } + } + + // return merged menu return [ - this.#getMenuItem('Tickets', 'tickets', faTicket, () => this.getTicketsSubItems()), - this.#getMenuItem('Ticket groups', 'ticket_groups', faClock, () => this.getSubItemsByPath('ticket_groups')), - this.#getMenuItem('Events', 'events', faCalendarDays, () => this.getSubItemsByPath('events')), + ...menu, + ...this.#defaultMenu, ].filter(o => o); } @@ -19,14 +52,10 @@ export class MenuBuilder { ): MenuSubItem[] { const result: MenuSubItem[] = []; result.push(new MenuSubItem('List', `/${path}/list`)); - result.push(new MenuSubItem('New', `/${path}/add`)); - return result; - } - getTicketsSubItems(): MenuSubItem[] { - const result: MenuSubItem[] = []; - result.push(new MenuSubItem('List', '/tickets/list')); - result.push(new MenuSubItem('New', '/tickets/add')); + if (this.#adminMode.status() || this.#auth.getScopes().includes(`${path}:edit`)) { + result.push(new MenuSubItem('New', `/${path}/add`)); + } return result; } diff --git a/src/app/administration/layout/nav-bar/nav-bar.component.ts b/src/app/administration/layout/nav-bar/nav-bar.component.ts index dcefe60..607b7d4 100644 --- a/src/app/administration/layout/nav-bar/nav-bar.component.ts +++ b/src/app/administration/layout/nav-bar/nav-bar.component.ts @@ -1,8 +1,13 @@ -import { Component, OnInit, inject } from '@angular/core'; +import { Component, DestroyRef, OnInit, inject } from '@angular/core'; import { MenuItem } from './menu-items'; import { MenuBuilder } from './menu-builder'; import { AuthService } from 'src/app/services/auth.service'; import { faBars, faChartLine, faSignOutAlt, faTimes, faUser } from '@fortawesome/free-solid-svg-icons'; +import { NavigationEnd, Router } from '@angular/router'; +import { filter } from 'rxjs'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { StorageService } from 'src/app/services/storage.service'; +import { StorageKeys } from 'src/app/tokens/storage.tokens'; @Component({ selector: 'app-nav-bar', @@ -12,6 +17,9 @@ import { faBars, faChartLine, faSignOutAlt, faTimes, faUser } from '@fortawesome }) export class NavBarComponent implements OnInit { readonly #authService = inject(AuthService); + readonly #router = inject(Router); + readonly #storageService = inject(StorageService); + readonly #destroyRef = inject(DestroyRef); dashboardItem = new MenuItem('Dashboard', 'dashboard', faChartLine); userProfileItem = new MenuItem('My profile', 'profile', faUser); @@ -26,12 +34,20 @@ export class NavBarComponent implements OnInit { ngOnInit(): void { this.menuOpen = history.state.navBarVisible ?? false; - this.availableItems = this.builder.build() - this.availableItems.unshift(this.dashboardItem); - this.availableItems.push( - this.userProfileItem, - this.logoutItem - ); + this.#rebuildMenu(this.#router.url); + + this.#router.events.pipe( + filter((event): event is NavigationEnd => event instanceof NavigationEnd), + takeUntilDestroyed(this.#destroyRef), + ).subscribe(event => { + this.#rebuildMenu(event.urlAfterRedirects); + }); + + this.#storageService.storageEvent$(StorageKeys.ADMIN_MODE).pipe( + takeUntilDestroyed(this.#destroyRef), + ).subscribe(() => { + this.#rebuildMenu(this.#router.url); + }); } toggle(): void { @@ -45,4 +61,13 @@ export class NavBarComponent implements OnInit { logout(): void { this.#authService.logout(); } + + #rebuildMenu(currentUrl: string): void { + this.availableItems = this.builder.build(currentUrl); + this.availableItems.unshift(this.dashboardItem); + this.availableItems.push( + this.userProfileItem, + this.logoutItem + ); + } } diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index d8bf00d..42f0274 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -15,6 +15,30 @@ import { EventsFormComponent } from './administration/events/form/events-form.co import { authGuard } from './guards/auth.guard'; import { logoutGuard } from './guards/logout.guard'; +let eventsChildren: Routes = [ + { + path: '', + pathMatch: 'full', + redirectTo: 'list', + }, + { + path: 'list', + component: EventsListComponent + }, + { + path: 'add', + component: EventsFormComponent + }, + { + path: 'edit/:id', + component: EventsFormComponent + }, + { + path: 'detail/:id', + component: EventsFormComponent + }, +]; + export let APP_ROUTES: Routes = [ { path: '', @@ -96,31 +120,13 @@ export let APP_ROUTES: Routes = [ } ] }, + { + path: 'my-events', + children: eventsChildren, + }, { path: 'events', - children: [ - { - path: '', - pathMatch: 'full', - redirectTo: 'list', - }, - { - path: 'list', - component: EventsListComponent - }, - { - path: 'add', - component: EventsFormComponent - }, - { - path: 'edit/:id', - component: EventsFormComponent - }, - { - path: 'detail/:id', - component: EventsFormComponent - }, - ] + children: eventsChildren, }, { path: '**', diff --git a/src/app/components/user-info/user-info.component.html b/src/app/components/user-info/user-info.component.html index b156776..00abee6 100644 --- a/src/app/components/user-info/user-info.component.html +++ b/src/app/components/user-info/user-info.component.html @@ -2,6 +2,11 @@