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

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 (60) hide show
  1. package/README.md +2 -2
  2. package/ng-package.json +7 -0
  3. package/package.json +1 -1
  4. package/src/assets/i18n/ar.json +725 -0
  5. package/src/assets/i18n/en.json +683 -0
  6. package/src/assets/i18n/fr.json +687 -0
  7. package/src/lib/shared/common-methods/navigation.utils.ts +21 -0
  8. package/src/lib/shared/menu.dtos.ts +107 -0
  9. package/src/lib/shared/menu.service.ts +157 -0
  10. package/src/lib/top-menu-widget/components/about-dialog-widget/about-dialog-widget.component.html +37 -0
  11. package/src/lib/top-menu-widget/components/about-dialog-widget/about-dialog-widget.component.ts +68 -0
  12. package/src/lib/top-menu-widget/components/change-password-widget/change-password-widget.component.html +56 -0
  13. package/src/lib/top-menu-widget/components/change-password-widget/change-password-widget.component.ts +158 -0
  14. package/src/lib/top-menu-widget/components/global-search-widget/global-search-widget.component.html +39 -0
  15. package/src/lib/top-menu-widget/components/global-search-widget/global-search-widget.component.ts +153 -0
  16. package/src/lib/top-menu-widget/components/item-widget/item-widget.component.html +39 -0
  17. package/src/lib/top-menu-widget/components/item-widget/item-widget.component.ts +95 -0
  18. package/src/lib/top-menu-widget/components/notifications-widget/notifications-widget.component.html +10 -0
  19. package/src/lib/top-menu-widget/components/notifications-widget/notifications-widget.component.ts +89 -0
  20. package/src/lib/top-menu-widget/components/settings-widget/settings-widget.component.html +119 -0
  21. package/src/lib/top-menu-widget/components/settings-widget/settings-widget.component.ts +233 -0
  22. package/src/lib/top-menu-widget/components/user-panel-widget/user-panel-widget.component.html +53 -0
  23. package/src/lib/top-menu-widget/components/user-panel-widget/user-panel-widget.component.ts +140 -0
  24. package/src/lib/top-menu-widget/top-menu-widget.component.html +103 -0
  25. package/src/lib/top-menu-widget/top-menu-widget.component.ts +148 -0
  26. package/src/lib/top-menu-widget/top-menu-widget.models.ts +29 -0
  27. package/src/lib/top-menu-widget/top-menu-widget.styles.css +576 -0
  28. package/{public-api.d.ts → src/public-api.ts} +7 -4
  29. package/tsconfig.lib.json +16 -0
  30. package/tsconfig.lib.prod.json +9 -0
  31. package/tsconfig.spec.json +13 -0
  32. package/fesm2022/skysoftware-co-bayan-core-widgets-ui.mjs +0 -1092
  33. package/fesm2022/skysoftware-co-bayan-core-widgets-ui.mjs.map +0 -1
  34. package/index.d.ts +0 -6
  35. package/lib/shared/common-methods/navigation.utils.d.ts +0 -4
  36. package/lib/shared/common-methods/navigation.utils.d.ts.map +0 -1
  37. package/lib/shared/menu.dtos.d.ts +0 -91
  38. package/lib/shared/menu.dtos.d.ts.map +0 -1
  39. package/lib/shared/menu.service.d.ts +0 -24
  40. package/lib/shared/menu.service.d.ts.map +0 -1
  41. package/lib/top-menu-widget/components/about-dialog-widget/about-dialog-widget.component.d.ts +0 -18
  42. package/lib/top-menu-widget/components/about-dialog-widget/about-dialog-widget.component.d.ts.map +0 -1
  43. package/lib/top-menu-widget/components/change-password-widget/change-password-widget.component.d.ts +0 -30
  44. package/lib/top-menu-widget/components/change-password-widget/change-password-widget.component.d.ts.map +0 -1
  45. package/lib/top-menu-widget/components/global-search-widget/global-search-widget.component.d.ts +0 -59
  46. package/lib/top-menu-widget/components/global-search-widget/global-search-widget.component.d.ts.map +0 -1
  47. package/lib/top-menu-widget/components/item-widget/item-widget.component.d.ts +0 -29
  48. package/lib/top-menu-widget/components/item-widget/item-widget.component.d.ts.map +0 -1
  49. package/lib/top-menu-widget/components/notifications-widget/notifications-widget.component.d.ts +0 -23
  50. package/lib/top-menu-widget/components/notifications-widget/notifications-widget.component.d.ts.map +0 -1
  51. package/lib/top-menu-widget/components/settings-widget/settings-widget.component.d.ts +0 -37
  52. package/lib/top-menu-widget/components/settings-widget/settings-widget.component.d.ts.map +0 -1
  53. package/lib/top-menu-widget/components/user-panel-widget/user-panel-widget.component.d.ts +0 -43
  54. package/lib/top-menu-widget/components/user-panel-widget/user-panel-widget.component.d.ts.map +0 -1
  55. package/lib/top-menu-widget/top-menu-widget.component.d.ts +0 -76
  56. package/lib/top-menu-widget/top-menu-widget.component.d.ts.map +0 -1
  57. package/lib/top-menu-widget/top-menu-widget.models.d.ts +0 -36
  58. package/lib/top-menu-widget/top-menu-widget.models.d.ts.map +0 -1
  59. package/public-api.d.ts.map +0 -1
  60. package/skysoftware-co-bayan-core-widgets-ui.d.ts.map +0 -1
