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

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 (58) hide show
  1. package/README.md +520 -1
  2. package/fesm2022/skysoftware-co-bayan-core-widgets-ui.mjs +1232 -0
  3. package/fesm2022/skysoftware-co-bayan-core-widgets-ui.mjs.map +1 -0
  4. package/index.d.ts +5 -0
  5. package/lib/shared/common-methods/navigation.utils.d.ts +3 -0
  6. package/lib/shared/menu.dtos.d.ts +90 -0
  7. package/lib/shared/menu.service.d.ts +23 -0
  8. package/lib/top-menu-widget/components/about-dialog-widget/about-dialog-widget.component.d.ts +36 -0
  9. package/lib/top-menu-widget/components/change-password-widget/change-password-widget.component.d.ts +33 -0
  10. package/lib/top-menu-widget/components/global-search-widget/global-search-widget.component.d.ts +58 -0
  11. package/lib/top-menu-widget/components/item-widget/item-widget.component.d.ts +28 -0
  12. package/lib/top-menu-widget/components/notifications-widget/notifications-widget.component.d.ts +22 -0
  13. package/lib/top-menu-widget/components/settings-widget/settings-widget.component.d.ts +73 -0
  14. package/lib/top-menu-widget/components/user-panel-widget/user-panel-widget.component.d.ts +42 -0
  15. package/lib/top-menu-widget/top-menu-widget.component.d.ts +57 -0
  16. package/lib/top-menu-widget/top-menu-widget.models.d.ts +24 -0
  17. package/package.json +48 -59
  18. package/{projects/bayan-core-ui/src/public-api.ts → public-api.d.ts} +10 -14
  19. package/.editorconfig +0 -17
  20. package/.github/copilot/WidgetDevelopmentGuide.md +0 -632
  21. package/.github/copilot/WidgetProjectStructure.md +0 -81
  22. package/.github/copilot/git.md +0 -176
  23. package/.github/copilot/guideline.md +0 -466
  24. package/.github/copilot-instructions.md +0 -697
  25. package/.github/prompts/As world class developer, create unit tests for.prompt.md +0 -7
  26. package/Web.config +0 -7
  27. package/angular.json +0 -43
  28. package/projects/bayan-core-ui/README.md +0 -522
  29. package/projects/bayan-core-ui/ng-package.json +0 -7
  30. package/projects/bayan-core-ui/package.json +0 -36
  31. package/projects/bayan-core-ui/src/assets/i18n/ar.json +0 -725
  32. package/projects/bayan-core-ui/src/assets/i18n/en.json +0 -683
  33. package/projects/bayan-core-ui/src/assets/i18n/fr.json +0 -687
  34. package/projects/bayan-core-ui/src/lib/shared/common-methods/navigation.utils.ts +0 -21
  35. package/projects/bayan-core-ui/src/lib/shared/menu.dtos.ts +0 -107
  36. package/projects/bayan-core-ui/src/lib/shared/menu.service.ts +0 -157
  37. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/about-dialog-widget/about-dialog-widget.component.html +0 -37
  38. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/about-dialog-widget/about-dialog-widget.component.ts +0 -68
  39. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/change-password-widget/change-password-widget.component.html +0 -56
  40. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/change-password-widget/change-password-widget.component.ts +0 -158
  41. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/global-search-widget/global-search-widget.component.html +0 -39
  42. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/global-search-widget/global-search-widget.component.ts +0 -152
  43. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/item-widget/item-widget.component.html +0 -39
  44. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/item-widget/item-widget.component.ts +0 -80
  45. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/notifications-widget/notifications-widget.component.html +0 -10
  46. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/notifications-widget/notifications-widget.component.ts +0 -89
  47. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/settings-widget/settings-widget.component.html +0 -111
  48. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/settings-widget/settings-widget.component.ts +0 -235
  49. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/user-panel-widget/user-panel-widget.component.html +0 -54
  50. package/projects/bayan-core-ui/src/lib/top-menu-widget/components/user-panel-widget/user-panel-widget.component.ts +0 -140
  51. package/projects/bayan-core-ui/src/lib/top-menu-widget/top-menu-widget.component.html +0 -107
  52. package/projects/bayan-core-ui/src/lib/top-menu-widget/top-menu-widget.component.ts +0 -164
  53. package/projects/bayan-core-ui/src/lib/top-menu-widget/top-menu-widget.models.ts +0 -29
  54. package/projects/bayan-core-ui/src/lib/top-menu-widget/top-menu-widget.styles.css +0 -1378
  55. package/projects/bayan-core-ui/tsconfig.lib.json +0 -16
  56. package/projects/bayan-core-ui/tsconfig.lib.prod.json +0 -9
  57. package/projects/bayan-core-ui/tsconfig.spec.json +0 -13
  58. package/tsconfig.json +0 -40
