@skysoftware-co/bayan-core-widgets-ui 0.0.4 → 0.0.8

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.
Files changed (73) hide show
  1. package/.editorconfig +17 -0
  2. package/.github/copilot/WidgetDevelopmentGuide.md +632 -0
  3. package/.github/copilot/WidgetProjectStructure.md +81 -0
  4. package/.github/copilot/git.md +176 -0
  5. package/.github/copilot/guideline.md +466 -0
  6. package/.github/copilot-instructions.md +697 -0
  7. package/.github/prompts/As world class developer, create unit tests for.prompt.md +7 -0
  8. package/README.md +1 -337
  9. package/Web.config +7 -0
  10. package/angular.json +43 -0
  11. package/package.json +54 -31
  12. package/projects/bayan-core-ui/README.md +522 -0
  13. package/projects/bayan-core-ui/ng-package.json +7 -0
  14. package/projects/bayan-core-ui/package.json +36 -0
  15. package/projects/bayan-core-ui/src/assets/i18n/ar.json +725 -0
  16. package/projects/bayan-core-ui/src/assets/i18n/en.json +683 -0
  17. package/projects/bayan-core-ui/src/assets/i18n/fr.json +687 -0
  18. package/projects/bayan-core-ui/src/lib/shared/common-methods/navigation.utils.ts +21 -0
  19. package/projects/bayan-core-ui/src/lib/shared/menu.dtos.ts +107 -0
  20. package/projects/bayan-core-ui/src/lib/shared/menu.service.ts +157 -0
  21. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/about-dialog-widget/about-dialog-widget.component.html +37 -0
  22. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/about-dialog-widget/about-dialog-widget.component.ts +68 -0
  23. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/change-password-widget/change-password-widget.component.html +56 -0
  24. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/change-password-widget/change-password-widget.component.ts +158 -0
  25. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/global-search-widget/global-search-widget.component.html +39 -0
  26. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/global-search-widget/global-search-widget.component.ts +152 -0
  27. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/item-widget/item-widget.component.html +39 -0
  28. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/item-widget/item-widget.component.ts +80 -0
  29. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/notifications-widget/notifications-widget.component.html +10 -0
  30. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/notifications-widget/notifications-widget.component.ts +89 -0
  31. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/settings-widget/settings-widget.component.html +111 -0
  32. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/settings-widget/settings-widget.component.ts +235 -0
  33. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/user-panel-widget/user-panel-widget.component.html +54 -0
  34. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/user-panel-widget/user-panel-widget.component.ts +140 -0
  35. package/projects/bayan-core-ui/src/lib/top-menu-widget/top-menu-widget.component.html +107 -0
  36. package/projects/bayan-core-ui/src/lib/top-menu-widget/top-menu-widget.component.ts +164 -0
  37. package/projects/bayan-core-ui/src/lib/top-menu-widget/top-menu-widget.models.ts +29 -0
  38. package/projects/bayan-core-ui/src/lib/top-menu-widget/top-menu-widget.styles.css +1378 -0
  39. package/projects/bayan-core-ui/src/public-api.ts +14 -0
  40. package/projects/bayan-core-ui/tsconfig.lib.json +16 -0
  41. package/projects/bayan-core-ui/tsconfig.lib.prod.json +9 -0
  42. package/projects/bayan-core-ui/tsconfig.spec.json +13 -0
  43. package/tsconfig.json +40 -0
  44. package/fesm2022/skysoftware-co-bayan-core-widgets-ui.mjs +0 -1092
  45. package/fesm2022/skysoftware-co-bayan-core-widgets-ui.mjs.map +0 -1
  46. package/index.d.ts +0 -6
  47. package/lib/shared/common-methods/navigation.utils.d.ts +0 -4
  48. package/lib/shared/common-methods/navigation.utils.d.ts.map +0 -1
  49. package/lib/shared/menu.dtos.d.ts +0 -91
  50. package/lib/shared/menu.dtos.d.ts.map +0 -1
  51. package/lib/shared/menu.service.d.ts +0 -24
  52. package/lib/shared/menu.service.d.ts.map +0 -1
  53. package/lib/top-menu-widget/components/about-dialog-widget/about-dialog-widget.component.d.ts +0 -18
  54. package/lib/top-menu-widget/components/about-dialog-widget/about-dialog-widget.component.d.ts.map +0 -1
  55. package/lib/top-menu-widget/components/change-password-widget/change-password-widget.component.d.ts +0 -30
  56. package/lib/top-menu-widget/components/change-password-widget/change-password-widget.component.d.ts.map +0 -1
  57. package/lib/top-menu-widget/components/global-search-widget/global-search-widget.component.d.ts +0 -59
  58. package/lib/top-menu-widget/components/global-search-widget/global-search-widget.component.d.ts.map +0 -1
  59. package/lib/top-menu-widget/components/item-widget/item-widget.component.d.ts +0 -29
  60. package/lib/top-menu-widget/components/item-widget/item-widget.component.d.ts.map +0 -1
  61. package/lib/top-menu-widget/components/notifications-widget/notifications-widget.component.d.ts +0 -23
  62. package/lib/top-menu-widget/components/notifications-widget/notifications-widget.component.d.ts.map +0 -1
  63. package/lib/top-menu-widget/components/settings-widget/settings-widget.component.d.ts +0 -37
  64. package/lib/top-menu-widget/components/settings-widget/settings-widget.component.d.ts.map +0 -1
  65. package/lib/top-menu-widget/components/user-panel-widget/user-panel-widget.component.d.ts +0 -43
  66. package/lib/top-menu-widget/components/user-panel-widget/user-panel-widget.component.d.ts.map +0 -1
  67. package/lib/top-menu-widget/top-menu-widget.component.d.ts +0 -76
  68. package/lib/top-menu-widget/top-menu-widget.component.d.ts.map +0 -1
  69. package/lib/top-menu-widget/top-menu-widget.models.d.ts +0 -36
  70. package/lib/top-menu-widget/top-menu-widget.models.d.ts.map +0 -1
  71. package/public-api.d.ts +0 -4
  72. package/public-api.d.ts.map +0 -1
  73. package/skysoftware-co-bayan-core-widgets-ui.d.ts.map +0 -1
