@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,235 @@
1
+ import { ModuleBlockState, AppFramePreferences, EmployeeNamesModeOption, BlockableModule, SystemModule } from '../../../shared/menu.dtos';
2
+ import { SkyAlertToastService } from '@skysoftware-co/sky-components-ui';
3
+ import { CommonModule } from '@angular/common';
4
+ import { BayanCoreChangePasswordWidgetComponent } from '../change-password-widget/change-password-widget.component';
5
+ import { BayanCoreAboutDialogWidgetComponent } from '../about-dialog-widget/about-dialog-widget.component';
6
+ import {
7
+ ChangeDetectionStrategy,
8
+ Component,
9
+ ElementRef,
10
+ EventEmitter,
11
+ HostListener,
12
+ Input,
13
+ OnChanges,
14
+ OnInit,
15
+ Output,
16
+ SimpleChanges,
17
+ inject,
18
+ signal,
19
+ } from '@angular/core';
20
+ import { BayanCoreTopMenuService } from '../../../shared/menu.service';
21
+ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
22
+ import { faCheck, faCog, faInfoCircle } from '@fortawesome/pro-solid-svg-icons';
23
+ import { TranslatePipe } from '@skysoftware-co/sky-components-ui';
24
+ // Removed duplicate import
25
+
26
+
27
+ @Component({
28
+ selector: 'bayan-core-settings-widget',
29
+ standalone: true,
30
+ imports: [
31
+ CommonModule,
32
+ FontAwesomeModule,
33
+ TranslatePipe,
34
+ BayanCoreChangePasswordWidgetComponent,
35
+ BayanCoreAboutDialogWidgetComponent
36
+ ],
37
+ templateUrl: './settings-widget.component.html',
38
+ styleUrls: ['../../top-menu-widget.styles.css'],
39
+ changeDetection: ChangeDetectionStrategy.OnPush,
40
+ })
41
+ export class BayanCoreSettingsWidgetComponent implements OnInit, OnChanges {
42
+ private readonly menuService = inject(BayanCoreTopMenuService);
43
+ private readonly alertToastService = inject(SkyAlertToastService);
44
+ @Input() baseUrl: string = '';
45
+ @Input() licenseUrl = '';
46
+ @Input() releaseNotesUrl = '';
47
+ @Input() supportUrl = 'https://skyits.com/contact';
48
+
49
+ @Input() ActivePropertyChanged: boolean = false;
50
+ @Input() systemModule : SystemModule | null =null;
51
+
52
+ @Input() checkIcon: any = faCheck;
53
+ @Input() cogIcon: any = faCog;
54
+ @Input() infoIcon: any = faInfoCircle;
55
+ @Input() dropdownOpen = signal(false);
56
+ showChangePassword = false;
57
+ showAbout = false;
58
+ currentModule: SystemModule | null = null;
59
+ SystemModule = SystemModule;
60
+ // CSS class bindings for customization
61
+ @Input() dropdownHostClass: string = 'dropdown menu-dropdown-host';
62
+ @Input() toggleBtnClass: string = 'menu-icon-btn';
63
+ @Input() menuPanelClass: string = 'settings-menu menu-dropdown-panel';
64
+ @Input() sectionLabelClass: string = 'menu-section-label';
65
+ @Input() menuRowClass: string = 'header-dropdown-item';
66
+ @Input() dividerClass: string = 'dropdown-divider';
67
+ @Input() indicatorClass: string = 'menu-indicator';
68
+ @Input() indicatorActiveClass: string = 'menu-indicator menu-indicator-active';
69
+ @Input() indicatorInvisibleClass: string = 'menu-indicator invisible';
70
+
71
+ @Output() alternateNamesChange = new EventEmitter<boolean>();
72
+ @Output() nameModeChange = new EventEmitter<EmployeeNamesModeOption>();
73
+
74
+ preferences: AppFramePreferences | null = null;
75
+ BlockableModule = BlockableModule;
76
+ EmployeeNamesModeOption = EmployeeNamesModeOption;
77
+ hrBlockState: ModuleBlockState | null = null;
78
+ tkBlockState: ModuleBlockState | null = null;
79
+ changePasswordDialog = {
80
+ title: 'ChangePassword',
81
+ currentPasswordLabel: 'CurrentPassword',
82
+ newPasswordLabel: 'NewPassword',
83
+ confirmNewPasswordLabel: 'ConfirmPassword',
84
+ primaryButtonText: 'Change',
85
+ };
86
+
87
+ aboutDialog = {
88
+ title: 'Sky Bayan Human Resources Management',
89
+ logoUrl: 'https://cdn-dev.skysoftware.cloud/bayan/images/logo-enterprise.png',
90
+ version: '',
91
+ versionLabel: 'Version',
92
+ copyright: `Copyright 2026, Sky Software Co LLC All Rights Reserved\nSky Bayan and Sky Bayan Logo are registered trademarks of Sky Software`,
93
+ statusLabel: 'SkyBayanUpToDate',
94
+ licenseButtonLabel: 'LicenseInformation',
95
+ releaseNotesButtonLabel: 'ReleaseNotes',
96
+ supportButtonLabel: 'TechnicalSupport',
97
+ closeButtonLabel: 'Close',
98
+ };
99
+
100
+ constructor(private readonly elementRef: ElementRef<HTMLElement>) {}
101
+
102
+ // ...existing methods...
103
+
104
+ showAlert(message: string, type: string = 'success') {
105
+ this.alertToastService.toastInformation(message, type as any);
106
+ }
107
+
108
+ ngOnInit(): void {
109
+ this.loadPreferences();
110
+ this.loadModuleBlockStates();
111
+ }
112
+
113
+ loadModuleBlockStates() {
114
+ if (this.baseUrl) {
115
+ this.menuService.getModuleBlockState(this.baseUrl, BlockableModule.HumanResources).subscribe({
116
+ next: state => this.hrBlockState = state,
117
+ error: () => this.hrBlockState = null
118
+ });
119
+ this.menuService.getModuleBlockState(this.baseUrl, BlockableModule.Timekeeping).subscribe({
120
+ next: state => this.tkBlockState = state,
121
+ error: () => this.tkBlockState = null
122
+ });
123
+ }
124
+ }
125
+
126
+ loadPreferences() {
127
+ if (this.baseUrl) {
128
+ this.menuService.getPreferences(this.baseUrl).subscribe({
129
+ next: prefs => {
130
+ this.preferences = prefs;
131
+ this.aboutDialog.version = prefs.VersionNumber;
132
+ },
133
+ error: () => {
134
+ this.preferences = null;
135
+ }
136
+ });
137
+ }
138
+ }
139
+
140
+ // No need to derive flags, use preferences directly in template and logic.
141
+ ngOnChanges(changes: SimpleChanges): void {
142
+ if (
143
+ changes['ActivePropertyChanged']
144
+ && !changes['ActivePropertyChanged'].firstChange
145
+ && changes['ActivePropertyChanged'].previousValue !== changes['ActivePropertyChanged'].currentValue
146
+ ) {
147
+ this.dropdownOpen.set(false);
148
+ this.loadPreferences();
149
+ this.loadModuleBlockStates();
150
+ }
151
+ }
152
+
153
+ @HostListener('document:click', ['$event'])
154
+ onDocumentClick(event: MouseEvent): void {
155
+ const target = event.target as Node | null;
156
+ if (target && !this.elementRef.nativeElement.contains(target)) {
157
+ this.dropdownOpen.set(false);
158
+ }
159
+ }
160
+
161
+ toggleDropdown(event: Event): void {
162
+ event.preventDefault();
163
+ this.dropdownOpen.update((value) => !value);
164
+ }
165
+
166
+ async onAlternateNamesClick(event: Event): Promise<void> {
167
+ event.preventDefault();
168
+ this.dropdownOpen.set(false);
169
+ if (!this.preferences || !this.baseUrl) {
170
+ return;
171
+ }
172
+ // Toggle the value
173
+ this.preferences.UseAlternateNames = !this.preferences.UseAlternateNames;
174
+ const newValue = !this.preferences.UseAlternateNames;
175
+ try {
176
+ await this.menuService.setDisplayAlternateNames(this.baseUrl, { DisplayAlternateNames: newValue }).toPromise();
177
+ await this.loadPreferences();
178
+ this.alternateNamesChange.emit(newValue);
179
+ } catch (err) {}
180
+ }
181
+
182
+ async onNameModeClick(nameMode: EmployeeNamesModeOption, event: Event): Promise<void> {
183
+ event.preventDefault();
184
+ this.dropdownOpen.set(false);
185
+
186
+ if (!this.preferences || !this.baseUrl) {
187
+ return;
188
+ }
189
+
190
+ try {
191
+ await this.menuService.setEmployeeNamesMode(this.baseUrl, { EmployeeNamesMode: nameMode }).toPromise();
192
+ // Reload preferences
193
+ await this.loadPreferences();
194
+ this.nameModeChange.emit(nameMode);
195
+ } catch (err) {
196
+ // Optionally handle error
197
+ }
198
+ }
199
+
200
+ onChangePasswordClick(event: Event): void {
201
+ event.preventDefault();
202
+ this.dropdownOpen.set(false);
203
+ this.showChangePassword = true;
204
+ }
205
+
206
+ onOpenAboutClick(event: Event): void {
207
+ event.preventDefault();
208
+ this.dropdownOpen.set(false);
209
+ this.showAbout = true;
210
+ }
211
+
212
+ async blockModule(module: BlockableModule, event: Event): Promise<void> {
213
+ event.preventDefault();
214
+ this.dropdownOpen.set(false);
215
+ if (!this.baseUrl) return;
216
+ try {
217
+ await this.menuService.blockModule(this.baseUrl, { Module: module }).toPromise();
218
+ await this.loadModuleBlockStates();
219
+ const key = module === BlockableModule.HumanResources ? 'BlockHRSuccess' : 'BlockTKSuccess';
220
+ this.showAlert(key);
221
+ } catch {}
222
+ }
223
+
224
+ async releaseModule(module: BlockableModule, event: Event): Promise<void> {
225
+ event.preventDefault();
226
+ this.dropdownOpen.set(false);
227
+ if (!this.baseUrl) return;
228
+ try {
229
+ await this.menuService.releaseModule(this.baseUrl, { Module: module }).toPromise();
230
+ await this.loadModuleBlockStates();
231
+ const key = module === BlockableModule.HumanResources ? 'ReleaseHRSuccess' : 'ReleaseTKSuccess';
232
+ this.showAlert(key);
233
+ } catch {}
234
+ }
235
+ }
@@ -0,0 +1,54 @@
1
+ <div [ngClass]="[wrapperClass, dropdownOpen() ? dropdownOpenClass : '']">
2
+ <a href="#" [class]="toggleButtonClass" (click)="toggleDropdown($event)">
3
+ <bayan-employee-badge [badge]="badge()" width="34px" height="34px"></bayan-employee-badge>
4
+
5
+ <div [class]="employeeInfoClass">
6
+ <span [class]="userNameClass">{{ userPanel()?.UserDisplayName || '' }}</span>
7
+
8
+ @if (userPanel()?.ActivePropertyName) {
9
+ <span [class]="propertyNameClass">{{ userPanel()?.ActivePropertyName }}</span>
10
+ }
11
+ </div>
12
+
13
+ <span [class]="caretClass">&#9660;</span>
14
+ </a>
15
+
16
+ @if (dropdownOpen()) {
17
+ <ul [class]="menuClass">
18
+ @if ((userPanel()?.Properties?.length || 0) > 0) {
19
+ <li [class]="sectionLabelClass">{{ 'Properties' | translate }}</li>
20
+
21
+ @for (property of userPanel()?.Properties ?? []; track property.PropertyId) {
22
+ <li>
23
+ <a
24
+ class="text-dark-gray"
25
+ [ngClass]="[menuItemClass, property.PropertyId === userPanel()?.ActivePropertyId ? menuItemActiveClass : '']"
26
+ (click)="selectProperty($event, property)">
27
+ @if (property.PropertyId === userPanel()?.ActivePropertyId) {
28
+ <span [class]="indicatorClass">&#9658;</span>
29
+ } @else {
30
+ <span [class]="indicatorClass + ' ' + invisibleIndicatorClass"></span>
31
+ }
32
+
33
+ {{ property.PropertyName }}
34
+ </a>
35
+ </li>
36
+ }
37
+
38
+ <li><hr [class]="dividerClass"></li>
39
+ }
40
+
41
+ @if (!userPanel()?.IsSSOLogin) {
42
+ <li>
43
+ <a class="text-dark-gray" [class]="signOutButtonClass"
44
+ [ngClass]="{'ms-3': !showSignOutIcon}" (click)="signOut($event)">
45
+ @if (showSignOutIcon) {
46
+ <fa-icon [class]="signOutIconClass" [icon]="signOutIcon"></fa-icon>
47
+ }
48
+ {{ 'SignOut' | translate }}
49
+ </a>
50
+ </li>
51
+ }
52
+ </ul>
53
+ }
54
+ </div>
@@ -0,0 +1,140 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ ElementRef,
6
+ EventEmitter,
7
+ HostListener,
8
+ Input,
9
+ OnChanges,
10
+ OnInit,
11
+ Output,
12
+ SimpleChanges,
13
+ computed,
14
+ inject,
15
+ signal,
16
+ } from '@angular/core';
17
+ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
18
+ import { faPersonRunning } from '@fortawesome/pro-solid-svg-icons';
19
+ import { BayanEmployeeBadgeComponent, BayanEmployeeBadgeDTO } from '@skysoftware-co/bayan-components-ui';
20
+ import { TranslatePipe } from '@skysoftware-co/sky-components-ui';
21
+ import { UserPanel, PropertyOption } from '../../../shared/menu.dtos';
22
+ import { BayanCoreTopMenuService } from '../../../shared/menu.service';
23
+
24
+ @Component({
25
+ selector: 'bayan-core-user-panel-widget',
26
+ standalone: true,
27
+ imports: [CommonModule, FontAwesomeModule, BayanEmployeeBadgeComponent, TranslatePipe],
28
+ templateUrl: './user-panel-widget.component.html',
29
+ styleUrls: ['../../top-menu-widget.styles.css'],
30
+ changeDetection: ChangeDetectionStrategy.OnPush,
31
+ })
32
+ export class BayanCoreUserPanelWidgetComponent implements OnInit, OnChanges {
33
+ private readonly topMenuService = inject(BayanCoreTopMenuService);
34
+
35
+ @Input() baseUrl = '';
36
+ @Input() wrapperClass = 'menu-dropdown-host';
37
+ @Input() dropdownOpenClass = 'open';
38
+ @Input() toggleButtonClass = 'employee-toggle';
39
+ @Input() employeeInfoClass = 'employee-info';
40
+ @Input() userNameClass = 'user-name';
41
+ @Input() propertyNameClass = 'property-name';
42
+ @Input() caretClass = 'employee-caret';
43
+ @Input() menuClass = 'employee-menu menu-dropdown-panel';
44
+ @Input() sectionLabelClass = 'menu-section-label';
45
+ @Input() menuItemClass = 'menu-item';
46
+ @Input() menuItemActiveClass = 'menu-item-active';
47
+ @Input() indicatorClass = 'menu-indicator';
48
+ @Input() invisibleIndicatorClass = 'menu-indicator invisible';
49
+ @Input() dividerClass = 'menu-divider';
50
+ @Input() signOutButtonClass = 'menu-item menu-item-signout';
51
+ @Input() showSignOutIcon = true;
52
+ @Input() signOutIconClass = 'mx-2';
53
+
54
+ @Output() propertyChanged = new EventEmitter<PropertyOption>();
55
+ @Output() signOutClick = new EventEmitter<void>();
56
+
57
+ readonly signOutIcon = faPersonRunning;
58
+ readonly dropdownOpen = signal(false);
59
+ readonly userPanel = signal<UserPanel | null>(null);
60
+
61
+ readonly badge = computed<BayanEmployeeBadgeDTO>(() => ({
62
+ EmployeePhotoKey: this.userPanel()?.PhotoPath ?? null,
63
+ EmployeePhotoFailed: false,
64
+ EmployeeNameInitials: this.userPanel()?.NameInitials ?? '',
65
+ }));
66
+
67
+ constructor(private readonly elementRef: ElementRef<HTMLElement>) {}
68
+
69
+ ngOnInit(): void {
70
+ this.loadUserPanel();
71
+ }
72
+
73
+ ngOnChanges(changes: SimpleChanges): void {
74
+ if (changes['baseUrl'] && !changes['baseUrl'].firstChange) {
75
+ this.loadUserPanel();
76
+ }
77
+ }
78
+
79
+ @HostListener('document:click', ['$event'])
80
+ onDocumentClick(event: MouseEvent): void {
81
+ const target = event.target as Node | null;
82
+ if (target && !this.elementRef.nativeElement.contains(target)) {
83
+ this.dropdownOpen.set(false);
84
+ }
85
+ }
86
+
87
+ toggleDropdown(event: Event): void {
88
+ event.preventDefault();
89
+ this.dropdownOpen.update((value) => !value);
90
+ }
91
+
92
+ selectProperty(event: Event, property: PropertyOption): void {
93
+ event.preventDefault();
94
+ if (property.PropertyId === this.userPanel()?.ActivePropertyId) {
95
+ this.dropdownOpen.set(false);
96
+ return;
97
+ }
98
+
99
+ this.dropdownOpen.set(false);
100
+
101
+ this.topMenuService
102
+ .switchProperty(this.baseUrl, { PropertyId: property.PropertyId })
103
+ .subscribe({
104
+ next: () => {
105
+ this.topMenuService.getUserPanel(this.baseUrl).subscribe({
106
+ next: (userPanel) => {
107
+ this.userPanel.set(userPanel);
108
+ this.propertyChanged.emit(property);
109
+ },
110
+ });
111
+ },
112
+ });
113
+ }
114
+
115
+ signOut(event: Event): void {
116
+ event.preventDefault();
117
+ this.dropdownOpen.set(false);
118
+ this.signOutClick.emit();
119
+ }
120
+
121
+ private loadUserPanel(): void {
122
+ if (!this.baseUrl) {
123
+ this.userPanel.set(null);
124
+ return;
125
+ }
126
+
127
+ this.topMenuService.getUserPanel(this.baseUrl).subscribe({
128
+ next: (userPanel) => {
129
+ this.userPanel.set(userPanel);
130
+ let property : PropertyOption = {
131
+ PropertyId: userPanel.ActivePropertyId,
132
+ PropertyName: userPanel.ActivePropertyName };
133
+ this.propertyChanged.emit(property);
134
+ },
135
+ error: () => {
136
+ this.userPanel.set(null);
137
+ },
138
+ });
139
+ }
140
+ }
@@ -0,0 +1,107 @@
1
+ <header class="top-bar-header shadow-sm w-100 sticky-top">
2
+ <dx-toolbar class="header-toolbar px-4">
3
+ <dxi-item location="before">
4
+ <div *dxTemplate>
5
+ <a
6
+ class="navbar-brand-link" href="#"
7
+ [class.collapsed]="sidebarCollapsed"
8
+ (click)="onLogoClicked($event)">
9
+ <img
10
+ [src]="getLogoSrc()"
11
+ alt=""
12
+ [class.header-logo]="!sidebarCollapsed"
13
+ [class.header-logo-collapsed]="sidebarCollapsed && !!collapsedLogoUrl">
14
+ </a>
15
+ </div>
16
+ </dxi-item>
17
+
18
+ @if (showShortcutMenus) {
19
+ <dxi-item location="before" locateInMenu="never">
20
+ <div *dxTemplate>
21
+ <ul class="nav navbar-nav d-flex flex-row align-items-center mb-0 gap-1">
22
+ @for (item of menuItems; track item.MenuName; let idx = $index) {
23
+ <bayan-core-item-widget [item]="item"
24
+ [baseUrl]="baseUrl"
25
+ [ActivePropertyChanged]="ActivePropertyChanged"
26
+ [open]="openDropdownIndex === idx"
27
+ (toggleOpen)="openDropdownIndex = openDropdownIndex === idx ? null : idx"
28
+ (itemClick)="menuItemClick.emit($event)">
29
+ </bayan-core-item-widget>
30
+ }
31
+ </ul>
32
+ </div>
33
+ </dxi-item>
34
+ }
35
+
36
+ @if (showGlobalSearch) {
37
+ <dxi-item location="after" locateInMenu="never">
38
+ <div *dxTemplate>
39
+ <bayan-core-global-search-widget
40
+ #globalSearchWidget
41
+ [baseUrl]="baseUrl"
42
+ [ActivePropertyId]="ActivePropertyId"
43
+ [ActivePropertyChanged]="ActivePropertyChanged"
44
+ (search)="searchSubmit.emit($event)">
45
+ </bayan-core-global-search-widget>
46
+ </div>
47
+ </dxi-item>
48
+ }
49
+
50
+ @if (showUserPanel) {
51
+ <dxi-item location="after" locateInMenu="never">
52
+ <div *dxTemplate>
53
+ <bayan-core-user-panel-widget
54
+ [baseUrl]="baseUrl"
55
+ [showSignOutIcon]="false"
56
+ (propertyChanged)="onPropertyChanged($event)"
57
+ (signOutClick)="signOutClick.emit()">
58
+ </bayan-core-user-panel-widget>
59
+ </div>
60
+ </dxi-item>
61
+ }
62
+
63
+ @if (showSettings) {
64
+ <dxi-item location="after" locateInMenu="never">
65
+ <div *dxTemplate>
66
+ <bayan-core-settings-widget
67
+ [ActivePropertyChanged]="ActivePropertyChanged"
68
+ [baseUrl]="baseUrl"
69
+ [licenseUrl]="licenseUrl"
70
+ [releaseNotesUrl]="releaseNotesUrl"
71
+ [supportUrl]="supportUrl"
72
+ [systemModule]="systemModule"
73
+ (alternateNamesChange)="alternateNamesChange.emit($event)"
74
+ (employeeNameModeChange)="onEmployeeNameModeChange($event)">
75
+ </bayan-core-settings-widget>
76
+ </div>
77
+ </dxi-item>
78
+ }
79
+
80
+ @if (showNotifications) {
81
+ <dxi-item location="after" locateInMenu="never">
82
+ <div *dxTemplate>
83
+ <bayan-core-notifications-widget [baseUrl]="baseUrl"
84
+ [title]="notificationsTitle | translate" >
85
+ </bayan-core-notifications-widget>
86
+ </div>
87
+ </dxi-item>
88
+ }
89
+
90
+ @if (showHelp) {
91
+ <dxi-item location="after" locateInMenu="never">
92
+ <div *dxTemplate>
93
+ <a
94
+ [class]="helpAnchorClass"
95
+ [title]="helpTitle | translate"
96
+ [target]="helpUrlTarget"
97
+ href="#"
98
+ (click)="onHelpClicked($event)">
99
+ <fa-icon [icon]="helpIcon" class="fs-6"></fa-icon>
100
+ </a>
101
+ </div>
102
+ </dxi-item>
103
+ }
104
+ </dx-toolbar>
105
+ </header>
106
+
107
+ <!-- Dialogs are now rendered inside settings-widget, not here -->