@flusys/ng-auth 3.0.0-rc → 3.0.1

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.
@@ -1,33 +1,34 @@
1
- import * as i1 from '@angular/common/http';
2
1
  import { HttpClient } from '@angular/common/http';
3
2
  import * as i0 from '@angular/core';
4
- import { inject, Injectable, signal, computed, effect, PLATFORM_ID, ChangeDetectionStrategy, Component, untracked, DestroyRef, input, output, makeStateKey, TransferState } from '@angular/core';
5
- import { APP_CONFIG, getServiceUrl, isCompanyFeatureEnabled, isFeatureEnabled, getPermissionMode } from '@flusys/ng-core';
3
+ import { inject, Injectable, signal, computed, effect, PLATFORM_ID, InjectionToken, ChangeDetectionStrategy, Component, untracked, DestroyRef, input, Injector, output, makeStateKey, TransferState } from '@angular/core';
4
+ import { APP_CONFIG, getServiceUrl, isCompanyFeatureEnabled, isEmailFeatureEnabled, isSignUpEnabled, isFeatureEnabled, getPermissionMode, getDefaultCompanySlug, getDefaultBranchSlug } from '@flusys/ng-core';
6
5
  import * as i2$1 from '@angular/router';
7
6
  import { Router, RouterOutlet, RouterLink, RouterLinkActive, ActivatedRoute } from '@angular/router';
8
- import { of, timeout, switchMap, map, tap, catchError, shareReplay, finalize, BehaviorSubject, throwError, filter, take, firstValueFrom } from 'rxjs';
7
+ import { of, timeout, switchMap, map, tap, catchError, shareReplay, finalize, BehaviorSubject, throwError, filter, take, forkJoin, firstValueFrom } from 'rxjs';
9
8
  import { PlatformService, ApiResourceService, CookieService, permissionGuard, USER_PERMISSIONS, COMPANY_PERMISSIONS, BRANCH_PERMISSIONS, USER_PROVIDER, COMPANY_API_PROVIDER, USER_PERMISSION_PROVIDER, AUTH_STATE_PROVIDER, PermissionValidatorService, AngularModule, PrimeModule, HasPermissionDirective, FileUrlService, PROFILE_UPLOAD_PROVIDER, PROFILE_PERMISSION_PROVIDER, FileUploaderComponent } from '@flusys/ng-shared';
10
9
  import { map as map$1, catchError as catchError$1, tap as tap$1 } from 'rxjs/operators';
10
+ import * as i1$1 from '@angular/common';
11
11
  import { isPlatformBrowser, CommonModule } from '@angular/common';
12
12
  import { MessageService, ConfirmationService } from 'primeng/api';
13
13
  import { LAYOUT_AUTH_STATE, LAYOUT_AUTH_API, AppFloatingConfigurator } from '@flusys/ng-layout';
14
14
  import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
15
15
  import { form, required, FormField, email, minLength } from '@angular/forms/signals';
16
- import * as i1$1 from '@angular/forms';
16
+ import * as i1 from '@angular/forms';
17
17
  import * as i2 from 'primeng/button';
18
18
  import * as i3 from 'primeng/card';
19
19
  import * as i4 from 'primeng/inputtext';
20
- import * as i4$2 from 'primeng/tag';
20
+ import * as i6 from 'primeng/tag';
21
21
  import { TagModule } from 'primeng/tag';
22
22
  import * as i4$1 from 'primeng/select';
23
- import * as i3$1 from 'primeng/table';
24
- import * as i5 from 'primeng/tooltip';
25
- import * as i2$2 from 'primeng/avatar';
26
- import * as i5$1 from 'primeng/password';
27
- import * as i6 from 'primeng/skeleton';
28
- import * as i4$3 from 'primeng/dialog';
23
+ import * as i5 from 'primeng/table';
24
+ import * as i7 from 'primeng/tooltip';
25
+ import * as i3$1 from 'primeng/avatar';
26
+ import * as i6$1 from 'primeng/password';
27
+ import * as i7$1 from 'primeng/skeleton';
28
+ import * as i9 from 'primeng/textarea';
29
+ import * as i4$2 from 'primeng/dialog';
29
30
  import { DialogModule } from 'primeng/dialog';
30
- import * as i5$2 from 'primeng/progressspinner';
31
+ import * as i5$1 from 'primeng/progressspinner';
31
32
  import { ProgressSpinnerModule } from 'primeng/progressspinner';
32
33
  import * as i3$2 from 'primeng/checkbox';
33
34
 
@@ -144,10 +145,10 @@ class AuthApiService {
144
145
  token,
145
146
  });
146
147
  }
147
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
148
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthApiService, providedIn: 'root' });
148
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
149
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthApiService, providedIn: 'root' });
149
150
  }
150
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthApiService, decorators: [{
151
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthApiService, decorators: [{
151
152
  type: Injectable,
152
153
  args: [{ providedIn: 'root' }]
153
154
  }], ctorParameters: () => [] });
@@ -347,10 +348,10 @@ class AuthStateService {
347
348
  if (!this.platform.isServer)
348
349
  localStorage.removeItem(key);
349
350
  }
350
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
351
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthStateService, providedIn: 'root' });
351
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
352
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthStateService, providedIn: 'root' });
352
353
  }
353
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthStateService, decorators: [{
354
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthStateService, decorators: [{
354
355
  type: Injectable,
355
356
  args: [{ providedIn: 'root' }]
356
357
  }], ctorParameters: () => [] });
@@ -457,10 +458,10 @@ class AuthInitService {
457
458
  }));
458
459
  return this.initializationCache$;
459
460
  }
460
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthInitService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
461
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthInitService, providedIn: 'root' });
461
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthInitService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
462
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthInitService, providedIn: 'root' });
462
463
  }
463
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthInitService, decorators: [{
464
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthInitService, decorators: [{
464
465
  type: Injectable,
465
466
  args: [{ providedIn: 'root' }]
466
467
  }] });
@@ -471,8 +472,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
471
472
  */
472
473
  class BranchApiService extends ApiResourceService {
473
474
  _currentCompanyId = signal(null, ...(ngDevMode ? [{ debugName: "_currentCompanyId" }] : []));
474
- constructor(http) {
475
- super('administration/branch', http);
475
+ constructor() {
476
+ super('branch', inject(HttpClient), 'administration');
476
477
  }
477
478
  setCurrentCompanyId(companyId) {
478
479
  this._currentCompanyId.set(companyId);
@@ -481,29 +482,29 @@ class BranchApiService extends ApiResourceService {
481
482
  this.setCurrentCompanyId(companyId);
482
483
  this.fetchList(search, { filter: { companyId } });
483
484
  }
484
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BranchApiService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
485
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BranchApiService, providedIn: 'root' });
485
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: BranchApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
486
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: BranchApiService, providedIn: 'root' });
486
487
  }
487
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BranchApiService, decorators: [{
488
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: BranchApiService, decorators: [{
488
489
  type: Injectable,
489
490
  args: [{ providedIn: 'root' }]
490
- }], ctorParameters: () => [{ type: i1.HttpClient }] });
491
+ }], ctorParameters: () => [] });
491
492
 
492
493
  /**
493
494
  * Company API Service
494
495
  * Signal-based service for company CRUD operations
495
496
  */
496
497
  class CompanyApiService extends ApiResourceService {
497
- constructor(http) {
498
- super('administration/company', http);
498
+ constructor() {
499
+ super('company', inject(HttpClient), 'administration');
499
500
  }
500
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CompanyApiService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
501
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CompanyApiService, providedIn: 'root' });
501
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CompanyApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
502
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CompanyApiService, providedIn: 'root' });
502
503
  }
503
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CompanyApiService, decorators: [{
504
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CompanyApiService, decorators: [{
504
505
  type: Injectable,
505
506
  args: [{ providedIn: 'root' }]
506
- }], ctorParameters: () => [{ type: i1.HttpClient }] });
507
+ }], ctorParameters: () => [] });
507
508
 
508
509
  /**
509
510
  * Token Refresh State Service
@@ -526,10 +527,10 @@ class TokenRefreshStateService {
526
527
  failRefresh() {
527
528
  this._isRefreshing.set(false);
528
529
  }
529
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TokenRefreshStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
530
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TokenRefreshStateService, providedIn: 'root' });
530
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: TokenRefreshStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
531
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: TokenRefreshStateService, providedIn: 'root' });
531
532
  }
532
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TokenRefreshStateService, decorators: [{
533
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: TokenRefreshStateService, decorators: [{
533
534
  type: Injectable,
534
535
  args: [{ providedIn: 'root' }]
535
536
  }] });
@@ -539,28 +540,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
539
540
  * Signal-based service for user CRUD operations
540
541
  */
541
542
  class UserApiService extends ApiResourceService {
542
- constructor(http) {
543
- super('administration/users', http);
543
+ constructor() {
544
+ super('users', inject(HttpClient), 'administration');
544
545
  }
545
546
  updateProfile(data) {
546
547
  return this.http.post(`${this.baseUrl}/profile`, data);
547
548
  }
548
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserApiService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
549
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserApiService, providedIn: 'root' });
549
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
550
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserApiService, providedIn: 'root' });
550
551
  }
551
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserApiService, decorators: [{
552
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserApiService, decorators: [{
552
553
  type: Injectable,
553
554
  args: [{ providedIn: 'root' }]
554
- }], ctorParameters: () => [{ type: i1.HttpClient }] });
555
+ }], ctorParameters: () => [] });
555
556
 
556
557
  /**
557
558
  * User Permission API Service
558
559
  * Handles user-company and user-branch permission assignments.
560
+ * Endpoint: POST /administration/permissions/*
559
561
  */
560
562
  class UserPermissionApiService {
561
563
  appConfig = inject(APP_CONFIG);
562
564
  http = inject(HttpClient);
563
- baseUrl = this.appConfig.apiBaseUrl + '/administration/permissions';
565
+ baseUrl = `${getServiceUrl(this.appConfig, 'administration')}/permissions`;
564
566
  // Company Permissions
565
567
  assignUserCompanies(data) {
566
568
  return this.http.post(`${this.baseUrl}/user-company/assign`, data);
@@ -590,10 +592,10 @@ class UserPermissionApiService {
590
592
  ...(companyId && { companyId }),
591
593
  });
592
594
  }
593
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserPermissionApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
594
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserPermissionApiService, providedIn: 'root' });
595
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserPermissionApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
596
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserPermissionApiService, providedIn: 'root' });
595
597
  }
596
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserPermissionApiService, decorators: [{
598
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserPermissionApiService, decorators: [{
597
599
  type: Injectable,
598
600
  args: [{ providedIn: 'root' }]
599
601
  }] });
@@ -672,6 +674,22 @@ const companyFeatureGuard = () => {
672
674
  return router.createUrlTree(['/']);
673
675
  return true;
674
676
  };
677
+ /** Protects routes requiring email feature to be enabled */
678
+ const emailFeatureGuard = () => {
679
+ const router = inject(Router);
680
+ const appConfig = inject(APP_CONFIG);
681
+ if (!appConfig.services.email?.enabled)
682
+ return router.createUrlTree([AUTH_ENDPOINTS.LOGIN]);
683
+ return true;
684
+ };
685
+ /** Protects routes requiring sign-up feature to be enabled */
686
+ const signUpFeatureGuard = () => {
687
+ const router = inject(Router);
688
+ const appConfig = inject(APP_CONFIG);
689
+ if (appConfig.enableSignUp === false)
690
+ return router.createUrlTree([AUTH_ENDPOINTS.LOGIN]);
691
+ return true;
692
+ };
675
693
 
676
694
  /** Endpoints that need withCredentials for cookie handling */
677
695
  const COOKIE_ENDPOINTS = [
@@ -789,21 +807,22 @@ const AUTH_ROUTES = [
789
807
  {
790
808
  path: 'register',
791
809
  loadComponent: () => Promise.resolve().then(function () { return registerPage_component; }).then((m) => m.RegisterPageComponent),
792
- canActivate: [guestGuard],
810
+ canActivate: [signUpFeatureGuard, guestGuard],
793
811
  },
794
812
  {
795
813
  path: 'forgot-password',
796
814
  loadComponent: () => Promise.resolve().then(function () { return forgotPasswordPage_component; }).then((m) => m.ForgotPasswordPageComponent),
797
- canActivate: [guestGuard],
815
+ canActivate: [emailFeatureGuard, guestGuard],
798
816
  },
799
817
  {
800
818
  path: 'reset-password',
801
819
  loadComponent: () => Promise.resolve().then(function () { return resetPasswordPage_component; }).then((m) => m.ResetPasswordPageComponent),
802
- canActivate: [guestGuard],
820
+ canActivate: [emailFeatureGuard, guestGuard],
803
821
  },
804
822
  {
805
823
  path: 'verify-email',
806
824
  loadComponent: () => Promise.resolve().then(function () { return verifyEmailPage_component; }).then((m) => m.VerifyEmailPageComponent),
825
+ canActivate: [emailFeatureGuard],
807
826
  },
808
827
  {
809
828
  path: '',
@@ -953,10 +972,10 @@ class AuthLayoutStateAdapter {
953
972
  }
954
973
  return null;
955
974
  }, ...(ngDevMode ? [{ debugName: "loginUserData" }] : []));
956
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthLayoutStateAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
957
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthLayoutStateAdapter, providedIn: 'root' });
975
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthLayoutStateAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
976
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthLayoutStateAdapter, providedIn: 'root' });
958
977
  }
959
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthLayoutStateAdapter, decorators: [{
978
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthLayoutStateAdapter, decorators: [{
960
979
  type: Injectable,
961
980
  args: [{ providedIn: 'root' }]
962
981
  }] });
@@ -1010,10 +1029,10 @@ class AuthLayoutApiAdapter {
1010
1029
  slug: permission.branchSlug ?? '',
1011
1030
  }))));
1012
1031
  }
1013
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthLayoutApiAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1014
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthLayoutApiAdapter, providedIn: 'root' });
1032
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthLayoutApiAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1033
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthLayoutApiAdapter, providedIn: 'root' });
1015
1034
  }
1016
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthLayoutApiAdapter, decorators: [{
1035
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthLayoutApiAdapter, decorators: [{
1017
1036
  type: Injectable,
1018
1037
  args: [{ providedIn: 'root' }]
1019
1038
  }] });
@@ -1059,10 +1078,10 @@ class AuthUserProviderAdapter {
1059
1078
  meta: response.meta,
1060
1079
  })));
1061
1080
  }
1062
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthUserProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1063
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthUserProviderAdapter });
1081
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthUserProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1082
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthUserProviderAdapter });
1064
1083
  }
1065
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthUserProviderAdapter, decorators: [{
1084
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthUserProviderAdapter, decorators: [{
1066
1085
  type: Injectable
1067
1086
  }] });
1068
1087
  // =============================================================================
@@ -1089,10 +1108,10 @@ class AuthCompanyApiProviderAdapter {
1089
1108
  meta: response.meta,
1090
1109
  })));
1091
1110
  }
1092
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthCompanyApiProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1093
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthCompanyApiProviderAdapter });
1111
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthCompanyApiProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1112
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthCompanyApiProviderAdapter });
1094
1113
  }
1095
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthCompanyApiProviderAdapter, decorators: [{
1114
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthCompanyApiProviderAdapter, decorators: [{
1096
1115
  type: Injectable
1097
1116
  }] });
1098
1117
  // =============================================================================
@@ -1103,10 +1122,10 @@ class AuthUserPermissionProviderAdapter {
1103
1122
  getUserBranchPermissions(userId, companyId) {
1104
1123
  return this.userPermissionApi.getUserBranches(userId, companyId);
1105
1124
  }
1106
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthUserPermissionProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1107
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthUserPermissionProviderAdapter });
1125
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthUserPermissionProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1126
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthUserPermissionProviderAdapter });
1108
1127
  }
1109
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthUserPermissionProviderAdapter, decorators: [{
1128
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthUserPermissionProviderAdapter, decorators: [{
1110
1129
  type: Injectable
1111
1130
  }] });
1112
1131
  // =============================================================================
@@ -1121,10 +1140,10 @@ class AuthStateProviderAdapter {
1121
1140
  initialize() {
1122
1141
  return this.authInit.initialize().pipe(map(() => undefined));
1123
1142
  }
1124
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthStateProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1125
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthStateProviderAdapter });
1143
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthStateProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1144
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthStateProviderAdapter });
1126
1145
  }
1127
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthStateProviderAdapter, decorators: [{
1146
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AuthStateProviderAdapter, decorators: [{
1128
1147
  type: Injectable
1129
1148
  }] });
1130
1149
 
@@ -1146,6 +1165,51 @@ function provideAuthProviders() {
1146
1165
  ];
1147
1166
  }
1148
1167
 
