tin-spa 20.4.9 → 20.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4310,13 +4310,17 @@ class AccountingService {
4310
4310
  this.accountsTableConfig = {
4311
4311
  showFilter: true,
4312
4312
  pageSizes: [5, 10, 25, 50],
4313
- minColumns: ['name', 'type', 'balance'],
4313
+ minColumns: ['name', 'typeName', 'balanceDisplay'],
4314
4314
  flatButtons: true,
4315
4315
  columns: [
4316
4316
  { name: 'name', type: 'button', detailsConfig: this.accountDetailsConfig },
4317
- { name: 'typeName', type: 'text', alias: 'Type' },
4318
- { name: 'currencyCode', type: 'text', alias: 'CCY' }, // Changed: Added currency code column for multi-currency support
4319
- { name: 'balance', type: 'money' }
4317
+ { name: 'typeName', type: 'text', alias: 'Type',
4318
+ icons: [
4319
+ { name: 'payments', color: '#4CAF50', condition: (x) => x.includeInCashTotal, tip: 'Included in Cash Total' },
4320
+ { name: 'account_balance', color: '#2196F3', condition: (x) => x.includeInBankTotal, tip: 'Included in Bank Total' },
4321
+ ]
4322
+ },
4323
+ { name: 'balanceDisplay', type: 'text', alias: 'Balance' }, // Changed: Pre-formatted with currency prefix (e.g. "USD 1,964.21")
4320
4324
  ],
4321
4325
  buttons: [
4322
4326
  this.accountCreateButton,
@@ -9538,11 +9542,11 @@ class NavMenuComponent {
9538
9542
  return !this.isMiniSidebar || this.isMiniHovered;
9539
9543
  }
9540
9544
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: NavMenuComponent, deps: [{ token: i1$2.Router }, { token: AuthService }, { token: StorageService }, { token: NotificationsService }, { token: i1$3.BreakpointObserver }, { token: DataServiceLib }, { token: i1.MatDialog }, { token: SubscriptionService }], target: i0.ɵɵFactoryTarget.Component }); }
9541
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: NavMenuComponent, isStandalone: false, selector: "spa-nav-menu", inputs: { appConfig: "appConfig", footer: "footer" }, host: { listeners: { "window:scroll": "onWindowScroll()" } }, ngImport: i0, template: "<header *ngIf=\"loggedin && dataService.appConfig.navigation == 'top'\">\r\n\r\n <!-- Changed: Removed mb-3 class to eliminate gap between toolbar and content -->\r\n <nav class=\"toolbar navbar navbar-expand-sm navbar-toggleable-sm navbar-light border-bottom box-shadow\" style=\"padding-right: 10px;\">\r\n\r\n\r\n <div class=\"container-fluid\" style=\"padding-right: 0px;\">\r\n\r\n <img *ngIf=\"appConfig.logo!=''\" [src]=\"appConfig.logo\" style=\"height: 50px; margin-right: 2em\" />\r\n\r\n <div>\r\n <!-- <div style=\"font-size: 20px;\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant && tenantName\" style=\"font-size: 12px;\">\r\n {{tenantName}}\r\n </div> -->\r\n\r\n <div *ngIf=\"!dataService.appConfig.multitenant\" style=\"font-size: 22px;\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant\" style=\"font-size: 20px; ; font-weight: 400;\" [ngStyle]=\"{'margin-top': dataService.appConfig.multitenant ? '12px' : ''}\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant && tenantName\" style=\"font-size: 12px; margin-bottom: 5px;\">\r\n {{tenantName}}\r\n </div>\r\n\r\n </div>\r\n\r\n\r\n\r\n <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\".navbar-collapse\" aria-label=\"Toggle navigation\" [attr.aria-expanded]=\"isExpanded\" (click)=\"toggle()\">\r\n <span class=\"navbar-toggler-icon\"></span>\r\n </button>\r\n\r\n <div *ngIf=\"myRole\" class=\" navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse stack-top\" style=\"margin-right: 0px;\" [ngClass]=\"{ show: isExpanded, navitems: isExpanded }\" >\r\n\r\n <button mat-icon-button (click)=\"logoff()\" > <mat-icon>logout</mat-icon> </button>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant\">\r\n\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/tenant-settings')\" > <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon> </button>\r\n\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/bug')\"> <mat-icon >support_agent</mat-icon> </button>\r\n\r\n <!-- <button mat-icon-button (click)=\"redirectTo('home/admin/notifications')\"> <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon> </button> -->\r\n </div>\r\n\r\n\r\n <button id=\"btnUser\" mat-button [matMenuTriggerFor]=\"profileMenu\" ><mat-icon style=\"font-size: 24px;\">account_circle</mat-icon> &nbsp;{{loggedUserFullName}}</button>\r\n\r\n <mat-menu #profileMenu=\"matMenu\">\r\n <button id=\"btnProfile\" mat-menu-item (click)=\"redirectTo('home/user/profile')\" >Profile</button>\r\n <button id=\"btnLogOff\" mat-menu-item (click)=\"logoff()\">Log Off</button>\r\n </mat-menu>\r\n\r\n <div *ngFor=\"let item of reversedCapItems\">\r\n\r\n <!-- Menu Item \u2014 Added: isFeatureAllowed check for plan-based gating -->\r\n <button id=\"btnMenu\" *ngIf=\"myRole[item.name] && !item.capSubItems && item.showMenu && isFeatureAllowed(item)\" mat-button (click)=\"redirectTo(item.link)\">{{item.display}}</button>\r\n\r\n <!-- Menu Item with Sub items ignored \u2014 Added: isFeatureAllowed check -->\r\n <button id=\"btnMenu\" *ngIf=\"myRole[item.name] && item.capSubItems && item.showMenu && item.ignoreSubsDisplay && isFeatureAllowed(item)\" mat-button (click)=\"redirectTo(item.link)\">{{item.display}}</button>\r\n\r\n <!-- Menu Item with Sub items to display \u2014 Added: isFeatureAllowed check -->\r\n <button id=\"btnMenu\" *ngIf=\"myRole[item.name] && item.capSubItems && item.showMenu && !item.ignoreSubsDisplay && isFeatureAllowed(item)\" mat-button [matMenuTriggerFor]=\"adminMenu\">{{item.display}}</button>\r\n\r\n\r\n <!-- Sub Menu Items \u2014 Added: isFeatureAllowed check on sub-items -->\r\n <mat-menu #adminMenu=\"matMenu\">\r\n\r\n <div *ngFor=\"let subItem of item.capSubItems\">\r\n\r\n <button *ngIf=\"myRole[subItem.name] && subItem.showMenu && isFeatureAllowed(subItem)\" mat-menu-item (click)=\"redirectTo(subItem.link)\">{{subItem.display}}</button>\r\n\r\n </div>\r\n\r\n </mat-menu>\r\n\r\n </div>\r\n\r\n </div>\r\n\r\n\r\n </div>\r\n\r\n </nav>\r\n\r\n</header>\r\n\r\n<!-- Changed: Removed top/bottom padding to eliminate gaps, but kept left/right padding for content spacing -->\r\n<div class=\"container-fluid tin-bg-image\" *ngIf=\"dataService.appConfig.navigation == 'top'\" style=\"padding: 12px 12px; margin: 0;\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n</div>\r\n\r\n\r\n\r\n\r\n\r\n\r\n<!-- SIDE -->\r\n<mat-toolbar class=\"tin-bg-image-toolbar\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\" style=\"padding: 0px 8px;\">\r\n\r\n <button mat-icon-button (click)=\"toggle()\" matTooltip=\"Menu\">\r\n <mat-icon>menu</mat-icon>\r\n </button>\r\n\r\n <img [src]=\"dataService.appConfig.logo\" style=\"height: 50px;\" />\r\n\r\n <div style=\"padding-left: 10px; \">\r\n\r\n <div style=\"font-size: 22px; font-weight: 400;\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <!-- <div style=\"font-size: 20px; height: 25px; font-weight: 400;\" [ngStyle]=\"{'margin-top': dataService.appConfig.multitenant ? '12px' : ''}\">\r\n {{appConfig.appName}}\r\n </div> -->\r\n\r\n <!-- <div *ngIf=\"dataService.appConfig.multitenant && tenantName\" style=\"font-size: 12px; margin-bottom: 5px;\">\r\n {{tenantName}}\r\n </div> -->\r\n\r\n </div>\r\n\r\n\r\n\r\n <span class=\"toolbar-item-spacer\"></span>\r\n\r\n <!-- buttons -->\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant\" style=\"display: flex; align-items: center;\">\r\n\r\n <!-- <label style=\"font-size: 14px;\">Hi, {{loggedUserFullName}}</label> -->\r\n\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/tenant-settings')\" matTooltip=\"Organisation Settings\">\r\n <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon>\r\n </button>\r\n <label style=\"font-size: 14px;margin-right: 20px;\">{{tenantName}}</label>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/bug')\" matTooltip=\"Support\">\r\n <mat-icon >help</mat-icon>\r\n </button>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/notifications')\" matTooltip=\"Notifications\">\r\n <mat-icon [matBadge]=\"notificationCount$ | async\" [matBadgeHidden]=\"(notificationCount$ | async) === 0\" matBadgeColor=\"warn\" matBadgeSize=\"small\">notifications</mat-icon>\r\n </button>\r\n\r\n </div>\r\n\r\n\r\n\r\n <button mat-icon-button matTooltip=\"My Account\" [matMenuTriggerFor]=\"userAccountMenu\"><mat-icon>account_circle</mat-icon></button>\r\n <label style=\"font-size: 14px;\">{{loggedUserFullName}}</label>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"logoff()\" matTooltip=\"Signout\">\r\n <mat-icon>logout</mat-icon>\r\n </button>\r\n\r\n\r\n <!-- my account menu -->\r\n <mat-menu #userAccountMenu [overlapTrigger]=\"false\" yPosition=\"below\">\r\n\r\n\r\n <button mat-menu-item routerLink=\"home/user/profile\">\r\n <mat-icon>person</mat-icon><span>Profile</span>\r\n </button>\r\n\r\n <button mat-menu-item routerLink=\"home/admin/bug\" *ngIf=\"dataService.appConfig.multitenant && smallScreen\">\r\n <mat-icon>help</mat-icon> <span>Help</span>\r\n </button>\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <button mat-menu-item (click)=\"logoff()\">\r\n <mat-icon>logout</mat-icon>Logout\r\n </button>\r\n\r\n </mat-menu>\r\n\r\n</mat-toolbar>\r\n\r\n\r\n\r\n\r\n<mat-sidenav-container class=\"app-container\" [hasBackdrop]=\"smallScreen\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\">\r\n\r\n <mat-sidenav #sidenav [mode]=\"smallScreen ? 'over' : 'side'\" [class.mat-elevation-z4]=\"true\" [opened]=\"isExpanded\" class=\"app-sidenav side-color\" style=\"height: 100%;\"\r\n [ngStyle]=\"{'width': dataService.appConfig.navWidth}\">\r\n <mat-nav-list >\r\n\r\n <ng-container *ngFor=\"let cap of dataService.appConfig.capItems\" >\r\n\r\n <!-- Menu item \u2014 Added: isFeatureAllowed check for plan-based gating -->\r\n <mat-list-item [routerLink]=\"cap.link\" *ngIf=\"myRole[cap.name] && cap.showMenu && (!cap.capSubItems || cap.capSubItems && cap.ignoreSubsDisplay) && isFeatureAllowed(cap)\" style=\"height: 40px;font-size: 15px;\"\r\n (click)=\"smallScreen ? toggle() : null\">\r\n <mat-icon [ngStyle]=\"{'color': cap.color}\" style=\"margin-right: 5px;\">{{cap.icon}}</mat-icon>{{cap.display}}\r\n </mat-list-item>\r\n\r\n <!-- Menu With Sub items \u2014 Added: isFeatureAllowed check -->\r\n <mat-expansion-panel class=\"side-color\" [class.mat-elevation-z0]=\"true\" *ngIf=\"myRole[cap.name] && cap.showMenu && cap.capSubItems && !cap.ignoreSubsDisplay && isFeatureAllowed(cap)\">\r\n\r\n <mat-expansion-panel-header style=\"height: 40px;padding-left: 15px;\">\r\n <mat-icon [ngStyle]=\"{'color': cap.color}\" style=\"margin-right: 5px;\">{{cap.icon != 'navigate_next' ? cap.icon : 'fiber_manual_record' }}</mat-icon>{{cap.display}}\r\n </mat-expansion-panel-header>\r\n\r\n <!-- Sub items - Changed: Use ng-container to avoid blank spaces for hidden items -->\r\n <mat-nav-list>\r\n <ng-container *ngFor=\"let capSub of getSubItems(cap)\">\r\n <mat-list-item [routerLink]=\"capSub.link\" style=\"height: 30px; font-size: 15px; padding-left: 4px; padding-right: 10px; margin-bottom: 5px;\" (click)=\"smallScreen ? toggle() : null\" *ngIf=\"myRole[capSub.name] && capSub.showMenu && isFeatureAllowed(capSub)\" [matTooltip]=\"capSub.display\" matTooltipPosition=\"right\">\r\n <mat-icon [ngStyle]=\"{'color': capSub.color}\" style=\"margin-right: 5px;\">{{capSub.icon}}</mat-icon>{{capSub.display}}\r\n </mat-list-item>\r\n </ng-container>\r\n </mat-nav-list>\r\n\r\n </mat-expansion-panel>\r\n\r\n </ng-container>\r\n\r\n </mat-nav-list>\r\n </mat-sidenav>\r\n\r\n\r\n\r\n <mat-sidenav-content class=\"tin-bg-image\" style=\"padding: 0px 12px;\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\">\r\n <hr style=\"margin-top: 0px;\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n </mat-sidenav-content>\r\n\r\n</mat-sidenav-container>\r\n\r\n\r\n<!-- footer -->\r\n<div class=\"tin-center\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\">\r\n <label style=\"text-align: center; font-size: 12px;\">&copy; {{nowDate | date : 'yyyy'}} <a color=\"primary\" class=\"terms-link\" [href]=\"appConfig.siteUrl\" target=\"_blank\">{{footer}}</a> | <a color=\"primary\" class=\"terms-link\" style=\"cursor: pointer;\" (click)=\"openTerms()\">Terms</a> | <a color=\"primary\" class=\"terms-link\" style=\"cursor: pointer;\" (click)=\"openPrivacy()\">Privacy Policy</a></label>\r\n</div>\r\n\r\n\r\n<div class=\"tin-bg-image\" *ngIf=\"!loggedin && dataService.appConfig.navigation == 'side'\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n</div>\r\n\r\n\r\n<!-- SIDE-MODERN -->\r\n\r\n<!-- Changed: Side-modern navigation layout -->\r\n<div class=\"sm-layout\"\r\n *ngIf=\"loggedin && dataService.appConfig.navigation == 'side-modern'\"\r\n [class.sm-mini]=\"isMiniSidebar && !isMiniHovered\"\r\n [class.sm-mini-hovered]=\"isMiniSidebar && isMiniHovered\"\r\n [class.sm-mobile-open]=\"smallScreen && isExpanded\">\r\n\r\n <!-- Sidebar -->\r\n <aside class=\"sm-sidebar\"\r\n (mouseenter)=\"onMiniMouseEnter()\"\r\n (mouseleave)=\"onMiniMouseLeave()\">\r\n\r\n <!-- Background layers -->\r\n <div class=\"sm-sidebar-bg\">\r\n <div class=\"sm-sidebar-bg-image\" *ngIf=\"appConfig.navImage\" [ngStyle]=\"{'background-image': 'url(' + appConfig.navImage + ')'}\"></div>\r\n <div class=\"sm-sidebar-bg-overlay\" [ngStyle]=\"{'background-color': appConfig.navColor}\"></div>\r\n </div>\r\n\r\n <!-- Sidebar content -->\r\n <div class=\"sm-sidebar-content\">\r\n\r\n <!-- Brand -->\r\n <div class=\"sm-brand\">\r\n <img *ngIf=\"appConfig.logo\" [src]=\"appConfig.logo\" alt=\"logo\" />\r\n <span class=\"sm-brand-name\">{{appConfig.appName}}</span>\r\n </div>\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Profile -->\r\n <div class=\"sm-profile\">\r\n <mat-icon class=\"sm-profile-icon\">account_circle</mat-icon>\r\n <div class=\"sm-profile-info\">\r\n <div class=\"sm-profile-name\">{{loggedUserFullName}}</div>\r\n <div class=\"sm-profile-role\">{{tenantName || 'User'}}</div>\r\n </div>\r\n </div>\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Scrollable menu -->\r\n <div class=\"sm-menu-scroll\">\r\n\r\n <ng-container *ngFor=\"let cap of dataService.appConfig.capItems\">\r\n\r\n <!-- Simple menu item (no sub-items or ignoring sub display) \u2014 Added: isFeatureAllowed check -->\r\n <div *ngIf=\"myRole[cap.name] && cap.showMenu && (!cap.capSubItems || cap.ignoreSubsDisplay) && isFeatureAllowed(cap)\"\r\n class=\"sm-menu-item\"\r\n [class.sm-active]=\"isActiveRoute(cap.link)\"\r\n (click)=\"modernNavigate(cap.link)\">\r\n <mat-icon class=\"sm-menu-icon\">{{cap.icon != 'navigate_next' ? cap.icon : 'dashboard'}}</mat-icon>\r\n <span class=\"sm-menu-text\">{{cap.display}}</span>\r\n </div>\r\n\r\n <!-- Parent menu item with sub-items \u2014 Added: isFeatureAllowed check -->\r\n <ng-container *ngIf=\"myRole[cap.name] && cap.showMenu && cap.capSubItems && !cap.ignoreSubsDisplay && isFeatureAllowed(cap)\">\r\n\r\n <!-- Parent item (toggles sub-menu) -->\r\n <div class=\"sm-menu-item\"\r\n [class.sm-active]=\"isParentActive(cap) && !isMenuOpen(cap.name)\"\r\n (click)=\"toggleModernMenu(cap.name)\">\r\n <mat-icon class=\"sm-menu-icon\">{{cap.icon != 'navigate_next' ? cap.icon : 'dashboard'}}</mat-icon>\r\n <span class=\"sm-menu-text\">{{cap.display}}</span>\r\n <mat-icon class=\"sm-caret\" [class.sm-caret-open]=\"isMenuOpen(cap.name)\">expand_more</mat-icon>\r\n </div>\r\n\r\n <!-- Sub-menu container (animated) -->\r\n <div class=\"sm-submenu\" [class.sm-submenu-open]=\"isMenuOpen(cap.name)\">\r\n <ng-container *ngFor=\"let sub of getSubItems(cap)\">\r\n <div *ngIf=\"myRole[sub.name] && sub.showMenu && isFeatureAllowed(sub)\"\r\n class=\"sm-submenu-item\"\r\n [class.sm-active]=\"isActiveRoute(sub.link)\"\r\n (click)=\"modernNavigate(sub.link)\">\r\n <mat-icon *ngIf=\"sub.icon && sub.icon != 'navigate_next'\" class=\"sm-sub-icon\">{{sub.icon}}</mat-icon>\r\n <span *ngIf=\"!sub.icon || sub.icon == 'navigate_next'\" class=\"sm-initials\">{{getInitials(sub.display)}}</span>\r\n <span class=\"sm-menu-text\">{{sub.display}}</span>\r\n </div>\r\n </ng-container>\r\n </div>\r\n\r\n </ng-container>\r\n\r\n </ng-container>\r\n\r\n </div>\r\n\r\n </div>\r\n </aside>\r\n\r\n <!-- Mobile backdrop -->\r\n <div class=\"sm-backdrop\" (click)=\"isExpanded = false\"></div>\r\n\r\n <!-- Main content -->\r\n <div class=\"sm-main\">\r\n\r\n <!-- Top bar - Changed: Added scroll class for frosted glass effect -->\r\n <div class=\"sm-topbar\" [class.sm-topbar-scrolled]=\"topbarScrolled\">\r\n <button mat-icon-button (click)=\"smallScreen ? toggle() : toggleMiniSidebar()\" matTooltip=\"Menu\">\r\n <mat-icon>menu</mat-icon>\r\n </button>\r\n\r\n <!-- Changed: Mobile branding - show logo + app name when sidebar is hidden on small screens -->\r\n <img *ngIf=\"smallScreen && appConfig.logo\" [src]=\"appConfig.logo\" alt=\"logo\" class=\"sm-topbar-logo\" />\r\n <span *ngIf=\"smallScreen\" class=\"sm-topbar-brand\">{{appConfig.appName}}</span>\r\n\r\n <span class=\"sm-topbar-spacer\"></span>\r\n\r\n <!-- Multitenant buttons -->\r\n <div *ngIf=\"dataService.appConfig.multitenant\" style=\"display: flex; align-items: center;\">\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/tenant-settings')\" matTooltip=\"Organisation Settings\">\r\n <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon>\r\n </button>\r\n <span class=\"sm-topbar-label\">{{tenantName}}</span>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/bug')\" matTooltip=\"Support\">\r\n <mat-icon>help</mat-icon>\r\n </button>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/notifications')\" matTooltip=\"Notifications\">\r\n <mat-icon [matBadge]=\"notificationCount$ | async\" [matBadgeHidden]=\"(notificationCount$ | async) === 0\" matBadgeColor=\"warn\" matBadgeSize=\"small\">notifications</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Profile menu -->\r\n <button mat-icon-button matTooltip=\"My Account\" [matMenuTriggerFor]=\"smProfileMenu\">\r\n <mat-icon>account_circle</mat-icon>\r\n </button>\r\n <span class=\"sm-topbar-label\">{{loggedUserFullName}}</span>\r\n\r\n <mat-menu #smProfileMenu=\"matMenu\" [overlapTrigger]=\"false\" yPosition=\"below\">\r\n <button mat-menu-item routerLink=\"home/user/profile\">\r\n <mat-icon>person</mat-icon><span>Profile</span>\r\n </button>\r\n <button mat-menu-item routerLink=\"home/admin/bug\" *ngIf=\"dataService.appConfig.multitenant && smallScreen\">\r\n <mat-icon>help</mat-icon><span>Help</span>\r\n </button>\r\n <mat-divider></mat-divider>\r\n <button mat-menu-item (click)=\"logoff()\">\r\n <mat-icon>logout</mat-icon>Logout\r\n </button>\r\n </mat-menu>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"logoff()\" matTooltip=\"Signout\">\r\n <mat-icon>logout</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Page content - Changed: Replaced tin-bg-image with sm-content modern texture -->\r\n <div class=\"sm-content\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"sm-footer\">\r\n &copy; {{nowDate | date : 'yyyy'}} <a [href]=\"appConfig.siteUrl\" target=\"_blank\">{{footer}}</a> | <a (click)=\"openTerms()\">Terms</a> | <a (click)=\"openPrivacy()\">Privacy Policy</a>\r\n </div>\r\n\r\n </div>\r\n\r\n</div>\r\n\r\n<!-- Not logged in fallback for side-modern -->\r\n<div class=\"tin-bg-image\" *ngIf=\"!loggedin && dataService.appConfig.navigation == 'side-modern'\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n</div>", styles: ["a.navbar-brand{white-space:normal;text-align:center;word-break:break-all}html{font-size:14px}.box-shadow{box-shadow:0 .25rem .75rem #0000000d}.toolbar-item-spacer{flex:1 1 auto}.toolbar{height:60px;display:flex;align-items:center;background-color:#03a;color:#fff;margin-bottom:0!important}.toolbar button,.toolbar .mat-mdc-button,.toolbar .mat-mdc-icon-button{color:#fff!important}.toolbar mat-icon{color:#fff!important}.stack-top{z-index:9;margin:20px}.navitems{background-color:#03a}.app-container{height:90%;margin:0}.app-sidenav{width:200px;border:1px solid rgb(192,190,199)}.side-color{background-color:#e6f4ff}.app-sidenav mat-list-item{display:flex!important;align-items:center!important}.app-sidenav mat-icon{display:inline-flex!important;align-items:center!important;vertical-align:middle!important}.app-sidenav mat-expansion-panel-header mat-icon{display:inline-flex!important;align-items:center!important;vertical-align:middle!important}::ng-deep .app-sidenav .mat-expansion-panel-body{padding-bottom:5px!important;padding-right:5px!important}::ng-deep .app-sidenav .mdc-list{padding-bottom:0!important}.sm-layout{display:flex;min-height:100vh;position:relative}.sm-sidebar{position:fixed;top:0;left:0;bottom:0;width:260px;z-index:1030;overflow:hidden;transition:width .3s cubic-bezier(.4,0,.2,1)}.sm-sidebar-bg{position:absolute;inset:0;z-index:0}.sm-sidebar-bg-image{position:absolute;inset:0;background-size:cover;background-position:center}.sm-sidebar-bg-overlay{position:absolute;inset:0}.sm-sidebar-content{position:relative;z-index:1;display:flex;flex-direction:column;height:100%;color:#fff}.sm-brand{display:flex;align-items:center;padding:18px 15px 10px;min-height:60px;text-decoration:none;white-space:nowrap;overflow:hidden}.sm-brand img{height:34px;width:34px;object-fit:contain;margin-right:12px;flex-shrink:0}.sm-brand-name{font-size:16px;font-weight:500;letter-spacing:.5px;color:#fff;overflow:hidden;text-overflow:ellipsis;transition:opacity .2s ease}.sm-profile{display:flex;align-items:center;padding:12px 15px;white-space:nowrap;overflow:hidden}.sm-profile-icon{font-size:34px!important;width:34px!important;height:34px!important;margin-right:12px;flex-shrink:0;color:#fffc}.sm-profile-info{overflow:hidden;transition:opacity .2s ease}.sm-profile-name{font-size:14px;font-weight:500;color:#fff;line-height:1.3;overflow:hidden;text-overflow:ellipsis}.sm-profile-role{font-size:11px;color:#fff9;line-height:1.3;overflow:hidden;text-overflow:ellipsis}.sm-sidebar mat-divider{border-color:#ffffff26!important;margin:0 15px}.sm-menu-scroll{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px 0}.sm-menu-scroll::-webkit-scrollbar{width:4px}.sm-menu-scroll::-webkit-scrollbar-track{background:transparent}.sm-menu-scroll::-webkit-scrollbar-thumb{background:#fff3;border-radius:2px}.sm-menu-item{display:flex;align-items:center;padding:10px 15px;margin:2px 15px;border-radius:4px;cursor:pointer;color:#fff;font-size:13px;font-weight:400;letter-spacing:.3px;transition:all .15s ease;text-decoration:none;white-space:nowrap;overflow:hidden}.sm-menu-item:hover{background:#ffffff1f}.sm-menu-item.sm-active{background-color:#fff;color:#3c4858;box-shadow:0 4px 20px #00000024,0 7px 10px -5px #0003;font-weight:500}.sm-menu-item.sm-active .sm-menu-icon{color:#3c4858}.sm-menu-icon{font-size:20px!important;width:24px!important;height:24px!important;display:inline-flex!important;align-items:center;justify-content:center;margin-right:12px;flex-shrink:0;color:#fffc;transition:color .15s ease}.sm-menu-text{flex:1;overflow:hidden;text-overflow:ellipsis;transition:opacity .2s ease}.sm-caret{font-size:18px!important;width:18px!important;height:18px!important;transition:transform .3s cubic-bezier(.4,0,.2,1);flex-shrink:0;color:#fff9}.sm-caret.sm-caret-open{transform:rotate(180deg)}.sm-active .sm-caret{color:#3c4858}.sm-submenu{max-height:0;overflow:hidden;transition:max-height .35s cubic-bezier(.4,0,.2,1)}.sm-submenu.sm-submenu-open{max-height:1000px}.sm-submenu-item{display:flex;align-items:center;padding:8px 15px 8px 30px;margin:1px 15px;border-radius:4px;cursor:pointer;color:#fffc;font-size:12px;font-weight:400;transition:all .15s ease;white-space:nowrap;overflow:hidden}.sm-submenu-item:hover{background:#ffffff1f;color:#fff}.sm-submenu-item.sm-active{background-color:#fff;color:#3c4858;box-shadow:0 4px 20px #00000024,0 7px 10px -5px #0003;font-weight:500}.sm-submenu-item.sm-active .sm-sub-icon{color:#3c4858}.sm-sub-icon{font-size:16px!important;width:20px!important;height:20px!important;display:inline-flex!important;align-items:center;justify-content:center;margin-right:10px;flex-shrink:0;color:#fff9}.sm-initials{width:20px;height:20px;border-radius:50%;background:#ffffff26;display:inline-flex;align-items:center;justify-content:center;font-size:9px;font-weight:600;margin-right:10px;flex-shrink:0;color:#fffc}.sm-active .sm-initials{background:#3c48581f;color:#3c4858}.sm-main{flex:1;margin-left:260px;min-height:100vh;display:flex;flex-direction:column;transition:margin-left .3s cubic-bezier(.4,0,.2,1);background-color:#eef2f7}.sm-topbar{display:flex;align-items:center;padding:8px 16px;min-height:56px;background-color:#eef2f7;background-image:radial-gradient(circle,#d5dbe3 1px,transparent 1px);background-size:16px 16px;border-bottom:1px solid rgba(0,0,0,.08);position:sticky;top:0;z-index:1020;transition:background .3s ease,backdrop-filter .3s ease}.sm-topbar-scrolled{background-color:#eef2f78c;background-image:none;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);box-shadow:0 1px 3px #0000000f}.sm-topbar-spacer{flex:1 1 auto}.sm-topbar-logo{height:32px;width:32px;object-fit:contain;margin-right:8px}.sm-topbar-brand{font-size:18px;font-weight:500;margin-right:8px;white-space:nowrap}.sm-topbar-label{font-size:14px;margin-right:4px;display:inline-flex;align-items:center;align-self:center;height:40px;line-height:1}.sm-topbar .mat-mdc-icon-button{display:inline-flex!important;align-items:center!important;justify-content:center!important}.sm-content{flex:1;padding:12px;background-color:#e5eaf2;background-image:radial-gradient(ellipse at 50% 45%,#fffffff2,#fff6 35%,#fff0 60%),radial-gradient(circle,#bec7d4 1px,transparent 1px);background-size:100% 100%,16px 16px;min-height:calc(100vh - 104px)}.sm-footer{padding:12px 16px;text-align:center;font-size:12px;color:#999;border-top:1px solid #e0e0e0;background:#fff}.sm-footer a{color:inherit;cursor:pointer}.sm-footer a:hover{text-decoration:underline}.sm-backdrop{display:none;position:fixed;inset:0;background:#00000080;z-index:1025}.sm-layout.sm-mini .sm-sidebar{width:80px}.sm-layout.sm-mini .sm-main{margin-left:80px}.sm-layout.sm-mini .sm-brand-name,.sm-layout.sm-mini .sm-profile-info,.sm-layout.sm-mini .sm-menu-text,.sm-layout.sm-mini .sm-caret,.sm-layout.sm-mini .sm-submenu{display:none}.sm-layout.sm-mini .sm-sidebar mat-divider{margin:0 10px}.sm-layout.sm-mini .sm-brand{justify-content:center;padding:18px 0 10px}.sm-layout.sm-mini .sm-brand img{margin-right:0}.sm-layout.sm-mini .sm-profile{justify-content:center;padding:12px 0}.sm-layout.sm-mini .sm-profile-icon{margin-right:0}.sm-layout.sm-mini .sm-menu-item{justify-content:center;padding:12px 0;margin:2px 0}.sm-layout.sm-mini .sm-menu-icon{margin-right:0;font-size:22px!important}.sm-layout.sm-mini-hovered .sm-sidebar{width:260px;box-shadow:4px 0 20px #0000004d}.sm-layout.sm-mini-hovered .sm-main{margin-left:80px}.sm-layout.sm-mini-hovered .sm-brand-name,.sm-layout.sm-mini-hovered .sm-profile-info,.sm-layout.sm-mini-hovered .sm-menu-text,.sm-layout.sm-mini-hovered .sm-caret{display:initial}.sm-layout.sm-mini-hovered .sm-submenu{display:block}.sm-layout.sm-mini-hovered .sm-sidebar mat-divider{margin:0 15px}.sm-layout.sm-mini-hovered .sm-brand{justify-content:flex-start;padding:18px 15px 10px}.sm-layout.sm-mini-hovered .sm-brand img{margin-right:12px}.sm-layout.sm-mini-hovered .sm-profile{justify-content:flex-start;padding:12px 15px}.sm-layout.sm-mini-hovered .sm-profile-icon{margin-right:12px}.sm-layout.sm-mini-hovered .sm-menu-item{justify-content:flex-start;padding:10px 15px;margin:2px 15px}.sm-layout.sm-mini-hovered .sm-menu-icon{margin-right:12px;font-size:20px!important}@media (max-width: 600px){.sm-sidebar{transform:translate(-100%);transition:transform .3s cubic-bezier(.4,0,.2,1);width:260px!important}.sm-layout.sm-mobile-open .sm-sidebar{transform:translate(0)}.sm-layout.sm-mobile-open .sm-backdrop{display:block}.sm-main{margin-left:0!important}.sm-layout.sm-mini .sm-sidebar{width:260px!important}.sm-layout.sm-mini .sm-brand-name,.sm-layout.sm-mini .sm-profile-info,.sm-layout.sm-mini .sm-menu-text,.sm-layout.sm-mini .sm-caret{display:initial}.sm-layout.sm-mini .sm-submenu{display:block}.sm-layout.sm-mini .sm-sidebar mat-divider{margin:0 15px}.sm-layout.sm-mini .sm-menu-item{justify-content:flex-start;padding:10px 15px;margin:2px 15px}.sm-layout.sm-mini .sm-menu-icon{margin-right:12px;font-size:20px!important}.sm-layout.sm-mini .sm-brand{justify-content:flex-start;padding:18px 15px 10px}.sm-layout.sm-mini .sm-brand img{margin-right:12px}.sm-layout.sm-mini .sm-profile{justify-content:flex-start;padding:12px 15px}.sm-layout.sm-mini .sm-profile-icon{margin-right:12px}}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i4$4.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4$4.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4$4.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "directive", type: i3$2.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i14.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "component", type: i14.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "component", type: i14.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: i16.MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { kind: "component", type: i16.MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { kind: "component", type: i16.MatSidenavContent, selector: "mat-sidenav-content" }, { kind: "component", type: i17.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "directive", type: i1$2.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: i1$2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i18.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i18.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "component", type: LoaderComponent, selector: "spa-loader", inputs: ["logo"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.DatePipe, name: "date" }] }); }
9545
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: NavMenuComponent, isStandalone: false, selector: "spa-nav-menu", inputs: { appConfig: "appConfig", footer: "footer" }, host: { listeners: { "window:scroll": "onWindowScroll()" } }, ngImport: i0, template: "<header *ngIf=\"loggedin && dataService.appConfig.navigation == 'top'\">\r\n\r\n <!-- Changed: Removed mb-3 class to eliminate gap between toolbar and content -->\r\n <nav class=\"toolbar navbar navbar-expand-sm navbar-toggleable-sm navbar-light border-bottom box-shadow\" style=\"padding-right: 10px;\">\r\n\r\n\r\n <div class=\"container-fluid\" style=\"padding-right: 0px;\">\r\n\r\n <img *ngIf=\"appConfig.logo!=''\" [src]=\"appConfig.logo\" style=\"height: 50px; margin-right: 2em\" />\r\n\r\n <div>\r\n <!-- <div style=\"font-size: 20px;\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant && tenantName\" style=\"font-size: 12px;\">\r\n {{tenantName}}\r\n </div> -->\r\n\r\n <div *ngIf=\"!dataService.appConfig.multitenant\" style=\"font-size: 22px;\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant\" style=\"font-size: 20px; ; font-weight: 400;\" [ngStyle]=\"{'margin-top': dataService.appConfig.multitenant ? '12px' : ''}\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant && tenantName\" style=\"font-size: 12px; margin-bottom: 5px;\">\r\n {{tenantName}}\r\n </div>\r\n\r\n </div>\r\n\r\n\r\n\r\n <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\".navbar-collapse\" aria-label=\"Toggle navigation\" [attr.aria-expanded]=\"isExpanded\" (click)=\"toggle()\">\r\n <span class=\"navbar-toggler-icon\"></span>\r\n </button>\r\n\r\n <div *ngIf=\"myRole\" class=\" navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse stack-top\" style=\"margin-right: 0px;\" [ngClass]=\"{ show: isExpanded, navitems: isExpanded }\" >\r\n\r\n <button mat-icon-button (click)=\"logoff()\" > <mat-icon>logout</mat-icon> </button>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant\">\r\n\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/tenant-settings')\" > <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon> </button>\r\n\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/bug')\"> <mat-icon >support_agent</mat-icon> </button>\r\n\r\n <!-- <button mat-icon-button (click)=\"redirectTo('home/admin/notifications')\"> <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon> </button> -->\r\n </div>\r\n\r\n\r\n <button id=\"btnUser\" mat-button [matMenuTriggerFor]=\"profileMenu\" ><mat-icon style=\"font-size: 24px;\">account_circle</mat-icon> &nbsp;{{loggedUserFullName}}</button>\r\n\r\n <mat-menu #profileMenu=\"matMenu\">\r\n <button id=\"btnProfile\" mat-menu-item (click)=\"redirectTo('home/user/profile')\" >Profile</button>\r\n <button id=\"btnLogOff\" mat-menu-item (click)=\"logoff()\">Log Off</button>\r\n </mat-menu>\r\n\r\n <div *ngFor=\"let item of reversedCapItems\">\r\n\r\n <!-- Menu Item \u2014 Added: isFeatureAllowed check for plan-based gating -->\r\n <button id=\"btnMenu\" *ngIf=\"myRole[item.name] && !item.capSubItems && item.showMenu && isFeatureAllowed(item)\" mat-button (click)=\"redirectTo(item.link)\">{{item.display}}</button>\r\n\r\n <!-- Menu Item with Sub items ignored \u2014 Added: isFeatureAllowed check -->\r\n <button id=\"btnMenu\" *ngIf=\"myRole[item.name] && item.capSubItems && item.showMenu && item.ignoreSubsDisplay && isFeatureAllowed(item)\" mat-button (click)=\"redirectTo(item.link)\">{{item.display}}</button>\r\n\r\n <!-- Menu Item with Sub items to display \u2014 Added: isFeatureAllowed check -->\r\n <button id=\"btnMenu\" *ngIf=\"myRole[item.name] && item.capSubItems && item.showMenu && !item.ignoreSubsDisplay && isFeatureAllowed(item)\" mat-button [matMenuTriggerFor]=\"adminMenu\">{{item.display}}</button>\r\n\r\n\r\n <!-- Sub Menu Items \u2014 Added: isFeatureAllowed check on sub-items -->\r\n <mat-menu #adminMenu=\"matMenu\">\r\n\r\n <div *ngFor=\"let subItem of item.capSubItems\">\r\n\r\n <button *ngIf=\"myRole[subItem.name] && subItem.showMenu && isFeatureAllowed(subItem)\" mat-menu-item (click)=\"redirectTo(subItem.link)\">{{subItem.display}}</button>\r\n\r\n </div>\r\n\r\n </mat-menu>\r\n\r\n </div>\r\n\r\n </div>\r\n\r\n\r\n </div>\r\n\r\n </nav>\r\n\r\n</header>\r\n\r\n<!-- Changed: Removed top/bottom padding to eliminate gaps, but kept left/right padding for content spacing -->\r\n<div class=\"container-fluid tin-bg-image\" *ngIf=\"dataService.appConfig.navigation == 'top'\" style=\"padding: 12px 12px; margin: 0;\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n</div>\r\n\r\n\r\n\r\n\r\n\r\n\r\n<!-- SIDE -->\r\n<mat-toolbar class=\"tin-bg-image-toolbar\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\" style=\"padding: 0px 8px;\">\r\n\r\n <button mat-icon-button (click)=\"toggle()\" matTooltip=\"Menu\">\r\n <mat-icon>menu</mat-icon>\r\n </button>\r\n\r\n <img [src]=\"dataService.appConfig.logo\" style=\"height: 50px;\" />\r\n\r\n <div style=\"padding-left: 10px; \">\r\n\r\n <div style=\"font-size: 22px; font-weight: 400;\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <!-- <div style=\"font-size: 20px; height: 25px; font-weight: 400;\" [ngStyle]=\"{'margin-top': dataService.appConfig.multitenant ? '12px' : ''}\">\r\n {{appConfig.appName}}\r\n </div> -->\r\n\r\n <!-- <div *ngIf=\"dataService.appConfig.multitenant && tenantName\" style=\"font-size: 12px; margin-bottom: 5px;\">\r\n {{tenantName}}\r\n </div> -->\r\n\r\n </div>\r\n\r\n\r\n\r\n <span class=\"toolbar-item-spacer\"></span>\r\n\r\n <!-- buttons -->\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant\" style=\"display: flex; align-items: center;\">\r\n\r\n <!-- <label style=\"font-size: 14px;\">Hi, {{loggedUserFullName}}</label> -->\r\n\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/tenant-settings')\" matTooltip=\"Organisation Settings\">\r\n <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon>\r\n </button>\r\n <label style=\"font-size: 14px;margin-right: 20px;\">{{tenantName}}</label>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/bug')\" matTooltip=\"Support\">\r\n <mat-icon >help</mat-icon>\r\n </button>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/notifications')\" matTooltip=\"Notifications\">\r\n <mat-icon [matBadge]=\"notificationCount$ | async\" [matBadgeHidden]=\"(notificationCount$ | async) === 0\" matBadgeColor=\"warn\" matBadgeSize=\"small\">notifications</mat-icon>\r\n </button>\r\n\r\n </div>\r\n\r\n\r\n\r\n <button mat-icon-button matTooltip=\"My Account\" [matMenuTriggerFor]=\"userAccountMenu\"><mat-icon>account_circle</mat-icon></button>\r\n <label style=\"font-size: 14px;\">{{loggedUserFullName}}</label>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"logoff()\" matTooltip=\"Signout\">\r\n <mat-icon>logout</mat-icon>\r\n </button>\r\n\r\n\r\n <!-- my account menu -->\r\n <mat-menu #userAccountMenu [overlapTrigger]=\"false\" yPosition=\"below\">\r\n\r\n\r\n <button mat-menu-item routerLink=\"home/user/profile\">\r\n <mat-icon>person</mat-icon><span>Profile</span>\r\n </button>\r\n\r\n <button mat-menu-item routerLink=\"home/admin/bug\" *ngIf=\"dataService.appConfig.multitenant && smallScreen\">\r\n <mat-icon>help</mat-icon> <span>Help</span>\r\n </button>\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <button mat-menu-item (click)=\"logoff()\">\r\n <mat-icon>logout</mat-icon>Logout\r\n </button>\r\n\r\n </mat-menu>\r\n\r\n</mat-toolbar>\r\n\r\n\r\n\r\n\r\n<mat-sidenav-container class=\"app-container\" [hasBackdrop]=\"smallScreen\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\">\r\n\r\n <mat-sidenav #sidenav [mode]=\"smallScreen ? 'over' : 'side'\" [class.mat-elevation-z4]=\"true\" [opened]=\"isExpanded\" class=\"app-sidenav side-color\" style=\"height: 100%;\"\r\n [ngStyle]=\"{'width': dataService.appConfig.navWidth}\">\r\n <mat-nav-list >\r\n\r\n <ng-container *ngFor=\"let cap of dataService.appConfig.capItems\" >\r\n\r\n <!-- Menu item \u2014 Added: isFeatureAllowed check for plan-based gating -->\r\n <mat-list-item [routerLink]=\"cap.link\" *ngIf=\"myRole[cap.name] && cap.showMenu && (!cap.capSubItems || cap.capSubItems && cap.ignoreSubsDisplay) && isFeatureAllowed(cap)\" style=\"height: 40px;font-size: 15px;\"\r\n (click)=\"smallScreen ? toggle() : null\">\r\n <mat-icon [ngStyle]=\"{'color': cap.color}\" style=\"margin-right: 5px;\">{{cap.icon}}</mat-icon>{{cap.display}}\r\n </mat-list-item>\r\n\r\n <!-- Menu With Sub items \u2014 Added: isFeatureAllowed check -->\r\n <mat-expansion-panel class=\"side-color\" [class.mat-elevation-z0]=\"true\" *ngIf=\"myRole[cap.name] && cap.showMenu && cap.capSubItems && !cap.ignoreSubsDisplay && isFeatureAllowed(cap)\">\r\n\r\n <mat-expansion-panel-header style=\"height: 40px;padding-left: 15px;\">\r\n <mat-icon [ngStyle]=\"{'color': cap.color}\" style=\"margin-right: 5px;\">{{cap.icon != 'navigate_next' ? cap.icon : 'fiber_manual_record' }}</mat-icon>{{cap.display}}\r\n </mat-expansion-panel-header>\r\n\r\n <!-- Sub items - Changed: Use ng-container to avoid blank spaces for hidden items -->\r\n <mat-nav-list>\r\n <ng-container *ngFor=\"let capSub of getSubItems(cap)\">\r\n <mat-list-item [routerLink]=\"capSub.link\" style=\"height: 30px; font-size: 15px; padding-left: 4px; padding-right: 10px; margin-bottom: 5px;\" (click)=\"smallScreen ? toggle() : null\" *ngIf=\"myRole[capSub.name] && capSub.showMenu && isFeatureAllowed(capSub)\" [matTooltip]=\"capSub.display\" matTooltipPosition=\"right\">\r\n <mat-icon [ngStyle]=\"{'color': capSub.color}\" style=\"margin-right: 5px;\">{{capSub.icon}}</mat-icon>{{capSub.display}}\r\n </mat-list-item>\r\n </ng-container>\r\n </mat-nav-list>\r\n\r\n </mat-expansion-panel>\r\n\r\n </ng-container>\r\n\r\n </mat-nav-list>\r\n </mat-sidenav>\r\n\r\n\r\n\r\n <mat-sidenav-content class=\"tin-bg-image\" style=\"padding: 0px 12px;\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\">\r\n <hr style=\"margin-top: 0px;\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n </mat-sidenav-content>\r\n\r\n</mat-sidenav-container>\r\n\r\n\r\n<!-- footer -->\r\n<div class=\"tin-center\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\">\r\n <label style=\"text-align: center; font-size: 12px;\">&copy; {{nowDate | date : 'yyyy'}} <a color=\"primary\" class=\"terms-link\" [href]=\"appConfig.siteUrl\" target=\"_blank\">{{footer}}</a> | <a color=\"primary\" class=\"terms-link\" style=\"cursor: pointer;\" (click)=\"openTerms()\">Terms</a> | <a color=\"primary\" class=\"terms-link\" style=\"cursor: pointer;\" (click)=\"openPrivacy()\">Privacy Policy</a></label>\r\n</div>\r\n\r\n\r\n<div class=\"tin-bg-image\" *ngIf=\"!loggedin && dataService.appConfig.navigation == 'side'\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n</div>\r\n\r\n\r\n<!-- SIDE-MODERN -->\r\n\r\n<!-- Changed: Side-modern navigation layout -->\r\n<div class=\"sm-layout\"\r\n *ngIf=\"loggedin && dataService.appConfig.navigation == 'side-modern'\"\r\n [class.sm-mini]=\"isMiniSidebar && !isMiniHovered\"\r\n [class.sm-mini-hovered]=\"isMiniSidebar && isMiniHovered\"\r\n [class.sm-mobile-open]=\"smallScreen && isExpanded\">\r\n\r\n <!-- Sidebar -->\r\n <aside class=\"sm-sidebar\"\r\n (mouseenter)=\"onMiniMouseEnter()\"\r\n (mouseleave)=\"onMiniMouseLeave()\">\r\n\r\n <!-- Background layers -->\r\n <div class=\"sm-sidebar-bg\">\r\n <div class=\"sm-sidebar-bg-image\" *ngIf=\"appConfig.navImage\" [ngStyle]=\"{'background-image': 'url(' + appConfig.navImage + ')'}\"></div>\r\n <div class=\"sm-sidebar-bg-overlay\" [ngStyle]=\"{'background-color': appConfig.navColor}\"></div>\r\n </div>\r\n\r\n <!-- Sidebar content -->\r\n <div class=\"sm-sidebar-content\">\r\n\r\n <!-- Brand -->\r\n <div class=\"sm-brand\">\r\n <img *ngIf=\"appConfig.logo\" [src]=\"appConfig.logo\" alt=\"logo\" />\r\n <span class=\"sm-brand-name\">{{appConfig.appName}}</span>\r\n </div>\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Profile -->\r\n <div class=\"sm-profile\">\r\n <mat-icon class=\"sm-profile-icon\">account_circle</mat-icon>\r\n <div class=\"sm-profile-info\">\r\n <div class=\"sm-profile-name\">{{loggedUserFullName}}</div>\r\n <div class=\"sm-profile-role\">{{tenantName || 'User'}}</div>\r\n </div>\r\n </div>\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Scrollable menu -->\r\n <div class=\"sm-menu-scroll\">\r\n\r\n <ng-container *ngFor=\"let cap of dataService.appConfig.capItems\">\r\n\r\n <!-- Simple menu item (no sub-items or ignoring sub display) \u2014 Added: isFeatureAllowed check -->\r\n <div *ngIf=\"myRole[cap.name] && cap.showMenu && (!cap.capSubItems || cap.ignoreSubsDisplay) && isFeatureAllowed(cap)\"\r\n class=\"sm-menu-item\"\r\n [class.sm-active]=\"isActiveRoute(cap.link)\"\r\n (click)=\"modernNavigate(cap.link)\">\r\n <mat-icon class=\"sm-menu-icon\">{{cap.icon != 'navigate_next' ? cap.icon : 'dashboard'}}</mat-icon>\r\n <span class=\"sm-menu-text\">{{cap.display}}</span>\r\n </div>\r\n\r\n <!-- Parent menu item with sub-items \u2014 Added: isFeatureAllowed check -->\r\n <ng-container *ngIf=\"myRole[cap.name] && cap.showMenu && cap.capSubItems && !cap.ignoreSubsDisplay && isFeatureAllowed(cap)\">\r\n\r\n <!-- Parent item (toggles sub-menu) -->\r\n <div class=\"sm-menu-item\"\r\n [class.sm-active]=\"isParentActive(cap) && !isMenuOpen(cap.name)\"\r\n (click)=\"toggleModernMenu(cap.name)\">\r\n <mat-icon class=\"sm-menu-icon\">{{cap.icon != 'navigate_next' ? cap.icon : 'dashboard'}}</mat-icon>\r\n <span class=\"sm-menu-text\">{{cap.display}}</span>\r\n <mat-icon class=\"sm-caret\" [class.sm-caret-open]=\"isMenuOpen(cap.name)\">expand_more</mat-icon>\r\n </div>\r\n\r\n <!-- Sub-menu container (animated) -->\r\n <div class=\"sm-submenu\" [class.sm-submenu-open]=\"isMenuOpen(cap.name)\">\r\n <ng-container *ngFor=\"let sub of getSubItems(cap)\">\r\n <div *ngIf=\"myRole[sub.name] && sub.showMenu && isFeatureAllowed(sub)\"\r\n class=\"sm-submenu-item\"\r\n [class.sm-active]=\"isActiveRoute(sub.link)\"\r\n (click)=\"modernNavigate(sub.link)\">\r\n <mat-icon *ngIf=\"sub.icon && sub.icon != 'navigate_next'\" class=\"sm-sub-icon\">{{sub.icon}}</mat-icon>\r\n <span *ngIf=\"!sub.icon || sub.icon == 'navigate_next'\" class=\"sm-initials\">{{getInitials(sub.display)}}</span>\r\n <span class=\"sm-menu-text\">{{sub.display}}</span>\r\n </div>\r\n </ng-container>\r\n </div>\r\n\r\n </ng-container>\r\n\r\n </ng-container>\r\n\r\n </div>\r\n\r\n </div>\r\n </aside>\r\n\r\n <!-- Mobile backdrop -->\r\n <div class=\"sm-backdrop\" (click)=\"isExpanded = false\"></div>\r\n\r\n <!-- Main content -->\r\n <div class=\"sm-main\">\r\n\r\n <!-- Top bar - Changed: Added scroll class for frosted glass effect -->\r\n <div class=\"sm-topbar\" [class.sm-topbar-scrolled]=\"topbarScrolled\">\r\n <button mat-icon-button (click)=\"smallScreen ? toggle() : toggleMiniSidebar()\" matTooltip=\"Menu\">\r\n <mat-icon>menu</mat-icon>\r\n </button>\r\n\r\n <!-- Changed: Mobile branding - show logo + app name when sidebar is hidden on small screens -->\r\n <img *ngIf=\"smallScreen && appConfig.logo\" [src]=\"appConfig.logo\" alt=\"logo\" class=\"sm-topbar-logo\" />\r\n <span *ngIf=\"smallScreen\" class=\"sm-topbar-brand\">{{appConfig.appName}}</span>\r\n\r\n <span class=\"sm-topbar-spacer\"></span>\r\n\r\n <!-- Multitenant buttons -->\r\n <div *ngIf=\"dataService.appConfig.multitenant\" style=\"display: flex; align-items: center;\">\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/tenant-settings')\" matTooltip=\"Organisation Settings\">\r\n <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon>\r\n </button>\r\n <span class=\"sm-topbar-label\">{{tenantName}}</span>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/bug')\" matTooltip=\"Support\">\r\n <mat-icon>help</mat-icon>\r\n </button>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/notifications')\" matTooltip=\"Notifications\">\r\n <mat-icon [matBadge]=\"notificationCount$ | async\" [matBadgeHidden]=\"(notificationCount$ | async) === 0\" matBadgeColor=\"warn\" matBadgeSize=\"small\">notifications</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Profile menu -->\r\n <button mat-icon-button matTooltip=\"My Account\" [matMenuTriggerFor]=\"smProfileMenu\">\r\n <mat-icon>account_circle</mat-icon>\r\n </button>\r\n <span class=\"sm-topbar-label\">{{loggedUserFullName}}</span>\r\n\r\n <mat-menu #smProfileMenu=\"matMenu\" [overlapTrigger]=\"false\" yPosition=\"below\">\r\n <button mat-menu-item routerLink=\"home/user/profile\">\r\n <mat-icon>person</mat-icon><span>Profile</span>\r\n </button>\r\n <button mat-menu-item routerLink=\"home/admin/bug\" *ngIf=\"dataService.appConfig.multitenant && smallScreen\">\r\n <mat-icon>help</mat-icon><span>Help</span>\r\n </button>\r\n <mat-divider></mat-divider>\r\n <button mat-menu-item (click)=\"logoff()\">\r\n <mat-icon>logout</mat-icon>Logout\r\n </button>\r\n </mat-menu>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"logoff()\" matTooltip=\"Signout\">\r\n <mat-icon>logout</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Page content - Changed: Replaced tin-bg-image with sm-content modern texture -->\r\n <div class=\"sm-content\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"sm-footer\">\r\n &copy; {{nowDate | date : 'yyyy'}} <a [href]=\"appConfig.siteUrl\" target=\"_blank\">{{footer}}</a> | <a (click)=\"openTerms()\">Terms</a> | <a (click)=\"openPrivacy()\">Privacy Policy</a>\r\n </div>\r\n\r\n </div>\r\n\r\n</div>\r\n\r\n<!-- Not logged in fallback for side-modern -->\r\n<div class=\"tin-bg-image\" *ngIf=\"!loggedin && dataService.appConfig.navigation == 'side-modern'\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n</div>", styles: ["a.navbar-brand{white-space:normal;text-align:center;word-break:break-all}html{font-size:14px}.box-shadow{box-shadow:0 .25rem .75rem #0000000d}.toolbar-item-spacer{flex:1 1 auto}.toolbar{height:60px;display:flex;align-items:center;background-color:#03a;color:#fff;margin-bottom:0!important}.toolbar button,.toolbar .mat-mdc-button,.toolbar .mat-mdc-icon-button{color:#fff!important}.toolbar mat-icon{color:#fff!important}.stack-top{z-index:9;margin:20px}.navitems{background-color:#03a}.app-container{height:90%;margin:0}.app-sidenav{width:200px;border:1px solid rgb(192,190,199)}.side-color{background-color:#e6f4ff}.app-sidenav mat-list-item{display:flex!important;align-items:center!important}.app-sidenav mat-icon{display:inline-flex!important;align-items:center!important;vertical-align:middle!important}.app-sidenav mat-expansion-panel-header mat-icon{display:inline-flex!important;align-items:center!important;vertical-align:middle!important}::ng-deep .app-sidenav .mat-expansion-panel-body{padding-bottom:5px!important;padding-right:5px!important}::ng-deep .app-sidenav .mdc-list{padding-bottom:0!important}.sm-layout{display:flex;min-height:100vh;position:relative}.sm-sidebar{position:fixed;top:0;left:0;bottom:0;width:260px;z-index:1030;overflow:hidden;transition:width .3s cubic-bezier(.4,0,.2,1)}.sm-sidebar-bg{position:absolute;inset:0;z-index:0}.sm-sidebar-bg-image{position:absolute;inset:0;background-size:cover;background-position:center}.sm-sidebar-bg-overlay{position:absolute;inset:0}.sm-sidebar-content{position:relative;z-index:1;display:flex;flex-direction:column;height:100%;color:#fff}.sm-brand{display:flex;align-items:center;padding:18px 15px 10px;min-height:60px;text-decoration:none;white-space:nowrap;overflow:hidden}.sm-brand img{height:34px;width:34px;object-fit:contain;margin-right:12px;flex-shrink:0}.sm-brand-name{font-size:16px;font-weight:500;letter-spacing:.5px;color:#fff;overflow:hidden;text-overflow:ellipsis;transition:opacity .2s ease}.sm-profile{display:flex;align-items:center;padding:12px 15px;white-space:nowrap;overflow:hidden}.sm-profile-icon{font-size:34px!important;width:34px!important;height:34px!important;margin-right:12px;flex-shrink:0;color:#fffc}.sm-profile-info{overflow:hidden;transition:opacity .2s ease}.sm-profile-name{font-size:14px;font-weight:500;color:#fff;line-height:1.3;overflow:hidden;text-overflow:ellipsis}.sm-profile-role{font-size:11px;color:#fff9;line-height:1.3;overflow:hidden;text-overflow:ellipsis}.sm-sidebar mat-divider{border-color:#ffffff26!important;margin:0 15px}.sm-menu-scroll{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px 0}.sm-menu-scroll::-webkit-scrollbar{width:4px}.sm-menu-scroll::-webkit-scrollbar-track{background:transparent}.sm-menu-scroll::-webkit-scrollbar-thumb{background:#fff3;border-radius:2px}.sm-menu-item{display:flex;align-items:center;padding:10px 15px;margin:2px 15px;border-radius:4px;cursor:pointer;color:#fff;font-size:13px;font-weight:400;letter-spacing:.3px;transition:all .15s ease;text-decoration:none;white-space:nowrap;overflow:hidden}.sm-menu-item:hover{background:#ffffff1f}.sm-menu-item.sm-active{background-color:#fff;color:#3c4858;box-shadow:0 4px 20px #00000024,0 7px 10px -5px #0003;font-weight:500}.sm-menu-item.sm-active .sm-menu-icon{color:#3c4858}.sm-menu-icon{font-size:20px!important;width:24px!important;height:24px!important;display:inline-flex!important;align-items:center;justify-content:center;margin-right:12px;flex-shrink:0;color:#fffc;transition:color .15s ease}.sm-menu-text{flex:1;overflow:hidden;text-overflow:ellipsis;transition:opacity .2s ease}.sm-caret{font-size:18px!important;width:18px!important;height:18px!important;transition:transform .3s cubic-bezier(.4,0,.2,1);flex-shrink:0;color:#fff9}.sm-caret.sm-caret-open{transform:rotate(180deg)}.sm-active .sm-caret{color:#3c4858}.sm-submenu{max-height:0;overflow:hidden;transition:max-height .35s cubic-bezier(.4,0,.2,1)}.sm-submenu.sm-submenu-open{max-height:1000px}.sm-submenu-item{display:flex;align-items:center;padding:8px 15px 8px 30px;margin:1px 15px;border-radius:4px;cursor:pointer;color:#fffc;font-size:12px;font-weight:400;transition:all .15s ease;white-space:nowrap;overflow:hidden}.sm-submenu-item:hover{background:#ffffff1f;color:#fff}.sm-submenu-item.sm-active{background-color:#fff;color:#3c4858;box-shadow:0 4px 20px #00000024,0 7px 10px -5px #0003;font-weight:500}.sm-submenu-item.sm-active .sm-sub-icon{color:#3c4858}.sm-sub-icon{font-size:16px!important;width:20px!important;height:20px!important;display:inline-flex!important;align-items:center;justify-content:center;margin-right:10px;flex-shrink:0;color:#fff9}.sm-initials{width:20px;height:20px;border-radius:50%;background:#ffffff26;display:inline-flex;align-items:center;justify-content:center;font-size:9px;font-weight:600;margin-right:10px;flex-shrink:0;color:#fffc}.sm-active .sm-initials{background:#3c48581f;color:#3c4858}.sm-main{flex:1;min-width:0;margin-left:260px;min-height:100vh;display:flex;flex-direction:column;transition:margin-left .3s cubic-bezier(.4,0,.2,1);background-color:#eef2f7}.sm-topbar{display:flex;align-items:center;padding:8px 16px;min-height:56px;background-color:#eef2f7;background-image:radial-gradient(circle,#d5dbe3 1px,transparent 1px);background-size:16px 16px;border-bottom:1px solid rgba(0,0,0,.08);position:sticky;top:0;z-index:1020;transition:background .3s ease,backdrop-filter .3s ease}.sm-topbar-scrolled{background-color:#eef2f78c;background-image:none;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);box-shadow:0 1px 3px #0000000f}.sm-topbar-spacer{flex:1 1 auto}.sm-topbar-logo{height:32px;width:32px;object-fit:contain;margin-right:8px}.sm-topbar-brand{font-size:18px;font-weight:500;margin-right:8px;white-space:nowrap}.sm-topbar-label{font-size:14px;margin-right:4px;display:inline-flex;align-items:center;align-self:center;height:40px;line-height:1}.sm-topbar .mat-mdc-icon-button{display:inline-flex!important;align-items:center!important;justify-content:center!important}.sm-content{flex:1;padding:12px;min-width:0;background-color:#e5eaf2;background-image:radial-gradient(ellipse at 50% 45%,#fffffff2,#fff6 35%,#fff0 60%),radial-gradient(circle,#bec7d4 1px,transparent 1px);background-size:100% 100%,16px 16px;min-height:calc(100vh - 104px)}.sm-footer{padding:12px 16px;text-align:center;font-size:12px;color:#999;border-top:1px solid #e0e0e0;background:#fff}.sm-footer a{color:inherit;cursor:pointer}.sm-footer a:hover{text-decoration:underline}.sm-backdrop{display:none;position:fixed;inset:0;background:#00000080;z-index:1025}.sm-layout.sm-mini .sm-sidebar{width:80px}.sm-layout.sm-mini .sm-main{margin-left:80px}.sm-layout.sm-mini .sm-brand-name,.sm-layout.sm-mini .sm-profile-info,.sm-layout.sm-mini .sm-menu-text,.sm-layout.sm-mini .sm-caret,.sm-layout.sm-mini .sm-submenu{display:none}.sm-layout.sm-mini .sm-sidebar mat-divider{margin:0 10px}.sm-layout.sm-mini .sm-brand{justify-content:center;padding:18px 0 10px}.sm-layout.sm-mini .sm-brand img{margin-right:0}.sm-layout.sm-mini .sm-profile{justify-content:center;padding:12px 0}.sm-layout.sm-mini .sm-profile-icon{margin-right:0}.sm-layout.sm-mini .sm-menu-item{justify-content:center;padding:12px 0;margin:2px 0}.sm-layout.sm-mini .sm-menu-icon{margin-right:0;font-size:22px!important}.sm-layout.sm-mini-hovered .sm-sidebar{width:260px;box-shadow:4px 0 20px #0000004d}.sm-layout.sm-mini-hovered .sm-main{margin-left:80px}.sm-layout.sm-mini-hovered .sm-brand-name,.sm-layout.sm-mini-hovered .sm-profile-info,.sm-layout.sm-mini-hovered .sm-menu-text,.sm-layout.sm-mini-hovered .sm-caret{display:initial}.sm-layout.sm-mini-hovered .sm-submenu{display:block}.sm-layout.sm-mini-hovered .sm-sidebar mat-divider{margin:0 15px}.sm-layout.sm-mini-hovered .sm-brand{justify-content:flex-start;padding:18px 15px 10px}.sm-layout.sm-mini-hovered .sm-brand img{margin-right:12px}.sm-layout.sm-mini-hovered .sm-profile{justify-content:flex-start;padding:12px 15px}.sm-layout.sm-mini-hovered .sm-profile-icon{margin-right:12px}.sm-layout.sm-mini-hovered .sm-menu-item{justify-content:flex-start;padding:10px 15px;margin:2px 15px}.sm-layout.sm-mini-hovered .sm-menu-icon{margin-right:12px;font-size:20px!important}@media (max-width: 600px){.sm-sidebar{transform:translate(-100%);transition:transform .3s cubic-bezier(.4,0,.2,1);width:260px!important}.sm-layout.sm-mobile-open .sm-sidebar{transform:translate(0)}.sm-layout.sm-mobile-open .sm-backdrop{display:block}.sm-main{margin-left:0!important}.sm-layout.sm-mini .sm-sidebar{width:260px!important}.sm-layout.sm-mini .sm-brand-name,.sm-layout.sm-mini .sm-profile-info,.sm-layout.sm-mini .sm-menu-text,.sm-layout.sm-mini .sm-caret{display:initial}.sm-layout.sm-mini .sm-submenu{display:block}.sm-layout.sm-mini .sm-sidebar mat-divider{margin:0 15px}.sm-layout.sm-mini .sm-menu-item{justify-content:flex-start;padding:10px 15px;margin:2px 15px}.sm-layout.sm-mini .sm-menu-icon{margin-right:12px;font-size:20px!important}.sm-layout.sm-mini .sm-brand{justify-content:flex-start;padding:18px 15px 10px}.sm-layout.sm-mini .sm-brand img{margin-right:12px}.sm-layout.sm-mini .sm-profile{justify-content:flex-start;padding:12px 15px}.sm-layout.sm-mini .sm-profile-icon{margin-right:12px}}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i4$4.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4$4.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4$4.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "directive", type: i3$2.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i14.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "component", type: i14.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "component", type: i14.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: i16.MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { kind: "component", type: i16.MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { kind: "component", type: i16.MatSidenavContent, selector: "mat-sidenav-content" }, { kind: "component", type: i17.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "directive", type: i1$2.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: i1$2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i18.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i18.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "component", type: LoaderComponent, selector: "spa-loader", inputs: ["logo"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.DatePipe, name: "date" }] }); }
9542
9546
  }
9543
9547
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: NavMenuComponent, decorators: [{
9544
9548
  type: Component,
9545
- args: [{ selector: 'spa-nav-menu', standalone: false, template: "<header *ngIf=\"loggedin && dataService.appConfig.navigation == 'top'\">\r\n\r\n <!-- Changed: Removed mb-3 class to eliminate gap between toolbar and content -->\r\n <nav class=\"toolbar navbar navbar-expand-sm navbar-toggleable-sm navbar-light border-bottom box-shadow\" style=\"padding-right: 10px;\">\r\n\r\n\r\n <div class=\"container-fluid\" style=\"padding-right: 0px;\">\r\n\r\n <img *ngIf=\"appConfig.logo!=''\" [src]=\"appConfig.logo\" style=\"height: 50px; margin-right: 2em\" />\r\n\r\n <div>\r\n <!-- <div style=\"font-size: 20px;\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant && tenantName\" style=\"font-size: 12px;\">\r\n {{tenantName}}\r\n </div> -->\r\n\r\n <div *ngIf=\"!dataService.appConfig.multitenant\" style=\"font-size: 22px;\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant\" style=\"font-size: 20px; ; font-weight: 400;\" [ngStyle]=\"{'margin-top': dataService.appConfig.multitenant ? '12px' : ''}\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant && tenantName\" style=\"font-size: 12px; margin-bottom: 5px;\">\r\n {{tenantName}}\r\n </div>\r\n\r\n </div>\r\n\r\n\r\n\r\n <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\".navbar-collapse\" aria-label=\"Toggle navigation\" [attr.aria-expanded]=\"isExpanded\" (click)=\"toggle()\">\r\n <span class=\"navbar-toggler-icon\"></span>\r\n </button>\r\n\r\n <div *ngIf=\"myRole\" class=\" navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse stack-top\" style=\"margin-right: 0px;\" [ngClass]=\"{ show: isExpanded, navitems: isExpanded }\" >\r\n\r\n <button mat-icon-button (click)=\"logoff()\" > <mat-icon>logout</mat-icon> </button>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant\">\r\n\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/tenant-settings')\" > <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon> </button>\r\n\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/bug')\"> <mat-icon >support_agent</mat-icon> </button>\r\n\r\n <!-- <button mat-icon-button (click)=\"redirectTo('home/admin/notifications')\"> <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon> </button> -->\r\n </div>\r\n\r\n\r\n <button id=\"btnUser\" mat-button [matMenuTriggerFor]=\"profileMenu\" ><mat-icon style=\"font-size: 24px;\">account_circle</mat-icon> &nbsp;{{loggedUserFullName}}</button>\r\n\r\n <mat-menu #profileMenu=\"matMenu\">\r\n <button id=\"btnProfile\" mat-menu-item (click)=\"redirectTo('home/user/profile')\" >Profile</button>\r\n <button id=\"btnLogOff\" mat-menu-item (click)=\"logoff()\">Log Off</button>\r\n </mat-menu>\r\n\r\n <div *ngFor=\"let item of reversedCapItems\">\r\n\r\n <!-- Menu Item \u2014 Added: isFeatureAllowed check for plan-based gating -->\r\n <button id=\"btnMenu\" *ngIf=\"myRole[item.name] && !item.capSubItems && item.showMenu && isFeatureAllowed(item)\" mat-button (click)=\"redirectTo(item.link)\">{{item.display}}</button>\r\n\r\n <!-- Menu Item with Sub items ignored \u2014 Added: isFeatureAllowed check -->\r\n <button id=\"btnMenu\" *ngIf=\"myRole[item.name] && item.capSubItems && item.showMenu && item.ignoreSubsDisplay && isFeatureAllowed(item)\" mat-button (click)=\"redirectTo(item.link)\">{{item.display}}</button>\r\n\r\n <!-- Menu Item with Sub items to display \u2014 Added: isFeatureAllowed check -->\r\n <button id=\"btnMenu\" *ngIf=\"myRole[item.name] && item.capSubItems && item.showMenu && !item.ignoreSubsDisplay && isFeatureAllowed(item)\" mat-button [matMenuTriggerFor]=\"adminMenu\">{{item.display}}</button>\r\n\r\n\r\n <!-- Sub Menu Items \u2014 Added: isFeatureAllowed check on sub-items -->\r\n <mat-menu #adminMenu=\"matMenu\">\r\n\r\n <div *ngFor=\"let subItem of item.capSubItems\">\r\n\r\n <button *ngIf=\"myRole[subItem.name] && subItem.showMenu && isFeatureAllowed(subItem)\" mat-menu-item (click)=\"redirectTo(subItem.link)\">{{subItem.display}}</button>\r\n\r\n </div>\r\n\r\n </mat-menu>\r\n\r\n </div>\r\n\r\n </div>\r\n\r\n\r\n </div>\r\n\r\n </nav>\r\n\r\n</header>\r\n\r\n<!-- Changed: Removed top/bottom padding to eliminate gaps, but kept left/right padding for content spacing -->\r\n<div class=\"container-fluid tin-bg-image\" *ngIf=\"dataService.appConfig.navigation == 'top'\" style=\"padding: 12px 12px; margin: 0;\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n</div>\r\n\r\n\r\n\r\n\r\n\r\n\r\n<!-- SIDE -->\r\n<mat-toolbar class=\"tin-bg-image-toolbar\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\" style=\"padding: 0px 8px;\">\r\n\r\n <button mat-icon-button (click)=\"toggle()\" matTooltip=\"Menu\">\r\n <mat-icon>menu</mat-icon>\r\n </button>\r\n\r\n <img [src]=\"dataService.appConfig.logo\" style=\"height: 50px;\" />\r\n\r\n <div style=\"padding-left: 10px; \">\r\n\r\n <div style=\"font-size: 22px; font-weight: 400;\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <!-- <div style=\"font-size: 20px; height: 25px; font-weight: 400;\" [ngStyle]=\"{'margin-top': dataService.appConfig.multitenant ? '12px' : ''}\">\r\n {{appConfig.appName}}\r\n </div> -->\r\n\r\n <!-- <div *ngIf=\"dataService.appConfig.multitenant && tenantName\" style=\"font-size: 12px; margin-bottom: 5px;\">\r\n {{tenantName}}\r\n </div> -->\r\n\r\n </div>\r\n\r\n\r\n\r\n <span class=\"toolbar-item-spacer\"></span>\r\n\r\n <!-- buttons -->\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant\" style=\"display: flex; align-items: center;\">\r\n\r\n <!-- <label style=\"font-size: 14px;\">Hi, {{loggedUserFullName}}</label> -->\r\n\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/tenant-settings')\" matTooltip=\"Organisation Settings\">\r\n <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon>\r\n </button>\r\n <label style=\"font-size: 14px;margin-right: 20px;\">{{tenantName}}</label>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/bug')\" matTooltip=\"Support\">\r\n <mat-icon >help</mat-icon>\r\n </button>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/notifications')\" matTooltip=\"Notifications\">\r\n <mat-icon [matBadge]=\"notificationCount$ | async\" [matBadgeHidden]=\"(notificationCount$ | async) === 0\" matBadgeColor=\"warn\" matBadgeSize=\"small\">notifications</mat-icon>\r\n </button>\r\n\r\n </div>\r\n\r\n\r\n\r\n <button mat-icon-button matTooltip=\"My Account\" [matMenuTriggerFor]=\"userAccountMenu\"><mat-icon>account_circle</mat-icon></button>\r\n <label style=\"font-size: 14px;\">{{loggedUserFullName}}</label>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"logoff()\" matTooltip=\"Signout\">\r\n <mat-icon>logout</mat-icon>\r\n </button>\r\n\r\n\r\n <!-- my account menu -->\r\n <mat-menu #userAccountMenu [overlapTrigger]=\"false\" yPosition=\"below\">\r\n\r\n\r\n <button mat-menu-item routerLink=\"home/user/profile\">\r\n <mat-icon>person</mat-icon><span>Profile</span>\r\n </button>\r\n\r\n <button mat-menu-item routerLink=\"home/admin/bug\" *ngIf=\"dataService.appConfig.multitenant && smallScreen\">\r\n <mat-icon>help</mat-icon> <span>Help</span>\r\n </button>\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <button mat-menu-item (click)=\"logoff()\">\r\n <mat-icon>logout</mat-icon>Logout\r\n </button>\r\n\r\n </mat-menu>\r\n\r\n</mat-toolbar>\r\n\r\n\r\n\r\n\r\n<mat-sidenav-container class=\"app-container\" [hasBackdrop]=\"smallScreen\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\">\r\n\r\n <mat-sidenav #sidenav [mode]=\"smallScreen ? 'over' : 'side'\" [class.mat-elevation-z4]=\"true\" [opened]=\"isExpanded\" class=\"app-sidenav side-color\" style=\"height: 100%;\"\r\n [ngStyle]=\"{'width': dataService.appConfig.navWidth}\">\r\n <mat-nav-list >\r\n\r\n <ng-container *ngFor=\"let cap of dataService.appConfig.capItems\" >\r\n\r\n <!-- Menu item \u2014 Added: isFeatureAllowed check for plan-based gating -->\r\n <mat-list-item [routerLink]=\"cap.link\" *ngIf=\"myRole[cap.name] && cap.showMenu && (!cap.capSubItems || cap.capSubItems && cap.ignoreSubsDisplay) && isFeatureAllowed(cap)\" style=\"height: 40px;font-size: 15px;\"\r\n (click)=\"smallScreen ? toggle() : null\">\r\n <mat-icon [ngStyle]=\"{'color': cap.color}\" style=\"margin-right: 5px;\">{{cap.icon}}</mat-icon>{{cap.display}}\r\n </mat-list-item>\r\n\r\n <!-- Menu With Sub items \u2014 Added: isFeatureAllowed check -->\r\n <mat-expansion-panel class=\"side-color\" [class.mat-elevation-z0]=\"true\" *ngIf=\"myRole[cap.name] && cap.showMenu && cap.capSubItems && !cap.ignoreSubsDisplay && isFeatureAllowed(cap)\">\r\n\r\n <mat-expansion-panel-header style=\"height: 40px;padding-left: 15px;\">\r\n <mat-icon [ngStyle]=\"{'color': cap.color}\" style=\"margin-right: 5px;\">{{cap.icon != 'navigate_next' ? cap.icon : 'fiber_manual_record' }}</mat-icon>{{cap.display}}\r\n </mat-expansion-panel-header>\r\n\r\n <!-- Sub items - Changed: Use ng-container to avoid blank spaces for hidden items -->\r\n <mat-nav-list>\r\n <ng-container *ngFor=\"let capSub of getSubItems(cap)\">\r\n <mat-list-item [routerLink]=\"capSub.link\" style=\"height: 30px; font-size: 15px; padding-left: 4px; padding-right: 10px; margin-bottom: 5px;\" (click)=\"smallScreen ? toggle() : null\" *ngIf=\"myRole[capSub.name] && capSub.showMenu && isFeatureAllowed(capSub)\" [matTooltip]=\"capSub.display\" matTooltipPosition=\"right\">\r\n <mat-icon [ngStyle]=\"{'color': capSub.color}\" style=\"margin-right: 5px;\">{{capSub.icon}}</mat-icon>{{capSub.display}}\r\n </mat-list-item>\r\n </ng-container>\r\n </mat-nav-list>\r\n\r\n </mat-expansion-panel>\r\n\r\n </ng-container>\r\n\r\n </mat-nav-list>\r\n </mat-sidenav>\r\n\r\n\r\n\r\n <mat-sidenav-content class=\"tin-bg-image\" style=\"padding: 0px 12px;\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\">\r\n <hr style=\"margin-top: 0px;\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n </mat-sidenav-content>\r\n\r\n</mat-sidenav-container>\r\n\r\n\r\n<!-- footer -->\r\n<div class=\"tin-center\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\">\r\n <label style=\"text-align: center; font-size: 12px;\">&copy; {{nowDate | date : 'yyyy'}} <a color=\"primary\" class=\"terms-link\" [href]=\"appConfig.siteUrl\" target=\"_blank\">{{footer}}</a> | <a color=\"primary\" class=\"terms-link\" style=\"cursor: pointer;\" (click)=\"openTerms()\">Terms</a> | <a color=\"primary\" class=\"terms-link\" style=\"cursor: pointer;\" (click)=\"openPrivacy()\">Privacy Policy</a></label>\r\n</div>\r\n\r\n\r\n<div class=\"tin-bg-image\" *ngIf=\"!loggedin && dataService.appConfig.navigation == 'side'\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n</div>\r\n\r\n\r\n<!-- SIDE-MODERN -->\r\n\r\n<!-- Changed: Side-modern navigation layout -->\r\n<div class=\"sm-layout\"\r\n *ngIf=\"loggedin && dataService.appConfig.navigation == 'side-modern'\"\r\n [class.sm-mini]=\"isMiniSidebar && !isMiniHovered\"\r\n [class.sm-mini-hovered]=\"isMiniSidebar && isMiniHovered\"\r\n [class.sm-mobile-open]=\"smallScreen && isExpanded\">\r\n\r\n <!-- Sidebar -->\r\n <aside class=\"sm-sidebar\"\r\n (mouseenter)=\"onMiniMouseEnter()\"\r\n (mouseleave)=\"onMiniMouseLeave()\">\r\n\r\n <!-- Background layers -->\r\n <div class=\"sm-sidebar-bg\">\r\n <div class=\"sm-sidebar-bg-image\" *ngIf=\"appConfig.navImage\" [ngStyle]=\"{'background-image': 'url(' + appConfig.navImage + ')'}\"></div>\r\n <div class=\"sm-sidebar-bg-overlay\" [ngStyle]=\"{'background-color': appConfig.navColor}\"></div>\r\n </div>\r\n\r\n <!-- Sidebar content -->\r\n <div class=\"sm-sidebar-content\">\r\n\r\n <!-- Brand -->\r\n <div class=\"sm-brand\">\r\n <img *ngIf=\"appConfig.logo\" [src]=\"appConfig.logo\" alt=\"logo\" />\r\n <span class=\"sm-brand-name\">{{appConfig.appName}}</span>\r\n </div>\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Profile -->\r\n <div class=\"sm-profile\">\r\n <mat-icon class=\"sm-profile-icon\">account_circle</mat-icon>\r\n <div class=\"sm-profile-info\">\r\n <div class=\"sm-profile-name\">{{loggedUserFullName}}</div>\r\n <div class=\"sm-profile-role\">{{tenantName || 'User'}}</div>\r\n </div>\r\n </div>\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Scrollable menu -->\r\n <div class=\"sm-menu-scroll\">\r\n\r\n <ng-container *ngFor=\"let cap of dataService.appConfig.capItems\">\r\n\r\n <!-- Simple menu item (no sub-items or ignoring sub display) \u2014 Added: isFeatureAllowed check -->\r\n <div *ngIf=\"myRole[cap.name] && cap.showMenu && (!cap.capSubItems || cap.ignoreSubsDisplay) && isFeatureAllowed(cap)\"\r\n class=\"sm-menu-item\"\r\n [class.sm-active]=\"isActiveRoute(cap.link)\"\r\n (click)=\"modernNavigate(cap.link)\">\r\n <mat-icon class=\"sm-menu-icon\">{{cap.icon != 'navigate_next' ? cap.icon : 'dashboard'}}</mat-icon>\r\n <span class=\"sm-menu-text\">{{cap.display}}</span>\r\n </div>\r\n\r\n <!-- Parent menu item with sub-items \u2014 Added: isFeatureAllowed check -->\r\n <ng-container *ngIf=\"myRole[cap.name] && cap.showMenu && cap.capSubItems && !cap.ignoreSubsDisplay && isFeatureAllowed(cap)\">\r\n\r\n <!-- Parent item (toggles sub-menu) -->\r\n <div class=\"sm-menu-item\"\r\n [class.sm-active]=\"isParentActive(cap) && !isMenuOpen(cap.name)\"\r\n (click)=\"toggleModernMenu(cap.name)\">\r\n <mat-icon class=\"sm-menu-icon\">{{cap.icon != 'navigate_next' ? cap.icon : 'dashboard'}}</mat-icon>\r\n <span class=\"sm-menu-text\">{{cap.display}}</span>\r\n <mat-icon class=\"sm-caret\" [class.sm-caret-open]=\"isMenuOpen(cap.name)\">expand_more</mat-icon>\r\n </div>\r\n\r\n <!-- Sub-menu container (animated) -->\r\n <div class=\"sm-submenu\" [class.sm-submenu-open]=\"isMenuOpen(cap.name)\">\r\n <ng-container *ngFor=\"let sub of getSubItems(cap)\">\r\n <div *ngIf=\"myRole[sub.name] && sub.showMenu && isFeatureAllowed(sub)\"\r\n class=\"sm-submenu-item\"\r\n [class.sm-active]=\"isActiveRoute(sub.link)\"\r\n (click)=\"modernNavigate(sub.link)\">\r\n <mat-icon *ngIf=\"sub.icon && sub.icon != 'navigate_next'\" class=\"sm-sub-icon\">{{sub.icon}}</mat-icon>\r\n <span *ngIf=\"!sub.icon || sub.icon == 'navigate_next'\" class=\"sm-initials\">{{getInitials(sub.display)}}</span>\r\n <span class=\"sm-menu-text\">{{sub.display}}</span>\r\n </div>\r\n </ng-container>\r\n </div>\r\n\r\n </ng-container>\r\n\r\n </ng-container>\r\n\r\n </div>\r\n\r\n </div>\r\n </aside>\r\n\r\n <!-- Mobile backdrop -->\r\n <div class=\"sm-backdrop\" (click)=\"isExpanded = false\"></div>\r\n\r\n <!-- Main content -->\r\n <div class=\"sm-main\">\r\n\r\n <!-- Top bar - Changed: Added scroll class for frosted glass effect -->\r\n <div class=\"sm-topbar\" [class.sm-topbar-scrolled]=\"topbarScrolled\">\r\n <button mat-icon-button (click)=\"smallScreen ? toggle() : toggleMiniSidebar()\" matTooltip=\"Menu\">\r\n <mat-icon>menu</mat-icon>\r\n </button>\r\n\r\n <!-- Changed: Mobile branding - show logo + app name when sidebar is hidden on small screens -->\r\n <img *ngIf=\"smallScreen && appConfig.logo\" [src]=\"appConfig.logo\" alt=\"logo\" class=\"sm-topbar-logo\" />\r\n <span *ngIf=\"smallScreen\" class=\"sm-topbar-brand\">{{appConfig.appName}}</span>\r\n\r\n <span class=\"sm-topbar-spacer\"></span>\r\n\r\n <!-- Multitenant buttons -->\r\n <div *ngIf=\"dataService.appConfig.multitenant\" style=\"display: flex; align-items: center;\">\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/tenant-settings')\" matTooltip=\"Organisation Settings\">\r\n <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon>\r\n </button>\r\n <span class=\"sm-topbar-label\">{{tenantName}}</span>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/bug')\" matTooltip=\"Support\">\r\n <mat-icon>help</mat-icon>\r\n </button>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/notifications')\" matTooltip=\"Notifications\">\r\n <mat-icon [matBadge]=\"notificationCount$ | async\" [matBadgeHidden]=\"(notificationCount$ | async) === 0\" matBadgeColor=\"warn\" matBadgeSize=\"small\">notifications</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Profile menu -->\r\n <button mat-icon-button matTooltip=\"My Account\" [matMenuTriggerFor]=\"smProfileMenu\">\r\n <mat-icon>account_circle</mat-icon>\r\n </button>\r\n <span class=\"sm-topbar-label\">{{loggedUserFullName}}</span>\r\n\r\n <mat-menu #smProfileMenu=\"matMenu\" [overlapTrigger]=\"false\" yPosition=\"below\">\r\n <button mat-menu-item routerLink=\"home/user/profile\">\r\n <mat-icon>person</mat-icon><span>Profile</span>\r\n </button>\r\n <button mat-menu-item routerLink=\"home/admin/bug\" *ngIf=\"dataService.appConfig.multitenant && smallScreen\">\r\n <mat-icon>help</mat-icon><span>Help</span>\r\n </button>\r\n <mat-divider></mat-divider>\r\n <button mat-menu-item (click)=\"logoff()\">\r\n <mat-icon>logout</mat-icon>Logout\r\n </button>\r\n </mat-menu>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"logoff()\" matTooltip=\"Signout\">\r\n <mat-icon>logout</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Page content - Changed: Replaced tin-bg-image with sm-content modern texture -->\r\n <div class=\"sm-content\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"sm-footer\">\r\n &copy; {{nowDate | date : 'yyyy'}} <a [href]=\"appConfig.siteUrl\" target=\"_blank\">{{footer}}</a> | <a (click)=\"openTerms()\">Terms</a> | <a (click)=\"openPrivacy()\">Privacy Policy</a>\r\n </div>\r\n\r\n </div>\r\n\r\n</div>\r\n\r\n<!-- Not logged in fallback for side-modern -->\r\n<div class=\"tin-bg-image\" *ngIf=\"!loggedin && dataService.appConfig.navigation == 'side-modern'\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n</div>", styles: ["a.navbar-brand{white-space:normal;text-align:center;word-break:break-all}html{font-size:14px}.box-shadow{box-shadow:0 .25rem .75rem #0000000d}.toolbar-item-spacer{flex:1 1 auto}.toolbar{height:60px;display:flex;align-items:center;background-color:#03a;color:#fff;margin-bottom:0!important}.toolbar button,.toolbar .mat-mdc-button,.toolbar .mat-mdc-icon-button{color:#fff!important}.toolbar mat-icon{color:#fff!important}.stack-top{z-index:9;margin:20px}.navitems{background-color:#03a}.app-container{height:90%;margin:0}.app-sidenav{width:200px;border:1px solid rgb(192,190,199)}.side-color{background-color:#e6f4ff}.app-sidenav mat-list-item{display:flex!important;align-items:center!important}.app-sidenav mat-icon{display:inline-flex!important;align-items:center!important;vertical-align:middle!important}.app-sidenav mat-expansion-panel-header mat-icon{display:inline-flex!important;align-items:center!important;vertical-align:middle!important}::ng-deep .app-sidenav .mat-expansion-panel-body{padding-bottom:5px!important;padding-right:5px!important}::ng-deep .app-sidenav .mdc-list{padding-bottom:0!important}.sm-layout{display:flex;min-height:100vh;position:relative}.sm-sidebar{position:fixed;top:0;left:0;bottom:0;width:260px;z-index:1030;overflow:hidden;transition:width .3s cubic-bezier(.4,0,.2,1)}.sm-sidebar-bg{position:absolute;inset:0;z-index:0}.sm-sidebar-bg-image{position:absolute;inset:0;background-size:cover;background-position:center}.sm-sidebar-bg-overlay{position:absolute;inset:0}.sm-sidebar-content{position:relative;z-index:1;display:flex;flex-direction:column;height:100%;color:#fff}.sm-brand{display:flex;align-items:center;padding:18px 15px 10px;min-height:60px;text-decoration:none;white-space:nowrap;overflow:hidden}.sm-brand img{height:34px;width:34px;object-fit:contain;margin-right:12px;flex-shrink:0}.sm-brand-name{font-size:16px;font-weight:500;letter-spacing:.5px;color:#fff;overflow:hidden;text-overflow:ellipsis;transition:opacity .2s ease}.sm-profile{display:flex;align-items:center;padding:12px 15px;white-space:nowrap;overflow:hidden}.sm-profile-icon{font-size:34px!important;width:34px!important;height:34px!important;margin-right:12px;flex-shrink:0;color:#fffc}.sm-profile-info{overflow:hidden;transition:opacity .2s ease}.sm-profile-name{font-size:14px;font-weight:500;color:#fff;line-height:1.3;overflow:hidden;text-overflow:ellipsis}.sm-profile-role{font-size:11px;color:#fff9;line-height:1.3;overflow:hidden;text-overflow:ellipsis}.sm-sidebar mat-divider{border-color:#ffffff26!important;margin:0 15px}.sm-menu-scroll{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px 0}.sm-menu-scroll::-webkit-scrollbar{width:4px}.sm-menu-scroll::-webkit-scrollbar-track{background:transparent}.sm-menu-scroll::-webkit-scrollbar-thumb{background:#fff3;border-radius:2px}.sm-menu-item{display:flex;align-items:center;padding:10px 15px;margin:2px 15px;border-radius:4px;cursor:pointer;color:#fff;font-size:13px;font-weight:400;letter-spacing:.3px;transition:all .15s ease;text-decoration:none;white-space:nowrap;overflow:hidden}.sm-menu-item:hover{background:#ffffff1f}.sm-menu-item.sm-active{background-color:#fff;color:#3c4858;box-shadow:0 4px 20px #00000024,0 7px 10px -5px #0003;font-weight:500}.sm-menu-item.sm-active .sm-menu-icon{color:#3c4858}.sm-menu-icon{font-size:20px!important;width:24px!important;height:24px!important;display:inline-flex!important;align-items:center;justify-content:center;margin-right:12px;flex-shrink:0;color:#fffc;transition:color .15s ease}.sm-menu-text{flex:1;overflow:hidden;text-overflow:ellipsis;transition:opacity .2s ease}.sm-caret{font-size:18px!important;width:18px!important;height:18px!important;transition:transform .3s cubic-bezier(.4,0,.2,1);flex-shrink:0;color:#fff9}.sm-caret.sm-caret-open{transform:rotate(180deg)}.sm-active .sm-caret{color:#3c4858}.sm-submenu{max-height:0;overflow:hidden;transition:max-height .35s cubic-bezier(.4,0,.2,1)}.sm-submenu.sm-submenu-open{max-height:1000px}.sm-submenu-item{display:flex;align-items:center;padding:8px 15px 8px 30px;margin:1px 15px;border-radius:4px;cursor:pointer;color:#fffc;font-size:12px;font-weight:400;transition:all .15s ease;white-space:nowrap;overflow:hidden}.sm-submenu-item:hover{background:#ffffff1f;color:#fff}.sm-submenu-item.sm-active{background-color:#fff;color:#3c4858;box-shadow:0 4px 20px #00000024,0 7px 10px -5px #0003;font-weight:500}.sm-submenu-item.sm-active .sm-sub-icon{color:#3c4858}.sm-sub-icon{font-size:16px!important;width:20px!important;height:20px!important;display:inline-flex!important;align-items:center;justify-content:center;margin-right:10px;flex-shrink:0;color:#fff9}.sm-initials{width:20px;height:20px;border-radius:50%;background:#ffffff26;display:inline-flex;align-items:center;justify-content:center;font-size:9px;font-weight:600;margin-right:10px;flex-shrink:0;color:#fffc}.sm-active .sm-initials{background:#3c48581f;color:#3c4858}.sm-main{flex:1;margin-left:260px;min-height:100vh;display:flex;flex-direction:column;transition:margin-left .3s cubic-bezier(.4,0,.2,1);background-color:#eef2f7}.sm-topbar{display:flex;align-items:center;padding:8px 16px;min-height:56px;background-color:#eef2f7;background-image:radial-gradient(circle,#d5dbe3 1px,transparent 1px);background-size:16px 16px;border-bottom:1px solid rgba(0,0,0,.08);position:sticky;top:0;z-index:1020;transition:background .3s ease,backdrop-filter .3s ease}.sm-topbar-scrolled{background-color:#eef2f78c;background-image:none;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);box-shadow:0 1px 3px #0000000f}.sm-topbar-spacer{flex:1 1 auto}.sm-topbar-logo{height:32px;width:32px;object-fit:contain;margin-right:8px}.sm-topbar-brand{font-size:18px;font-weight:500;margin-right:8px;white-space:nowrap}.sm-topbar-label{font-size:14px;margin-right:4px;display:inline-flex;align-items:center;align-self:center;height:40px;line-height:1}.sm-topbar .mat-mdc-icon-button{display:inline-flex!important;align-items:center!important;justify-content:center!important}.sm-content{flex:1;padding:12px;background-color:#e5eaf2;background-image:radial-gradient(ellipse at 50% 45%,#fffffff2,#fff6 35%,#fff0 60%),radial-gradient(circle,#bec7d4 1px,transparent 1px);background-size:100% 100%,16px 16px;min-height:calc(100vh - 104px)}.sm-footer{padding:12px 16px;text-align:center;font-size:12px;color:#999;border-top:1px solid #e0e0e0;background:#fff}.sm-footer a{color:inherit;cursor:pointer}.sm-footer a:hover{text-decoration:underline}.sm-backdrop{display:none;position:fixed;inset:0;background:#00000080;z-index:1025}.sm-layout.sm-mini .sm-sidebar{width:80px}.sm-layout.sm-mini .sm-main{margin-left:80px}.sm-layout.sm-mini .sm-brand-name,.sm-layout.sm-mini .sm-profile-info,.sm-layout.sm-mini .sm-menu-text,.sm-layout.sm-mini .sm-caret,.sm-layout.sm-mini .sm-submenu{display:none}.sm-layout.sm-mini .sm-sidebar mat-divider{margin:0 10px}.sm-layout.sm-mini .sm-brand{justify-content:center;padding:18px 0 10px}.sm-layout.sm-mini .sm-brand img{margin-right:0}.sm-layout.sm-mini .sm-profile{justify-content:center;padding:12px 0}.sm-layout.sm-mini .sm-profile-icon{margin-right:0}.sm-layout.sm-mini .sm-menu-item{justify-content:center;padding:12px 0;margin:2px 0}.sm-layout.sm-mini .sm-menu-icon{margin-right:0;font-size:22px!important}.sm-layout.sm-mini-hovered .sm-sidebar{width:260px;box-shadow:4px 0 20px #0000004d}.sm-layout.sm-mini-hovered .sm-main{margin-left:80px}.sm-layout.sm-mini-hovered .sm-brand-name,.sm-layout.sm-mini-hovered .sm-profile-info,.sm-layout.sm-mini-hovered .sm-menu-text,.sm-layout.sm-mini-hovered .sm-caret{display:initial}.sm-layout.sm-mini-hovered .sm-submenu{display:block}.sm-layout.sm-mini-hovered .sm-sidebar mat-divider{margin:0 15px}.sm-layout.sm-mini-hovered .sm-brand{justify-content:flex-start;padding:18px 15px 10px}.sm-layout.sm-mini-hovered .sm-brand img{margin-right:12px}.sm-layout.sm-mini-hovered .sm-profile{justify-content:flex-start;padding:12px 15px}.sm-layout.sm-mini-hovered .sm-profile-icon{margin-right:12px}.sm-layout.sm-mini-hovered .sm-menu-item{justify-content:flex-start;padding:10px 15px;margin:2px 15px}.sm-layout.sm-mini-hovered .sm-menu-icon{margin-right:12px;font-size:20px!important}@media (max-width: 600px){.sm-sidebar{transform:translate(-100%);transition:transform .3s cubic-bezier(.4,0,.2,1);width:260px!important}.sm-layout.sm-mobile-open .sm-sidebar{transform:translate(0)}.sm-layout.sm-mobile-open .sm-backdrop{display:block}.sm-main{margin-left:0!important}.sm-layout.sm-mini .sm-sidebar{width:260px!important}.sm-layout.sm-mini .sm-brand-name,.sm-layout.sm-mini .sm-profile-info,.sm-layout.sm-mini .sm-menu-text,.sm-layout.sm-mini .sm-caret{display:initial}.sm-layout.sm-mini .sm-submenu{display:block}.sm-layout.sm-mini .sm-sidebar mat-divider{margin:0 15px}.sm-layout.sm-mini .sm-menu-item{justify-content:flex-start;padding:10px 15px;margin:2px 15px}.sm-layout.sm-mini .sm-menu-icon{margin-right:12px;font-size:20px!important}.sm-layout.sm-mini .sm-brand{justify-content:flex-start;padding:18px 15px 10px}.sm-layout.sm-mini .sm-brand img{margin-right:12px}.sm-layout.sm-mini .sm-profile{justify-content:flex-start;padding:12px 15px}.sm-layout.sm-mini .sm-profile-icon{margin-right:12px}}\n"] }]
9549
+ args: [{ selector: 'spa-nav-menu', standalone: false, template: "<header *ngIf=\"loggedin && dataService.appConfig.navigation == 'top'\">\r\n\r\n <!-- Changed: Removed mb-3 class to eliminate gap between toolbar and content -->\r\n <nav class=\"toolbar navbar navbar-expand-sm navbar-toggleable-sm navbar-light border-bottom box-shadow\" style=\"padding-right: 10px;\">\r\n\r\n\r\n <div class=\"container-fluid\" style=\"padding-right: 0px;\">\r\n\r\n <img *ngIf=\"appConfig.logo!=''\" [src]=\"appConfig.logo\" style=\"height: 50px; margin-right: 2em\" />\r\n\r\n <div>\r\n <!-- <div style=\"font-size: 20px;\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant && tenantName\" style=\"font-size: 12px;\">\r\n {{tenantName}}\r\n </div> -->\r\n\r\n <div *ngIf=\"!dataService.appConfig.multitenant\" style=\"font-size: 22px;\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant\" style=\"font-size: 20px; ; font-weight: 400;\" [ngStyle]=\"{'margin-top': dataService.appConfig.multitenant ? '12px' : ''}\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant && tenantName\" style=\"font-size: 12px; margin-bottom: 5px;\">\r\n {{tenantName}}\r\n </div>\r\n\r\n </div>\r\n\r\n\r\n\r\n <button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\".navbar-collapse\" aria-label=\"Toggle navigation\" [attr.aria-expanded]=\"isExpanded\" (click)=\"toggle()\">\r\n <span class=\"navbar-toggler-icon\"></span>\r\n </button>\r\n\r\n <div *ngIf=\"myRole\" class=\" navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse stack-top\" style=\"margin-right: 0px;\" [ngClass]=\"{ show: isExpanded, navitems: isExpanded }\" >\r\n\r\n <button mat-icon-button (click)=\"logoff()\" > <mat-icon>logout</mat-icon> </button>\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant\">\r\n\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/tenant-settings')\" > <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon> </button>\r\n\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/bug')\"> <mat-icon >support_agent</mat-icon> </button>\r\n\r\n <!-- <button mat-icon-button (click)=\"redirectTo('home/admin/notifications')\"> <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon> </button> -->\r\n </div>\r\n\r\n\r\n <button id=\"btnUser\" mat-button [matMenuTriggerFor]=\"profileMenu\" ><mat-icon style=\"font-size: 24px;\">account_circle</mat-icon> &nbsp;{{loggedUserFullName}}</button>\r\n\r\n <mat-menu #profileMenu=\"matMenu\">\r\n <button id=\"btnProfile\" mat-menu-item (click)=\"redirectTo('home/user/profile')\" >Profile</button>\r\n <button id=\"btnLogOff\" mat-menu-item (click)=\"logoff()\">Log Off</button>\r\n </mat-menu>\r\n\r\n <div *ngFor=\"let item of reversedCapItems\">\r\n\r\n <!-- Menu Item \u2014 Added: isFeatureAllowed check for plan-based gating -->\r\n <button id=\"btnMenu\" *ngIf=\"myRole[item.name] && !item.capSubItems && item.showMenu && isFeatureAllowed(item)\" mat-button (click)=\"redirectTo(item.link)\">{{item.display}}</button>\r\n\r\n <!-- Menu Item with Sub items ignored \u2014 Added: isFeatureAllowed check -->\r\n <button id=\"btnMenu\" *ngIf=\"myRole[item.name] && item.capSubItems && item.showMenu && item.ignoreSubsDisplay && isFeatureAllowed(item)\" mat-button (click)=\"redirectTo(item.link)\">{{item.display}}</button>\r\n\r\n <!-- Menu Item with Sub items to display \u2014 Added: isFeatureAllowed check -->\r\n <button id=\"btnMenu\" *ngIf=\"myRole[item.name] && item.capSubItems && item.showMenu && !item.ignoreSubsDisplay && isFeatureAllowed(item)\" mat-button [matMenuTriggerFor]=\"adminMenu\">{{item.display}}</button>\r\n\r\n\r\n <!-- Sub Menu Items \u2014 Added: isFeatureAllowed check on sub-items -->\r\n <mat-menu #adminMenu=\"matMenu\">\r\n\r\n <div *ngFor=\"let subItem of item.capSubItems\">\r\n\r\n <button *ngIf=\"myRole[subItem.name] && subItem.showMenu && isFeatureAllowed(subItem)\" mat-menu-item (click)=\"redirectTo(subItem.link)\">{{subItem.display}}</button>\r\n\r\n </div>\r\n\r\n </mat-menu>\r\n\r\n </div>\r\n\r\n </div>\r\n\r\n\r\n </div>\r\n\r\n </nav>\r\n\r\n</header>\r\n\r\n<!-- Changed: Removed top/bottom padding to eliminate gaps, but kept left/right padding for content spacing -->\r\n<div class=\"container-fluid tin-bg-image\" *ngIf=\"dataService.appConfig.navigation == 'top'\" style=\"padding: 12px 12px; margin: 0;\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n</div>\r\n\r\n\r\n\r\n\r\n\r\n\r\n<!-- SIDE -->\r\n<mat-toolbar class=\"tin-bg-image-toolbar\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\" style=\"padding: 0px 8px;\">\r\n\r\n <button mat-icon-button (click)=\"toggle()\" matTooltip=\"Menu\">\r\n <mat-icon>menu</mat-icon>\r\n </button>\r\n\r\n <img [src]=\"dataService.appConfig.logo\" style=\"height: 50px;\" />\r\n\r\n <div style=\"padding-left: 10px; \">\r\n\r\n <div style=\"font-size: 22px; font-weight: 400;\">\r\n {{appConfig.appName}}\r\n </div>\r\n\r\n <!-- <div style=\"font-size: 20px; height: 25px; font-weight: 400;\" [ngStyle]=\"{'margin-top': dataService.appConfig.multitenant ? '12px' : ''}\">\r\n {{appConfig.appName}}\r\n </div> -->\r\n\r\n <!-- <div *ngIf=\"dataService.appConfig.multitenant && tenantName\" style=\"font-size: 12px; margin-bottom: 5px;\">\r\n {{tenantName}}\r\n </div> -->\r\n\r\n </div>\r\n\r\n\r\n\r\n <span class=\"toolbar-item-spacer\"></span>\r\n\r\n <!-- buttons -->\r\n\r\n <div *ngIf=\"dataService.appConfig.multitenant\" style=\"display: flex; align-items: center;\">\r\n\r\n <!-- <label style=\"font-size: 14px;\">Hi, {{loggedUserFullName}}</label> -->\r\n\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/tenant-settings')\" matTooltip=\"Organisation Settings\">\r\n <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon>\r\n </button>\r\n <label style=\"font-size: 14px;margin-right: 20px;\">{{tenantName}}</label>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/bug')\" matTooltip=\"Support\">\r\n <mat-icon >help</mat-icon>\r\n </button>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/notifications')\" matTooltip=\"Notifications\">\r\n <mat-icon [matBadge]=\"notificationCount$ | async\" [matBadgeHidden]=\"(notificationCount$ | async) === 0\" matBadgeColor=\"warn\" matBadgeSize=\"small\">notifications</mat-icon>\r\n </button>\r\n\r\n </div>\r\n\r\n\r\n\r\n <button mat-icon-button matTooltip=\"My Account\" [matMenuTriggerFor]=\"userAccountMenu\"><mat-icon>account_circle</mat-icon></button>\r\n <label style=\"font-size: 14px;\">{{loggedUserFullName}}</label>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"logoff()\" matTooltip=\"Signout\">\r\n <mat-icon>logout</mat-icon>\r\n </button>\r\n\r\n\r\n <!-- my account menu -->\r\n <mat-menu #userAccountMenu [overlapTrigger]=\"false\" yPosition=\"below\">\r\n\r\n\r\n <button mat-menu-item routerLink=\"home/user/profile\">\r\n <mat-icon>person</mat-icon><span>Profile</span>\r\n </button>\r\n\r\n <button mat-menu-item routerLink=\"home/admin/bug\" *ngIf=\"dataService.appConfig.multitenant && smallScreen\">\r\n <mat-icon>help</mat-icon> <span>Help</span>\r\n </button>\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <button mat-menu-item (click)=\"logoff()\">\r\n <mat-icon>logout</mat-icon>Logout\r\n </button>\r\n\r\n </mat-menu>\r\n\r\n</mat-toolbar>\r\n\r\n\r\n\r\n\r\n<mat-sidenav-container class=\"app-container\" [hasBackdrop]=\"smallScreen\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\">\r\n\r\n <mat-sidenav #sidenav [mode]=\"smallScreen ? 'over' : 'side'\" [class.mat-elevation-z4]=\"true\" [opened]=\"isExpanded\" class=\"app-sidenav side-color\" style=\"height: 100%;\"\r\n [ngStyle]=\"{'width': dataService.appConfig.navWidth}\">\r\n <mat-nav-list >\r\n\r\n <ng-container *ngFor=\"let cap of dataService.appConfig.capItems\" >\r\n\r\n <!-- Menu item \u2014 Added: isFeatureAllowed check for plan-based gating -->\r\n <mat-list-item [routerLink]=\"cap.link\" *ngIf=\"myRole[cap.name] && cap.showMenu && (!cap.capSubItems || cap.capSubItems && cap.ignoreSubsDisplay) && isFeatureAllowed(cap)\" style=\"height: 40px;font-size: 15px;\"\r\n (click)=\"smallScreen ? toggle() : null\">\r\n <mat-icon [ngStyle]=\"{'color': cap.color}\" style=\"margin-right: 5px;\">{{cap.icon}}</mat-icon>{{cap.display}}\r\n </mat-list-item>\r\n\r\n <!-- Menu With Sub items \u2014 Added: isFeatureAllowed check -->\r\n <mat-expansion-panel class=\"side-color\" [class.mat-elevation-z0]=\"true\" *ngIf=\"myRole[cap.name] && cap.showMenu && cap.capSubItems && !cap.ignoreSubsDisplay && isFeatureAllowed(cap)\">\r\n\r\n <mat-expansion-panel-header style=\"height: 40px;padding-left: 15px;\">\r\n <mat-icon [ngStyle]=\"{'color': cap.color}\" style=\"margin-right: 5px;\">{{cap.icon != 'navigate_next' ? cap.icon : 'fiber_manual_record' }}</mat-icon>{{cap.display}}\r\n </mat-expansion-panel-header>\r\n\r\n <!-- Sub items - Changed: Use ng-container to avoid blank spaces for hidden items -->\r\n <mat-nav-list>\r\n <ng-container *ngFor=\"let capSub of getSubItems(cap)\">\r\n <mat-list-item [routerLink]=\"capSub.link\" style=\"height: 30px; font-size: 15px; padding-left: 4px; padding-right: 10px; margin-bottom: 5px;\" (click)=\"smallScreen ? toggle() : null\" *ngIf=\"myRole[capSub.name] && capSub.showMenu && isFeatureAllowed(capSub)\" [matTooltip]=\"capSub.display\" matTooltipPosition=\"right\">\r\n <mat-icon [ngStyle]=\"{'color': capSub.color}\" style=\"margin-right: 5px;\">{{capSub.icon}}</mat-icon>{{capSub.display}}\r\n </mat-list-item>\r\n </ng-container>\r\n </mat-nav-list>\r\n\r\n </mat-expansion-panel>\r\n\r\n </ng-container>\r\n\r\n </mat-nav-list>\r\n </mat-sidenav>\r\n\r\n\r\n\r\n <mat-sidenav-content class=\"tin-bg-image\" style=\"padding: 0px 12px;\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\">\r\n <hr style=\"margin-top: 0px;\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n </mat-sidenav-content>\r\n\r\n</mat-sidenav-container>\r\n\r\n\r\n<!-- footer -->\r\n<div class=\"tin-center\" *ngIf=\"loggedin && dataService.appConfig.navigation == 'side'\">\r\n <label style=\"text-align: center; font-size: 12px;\">&copy; {{nowDate | date : 'yyyy'}} <a color=\"primary\" class=\"terms-link\" [href]=\"appConfig.siteUrl\" target=\"_blank\">{{footer}}</a> | <a color=\"primary\" class=\"terms-link\" style=\"cursor: pointer;\" (click)=\"openTerms()\">Terms</a> | <a color=\"primary\" class=\"terms-link\" style=\"cursor: pointer;\" (click)=\"openPrivacy()\">Privacy Policy</a></label>\r\n</div>\r\n\r\n\r\n<div class=\"tin-bg-image\" *ngIf=\"!loggedin && dataService.appConfig.navigation == 'side'\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n</div>\r\n\r\n\r\n<!-- SIDE-MODERN -->\r\n\r\n<!-- Changed: Side-modern navigation layout -->\r\n<div class=\"sm-layout\"\r\n *ngIf=\"loggedin && dataService.appConfig.navigation == 'side-modern'\"\r\n [class.sm-mini]=\"isMiniSidebar && !isMiniHovered\"\r\n [class.sm-mini-hovered]=\"isMiniSidebar && isMiniHovered\"\r\n [class.sm-mobile-open]=\"smallScreen && isExpanded\">\r\n\r\n <!-- Sidebar -->\r\n <aside class=\"sm-sidebar\"\r\n (mouseenter)=\"onMiniMouseEnter()\"\r\n (mouseleave)=\"onMiniMouseLeave()\">\r\n\r\n <!-- Background layers -->\r\n <div class=\"sm-sidebar-bg\">\r\n <div class=\"sm-sidebar-bg-image\" *ngIf=\"appConfig.navImage\" [ngStyle]=\"{'background-image': 'url(' + appConfig.navImage + ')'}\"></div>\r\n <div class=\"sm-sidebar-bg-overlay\" [ngStyle]=\"{'background-color': appConfig.navColor}\"></div>\r\n </div>\r\n\r\n <!-- Sidebar content -->\r\n <div class=\"sm-sidebar-content\">\r\n\r\n <!-- Brand -->\r\n <div class=\"sm-brand\">\r\n <img *ngIf=\"appConfig.logo\" [src]=\"appConfig.logo\" alt=\"logo\" />\r\n <span class=\"sm-brand-name\">{{appConfig.appName}}</span>\r\n </div>\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Profile -->\r\n <div class=\"sm-profile\">\r\n <mat-icon class=\"sm-profile-icon\">account_circle</mat-icon>\r\n <div class=\"sm-profile-info\">\r\n <div class=\"sm-profile-name\">{{loggedUserFullName}}</div>\r\n <div class=\"sm-profile-role\">{{tenantName || 'User'}}</div>\r\n </div>\r\n </div>\r\n\r\n <mat-divider></mat-divider>\r\n\r\n <!-- Scrollable menu -->\r\n <div class=\"sm-menu-scroll\">\r\n\r\n <ng-container *ngFor=\"let cap of dataService.appConfig.capItems\">\r\n\r\n <!-- Simple menu item (no sub-items or ignoring sub display) \u2014 Added: isFeatureAllowed check -->\r\n <div *ngIf=\"myRole[cap.name] && cap.showMenu && (!cap.capSubItems || cap.ignoreSubsDisplay) && isFeatureAllowed(cap)\"\r\n class=\"sm-menu-item\"\r\n [class.sm-active]=\"isActiveRoute(cap.link)\"\r\n (click)=\"modernNavigate(cap.link)\">\r\n <mat-icon class=\"sm-menu-icon\">{{cap.icon != 'navigate_next' ? cap.icon : 'dashboard'}}</mat-icon>\r\n <span class=\"sm-menu-text\">{{cap.display}}</span>\r\n </div>\r\n\r\n <!-- Parent menu item with sub-items \u2014 Added: isFeatureAllowed check -->\r\n <ng-container *ngIf=\"myRole[cap.name] && cap.showMenu && cap.capSubItems && !cap.ignoreSubsDisplay && isFeatureAllowed(cap)\">\r\n\r\n <!-- Parent item (toggles sub-menu) -->\r\n <div class=\"sm-menu-item\"\r\n [class.sm-active]=\"isParentActive(cap) && !isMenuOpen(cap.name)\"\r\n (click)=\"toggleModernMenu(cap.name)\">\r\n <mat-icon class=\"sm-menu-icon\">{{cap.icon != 'navigate_next' ? cap.icon : 'dashboard'}}</mat-icon>\r\n <span class=\"sm-menu-text\">{{cap.display}}</span>\r\n <mat-icon class=\"sm-caret\" [class.sm-caret-open]=\"isMenuOpen(cap.name)\">expand_more</mat-icon>\r\n </div>\r\n\r\n <!-- Sub-menu container (animated) -->\r\n <div class=\"sm-submenu\" [class.sm-submenu-open]=\"isMenuOpen(cap.name)\">\r\n <ng-container *ngFor=\"let sub of getSubItems(cap)\">\r\n <div *ngIf=\"myRole[sub.name] && sub.showMenu && isFeatureAllowed(sub)\"\r\n class=\"sm-submenu-item\"\r\n [class.sm-active]=\"isActiveRoute(sub.link)\"\r\n (click)=\"modernNavigate(sub.link)\">\r\n <mat-icon *ngIf=\"sub.icon && sub.icon != 'navigate_next'\" class=\"sm-sub-icon\">{{sub.icon}}</mat-icon>\r\n <span *ngIf=\"!sub.icon || sub.icon == 'navigate_next'\" class=\"sm-initials\">{{getInitials(sub.display)}}</span>\r\n <span class=\"sm-menu-text\">{{sub.display}}</span>\r\n </div>\r\n </ng-container>\r\n </div>\r\n\r\n </ng-container>\r\n\r\n </ng-container>\r\n\r\n </div>\r\n\r\n </div>\r\n </aside>\r\n\r\n <!-- Mobile backdrop -->\r\n <div class=\"sm-backdrop\" (click)=\"isExpanded = false\"></div>\r\n\r\n <!-- Main content -->\r\n <div class=\"sm-main\">\r\n\r\n <!-- Top bar - Changed: Added scroll class for frosted glass effect -->\r\n <div class=\"sm-topbar\" [class.sm-topbar-scrolled]=\"topbarScrolled\">\r\n <button mat-icon-button (click)=\"smallScreen ? toggle() : toggleMiniSidebar()\" matTooltip=\"Menu\">\r\n <mat-icon>menu</mat-icon>\r\n </button>\r\n\r\n <!-- Changed: Mobile branding - show logo + app name when sidebar is hidden on small screens -->\r\n <img *ngIf=\"smallScreen && appConfig.logo\" [src]=\"appConfig.logo\" alt=\"logo\" class=\"sm-topbar-logo\" />\r\n <span *ngIf=\"smallScreen\" class=\"sm-topbar-brand\">{{appConfig.appName}}</span>\r\n\r\n <span class=\"sm-topbar-spacer\"></span>\r\n\r\n <!-- Multitenant buttons -->\r\n <div *ngIf=\"dataService.appConfig.multitenant\" style=\"display: flex; align-items: center;\">\r\n <button mat-icon-button (click)=\"redirectTo('home/admin/tenant-settings')\" matTooltip=\"Organisation Settings\">\r\n <mat-icon fontSet=\"material-icons-round\">apartment</mat-icon>\r\n </button>\r\n <span class=\"sm-topbar-label\">{{tenantName}}</span>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/bug')\" matTooltip=\"Support\">\r\n <mat-icon>help</mat-icon>\r\n </button>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"redirectTo('home/admin/notifications')\" matTooltip=\"Notifications\">\r\n <mat-icon [matBadge]=\"notificationCount$ | async\" [matBadgeHidden]=\"(notificationCount$ | async) === 0\" matBadgeColor=\"warn\" matBadgeSize=\"small\">notifications</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Profile menu -->\r\n <button mat-icon-button matTooltip=\"My Account\" [matMenuTriggerFor]=\"smProfileMenu\">\r\n <mat-icon>account_circle</mat-icon>\r\n </button>\r\n <span class=\"sm-topbar-label\">{{loggedUserFullName}}</span>\r\n\r\n <mat-menu #smProfileMenu=\"matMenu\" [overlapTrigger]=\"false\" yPosition=\"below\">\r\n <button mat-menu-item routerLink=\"home/user/profile\">\r\n <mat-icon>person</mat-icon><span>Profile</span>\r\n </button>\r\n <button mat-menu-item routerLink=\"home/admin/bug\" *ngIf=\"dataService.appConfig.multitenant && smallScreen\">\r\n <mat-icon>help</mat-icon><span>Help</span>\r\n </button>\r\n <mat-divider></mat-divider>\r\n <button mat-menu-item (click)=\"logoff()\">\r\n <mat-icon>logout</mat-icon>Logout\r\n </button>\r\n </mat-menu>\r\n\r\n <button *ngIf=\"!smallScreen\" mat-icon-button (click)=\"logoff()\" matTooltip=\"Signout\">\r\n <mat-icon>logout</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <!-- Page content - Changed: Replaced tin-bg-image with sm-content modern texture -->\r\n <div class=\"sm-content\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"sm-footer\">\r\n &copy; {{nowDate | date : 'yyyy'}} <a [href]=\"appConfig.siteUrl\" target=\"_blank\">{{footer}}</a> | <a (click)=\"openTerms()\">Terms</a> | <a (click)=\"openPrivacy()\">Privacy Policy</a>\r\n </div>\r\n\r\n </div>\r\n\r\n</div>\r\n\r\n<!-- Not logged in fallback for side-modern -->\r\n<div class=\"tin-bg-image\" *ngIf=\"!loggedin && dataService.appConfig.navigation == 'side-modern'\">\r\n <router-outlet></router-outlet>\r\n <spa-loader [logo]=\"this.dataService.appConfig.logo\"></spa-loader>\r\n</div>", styles: ["a.navbar-brand{white-space:normal;text-align:center;word-break:break-all}html{font-size:14px}.box-shadow{box-shadow:0 .25rem .75rem #0000000d}.toolbar-item-spacer{flex:1 1 auto}.toolbar{height:60px;display:flex;align-items:center;background-color:#03a;color:#fff;margin-bottom:0!important}.toolbar button,.toolbar .mat-mdc-button,.toolbar .mat-mdc-icon-button{color:#fff!important}.toolbar mat-icon{color:#fff!important}.stack-top{z-index:9;margin:20px}.navitems{background-color:#03a}.app-container{height:90%;margin:0}.app-sidenav{width:200px;border:1px solid rgb(192,190,199)}.side-color{background-color:#e6f4ff}.app-sidenav mat-list-item{display:flex!important;align-items:center!important}.app-sidenav mat-icon{display:inline-flex!important;align-items:center!important;vertical-align:middle!important}.app-sidenav mat-expansion-panel-header mat-icon{display:inline-flex!important;align-items:center!important;vertical-align:middle!important}::ng-deep .app-sidenav .mat-expansion-panel-body{padding-bottom:5px!important;padding-right:5px!important}::ng-deep .app-sidenav .mdc-list{padding-bottom:0!important}.sm-layout{display:flex;min-height:100vh;position:relative}.sm-sidebar{position:fixed;top:0;left:0;bottom:0;width:260px;z-index:1030;overflow:hidden;transition:width .3s cubic-bezier(.4,0,.2,1)}.sm-sidebar-bg{position:absolute;inset:0;z-index:0}.sm-sidebar-bg-image{position:absolute;inset:0;background-size:cover;background-position:center}.sm-sidebar-bg-overlay{position:absolute;inset:0}.sm-sidebar-content{position:relative;z-index:1;display:flex;flex-direction:column;height:100%;color:#fff}.sm-brand{display:flex;align-items:center;padding:18px 15px 10px;min-height:60px;text-decoration:none;white-space:nowrap;overflow:hidden}.sm-brand img{height:34px;width:34px;object-fit:contain;margin-right:12px;flex-shrink:0}.sm-brand-name{font-size:16px;font-weight:500;letter-spacing:.5px;color:#fff;overflow:hidden;text-overflow:ellipsis;transition:opacity .2s ease}.sm-profile{display:flex;align-items:center;padding:12px 15px;white-space:nowrap;overflow:hidden}.sm-profile-icon{font-size:34px!important;width:34px!important;height:34px!important;margin-right:12px;flex-shrink:0;color:#fffc}.sm-profile-info{overflow:hidden;transition:opacity .2s ease}.sm-profile-name{font-size:14px;font-weight:500;color:#fff;line-height:1.3;overflow:hidden;text-overflow:ellipsis}.sm-profile-role{font-size:11px;color:#fff9;line-height:1.3;overflow:hidden;text-overflow:ellipsis}.sm-sidebar mat-divider{border-color:#ffffff26!important;margin:0 15px}.sm-menu-scroll{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px 0}.sm-menu-scroll::-webkit-scrollbar{width:4px}.sm-menu-scroll::-webkit-scrollbar-track{background:transparent}.sm-menu-scroll::-webkit-scrollbar-thumb{background:#fff3;border-radius:2px}.sm-menu-item{display:flex;align-items:center;padding:10px 15px;margin:2px 15px;border-radius:4px;cursor:pointer;color:#fff;font-size:13px;font-weight:400;letter-spacing:.3px;transition:all .15s ease;text-decoration:none;white-space:nowrap;overflow:hidden}.sm-menu-item:hover{background:#ffffff1f}.sm-menu-item.sm-active{background-color:#fff;color:#3c4858;box-shadow:0 4px 20px #00000024,0 7px 10px -5px #0003;font-weight:500}.sm-menu-item.sm-active .sm-menu-icon{color:#3c4858}.sm-menu-icon{font-size:20px!important;width:24px!important;height:24px!important;display:inline-flex!important;align-items:center;justify-content:center;margin-right:12px;flex-shrink:0;color:#fffc;transition:color .15s ease}.sm-menu-text{flex:1;overflow:hidden;text-overflow:ellipsis;transition:opacity .2s ease}.sm-caret{font-size:18px!important;width:18px!important;height:18px!important;transition:transform .3s cubic-bezier(.4,0,.2,1);flex-shrink:0;color:#fff9}.sm-caret.sm-caret-open{transform:rotate(180deg)}.sm-active .sm-caret{color:#3c4858}.sm-submenu{max-height:0;overflow:hidden;transition:max-height .35s cubic-bezier(.4,0,.2,1)}.sm-submenu.sm-submenu-open{max-height:1000px}.sm-submenu-item{display:flex;align-items:center;padding:8px 15px 8px 30px;margin:1px 15px;border-radius:4px;cursor:pointer;color:#fffc;font-size:12px;font-weight:400;transition:all .15s ease;white-space:nowrap;overflow:hidden}.sm-submenu-item:hover{background:#ffffff1f;color:#fff}.sm-submenu-item.sm-active{background-color:#fff;color:#3c4858;box-shadow:0 4px 20px #00000024,0 7px 10px -5px #0003;font-weight:500}.sm-submenu-item.sm-active .sm-sub-icon{color:#3c4858}.sm-sub-icon{font-size:16px!important;width:20px!important;height:20px!important;display:inline-flex!important;align-items:center;justify-content:center;margin-right:10px;flex-shrink:0;color:#fff9}.sm-initials{width:20px;height:20px;border-radius:50%;background:#ffffff26;display:inline-flex;align-items:center;justify-content:center;font-size:9px;font-weight:600;margin-right:10px;flex-shrink:0;color:#fffc}.sm-active .sm-initials{background:#3c48581f;color:#3c4858}.sm-main{flex:1;min-width:0;margin-left:260px;min-height:100vh;display:flex;flex-direction:column;transition:margin-left .3s cubic-bezier(.4,0,.2,1);background-color:#eef2f7}.sm-topbar{display:flex;align-items:center;padding:8px 16px;min-height:56px;background-color:#eef2f7;background-image:radial-gradient(circle,#d5dbe3 1px,transparent 1px);background-size:16px 16px;border-bottom:1px solid rgba(0,0,0,.08);position:sticky;top:0;z-index:1020;transition:background .3s ease,backdrop-filter .3s ease}.sm-topbar-scrolled{background-color:#eef2f78c;background-image:none;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);box-shadow:0 1px 3px #0000000f}.sm-topbar-spacer{flex:1 1 auto}.sm-topbar-logo{height:32px;width:32px;object-fit:contain;margin-right:8px}.sm-topbar-brand{font-size:18px;font-weight:500;margin-right:8px;white-space:nowrap}.sm-topbar-label{font-size:14px;margin-right:4px;display:inline-flex;align-items:center;align-self:center;height:40px;line-height:1}.sm-topbar .mat-mdc-icon-button{display:inline-flex!important;align-items:center!important;justify-content:center!important}.sm-content{flex:1;padding:12px;min-width:0;background-color:#e5eaf2;background-image:radial-gradient(ellipse at 50% 45%,#fffffff2,#fff6 35%,#fff0 60%),radial-gradient(circle,#bec7d4 1px,transparent 1px);background-size:100% 100%,16px 16px;min-height:calc(100vh - 104px)}.sm-footer{padding:12px 16px;text-align:center;font-size:12px;color:#999;border-top:1px solid #e0e0e0;background:#fff}.sm-footer a{color:inherit;cursor:pointer}.sm-footer a:hover{text-decoration:underline}.sm-backdrop{display:none;position:fixed;inset:0;background:#00000080;z-index:1025}.sm-layout.sm-mini .sm-sidebar{width:80px}.sm-layout.sm-mini .sm-main{margin-left:80px}.sm-layout.sm-mini .sm-brand-name,.sm-layout.sm-mini .sm-profile-info,.sm-layout.sm-mini .sm-menu-text,.sm-layout.sm-mini .sm-caret,.sm-layout.sm-mini .sm-submenu{display:none}.sm-layout.sm-mini .sm-sidebar mat-divider{margin:0 10px}.sm-layout.sm-mini .sm-brand{justify-content:center;padding:18px 0 10px}.sm-layout.sm-mini .sm-brand img{margin-right:0}.sm-layout.sm-mini .sm-profile{justify-content:center;padding:12px 0}.sm-layout.sm-mini .sm-profile-icon{margin-right:0}.sm-layout.sm-mini .sm-menu-item{justify-content:center;padding:12px 0;margin:2px 0}.sm-layout.sm-mini .sm-menu-icon{margin-right:0;font-size:22px!important}.sm-layout.sm-mini-hovered .sm-sidebar{width:260px;box-shadow:4px 0 20px #0000004d}.sm-layout.sm-mini-hovered .sm-main{margin-left:80px}.sm-layout.sm-mini-hovered .sm-brand-name,.sm-layout.sm-mini-hovered .sm-profile-info,.sm-layout.sm-mini-hovered .sm-menu-text,.sm-layout.sm-mini-hovered .sm-caret{display:initial}.sm-layout.sm-mini-hovered .sm-submenu{display:block}.sm-layout.sm-mini-hovered .sm-sidebar mat-divider{margin:0 15px}.sm-layout.sm-mini-hovered .sm-brand{justify-content:flex-start;padding:18px 15px 10px}.sm-layout.sm-mini-hovered .sm-brand img{margin-right:12px}.sm-layout.sm-mini-hovered .sm-profile{justify-content:flex-start;padding:12px 15px}.sm-layout.sm-mini-hovered .sm-profile-icon{margin-right:12px}.sm-layout.sm-mini-hovered .sm-menu-item{justify-content:flex-start;padding:10px 15px;margin:2px 15px}.sm-layout.sm-mini-hovered .sm-menu-icon{margin-right:12px;font-size:20px!important}@media (max-width: 600px){.sm-sidebar{transform:translate(-100%);transition:transform .3s cubic-bezier(.4,0,.2,1);width:260px!important}.sm-layout.sm-mobile-open .sm-sidebar{transform:translate(0)}.sm-layout.sm-mobile-open .sm-backdrop{display:block}.sm-main{margin-left:0!important}.sm-layout.sm-mini .sm-sidebar{width:260px!important}.sm-layout.sm-mini .sm-brand-name,.sm-layout.sm-mini .sm-profile-info,.sm-layout.sm-mini .sm-menu-text,.sm-layout.sm-mini .sm-caret{display:initial}.sm-layout.sm-mini .sm-submenu{display:block}.sm-layout.sm-mini .sm-sidebar mat-divider{margin:0 15px}.sm-layout.sm-mini .sm-menu-item{justify-content:flex-start;padding:10px 15px;margin:2px 15px}.sm-layout.sm-mini .sm-menu-icon{margin-right:12px;font-size:20px!important}.sm-layout.sm-mini .sm-brand{justify-content:flex-start;padding:18px 15px 10px}.sm-layout.sm-mini .sm-brand img{margin-right:12px}.sm-layout.sm-mini .sm-profile{justify-content:flex-start;padding:12px 15px}.sm-layout.sm-mini .sm-profile-icon{margin-right:12px}}\n"] }]
9546
9550
  }], ctorParameters: () => [{ type: i1$2.Router }, { type: AuthService }, { type: StorageService }, { type: NotificationsService }, { type: i1$3.BreakpointObserver }, { type: DataServiceLib }, { type: i1.MatDialog }, { type: SubscriptionService }], propDecorators: { onWindowScroll: [{
9547
9551
  type: HostListener,
9548
9552
  args: ['window:scroll']
@@ -15713,11 +15717,11 @@ class TabsComponent {
15713
15717
  return this.reload || this.tableReloads[index];
15714
15718
  }
15715
15719
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TabsComponent, deps: [{ token: TabService }], target: i0.ɵɵFactoryTarget.Component }); }
15716
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: TabsComponent, isStandalone: false, selector: "spa-tabs", inputs: { tableConfigs: "tableConfigs", reload: "reload", parentDetails: "parentDetails" }, outputs: { formRefresh: "formRefresh" }, usesOnChanges: true, ngImport: i0, template: "<mat-tab-group (selectedTabChange)=\"onTabChange($event)\" [selectedIndex]=\"selectedTabIndex\">\r\n\r\n <!-- Changed: Use cached visibleTabs property to prevent infinite change detection loop -->\r\n <ng-container *ngFor=\"let tab of visibleTabs; let i = index\">\r\n <mat-tab *ngIf=\"isTabVisible(tab.config)\">\r\n\r\n <!-- Tab label with optional count badge -->\r\n <ng-template matTabLabel>\r\n <span\r\n [matBadge]=\"shouldShowBadge(tab.originalIndex) ? getTabCount(tab.originalIndex) : null\"\r\n [matBadgeHidden]=\"!shouldShowBadge(tab.originalIndex)\"\r\n matBadgeOverlap=\"false\">\r\n {{getTabTitle(tab.config)}}\r\n </span>\r\n </ng-template>\r\n\r\n <!-- Tab content with lazy-loaded table -->\r\n <div *ngIf=\"shouldLoadTabData(i)\" class=\"tab-content\">\r\n <spa-table\r\n [config]=\"tab.config\"\r\n [reload]=\"getReloadSubject(tab.originalIndex)\"\r\n [inTab]=\"true\"\r\n [activeTab]=\"selectedTabIndex === i\"\r\n (actionSuccess)=\"onTableActionSuccess(tab.originalIndex, $event)\">\r\n </spa-table>\r\n </div>\r\n\r\n <!-- Placeholder for non-loaded tabs -->\r\n <div *ngIf=\"!shouldLoadTabData(i)\" class=\"tab-placeholder\">\r\n <!-- Empty placeholder - content will load when tab is activated -->\r\n </div>\r\n\r\n </mat-tab>\r\n </ng-container>\r\n\r\n</mat-tab-group>", styles: [".tab-content{padding-top:16px}.tab-placeholder{min-height:100px;display:flex;align-items:center;justify-content:center}.badge{background-color:#2196f3;color:#fff;border-radius:12px;padding:2px 8px;margin-left:8px;font-size:12px}\n"], dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3$2.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "directive", type: i4$5.MatTabLabel, selector: "[mat-tab-label], [matTabLabel]" }, { kind: "component", type: i4$5.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i4$5.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "component", type: TableComponent, selector: "spa-table", inputs: ["data", "tileData", "config", "reload", "activeTab", "inTab"], outputs: ["dataLoad", "actionSuccess", "refreshClick", "searchClick", "createClick", "actionClick", "inputChange", "actionResponse"] }] }); }
15720
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: TabsComponent, isStandalone: false, selector: "spa-tabs", inputs: { tableConfigs: "tableConfigs", reload: "reload", parentDetails: "parentDetails" }, outputs: { formRefresh: "formRefresh" }, usesOnChanges: true, ngImport: i0, template: "<mat-tab-group (selectedTabChange)=\"onTabChange($event)\" [selectedIndex]=\"selectedTabIndex\">\r\n\r\n <!-- Changed: Use cached visibleTabs property to prevent infinite change detection loop -->\r\n <ng-container *ngFor=\"let tab of visibleTabs; let i = index\">\r\n <mat-tab *ngIf=\"isTabVisible(tab.config)\">\r\n\r\n <!-- Tab label with optional count badge -->\r\n <ng-template matTabLabel>\r\n <span\r\n [matBadge]=\"shouldShowBadge(tab.originalIndex) ? getTabCount(tab.originalIndex) : null\"\r\n [matBadgeHidden]=\"!shouldShowBadge(tab.originalIndex)\"\r\n matBadgeOverlap=\"false\">\r\n {{getTabTitle(tab.config)}}\r\n </span>\r\n </ng-template>\r\n\r\n <!-- Tab content with lazy-loaded table -->\r\n <div *ngIf=\"shouldLoadTabData(i)\" class=\"tab-content\">\r\n <spa-table\r\n [config]=\"tab.config\"\r\n [reload]=\"getReloadSubject(tab.originalIndex)\"\r\n [inTab]=\"true\"\r\n [activeTab]=\"selectedTabIndex === i\"\r\n (actionSuccess)=\"onTableActionSuccess(tab.originalIndex, $event)\">\r\n </spa-table>\r\n </div>\r\n\r\n <!-- Placeholder for non-loaded tabs -->\r\n <div *ngIf=\"!shouldLoadTabData(i)\" class=\"tab-placeholder\">\r\n <!-- Empty placeholder - content will load when tab is activated -->\r\n </div>\r\n\r\n </mat-tab>\r\n </ng-container>\r\n\r\n</mat-tab-group>", styles: [".tab-content{padding-top:16px;overflow-x:auto}.tab-placeholder{min-height:100px;display:flex;align-items:center;justify-content:center}.badge{background-color:#2196f3;color:#fff;border-radius:12px;padding:2px 8px;margin-left:8px;font-size:12px}\n"], dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3$2.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "directive", type: i4$5.MatTabLabel, selector: "[mat-tab-label], [matTabLabel]" }, { kind: "component", type: i4$5.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i4$5.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "component", type: TableComponent, selector: "spa-table", inputs: ["data", "tileData", "config", "reload", "activeTab", "inTab"], outputs: ["dataLoad", "actionSuccess", "refreshClick", "searchClick", "createClick", "actionClick", "inputChange", "actionResponse"] }] }); }
15717
15721
  }