@@ -0,0 +1,152 @@
1
+ import { CommonModule, DOCUMENT } from '@angular/common';
2
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild, inject } from '@angular/core';
3
+ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
4
+ import {
5
+ faDollar,
6
+ faGraduationCap,
7
+ faGrid,
8
+ faMedal,
9
+ faRightLeft,
10
+ faTools,
11
+ faUsers,
12
+ } from '@fortawesome/pro-solid-svg-icons';
13
+ import { faClock } from '@fortawesome/pro-light-svg-icons';
14
+ import { Router } from '@angular/router';
15
+ import { DxAutocompleteComponent, DxAutocompleteModule } from 'devextreme-angular';
16
+ import { TranslatePipe } from '@skysoftware-co/sky-components-ui';
17
+ import { GlobalSearchMenu } from '../../../shared/menu.dtos';
18
+ import { BayanCoreTopMenuService } from '../../../shared/menu.service';
19
+ import { isExternalNavigation, resolveUrl } from '../../../shared/common-methods/navigation.utils';
20
+
21
+ @Component({
22
+ selector: 'bayan-core-global-search-widget',
23
+ standalone: true,
24
+ imports: [CommonModule, DxAutocompleteModule, FontAwesomeModule, TranslatePipe],
25
+ templateUrl: './global-search-widget.component.html',
26
+ styles: [':host { display: flex; align-items: center; height: 56px; }'],
27
+ styleUrls: ['../../top-menu-widget.styles.css'],
28
+ changeDetection: ChangeDetectionStrategy.OnPush,
29
+ })
30
+ export class BayanCoreGlobalSearchWidgetComponent implements OnInit, OnChanges {
31
+ private readonly menuService = inject(BayanCoreTopMenuService);
32
+ private readonly document = inject(DOCUMENT);
33
+ private readonly router = inject(Router);
34
+
35
+ @ViewChild('searchAutoComplete') searchAutoComplete?: DxAutocompleteComponent;
36
+
37
+ @Input() baseUrl = '';
38
+ @Input() ActivePropertyChanged = false;
39
+ @Input() ActivePropertyId: number = 0;
40
+ @Input() placeholder = 'Type to search';
41
+
42
+ @Input() searchMode: 'contains' | 'startswith' = 'contains';
43
+ @Input() stylingMode: 'filled' | 'outlined' | 'underlined' = 'filled';
44
+ // Use canonical Payroll menu-styles.css classes
45
+ @Input() searchWrapperClass = '';
46
+ @Input() searchItemClass = '';
47
+ @Input() searchItemTitleClass = '';
48
+ @Input() searchItemSubtitleClass = '';
49
+ @Input() iconClass = '';
50
+
51
+ @Output() search = new EventEmitter<string>();
52
+ @Output() itemNavigate = new EventEmitter<GlobalSearchMenu>();
53
+
54
+ dataSource: GlobalSearchMenu[] = [];
55
+ readonly toolsIcon = faTools;
56
+ readonly gridIcon = faGrid;
57
+ readonly creditIcon = faDollar;
58
+ readonly usersIcon = faUsers;
59
+ readonly clockIcon = faClock;
60
+ readonly swapIcon = faRightLeft;
61
+ readonly medalIcon = faMedal;
62
+ readonly graduateIcon = faGraduationCap;
63
+
64
+ ngOnInit(): void {
65
+ this.loadMenus();
66
+ }
67
+
68
+ private loadMenus(): void {
69
+ if (this.baseUrl && this.ActivePropertyId > 0) {
70
+ this.menuService.getGlobalSearchMenus(this.baseUrl, this.ActivePropertyId).subscribe({
71
+ next: (menus) => this.dataSource = menus ?? [],
72
+ error: () => this.dataSource = []
73
+ });
74
+ }
75
+ }
76
+
77
+ ngOnChanges(changes: SimpleChanges): void {
78
+ if (
79
+ changes['ActivePropertyChanged']
80
+ && !changes['ActivePropertyChanged'].firstChange
81
+ && changes['ActivePropertyChanged'].previousValue !== changes['ActivePropertyChanged'].currentValue
82
+ ) {
83
+ this.reset();
84
+ this.loadMenus();
85
+ }
86
+ }
87
+
88
+ onInput(event: { event?: { target?: { value?: string } }; component?: { option: (name: string, value: string) => void } } | any): void {
89
+ const searchTerm = event.event?.target?.value;
90
+ if (typeof searchTerm === 'string' && searchTerm.startsWith(' ')) {
91
+ event.component?.option('value', searchTerm.trim());
92
+ }
93
+ }
94
+
95
+ onEnterKey(event: { event?: { target?: { value?: string } } } | any): void {
96
+ const searchTerm = (event.event?.target?.value ?? '').toString().trim();
97
+ if (!searchTerm) {
98
+ return;
99
+ }
100
+
101
+ const match = this.dataSource.find(
102
+ (item) => item.MenuSubTitle.toLowerCase().trim() === searchTerm.toLowerCase().trim(),
103
+ );
104
+
105
+ if (match) {
106
+ window.location.href = match.MenuUrl;
107
+ this.itemNavigate.emit(match);
108
+ return;
109
+ }
110
+
111
+ this.search.emit(searchTerm);
112
+ }
113
+
114
+ onItemSelected(event: Event, item: GlobalSearchMenu): void {
115
+ event.preventDefault();
116
+ event.stopPropagation();
117
+ if (item.MenuUrl) {
118
+ window.location.href = item.MenuUrl;
119
+ }
120
+ }
121
+
122
+ reset(): void {
123
+ this.searchAutoComplete?.instance?.option('value', '');
124
+ }
125
+
126
+ getText(text: string, isTranslatable = false): string {
127
+ return isTranslatable ? text : text;
128
+ }
129
+
130
+ getIconForClass(iconClass: string) {
131
+ switch (iconClass) {
132
+ case 'icon icon-tools':
133
+ return this.toolsIcon;
134
+ case 'icon icon-grid':
135
+ return this.gridIcon;
136
+ case 'icon icon-credit':
137
+ return this.creditIcon;
138
+ case 'icon icon-users':
139
+ return this.usersIcon;
140
+ case 'icon icon-clock':
141
+ return this.clockIcon;
142
+ case 'icon icon-swap':
143
+ return this.swapIcon;
144
+ case 'icon icon-medal':
145
+ return this.medalIcon;
146
+ case 'icon icon-graduation-cap':
147
+ return this.graduateIcon;
148
+ default:
149
+ return this.toolsIcon;
150
+ }
151
+ }
152
+ }
@@ -0,0 +1,39 @@
1
+ @if (!hasChildren()) {
2
+ <li [class]="navItemClass">
3
+ <a
4
+ [class]="navLinkClass"
5
+ href="#"
6
+ (click)="onItemActivated($event)">
7
+ {{ item.MenuName | translate }}
8
+ </a>
9
+ </li>
10
+ }
11
+
12
+ @if (hasChildren()) {
13
+ <li [class]="dropdownClass" [class.open]="open">
14
+ <a href="#" [class]="dropdownToggleClass" (click)="onItemActivated($event)">
15
+ {{ item.MenuName | translate }} <span [class]="caretClass"></span>
16
+ </a>
17
+
18
+ @if (open) {
19
+ <ul [class]="dropdownMenuClass">
20
+ @for (child of item.Children; track child.MenuName) {
21
+ <bayan-core-item-widget
22
+ [baseUrl]="baseUrl"
23
+ [ActivePropertyChanged]="ActivePropertyChanged"
24
+ [item]="child"
25
+ (itemClick)="onChildItemClick($event)"
26
+ [navItemClass]="navItemClass"
27
+ [navLinkClass]="navLinkClass"
28
+ [dropdownClass]="dropdownClass"
29
+ [dropdownOpenClass]="dropdownOpenClass"
30
+ [dropdownToggleClass]="dropdownToggleClass"
31
+ [caretClass]="caretClass"
32
+ [dropdownMenuClass]="dropdownMenuClass"
33
+ >
34
+ </bayan-core-item-widget>
35
+ }
36
+ </ul>
37
+ }
38
+ </li>
39
+ }
@@ -0,0 +1,80 @@
1
+ import { CommonModule, DOCUMENT } from '@angular/common';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ ElementRef,
6
+ EventEmitter,
7
+ Input,
8
+ OnChanges,
9
+ Output,
10
+ SimpleChanges,
11
+ inject,
12
+ } from '@angular/core';
13
+ import { Router } from '@angular/router';
14
+ import { TranslatePipe } from '@skysoftware-co/sky-components-ui';
15
+ import { TopMenuShortcut } from '../../../shared/menu.dtos';
16
+
17
+ @Component({
18
+ selector: 'bayan-core-item-widget',
19
+ standalone: true,
20
+ imports: [CommonModule, TranslatePipe],
21
+ templateUrl: './item-widget.component.html',
22
+ styles: [':host { display: contents; }'],
23
+ styleUrls: ['../../top-menu-widget.styles.css'],
24
+ changeDetection: ChangeDetectionStrategy.OnPush,
25
+ })
26
+ export class BayanCoreItemWidgetComponent implements OnChanges {
27
+ private readonly document = inject(DOCUMENT);
28
+ private readonly router = inject(Router);
29
+
30
+ @Input() baseUrl = '';
31
+ @Input() ActivePropertyChanged = false;
32
+ @Input({ required: true }) item!: TopMenuShortcut;
33
+
34
+ @Input() navItemClass = 'nav-item';
35
+ @Input() navLinkClass = 'nav-link';
36
+ @Input() dropdownClass = 'nav-item dropdown';
37
+ @Input() dropdownOpenClass = 'open';
38
+ @Input() dropdownToggleClass = 'nav-link dropdown-toggle';
39
+ @Input() caretClass = 'caret';
40
+ @Input() dropdownMenuClass = 'dropdown-menu menu-dropdown-panel';
41
+
42
+ @Output() itemClick = new EventEmitter<TopMenuShortcut>();
43
+
44
+ @Input() open = false;
45
+ @Output() toggleOpen = new EventEmitter<void>();
46
+
47
+ constructor(private readonly elementRef: ElementRef<HTMLElement>) {}
48
+
49
+ ngOnChanges(changes: SimpleChanges): void {
50
+ if (
51
+ changes['ActivePropertyChanged']
52
+ && !changes['ActivePropertyChanged'].firstChange
53
+ && changes['ActivePropertyChanged'].previousValue !== changes['ActivePropertyChanged'].currentValue
54
+ ) {
55
+ }
56
+ }
57
+
58
+ hasChildren(): boolean {
59
+ return (this.item.Children ?? []).length > 0;
60
+ }
61
+
62
+ onItemActivated(event: Event): void {
63
+ event.preventDefault();
64
+ if (this.hasChildren()) {
65
+ event.stopPropagation();
66
+ this.toggleOpen.emit();
67
+ return;
68
+ }
69
+ this.itemClick.emit(this.item);
70
+ if (typeof this.item.MenuUrl === 'string' && this.item.MenuName == 'Reports') {
71
+ window.open(this.item.MenuUrl, '_blank');
72
+ } else if (this.item.MenuUrl) {
73
+ window.location.href = this.item.MenuUrl;
74
+ }
75
+ }
76
+
77
+ onChildItemClick(item: TopMenuShortcut): void {
78
+ this.itemClick.emit(item);
79
+ }
80
+ }
@@ -0,0 +1,10 @@
1
+ <div [class]="wrapperClass">
2
+ <a [class]="linkClass"
3
+ [title]="title | translate"
4
+ (click)="onNotificationClick($event)">
5
+ <fa-icon [class]="iconClass" [icon]="bellIcon"></fa-icon>
6
+ @if ((notificationsSummary().TotalNotificationsCount || 0) > 0) {
7
+ <span [class]="badgeClass">{{ notificationsSummary().TotalNotificationsCount }}</span>
8
+ }
9
+ </a>
10
+ </div>
@@ -0,0 +1,89 @@
1
+ import { CommonModule, DOCUMENT } from '@angular/common';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ Input,
6
+ OnChanges,
7
+ OnInit,
8
+ SimpleChanges,
9
+ inject,
10
+ signal,
11
+ } from '@angular/core';
12
+ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
13
+ import { faBell } from '@fortawesome/pro-solid-svg-icons';
14
+ import { TranslatePipe } from '@skysoftware-co/sky-components-ui';
15
+ import { isExternalNavigation, resolveUrl } from '../../../shared/common-methods/navigation.utils';
16
+ import { NotificationsSummary } from '../../../shared/menu.dtos';
17
+ import { BayanCoreTopMenuService } from '../../../shared/menu.service';
18
+
19
+ @Component({
20
+ selector: 'bayan-core-notifications-widget',
21
+ standalone: true,
22
+ imports: [CommonModule, FontAwesomeModule, TranslatePipe],
23
+ templateUrl: './notifications-widget.component.html',
24
+ styles: [':host { display: flex; align-items: center; height: 56px; }'],
25
+ styleUrls: ['../../top-menu-widget.styles.css'],
26
+ changeDetection: ChangeDetectionStrategy.OnPush,
27
+ })
28
+ export class BayanCoreNotificationsWidgetComponent implements OnInit, OnChanges {
29
+ private readonly document = inject(DOCUMENT);
30
+ private readonly topMenuService = inject(BayanCoreTopMenuService);
31
+
32
+ @Input() baseUrl = '';
33
+ @Input() title = 'Notifications';
34
+ @Input() wrapperClass = 'menu-dropdown-host';
35
+ @Input() linkClass = 'menu-icon-btn notifications-icon-btn';
36
+ @Input() iconClass = '';
37
+ @Input() badgeClass = 'notifications-badge';
38
+
39
+ readonly bellIcon = faBell;
40
+ readonly notificationsSummary = signal<NotificationsSummary>({
41
+ NotificationsUrl: '',
42
+ TotalNotificationsCount: 0,
43
+ });
44
+
45
+ ngOnInit(): void {
46
+ this.loadNotificationsSummary();
47
+ }
48
+
49
+ ngOnChanges(changes: SimpleChanges): void {
50
+ if (changes['baseUrl'] && !changes['baseUrl'].firstChange) {
51
+ this.loadNotificationsSummary();
52
+ }
53
+ }
54
+
55
+ onNotificationClick(event?: Event): void {
56
+ event?.preventDefault();
57
+ const rawNotificationUrl = this.notificationsSummary().NotificationsUrl;
58
+
59
+ if (rawNotificationUrl) {
60
+ this.document.location.href = `${window.location.origin}${rawNotificationUrl}`;
61
+ }
62
+ }
63
+
64
+ private loadNotificationsSummary(): void {
65
+ if (!this.baseUrl) {
66
+ this.resetNotificationsData();
67
+ return;
68
+ }
69
+
70
+ this.topMenuService.getNotificationsSummary(this.baseUrl).subscribe({
71
+ next: (summary) => {
72
+ this.notificationsSummary.set({
73
+ NotificationsUrl: summary.NotificationsUrl,
74
+ TotalNotificationsCount: summary.TotalNotificationsCount,
75
+ });
76
+ },
77
+ error: () => {
78
+ this.resetNotificationsData();
79
+ },
80
+ });
81
+ }
82
+
83
+ private resetNotificationsData(): void {
84
+ this.notificationsSummary.set({
85
+ NotificationsUrl: '',
86
+ TotalNotificationsCount: 0,
87
+ });
88
+ }
89
+ }
@@ -0,0 +1,111 @@
1
+ <div [class]="dropdownHostClass" [class.open]="dropdownOpen()">
2
+ <a href="#" [class]="toggleBtnClass" (click)="toggleDropdown($event)" [title]="'Settings' | translate">
3
+ <fa-icon [icon]="cogIcon" class="fs-6"></fa-icon>
4
+ </a>
5
+
6
+ @if (dropdownOpen()) {
7
+ <ul [class]="menuPanelClass">
8
+ @if (preferences?.UseAlternateNames) {
9
+ <li>
10
+ <a [class]="menuRowClass" (click)="onAlternateNamesClick($event)">
11
+ @if (preferences?.DisplayAlternateNames) {
12
+ <fa-icon [class]="indicatorActiveClass" [icon]="checkIcon"></fa-icon>
13
+ } @else {
14
+ <fa-icon [class]="indicatorInvisibleClass" [icon]="checkIcon"></fa-icon>
15
+ }
16
+ {{ 'DisplayAlternateNames' | translate }}
17
+ </a>
18
+ </li>
19
+ <li><hr [class]="dividerClass"></li>
20
+ }
21
+
22
+ <li>
23
+ <span [class]="sectionLabelClass + ' menu-section-label'">{{ 'EmployeeNamesMode' | translate }}</span>
24
+ </li>
25
+ <li>
26
+ <a [class]="menuRowClass + (preferences?.EmployeeNamesMode === EmployeeNamesModeOption.FullNames ? ' menu-item-active' : '')"
27
+ (click)="onNameModeClick(EmployeeNamesModeOption.FullNames, $event); $event.stopPropagation()">
28
+ <fa-icon [class]="preferences?.EmployeeNamesMode === EmployeeNamesModeOption.FullNames ? indicatorActiveClass : indicatorInvisibleClass" [icon]="checkIcon"></fa-icon>
29
+ {{ 'FullNames' | translate }}
30
+ </a>
31
+ </li>
32
+ <li>
33
+ <a [class]="menuRowClass + (preferences?.EmployeeNamesMode === EmployeeNamesModeOption.ShortNames ? ' menu-item-active' : '')"
34
+ (click)="onNameModeClick(EmployeeNamesModeOption.ShortNames, $event); $event.stopPropagation()">
35
+ <fa-icon [class]="preferences?.EmployeeNamesMode === EmployeeNamesModeOption.ShortNames ? indicatorActiveClass : indicatorInvisibleClass" [icon]="checkIcon"></fa-icon>
36
+ {{ 'ShortNames' | translate }}
37
+ </a>
38
+ </li>
39
+ <li>
40
+ <a [class]="menuRowClass + (preferences?.EmployeeNamesMode === EmployeeNamesModeOption.StandardNames ? ' menu-item-active' : '')"
41
+ (click)="onNameModeClick(EmployeeNamesModeOption.StandardNames, $event); $event.stopPropagation()">
42
+ <fa-icon [class]="preferences?.EmployeeNamesMode === EmployeeNamesModeOption.StandardNames ? indicatorActiveClass : indicatorInvisibleClass" [icon]="checkIcon"></fa-icon>
43
+ {{ 'StandardNames' | translate }}
44
+ </a>
45
+ </li>
46
+ <li><hr [class]="dividerClass"></li>
47
+
48
+ @if (hrBlockState && hrBlockState.UserCanBlockModule && systemModule == SystemModule.Payroll) {
49
+ <li>
50
+ @if (hrBlockState.IsBlocked) {
51
+ <a [class]="menuRowClass" (click)="releaseModule(BlockableModule.HumanResources, $event)">
52
+ {{ 'ReleaseHR' | translate }}
53
+ </a>
54
+ } @else {
55
+ <a [class]="menuRowClass" (click)="blockModule(BlockableModule.HumanResources, $event)">
56
+ {{ 'BlockHR' | translate }}
57
+ </a>
58
+ }
59
+ </li>
60
+ <li><hr [class]="dividerClass"></li>
61
+ }
62
+
63
+ @if (tkBlockState && tkBlockState.UserCanBlockModule && systemModule == SystemModule.HumanResources) {
64
+ <li>
65
+ @if (tkBlockState.IsBlocked) {
66
+ <a [class]="menuRowClass" (click)="releaseModule(BlockableModule.Timekeeping, $event)">
67
+ {{ 'ReleaseTK' | translate }}
68
+ </a>
69
+ } @else {
70
+ <a [class]="menuRowClass" (click)="blockModule(BlockableModule.Timekeeping, $event)">
71
+ {{ 'BlockTK' | translate }}
72
+ </a>
73
+ }
74
+ </li>
75
+ <li><hr [class]="dividerClass">></li>
76
+ }
77
+
78
+ <li>
79
+ <a [class]="menuRowClass" (click)="onChangePasswordClick($event)">
80
+ <span [class]="indicatorClass"></span>
81
+ {{ 'ChangePassword' | translate }}
82
+ </a>
83
+ </li>
84
+
85
+ <li><hr [class]="dividerClass"></li>
86
+
87
+ <li>
88
+ <a [class]="menuRowClass" (click)="onOpenAboutClick($event)">
89
+ <fa-icon [class]="indicatorClass" [icon]="infoIcon"></fa-icon>
90
+ {{ 'About' | translate }}
91
+ </a>
92
+ </li>
93
+ </ul>
94
+ }
95
+ </div>
96
+
97
+ <bayan-core-change-password-widget
98
+ [baseUrl]="baseUrl"
99
+ [visible]="showChangePassword"
100
+ [config]="changePasswordDialog"
101
+ (visibleChange)="showChangePassword = !!$event">
102
+ </bayan-core-change-password-widget>
103
+
104
+ <bayan-core-about-dialog-widget
105
+ [visible]="showAbout"
106
+ [config]="aboutDialog"
107
+ [licenseUrl]="licenseUrl"
108
+ [releaseNotesUrl]="releaseNotesUrl"
109
+ [supportUrl]="supportUrl"
110
+ (visibleChange)="showAbout = !!$event">
111
+ </bayan-core-about-dialog-widget>