1168
+ const AUTH_VALIDATION_CONFIG = new InjectionToken('AUTH_VALIDATION_CONFIG');
1169
+ const REGISTRATION_FIELD_CONTEXT = new InjectionToken('REGISTRATION_FIELD_CONTEXT');
1170
+ const AUTH_REGISTRATION_EXTENSION = new InjectionToken('AUTH_REGISTRATION_EXTENSION');
1171
+ const AUTH_USER_LIST_EXTENSION = new InjectionToken('AUTH_USER_LIST_EXTENSION');
1172
+ const PROFILE_FIELD_CONTEXT = new InjectionToken('PROFILE_FIELD_CONTEXT');
1173
+ const AUTH_PROFILE_EXTENSION = new InjectionToken('AUTH_PROFILE_EXTENSION');
1174
+ const AUTH_USER_DETAIL_CONFIG = new InjectionToken('AUTH_USER_DETAIL_CONFIG');
1175
+ function validatePassword(password, config) {
1176
+ const minLen = config.minLength ?? 8;
1177
+ const maxLen = config.maxLength;
1178
+ if (password.length < minLen) {
1179
+ return config.message ?? `Password must be at least ${minLen} characters`;
1180
+ }
1181
+ if (maxLen && password.length > maxLen) {
1182
+ return config.message ?? `Password must be at most ${maxLen} characters`;
1183
+ }
1184
+ if (config.pattern) {
1185
+ if (!config.pattern.test(password)) {
1186
+ return config.message ?? 'Password does not meet requirements';
1187
+ }
1188
+ }
1189
+ else {
1190
+ if (config.requireUppercase && !/[A-Z]/.test(password)) {
1191
+ return config.message ?? 'Password must contain at least one uppercase letter';
1192
+ }
1193
+ if (config.requireLowercase && !/[a-z]/.test(password)) {
1194
+ return config.message ?? 'Password must contain at least one lowercase letter';
1195
+ }
1196
+ if (config.requireNumbers && !/\d/.test(password)) {
1197
+ return config.message ?? 'Password must contain at least one number';
1198
+ }
1199
+ if (config.requireSpecialChars && !/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password)) {
1200
+ return config.message ?? 'Password must contain at least one special character';
1201
+ }
1202
+ }
1203
+ return null;
1204
+ }
1205
+ function validateEmail(email, config) {
1206
+ const pattern = config?.pattern ?? /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1207
+ const message = config?.message ?? 'Please enter a valid email address';
1208
+ if (!pattern.test(email))
1209
+ return message;
1210
+ return null;
1211
+ }
1212
+
1149
1213
  /**
1150
1214
  * Administration Page Component
1151
1215
  * Unified administration page with tabs for:
@@ -1199,8 +1263,8 @@ class AdministrationPageComponent {
1199
1263
  return 'No permissions available';
1200
1264
  return `Manage ${tabs.map((t) => t.label.toLowerCase()).join(', ')}`;
1201
1265
  }, ...(ngDevMode ? [{ debugName: "subtitle" }] : []));
1202
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AdministrationPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1203
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: AdministrationPageComponent, isStandalone: true, selector: "lib-administration-page", ngImport: i0, template: `
1266
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AdministrationPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1267
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: AdministrationPageComponent, isStandalone: true, selector: "lib-administration-page", ngImport: i0, template: `
1204
1268
  <div class="p-4">
1205
1269
  <div class="mb-4">
1206
1270
  <h1 class="text-2xl font-bold m-0">Administration</h1>
@@ -1225,7 +1289,7 @@ class AdministrationPageComponent {
1225
1289
  </div>
1226
1290
  `, isInline: true, styles: [".scrollbar-hide{-ms-overflow-style:none;scrollbar-width:none}.scrollbar-hide::-webkit-scrollbar{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1227
1291
  }
1228
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AdministrationPageComponent, decorators: [{
1292
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: AdministrationPageComponent, decorators: [{
1229
1293
  type: Component,
1230
1294
  args: [{ selector: 'lib-administration-page', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, RouterOutlet, RouterLink, RouterLinkActive], template: `
1231
1295
  <div class="p-4">
@@ -1441,8 +1505,8 @@ class BranchFormComponent {
1441
1505
  onCancel() {
1442
1506
  this.navigateToList();
1443
1507
  }
1444
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BranchFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1445
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: BranchFormComponent, isStandalone: true, selector: "lib-branch-form", ngImport: i0, template: `
1508
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: BranchFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1509
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: BranchFormComponent, isStandalone: true, selector: "lib-branch-form", ngImport: i0, template: `
1446
1510
  <p-card>
1447
1511
  <ng-template #header>
1448
1512
  <div class="flex justify-between items-center p-4">
@@ -1553,9 +1617,9 @@ class BranchFormComponent {
1553
1617
  </div>
1554
1618
  </form>
1555
1619
  </p-card>
1556
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1620
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1557
1621
  }
1558
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BranchFormComponent, decorators: [{
1622
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: BranchFormComponent, decorators: [{
1559
1623
  type: Component,
1560
1624
  args: [{
1561
1625
  selector: 'lib-branch-form',
@@ -1783,8 +1847,8 @@ class BranchListComponent {
1783
1847
  },
1784
1848
  });
1785
1849
  }
1786
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BranchListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1787
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: BranchListComponent, isStandalone: true, selector: "lib-branch-list", ngImport: i0, template: `
1850
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: BranchListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1851
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: BranchListComponent, isStandalone: true, selector: "lib-branch-list", ngImport: i0, template: `
1788
1852
  <p-card>
1789
1853
  <ng-template #header>
1790
1854
  <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 p-4">
@@ -1881,9 +1945,9 @@ class BranchListComponent {
1881
1945
  </p-table>
1882
1946
  </div>
1883
1947
  </p-card>
1884
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: i4$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i3$1.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "component", type: i4$2.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: TagModule }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1948
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: i4$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i5.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "component", type: i6.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: i7.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: TagModule }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1885
1949
  }
1886
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BranchListComponent, decorators: [{
1950
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: BranchListComponent, decorators: [{
1887
1951
  type: Component,
1888
1952
  args: [{
1889
1953
  selector: 'lib-branch-list',
@@ -2134,8 +2198,8 @@ class CompanyFormComponent {
2134
2198
  isActive: model.isActive,
2135
2199
  };
2136
2200
  }
2137
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CompanyFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2138
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: CompanyFormComponent, isStandalone: true, selector: "lib-company-form", ngImport: i0, template: `
2201
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CompanyFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2202
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.5", type: CompanyFormComponent, isStandalone: true, selector: "lib-company-form", ngImport: i0, template: `
2139
2203
  <p-card>
2140
2204
  <ng-template #header>
2141
2205
  <div class="flex justify-between items-center p-4">
@@ -2241,9 +2305,9 @@ class CompanyFormComponent {
2241
2305
  </div>
2242
2306
  </form>
2243
2307
  </p-card>
2244
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2308
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2245
2309
  }
2246
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CompanyFormComponent, decorators: [{
2310
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CompanyFormComponent, decorators: [{
2247
2311
  type: Component,
2248
2312
  args: [{
2249
2313
  selector: 'lib-company-form',
@@ -2424,8 +2488,8 @@ class CompanyListComponent {
2424
2488
  },
2425
2489
  });
2426
2490
  }
2427
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CompanyListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2428
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: CompanyListComponent, isStandalone: true, selector: "lib-company-list", ngImport: i0, template: `
2491
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CompanyListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2492
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: CompanyListComponent, isStandalone: true, selector: "lib-company-list", ngImport: i0, template: `
2429
2493
  <p-card>
2430
2494
  <ng-template #header>
2431
2495
  <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 p-4">
@@ -2513,9 +2577,9 @@ class CompanyListComponent {
2513
2577
  </p-table>
2514
2578
  </div>
2515
2579
  </p-card>
2516
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: i3$1.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "component", type: i4$2.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: TagModule }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2580
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: i5.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "component", type: i6.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: i7.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: TagModule }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2517
2581
  }
2518
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CompanyListComponent, decorators: [{
2582
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CompanyListComponent, decorators: [{
2519
2583
  type: Component,
2520
2584
  args: [{
2521
2585
  selector: 'lib-company-list',
@@ -2657,8 +2721,8 @@ class ForgotPasswordPageComponent {
2657
2721
  this.submittedEmail.set('');
2658
2722
  this.formModel.set({ email: '' });
2659
2723
  }
2660
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ForgotPasswordPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2661
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ForgotPasswordPageComponent, isStandalone: true, selector: "lib-forgot-password-page", ngImport: i0, template: `
2724
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: ForgotPasswordPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2725
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: ForgotPasswordPageComponent, isStandalone: true, selector: "lib-forgot-password-page", ngImport: i0, template: `
2662
2726
  <app-floating-configurator />
2663
2727
  <div class="bg-surface-ground flex items-center justify-center min-h-screen">
2664
2728
  <div class="flex flex-col items-center justify-center w-full max-w-[32rem] px-4">
@@ -2735,9 +2799,9 @@ class ForgotPasswordPageComponent {
2735
2799
  </div>
2736
2800
  </div>
2737
2801
  </div>
2738
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "component", type: AppFloatingConfigurator, selector: "app-floating-configurator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2802
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "component", type: AppFloatingConfigurator, selector: "app-floating-configurator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2739
2803
  }
2740
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ForgotPasswordPageComponent, decorators: [{
2804
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: ForgotPasswordPageComponent, decorators: [{
2741
2805
  type: Component,
2742
2806
  args: [{
2743
2807
  selector: 'lib-forgot-password-page',
@@ -2835,6 +2899,7 @@ class LoginPageComponent {
2835
2899
  messageService = inject(MessageService);
2836
2900
  authApi = inject(AuthApiService);
2837
2901
  authState = inject(AuthStateService);
2902
+ validationConfig = inject(AUTH_VALIDATION_CONFIG, { optional: true });
2838
2903
  returnUrl = input('', ...(ngDevMode ? [{ debugName: "returnUrl" }] : []));
2839
2904
  currentStep = signal('credentials', ...(ngDevMode ? [{ debugName: "currentStep" }] : []));
2840
2905
  isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
@@ -2844,13 +2909,35 @@ class LoginPageComponent {
2844
2909
  password: '',
2845
2910
  rememberMe: true,
2846
2911
  }, ...(ngDevMode ? [{ debugName: "loginFormModel" }] : []));
2912
+ emailErrorMessage = computed(() => this.validationConfig?.email?.message ?? 'Please enter a valid email address', ...(ngDevMode ? [{ debugName: "emailErrorMessage" }] : []));
2913
+ passwordMinLength = computed(() => this.validationConfig?.password?.minLength ?? 8, ...(ngDevMode ? [{ debugName: "passwordMinLength" }] : []));
2914
+ passwordErrorMessage = computed(() => this.validationConfig?.password?.message ?? `Password must be at least ${this.passwordMinLength()} characters`, ...(ngDevMode ? [{ debugName: "passwordErrorMessage" }] : []));
2847
2915
  loginForm = form(this.loginFormModel, (f) => {
2848
2916
  required(f.email, { message: 'Email is required' });
2849
- email(f.email, { message: 'Please enter a valid email address' });
2917
+ email(f.email, { message: this.emailErrorMessage() });
2850
2918
  required(f.password, { message: 'Password is required' });
2851
- minLength(f.password, 8, { message: 'Password must be at least 8 characters' });
2919
+ minLength(f.password, this.passwordMinLength(), { message: this.passwordErrorMessage() });
2852
2920
  });
2853
- isLoginFormValid = computed(() => this.loginForm().valid(), ...(ngDevMode ? [{ debugName: "isLoginFormValid" }] : []));
2921
+ emailValidationError = computed(() => {
2922
+ const email = this.loginFormModel().email;
2923
+ if (!email)
2924
+ return null;
2925
+ return validateEmail(email, this.validationConfig?.email ?? undefined);
2926
+ }, ...(ngDevMode ? [{ debugName: "emailValidationError" }] : []));
2927
+ passwordValidationError = computed(() => {
2928
+ const password = this.loginFormModel().password;
2929
+ if (!password)
2930
+ return null;
2931
+ if (!this.validationConfig?.password)
2932
+ return null;
2933
+ return validatePassword(password, this.validationConfig.password);
2934
+ }, ...(ngDevMode ? [{ debugName: "passwordValidationError" }] : []));
2935
+ isLoginFormValid = computed(() => {
2936
+ const formValid = this.loginForm().valid();
2937
+ const emailError = this.emailValidationError();
2938
+ const passwordError = this.passwordValidationError();
2939
+ return formValid && !emailError && !passwordError;
2940
+ }, ...(ngDevMode ? [{ debugName: "isLoginFormValid" }] : []));
2854
2941
  selectionFormModel = signal({
2855
2942
  companyId: '',
2856
2943
  branchId: '',
@@ -2862,6 +2949,8 @@ class LoginPageComponent {
2862
2949
  });
2863
2950
  isSelectionFormValid = computed(() => this.selectionForm().valid(), ...(ngDevMode ? [{ debugName: "isSelectionFormValid" }] : []));
2864
2951
  companyFeatureEnabled = computed(() => isCompanyFeatureEnabled(this.appConfig), ...(ngDevMode ? [{ debugName: "companyFeatureEnabled" }] : []));
2952
+ emailFeatureEnabled = computed(() => isEmailFeatureEnabled(this.appConfig), ...(ngDevMode ? [{ debugName: "emailFeatureEnabled" }] : []));
2953
+ signUpEnabled = computed(() => isSignUpEnabled(this.appConfig), ...(ngDevMode ? [{ debugName: "signUpEnabled" }] : []));
2865
2954
  sessionId = null;
2866
2955
  companies = signal([], ...(ngDevMode ? [{ debugName: "companies" }] : []));
2867
2956
  userName = signal('', ...(ngDevMode ? [{ debugName: "userName" }] : []));
@@ -3066,8 +3155,8 @@ class LoginPageComponent {
3066
3155
  }
3067
3156
  }
3068
3157
  }
3069
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: LoginPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3070
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: LoginPageComponent, isStandalone: true, selector: "lib-login-page", inputs: { returnUrl: { classPropertyName: "returnUrl", publicName: "returnUrl", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
3158
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: LoginPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3159
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: LoginPageComponent, isStandalone: true, selector: "lib-login-page", inputs: { returnUrl: { classPropertyName: "returnUrl", publicName: "returnUrl", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
3071
3160
  <app-floating-configurator />
3072
3161
  <div class="bg-surface-ground flex items-center justify-center min-h-screen">
3073
3162
  <div class="flex flex-col items-center justify-center w-full max-w-[32rem] px-4">
@@ -3119,9 +3208,13 @@ class LoginPageComponent {
3119
3208
  id="email"
3120
3209
  type="email"
3121
3210
  placeholder="Email address"
3122
- class="w-full md:w-[25rem] mb-4"
3211
+ class="w-full md:w-[25rem]"
3123
3212
  [formField]="loginForm.email"
3124
3213
  autocomplete="email" />
3214
+ @if (emailValidationError() && loginFormModel().email) {
3215
+ <small class="text-danger block mt-1">{{ emailValidationError() }}</small>
3216
+ }
3217
+ <div class="mb-4"></div>
3125
3218
 
3126
3219
  <label for="password" class="block font-medium text-lg mb-2 text-color">
3127
3220
  Password
@@ -3135,6 +3228,9 @@ class LoginPageComponent {
3135
3228
  class="w-full md:w-[25rem]"
3136
3229
  [formField]="loginForm.password"
3137
3230
  autocomplete="current-password" />
3231
+ @if (passwordValidationError() && loginFormModel().password) {
3232
+ <small class="text-danger block mt-1">{{ passwordValidationError() }}</small>
3233
+ }
3138
3234
  </div>
3139
3235
 
3140
3236
  <div class="flex flex-col sm:flex-row items-start sm:items-center justify-between mt-2 mb-8 gap-4">
@@ -3144,11 +3240,13 @@ class LoginPageComponent {
3144
3240
  [formField]="loginForm.rememberMe" />
3145
3241
  <span>Remember me</span>
3146
3242
  </label>
3147
- <span
3148
- class="font-medium no-underline ml-2 text-right cursor-pointer text-primary"
3149
- routerLink="/auth/forgot-password">
3150
- Forgot password?
3151
- </span>
3243
+ @if (emailFeatureEnabled()) {
3244
+ <span
3245
+ class="font-medium no-underline ml-2 text-right cursor-pointer text-primary"
3246
+ routerLink="/auth/forgot-password">
3247
+ Forgot password?
3248
+ </span>
3249
+ }
3152
3250
  </div>
3153
3251
 
3154
3252
  <p-button
@@ -3158,12 +3256,14 @@ class LoginPageComponent {
3158
3256
  [loading]="isLoading()"
3159
3257
  [disabled]="!isLoginFormValid() || isLoading()" />
3160
3258
 
3161
- <div class="flex items-center justify-center mt-4 gap-2">
3162
- <span class="font-medium">Don't have an account?</span>
3163
- <a routerLink="/auth/register" class="font-semibold text-primary cursor-pointer">
3164
- Sign Up
3165
- </a>
3166
- </div>
3259
+ @if (signUpEnabled()) {
3260
+ <div class="flex items-center justify-center mt-4 gap-2">
3261
+ <span class="font-medium">Don't have an account?</span>
3262
+ <a routerLink="/auth/register" class="font-semibold text-primary cursor-pointer">
3263
+ Sign Up
3264
+ </a>
3265
+ </div>
3266
+ }
3167
3267
  </form>
3168
3268
  }
3169
3269
 
@@ -3263,9 +3363,9 @@ class LoginPageComponent {
3263
3363
  </div>
3264
3364
  </div>
3265
3365
  </div>
3266
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "component", type: AppFloatingConfigurator, selector: "app-floating-configurator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3366
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "component", type: AppFloatingConfigurator, selector: "app-floating-configurator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3267
3367
  }
3268
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: LoginPageComponent, decorators: [{
3368
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: LoginPageComponent, decorators: [{
3269
3369
  type: Component,
3270
3370
  args: [{
3271
3371
  selector: 'lib-login-page',
@@ -3323,9 +3423,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
3323
3423
  id="email"
3324
3424
  type="email"
3325
3425
  placeholder="Email address"
3326
- class="w-full md:w-[25rem] mb-4"
3426
+ class="w-full md:w-[25rem]"
3327
3427
  [formField]="loginForm.email"
3328
3428
  autocomplete="email" />
3429
+ @if (emailValidationError() && loginFormModel().email) {
3430
+ <small class="text-danger block mt-1">{{ emailValidationError() }}</small>
3431
+ }
3432
+ <div class="mb-4"></div>
3329
3433
 
3330
3434
  <label for="password" class="block font-medium text-lg mb-2 text-color">
3331
3435
  Password
@@ -3339,6 +3443,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
3339
3443
  class="w-full md:w-[25rem]"
3340
3444
  [formField]="loginForm.password"
3341
3445
  autocomplete="current-password" />
3446
+ @if (passwordValidationError() && loginFormModel().password) {
3447
+ <small class="text-danger block mt-1">{{ passwordValidationError() }}</small>
3448
+ }
3342
3449
  </div>
3343
3450
 
3344
3451
  <div class="flex flex-col sm:flex-row items-start sm:items-center justify-between mt-2 mb-8 gap-4">
@@ -3348,11 +3455,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
3348
3455
  [formField]="loginForm.rememberMe" />
3349
3456
  <span>Remember me</span>
3350
3457
  </label>
3351
- <span
3352
- class="font-medium no-underline ml-2 text-right cursor-pointer text-primary"
3353
- routerLink="/auth/forgot-password">
3354
- Forgot password?
3355
- </span>
3458
+ @if (emailFeatureEnabled()) {
3459
+ <span
3460
+ class="font-medium no-underline ml-2 text-right cursor-pointer text-primary"
3461
+ routerLink="/auth/forgot-password">
3462
+ Forgot password?
3463
+ </span>
3464
+ }
3356
3465
  </div>
3357
3466
 
3358
3467
  <p-button
@@ -3362,12 +3471,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
3362
3471
  [loading]="isLoading()"
3363
3472
  [disabled]="!isLoginFormValid() || isLoading()" />
3364
3473
 
3365
- <div class="flex items-center justify-center mt-4 gap-2">
3366
- <span class="font-medium">Don't have an account?</span>
3367
- <a routerLink="/auth/register" class="font-semibold text-primary cursor-pointer">
3368
- Sign Up
3369
- </a>
3370
- </div>
3474
+ @if (signUpEnabled()) {
3475
+ <div class="flex items-center justify-center mt-4 gap-2">
3476
+ <span class="font-medium">Don't have an account?</span>
3477
+ <a routerLink="/auth/register" class="font-semibold text-primary cursor-pointer">
3478
+ Sign Up
3479
+ </a>
3480
+ </div>
3481
+ }
3371
3482
  </form>
3372
3483
  }
3373
3484
 
@@ -3476,20 +3587,6 @@ var loginPage_component = /*#__PURE__*/Object.freeze({
3476
3587
  LoginPageComponent: LoginPageComponent
3477
3588
  });
3478
3589
 