@@ -1,21 +0,0 @@
1
- export function resolveUrl(baseUrl: string | null | undefined, url: string | null | undefined): string | null {
2
- if (!url) {
3
- return null;
4
- }
5
-
6
- return baseUrl ? joinUrl(baseUrl, url) : url;
7
- }
8
-
9
- export function isExternalNavigation(baseUrl: string | null | undefined, url: string): boolean {
10
- return isAbsoluteUrl(url) || (!!baseUrl && isAbsoluteUrl(baseUrl));
11
- }
12
-
13
- export function joinUrl(baseUrl: string, url: string): string {
14
- const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
15
- const normalizedUrl = url.startsWith('/') ? url : `/${url}`;
16
- return `${normalizedBaseUrl}${normalizedUrl}`;
17
- }
18
-
19
- function isAbsoluteUrl(url: string): boolean {
20
- return /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(url);
21
- }
@@ -1,107 +0,0 @@
1
- export interface ApiEnvelope<T> {
2
- ResponseData: T;
3
- ApiVersion: number;
4
- }
5
-
6
- export interface TopMenuShortcut {
7
- MenuName: string;
8
- MenuUrl: string | null;
9
- Children: TopMenuShortcut[];
10
- }
11
-
12
- export interface SystemMenu {
13
- MenuName: string;
14
- MenuUrl: string | null;
15
- IconClass: string | null;
16
- Expanded: boolean;
17
- Children: SystemMenu[];
18
- }
19
-
20
- export interface GlobalSearchMenu {
21
- MenuTitle: string;
22
- MenuSubTitle: string;
23
- IconClass: string;
24
- MenuUrl: string;
25
- IsTranslatable: boolean;
26
- }
27
-
28
- export interface PropertyOption {
29
- PropertyId: number;
30
- PropertyName: string;
31
- }
32
-
33
- export interface UserPanel {
34
- UserDisplayName: string;
35
- ActivePropertyId: number;
36
- ActivePropertyName: string;
37
- PhotoPath: string | null;
38
- NameInitials: string;
39
- IsSSOLogin: boolean;
40
- Properties: PropertyOption[];
41
- }
42
-
43
- export interface SwitchPropertyRequest {
44
- PropertyId: number;
45
- }
46
-
47
- export interface SwitchPropertyResult {
48
- PropertyId: number;
49
- }
50
-
51
- export enum EmployeeNamesModeOption {
52
- ShortNames = 1,
53
- StandardNames = 2,
54
- FullNames = 3,
55
- }
56
-
57
- export interface AppFramePreferences {
58
- UseAlternateNames: boolean;
59
- DisplayAlternateNames: boolean;
60
- EmployeeNamesMode: EmployeeNamesModeOption;
61
- VersionNumber: string;
62
- }
63
-
64
- export interface SetDisplayAlternateNamesRequest {
65
- DisplayAlternateNames: boolean;
66
- }
67
-
68
- export interface SetEmployeeNamesModeRequest {
69
- EmployeeNamesMode: EmployeeNamesModeOption;
70
- }
71
-
72
- export enum BlockableModule {
73
- HumanResources = 4,
74
- Timekeeping = 5,
75
- }
76
-
77
- export interface ModuleBlockState {
78
- IsBlocked: boolean;
79
- UserCanBlockModule: boolean;
80
- }
81
-
82
- export interface BlockReleaseModuleRequest {
83
- Module: BlockableModule;
84
- }
85
-
86
- export interface NotificationsSummary {
87
- TotalNotificationsCount: number;
88
- NotificationsUrl: string;
89
- }
90
-
91
- export interface ChangePasswordRequest {
92
- CurrentPassword: string;
93
- NewPassword: string;
94
- }
95
-
96
- export enum SystemModule {
97
- Corporate = 1,
98
- Cluster = 2,
99
- Setup = 3,
100
- HumanResources = 4,
101
- Timekeeping = 5,
102
- Payroll = 6,
103
- Training = 7,
104
- Workflow = 8,
105
- Appraisal = 9,
106
- BusinessIntelligence = 10,
107
- }
@@ -1,157 +0,0 @@
1
- import { HttpClient, HttpParams } from '@angular/common/http';
2
- import { Injectable, inject } from '@angular/core';
3
- import { catchError, map, Observable, throwError } from 'rxjs';
4
- import {
5
- ApiEnvelope,
6
- AppFramePreferences,
7
- BlockableModule,
8
- BlockReleaseModuleRequest,
9
- ChangePasswordRequest,
10
- GlobalSearchMenu,
11
- ModuleBlockState,
12
- NotificationsSummary,
13
- SetDisplayAlternateNamesRequest,
14
- SetEmployeeNamesModeRequest,
15
- SwitchPropertyRequest,
16
- SwitchPropertyResult,
17
- SystemMenu,
18
- SystemModule,
19
- TopMenuShortcut,
20
- UserPanel,
21
- } from './menu.dtos';
22
-
23
- @Injectable({
24
- providedIn: 'root',
25
- })
26
- export class BayanCoreTopMenuService {
27
- private readonly http = inject(HttpClient);
28
-
29
- private unwrap<T>(obs: Observable<ApiEnvelope<T>>): Observable<T> {
30
- return obs.pipe(
31
- map((env) => {
32
- if (!env.ResponseData) {
33
- throw new Error('No data received');
34
- }
35
-
36
- return env.ResponseData;
37
- }),
38
- catchError((error) => throwError(() => error)),
39
- );
40
- }
41
-
42
- private getBaseUrl(baseUrl: string): string {
43
- let url = baseUrl.replace('/api','');
44
- return `${url.replace(/\/$/, '')}/api/app-frame`;
45
- }
46
-
47
- getMicroserviceMenusByProperty(
48
- baseUrl: string,
49
- propertyId: number | string,
50
- systemModule: SystemModule,
51
- ): Observable<SystemMenu[]> {
52
- const params = new HttpParams()
53
- .set('PropertyId', propertyId)
54
- .set('SystemModule', systemModule);
55
-
56
- return this.unwrap(
57
- this.http.get<ApiEnvelope<SystemMenu[]>>(`${this.getBaseUrl(baseUrl)}/left-menu`, { params }),
58
- );
59
- }
60
-
61
- getMicroserviceTopMenusShortcut(
62
- baseUrl: string,
63
- propertyId: number | string,
64
- systemModule: SystemModule,
65
- ): Observable<TopMenuShortcut[]> {
66
- const params = new HttpParams()
67
- .set('PropertyId', propertyId)
68
- .set('SystemModule', systemModule);
69
-
70
- return this.unwrap(
71
- this.http.get<ApiEnvelope<TopMenuShortcut[]>>(`${this.getBaseUrl(baseUrl)}/top-shortcuts`, {
72
- params,
73
- }),
74
- );
75
- }
76
-
77
- getGlobalSearchMenus(baseUrl: string, propertyId?: number): Observable<GlobalSearchMenu[]> {
78
- let params = new HttpParams();
79
-
80
- if (propertyId != null) {
81
- params = params.set('PropertyId', propertyId);
82
- }
83
-
84
- return this.unwrap(
85
- this.http.get<ApiEnvelope<GlobalSearchMenu[]>>(
86
- `${this.getBaseUrl(baseUrl)}/global-search-menus`,
87
- { params },
88
- ),
89
- );
90
- }
91
-
92
- getUserPanel(baseUrl: string): Observable<UserPanel> {
93
- return this.unwrap(this.http.get<ApiEnvelope<UserPanel>>(`${this.getBaseUrl(baseUrl)}/user-panel`));
94
- }
95
-
96
- switchProperty(baseUrl: string, request: SwitchPropertyRequest): Observable<SwitchPropertyResult> {
97
- return this.unwrap(
98
- this.http.post<ApiEnvelope<SwitchPropertyResult>>(
99
- `${this.getBaseUrl(baseUrl)}/switch-property`,
100
- request,
101
- ),
102
- );
103
- }
104
-
105
- getPreferences(baseUrl: string): Observable<AppFramePreferences> {
106
- return this.unwrap(
107
- this.http.get<ApiEnvelope<AppFramePreferences>>(`${this.getBaseUrl(baseUrl)}/preferences`),
108
- );
109
- }
110
-
111
- setDisplayAlternateNames(
112
- baseUrl: string,
113
- request: SetDisplayAlternateNamesRequest,
114
- ): Observable<void> {
115
- return this.http.post<void>(`${this.getBaseUrl(baseUrl)}/preferences/alternate-names`, request);
116
- }
117
-
118
- setEmployeeNamesMode(baseUrl: string, request: SetEmployeeNamesModeRequest): Observable<void> {
119
- return this.http.post<void>(
120
- `${this.getBaseUrl(baseUrl)}/preferences/employee-names-mode`,
121
- request,
122
- );
123
- }
124
-
125
- getModuleBlockState(
126
- baseUrl: string,
127
- systemModule: SystemModule | BlockableModule,
128
- ): Observable<ModuleBlockState> {
129
- const params = new HttpParams().set('SystemModule', systemModule);
130
-
131
- return this.unwrap(
132
- this.http.get<ApiEnvelope<ModuleBlockState>>(`${this.getBaseUrl(baseUrl)}/module-block-state`, {
133
- params,
134
- }),
135
- );
136
- }
137
-
138
- blockModule(baseUrl: string, request: BlockReleaseModuleRequest): Observable<void> {
139
- return this.http.post<void>(`${this.getBaseUrl(baseUrl)}/block-module`, request);
140
- }
141
-
142
- releaseModule(baseUrl: string, request: BlockReleaseModuleRequest): Observable<void> {
143
- return this.http.post<void>(`${this.getBaseUrl(baseUrl)}/release-module`, request);
144
- }
145
-
146
- getNotificationsSummary(baseUrl: string): Observable<NotificationsSummary> {
147
- return this.unwrap(
148
- this.http.get<ApiEnvelope<NotificationsSummary>>(
149
- `${this.getBaseUrl(baseUrl)}/notifications-summary`,
150
- ),
151
- );
152
- }
153
-
154
- changePassword(baseUrl: string, request: ChangePasswordRequest): Observable<boolean> {
155
- return this.http.post<boolean>(`${this.getBaseUrl(baseUrl)}/change-password`, request);
156
- }
157
- }
@@ -1,37 +0,0 @@
1
- @if (visible) {
2
- <div [class]="backdropClass" (click)="onBackdropClick($event)">
3
- <div [class]="modalClass" role="dialog" aria-labelledby="topMenuAboutDialogTitle" aria-modal="true">
4
- <div [class]="headerClass">
5
- <h4 [class]="titleClass" id="topMenuAboutDialogTitle">{{ 'AboutSkyBayan' | translate }}</h4>
6
- <button type="button" [class]="closeBtnClass" (click)="closeDialog()" [attr.aria-label]="(config.closeButtonLabel || 'Close') | translate">
7
- <span aria-hidden="true">&times;</span>
8
- </button>
9
- </div>
10
-
11
- <div [class]="bodyClass">
12
- <div class="row align-items-start">
13
- <div class="col-4">
14
- @if (config.logoUrl) {
15
- <img [src]="config.logoUrl" alt="Logo" [class]="logoClass">
16
- }
17
- </div>
18
- <div class="col-8">
19
- <h3 [class]="productNameClass">{{ (config.title || 'AboutSkyBayan') | translate }}</h3>
20
- <p [class]="versionTextClass">{{ (config.versionLabel || 'Version') | translate }} {{ config.version || '' }}</p>
21
- <p [class]="upToDateClass">
22
- <fa-icon [icon]="checkCircleIcon" class="text-info me-1"></fa-icon>
23
- <small class="text-muted">{{ (config.statusLabel || 'SkyBayanUpToDate') | translate }}</small>
24
- </p>
25
- <p [class]="copyrightClass">{{ (config.copyright || '') | translate }}</p>
26
- </div>
27
- </div>
28
- </div>
29
-
30
- <div [class]="actionsClass">
31
- <button type="button" [class]="actionBtnClass" (click)="openLicense()">{{ (config.licenseButtonLabel || 'LicenseInformation') | translate }}</button>
32
- <button type="button" [class]="actionBtnClass" (click)="openReleaseNotes()">{{ (config.releaseNotesButtonLabel || 'ReleaseNotes') | translate }}</button>
33
- <button type="button" [class]="actionBtnClass" (click)="openSupport()">{{ (config.supportButtonLabel || 'TechnicalSupport') | translate }}</button>
34
- </div>
35
- </div>
36
- </div>
37
- }
@@ -1,68 +0,0 @@
1
- import { CommonModule } from '@angular/common';
2
- import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
3
- import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
4
- import { faCheckCircle } from '@fortawesome/pro-solid-svg-icons';
5
- import { TranslatePipe } from '@skysoftware-co/sky-components-ui';
6
- import { TopMenuWidgetAboutDialogConfig } from '../../top-menu-widget.models';
7
-
8
- @Component({
9
- selector: 'bayan-core-about-dialog-widget',
10
- standalone: true,
11
- imports: [CommonModule, FontAwesomeModule, TranslatePipe],
12
- templateUrl: './about-dialog-widget.component.html',
13
- styleUrls: ['../../top-menu-widget.styles.css'],
14
- changeDetection: ChangeDetectionStrategy.OnPush,
15
- })
16
- export class BayanCoreAboutDialogWidgetComponent {
17
-
18
- @Input() baseUrl = '';
19
- @Input() visible = false;
20
- @Input({ required: true }) config!: TopMenuWidgetAboutDialogConfig;
21
- @Input() licenseUrl = '';
22
- @Input() releaseNotesUrl = '';
23
- @Input() supportUrl = 'https://skyits.com/contact';
24
-
25
- // CSS class attributes as @Input with defaults
26
- @Input() backdropClass: string = 'about-backdrop';
27
- @Input() modalClass: string = 'about-modal';
28
- @Input() headerClass: string = 'about-modal-header';
29
- @Input() titleClass: string = 'about-modal-title';
30
- @Input() closeBtnClass: string = 'about-close-btn';
31
- @Input() bodyClass: string = 'about-modal-body';
32
- @Input() logoClass: string = 'about-logo';
33
- @Input() productNameClass: string = 'about-product-name';
34
- @Input() versionTextClass: string = 'about-version-text';
35
- @Input() upToDateClass: string = 'about-up-to-date';
36
- @Input() copyrightClass: string = 'about-copyright';
37
- @Input() actionsClass: string = 'about-modal-actions';
38
- @Input() actionBtnClass: string = 'about-action-btn';
39
-
40
- @Output() visibleChange = new EventEmitter<boolean>();
41
- @Output() licenseClick = new EventEmitter<void>();
42
- @Output() releaseNotesClick = new EventEmitter<void>();
43
- @Output() supportClick = new EventEmitter<void>();
44
-
45
- readonly checkCircleIcon = faCheckCircle;
46
-
47
- onBackdropClick(event: MouseEvent): void {
48
- if ((event.target as HTMLElement).classList.contains('about-backdrop')) {
49
- this.closeDialog();
50
- }
51
- }
52
-
53
- closeDialog(): void {
54
- this.visibleChange.emit(false);
55
- }
56
-
57
- openLicense() {
58
- window.open(this.licenseUrl, '_blank');
59
- }
60
-
61
- openReleaseNotes() {
62
- window.open(this.releaseNotesUrl, '_blank');
63
- }
64
-
65
- openSupport() {
66
- window.open(this.supportUrl, '_blank');
67
- }
68
- }
@@ -1,56 +0,0 @@
1
- <dx-popup
2
- [visible]="visible"
3
- (onHiding)="closeDialog()"
4
- [title]="config.title | translate"
5
- [showCloseButton]="true"
6
- [width]="450"
7
- [height]="'auto'"
8
- [dragEnabled]="false"
9
- [shading]="true"
10
- shadingColor="rgba(0,0,0,0.4)">
11
- <div *dxTemplate="let data of 'content'">
12
- <dx-form
13
- #changePasswordForm
14
- [formData]="formData"
15
- labelLocation="top"
16
- [showColonAfterLabel]="false"
17
- class="mb-3 mx-2">
18
- <dxi-item
19
- dataField="currentPassword"
20
- editorType="dxTextBox"
21
- [editorOptions]="getCurrentPasswordEditorOptions()">
22
- <dxo-label [text]="config.currentPasswordLabel | translate"></dxo-label>
23
- <dxi-validation-rule type="required"></dxi-validation-rule>
24
- </dxi-item>
25
-
26
- <dxi-item
27
- dataField="newPassword"
28
- editorType="dxTextBox"
29
- [editorOptions]="getNewPasswordEditorOptions()">
30
- <dxo-label [text]="config.newPasswordLabel | translate"></dxo-label>
31
- <dxi-validation-rule type="required"></dxi-validation-rule>
32
- </dxi-item>
33
-
34
- <dxi-item
35
- dataField="confirmNewPassword"
36
- editorType="dxTextBox"
37
- [editorOptions]="getConfirmPasswordEditorOptions()">
38
- <dxo-label [text]="config.confirmNewPasswordLabel | translate"></dxo-label>
39
- <dxi-validation-rule type="required"></dxi-validation-rule>
40
- <dxi-validation-rule
41
- type="compare"
42
- [comparisonTarget]="passwordComparison">
43
- </dxi-validation-rule>
44
- </dxi-item>
45
- </dx-form>
46
-
47
- <sky-footer-actions
48
- [primaryButtonText]="config.primaryButtonText | translate"
49
- [showSecondaryButton]="false"
50
- [isLoading]="isSubmitting"
51
- [disabledPrimaryButton]="isSubmitting || !isChangePasswordValid()"
52
- (PrimaryButtonClick)="onSaveButtonClick()"
53
- [errorMessage]="errorMessage">
54
- </sky-footer-actions>
55
- </div>
56
- </dx-popup>
@@ -1,158 +0,0 @@
1
- import { CommonModule } from '@angular/common';
2
- import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewChild, signal, WritableSignal, inject } from '@angular/core';
3
- import { DxFormComponent, DxFormModule, DxPopupModule } from 'devextreme-angular';
4
- import { SkyFooterActionsComponent, TranslatePipe } from '@skysoftware-co/sky-components-ui';
5
- import {
6
- TopMenuWidgetChangePasswordDialogConfig,
7
- TopMenuWidgetChangePasswordPayload,
8
- } from '../../top-menu-widget.models';
9
- import { BayanCoreTopMenuService } from '../../../shared/menu.service';
10
- import { SkyAlertToastService } from '@skysoftware-co/sky-components-ui';
11
- // import { SkyAlertType } from '@skysoftware-co/sky-components-ui/lib/constants/constants';
12
-
13
-
14
- @Component({
15
- selector: 'bayan-core-change-password-widget',
16
- standalone: true,
17
- imports: [CommonModule, DxPopupModule, DxFormModule, SkyFooterActionsComponent, TranslatePipe],
18
- templateUrl: './change-password-widget.component.html',
19
- changeDetection: ChangeDetectionStrategy.OnPush,
20
- })
21
- export class BayanCoreChangePasswordWidgetComponent {
22
- private readonly menuService = inject(BayanCoreTopMenuService);
23
- private readonly alertToastService = inject(SkyAlertToastService);
24
- private readonly translate = inject(TranslatePipe);
25
-
26
- @Input() baseUrl = '';
27
- @Input() visible = false;
28
- @Input({ required: true }) config!: TopMenuWidgetChangePasswordDialogConfig;
29
- @Input() isSubmitting = false;
30
- @Output() visibleChange = new EventEmitter<boolean>();
31
-
32
- @ViewChild('changePasswordForm') changePasswordForm?: DxFormComponent;
33
-
34
- readonly currentPasswordMode = signal<'password' | 'text'>('password');
35
- readonly newPasswordMode = signal<'password' | 'text'>('password');
36
- readonly confirmNewPasswordMode = signal<'password' | 'text'>('password');
37
-
38
- formData: TopMenuWidgetChangePasswordPayload = {
39
- currentPassword: '',
40
- newPassword: '',
41
- confirmNewPassword: '',
42
- };
43
- errorMessage: WritableSignal<string> = signal('');
44
-
45
- closeDialog(): void {
46
- this.visible = false;
47
- this.visibleChange.emit(false);
48
- this.resetForm();
49
- this.errorMessage.set('');
50
- }
51
-
52
- resetForm(): void {
53
- this.formData = {
54
- currentPassword: '',
55
- newPassword: '',
56
- confirmNewPassword: '',
57
- };
58
- this.errorMessage.set('');
59
- }
60
-
61
- onSaveButtonClick(): void {
62
- const isValid = this.changePasswordForm?.instance.validate().isValid ?? false;
63
- if (!isValid) {
64
- return;
65
- }
66
- this.isSubmitting = true;
67
- this.menuService.changePassword(this.baseUrl, {
68
- CurrentPassword: this.formData.currentPassword,
69
- NewPassword: this.formData.newPassword
70
- }).subscribe({
71
- next: () => {
72
- this.isSubmitting = false;
73
- this.closeDialog();
74
- this.showAlert('PasswordChangedSuccessfully');
75
- },
76
- error: (e: any) => {
77
- this.isSubmitting = false;
78
- this.errorMessage.set(this.translate.transform("FailedToChangePassword"));
79
- // Optionally show error notification here
80
- }
81
- });
82
- }
83
- togglePasswordMode(field: 'currentPasswordMode' | 'newPasswordMode' | 'confirmNewPasswordMode'): void {
84
- const current = this[field]();
85
- this[field].set(current === 'text' ? 'password' : 'text');
86
- }
87
-
88
- updateField(field: keyof TopMenuWidgetChangePasswordPayload, value: string): void {
89
- this.formData = {
90
- ...this.formData,
91
- [field]: value,
92
- };
93
- }
94
-
95
- isChangePasswordValid(): boolean {
96
- return !!this.formData.currentPassword && !!this.formData.newPassword && !!this.formData.confirmNewPassword;
97
- }
98
-
99
- getCurrentPasswordEditorOptions(): object {
100
- return {
101
- maxLength: 256,
102
- disabled: this.isSubmitting,
103
- mode: this.currentPasswordMode(),
104
- onValueChanged: (event: { value?: string }) => this.updateField('currentPassword', event.value ?? ''),
105
- buttons: [{
106
- name: 'password',
107
- location: 'after',
108
- options: {
109
- stylingMode: 'text',
110
- icon: this.currentPasswordMode() === 'text' ? 'eyeopen' : 'eyeclose',
111
- onClick: () => this.togglePasswordMode('currentPasswordMode'),
112
- },
113
- }],
114
- };
115
- }
116
-
117
- getNewPasswordEditorOptions(): object {
118
- return {
119
- maxLength: 256,
120
- disabled: this.isSubmitting,
121
- mode: this.newPasswordMode(),
122
- onValueChanged: (event: { value?: string }) => this.updateField('newPassword', event.value ?? ''),
123
- buttons: [{
124
- name: 'password',
125
- location: 'after',
126
- options: {
127
- stylingMode: 'text',
128
- icon: this.newPasswordMode() === 'text' ? 'eyeopen' : 'eyeclose',
129
- onClick: () => this.togglePasswordMode('newPasswordMode'),
130
- },
131
- }],
132
- };
133
- }
134
-
135
- getConfirmPasswordEditorOptions(): object {
136
- return {
137
- maxLength: 256,
138
- disabled: this.isSubmitting,
139
- mode: this.confirmNewPasswordMode(),
140
- onValueChanged: (event: { value?: string }) => this.updateField('confirmNewPassword', event.value ?? ''),
141
- buttons: [{
142
- name: 'password',
143
- location: 'after',
144
- options: {
145
- stylingMode: 'text',
146
- icon: this.confirmNewPasswordMode() === 'text' ? 'eyeopen' : 'eyeclose',
147
- onClick: () => this.togglePasswordMode('confirmNewPasswordMode'),
148
- },
149
- }],
150
- };
151
- }
152
-
153
- passwordComparison = (): string => this.formData.newPassword;
154
-
155
- showAlert(message: string, type: string = 'success') {
156
- this.alertToastService.toastInformation(message, type as any);
157
- }
158
- }
@@ -1,39 +0,0 @@
1
- <div [class]="searchWrapperClass">
2
- <dx-autocomplete
3
- #searchAutoComplete
4
- [placeholder]="placeholder | translate"
5
- [dataSource]="dataSource"
6
- valueExpr="menuSubTitle"
7
- [searchExpr]="['menuSubTitle']"
8
- [showClearButton]="false"
9
- [showDropDownButton]="false"
10
- [searchMode]="searchMode"
11
- [width]="'100%'"
12
- [stylingMode]="stylingMode"
13
- [wrapItemText]="true"
14
- [searchTimeout]="100"
15
- (onInput)="onInput($event)"
16
- (onEnterKey)="onEnterKey($event)">
17
- <div class="w-100" *dxTemplate="let item of 'item'">
18
- <a
19
- [class]="searchItemClass"
20
- href="{{item.MenuUrl}}" >
21
- <div [class]="searchItemTitleClass">
22
- <fa-icon [icon]="getIconForClass(item.iconClass)" [class]="iconClass"></fa-icon>
23
- @if (item.isTranslatable) {
24
- {{ item.menuTitle | translate }}
25
- } @else {
26
- {{ item.menuTitle }}
27
- }
28
- </div>
29
- <div [class]="searchItemSubtitleClass">
30
- @if (item.isTranslatable) {
31
- {{ item.menuSubTitle | translate }}
32
- } @else {
33
- {{ item.menuSubTitle }}
34
- }
35
- </div>
36
- </a>
37
- </div>
38
- </dx-autocomplete>
39
- </div>