@@ -0,0 +1,233 @@
1
+ import { ModuleBlockState, AppFramePreferences, EmployeeNamesModeOption, BlockableModule } 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
+
51
+ @Input() checkIcon: any = faCheck;
52
+ @Input() cogIcon: any = faCog;
53
+ @Input() infoIcon: any = faInfoCircle;
54
+ @Input() dropdownOpen = signal(false);
55
+ showChangePassword = false;
56
+ showAbout = false;
57
+
58
+ // CSS class bindings for customization
59
+ @Input() dropdownHostClass: string = 'dropdown menu-dropdown-host';
60
+ @Input() toggleBtnClass: string = 'settings-toggle menu-icon-btn';
61
+ @Input() menuPanelClass: string = 'settings-menu menu-dropdown-panel';
62
+ @Input() sectionLabelClass: string = 'menu-section-label';
63
+ @Input() menuRowClass: string = 'dropdown-item header-dropdown-item menu-row text-dark-gray';
64
+ @Input() dividerClass: string = 'dropdown-divider';
65
+ @Input() indicatorClass: string = 'menu-indicator';
66
+ @Input() indicatorActiveClass: string = 'menu-indicator menu-indicator-active';
67
+ @Input() indicatorInvisibleClass: string = 'menu-indicator invisible';
68
+ @Input() alternateNamesLinkClass: string = 'dropdown-item header-dropdown-item menu-row text-dark-gray';
69
+
70
+ @Output() alternateNamesChange = new EventEmitter<boolean>();
71
+ @Output() nameModeChange = new EventEmitter<EmployeeNamesModeOption>();
72
+
73
+ preferences: AppFramePreferences | null = null;
74
+ BlockableModule = BlockableModule;
75
+ EmployeeNamesModeOption = EmployeeNamesModeOption;
76
+ hrBlockState: ModuleBlockState | null = null;
77
+ tkBlockState: ModuleBlockState | null = null;
78
+ changePasswordDialog = {
79
+ title: 'ChangePassword',
80
+ currentPasswordLabel: 'CurrentPassword',
81
+ newPasswordLabel: 'NewPassword',
82
+ confirmNewPasswordLabel: 'ConfirmPassword',
83
+ primaryButtonText: 'Change',
84
+ };
85
+
86
+ aboutDialog = {
87
+ title: 'Sky Bayan Human Resources Management',
88
+ logoUrl: 'https://cdn-dev.skysoftware.cloud/bayan/images/logo-enterprise.png',
89
+ version: '',
90
+ versionLabel: 'Version',
91
+ copyright: `Copyright 2026, Sky Software Co LLC All Rights Reserved\nSky Bayan and Sky Bayan Logo are registered trademarks of Sky Software`,
92
+ statusLabel: 'SkyBayanUpToDate',
93
+ licenseButtonLabel: 'LicenseInformation',
94
+ releaseNotesButtonLabel: 'ReleaseNotes',
95
+ supportButtonLabel: 'TechnicalSupport',
96
+ closeButtonLabel: 'Close',
97
+ };
98
+
99
+ constructor(private readonly elementRef: ElementRef<HTMLElement>) {}
100
+
101
+ // ...existing methods...
102
+
103
+ showAlert(message: string, type: string = 'success') {
104
+ this.alertToastService.toastInformation(message, type as any);
105
+ }
106
+
107
+ ngOnInit(): void {
108
+ this.loadPreferences();
109
+ this.loadModuleBlockStates();
110
+ }
111
+
112
+ loadModuleBlockStates() {
113
+ if (this.baseUrl) {
114
+ this.menuService.getModuleBlockState(this.baseUrl, BlockableModule.HumanResources).subscribe({
115
+ next: state => this.hrBlockState = state,
116
+ error: () => this.hrBlockState = null
117
+ });
118
+ this.menuService.getModuleBlockState(this.baseUrl, BlockableModule.Timekeeping).subscribe({
119
+ next: state => this.tkBlockState = state,
120
+ error: () => this.tkBlockState = null
121
+ });
122
+ }
123
+ }
124
+
125
+ loadPreferences() {
126
+ if (this.baseUrl) {
127
+ this.menuService.getPreferences(this.baseUrl).subscribe({
128
+ next: prefs => {
129
+ this.preferences = prefs;
130
+ this.aboutDialog.version = prefs.VersionNumber;
131
+ },
132
+ error: () => {
133
+ this.preferences = null;
134
+ }
135
+ });
136
+ }
137
+ }
138
+
139
+ // No need to derive flags, use preferences directly in template and logic.
140
+ ngOnChanges(changes: SimpleChanges): void {
141
+ if (
142
+ changes['ActivePropertyChanged']
143
+ && !changes['ActivePropertyChanged'].firstChange
144
+ && changes['ActivePropertyChanged'].previousValue !== changes['ActivePropertyChanged'].currentValue
145
+ ) {
146
+ this.dropdownOpen.set(false);
147
+ this.loadPreferences();
148
+ this.loadModuleBlockStates();
149
+ }
150
+ }
151
+
152
+ @HostListener('document:click', ['$event'])
153
+ onDocumentClick(event: MouseEvent): void {
154
+ const target = event.target as Node | null;
155
+ if (target && !this.elementRef.nativeElement.contains(target)) {
156
+ this.dropdownOpen.set(false);
157
+ }
158
+ }
159
+
160
+ toggleDropdown(event: Event): void {
161
+ event.preventDefault();
162
+ this.dropdownOpen.update((value) => !value);
163
+ }
164
+
165
+ async onAlternateNamesClick(event: Event): Promise<void> {
166
+ event.preventDefault();
167
+ this.dropdownOpen.set(false);
168
+ if (!this.preferences || !this.baseUrl) {
169
+ return;
170
+ }
171
+ // Toggle the value
172
+ const newValue = !this.preferences.UseAlternateNames;
173
+ try {
174
+ await this.menuService.setDisplayAlternateNames(this.baseUrl, { DisplayAlternateNames: newValue }).toPromise();
175
+ await this.loadPreferences();
176
+ this.alternateNamesChange.emit(newValue);
177
+ } catch (err) {}
178
+ }
179
+
180
+ async onNameModeClick(nameMode: EmployeeNamesModeOption, event: Event): Promise<void> {
181
+ event.preventDefault();
182
+ this.dropdownOpen.set(false);
183
+
184
+ if (!this.preferences || !this.baseUrl) {
185
+ return;
186
+ }
187
+
188
+ try {
189
+ await this.menuService.setEmployeeNamesMode(this.baseUrl, { EmployeeNamesMode: nameMode }).toPromise();
190
+ // Reload preferences
191
+ await this.loadPreferences();
192
+ this.nameModeChange.emit(nameMode);
193
+ } catch (err) {
194
+ // Optionally handle error
195
+ }
196
+ }
197
+
198
+ onChangePasswordClick(event: Event): void {
199
+ event.preventDefault();
200
+ this.dropdownOpen.set(false);
201
+ this.showChangePassword = true;
202
+ }
203
+
204
+ onOpenAboutClick(event: Event): void {
205
+ event.preventDefault();
206
+ this.dropdownOpen.set(false);
207
+ this.showAbout = true;
208
+ }
209
+
210
+ async blockModule(module: BlockableModule, event: Event): Promise<void> {
211
+ event.preventDefault();
212
+ this.dropdownOpen.set(false);
213
+ if (!this.baseUrl) return;
214
+ try {
215
+ await this.menuService.blockModule(this.baseUrl, { Module: module }).toPromise();
216
+ await this.loadModuleBlockStates();
217
+ const key = module === BlockableModule.HumanResources ? 'BlockHRSuccess' : 'BlockTKSuccess';
218
+ this.showAlert(key);
219
+ } catch {}
220
+ }
221
+
222
+ async releaseModule(module: BlockableModule, event: Event): Promise<void> {
223
+ event.preventDefault();
224
+ this.dropdownOpen.set(false);
225
+ if (!this.baseUrl) return;
226
+ try {
227
+ await this.menuService.releaseModule(this.baseUrl, { Module: module }).toPromise();
228
+ await this.loadModuleBlockStates();
229
+ const key = module === BlockableModule.HumanResources ? 'ReleaseHRSuccess' : 'ReleaseTKSuccess';
230
+ this.showAlert(key);
231
+ } catch {}
232
+ }
233
+ }
@@ -0,0 +1,53 @@
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" (click)="signOut($event)">
44
+ @if (showSignOutIcon) {
45
+ <fa-icon [class]="signOutIconClass" [icon]="signOutIcon"></fa-icon>
46
+ }
47
+ {{ 'SignOut' | translate }}
48
+ </a>
49
+ </li>
50
+ }
51
+ </ul>
52
+ }
53
+ </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 = '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,103 @@
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 (ShowShourtcutMenus) {
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) {
23
+ <bayan-core-item-widget [item]="item"
24
+ [baseUrl]="baseUrl"
25
+ [ActivePropertyChanged]="ActivePropertyChanged"
26
+ (itemClick)="menuItemClick.emit($event)">
27
+ </bayan-core-item-widget>
28
+ }
29
+ </ul>
30
+ </div>
31
+ </dxi-item>
32
+ }
33
+
34
+ @if (showGlobalSearch) {
35
+ <dxi-item location="after" locateInMenu="never">
36
+ <div *dxTemplate>
37
+ <bayan-core-global-search-widget
38
+ [baseUrl]="baseUrl"
39
+ [ActivePropertyId]="ActivePropertyId"
40
+ [ActivePropertyChanged]="ActivePropertyChanged"
41
+ (search)="searchSubmit.emit($event)">
42
+ </bayan-core-global-search-widget>
43
+ </div>
44
+ </dxi-item>
45
+ }
46
+
47
+ @if (showUserPanel) {
48
+ <dxi-item location="after" locateInMenu="never">
49
+ <div *dxTemplate>
50
+ <bayan-core-user-panel-widget
51
+ [baseUrl]="baseUrl"
52
+ [showSignOutIcon]="false"
53
+ (propertyChanged)="onPropertyChanged($event)"
54
+ (signOutClick)="signOutClick.emit()">
55
+ </bayan-core-user-panel-widget>
56
+ </div>
57
+ </dxi-item>
58
+ }
59
+
60
+ @if (showSettings) {
61
+ <dxi-item location="after" locateInMenu="never">
62
+ <div *dxTemplate>
63
+ <bayan-core-settings-widget
64
+ [ActivePropertyChanged]="ActivePropertyChanged"
65
+ [baseUrl]="baseUrl"
66
+ [licenseUrl]="licenseUrl"
67
+ [releaseNotesUrl]="releaseNotesUrl"
68
+ [supportUrl]="supportUrl"
69
+ (alternateNamesChange)="alternateNamesChange.emit($event)"
70
+ (employeeNameModeChange)="onEmployeeNameModeChange($event)">
71
+ </bayan-core-settings-widget>
72
+ </div>
73
+ </dxi-item>
74
+ }
75
+
76
+ @if (showNotifications) {
77
+ <dxi-item location="after" locateInMenu="never">
78
+ <div *dxTemplate>
79
+ <bayan-core-notifications-widget [baseUrl]="baseUrl"
80
+ [title]="notificationsTitle | translate" >
81
+ </bayan-core-notifications-widget>
82
+ </div>
83
+ </dxi-item>
84
+ }
85
+
86
+ @if (showHelp) {
87
+ <dxi-item location="after" locateInMenu="never">
88
+ <div *dxTemplate>
89
+ <a
90
+ [class]="helpAnchorClass"
91
+ [title]="helpTitle | translate"
92
+ [target]="helpUrlTarget"
93
+ href="#"
94
+ (click)="onHelpClicked($event)">
95
+ <fa-icon [icon]="helpIcon" class="fs-6"></fa-icon>
96
+ </a>
97
+ </div>
98
+ </dxi-item>
99
+ }
100
+ </dx-toolbar>
101
+ </header>
102
+
103
+ <!-- Dialogs are now rendered inside settings-widget, not here -->
@@ -0,0 +1,148 @@
1
+ import { BayanCoreTopMenuService } from '../shared/menu.service';
2
+ import { TopMenuShortcut, PropertyOption, SystemModule, EmployeeNamesModeOption } from '../shared/menu.dtos';
3
+ import { CommonModule, DOCUMENT } from '@angular/common';
4
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output, inject, signal } from '@angular/core';
5
+ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
6
+ import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
7
+ import { faQuestionCircle } from '@fortawesome/pro-solid-svg-icons';
8
+ import { Router } from '@angular/router';
9
+ import { DxToolbarModule } from 'devextreme-angular';
10
+ import { TranslatePipe } from '@skysoftware-co/sky-components-ui';
11
+ import { isExternalNavigation, resolveUrl } from '../shared/common-methods/navigation.utils';
12
+ import {
13
+ TopMenuWidgetAboutDialogConfig,
14
+ TopMenuWidgetChangePasswordDialogConfig,
15
+ TopMenuWidgetChangePasswordPayload
16
+ } from './top-menu-widget.models';
17
+ import { BayanCoreAboutDialogWidgetComponent } from './components/about-dialog-widget/about-dialog-widget.component';
18
+ import { BayanCoreChangePasswordWidgetComponent } from './components/change-password-widget/change-password-widget.component';
19
+ import { BayanCoreGlobalSearchWidgetComponent } from './components/global-search-widget/global-search-widget.component';
20
+ import { BayanCoreItemWidgetComponent } from './components/item-widget/item-widget.component';
21
+ import { BayanCoreNotificationsWidgetComponent } from './components/notifications-widget/notifications-widget.component';
22
+ import { BayanCoreSettingsWidgetComponent } from './components/settings-widget/settings-widget.component';
23
+ import { BayanCoreUserPanelWidgetComponent } from './components/user-panel-widget/user-panel-widget.component';
24
+
25
+ @Component({
26
+ selector: 'bayan-core-top-menu-widget',
27
+ standalone: true,
28
+ imports: [
29
+ CommonModule,
30
+ DxToolbarModule,
31
+ FontAwesomeModule,
32
+ TranslatePipe,
33
+ BayanCoreItemWidgetComponent,
34
+ BayanCoreGlobalSearchWidgetComponent,
35
+ BayanCoreUserPanelWidgetComponent,
36
+ BayanCoreSettingsWidgetComponent,
37
+ BayanCoreAboutDialogWidgetComponent,
38
+ BayanCoreChangePasswordWidgetComponent,
39
+ BayanCoreNotificationsWidgetComponent,
40
+ ],
41
+ templateUrl: './top-menu-widget.component.html',
42
+ styleUrls: ['./top-menu-widget.styles.css'],
43
+ changeDetection: ChangeDetectionStrategy.OnPush,
44
+ })
45
+ export class BayanCoreTopMenuWidgetComponent implements OnInit {
46
+ private readonly document = inject(DOCUMENT);
47
+ private readonly router = inject(Router);
48
+ private readonly menuService = inject(BayanCoreTopMenuService);
49
+
50
+ @Input() baseUrl = '';
51
+ @Input() systemModule : SystemModule | null =null;
52
+ menuItems: TopMenuShortcut[] = [];
53
+
54
+ @Input() sidebarCollapsed = false;
55
+ @Input() homeUrl: string | null = null;
56
+ @Input() logoUrl = 'https://cdn-dev.skysoftware.cloud/bayan/images/logo-enterprise-dark.png';
57
+ @Input() collapsedLogoUrl = 'https://cdn-dev.skysoftware.cloud/bayan/images/logo-collapsed.png';
58
+ @Output() logoClick = new EventEmitter<void>();
59
+
60
+ @Input() isSsoLogin = false;
61
+
62
+ // Removed useInternalDialogs and all related logic
63
+
64
+ @Input() showGlobalSearch = true;
65
+ @Input() showUserPanel = true;
66
+ @Input() showSettings = true;
67
+ @Input() ShowShourtcutMenus = true;
68
+ @Input() showNotifications = true;
69
+ @Input() notificationsTitle = 'Notifications';
70
+
71
+ @Input() showHelp = true;
72
+ @Input() helpTitle = 'Help';
73
+ @Input() helpUrl: string | null = 'https://docs.bayan.solutions/Bayan/index.html';
74
+ @Input() helpIcon: IconDefinition = faQuestionCircle;
75
+ @Input() helpAnchorClass = 'menu-icon-btn';
76
+ @Input() helpUrlTarget: '_self' | '_blank' | string = '_blank';
77
+ @Input() licenseUrl = '';
78
+ @Input() releaseNotesUrl = '';
79
+ @Input() supportUrl = 'https://skyits.com/contact';
80
+
81
+ @Output() helpClick = new EventEmitter<void>();
82
+ @Output() menuItemClick = new EventEmitter<TopMenuShortcut>();
83
+ @Output() searchSubmit = new EventEmitter<string>();
84
+ @Output() propertyChanged = new EventEmitter<PropertyOption>();
85
+ @Output() signOutClick = new EventEmitter<void>();
86
+ @Output() alternateNamesChange = new EventEmitter<boolean>();
87
+ @Output() employeeNameModeChange = new EventEmitter<EmployeeNamesModeOption>();
88
+
89
+ readonly aboutVisible = signal(false);
90
+ readonly changePasswordVisible = signal(false);
91
+
92
+ ActivePropertyChanged = false;
93
+ ActivePropertyId: number = 0;
94
+
95
+ ngOnInit(): void {
96
+ this.loadShortcutMenus();
97
+ }
98
+
99
+ onEmployeeNameModeChange(event: any): void {
100
+ this.employeeNameModeChange.emit(event);
101
+ }
102
+
103
+ getLogoSrc(): string | null {
104
+ if (this.sidebarCollapsed) {
105
+ return this.collapsedLogoUrl || null;
106
+ }
107
+
108
+ return this.logoUrl || null;
109
+ }
110
+
111
+ onLogoClicked(event?: Event): void {
112
+ event?.preventDefault();
113
+ if(this.homeUrl){
114
+ window.location.href = this.homeUrl;
115
+ return;
116
+ }
117
+
118
+ this.logoClick.emit();
119
+ }
120
+
121
+ onHelpClicked(event?: Event): void {
122
+ event?.preventDefault();
123
+ if(this.helpUrl){
124
+ window.open(this.helpUrl, this.helpUrlTarget);
125
+ return;
126
+ }
127
+ this.helpClick.emit();
128
+ }
129
+
130
+ onPropertyChanged(property: PropertyOption): void {
131
+ this.ActivePropertyChanged = !this.ActivePropertyChanged;
132
+ this.ActivePropertyId = property.PropertyId;
133
+ this.propertyChanged.emit(property);
134
+ this.loadShortcutMenus();
135
+ }
136
+
137
+ private loadShortcutMenus(): void {
138
+ if (this.ShowShourtcutMenus && this.ActivePropertyId > 0 && this.systemModule && this.baseUrl) {
139
+ this.menuService.getMicroserviceTopMenusShortcut(this.baseUrl, this.ActivePropertyId, this.systemModule)
140
+ .subscribe({
141
+ next: (menus: any) => this.menuItems = menus ?? [],
142
+ error: () => this.menuItems = []
143
+ });
144
+ } else {
145
+ this.menuItems = [];
146
+ }
147
+ }
148
+ }