3479
- /**
3480
- * Profile Page Component
3481
- *
3482
- * Allows users to view and update their profile information.
3483
- * Features:
3484
- * - Update name, phone, profile picture (if storage enabled)
3485
- * - View company/branch info (read-only, if company feature enabled)
3486
- * - View roles/actions (read-only, if IAM enabled via optional injection)
3487
- *
3488
- * Package Independence:
3489
- * - Uses PROFILE_UPLOAD_PROVIDER (optional) for storage functionality
3490
- * - Uses PROFILE_PERMISSION_PROVIDER (optional) for IAM functionality
3491
- * - No direct imports from ng-storage or ng-iam
3492
- */
3493
3590
  class ProfilePageComponent {
3494
3591
  destroyRef = inject(DestroyRef);
3495
3592
  appConfig = inject(APP_CONFIG);
@@ -3498,44 +3595,56 @@ class ProfilePageComponent {
3498
3595
  userService = inject(UserApiService);
3499
3596
  authApiService = inject(AuthApiService);
3500
3597
  fileUrlService = inject(FileUrlService);
3501
- // Optional injection - null if storage not configured
3502
- uploadProvider = inject(PROFILE_UPLOAD_PROVIDER, {
3503
- optional: true,
3504
- });
3505
- // Optional injection - null if IAM not configured
3506
- permissionProvider = inject(PROFILE_PERMISSION_PROVIDER, {
3507
- optional: true,
3508
- });
3509
- // State
3598
+ uploadProvider = inject(PROFILE_UPLOAD_PROVIDER, { optional: true });
3599
+ permissionProvider = inject(PROFILE_PERMISSION_PROVIDER, { optional: true });
3600
+ profileExtension = inject(AUTH_PROFILE_EXTENSION, { optional: true });
3510
3601
  isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
3511
3602
  isLoadingPermissions = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingPermissions" }] : []));
3603
+ isLoadingExtraFields = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingExtraFields" }] : []));
3512
3604
  _profilePictureUrl = signal(null, ...(ngDevMode ? [{ debugName: "_profilePictureUrl" }] : []));
3513
3605
  profilePictureUrl = this._profilePictureUrl.asReadonly();
3514
- // Permission data
3515
3606
  _userRoles = signal([], ...(ngDevMode ? [{ debugName: "_userRoles" }] : []));
3516
3607
  userRoles = this._userRoles.asReadonly();
3517
3608
  _userActions = signal([], ...(ngDevMode ? [{ debugName: "_userActions" }] : []));
3518
3609
  userActions = this._userActions.asReadonly();
3519
- // Computed from auth state
3610
+ extraSections = computed(() => {
3611
+ if (!this.profileExtension?.getExtraSections)
3612
+ return [];
3613
+ const sections = this.profileExtension.getExtraSections();
3614
+ return sections.sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
3615
+ }, ...(ngDevMode ? [{ debugName: "extraSections" }] : []));
3616
+ extraFields = computed(() => {
3617
+ if (!this.profileExtension?.getExtraFields)
3618
+ return [];
3619
+ const fields = this.profileExtension.getExtraFields();
3620
+ return fields.sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
3621
+ }, ...(ngDevMode ? [{ debugName: "extraFields" }] : []));
3622
+ viewOnlyFields = computed(() => this.extraFields().filter(f => f.editable === false), ...(ngDevMode ? [{ debugName: "viewOnlyFields" }] : []));
3623
+ editableFields = computed(() => this.extraFields().filter(f => f.editable !== false), ...(ngDevMode ? [{ debugName: "editableFields" }] : []));
3624
+ hasExtraContent = computed(() => this.extraSections().length > 0 || this.extraFields().length > 0, ...(ngDevMode ? [{ debugName: "hasExtraContent" }] : []));
3625
+ extraFieldsModel = signal({}, ...(ngDevMode ? [{ debugName: "extraFieldsModel" }] : []));
3626
+ originalExtraFieldsModel = signal({}, ...(ngDevMode ? [{ debugName: "originalExtraFieldsModel" }] : []));
3627
+ isExtraFieldsDirty = computed(() => {
3628
+ const current = this.extraFieldsModel();
3629
+ const original = this.originalExtraFieldsModel();
3630
+ return JSON.stringify(current) !== JSON.stringify(original);
3631
+ }, ...(ngDevMode ? [{ debugName: "isExtraFieldsDirty" }] : []));
3632
+ extraFieldsValidationError = computed(() => {
3633
+ if (!this.profileExtension?.validateExtraFields)
3634
+ return null;
3635
+ return this.profileExtension.validateExtraFields(this.extraFieldsModel());
3636
+ }, ...(ngDevMode ? [{ debugName: "extraFieldsValidationError" }] : []));
3520
3637
  userEmail = computed(() => this.authState.user()?.email ?? '', ...(ngDevMode ? [{ debugName: "userEmail" }] : []));
3521
3638
  userName = computed(() => this.authState.user()?.name ?? 'User', ...(ngDevMode ? [{ debugName: "userName" }] : []));
3522
3639
  userInitials = computed(() => {
3523
3640
  const name = this.authState.user()?.name ?? '';
3524
- return name
3525
- .split(' ')
3526
- .map((n) => n[0])
3527
- .join('')
3528
- .toUpperCase()
3529
- .slice(0, 2);
3641
+ return name.split(' ').map((n) => n[0]).join('').toUpperCase().slice(0, 2);
3530
3642
  }, ...(ngDevMode ? [{ debugName: "userInitials" }] : []));
3531
3643
  companyName = computed(() => this.authState.companyName(), ...(ngDevMode ? [{ debugName: "companyName" }] : []));
3532
3644
  branchName = computed(() => this.authState.branchName(), ...(ngDevMode ? [{ debugName: "branchName" }] : []));
3533
- // Feature flags - Storage feature check
3534
- showUploadSection = computed(() => isFeatureEnabled(this.appConfig, 'storage') &&
3535
- this.uploadProvider !== null, ...(ngDevMode ? [{ debugName: "showUploadSection" }] : []));
3645
+ showUploadSection = computed(() => isFeatureEnabled(this.appConfig, 'storage') && this.uploadProvider !== null, ...(ngDevMode ? [{ debugName: "showUploadSection" }] : []));
3536
3646
  showCompanySection = computed(() => isCompanyFeatureEnabled(this.appConfig), ...(ngDevMode ? [{ debugName: "showCompanySection" }] : []));
3537
- showPermissionsSection = computed(() => isFeatureEnabled(this.appConfig, 'iam') &&
3538
- this.permissionProvider !== null, ...(ngDevMode ? [{ debugName: "showPermissionsSection" }] : []));
3647
+ showPermissionsSection = computed(() => isFeatureEnabled(this.appConfig, 'iam') && this.permissionProvider !== null, ...(ngDevMode ? [{ debugName: "showPermissionsSection" }] : []));
3539
3648
  permissionMode = computed(() => getPermissionMode(this.appConfig), ...(ngDevMode ? [{ debugName: "permissionMode" }] : []));
3540
3649
  showRoles = computed(() => {
3541
3650
  const mode = this.permissionMode();
@@ -3545,30 +3654,45 @@ class ProfilePageComponent {
3545
3654
  const mode = this.permissionMode();
3546
3655
  return mode === 'direct' || mode === 'full';
3547
3656
  }, ...(ngDevMode ? [{ debugName: "showActions" }] : []));
3548
- // Show bottom row only if at least one section is visible
3549
3657
  showBottomRow = computed(() => this.showCompanySection() || this.showPermissionsSection(), ...(ngDevMode ? [{ debugName: "showBottomRow" }] : []));
3550
- // Form
3551
- originalFormModel = signal({
3552
- name: '',
3553
- phone: '',
3554
- }, ...(ngDevMode ? [{ debugName: "originalFormModel" }] : []));
3555
- formModel = signal({
3556
- name: '',
3557
- phone: '',
3558
- }, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
3658
+ originalFormModel = signal({ name: '', phone: '' }, ...(ngDevMode ? [{ debugName: "originalFormModel" }] : []));
3659
+ formModel = signal({ name: '', phone: '' }, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
3559
3660
  formTree = form(this.formModel, (f) => {
3560
3661
  required(f.name, { message: 'Name is required' });
3561
3662
  });
3562
- isFormValid = computed(() => {
3563
- const model = this.formModel();
3564
- return model.name.trim().length > 0;
3565
- }, ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
3663
+ isFormValid = computed(() => this.formModel().name.trim().length > 0, ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
3566
3664
  isFormDirty = computed(() => {
3567
3665
  const current = this.formModel();
3568
3666
  const original = this.originalFormModel();
3569
- return current.name !== original.name || current.phone !== original.phone;
3667
+ const basicDirty = current.name !== original.name || current.phone !== original.phone;
3668
+ return basicDirty || this.isExtraFieldsDirty();
3570
3669
  }, ...(ngDevMode ? [{ debugName: "isFormDirty" }] : []));
3571
- // Password form
3670
+ updateExtraField(key, value) {
3671
+ this.extraFieldsModel.update((model) => ({ ...model, [key]: value }));
3672
+ }
3673
+ getExtraFieldValue(key) {
3674
+ return this.extraFieldsModel()[key];
3675
+ }
3676
+ getSelectLabel(field, value) {
3677
+ if (!value || !field.options)
3678
+ return '-';
3679
+ const option = field.options.find(opt => opt.value === value);
3680
+ return option?.label ?? String(value);
3681
+ }
3682
+ getFieldTemplateContext(field) {
3683
+ return {
3684
+ field,
3685
+ value: this.extraFieldsModel()[field.key],
3686
+ updateValue: (value) => this.updateExtraField(field.key, value),
3687
+ };
3688
+ }
3689
+ parentInjector = inject(Injector);
3690
+ getFieldInjector(field) {
3691
+ return Injector.create({
3692
+ providers: [{ provide: PROFILE_FIELD_CONTEXT, useValue: this.getFieldTemplateContext(field) }],
3693
+ parent: field.injector ?? this.parentInjector,
3694
+ });
3695
+ }
3572
3696
  passwordModel = signal({
3573
3697
  currentPassword: '',
3574
3698
  newPassword: '',
@@ -3577,19 +3701,15 @@ class ProfilePageComponent {
3577
3701
  isPasswordLoading = signal(false, ...(ngDevMode ? [{ debugName: "isPasswordLoading" }] : []));
3578
3702
  isPasswordFormValid = computed(() => {
3579
3703
  const model = this.passwordModel();
3580
- return (model.currentPassword.length > 0 &&
3581
- model.newPassword.length >= 6 &&
3582
- model.newPassword === model.confirmPassword);
3704
+ return model.currentPassword.length > 0 && model.newPassword.length >= 6 && model.newPassword === model.confirmPassword;
3583
3705
  }, ...(ngDevMode ? [{ debugName: "isPasswordFormValid" }] : []));
3584
3706
  passwordsMatch = computed(() => {
3585
3707
  const model = this.passwordModel();
3586
3708
  return model.confirmPassword.length === 0 || model.newPassword === model.confirmPassword;
3587
3709
  }, ...(ngDevMode ? [{ debugName: "passwordsMatch" }] : []));
3588
- // Upload function for FileUploader - uses provider if available
3589
3710
  uploadFileFn = (file, options) => {
3590
- if (!this.uploadProvider) {
3711
+ if (!this.uploadProvider)
3591
3712
  throw new Error('Upload provider not available');
3592
- }
3593
3713
  return this.uploadProvider
3594
3714
  .uploadProfilePicture(file, {
3595
3715
  folderPath: options?.folderPath ?? 'profile-pictures',
@@ -3600,15 +3720,12 @@ class ProfilePageComponent {
3600
3720
  .pipe(map((response) => ({
3601
3721
  success: response.success,
3602
3722
  message: response.message,
3603
- data: response.data
3604
- ? this.mapUploadResultToUploadedFile(response.data)
3605
- : undefined,
3723
+ data: response.data ? this.mapUploadResultToUploadedFile(response.data) : undefined,
3606
3724
  })));
3607
3725
  };
3608
- /** Map upload result to IUploadedFile format */
3609
3726
  mapUploadResultToUploadedFile(result) {
3610
3727
  return {
3611
- id: result.id, // UUID for storing in profilePictureId
3728
+ id: result.id,
3612
3729
  name: result.name,
3613
3730
  key: result.key,
3614
3731
  size: result.size,
@@ -3616,32 +3733,28 @@ class ProfilePageComponent {
3616
3733
  };
3617
3734
  }
3618
3735
  constructor() {
3619
- // Initialize user data on construction
3620
3736
  this.loadUserData();
3621
- // Effect for permissions loading when section is visible
3622
3737
  effect(() => {
3623
- if (this.showPermissionsSection()) {
3738
+ if (this.showPermissionsSection())
3624
3739
  this.loadPermissions();
3625
- }
3740
+ });
3741
+ effect(() => {
3742
+ const user = this.authState.user();
3743
+ if (user && this.hasExtraContent())
3744
+ this.loadExtraFields();
3626
3745
  });
3627
3746
  }
3628
3747
  loadUserData() {
3629
3748
  const user = this.authState.user();
3630
3749
  if (user) {
3631
- const initialValues = {
3632
- name: user.name ?? '',
3633
- phone: user.phone ?? '',
3634
- };
3750
+ const initialValues = { name: user.name ?? '', phone: user.phone ?? '' };
3635
3751
  this.originalFormModel.set(initialValues);
3636
3752
  this.formModel.set(initialValues);
3637
- // Load profile picture URL (only if storage is enabled)
3638
3753
  if (user.profilePictureId && isFeatureEnabled(this.appConfig, 'storage')) {
3639
3754
  this.fileUrlService
3640
3755
  .fetchSingleFileUrl(user.profilePictureId)
3641
3756
  .pipe(takeUntilDestroyed(this.destroyRef))
3642
- .subscribe((file) => {
3643
- this._profilePictureUrl.set(file?.url ?? null);
3644
- });
3757
+ .subscribe((file) => this._profilePictureUrl.set(file?.url ?? null));
3645
3758
  }
3646
3759
  }
3647
3760
  }
@@ -3655,52 +3768,44 @@ class ProfilePageComponent {
3655
3768
  if (!loadRoles && !loadActions)
3656
3769
  return;
3657
3770
  this.isLoadingPermissions.set(true);
3658
- let rolesLoaded = !loadRoles;
3659
- let actionsLoaded = !loadActions;
3660
- const checkComplete = () => {
3661
- if (rolesLoaded && actionsLoaded) {
3662
- this.isLoadingPermissions.set(false);
3663
- }
3664
- };
3665
- // Load roles (if applicable)
3666
- if (loadRoles) {
3667
- this.permissionProvider
3668
- .getUserRoles(user.id, branch?.id)
3669
- .pipe(takeUntilDestroyed(this.destroyRef))
3670
- .subscribe({
3671
- next: (response) => {
3672
- this._userRoles.set(response.data ?? []);
3673
- rolesLoaded = true;
3674
- checkComplete();
3675
- },
3676
- error: () => {
3677
- this._userRoles.set([]);
3678
- rolesLoaded = true;
3679
- checkComplete();
3680
- },
3681
- });
3682
- }
3683
- // Load actions (if applicable)
3684
- if (loadActions) {
3685
- this.permissionProvider
3686
- .getUserActions(user.id, branch?.id)
3687
- .pipe(takeUntilDestroyed(this.destroyRef))
3688
- .subscribe({
3689
- next: (response) => {
3690
- this._userActions.set(response.data ?? []);
3691
- actionsLoaded = true;
3692
- checkComplete();
3693
- },
3694
- error: () => {
3695
- this._userActions.set([]);
3696
- actionsLoaded = true;
3697
- checkComplete();
3698
- },
3699
- });
3700
- }
3771
+ const roles$ = loadRoles
3772
+ ? this.permissionProvider.getUserRoles(user.id, branch?.id).pipe(catchError(() => of({ data: [] })))
3773
+ : of({ data: [] });
3774
+ const actions$ = loadActions
3775
+ ? this.permissionProvider.getUserActions(user.id, branch?.id).pipe(catchError(() => of({ data: [] })))
3776
+ : of({ data: [] });
3777
+ forkJoin([roles$, actions$])
3778
+ .pipe(takeUntilDestroyed(this.destroyRef), finalize(() => this.isLoadingPermissions.set(false)))
3779
+ .subscribe(([rolesResponse, actionsResponse]) => {
3780
+ this._userRoles.set(rolesResponse.data ?? []);
3781
+ this._userActions.set(actionsResponse.data ?? []);
3782
+ });
3783
+ }
3784
+ loadExtraFields() {
3785
+ const user = this.authState.user();
3786
+ if (!user || !this.profileExtension?.getExtraFieldValues)
3787
+ return;
3788
+ this.isLoadingExtraFields.set(true);
3789
+ this.profileExtension
3790
+ .getExtraFieldValues(user.id)
3791
+ .pipe(takeUntilDestroyed(this.destroyRef), finalize(() => this.isLoadingExtraFields.set(false)))
3792
+ .subscribe({
3793
+ next: (values) => {
3794
+ this.extraFieldsModel.set(values);
3795
+ this.originalExtraFieldsModel.set(values);
3796
+ },
3797
+ error: () => {
3798
+ const defaults = {};
3799
+ for (const field of this.extraFields()) {
3800
+ if (field.key)
3801
+ defaults[field.key] = undefined;
3802
+ }
3803
+ this.extraFieldsModel.set(defaults);
3804
+ this.originalExtraFieldsModel.set(defaults);
3805
+ },
3806
+ });
3701
3807
  }
3702
3808
  onProfilePictureUploaded(file) {
3703
- // Update user with new profile picture ID (file.id is the FileManager UUID)
3704
3809
  const user = this.authState.user();
3705
3810
  if (!user || !file.id)
3706
3811
  return;
@@ -3711,33 +3816,25 @@ class ProfilePageComponent {
3711
3816
  .subscribe({
3712
3817
  next: (response) => {
3713
3818
  if (response.success && response.data) {
3714
- // Update auth state with new profile picture ID
3715
- this.authState.setUser({
3716
- ...user,
3717
- profilePictureId: fileManagerId,
3718
- });
3719
- // Fetch new profile picture URL (force refresh to get fresh URL)
3819
+ this.authState.setUser({ ...user, profilePictureId: fileManagerId });
3720
3820
  this.fileUrlService
3721
3821
  .fetchSingleFileUrl(fileManagerId, true)
3722
3822
  .pipe(takeUntilDestroyed(this.destroyRef))
3723
- .subscribe((fileInfo) => {
3724
- this._profilePictureUrl.set(fileInfo?.url ?? null);
3725
- });
3726
- this.messageService.add({
3727
- severity: 'success',
3728
- summary: 'Success',
3729
- detail: 'Profile picture updated',
3730
- });
3823
+ .subscribe((fileInfo) => this._profilePictureUrl.set(fileInfo?.url ?? null));
3824
+ this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Profile picture updated' });
3731
3825
  }
3732
3826
  },
3733
- error: () => {
3734
- // Error toast handled by global interceptor
3735
- },
3827
+ error: () => { },
3736
3828
  });
3737
3829
  }
3738
3830
  onSubmit() {
3739
3831
  if (!this.isFormValid())
3740
3832
  return;
3833
+ const extraFieldsError = this.extraFieldsValidationError();
3834
+ if (extraFieldsError) {
3835
+ this.messageService.add({ severity: 'error', summary: 'Validation Error', detail: extraFieldsError });
3836
+ return;
3837
+ }
3741
3838
  const user = this.authState.user();
3742
3839
  if (!user)
3743
3840
  return;
@@ -3748,33 +3845,22 @@ class ProfilePageComponent {
3748
3845
  name: model.name,
3749
3846
  phone: model.phone || undefined,
3750
3847
  };
3751
- this.userService
3752
- .updateProfile(updateData)
3848
+ const profileUpdate$ = this.userService.updateProfile(updateData);
3849
+ const extraFieldsUpdate$ = this.isExtraFieldsDirty() && this.profileExtension?.saveExtraFieldValues
3850
+ ? this.profileExtension.saveExtraFieldValues(user.id, this.extraFieldsModel())
3851
+ : of(undefined);
3852
+ forkJoin([profileUpdate$, extraFieldsUpdate$])
3753
3853
  .pipe(takeUntilDestroyed(this.destroyRef), finalize(() => this.isLoading.set(false)))
3754
3854
  .subscribe({
3755
- next: (response) => {
3855
+ next: ([response]) => {
3756
3856
  if (response.success && response.data) {
3757
- // Update auth state with new user data (name and phone)
3758
- this.authState.setUser({
3759
- ...user,
3760
- name: response.data.name,
3761
- phone: response.data.phone ?? null,
3762
- });
3763
- // Update original form model to reset dirty state
3764
- this.originalFormModel.set({
3765
- name: response.data.name,
3766
- phone: response.data.phone ?? '',
3767
- });
3768
- this.messageService.add({
3769
- severity: 'success',
3770
- summary: 'Success',
3771
- detail: 'Profile updated successfully',
3772
- });
3857
+ this.authState.setUser({ ...user, name: response.data.name, phone: response.data.phone ?? null });
3858
+ this.originalFormModel.set({ name: response.data.name, phone: response.data.phone ?? '' });
3859
+ this.originalExtraFieldsModel.set({ ...this.extraFieldsModel() });
3860
+ this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Profile updated successfully' });
3773
3861
  }
3774
3862
  },
3775
- error: () => {
3776
- // Error toast handled by global interceptor
3777
- },
3863
+ error: () => { },
3778
3864
  });
3779
3865
  }
3780
3866
  updatePasswordField(field, value) {
@@ -3786,42 +3872,25 @@ class ProfilePageComponent {
3786
3872
  this.isPasswordLoading.set(true);
3787
3873
  const model = this.passwordModel();
3788
3874
  this.authApiService
3789
- .changePassword({
3790
- currentPassword: model.currentPassword,
3791
- newPassword: model.newPassword,
3792
- })
3875
+ .changePassword({ currentPassword: model.currentPassword, newPassword: model.newPassword })
3793
3876
  .pipe(takeUntilDestroyed(this.destroyRef), finalize(() => this.isPasswordLoading.set(false)))
3794
3877
  .subscribe({
3795
3878
  next: () => {
3796
- this.messageService.add({
3797
- severity: 'success',
3798
- summary: 'Success',
3799
- detail: 'Password changed successfully',
3800
- });
3801
- // Reset password form
3802
- this.passwordModel.set({
3803
- currentPassword: '',
3804
- newPassword: '',
3805
- confirmPassword: '',
3806
- });
3807
- },
3808
- error: () => {
3809
- // Error toast handled by global interceptor
3879
+ this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Password changed successfully' });
3880
+ this.passwordModel.set({ currentPassword: '', newPassword: '', confirmPassword: '' });
3810
3881
  },
3882
+ error: () => { },
3811
3883
  });
3812
3884
  }
3813
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ProfilePageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3814
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ProfilePageComponent, isStandalone: true, selector: "lib-profile-page", ngImport: i0, template: `
3815
- <!-- Page Header -->
3885
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: ProfilePageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3886
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: ProfilePageComponent, isStandalone: true, selector: "lib-profile-page", ngImport: i0, template: `
3816
3887
  <div class="mb-4 md:mb-6">
3817
3888
  <h1 class="text-2xl font-bold text-color mb-2">My Profile</h1>
3818
3889
  <p class="text-muted-color">Manage your account settings and preferences.</p>
3819
3890
  </div>
3820
3891
 
3821
- <!-- Profile Form Card (full width) -->
3822
3892
  <div class="card mb-2 md:mb-4">
3823
3893
  <div class="flex flex-col md:flex-row gap-4 md:gap-6">
3824
- <!-- Avatar Section -->
3825
3894
  <div class="flex flex-col items-center gap-4 md:w-72 lg:w-80 md:border-r md:border-surface-200 md:pr-6">
3826
3895
  @if (profilePictureUrl()) {
3827
3896
  <p-avatar
@@ -3840,7 +3909,6 @@ class ProfilePageComponent {
3840
3909
  <div class="font-semibold text-color">{{ userName() }}</div>
3841
3910
  <div class="text-muted-color text-sm">{{ userEmail() }}</div>
3842
3911
  </div>
3843
- <!-- Upload section - only show if storage is enabled and provider is available -->
3844
3912
  @if (showUploadSection()) {
3845
3913
  <lib-file-uploader
3846
3914
  [uploadFile]="uploadFileFn"
@@ -3858,10 +3926,8 @@ class ProfilePageComponent {
3858
3926
  }
3859
3927
  </div>
3860
3928
 
3861
- <!-- Form Section -->
3862
3929
  <div class="flex-1">
3863
3930
  <form (ngSubmit)="onSubmit()" class="flex flex-col gap-4">
3864
- <!-- Email (read-only) -->
3865
3931
  <div class="flex flex-col gap-2">
3866
3932
  <label class="font-medium text-color">Email</label>
3867
3933
  <input
@@ -3871,7 +3937,6 @@ class ProfilePageComponent {
3871
3937
  class="bg-surface-50" />
3872
3938
  </div>
3873
3939
 
3874
- <!-- Name -->
3875
3940
  <div class="flex flex-col gap-2">
3876
3941
  <label for="name" class="font-medium text-color">Name *</label>
3877
3942
  <input
@@ -3881,7 +3946,6 @@ class ProfilePageComponent {
3881
3946
  placeholder="Your full name" />
3882
3947
  </div>
3883
3948
 
3884
- <!-- Phone -->
3885
3949
  <div class="flex flex-col gap-2">
3886
3950
  <label for="phone" class="font-medium text-color">Phone</label>
3887
3951
  <input
@@ -3891,7 +3955,140 @@ class ProfilePageComponent {
3891
3955
  placeholder="+1 234 567 8900" />
3892
3956
  </div>
3893
3957
 
3894
- <!-- Submit -->
3958
+ @if (editableFields().length > 0) {
3959
+ <div class="border-t border-surface pt-4 mt-2">
3960
+ <div class="text-sm font-medium text-muted-color mb-4">
3961
+ <i class="pi pi-pencil mr-2"></i>Additional Information
3962
+ </div>
3963
+ @if (isLoadingExtraFields()) {
3964
+ <p-skeleton height="2rem" styleClass="mb-2" />
3965
+ <p-skeleton height="2rem" />
3966
+ } @else {
3967
+ <div class="flex flex-col gap-4">
3968
+ @for (field of editableFields(); track field.key) {
3969
+ <div class="flex flex-col gap-2">
3970
+ <label [for]="field.key" class="font-medium text-color">
3971
+ {{ field.label }}{{ field.required ? ' *' : '' }}
3972
+ </label>
3973
+ @if (field.component) {
3974
+ <ng-container *ngComponentOutlet="field.component; injector: getFieldInjector(field)" />
3975
+ } @else if (field.template) {
3976
+ <ng-container [ngTemplateOutlet]="field.template" [ngTemplateOutletContext]="getFieldTemplateContext(field)" />
3977
+ } @else {
3978
+ <ng-container [ngTemplateOutlet]="fieldTemplate" [ngTemplateOutletContext]="{ field: field }" />
3979
+ }
3980
+ </div>
3981
+ }
3982
+ </div>
3983
+ @if (extraFieldsValidationError()) {
3984
+ <small class="text-danger block mt-2">{{ extraFieldsValidationError() }}</small>
3985
+ }
3986
+ }
3987
+ </div>
3988
+ }
3989
+
3990
+ @if (viewOnlyFields().length > 0) {
3991
+ <div class="border-t border-surface pt-4 mt-2">
3992
+ <div class="flex items-center justify-between mb-4">
3993
+ <div class="text-sm font-medium text-muted-color">
3994
+ <i class="pi pi-eye mr-2"></i>Employment Information
3995
+ </div>
3996
+ <p-tag value="Managed by Admin" severity="secondary" />
3997
+ </div>
3998
+ @if (isLoadingExtraFields()) {
3999
+ <p-skeleton height="2rem" styleClass="mb-2" />
4000
+ <p-skeleton height="2rem" />
4001
+ } @else {
4002
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
4003
+ @for (field of viewOnlyFields(); track field.key) {
4004
+ <div class="flex flex-col gap-1">
4005
+ <label class="text-sm text-muted-color">{{ field.label }}</label>
4006
+ <span class="text-color font-medium">
4007
+ @if (field.type === 'select') {
4008
+ {{ getSelectLabel(field, getExtraFieldValue(field.key)) }}
4009
+ } @else {
4010
+ {{ getExtraFieldValue(field.key) || '-' }}
4011
+ }
4012
+ </span>
4013
+ </div>
4014
+ }
4015
+ </div>
4016
+ }
4017
+ </div>
4018
+ }
4019
+
4020
+ <ng-template #fieldTemplate let-field="field">
4021
+ @switch (field.type) {
4022
+ @case ('text') {
4023
+ <input
4024
+ pInputText
4025
+ [id]="field.key"
4026
+ [placeholder]="field.placeholder ?? ''"
4027
+ [value]="getExtraFieldValue(field.key) ?? ''"
4028
+ [disabled]="field.editable === false"
4029
+ (input)="updateExtraField(field.key, $any($event.target).value)"
4030
+ class="w-full" />
4031
+ }
4032
+ @case ('number') {
4033
+ <input
4034
+ pInputText
4035
+ type="number"
4036
+ [id]="field.key"
4037
+ [placeholder]="field.placeholder ?? ''"
4038
+ [value]="getExtraFieldValue(field.key) ?? ''"
4039
+ [disabled]="field.editable === false"
4040
+ (input)="updateExtraField(field.key, $any($event.target).valueAsNumber)"
4041
+ class="w-full" />
4042
+ }
4043
+ @case ('textarea') {
4044
+ <textarea
4045
+ pInputTextarea
4046
+ [id]="field.key"
4047
+ [placeholder]="field.placeholder ?? ''"
4048
+ [value]="getExtraFieldValue(field.key) ?? ''"
4049
+ [disabled]="field.editable === false"
4050
+ (input)="updateExtraField(field.key, $any($event.target).value)"
4051
+ class="w-full"
4052
+ rows="3"></textarea>
4053
+ }
4054
+ @case ('select') {
4055
+ <select
4056
+ [id]="field.key"
4057
+ class="p-select-native w-full"
4058
+ [ngModel]="getExtraFieldValue(field.key) ?? ''"
4059
+ [ngModelOptions]="{standalone: true}"
4060
+ [disabled]="field.editable === false"
4061
+ (ngModelChange)="updateExtraField(field.key, $event)">
4062
+ <option value="">{{ field.placeholder ?? 'Select...' }}</option>
4063
+ @for (opt of field.options; track opt.value) {
4064
+ <option [value]="opt.value">{{ opt.label }}</option>
4065
+ }
4066
+ </select>
4067
+ }
4068
+ @case ('checkbox') {
4069
+ <label class="p-checkbox-native">
4070
+ <input
4071
+ type="checkbox"
4072
+ [id]="field.key"
4073
+ [checked]="getExtraFieldValue(field.key) ?? false"
4074
+ [disabled]="field.editable === false"
4075
+ (change)="updateExtraField(field.key, $any($event.target).checked)" />
4076
+ <span>{{ field.placeholder ?? field.label }}</span>
4077
+ </label>
4078
+ }
4079
+ @case ('date') {
4080
+ <input
4081
+ pInputText
4082
+ type="date"
4083
+ [id]="field.key"
4084
+ [value]="getExtraFieldValue(field.key) ?? ''"
4085
+ [disabled]="field.editable === false"
4086
+ (input)="updateExtraField(field.key, $any($event.target).value)"
4087
+ class="w-full" />
4088
+ }
4089
+ }
4090
+ </ng-template>
4091
+
3895
4092
  <div class="flex justify-end pt-4">
3896
4093
  <p-button
3897
4094
  label="Save Changes"
@@ -3905,7 +4102,6 @@ class ProfilePageComponent {
3905
4102
  </div>
3906
4103
  </div>
3907
4104
 
3908
- <!-- Security Card -->
3909
4105
  <div class="card mb-2 md:mb-4">
3910
4106
  <div class="flex items-center gap-2 mb-4">
3911
4107
  <i class="pi pi-lock text-primary"></i>
@@ -3913,7 +4109,6 @@ class ProfilePageComponent {
3913
4109
  </div>
3914
4110
  <form (ngSubmit)="onChangePassword()" class="flex flex-col gap-4">
3915
4111
  <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
3916
- <!-- Current Password -->
3917
4112
  <div class="flex flex-col gap-2">
3918
4113
  <label for="currentPassword" class="font-medium text-color">Current Password *</label>
3919
4114
  <p-password
@@ -3928,7 +4123,6 @@ class ProfilePageComponent {
3928
4123
  inputStyleClass="w-full" />
3929
4124
  </div>
3930
4125
 
3931
- <!-- New Password -->
3932
4126
  <div class="flex flex-col gap-2">
3933
4127
  <label for="newPassword" class="font-medium text-color">New Password *</label>
3934
4128
  <p-password
@@ -3943,7 +4137,6 @@ class ProfilePageComponent {
3943
4137
  inputStyleClass="w-full" />
3944
4138
  </div>
3945
4139
 
3946
- <!-- Confirm Password -->
3947
4140
  <div class="flex flex-col gap-2">
3948
4141
  <label for="confirmPassword" class="font-medium text-color">Confirm Password *</label>
3949
4142
  <p-password
@@ -3962,7 +4155,6 @@ class ProfilePageComponent {
3962
4155
  </div>
3963
4156
  </div>
3964
4157
 
3965
- <!-- Submit -->
3966
4158
  <div class="flex justify-end">
3967
4159
  <p-button
3968
4160
  label="Change Password"
@@ -3974,10 +4166,40 @@ class ProfilePageComponent {
3974
4166
  </form>
3975
4167
  </div>
3976
4168
 
3977
- <!-- Company & Permissions Row (50/50 on desktop, stacked on mobile) -->
4169
+ @for (section of extraSections(); track section.key) {
4170
+ @if (section.editPermission) {
4171
+ <div *hasPermission="section.editPermission" class="card mb-2 md:mb-4">
4172
+ <div class="flex items-center gap-2 mb-4">
4173
+ @if (section.icon) {
4174
+ <i [class]="section.icon + ' text-primary'"></i>
4175
+ }
4176
+ <span class="font-semibold text-color">{{ section.title }}</span>
4177
+ </div>
4178
+ <div class="section-content">
4179
+ @if (section.component) {
4180
+ <ng-container *ngComponentOutlet="section.component" />
4181
+ }
4182
+ </div>
4183
+ </div>
4184
+ } @else {
4185
+ <div class="card mb-2 md:mb-4">
4186
+ <div class="flex items-center gap-2 mb-4">
4187
+ @if (section.icon) {
4188
+ <i [class]="section.icon + ' text-primary'"></i>
4189
+ }
4190
+ <span class="font-semibold text-color">{{ section.title }}</span>
4191
+ </div>
4192
+ <div class="section-content">
4193
+ @if (section.component) {
4194
+ <ng-container *ngComponentOutlet="section.component" />
4195
+ }
4196
+ </div>
4197
+ </div>
4198
+ }
4199
+ }
4200
+
3978
4201
  @if (showBottomRow()) {
3979
4202
  <div class="grid grid-cols-1 md:grid-cols-2 gap-2 md:gap-4 flex-1">
3980
- <!-- Company/Branch Info -->
3981
4203
  @if (showCompanySection()) {
3982
4204
  <div class="card h-48 md:h-56 flex flex-col">
3983
4205
  <div class="flex items-center gap-2 mb-4">
@@ -4007,7 +4229,6 @@ class ProfilePageComponent {
4007
4229
  </div>
4008
4230
  }
4009
4231
 
4010
- <!-- Permissions -->
4011
4232
  @if (showPermissionsSection()) {
4012
4233
  <div class="card h-48 md:h-56 flex flex-col">
4013
4234
  <div class="flex items-center justify-between mb-4">
@@ -4018,7 +4239,6 @@ class ProfilePageComponent {
4018
4239
  <p-tag value="Read-only" severity="secondary" />
4019
4240
  </div>
4020
4241
  <div class="flex flex-col gap-4 flex-1 overflow-auto">
4021
- <!-- Roles -->
4022
4242
  @if (showRoles()) {
4023
4243
  <div>
4024
4244
  <div class="text-sm text-muted-color mb-2 flex items-center gap-2">
@@ -4038,7 +4258,6 @@ class ProfilePageComponent {
4038
4258
  </div>
4039
4259
  }
4040
4260
 
4041
- <!-- Actions -->
4042
4261
  @if (showActions()) {
4043
4262
  <div>
4044
4263
  <div class="text-sm text-muted-color mb-2 flex items-center gap-2">
@@ -4062,24 +4281,21 @@ class ProfilePageComponent {
4062
4281
  }
4063
4282
  </div>
4064
4283
  }
4065
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2$2.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: i5$1.Password, selector: "p-password", inputs: ["ariaLabel", "ariaLabelledBy", "label", "promptLabel", "mediumRegex", "strongRegex", "weakLabel", "mediumLabel", "maxLength", "strongLabel", "inputId", "feedback", "toggleMask", "inputStyleClass", "styleClass", "inputStyle", "showTransitionOptions", "hideTransitionOptions", "autocomplete", "placeholder", "showClear", "autofocus", "tabindex", "appendTo", "motionOptions", "overlayOptions"], outputs: ["onFocus", "onBlur", "onClear"] }, { kind: "component", type: i6.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: i4$2.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "component", type: FileUploaderComponent, selector: "lib-file-uploader", inputs: ["uploadFile", "acceptTypes", "multiple", "maxFiles", "maxSizeMb", "uploadOptions", "disabled", "showPreview", "autoUpload"], outputs: ["fileUploaded", "filesUploaded", "onError", "fileSelected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4284
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i3$1.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: i6$1.Password, selector: "p-password", inputs: ["ariaLabel", "ariaLabelledBy", "label", "promptLabel", "mediumRegex", "strongRegex", "weakLabel", "mediumLabel", "maxLength", "strongLabel", "inputId", "feedback", "toggleMask", "inputStyleClass", "styleClass", "inputStyle", "showTransitionOptions", "hideTransitionOptions", "autocomplete", "placeholder", "showClear", "autofocus", "tabindex", "appendTo", "motionOptions", "overlayOptions"], outputs: ["onFocus", "onBlur", "onClear"] }, { kind: "component", type: i7$1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: i6.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: i9.Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["pTextareaPT", "pTextareaUnstyled", "autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "component", type: FileUploaderComponent, selector: "lib-file-uploader", inputs: ["uploadFile", "acceptTypes", "multiple", "maxFiles", "maxSizeMb", "uploadOptions", "disabled", "showPreview", "autoUpload"], outputs: ["fileUploaded", "filesUploaded", "onError", "fileSelected"] }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4066
4285
  }
4067
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ProfilePageComponent, decorators: [{
4286
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: ProfilePageComponent, decorators: [{
4068
4287
  type: Component,
4069
4288
  args: [{
4070
4289
  selector: 'lib-profile-page',
4071
- imports: [AngularModule, PrimeModule, FormField, FileUploaderComponent],
4290
+ imports: [AngularModule, PrimeModule, FormField, FileUploaderComponent, HasPermissionDirective],
4072
4291
  template: `
4073
- <!-- Page Header -->
4074
4292
  <div class="mb-4 md:mb-6">
4075
4293
  <h1 class="text-2xl font-bold text-color mb-2">My Profile</h1>
4076
4294
  <p class="text-muted-color">Manage your account settings and preferences.</p>
4077
4295
  </div>
4078
4296
 
4079
- <!-- Profile Form Card (full width) -->
4080
4297
  <div class="card mb-2 md:mb-4">
4081
4298
  <div class="flex flex-col md:flex-row gap-4 md:gap-6">
4082
- <!-- Avatar Section -->
4083
4299
  <div class="flex flex-col items-center gap-4 md:w-72 lg:w-80 md:border-r md:border-surface-200 md:pr-6">
4084
4300
  @if (profilePictureUrl()) {
4085
4301
  <p-avatar
@@ -4098,7 +4314,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4098
4314
  <div class="font-semibold text-color">{{ userName() }}</div>
4099
4315
  <div class="text-muted-color text-sm">{{ userEmail() }}</div>
4100
4316
  </div>
4101
- <!-- Upload section - only show if storage is enabled and provider is available -->
4102
4317
  @if (showUploadSection()) {
4103
4318
  <lib-file-uploader
4104
4319
  [uploadFile]="uploadFileFn"
@@ -4116,10 +4331,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4116
4331
  }
4117
4332
  </div>
4118
4333
 
4119
- <!-- Form Section -->
4120
4334
  <div class="flex-1">
4121
4335
  <form (ngSubmit)="onSubmit()" class="flex flex-col gap-4">
4122
- <!-- Email (read-only) -->
4123
4336
  <div class="flex flex-col gap-2">
4124
4337
  <label class="font-medium text-color">Email</label>
4125
4338
  <input
@@ -4129,7 +4342,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4129
4342
  class="bg-surface-50" />
4130
4343
  </div>
4131
4344
 
4132
- <!-- Name -->
4133
4345
  <div class="flex flex-col gap-2">
4134
4346
  <label for="name" class="font-medium text-color">Name *</label>
4135
4347
  <input
@@ -4139,7 +4351,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4139
4351
  placeholder="Your full name" />
4140
4352
  </div>
4141
4353
 
4142
- <!-- Phone -->
4143
4354
  <div class="flex flex-col gap-2">
4144
4355
  <label for="phone" class="font-medium text-color">Phone</label>
4145
4356
  <input
@@ -4149,7 +4360,140 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4149
4360
  placeholder="+1 234 567 8900" />
4150
4361
  </div>
4151
4362
 
4152
- <!-- Submit -->
4363
+ @if (editableFields().length > 0) {
4364
+ <div class="border-t border-surface pt-4 mt-2">
4365
+ <div class="text-sm font-medium text-muted-color mb-4">
4366
+ <i class="pi pi-pencil mr-2"></i>Additional Information
4367
+ </div>
4368
+ @if (isLoadingExtraFields()) {
4369
+ <p-skeleton height="2rem" styleClass="mb-2" />
4370
+ <p-skeleton height="2rem" />
4371
+ } @else {
4372
+ <div class="flex flex-col gap-4">
4373
+ @for (field of editableFields(); track field.key) {
4374
+ <div class="flex flex-col gap-2">
4375
+ <label [for]="field.key" class="font-medium text-color">
4376
+ {{ field.label }}{{ field.required ? ' *' : '' }}
4377
+ </label>
4378
+ @if (field.component) {
4379
+ <ng-container *ngComponentOutlet="field.component; injector: getFieldInjector(field)" />
4380
+ } @else if (field.template) {
4381
+ <ng-container [ngTemplateOutlet]="field.template" [ngTemplateOutletContext]="getFieldTemplateContext(field)" />
4382
+ } @else {
4383
+ <ng-container [ngTemplateOutlet]="fieldTemplate" [ngTemplateOutletContext]="{ field: field }" />
4384
+ }
4385
+ </div>
4386
+ }
4387
+ </div>
4388
+ @if (extraFieldsValidationError()) {
4389
+ <small class="text-danger block mt-2">{{ extraFieldsValidationError() }}</small>
4390
+ }
4391
+ }
4392
+ </div>
4393
+ }
4394
+
4395
+ @if (viewOnlyFields().length > 0) {
4396
+ <div class="border-t border-surface pt-4 mt-2">
4397
+ <div class="flex items-center justify-between mb-4">
4398
+ <div class="text-sm font-medium text-muted-color">
4399
+ <i class="pi pi-eye mr-2"></i>Employment Information
4400
+ </div>
4401
+ <p-tag value="Managed by Admin" severity="secondary" />
4402
+ </div>
4403
+ @if (isLoadingExtraFields()) {
4404
+ <p-skeleton height="2rem" styleClass="mb-2" />
4405
+ <p-skeleton height="2rem" />
4406
+ } @else {
4407
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
4408
+ @for (field of viewOnlyFields(); track field.key) {
4409
+ <div class="flex flex-col gap-1">
4410
+ <label class="text-sm text-muted-color">{{ field.label }}</label>
4411
+ <span class="text-color font-medium">
4412
+ @if (field.type === 'select') {
4413
+ {{ getSelectLabel(field, getExtraFieldValue(field.key)) }}
4414
+ } @else {
4415
+ {{ getExtraFieldValue(field.key) || '-' }}
4416
+ }
4417
+ </span>
4418
+ </div>
4419
+ }
4420
+ </div>
4421
+ }
4422
+ </div>
4423
+ }
4424
+
4425
+ <ng-template #fieldTemplate let-field="field">
4426
+ @switch (field.type) {
4427
+ @case ('text') {
4428
+ <input
4429
+ pInputText
4430
+ [id]="field.key"
4431
+ [placeholder]="field.placeholder ?? ''"
4432
+ [value]="getExtraFieldValue(field.key) ?? ''"
4433
+ [disabled]="field.editable === false"
4434
+ (input)="updateExtraField(field.key, $any($event.target).value)"
4435
+ class="w-full" />
4436
+ }
4437
+ @case ('number') {
4438
+ <input
4439
+ pInputText
4440
+ type="number"
4441
+ [id]="field.key"
4442
+ [placeholder]="field.placeholder ?? ''"
4443
+ [value]="getExtraFieldValue(field.key) ?? ''"
4444
+ [disabled]="field.editable === false"
4445
+ (input)="updateExtraField(field.key, $any($event.target).valueAsNumber)"
4446
+ class="w-full" />
4447
+ }
4448
+ @case ('textarea') {
4449
+ <textarea
4450
+ pInputTextarea
4451
+ [id]="field.key"
4452
+ [placeholder]="field.placeholder ?? ''"
4453
+ [value]="getExtraFieldValue(field.key) ?? ''"
4454
+ [disabled]="field.editable === false"
4455
+ (input)="updateExtraField(field.key, $any($event.target).value)"
4456
+ class="w-full"
4457
+ rows="3"></textarea>
4458
+ }
4459
+ @case ('select') {
4460
+ <select
4461
+ [id]="field.key"
4462
+ class="p-select-native w-full"
4463
+ [ngModel]="getExtraFieldValue(field.key) ?? ''"
4464
+ [ngModelOptions]="{standalone: true}"
4465
+ [disabled]="field.editable === false"
4466
+ (ngModelChange)="updateExtraField(field.key, $event)">
4467
+ <option value="">{{ field.placeholder ?? 'Select...' }}</option>
4468
+ @for (opt of field.options; track opt.value) {
4469
+ <option [value]="opt.value">{{ opt.label }}</option>
4470
+ }
4471
+ </select>
4472
+ }
4473
+ @case ('checkbox') {
4474
+ <label class="p-checkbox-native">
4475
+ <input
4476
+ type="checkbox"
4477
+ [id]="field.key"
4478
+ [checked]="getExtraFieldValue(field.key) ?? false"
4479
+ [disabled]="field.editable === false"
4480
+ (change)="updateExtraField(field.key, $any($event.target).checked)" />
4481
+ <span>{{ field.placeholder ?? field.label }}</span>
4482
+ </label>
4483
+ }
4484
+ @case ('date') {
4485
+ <input
4486
+ pInputText
4487
+ type="date"
4488
+ [id]="field.key"
4489
+ [value]="getExtraFieldValue(field.key) ?? ''"
4490
+ [disabled]="field.editable === false"
4491
+ (input)="updateExtraField(field.key, $any($event.target).value)"
4492
+ class="w-full" />
4493
+ }
4494
+ }
4495
+ </ng-template>
4496
+
4153
4497
  <div class="flex justify-end pt-4">
4154
4498
  <p-button
4155
4499
  label="Save Changes"
@@ -4163,7 +4507,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4163
4507
  </div>
4164
4508
  </div>
4165
4509
 
4166
- <!-- Security Card -->
4167
4510
  <div class="card mb-2 md:mb-4">
4168
4511
  <div class="flex items-center gap-2 mb-4">
4169
4512
  <i class="pi pi-lock text-primary"></i>
@@ -4171,7 +4514,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4171
4514
  </div>
4172
4515
  <form (ngSubmit)="onChangePassword()" class="flex flex-col gap-4">
4173
4516
  <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
4174
- <!-- Current Password -->
4175
4517
  <div class="flex flex-col gap-2">
4176
4518
  <label for="currentPassword" class="font-medium text-color">Current Password *</label>
4177
4519
  <p-password
@@ -4186,7 +4528,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4186
4528
  inputStyleClass="w-full" />
4187
4529
  </div>
4188
4530
 
4189
- <!-- New Password -->
4190
4531
  <div class="flex flex-col gap-2">
4191
4532
  <label for="newPassword" class="font-medium text-color">New Password *</label>
4192
4533
  <p-password
@@ -4201,7 +4542,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4201
4542
  inputStyleClass="w-full" />
4202
4543
  </div>
4203
4544
 
4204
- <!-- Confirm Password -->
4205
4545
  <div class="flex flex-col gap-2">
4206
4546
  <label for="confirmPassword" class="font-medium text-color">Confirm Password *</label>
4207
4547
  <p-password
@@ -4220,7 +4560,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4220
4560
  </div>
4221
4561
  </div>
4222
4562
 
4223
- <!-- Submit -->
4224
4563
  <div class="flex justify-end">
4225
4564
  <p-button
4226
4565
  label="Change Password"
@@ -4232,10 +4571,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4232
4571
  </form>
4233
4572
  </div>
4234
4573
 
4235
- <!-- Company & Permissions Row (50/50 on desktop, stacked on mobile) -->
4574
+ @for (section of extraSections(); track section.key) {
4575
+ @if (section.editPermission) {
4576
+ <div *hasPermission="section.editPermission" class="card mb-2 md:mb-4">
4577
+ <div class="flex items-center gap-2 mb-4">
4578
+ @if (section.icon) {
4579
+ <i [class]="section.icon + ' text-primary'"></i>
4580
+ }
4581
+ <span class="font-semibold text-color">{{ section.title }}</span>
4582
+ </div>
4583
+ <div class="section-content">
4584
+ @if (section.component) {
4585
+ <ng-container *ngComponentOutlet="section.component" />
4586
+ }
4587
+ </div>
4588
+ </div>
4589
+ } @else {
4590
+ <div class="card mb-2 md:mb-4">
4591
+ <div class="flex items-center gap-2 mb-4">
4592
+ @if (section.icon) {
4593
+ <i [class]="section.icon + ' text-primary'"></i>
4594
+ }
4595
+ <span class="font-semibold text-color">{{ section.title }}</span>
4596
+ </div>
4597
+ <div class="section-content">
4598
+ @if (section.component) {
4599
+ <ng-container *ngComponentOutlet="section.component" />
4600
+ }
4601
+ </div>
4602
+ </div>
4603
+ }
4604
+ }
4605
+
4236
4606
  @if (showBottomRow()) {
4237
4607
  <div class="grid grid-cols-1 md:grid-cols-2 gap-2 md:gap-4 flex-1">
4238
- <!-- Company/Branch Info -->
4239
4608
  @if (showCompanySection()) {
4240
4609
  <div class="card h-48 md:h-56 flex flex-col">
4241
4610
  <div class="flex items-center gap-2 mb-4">
@@ -4265,7 +4634,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4265
4634
  </div>
4266
4635
  }
4267
4636
 
4268
- <!-- Permissions -->
4269
4637
  @if (showPermissionsSection()) {
4270
4638
  <div class="card h-48 md:h-56 flex flex-col">
4271
4639
  <div class="flex items-center justify-between mb-4">
@@ -4276,7 +4644,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4276
4644
  <p-tag value="Read-only" severity="secondary" />
4277
4645
  </div>
4278
4646
  <div class="flex flex-col gap-4 flex-1 overflow-auto">
4279
- <!-- Roles -->
4280
4647
  @if (showRoles()) {
4281
4648
  <div>
4282
4649
  <div class="text-sm text-muted-color mb-2 flex items-center gap-2">
@@ -4296,7 +4663,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4296
4663
  </div>
4297
4664
  }
4298
4665
 
4299
- <!-- Actions -->
4300
4666
  @if (showActions()) {
4301
4667
  <div>
4302
4668
  <div class="text-sm text-muted-color mb-2 flex items-center gap-2">
@@ -4338,11 +4704,33 @@ class RegisterPageComponent {
4338
4704
  authState = inject(AuthStateService);
4339
4705
  route = inject(ActivatedRoute);
4340
4706
  router = inject(Router);
4707
+ validationConfig = inject(AUTH_VALIDATION_CONFIG, {
4708
+ optional: true,
4709
+ });
4710
+ registrationExtension = inject(AUTH_REGISTRATION_EXTENSION, {
4711
+ optional: true,
4712
+ });
4341
4713
  queryParamMap = toSignal(this.route.queryParamMap);
4342
4714
  companySlugInitialized = false;
4343
4715
  returnUrl = input('', ...(ngDevMode ? [{ debugName: "returnUrl" }] : []));
4344
4716
  isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
4345
4717
  companyFeatureEnabled = computed(() => isCompanyFeatureEnabled(this.appConfig), ...(ngDevMode ? [{ debugName: "companyFeatureEnabled" }] : []));
4718
+ defaultCompanySlug = computed(() => getDefaultCompanySlug(this.appConfig), ...(ngDevMode ? [{ debugName: "defaultCompanySlug" }] : []));
4719
+ defaultBranchSlug = computed(() => getDefaultBranchSlug(this.appConfig), ...(ngDevMode ? [{ debugName: "defaultBranchSlug" }] : []));
4720
+ hasDefaultCompany = computed(() => !!this.defaultCompanySlug(), ...(ngDevMode ? [{ debugName: "hasDefaultCompany" }] : []));
4721
+ hasDefaultBranch = computed(() => !!this.defaultBranchSlug(), ...(ngDevMode ? [{ debugName: "hasDefaultBranch" }] : []));
4722
+ extraFields = computed(() => {
4723
+ if (!this.registrationExtension)
4724
+ return [];
4725
+ const fields = this.registrationExtension.getExtraFields();
4726
+ return fields.sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
4727
+ }, ...(ngDevMode ? [{ debugName: "extraFields" }] : []));
4728
+ extraFieldsModel = signal({}, ...(ngDevMode ? [{ debugName: "extraFieldsModel" }] : []));
4729
+ emailErrorMessage = computed(() => this.validationConfig?.email?.message ??
4730
+ 'Please enter a valid email address', ...(ngDevMode ? [{ debugName: "emailErrorMessage" }] : []));
4731
+ passwordMinLength = computed(() => this.validationConfig?.password?.minLength ?? 8, ...(ngDevMode ? [{ debugName: "passwordMinLength" }] : []));
4732
+ passwordErrorMessage = computed(() => this.validationConfig?.password?.message ??
4733
+ `Password must be at least ${this.passwordMinLength()} characters`, ...(ngDevMode ? [{ debugName: "passwordErrorMessage" }] : []));
4346
4734
  userFormModel = signal({
4347
4735
  name: '',
4348
4736
  email: '',
@@ -4354,10 +4742,10 @@ class RegisterPageComponent {
4354
4742
  required(f.name, { message: 'Name is required' });
4355
4743
  minLength(f.name, 2, { message: 'Name must be at least 2 characters' });
4356
4744
  required(f.email, { message: 'Email is required' });
4357
- email(f.email, { message: 'Please enter a valid email address' });
4745
+ email(f.email, { message: this.emailErrorMessage() });
4358
4746
  required(f.password, { message: 'Password is required' });
4359
- minLength(f.password, 8, {
4360
- message: 'Password must be at least 8 characters',
4747
+ minLength(f.password, this.passwordMinLength(), {
4748
+ message: this.passwordErrorMessage(),
4361
4749
  });
4362
4750
  required(f.confirmPassword, { message: 'Please confirm your password' });
4363
4751
  });
@@ -4369,35 +4757,106 @@ class RegisterPageComponent {
4369
4757
  newCompanyPhone: '',
4370
4758
  newCompanyAddress: '',
4371
4759
  }, ...(ngDevMode ? [{ debugName: "companyFormModel" }] : []));
4372
- companyForm = form(this.companyFormModel, (f) => { });
4760
+ companyForm = form(this.companyFormModel);
4761
+ emailValidationError = computed(() => {
4762
+ const email = this.userFormModel().email;
4763
+ if (!email)
4764
+ return null;
4765
+ return validateEmail(email, this.validationConfig?.email ?? undefined);
4766
+ }, ...(ngDevMode ? [{ debugName: "emailValidationError" }] : []));
4767
+ passwordValidationError = computed(() => {
4768
+ const password = this.userFormModel().password;
4769
+ if (!password)
4770
+ return null;
4771
+ if (!this.validationConfig?.password)
4772
+ return null;
4773
+ return validatePassword(password, this.validationConfig.password);
4774
+ }, ...(ngDevMode ? [{ debugName: "passwordValidationError" }] : []));
4775
+ extraFieldsValidationError = computed(() => {
4776
+ if (!this.registrationExtension?.validateExtraFields)
4777
+ return null;
4778
+ return this.registrationExtension.validateExtraFields(this.extraFieldsModel());
4779
+ }, ...(ngDevMode ? [{ debugName: "extraFieldsValidationError" }] : []));
4373
4780
  passwordsMatch = computed(() => {
4374
4781
  const model = this.userFormModel();
4375
4782
  return model.password === model.confirmPassword;
4376
4783
  }, ...(ngDevMode ? [{ debugName: "passwordsMatch" }] : []));
4377
4784
  isFormValid = computed(() => {
4378
4785
  const userModel = this.userFormModel();
4786
+ const emailError = this.emailValidationError();
4787
+ const passwordError = this.passwordValidationError();
4788
+ const extraFieldsError = this.extraFieldsValidationError();
4379
4789
  const userValid = userModel.name.trim().length >= 2 &&
4380
4790
  userModel.email.includes('@') &&
4381
- userModel.password.length >= 8 &&
4791
+ !emailError &&
4792
+ userModel.password.length >= this.passwordMinLength() &&
4793
+ !passwordError &&
4382
4794
  userModel.confirmPassword.length > 0 &&
4383
- this.passwordsMatch();
4795
+ this.passwordsMatch() &&
4796
+ !extraFieldsError;
4797
+ const extraFieldsValid = this.validateRequiredExtraFields();
4384
4798
  if (!isCompanyFeatureEnabled(this.appConfig))
4385
- return userValid;
4799
+ return userValid && extraFieldsValid;
4386
4800
  const companyModel = this.companyFormModel();
4387
4801
  if (companyModel.createNewCompany) {
4388
- return userValid && companyModel.newCompanyName.trim().length > 0;
4802
+ return (userValid &&
4803
+ extraFieldsValid &&
4804
+ companyModel.newCompanyName.trim().length > 0);
4389
4805
  }
4390
- return userValid;
4806
+ return userValid && extraFieldsValid;
4391
4807
  }, ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
4808
+ validateRequiredExtraFields() {
4809
+ const fields = this.extraFields();
4810
+ const values = this.extraFieldsModel();
4811
+ for (const field of fields) {
4812
+ if (field.required) {
4813
+ const value = values[field.key];
4814
+ if (value === undefined || value === null || value === '') {
4815
+ return false;
4816
+ }
4817
+ }
4818
+ }
4819
+ return true;
4820
+ }
4821
+ updateExtraField(key, value) {
4822
+ this.extraFieldsModel.update((model) => ({ ...model, [key]: value }));
4823
+ }
4824
+ getFieldTemplateContext(field) {
4825
+ return {
4826
+ field,
4827
+ value: this.extraFieldsModel()[field.key] ?? field.defaultValue,
4828
+ updateValue: (value) => this.updateExtraField(field.key, value),
4829
+ };
4830
+ }
4831
+ parentInjector = inject(Injector);
4832
+ getFieldInjector(field) {
4833
+ return Injector.create({
4834
+ providers: [
4835
+ {
4836
+ provide: REGISTRATION_FIELD_CONTEXT,
4837
+ useValue: this.getFieldTemplateContext(field),
4838
+ },
4839
+ ],
4840
+ parent: field.injector ?? this.parentInjector,
4841
+ });
4842
+ }
4392
4843
  constructor() {
4393
4844
  effect(() => {
4394
4845
  const params = this.queryParamMap();
4395
4846
  if (!params || this.companySlugInitialized)
4396
4847
  return;
4397
4848
  this.companySlugInitialized = true;
4398
- const companySlug = params.get('companySlug');
4399
- if (companySlug) {
4400
- this.companyFormModel.update((model) => ({ ...model, companySlug }));
4849
+ const configCompanySlug = this.defaultCompanySlug();
4850
+ const configBranchSlug = this.defaultBranchSlug();
4851
+ const queryCompanySlug = params.get('companySlug');
4852
+ const companySlug = configCompanySlug || queryCompanySlug || '';
4853
+ const branchSlug = configBranchSlug || '';
4854
+ if (companySlug || branchSlug) {
4855
+ this.companyFormModel.update((model) => ({
4856
+ ...model,
4857
+ companySlug,
4858
+ branchSlug,
4859
+ }));
4401
4860
  }
4402
4861
  });
4403
4862
  }
@@ -4433,24 +4892,32 @@ class RegisterPageComponent {
4433
4892
  this.isLoading.set(true);
4434
4893
  const userModel = this.userFormModel();
4435
4894
  const companyModel = this.companyFormModel();
4436
- const registrationData = {
4895
+ let registrationData = {
4437
4896
  name: userModel.name,
4438
4897
  email: userModel.email,
4439
4898
  password: userModel.password,
4440
4899
  phone: userModel.phone || undefined,
4441
4900
  };
4901
+ const extraFieldsData = this.extraFieldsModel();
4902
+ if (Object.keys(extraFieldsData).length > 0) {
4903
+ registrationData['additionalFields'] = extraFieldsData;
4904
+ }
4905
+ if (this.registrationExtension?.transformRegistrationData) {
4906
+ registrationData =
4907
+ this.registrationExtension.transformRegistrationData(registrationData);
4908
+ }
4442
4909
  if (isCompanyFeatureEnabled(this.appConfig)) {
4443
4910
  if (companyModel.createNewCompany) {
4444
- registrationData.newCompanyName =
4911
+ registrationData['newCompanyName'] =
4445
4912
  companyModel.newCompanyName || undefined;
4446
- registrationData.newCompanyPhone =
4913
+ registrationData['newCompanyPhone'] =
4447
4914
  companyModel.newCompanyPhone || undefined;
4448
- registrationData.newCompanyAddress =
4915
+ registrationData['newCompanyAddress'] =
4449
4916
  companyModel.newCompanyAddress || undefined;
4450
4917
  }
4451
4918
  else {
4452
- registrationData.companySlug = companyModel.companySlug || undefined;
4453
- registrationData.branchSlug = companyModel.branchSlug || undefined;
4919
+ registrationData['companySlug'] = companyModel.companySlug || undefined;
4920
+ registrationData['branchSlug'] = companyModel.branchSlug || undefined;
4454
4921
  }
4455
4922
  }
4456
4923
  this.authApi
@@ -4490,8 +4957,8 @@ class RegisterPageComponent {
4490
4957
  },
4491
4958
  });
4492
4959
  }
4493
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: RegisterPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4494
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: RegisterPageComponent, isStandalone: true, selector: "lib-register-page", inputs: { returnUrl: { classPropertyName: "returnUrl", publicName: "returnUrl", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
4960
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: RegisterPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4961
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: RegisterPageComponent, isStandalone: true, selector: "lib-register-page", inputs: { returnUrl: { classPropertyName: "returnUrl", publicName: "returnUrl", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
4495
4962
  <app-floating-configurator />
4496
4963
  <div
4497
4964
  class="bg-surface-ground flex items-center justify-center min-h-screen py-8"
@@ -4557,6 +5024,11 @@ class RegisterPageComponent {
4557
5024
  class="w-full"
4558
5025
  autocomplete="email"
4559
5026
  />
5027
+ @if (emailValidationError() && userFormModel().email) {
5028
+ <small class="text-danger block mt-1">{{
5029
+ emailValidationError()
5030
+ }}</small>
5031
+ }
4560
5032
  </div>
4561
5033
 
4562
5034
  <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
@@ -4569,10 +5041,15 @@ class RegisterPageComponent {
4569
5041
  id="password"
4570
5042
  type="password"
4571
5043
  [formField]="userForm.password"
4572
- placeholder="Min. 8 characters"
5044
+ placeholder="Min. {{ passwordMinLength() }} characters"
4573
5045
  class="w-full"
4574
5046
  autocomplete="new-password"
4575
5047
  />
5048
+ @if (passwordValidationError() && userFormModel().password) {
5049
+ <small class="text-danger block mt-1">{{
5050
+ passwordValidationError()
5051
+ }}</small>
5052
+ }
4576
5053
  </div>
4577
5054
 
4578
5055
  <div>
@@ -4596,29 +5073,193 @@ class RegisterPageComponent {
4596
5073
  </div>
4597
5074
  </div>
4598
5075
 
5076
+ @if (extraFields().length > 0) {
5077
+ <div class="border-t border-surface pt-4 mt-4 mb-4">
5078
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
5079
+ @for (field of extraFields(); track field.key) {
5080
+ <div [class]="field.containerClass ?? ''">
5081
+ <label [for]="field.key" class="block font-medium mb-2">
5082
+ {{ field.label }}{{ field.required ? ' *' : '' }}
5083
+ </label>
5084
+ @if (field.component) {
5085
+ <ng-container
5086
+ *ngComponentOutlet="field.component; injector: getFieldInjector(field)"
5087
+ ></ng-container>
5088
+ } @else if (field.template) {
5089
+ <ng-container
5090
+ [ngTemplateOutlet]="field.template"
5091
+ [ngTemplateOutletContext]="getFieldTemplateContext(field)"
5092
+ ></ng-container>
5093
+ } @else {
5094
+ @switch (field.type) {
5095
+ @case ('text') {
5096
+ <input
5097
+ pInputText
5098
+ [id]="field.key"
5099
+ [placeholder]="field.placeholder ?? ''"
5100
+ [value]="
5101
+ extraFieldsModel()[field.key] ??
5102
+ field.defaultValue ??
5103
+ ''
5104
+ "
5105
+ (input)="
5106
+ updateExtraField(
5107
+ field.key,
5108
+ $any($event.target).value
5109
+ )
5110
+ "
5111
+ class="w-full"
5112
+ />
5113
+ }
5114
+ @case ('number') {
5115
+ <input
5116
+ pInputText
5117
+ type="number"
5118
+ [id]="field.key"
5119
+ [placeholder]="field.placeholder ?? ''"
5120
+ [value]="
5121
+ extraFieldsModel()[field.key] ??
5122
+ field.defaultValue ??
5123
+ ''
5124
+ "
5125
+ (input)="
5126
+ updateExtraField(
5127
+ field.key,
5128
+ $any($event.target).valueAsNumber
5129
+ )
5130
+ "
5131
+ class="w-full"
5132
+ />
5133
+ }
5134
+ @case ('textarea') {
5135
+ <textarea
5136
+ pInputTextarea
5137
+ [id]="field.key"
5138
+ [placeholder]="field.placeholder ?? ''"
5139
+ [value]="
5140
+ extraFieldsModel()[field.key] ??
5141
+ field.defaultValue ??
5142
+ ''
5143
+ "
5144
+ (input)="
5145
+ updateExtraField(
5146
+ field.key,
5147
+ $any($event.target).value
5148
+ )
5149
+ "
5150
+ class="w-full"
5151
+ rows="3"
5152
+ ></textarea>
5153
+ }
5154
+ @case ('select') {
5155
+ <select
5156
+ [id]="field.key"
5157
+ class="p-select-native w-full"
5158
+ [value]="
5159
+ extraFieldsModel()[field.key] ??
5160
+ field.defaultValue ??
5161
+ ''
5162
+ "
5163
+ (change)="
5164
+ updateExtraField(
5165
+ field.key,
5166
+ $any($event.target).value
5167
+ )
5168
+ "
5169
+ >
5170
+ <option value="">
5171
+ {{ field.placeholder ?? 'Select...' }}
5172
+ </option>
5173
+ @for (opt of field.options; track opt.value) {
5174
+ <option [value]="opt.value">
5175
+ {{ opt.label }}
5176
+ </option>
5177
+ }
5178
+ </select>
5179
+ }
5180
+ @case ('checkbox') {
5181
+ <label class="p-checkbox-native">
5182
+ <input
5183
+ type="checkbox"
5184
+ [id]="field.key"
5185
+ [checked]="
5186
+ extraFieldsModel()[field.key] ??
5187
+ field.defaultValue ??
5188
+ false
5189
+ "
5190
+ (change)="
5191
+ updateExtraField(
5192
+ field.key,
5193
+ $any($event.target).checked
5194
+ )
5195
+ "
5196
+ />
5197
+ <span>{{
5198
+ field.placeholder ?? field.label
5199
+ }}</span>
5200
+ </label>
5201
+ }
5202
+ @case ('date') {
5203
+ <input
5204
+ pInputText
5205
+ type="date"
5206
+ [id]="field.key"
5207
+ [value]="
5208
+ extraFieldsModel()[field.key] ??
5209
+ field.defaultValue ??
5210
+ ''
5211
+ "
5212
+ (input)="
5213
+ updateExtraField(
5214
+ field.key,
5215
+ $any($event.target).value
5216
+ )
5217
+ "
5218
+ class="w-full"
5219
+ />
5220
+ }
5221
+ }
5222
+ }
5223
+ </div>
5224
+ }
5225
+ </div>
5226
+ @if (extraFieldsValidationError()) {
5227
+ <small class="text-danger block mt-2">{{
5228
+ extraFieldsValidationError()
5229
+ }}</small>
5230
+ }
5231
+ </div>
5232
+ }
5233
+
4599
5234
  @if (companyFeatureEnabled()) {
4600
5235
  <div class="border-t border-surface pt-6 mt-6">
4601
5236
  <div class="text-center mb-6">
4602
5237
  <div class="text-2xl font-medium mb-2 text-color">
4603
5238
  Company Details
4604
5239
  </div>
4605
- <span class="text-muted-color font-medium"
4606
- >Join existing or create new company</span
4607
- >
5240
+ <span class="text-muted-color font-medium">
5241
+ @if (hasDefaultCompany()) {
5242
+ You will join the default company
5243
+ } @else {
5244
+ Join existing or create new company
5245
+ }
5246
+ </span>
4608
5247
  </div>
4609
5248
 
4610
- <div class="mb-4">
4611
- <label
4612
- class="p-checkbox-native"
4613
- (click)="onCreateCompanyToggle()"
4614
- >
4615
- <input
4616
- type="checkbox"
4617
- [formField]="companyForm.createNewCompany"
4618
- />
4619
- <span>Create new company</span>
4620
- </label>
4621
- </div>
5249
+ @if (!hasDefaultCompany()) {
5250
+ <div class="mb-4">
5251
+ <label
5252
+ class="p-checkbox-native"
5253
+ (click)="onCreateCompanyToggle()"
5254
+ >
5255
+ <input
5256
+ type="checkbox"
5257
+ [formField]="companyForm.createNewCompany"
5258
+ />
5259
+ <span>Create new company</span>
5260
+ </label>
5261
+ </div>
5262
+ }
4622
5263
 
4623
5264
  @if (!companyFormModel().createNewCompany) {
4624
5265
  <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
@@ -4626,29 +5267,55 @@ class RegisterPageComponent {
4626
5267
  <label for="companySlug" class="block font-medium mb-2"
4627
5268
  >Company Code</label
4628
5269
  >
4629
- <input
4630
- pInputText
4631
- id="companySlug"
4632
- [formField]="companyForm.companySlug"
4633
- placeholder="Company code/slug"
4634
- class="w-full"
4635
- />
4636
- <small class="text-muted-color"
4637
- >Enter company code to join</small
4638
- >
5270
+ @if (hasDefaultCompany()) {
5271
+ <input
5272
+ pInputText
5273
+ id="companySlug"
5274
+ [value]="defaultCompanySlug()"
5275
+ class="w-full bg-surface-100"
5276
+ readonly
5277
+ />
5278
+ <small class="text-muted-color"
5279
+ >Pre-configured company</small
5280
+ >
5281
+ } @else {
5282
+ <input
5283
+ pInputText
5284
+ id="companySlug"
5285
+ [formField]="companyForm.companySlug"
5286
+ placeholder="Company code/slug"
5287
+ class="w-full"
5288
+ />
5289
+ <small class="text-muted-color"
5290
+ >Enter company code to join</small
5291
+ >
5292
+ }
4639
5293
  </div>
4640
5294
 
4641
5295
  <div>
4642
5296
  <label for="branchSlug" class="block font-medium mb-2"
4643
5297
  >Branch Code</label
4644
5298
  >
4645
- <input
4646
- pInputText
4647
- id="branchSlug"
4648
- [formField]="companyForm.branchSlug"
4649
- placeholder="Branch code (optional)"
4650
- class="w-full"
4651
- />
5299
+ @if (hasDefaultBranch()) {
5300
+ <input
5301
+ pInputText
5302
+ id="branchSlug"
5303
+ [value]="defaultBranchSlug()"
5304
+ class="w-full bg-surface-100"
5305
+ readonly
5306
+ />
5307
+ <small class="text-muted-color"
5308
+ >Pre-configured branch</small
5309
+ >
5310
+ } @else {
5311
+ <input
5312
+ pInputText
5313
+ id="branchSlug"
5314
+ [formField]="companyForm.branchSlug"
5315
+ placeholder="Branch code (optional)"
5316
+ class="w-full"
5317
+ />
5318
+ }
4652
5319
  </div>
4653
5320
  </div>
4654
5321
  } @else {
@@ -4722,9 +5389,9 @@ class RegisterPageComponent {
4722
5389
  </div>
4723
5390
  </div>
4724
5391
  </div>
4725
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "component", type: AppFloatingConfigurator, selector: "app-floating-configurator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5392
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: i9.Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["pTextareaPT", "pTextareaUnstyled", "autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "component", type: AppFloatingConfigurator, selector: "app-floating-configurator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4726
5393
  }
4727
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: RegisterPageComponent, decorators: [{
5394
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: RegisterPageComponent, decorators: [{
4728
5395
  type: Component,
4729
5396
  args: [{
4730
5397
  selector: 'lib-register-page',
@@ -4796,6 +5463,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4796
5463
  class="w-full"
4797
5464
  autocomplete="email"
4798
5465
  />
5466
+ @if (emailValidationError() && userFormModel().email) {
5467
+ <small class="text-danger block mt-1">{{
5468
+ emailValidationError()
5469
+ }}</small>
5470
+ }
4799
5471
  </div>
4800
5472
 
4801
5473
  <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
@@ -4808,10 +5480,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4808
5480
  id="password"
4809
5481
  type="password"
4810
5482
  [formField]="userForm.password"
4811
- placeholder="Min. 8 characters"
5483
+ placeholder="Min. {{ passwordMinLength() }} characters"
4812
5484
  class="w-full"
4813
5485
  autocomplete="new-password"
4814
5486
  />
5487
+ @if (passwordValidationError() && userFormModel().password) {
5488
+ <small class="text-danger block mt-1">{{
5489
+ passwordValidationError()
5490
+ }}</small>
5491
+ }
4815
5492
  </div>
4816
5493
 
4817
5494
  <div>
@@ -4835,29 +5512,193 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4835
5512
  </div>
4836
5513
  </div>
4837
5514
 
5515
+ @if (extraFields().length > 0) {
5516
+ <div class="border-t border-surface pt-4 mt-4 mb-4">
5517
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
5518
+ @for (field of extraFields(); track field.key) {
5519
+ <div [class]="field.containerClass ?? ''">
5520
+ <label [for]="field.key" class="block font-medium mb-2">
5521
+ {{ field.label }}{{ field.required ? ' *' : '' }}
5522
+ </label>
5523
+ @if (field.component) {
5524
+ <ng-container
5525
+ *ngComponentOutlet="field.component; injector: getFieldInjector(field)"
5526
+ ></ng-container>
5527
+ } @else if (field.template) {
5528
+ <ng-container
5529
+ [ngTemplateOutlet]="field.template"
5530
+ [ngTemplateOutletContext]="getFieldTemplateContext(field)"
5531
+ ></ng-container>
5532
+ } @else {
5533
+ @switch (field.type) {
5534
+ @case ('text') {
5535
+ <input
5536
+ pInputText
5537
+ [id]="field.key"
5538
+ [placeholder]="field.placeholder ?? ''"
5539
+ [value]="
5540
+ extraFieldsModel()[field.key] ??
5541
+ field.defaultValue ??
5542
+ ''
5543
+ "
5544
+ (input)="
5545
+ updateExtraField(
5546
+ field.key,
5547
+ $any($event.target).value
5548
+ )
5549
+ "
5550
+ class="w-full"
5551
+ />
5552
+ }
5553
+ @case ('number') {
5554
+ <input
5555
+ pInputText
5556
+ type="number"
5557
+ [id]="field.key"
5558
+ [placeholder]="field.placeholder ?? ''"
5559
+ [value]="
5560
+ extraFieldsModel()[field.key] ??
5561
+ field.defaultValue ??
5562
+ ''
5563
+ "
5564
+ (input)="
5565
+ updateExtraField(
5566
+ field.key,
5567
+ $any($event.target).valueAsNumber
5568
+ )
5569
+ "
5570
+ class="w-full"
5571
+ />
5572
+ }
5573
+ @case ('textarea') {
5574
+ <textarea
5575
+ pInputTextarea
5576
+ [id]="field.key"
5577
+ [placeholder]="field.placeholder ?? ''"
5578
+ [value]="
5579
+ extraFieldsModel()[field.key] ??
5580
+ field.defaultValue ??
5581
+ ''
5582
+ "
5583
+ (input)="
5584
+ updateExtraField(
5585
+ field.key,
5586
+ $any($event.target).value
5587
+ )
5588
+ "
5589
+ class="w-full"
5590
+ rows="3"
5591
+ ></textarea>
5592
+ }
5593
+ @case ('select') {
5594
+ <select
5595
+ [id]="field.key"
5596
+ class="p-select-native w-full"
5597
+ [value]="
5598
+ extraFieldsModel()[field.key] ??
5599
+ field.defaultValue ??
5600
+ ''
5601
+ "
5602
+ (change)="
5603
+ updateExtraField(
5604
+ field.key,
5605
+ $any($event.target).value
5606
+ )
5607
+ "
5608
+ >
5609
+ <option value="">
5610
+ {{ field.placeholder ?? 'Select...' }}
5611
+ </option>
5612
+ @for (opt of field.options; track opt.value) {
5613
+ <option [value]="opt.value">
5614
+ {{ opt.label }}
5615
+ </option>
5616
+ }
5617
+ </select>
5618
+ }
5619
+ @case ('checkbox') {
5620
+ <label class="p-checkbox-native">
5621
+ <input
5622
+ type="checkbox"
5623
+ [id]="field.key"
5624
+ [checked]="
5625
+ extraFieldsModel()[field.key] ??
5626
+ field.defaultValue ??
5627
+ false
5628
+ "
5629
+ (change)="
5630
+ updateExtraField(
5631
+ field.key,
5632
+ $any($event.target).checked
5633
+ )
5634
+ "
5635
+ />
5636
+ <span>{{
5637
+ field.placeholder ?? field.label
5638
+ }}</span>
5639
+ </label>
5640
+ }
5641
+ @case ('date') {
5642
+ <input
5643
+ pInputText
5644
+ type="date"
5645
+ [id]="field.key"
5646
+ [value]="
5647
+ extraFieldsModel()[field.key] ??
5648
+ field.defaultValue ??
5649
+ ''
5650
+ "
5651
+ (input)="
5652
+ updateExtraField(
5653
+ field.key,
5654
+ $any($event.target).value
5655
+ )
5656
+ "
5657
+ class="w-full"
5658
+ />
5659
+ }
5660
+ }
5661
+ }
5662
+ </div>
5663
+ }
5664
+ </div>
5665
+ @if (extraFieldsValidationError()) {
5666
+ <small class="text-danger block mt-2">{{
5667
+ extraFieldsValidationError()
5668
+ }}</small>
5669
+ }
5670
+ </div>
5671
+ }
5672
+
4838
5673
  @if (companyFeatureEnabled()) {
4839
5674
  <div class="border-t border-surface pt-6 mt-6">
4840
5675
  <div class="text-center mb-6">
4841
5676
  <div class="text-2xl font-medium mb-2 text-color">
4842
5677
  Company Details
4843
5678
  </div>
4844
- <span class="text-muted-color font-medium"
4845
- >Join existing or create new company</span
4846
- >
5679
+ <span class="text-muted-color font-medium">
5680
+ @if (hasDefaultCompany()) {
5681
+ You will join the default company
5682
+ } @else {
5683
+ Join existing or create new company
5684
+ }
5685
+ </span>
4847
5686
  </div>
4848
5687
 
4849
- <div class="mb-4">
4850
- <label
4851
- class="p-checkbox-native"
4852
- (click)="onCreateCompanyToggle()"
4853
- >
4854
- <input
4855
- type="checkbox"
4856
- [formField]="companyForm.createNewCompany"
4857
- />
4858
- <span>Create new company</span>
4859
- </label>
4860
- </div>
5688
+ @if (!hasDefaultCompany()) {
5689
+ <div class="mb-4">
5690
+ <label
5691
+ class="p-checkbox-native"
5692
+ (click)="onCreateCompanyToggle()"
5693
+ >
5694
+ <input
5695
+ type="checkbox"
5696
+ [formField]="companyForm.createNewCompany"
5697
+ />
5698
+ <span>Create new company</span>
5699
+ </label>
5700
+ </div>
5701
+ }
4861
5702
 
4862
5703
  @if (!companyFormModel().createNewCompany) {
4863
5704
  <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
@@ -4865,29 +5706,55 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
4865
5706
  <label for="companySlug" class="block font-medium mb-2"
4866
5707
  >Company Code</label
4867
5708
  >
4868
- <input
4869
- pInputText
4870
- id="companySlug"
4871
- [formField]="companyForm.companySlug"
4872
- placeholder="Company code/slug"
4873
- class="w-full"
4874
- />
4875
- <small class="text-muted-color"
4876
- >Enter company code to join</small
4877
- >
5709
+ @if (hasDefaultCompany()) {
5710
+ <input
5711
+ pInputText
5712
+ id="companySlug"
5713
+ [value]="defaultCompanySlug()"
5714
+ class="w-full bg-surface-100"
5715
+ readonly
5716
+ />
5717
+ <small class="text-muted-color"
5718
+ >Pre-configured company</small
5719
+ >
5720
+ } @else {
5721
+ <input
5722
+ pInputText
5723
+ id="companySlug"
5724
+ [formField]="companyForm.companySlug"
5725
+ placeholder="Company code/slug"
5726
+ class="w-full"
5727
+ />
5728
+ <small class="text-muted-color"
5729
+ >Enter company code to join</small
5730
+ >
5731
+ }
4878
5732
  </div>
4879
5733
 
4880
5734
  <div>
4881
5735
  <label for="branchSlug" class="block font-medium mb-2"
4882
5736
  >Branch Code</label
4883
5737
  >
4884
- <input
4885
- pInputText
4886
- id="branchSlug"
4887
- [formField]="companyForm.branchSlug"
4888
- placeholder="Branch code (optional)"
4889
- class="w-full"
4890
- />
5738
+ @if (hasDefaultBranch()) {
5739
+ <input
5740
+ pInputText
5741
+ id="branchSlug"
5742
+ [value]="defaultBranchSlug()"
5743
+ class="w-full bg-surface-100"
5744
+ readonly
5745
+ />
5746
+ <small class="text-muted-color"
5747
+ >Pre-configured branch</small
5748
+ >
5749
+ } @else {
5750
+ <input
5751
+ pInputText
5752
+ id="branchSlug"
5753
+ [formField]="companyForm.branchSlug"
5754
+ placeholder="Branch code (optional)"
5755
+ class="w-full"
5756
+ />
5757
+ }
4891
5758
  </div>
4892
5759
  </div>
4893
5760
  } @else {
@@ -5036,8 +5903,8 @@ class ResetPasswordPageComponent {
5036
5903
  },
5037
5904
  });
5038
5905
  }
5039
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ResetPasswordPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5040
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ResetPasswordPageComponent, isStandalone: true, selector: "lib-reset-password-page", ngImport: i0, template: `
5906
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: ResetPasswordPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5907
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: ResetPasswordPageComponent, isStandalone: true, selector: "lib-reset-password-page", ngImport: i0, template: `
5041
5908
  <app-floating-configurator />
5042
5909
  <div class="bg-surface-ground flex items-center justify-center min-h-screen">
5043
5910
  <div class="flex flex-col items-center justify-center w-full max-w-[32rem] px-4">
@@ -5148,9 +6015,9 @@ class ResetPasswordPageComponent {
5148
6015
  </div>
5149
6016
  </div>
5150
6017
  </div>
5151
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "component", type: AppFloatingConfigurator, selector: "app-floating-configurator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6018
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "component", type: AppFloatingConfigurator, selector: "app-floating-configurator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5152
6019
  }
5153
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ResetPasswordPageComponent, decorators: [{
6020
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: ResetPasswordPageComponent, decorators: [{
5154
6021
  type: Component,
5155
6022
  args: [{
5156
6023
  selector: 'lib-reset-password-page',
@@ -5458,8 +6325,8 @@ class UserFormComponent {
5458
6325
  onCancel() {
5459
6326
  this.router.navigate(['/administration/users']);
5460
6327
  }
5461
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5462
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: UserFormComponent, isStandalone: true, selector: "lib-user-form", ngImport: i0, template: `
6328
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6329
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: UserFormComponent, isStandalone: true, selector: "lib-user-form", ngImport: i0, template: `
5463
6330
  <p-card>
5464
6331
  <ng-template #header>
5465
6332
  <div class="flex justify-between items-center p-4">
@@ -5561,9 +6428,9 @@ class UserFormComponent {
5561
6428
  </div>
5562
6429
  </form>
5563
6430
  </p-card>
5564
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6431
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5565
6432
  }
5566
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserFormComponent, decorators: [{
6433
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserFormComponent, decorators: [{
5567
6434
  type: Component,
5568
6435
  args: [{
5569
6436
  selector: 'lib-user-form',
@@ -5771,8 +6638,8 @@ class UserCompanyPermissionDialogComponent {
5771
6638
  onClose() {
5772
6639
  this.closed.emit();
5773
6640
  }
5774
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserCompanyPermissionDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5775
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: UserCompanyPermissionDialogComponent, isStandalone: true, selector: "lib-user-company-permission-dialog", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: true, transformFunction: null }, user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { closed: "closed", permissionsChanged: "permissionsChanged" }, ngImport: i0, template: `
6641
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserCompanyPermissionDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6642
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: UserCompanyPermissionDialogComponent, isStandalone: true, selector: "lib-user-company-permission-dialog", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: true, transformFunction: null }, user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { closed: "closed", permissionsChanged: "permissionsChanged" }, ngImport: i0, template: `
5776
6643
  <p-dialog
5777
6644
  [visible]="visible()"
5778
6645
  [modal]="true"
@@ -5823,9 +6690,9 @@ class UserCompanyPermissionDialogComponent {
5823
6690
  [disabled]="isSaving()" />
5824
6691
  </ng-template>
5825
6692
  </p-dialog>
5826
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3$2.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "component", type: i4$3.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "component", type: i5$2.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6693
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3$2.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "component", type: i4$2.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "component", type: i5$1.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: ProgressSpinnerModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5827
6694
  }
5828
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserCompanyPermissionDialogComponent, decorators: [{
6695
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserCompanyPermissionDialogComponent, decorators: [{
5829
6696
  type: Component,
5830
6697
  args: [{
5831
6698
  selector: 'lib-user-company-permission-dialog',
@@ -6003,8 +6870,8 @@ class UserBranchPermissionDialogComponent {
6003
6870
  onClose() {
6004
6871
  this.closed.emit();
6005
6872
  }
6006
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserBranchPermissionDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6007
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: UserBranchPermissionDialogComponent, isStandalone: true, selector: "lib-user-branch-permission-dialog", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: true, transformFunction: null }, user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { closed: "closed", permissionsChanged: "permissionsChanged" }, ngImport: i0, template: `
6873
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserBranchPermissionDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6874
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: UserBranchPermissionDialogComponent, isStandalone: true, selector: "lib-user-branch-permission-dialog", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: true, transformFunction: null }, user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { closed: "closed", permissionsChanged: "permissionsChanged" }, ngImport: i0, template: `
6008
6875
  <p-dialog
6009
6876
  [visible]="visible()"
6010
6877
  [modal]="true"
@@ -6074,9 +6941,9 @@ class UserBranchPermissionDialogComponent {
6074
6941
  [disabled]="isSaving()" />
6075
6942
  </ng-template>
6076
6943
  </p-dialog>
6077
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3$2.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "component", type: i4$3.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "component", type: i4$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "component", type: i5$2.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6944
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3$2.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "component", type: i4$2.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "component", type: i4$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i5$1.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: ProgressSpinnerModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6078
6945
  }
6079
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserBranchPermissionDialogComponent, decorators: [{
6946
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserBranchPermissionDialogComponent, decorators: [{
6080
6947
  type: Component,
6081
6948
  args: [{
6082
6949
  selector: 'lib-user-branch-permission-dialog',
@@ -6156,31 +7023,71 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
6156
7023
  }]
6157
7024
  }], ctorParameters: () => [], propDecorators: { visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: true }] }], user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: true }] }], closed: [{ type: i0.Output, args: ["closed"] }], permissionsChanged: [{ type: i0.Output, args: ["permissionsChanged"] }] } });
6158
7025
 
6159
- /**
6160
- * User List Component
6161
- * Displays a list of users with CRUD operations.
6162
- */
6163
7026
  class UserListComponent {
6164
- // Permission constants for template
6165
7027
  USER_PERMISSIONS = USER_PERMISSIONS;
6166
7028
  router = inject(Router);
6167
7029
  appConfig = inject(APP_CONFIG);
6168
7030
  messageService = inject(MessageService);
6169
7031
  confirmationService = inject(ConfirmationService);
6170
7032
  userService = inject(UserApiService);
6171
- /** Users from service */
7033
+ userListExtension = inject(AUTH_USER_LIST_EXTENSION, { optional: true });
7034
+ userDetailConfig = inject(AUTH_USER_DETAIL_CONFIG, { optional: true });
6172
7035
  users = this.userService.data;
6173
- /** Loading state from service */
6174
7036
  isLoading = this.userService.isLoading;
6175
- /** Total count from service */
6176
7037
  total = this.userService.total;
6177
- /** Whether company feature is enabled */
6178
7038
  companyFeatureEnabled = computed(() => isCompanyFeatureEnabled(this.appConfig), ...(ngDevMode ? [{ debugName: "companyFeatureEnabled" }] : []));
6179
- /** Dialog visibility */
7039
+ extraColumns = computed(() => {
7040
+ if (!this.userListExtension)
7041
+ return [];
7042
+ const columns = this.userListExtension.getExtraColumns();
7043
+ return columns.sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
7044
+ }, ...(ngDevMode ? [{ debugName: "extraColumns" }] : []));
7045
+ extraActions = computed(() => {
7046
+ if (!this.userListExtension)
7047
+ return [];
7048
+ const actions = this.userListExtension.getExtraActions();
7049
+ return actions.sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
7050
+ }, ...(ngDevMode ? [{ debugName: "extraActions" }] : []));
7051
+ hasUserDetailView = computed(() => !!this.userDetailConfig, ...(ngDevMode ? [{ debugName: "hasUserDetailView" }] : []));
7052
+ tableColspan = computed(() => 6 + this.extraColumns().length, ...(ngDevMode ? [{ debugName: "tableColspan" }] : []));
6180
7053
  showCompanyDialog = signal(false, ...(ngDevMode ? [{ debugName: "showCompanyDialog" }] : []));
6181
7054
  showBranchDialog = signal(false, ...(ngDevMode ? [{ debugName: "showBranchDialog" }] : []));
6182
- /** Selected user for permission management */
7055
+ showUserDetailDialog = signal(false, ...(ngDevMode ? [{ debugName: "showUserDetailDialog" }] : []));
6183
7056
  selectedUser = signal(null, ...(ngDevMode ? [{ debugName: "selectedUser" }] : []));
7057
+ getFieldValue(user, field) {
7058
+ const parts = field.split('.');
7059
+ let value = user;
7060
+ for (const part of parts) {
7061
+ if (value === null || value === undefined)
7062
+ return undefined;
7063
+ value = value[part];
7064
+ }
7065
+ return value;
7066
+ }
7067
+ isActionVisible(action, user) {
7068
+ return action.isVisible ? action.isVisible(user) : true;
7069
+ }
7070
+ isActionDisabled(action, user) {
7071
+ return action.isDisabled ? action.isDisabled(user) : false;
7072
+ }
7073
+ onExtraAction(action, user) {
7074
+ action.onClick(user);
7075
+ }
7076
+ onViewDetails(user) {
7077
+ if (!this.userDetailConfig)
7078
+ return;
7079
+ if (this.userDetailConfig.viewMode === 'page') {
7080
+ this.router.navigate(['/administration/users', user.id]);
7081
+ }
7082
+ else {
7083
+ this.selectedUser.set(user);
7084
+ this.showUserDetailDialog.set(true);
7085
+ }
7086
+ }
7087
+ closeUserDetailDialog() {
7088
+ this.showUserDetailDialog.set(false);
7089
+ this.selectedUser.set(null);
7090
+ }
6184
7091
  loadUsers() {
6185
7092
  this.userService.fetchList('', {
6186
7093
  pagination: { currentPage: 0, pageSize: 10 },
@@ -6232,8 +7139,8 @@ class UserListComponent {
6232
7139
  },
6233
7140
  });
6234
7141
  }
6235
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6236
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: UserListComponent, isStandalone: true, selector: "lib-user-list", ngImport: i0, template: `
7142
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7143
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: UserListComponent, isStandalone: true, selector: "lib-user-list", ngImport: i0, template: `
6237
7144
  <p-card>
6238
7145
  <ng-template #header>
6239
7146
  <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 p-4">
@@ -6261,7 +7168,12 @@ class UserListComponent {
6261
7168
  <th>Phone</th>
6262
7169
  <th>Email Verified</th>
6263
7170
  <th>Status</th>
6264
- <th class="w-[150px]">Actions</th>
7171
+ @for (col of extraColumns(); track col.key) {
7172
+ <th [class]="col.styleClass ?? ''" [style.width]="col.width ?? 'auto'">
7173
+ {{ col.header }}
7174
+ </th>
7175
+ }
7176
+ <th class="w-[180px]">Actions</th>
6265
7177
  </tr>
6266
7178
  </ng-template>
6267
7179
  <ng-template #body let-user>
@@ -6279,8 +7191,26 @@ class UserListComponent {
6279
7191
  [value]="user.isActive ? 'Active' : 'Inactive'"
6280
7192
  [severity]="user.isActive ? 'success' : 'danger'" />
6281
7193
  </td>
7194
+ @for (col of extraColumns(); track col.key) {
7195
+ <td [class]="col.styleClass ?? ''">
7196
+ @if (col.template) {
7197
+ <ng-container [ngTemplateOutlet]="col.template" [ngTemplateOutletContext]="{ $implicit: user }" />
7198
+ } @else if (col.field) {
7199
+ {{ getFieldValue(user, col.field) ?? '-' }}
7200
+ }
7201
+ </td>
7202
+ }
6282
7203
  <td>
6283
- <div class="flex gap-2">
7204
+ <div class="flex gap-1 flex-wrap">
7205
+ @if (hasUserDetailView()) {
7206
+ <p-button
7207
+ icon="pi pi-eye"
7208
+ [rounded]="true"
7209
+ [text]="true"
7210
+ severity="info"
7211
+ pTooltip="View Details"
7212
+ (onClick)="onViewDetails(user)" />
7213
+ }
6284
7214
  <p-button
6285
7215
  *hasPermission="USER_PERMISSIONS.UPDATE"
6286
7216
  icon="pi pi-pencil"
@@ -6307,6 +7237,18 @@ class UserListComponent {
6307
7237
  pTooltip="Branch Permissions"
6308
7238
  (onClick)="onManageBranchPermissions(user)" />
6309
7239
  }
7240
+ @for (action of extraActions(); track action.key) {
7241
+ @if (isActionVisible(action, user)) {
7242
+ <p-button
7243
+ [icon]="action.icon"
7244
+ [rounded]="true"
7245
+ [text]="true"
7246
+ [severity]="action.severity ?? 'secondary'"
7247
+ [pTooltip]="action.label"
7248
+ [disabled]="isActionDisabled(action, user)"
7249
+ (onClick)="onExtraAction(action, user)" />
7250
+ }
7251
+ }
6310
7252
  <p-button
6311
7253
  *hasPermission="USER_PERMISSIONS.DELETE"
6312
7254
  icon="pi pi-trash"
@@ -6321,7 +7263,7 @@ class UserListComponent {
6321
7263
  </ng-template>
6322
7264
  <ng-template #emptymessage>
6323
7265
  <tr>
6324
- <td colspan="6" class="text-center py-8">
7266
+ <td [attr.colspan]="tableColspan()" class="text-center py-8">
6325
7267
  No users found. Click "Add User" to create one.
6326
7268
  </td>
6327
7269
  </tr>
@@ -6330,7 +7272,6 @@ class UserListComponent {
6330
7272
  </div>
6331
7273
  </p-card>
6332
7274
 
6333
- <!-- Permission Dialogs -->
6334
7275
  @if (companyFeatureEnabled()) {
6335
7276
  <lib-user-company-permission-dialog
6336
7277
  [visible]="showCompanyDialog()"
@@ -6344,9 +7285,68 @@ class UserListComponent {
6344
7285
  (closed)="showBranchDialog.set(false)"
6345
7286
  (permissionsChanged)="loadUsers()" />
6346
7287
  }
6347
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: i3$1.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "component", type: i4$2.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: TagModule }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }, { kind: "component", type: UserCompanyPermissionDialogComponent, selector: "lib-user-company-permission-dialog", inputs: ["visible", "user"], outputs: ["closed", "permissionsChanged"] }, { kind: "component", type: UserBranchPermissionDialogComponent, selector: "lib-user-branch-permission-dialog", inputs: ["visible", "user"], outputs: ["closed", "permissionsChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7288
+
7289
+ @if (hasUserDetailView() && showUserDetailDialog()) {
7290
+ <p-dialog
7291
+ header="User Details"
7292
+ [visible]="showUserDetailDialog()"
7293
+ [modal]="true"
7294
+ [style]="{ width: userDetailConfig?.width ?? '600px' }"
7295
+ [draggable]="false"
7296
+ [resizable]="false"
7297
+ (onHide)="closeUserDetailDialog()">
7298
+ @if (selectedUser(); as user) {
7299
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
7300
+ <div class="flex flex-col gap-2">
7301
+ <label class="font-medium text-muted-color">Name</label>
7302
+ <span class="text-color">{{ user.name }}</span>
7303
+ </div>
7304
+ <div class="flex flex-col gap-2">
7305
+ <label class="font-medium text-muted-color">Email</label>
7306
+ <span class="text-color">{{ user.email }}</span>
7307
+ </div>
7308
+ <div class="flex flex-col gap-2">
7309
+ <label class="font-medium text-muted-color">Phone</label>
7310
+ <span class="text-color">{{ user.phone || '-' }}</span>
7311
+ </div>
7312
+ <div class="flex flex-col gap-2">
7313
+ <label class="font-medium text-muted-color">Status</label>
7314
+ <p-tag
7315
+ [value]="user.isActive ? 'Active' : 'Inactive'"
7316
+ [severity]="user.isActive ? 'success' : 'danger'" />
7317
+ </div>
7318
+ <div class="flex flex-col gap-2">
7319
+ <label class="font-medium text-muted-color">Email Verified</label>
7320
+ <p-tag
7321
+ [value]="user.emailVerified ? 'Verified' : 'Unverified'"
7322
+ [severity]="user.emailVerified ? 'success' : 'warn'" />
7323
+ </div>
7324
+ @for (col of extraColumns(); track col.key) {
7325
+ <div class="flex flex-col gap-2">
7326
+ <label class="font-medium text-muted-color">{{ col.header }}</label>
7327
+ <span class="text-color">{{ getFieldValue(user, col.field ?? col.key) ?? '-' }}</span>
7328
+ </div>
7329
+ }
7330
+ </div>
7331
+ <div class="flex justify-end gap-2 mt-6">
7332
+ @if (userDetailConfig?.allowEdit) {
7333
+ <p-button
7334
+ label="Edit"
7335
+ icon="pi pi-pencil"
7336
+ (onClick)="onEdit(user); closeUserDetailDialog()" />
7337
+ }
7338
+ <p-button
7339
+ label="Close"
7340
+ severity="secondary"
7341
+ [outlined]="true"
7342
+ (onClick)="closeUserDetailDialog()" />
7343
+ </div>
7344
+ }
7345
+ </p-dialog>
7346
+ }
7347
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: i4$2.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "component", type: i5.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "component", type: i6.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "directive", type: i7.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "directive", type: HasPermissionDirective, selector: "[hasPermission]", inputs: ["hasPermission"] }, { kind: "component", type: UserCompanyPermissionDialogComponent, selector: "lib-user-company-permission-dialog", inputs: ["visible", "user"], outputs: ["closed", "permissionsChanged"] }, { kind: "component", type: UserBranchPermissionDialogComponent, selector: "lib-user-branch-permission-dialog", inputs: ["visible", "user"], outputs: ["closed", "permissionsChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6348
7348
  }
6349
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserListComponent, decorators: [{
7349
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UserListComponent, decorators: [{
6350
7350
  type: Component,
6351
7351
  args: [{
6352
7352
  selector: 'lib-user-list',
@@ -6354,7 +7354,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
6354
7354
  imports: [
6355
7355
  AngularModule,
6356
7356
  PrimeModule,
6357
- TagModule,
6358
7357
  HasPermissionDirective,
6359
7358
  UserCompanyPermissionDialogComponent,
6360
7359
  UserBranchPermissionDialogComponent,
@@ -6387,7 +7386,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
6387
7386
  <th>Phone</th>
6388
7387
  <th>Email Verified</th>
6389
7388
  <th>Status</th>
6390
- <th class="w-[150px]">Actions</th>
7389
+ @for (col of extraColumns(); track col.key) {
7390
+ <th [class]="col.styleClass ?? ''" [style.width]="col.width ?? 'auto'">
7391
+ {{ col.header }}
7392
+ </th>
7393
+ }
7394
+ <th class="w-[180px]">Actions</th>
6391
7395
  </tr>
6392
7396
  </ng-template>
6393
7397
  <ng-template #body let-user>
@@ -6405,8 +7409,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
6405
7409
  [value]="user.isActive ? 'Active' : 'Inactive'"
6406
7410
  [severity]="user.isActive ? 'success' : 'danger'" />
6407
7411
  </td>
7412
+ @for (col of extraColumns(); track col.key) {
7413
+ <td [class]="col.styleClass ?? ''">
7414
+ @if (col.template) {
7415
+ <ng-container [ngTemplateOutlet]="col.template" [ngTemplateOutletContext]="{ $implicit: user }" />
7416
+ } @else if (col.field) {
7417
+ {{ getFieldValue(user, col.field) ?? '-' }}
7418
+ }
7419
+ </td>
7420
+ }
6408
7421
  <td>
6409
- <div class="flex gap-2">
7422
+ <div class="flex gap-1 flex-wrap">
7423
+ @if (hasUserDetailView()) {
7424
+ <p-button
7425
+ icon="pi pi-eye"
7426
+ [rounded]="true"
7427
+ [text]="true"
7428
+ severity="info"
7429
+ pTooltip="View Details"
7430
+ (onClick)="onViewDetails(user)" />
7431
+ }
6410
7432
  <p-button
6411
7433
  *hasPermission="USER_PERMISSIONS.UPDATE"
6412
7434
  icon="pi pi-pencil"
@@ -6433,6 +7455,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
6433
7455
  pTooltip="Branch Permissions"
6434
7456
  (onClick)="onManageBranchPermissions(user)" />
6435
7457
  }
7458
+ @for (action of extraActions(); track action.key) {
7459
+ @if (isActionVisible(action, user)) {
7460
+ <p-button
7461
+ [icon]="action.icon"
7462
+ [rounded]="true"
7463
+ [text]="true"
7464
+ [severity]="action.severity ?? 'secondary'"
7465
+ [pTooltip]="action.label"
7466
+ [disabled]="isActionDisabled(action, user)"
7467
+ (onClick)="onExtraAction(action, user)" />
7468
+ }
7469
+ }
6436
7470
  <p-button
6437
7471
  *hasPermission="USER_PERMISSIONS.DELETE"
6438
7472
  icon="pi pi-trash"
@@ -6447,7 +7481,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
6447
7481
  </ng-template>
6448
7482
  <ng-template #emptymessage>
6449
7483
  <tr>
6450
- <td colspan="6" class="text-center py-8">
7484
+ <td [attr.colspan]="tableColspan()" class="text-center py-8">
6451
7485
  No users found. Click "Add User" to create one.
6452
7486
  </td>
6453
7487
  </tr>
@@ -6456,7 +7490,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
6456
7490
  </div>
6457
7491
  </p-card>
6458
7492
 
6459
- <!-- Permission Dialogs -->
6460
7493
  @if (companyFeatureEnabled()) {
6461
7494
  <lib-user-company-permission-dialog
6462
7495
  [visible]="showCompanyDialog()"
@@ -6470,6 +7503,65 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
6470
7503
  (closed)="showBranchDialog.set(false)"
6471
7504
  (permissionsChanged)="loadUsers()" />
6472
7505
  }
7506
+
7507
+ @if (hasUserDetailView() && showUserDetailDialog()) {
7508
+ <p-dialog
7509
+ header="User Details"
7510
+ [visible]="showUserDetailDialog()"
7511
+ [modal]="true"
7512
+ [style]="{ width: userDetailConfig?.width ?? '600px' }"
7513
+ [draggable]="false"
7514
+ [resizable]="false"
7515
+ (onHide)="closeUserDetailDialog()">
7516
+ @if (selectedUser(); as user) {
7517
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
7518
+ <div class="flex flex-col gap-2">
7519
+ <label class="font-medium text-muted-color">Name</label>
7520
+ <span class="text-color">{{ user.name }}</span>
7521
+ </div>
7522
+ <div class="flex flex-col gap-2">
7523
+ <label class="font-medium text-muted-color">Email</label>
7524
+ <span class="text-color">{{ user.email }}</span>
7525
+ </div>
7526
+ <div class="flex flex-col gap-2">
7527
+ <label class="font-medium text-muted-color">Phone</label>
7528
+ <span class="text-color">{{ user.phone || '-' }}</span>
7529
+ </div>
7530
+ <div class="flex flex-col gap-2">
7531
+ <label class="font-medium text-muted-color">Status</label>
7532
+ <p-tag
7533
+ [value]="user.isActive ? 'Active' : 'Inactive'"
7534
+ [severity]="user.isActive ? 'success' : 'danger'" />
7535
+ </div>
7536
+ <div class="flex flex-col gap-2">
7537
+ <label class="font-medium text-muted-color">Email Verified</label>
7538
+ <p-tag
7539
+ [value]="user.emailVerified ? 'Verified' : 'Unverified'"
7540
+ [severity]="user.emailVerified ? 'success' : 'warn'" />
7541
+ </div>
7542
+ @for (col of extraColumns(); track col.key) {
7543
+ <div class="flex flex-col gap-2">
7544
+ <label class="font-medium text-muted-color">{{ col.header }}</label>
7545
+ <span class="text-color">{{ getFieldValue(user, col.field ?? col.key) ?? '-' }}</span>
7546
+ </div>
7547
+ }
7548
+ </div>
7549
+ <div class="flex justify-end gap-2 mt-6">
7550
+ @if (userDetailConfig?.allowEdit) {
7551
+ <p-button
7552
+ label="Edit"
7553
+ icon="pi pi-pencil"
7554
+ (onClick)="onEdit(user); closeUserDetailDialog()" />
7555
+ }
7556
+ <p-button
7557
+ label="Close"
7558
+ severity="secondary"
7559
+ [outlined]="true"
7560
+ (onClick)="closeUserDetailDialog()" />
7561
+ </div>
7562
+ }
7563
+ </p-dialog>
7564
+ }
6473
7565
  `,
6474
7566
  }]
6475
7567
  }] });
@@ -6586,8 +7678,8 @@ class VerifyEmailPageComponent {
6586
7678
  this.submittedEmail.set(email);
6587
7679
  this.resendSuccess.set(true);
6588
7680
  }
6589
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: VerifyEmailPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6590
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: VerifyEmailPageComponent, isStandalone: true, selector: "lib-verify-email-page", ngImport: i0, template: `
7681
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: VerifyEmailPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7682
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: VerifyEmailPageComponent, isStandalone: true, selector: "lib-verify-email-page", ngImport: i0, template: `
6591
7683
  <app-floating-configurator />
6592
7684
  <div class="bg-surface-ground flex items-center justify-center min-h-screen">
6593
7685
  <div class="flex flex-col items-center justify-center w-full max-w-[32rem] px-4">
@@ -6711,9 +7803,9 @@ class VerifyEmailPageComponent {
6711
7803
  </div>
6712
7804
  </div>
6713
7805
  </div>
6714
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "component", type: AppFloatingConfigurator, selector: "app-floating-configurator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7806
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i4.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "component", type: AppFloatingConfigurator, selector: "app-floating-configurator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6715
7807
  }
6716
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: VerifyEmailPageComponent, decorators: [{
7808
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: VerifyEmailPageComponent, decorators: [{
6717
7809
  type: Component,
6718
7810
  args: [{
6719
7811
  selector: 'lib-verify-email-page',
@@ -6861,5 +7953,5 @@ var verifyEmailPage_component = /*#__PURE__*/Object.freeze({
6861
7953
  * Generated bundle index. Do not edit.
6862
7954
  */
6863
7955
 
6864
- export { ADMINISTRATION_ROUTES, AUTH_ENDPOINTS, AUTH_ROUTES, AdministrationPageComponent, AuthApiService, AuthCompanyApiProviderAdapter, AuthInitService, AuthLayoutApiAdapter, AuthLayoutStateAdapter, AuthStateProviderAdapter, AuthStateService, AuthUserPermissionProviderAdapter, AuthUserProviderAdapter, BranchApiService, BranchFormComponent, BranchListComponent, CompanyApiService, CompanyFormComponent, CompanyListComponent, ForgotPasswordPageComponent, LoginPageComponent, PROFILE_ROUTES, ProfilePageComponent, RegisterPageComponent, ResetPasswordPageComponent, TokenRefreshStateService, UserApiService, UserBranchPermissionDialogComponent, UserCompanyPermissionDialogComponent, UserFormComponent, UserListComponent, UserPermissionApiService, VerifyEmailPageComponent, authGuard, authInterceptor, companyFeatureGuard, guestGuard, isCompanySelectionResponse, isEmailVerificationRequired, isEndpoint, isLoginResponse, provideAuthLayoutIntegration, provideAuthProviders, tokenRefreshInterceptor };
7956
+ export { ADMINISTRATION_ROUTES, AUTH_ENDPOINTS, AUTH_PROFILE_EXTENSION, AUTH_REGISTRATION_EXTENSION, AUTH_ROUTES, AUTH_USER_DETAIL_CONFIG, AUTH_USER_LIST_EXTENSION, AUTH_VALIDATION_CONFIG, AdministrationPageComponent, AuthApiService, AuthCompanyApiProviderAdapter, AuthInitService, AuthLayoutApiAdapter, AuthLayoutStateAdapter, AuthStateProviderAdapter, AuthStateService, AuthUserPermissionProviderAdapter, AuthUserProviderAdapter, BranchApiService, BranchFormComponent, BranchListComponent, CompanyApiService, CompanyFormComponent, CompanyListComponent, ForgotPasswordPageComponent, LoginPageComponent, PROFILE_FIELD_CONTEXT, PROFILE_ROUTES, ProfilePageComponent, REGISTRATION_FIELD_CONTEXT, RegisterPageComponent, ResetPasswordPageComponent, TokenRefreshStateService, UserApiService, UserBranchPermissionDialogComponent, UserCompanyPermissionDialogComponent, UserFormComponent, UserListComponent, UserPermissionApiService, VerifyEmailPageComponent, authGuard, authInterceptor, companyFeatureGuard, emailFeatureGuard, guestGuard, isCompanySelectionResponse, isEmailVerificationRequired, isEndpoint, isLoginResponse, provideAuthLayoutIntegration, provideAuthProviders, signUpFeatureGuard, tokenRefreshInterceptor, validateEmail, validatePassword };
6865
7957
  //# sourceMappingURL=flusys-ng-auth.mjs.map