15718
15722
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TabsComponent, decorators: [{
15719
15723
  type: Component,
15720
- args: [{ selector: 'spa-tabs', standalone: false, template: "<mat-tab-group (selectedTabChange)=\"onTabChange($event)\" [selectedIndex]=\"selectedTabIndex\">\r\n\r\n <!-- Changed: Use cached visibleTabs property to prevent infinite change detection loop -->\r\n <ng-container *ngFor=\"let tab of visibleTabs; let i = index\">\r\n <mat-tab *ngIf=\"isTabVisible(tab.config)\">\r\n\r\n <!-- Tab label with optional count badge -->\r\n <ng-template matTabLabel>\r\n <span\r\n [matBadge]=\"shouldShowBadge(tab.originalIndex) ? getTabCount(tab.originalIndex) : null\"\r\n [matBadgeHidden]=\"!shouldShowBadge(tab.originalIndex)\"\r\n matBadgeOverlap=\"false\">\r\n {{getTabTitle(tab.config)}}\r\n </span>\r\n </ng-template>\r\n\r\n <!-- Tab content with lazy-loaded table -->\r\n <div *ngIf=\"shouldLoadTabData(i)\" class=\"tab-content\">\r\n <spa-table\r\n [config]=\"tab.config\"\r\n [reload]=\"getReloadSubject(tab.originalIndex)\"\r\n [inTab]=\"true\"\r\n [activeTab]=\"selectedTabIndex === i\"\r\n (actionSuccess)=\"onTableActionSuccess(tab.originalIndex, $event)\">\r\n </spa-table>\r\n </div>\r\n\r\n <!-- Placeholder for non-loaded tabs -->\r\n <div *ngIf=\"!shouldLoadTabData(i)\" class=\"tab-placeholder\">\r\n <!-- Empty placeholder - content will load when tab is activated -->\r\n </div>\r\n\r\n </mat-tab>\r\n </ng-container>\r\n\r\n</mat-tab-group>", styles: [".tab-content{padding-top:16px}.tab-placeholder{min-height:100px;display:flex;align-items:center;justify-content:center}.badge{background-color:#2196f3;color:#fff;border-radius:12px;padding:2px 8px;margin-left:8px;font-size:12px}\n"] }]
15724
+ args: [{ selector: 'spa-tabs', standalone: false, template: "<mat-tab-group (selectedTabChange)=\"onTabChange($event)\" [selectedIndex]=\"selectedTabIndex\">\r\n\r\n <!-- Changed: Use cached visibleTabs property to prevent infinite change detection loop -->\r\n <ng-container *ngFor=\"let tab of visibleTabs; let i = index\">\r\n <mat-tab *ngIf=\"isTabVisible(tab.config)\">\r\n\r\n <!-- Tab label with optional count badge -->\r\n <ng-template matTabLabel>\r\n <span\r\n [matBadge]=\"shouldShowBadge(tab.originalIndex) ? getTabCount(tab.originalIndex) : null\"\r\n [matBadgeHidden]=\"!shouldShowBadge(tab.originalIndex)\"\r\n matBadgeOverlap=\"false\">\r\n {{getTabTitle(tab.config)}}\r\n </span>\r\n </ng-template>\r\n\r\n <!-- Tab content with lazy-loaded table -->\r\n <div *ngIf=\"shouldLoadTabData(i)\" class=\"tab-content\">\r\n <spa-table\r\n [config]=\"tab.config\"\r\n [reload]=\"getReloadSubject(tab.originalIndex)\"\r\n [inTab]=\"true\"\r\n [activeTab]=\"selectedTabIndex === i\"\r\n (actionSuccess)=\"onTableActionSuccess(tab.originalIndex, $event)\">\r\n </spa-table>\r\n </div>\r\n\r\n <!-- Placeholder for non-loaded tabs -->\r\n <div *ngIf=\"!shouldLoadTabData(i)\" class=\"tab-placeholder\">\r\n <!-- Empty placeholder - content will load when tab is activated -->\r\n </div>\r\n\r\n </mat-tab>\r\n </ng-container>\r\n\r\n</mat-tab-group>", styles: [".tab-content{padding-top:16px;overflow-x:auto}.tab-placeholder{min-height:100px;display:flex;align-items:center;justify-content:center}.badge{background-color:#2196f3;color:#fff;border-radius:12px;padding:2px 8px;margin-left:8px;font-size:12px}\n"] }]
15721
15725
  }], ctorParameters: () => [{ type: TabService }], propDecorators: { tableConfigs: [{
15722
15726
  type: Input
15723
15727
  }], reload: [{