Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
transition: all 150ms;
padding-top: 80px;
background: $backColorMediumDark;
border: 2.5px solid $backColor;
color: $foreColor;
transition: all 150ms;
opacity: 0;
Expand Down
53 changes: 40 additions & 13 deletions src/app/administration/layout/nav-bar/menu-builder.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,47 @@
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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proč ten filter?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To jsem si říkal taky, má to odjebat nevalidní objekty jako null, atd.


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[] = [];

for (let i = 0; i < this.#adminMenu.length; i++) {
const menuItem = this.#adminMenu[i];
if (currentUrl.startsWith(`/${menuItem.link}`)) {
menu.push(menuItem);
}
}
Comment on lines +26 to +41
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okomentovat, ale možná to nechápu, protože nevím, jaká je architektura toho menu buildingu.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Přidal jsem komentáře, snad je to teď lepší.


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);
}

Expand All @@ -19,14 +50,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;
}

Expand Down
39 changes: 32 additions & 7 deletions src/app/administration/layout/nav-bar/nav-bar.component.ts
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -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);
Expand All @@ -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 {
Expand All @@ -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
);
}
}
52 changes: 29 additions & 23 deletions src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: '',
Expand Down Expand Up @@ -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: '**',
Expand Down
5 changes: 5 additions & 0 deletions src/app/components/user-info/user-info.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
<div class="info" label="Scopes in token">{{ authService.getScopes() }}</div>
<div class="info" label="Access token expires on">{{ get_access_token_expiration() }} ‒ {{ time_to_access_token_expire }}</div>
<div class="info" label="Refresh token expires on">{{ refresh_token_expire() }} ‒ {{ time_to_refresh_token_expire }}
<div style="display: inline-flex;">
<div class="info" label="Admin mode">{{ adminModeService.status() ? "ON" : "OFF" }}</div>
<button (click)="adminModeService.toggle()" style="margin: auto 5px; padding: 0px 10px; min-width: 0px;">
<fa-icon [icon]="toggleIcon"></fa-icon>
</button>
</div>

@if (usersService.user.isLoading()) {
Expand Down
5 changes: 5 additions & 0 deletions src/app/components/user-info/user-info.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Component, computed, booleanAttribute, inject, input, OnDestroy, OnInit } from "@angular/core";
import { faRepeat } from "@fortawesome/free-solid-svg-icons";
import { AdminModeService } from "src/app/services/adminMode.service";
import { AuthService } from "src/app/services/auth.service";
import { UsersService } from "src/app/services/users.service";

Expand All @@ -11,6 +13,9 @@ import { UsersService } from "src/app/services/users.service";
export class UserInfoComponent implements OnInit, OnDestroy {
protected readonly authService = inject(AuthService);
protected readonly usersService = inject(UsersService);
protected readonly adminModeService = inject(AdminModeService);

protected readonly toggleIcon = faRepeat;

readonly show_favorite_events = input(true, {
transform: booleanAttribute,
Expand Down
42 changes: 42 additions & 0 deletions src/app/services/adminMode.service.ts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hele, toto Ti celé přepíšu doma na komplu... :)

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { inject, Injectable } from '@angular/core';
import { StorageService } from './storage.service';
import { LoggingService } from './logging.service';
import { StorageKeys } from '../tokens/storage.tokens';

@Injectable({
providedIn: 'root',
})
export class AdminModeService {
readonly #logging = inject(LoggingService);
readonly #storageService = inject(StorageService);

constructor() {
if (this.#storageService.get(StorageKeys.ADMIN_MODE) == null) {
this.off(true);
this.#logging.log("adminMode", `Set default initial value. Current value: ${this.status()}.`)
}
}

status(): boolean {
return this.#storageService.get(StorageKeys.ADMIN_MODE) == String(true);
}

on(silent: boolean = false): void {
this.#storageService.set(StorageKeys.ADMIN_MODE, String(true));
if (!silent) {
this.#logging.log("adminMode", `Force ON. Current value: ${this.status()}.`);
}
}

off(silent: boolean = false): void {
this.#storageService.set(StorageKeys.ADMIN_MODE, String(false));
if (!silent) {
this.#logging.log("adminMode", `Force OFF. Current value: ${this.status()}.`);
}
}

toggle(): void {
this.#storageService.set(StorageKeys.ADMIN_MODE, String(!this.status()));
this.#logging.log("adminMode", `Toggle. Current value: ${this.status()}.`);
}
}
4 changes: 2 additions & 2 deletions src/app/services/logging.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// import { Injectable, isDevMode } from "@angular/core";
import { Injectable } from "@angular/core";

const interestedFields = ["auth", "ws", "swUpdate", "user", "dashboardEventLoad", "userInfo"] as const;
const interestedFields = ["auth", "ws", "swUpdate", "user", "dashboardEventLoad", "userInfo", "adminMode"] as const;

export type Fields = typeof interestedFields[number];

Expand All @@ -13,7 +13,7 @@ export type Fields = typeof interestedFields[number];
export class LoggingService {
readonly #output = true;
// readonly #output = !isDevMode();
readonly #interestedFields = new Set<Fields>(["auth", "ws", "swUpdate", "user", "dashboardEventLoad", "userInfo"]);
readonly #interestedFields = new Set<Fields>(["auth", "ws", "swUpdate", "user", "dashboardEventLoad", "userInfo", "adminMode"]);

log(field: Fields, message?: any, ...optionalParams: any[]) {
if (this.#output && this.#interestedFields.has(field)) {
Expand Down
1 change: 1 addition & 0 deletions src/app/tokens/storage.tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const StorageKeys = {
THEME: "theme",
BROWSER_CORE_CHECK: "browser_core_check",
SUDO_PASSWORD_MODE: "sudo_password_mode",
ADMIN_MODE: "admin_mode",
} as const;

// TODO
Expand Down