@flusys/ng-auth 0.1.0-beta.3 → 1.1.0-beta

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,37 +1,44 @@
1
1
  import * as i1 from '@angular/common/http';
2
2
  import { HttpClient } from '@angular/common/http';
3
3
  import * as i0 from '@angular/core';
4
- import { inject, Injectable, signal, computed, effect, PLATFORM_ID, Component, DestroyRef, input, output } from '@angular/core';
5
- import { APP_CONFIG, getServiceUrl, isCompanyFeatureEnabled } from '@flusys/ng-core';
6
- import * as i2$1 from '@angular/router';
4
+ import { inject, Injectable, signal, computed, effect, PLATFORM_ID, Component, DestroyRef, input, ChangeDetectionStrategy, output, makeStateKey, TransferState } from '@angular/core';
5
+ import { APP_CONFIG, getServiceUrl, isCompanyFeatureEnabled, isFeatureEnabled, getPermissionMode } from '@flusys/ng-core';
6
+ import * as i2 from '@angular/router';
7
7
  import { Router, RouterOutlet, RouterLink, RouterLinkActive, ActivatedRoute } from '@angular/router';
8
- import { of, switchMap, map, tap, catchError, shareReplay, finalize, BehaviorSubject, throwError, filter, take, firstValueFrom } from 'rxjs';
9
- import { ApiResourceService, CookieService, USER_PROVIDER, COMPANY_API_PROVIDER, USER_PERMISSION_PROVIDER, AngularModule, PrimeModule } from '@flusys/ng-shared';
8
+ import { of, timeout, switchMap, map, tap, catchError, shareReplay, finalize, BehaviorSubject, throwError, filter, take, firstValueFrom } from 'rxjs';
9
+ import { ApiResourceService, CookieService, USER_PROVIDER, COMPANY_API_PROVIDER, USER_PERMISSION_PROVIDER, AUTH_STATE_PROVIDER, AngularModule, PrimeModule, FileUrlService, PROFILE_UPLOAD_PROVIDER, PROFILE_PERMISSION_PROVIDER, FileUploaderComponent } from '@flusys/ng-shared';
10
10
  import { map as map$1, catchError as catchError$1, tap as tap$1 } from 'rxjs/operators';
11
11
  import { isPlatformBrowser, CommonModule } from '@angular/common';
12
12
  import * as i2$2 from 'primeng/api';
13
13
  import { MessageService, ConfirmationService } from 'primeng/api';
14
- import { LAYOUT_AUTH_STATE, LAYOUT_AUTH_API } from '@flusys/ng-layout';
14
+ import { LAYOUT_AUTH_STATE, LAYOUT_AUTH_API, AppFloatingConfigurator } from '@flusys/ng-layout';
15
15
  import { form, required, FormField, email, minLength } from '@angular/forms/signals';
16
16
  import * as i1$1 from '@angular/forms';
17
- import * as i2 from 'primeng/inputtext';
18
17
  import * as i3 from 'primeng/button';
19
- import * as i4 from 'primeng/card';
20
- import * as i1$2 from 'primeng/tag';
18
+ import * as i3$1 from 'primeng/card';
19
+ import * as i4 from 'primeng/inputtext';
20
+ import * as i4$2 from 'primeng/tag';
21
21
  import { TagModule } from 'primeng/tag';
22
- import * as i3$1 from 'primeng/tooltip';
23
- import * as i4$1 from 'primeng/table';
24
- import * as i7 from 'primeng/select';
22
+ import * as i4$1 from 'primeng/select';
23
+ import * as i3$2 from 'primeng/table';
24
+ import * as i5 from 'primeng/tooltip';
25
25
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
26
- import * as i5 from 'primeng/dialog';
26
+ import * as i2$1 from 'primeng/avatar';
27
+ import * as i5$1 from 'primeng/password';
28
+ import * as i6 from 'primeng/skeleton';
29
+ import * as i5$2 from 'primeng/dialog';
27
30
  import { DialogModule } from 'primeng/dialog';
28
- import * as i6 from 'primeng/progressspinner';
31
+ import * as i6$1 from 'primeng/progressspinner';
29
32
  import { ProgressSpinnerModule } from 'primeng/progressspinner';
30
- import * as i4$2 from 'primeng/checkbox';
33
+ import * as i4$3 from 'primeng/checkbox';
31
34
 
32
- // =============================================================================
33
35
  // AUTH INTERFACES - Matching NestJS Auth Package DTOs
34
- // =============================================================================
36
+ /**
37
+ * Type guard to check if response requires email verification
38
+ */
39
+ function isEmailVerificationRequired(response) {
40
+ return 'requiresEmailVerification' in response && response.requiresEmailVerification === true;
41
+ }
35
42
  /**
36
43
  * Type guard to check if response requires company selection
37
44
  */
@@ -42,7 +49,7 @@ function isCompanySelectionResponse(response) {
42
49
  * Type guard to check if response is a successful login
43
50
  */
44
51
  function isLoginResponse(response) {
45
- return 'accessToken' in response && !('requiresSelection' in response);
52
+ return 'accessToken' in response && !('requiresSelection' in response) && !('requiresEmailVerification' in response);
46
53
  }
47
54
 
48
55
  // =============================================================================
@@ -148,10 +155,26 @@ class AuthApiService {
148
155
  newPassword,
149
156
  });
150
157
  }
151
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
152
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthApiService, providedIn: 'root' });
158
+ /**
159
+ * Resend verification email (unauthenticated)
160
+ */
161
+ resendVerification(email) {
162
+ return this.http.post(`${this.baseUrl}/resend-verification`, { email });
163
+ }
164
+ /**
165
+ * Verify email with token
166
+ * Returns IMessageResponse for existing user verification
167
+ * Returns IRegistrationResponse for pending registration completion
168
+ */
169
+ verifyEmail(token) {
170
+ return this.http.post(`${this.baseUrl}/verify-email`, {
171
+ token,
172
+ });
173
+ }
174
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
175
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthApiService, providedIn: 'root' });
153
176
  }
154
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthApiService, decorators: [{
177
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthApiService, decorators: [{
155
178
  type: Injectable,
156
179
  args: [{ providedIn: 'root' }]
157
180
  }], ctorParameters: () => [] });
@@ -274,10 +297,10 @@ class AuthStateService {
274
297
  if (typeof window !== 'undefined')
275
298
  localStorage.removeItem(key);
276
299
  }
277
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
278
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthStateService, providedIn: 'root' });
300
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
301
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthStateService, providedIn: 'root' });
279
302
  }
280
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthStateService, decorators: [{
303
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthStateService, decorators: [{
281
304
  type: Injectable,
282
305
  args: [{ providedIn: 'root' }]
283
306
  }], ctorParameters: () => [] });
@@ -316,7 +339,6 @@ class AuthInitService {
316
339
  * Uses shareReplay to prevent duplicate initialization calls.
317
340
  */
318
341
  initialize() {
319
- console.log('[AuthInit] initialize()');
320
342
  /**
321
343
  * 1. Already authenticated with full state
322
344
  */
@@ -340,8 +362,9 @@ class AuthInitService {
340
362
  this.error.set(null);
341
363
  /**
342
364
  * 4. Start initialization
365
+ * Timeout after 5 seconds to prevent app stability issues
343
366
  */
344
- this.initializationCache$ = this.authApi.refresh().pipe(switchMap((refreshResponse) => {
367
+ this.initializationCache$ = this.authApi.refresh().pipe(timeout(5000), switchMap((refreshResponse) => {
345
368
  // Set access token from refresh
346
369
  this.authState.accessToken.set(refreshResponse.accessToken);
347
370
  // Fetch user profile
@@ -354,16 +377,13 @@ class AuthInitService {
354
377
  }
355
378
  return true;
356
379
  }));
357
- }), tap((success) => {
380
+ }), tap(() => {
358
381
  this.initialized.set(true);
359
382
  this.loading.set(false);
360
- if (!success) {
361
- this.authState.resetState();
362
- this.initialized.set(false);
363
- }
364
383
  }), catchError((err) => {
365
- this.initialized.set(true);
366
384
  this.loading.set(false);
385
+ // Always mark as initialized to prevent retry loops
386
+ this.initialized.set(true);
367
387
  const errorMessage = err?.error?.message || err?.message || 'Authentication failed';
368
388
  const isCompanyError = errorMessage.includes('no company assigned') ||
369
389
  errorMessage.includes('Company with ID') ||
@@ -377,10 +397,9 @@ class AuthInitService {
377
397
  this.authState.branch.set(null);
378
398
  }
379
399
  else {
380
- // Full logout
400
+ // Full logout - but keep initialized=true to prevent retry
381
401
  this.authState.resetState();
382
402
  this.authState.accessToken.set('');
383
- this.initialized.set(false);
384
403
  }
385
404
  return of(false);
386
405
  }), shareReplay({ bufferSize: 1, refCount: true }), finalize(() => {
@@ -389,10 +408,10 @@ class AuthInitService {
389
408
  }));
390
409
  return this.initializationCache$;
391
410
  }
392
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthInitService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
393
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthInitService, providedIn: 'root' });
411
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthInitService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
412
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthInitService, providedIn: 'root' });
394
413
  }
395
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthInitService, decorators: [{
414
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthInitService, decorators: [{
396
415
  type: Injectable,
397
416
  args: [{ providedIn: 'root' }]
398
417
  }] });
@@ -458,10 +477,10 @@ class BranchApiService extends ApiResourceService {
458
477
  filter: { companyId },
459
478
  });
460
479
  }
461
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BranchApiService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
462
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BranchApiService, providedIn: 'root' });
480
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BranchApiService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
481
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BranchApiService, providedIn: 'root' });
463
482
  }
464
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BranchApiService, decorators: [{
483
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BranchApiService, decorators: [{
465
484
  type: Injectable,
466
485
  args: [{ providedIn: 'root' }]
467
486
  }], ctorParameters: () => [{ type: i1.HttpClient }] });
@@ -489,10 +508,10 @@ class CompanyApiService extends ApiResourceService {
489
508
  constructor(http) {
490
509
  super('administration/company', http);
491
510
  }
492
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: CompanyApiService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
493
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: CompanyApiService, providedIn: 'root' });
511
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CompanyApiService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
512
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CompanyApiService, providedIn: 'root' });
494
513
  }
495
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: CompanyApiService, decorators: [{
514
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CompanyApiService, decorators: [{
496
515
  type: Injectable,
497
516
  args: [{ providedIn: 'root' }]
498
517
  }], ctorParameters: () => [{ type: i1.HttpClient }] });
@@ -542,10 +561,10 @@ class TokenRefreshStateService {
542
561
  failRefresh() {
543
562
  this._isRefreshing.set(false);
544
563
  }
545
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TokenRefreshStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
546
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TokenRefreshStateService, providedIn: 'root' });
564
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TokenRefreshStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
565
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TokenRefreshStateService, providedIn: 'root' });
547
566
  }
548
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TokenRefreshStateService, decorators: [{
567
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TokenRefreshStateService, decorators: [{
549
568
  type: Injectable,
550
569
  args: [{ providedIn: 'root' }]
551
570
  }] });
@@ -601,10 +620,10 @@ class UserApiService extends ApiResourceService {
601
620
  updateProfile(data) {
602
621
  return this.http.post(`${this.baseUrl}/profile`, data);
603
622
  }
604
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: UserApiService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
605
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: UserApiService, providedIn: 'root' });
623
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserApiService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
624
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserApiService, providedIn: 'root' });
606
625
  }
607
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: UserApiService, decorators: [{
626
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserApiService, decorators: [{
608
627
  type: Injectable,
609
628
  args: [{ providedIn: 'root' }]
610
629
  }], ctorParameters: () => [{ type: i1.HttpClient }] });
@@ -740,10 +759,10 @@ class UserPermissionApiService {
740
759
  params: { userId },
741
760
  });
742
761
  }
743
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: UserPermissionApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
744
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: UserPermissionApiService, providedIn: 'root' });
762
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserPermissionApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
763
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserPermissionApiService, providedIn: 'root' });
745
764
  }
746
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: UserPermissionApiService, decorators: [{
765
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserPermissionApiService, decorators: [{
747
766
  type: Injectable,
748
767
  args: [{ providedIn: 'root' }]
749
768
  }], ctorParameters: () => [] });
@@ -768,6 +787,10 @@ const AUTH_ENDPOINTS = {
768
787
  REGISTER: '/auth/register',
769
788
  SELECT: '/auth/select',
770
789
  SWITCH_COMPANY: '/auth/switch-company',
790
+ VERIFY_EMAIL: '/auth/verify-email',
791
+ FORGOT_PASSWORD: '/auth/forgot-password',
792
+ RESET_PASSWORD: '/auth/reset-password',
793
+ RESEND_VERIFICATION: '/auth/resend-verification',
771
794
  };
772
795
  /**
773
796
  * Check if a URL is an auth-related endpoint
@@ -909,22 +932,18 @@ const companyFeatureGuard = () => {
909
932
  return true;
910
933
  };
911
934
 
935
+ /** Endpoints that need withCredentials for cookie handling */
936
+ const COOKIE_ENDPOINTS = [
937
+ AUTH_ENDPOINTS.LOGIN,
938
+ AUTH_ENDPOINTS.LOGOUT,
939
+ AUTH_ENDPOINTS.REFRESH,
940
+ AUTH_ENDPOINTS.REGISTER,
941
+ AUTH_ENDPOINTS.SELECT,
942
+ AUTH_ENDPOINTS.SWITCH_COMPANY,
943
+ AUTH_ENDPOINTS.VERIFY_EMAIL,
944
+ ];
912
945
  /**
913
- * Auth Interceptor
914
- * Adds Authorization header and tenant header to HTTP requests.
915
- *
916
- * - Adds Bearer token for authenticated requests (including /auth/me)
917
- * - Adds tenant header for multi-tenant mode
918
- * - Adds withCredentials for auth endpoints (cookies)
919
- *
920
- * @example
921
- * ```typescript
922
- * // In app.config.ts
923
- * provideHttpClient(
924
- * withFetch(),
925
- * withInterceptors([authInterceptor, tokenRefreshInterceptor])
926
- * )
927
- * ```
946
+ * Auth Interceptor - Adds auth headers and cookie credentials to requests
928
947
  */
929
948
  function authInterceptor(req, next) {
930
949
  const authState = inject(AuthStateService);
@@ -934,33 +953,21 @@ function authInterceptor(req, next) {
934
953
  // Add tenant header if multi-tenant mode
935
954
  if (appConfig.multiTenant.enabled) {
936
955
  const tenantId = authState.tenantId();
937
- const tenantHeader = appConfig.multiTenant.tenantHeader;
938
956
  if (tenantId) {
939
- headers[tenantHeader] = tenantId;
957
+ headers[appConfig.multiTenant.tenantHeader] = tenantId;
940
958
  }
941
959
  }
942
- // Add Bearer token for authenticated endpoints (including /auth/me)
960
+ // Add Bearer token if available
943
961
  const token = authState.accessToken();
944
962
  if (token) {
945
963
  headers['Authorization'] = `Bearer ${token}`;
946
964
  }
947
- // Check if this is an auth endpoint that needs withCredentials (for cookies)
948
- const needsCredentials = isEndpoint(req.url, AUTH_ENDPOINTS.REFRESH) ||
949
- isEndpoint(req.url, AUTH_ENDPOINTS.LOGOUT) ||
950
- isEndpoint(req.url, AUTH_ENDPOINTS.LOGIN) ||
951
- isEndpoint(req.url, AUTH_ENDPOINTS.REGISTER) ||
952
- isEndpoint(req.url, AUTH_ENDPOINTS.SELECT) ||
953
- isEndpoint(req.url, AUTH_ENDPOINTS.SWITCH_COMPANY);
965
+ // Check if this endpoint needs withCredentials for cookies
966
+ const needsCredentials = COOKIE_ENDPOINTS.some((ep) => isEndpoint(req.url, ep));
954
967
  if (needsCredentials) {
955
- // Auth endpoints use cookies
956
- return next(req.clone({
957
- withCredentials: true,
958
- setHeaders: {
959
- cookie: cookieService.get(),
960
- },
961
- }));
968
+ headers['cookie'] = cookieService.get();
969
+ return next(req.clone({ withCredentials: true, setHeaders: headers }));
962
970
  }
963
- // Other requests just need headers (Bearer token + tenant)
964
971
  if (Object.keys(headers).length > 0) {
965
972
  return next(req.clone({ setHeaders: headers }));
966
973
  }
@@ -1076,6 +1083,20 @@ const AUTH_ROUTES = [
1076
1083
  loadComponent: () => Promise.resolve().then(function () { return registerPage_component; }).then((m) => m.RegisterPageComponent),
1077
1084
  canActivate: [guestGuard],
1078
1085
  },
1086
+ {
1087
+ path: 'forgot-password',
1088
+ loadComponent: () => Promise.resolve().then(function () { return forgotPasswordPage_component; }).then((m) => m.ForgotPasswordPageComponent),
1089
+ canActivate: [guestGuard],
1090
+ },
1091
+ {
1092
+ path: 'reset-password',
1093
+ loadComponent: () => Promise.resolve().then(function () { return resetPasswordPage_component; }).then((m) => m.ResetPasswordPageComponent),
1094
+ canActivate: [guestGuard],
1095
+ },
1096
+ {
1097
+ path: 'verify-email',
1098
+ loadComponent: () => Promise.resolve().then(function () { return verifyEmailPage_component; }).then((m) => m.VerifyEmailPageComponent),
1099
+ },
1079
1100
  {
1080
1101
  path: '',
1081
1102
  redirectTo: 'login',
@@ -1161,6 +1182,17 @@ const ADMINISTRATION_ROUTES = [
1161
1182
  ],
1162
1183
  },
1163
1184
  ];
1185
+ /**
1186
+ * Profile Routes Configuration
1187
+ * Protected route for user profile management
1188
+ */
1189
+ const PROFILE_ROUTES = [
1190
+ {
1191
+ path: '',
1192
+ canActivate: [authGuard],
1193
+ loadComponent: () => Promise.resolve().then(function () { return profilePage_component; }).then((m) => m.ProfilePageComponent),
1194
+ },
1195
+ ];
1164
1196
 
1165
1197
  /**
1166
1198
  * Auth Layout State Adapter
@@ -1216,10 +1248,10 @@ class AuthLayoutStateAdapter {
1216
1248
  }
1217
1249
  return null;
1218
1250
  }, ...(ngDevMode ? [{ debugName: "loginUserData" }] : []));
1219
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthLayoutStateAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1220
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthLayoutStateAdapter, providedIn: 'root' });
1251
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthLayoutStateAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1252
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthLayoutStateAdapter, providedIn: 'root' });
1221
1253
  }
1222
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthLayoutStateAdapter, decorators: [{
1254
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthLayoutStateAdapter, decorators: [{
1223
1255
  type: Injectable,
1224
1256
  args: [{ providedIn: 'root' }]
1225
1257
  }] });
@@ -1305,10 +1337,10 @@ class AuthLayoutApiAdapter {
1305
1337
  }));
1306
1338
  }));
1307
1339
  }
1308
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthLayoutApiAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1309
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthLayoutApiAdapter, providedIn: 'root' });
1340
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthLayoutApiAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1341
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthLayoutApiAdapter, providedIn: 'root' });
1310
1342
  }
1311
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthLayoutApiAdapter, decorators: [{
1343
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthLayoutApiAdapter, decorators: [{
1312
1344
  type: Injectable,
1313
1345
  args: [{ providedIn: 'root' }]
1314
1346
  }] });
@@ -1341,6 +1373,7 @@ class AuthUserProviderAdapter {
1341
1373
  filter: {
1342
1374
  ...(filter?.companyId && { companyId: filter.companyId }),
1343
1375
  ...(filter?.branchId && { branchId: filter.branchId }),
1376
+ ...(filter?.isActive !== undefined && { isActive: filter.isActive }),
1344
1377
  },
1345
1378
  sort: { name: 'ASC' },
1346
1379
  };
@@ -1355,10 +1388,10 @@ class AuthUserProviderAdapter {
1355
1388
  meta: response.meta,
1356
1389
  })));
1357
1390
  }
1358
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthUserProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1359
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthUserProviderAdapter });
1391
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthUserProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1392
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthUserProviderAdapter });
1360
1393
  }
1361
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthUserProviderAdapter, decorators: [{
1394
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthUserProviderAdapter, decorators: [{
1362
1395
  type: Injectable
1363
1396
  }] });
1364
1397
 
@@ -1395,10 +1428,10 @@ class AuthCompanyApiProviderAdapter {
1395
1428
  meta: response.meta,
1396
1429
  })));
1397
1430
  }
1398
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthCompanyApiProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1399
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthCompanyApiProviderAdapter });
1431
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthCompanyApiProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1432
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthCompanyApiProviderAdapter });
1400
1433
  }
1401
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthCompanyApiProviderAdapter, decorators: [{
1434
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthCompanyApiProviderAdapter, decorators: [{
1402
1435
  type: Injectable
1403
1436
  }] });
1404
1437
 
@@ -1419,10 +1452,10 @@ class AuthUserPermissionProviderAdapter {
1419
1452
  getUserBranchPermissions(userId) {
1420
1453
  return this.userPermissionApi.getUserBranches(userId);
1421
1454
  }
1422
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthUserPermissionProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1423
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthUserPermissionProviderAdapter });
1455
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthUserPermissionProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1456
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthUserPermissionProviderAdapter });
1424
1457
  }
1425
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AuthUserPermissionProviderAdapter, decorators: [{
1458
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthUserPermissionProviderAdapter, decorators: [{
1426
1459
  type: Injectable
1427
1460
  }] });
1428
1461
 
@@ -1450,6 +1483,46 @@ function provideAuthLayoutIntegration() {
1450
1483
  ];
1451
1484
  }
1452
1485
 
1486
+ /**
1487
+ * Auth State Provider Adapter
1488
+ *
1489
+ * Implements IAuthStateProvider interface from ng-shared using auth services from ng-auth.
1490
+ * This allows feature packages (form-builder, etc.) to check auth state without
1491
+ * depending on ng-auth directly.
1492
+ *
1493
+ * @example
1494
+ * // In app.config.ts
1495
+ * providers: [
1496
+ * { provide: AUTH_STATE_PROVIDER, useClass: AuthStateProviderAdapter }
1497
+ * ]
1498
+ *
1499
+ * // In form-builder component
1500
+ * private readonly authStateProvider = inject(AUTH_STATE_PROVIDER);
1501
+ * const isLoggedIn = this.authStateProvider.isAuthenticated();
1502
+ */
1503
+ class AuthStateProviderAdapter {
1504
+ authState = inject(AuthStateService);
1505
+ authInit = inject(AuthInitService);
1506
+ /**
1507
+ * Signal indicating if user is currently authenticated
1508
+ */
1509
+ get isAuthenticated() {
1510
+ return this.authState.isAuthenticated;
1511
+ }
1512
+ /**
1513
+ * Initialize auth state (restore session from cookies/storage)
1514
+ * Returns Observable<void> that completes when initialization is done
1515
+ */
1516
+ initialize() {
1517
+ return this.authInit.initialize().pipe(map(() => undefined));
1518
+ }
1519
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthStateProviderAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1520
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthStateProviderAdapter });
1521
+ }
1522
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AuthStateProviderAdapter, decorators: [{
1523
+ type: Injectable
1524
+ }] });
1525
+
1453
1526
  /**
1454
1527
  * Provide Auth Provider Adapters
1455
1528
  *
@@ -1477,6 +1550,8 @@ function provideAuthProviders() {
1477
1550
  { provide: COMPANY_API_PROVIDER, useClass: AuthCompanyApiProviderAdapter },
1478
1551
  // User permission provider (for IAM permission assignment)
1479
1552
  { provide: USER_PERMISSION_PROVIDER, useClass: AuthUserPermissionProviderAdapter },
1553
+ // Auth state provider (for form-builder and other packages)
1554
+ { provide: AUTH_STATE_PROVIDER, useClass: AuthStateProviderAdapter },
1480
1555
  ];
1481
1556
  }
1482
1557
 
@@ -1524,8 +1599,8 @@ class AdministrationPageComponent {
1524
1599
  ? 'Manage users, companies, and branches'
1525
1600
  : 'Manage users';
1526
1601
  }, ...(ngDevMode ? [{ debugName: "subtitle" }] : []));
1527
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AdministrationPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1528
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: AdministrationPageComponent, isStandalone: true, selector: "lib-administration-page", ngImport: i0, template: `
1602
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AdministrationPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1603
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: AdministrationPageComponent, isStandalone: true, selector: "lib-administration-page", ngImport: i0, template: `
1529
1604
  <div class="administration-page p-4">
1530
1605
  <div class="administration-header mb-4">
1531
1606
  <h1 class="text-2xl font-bold m-0">Administration</h1>
@@ -1550,7 +1625,7 @@ class AdministrationPageComponent {
1550
1625
  </div>
1551
1626
  `, isInline: true, styles: [".tab-link{color:var(--text-color-secondary, #6b7280);text-decoration:none;border-bottom:2px solid transparent;margin-bottom:-1px}.tab-link.active{color:var(--primary-color, #3b82f6);border-bottom-color:var(--primary-color, #3b82f6);background-color:var(--surface-ground, #f9fafb)}.tab-link:hover:not(.active){background-color:var(--surface-hover, #f3f4f6)}\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"] }] });
1552
1627
  }
1553
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AdministrationPageComponent, decorators: [{
1628
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AdministrationPageComponent, decorators: [{
1554
1629
  type: Component,
1555
1630
  args: [{ selector: 'lib-administration-page', standalone: true, imports: [CommonModule, RouterOutlet, RouterLink, RouterLinkActive], template: `
1556
1631
  <div class="administration-page p-4">
@@ -1761,8 +1836,8 @@ class BranchFormComponent {
1761
1836
  queryParams: companyId ? { companyId } : {},
1762
1837
  });
1763
1838
  }
1764
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BranchFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1765
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: BranchFormComponent, isStandalone: true, selector: "lib-branch-form", ngImport: i0, template: `
1839
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BranchFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1840
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: BranchFormComponent, isStandalone: true, selector: "lib-branch-form", ngImport: i0, template: `
1766
1841
  <p-card>
1767
1842
  <ng-template #header>
1768
1843
  <div class="flex justify-between items-center p-4">
@@ -1876,9 +1951,9 @@ class BranchFormComponent {
1876
1951
  </div>
1877
1952
  </form>
1878
1953
  </p-card>
1879
- `, 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: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: i3.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: i4.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }] });
1954
+ `, 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: i3.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$1.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"] }] });
1880
1955
  }
1881
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BranchFormComponent, decorators: [{
1956
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BranchFormComponent, decorators: [{
1882
1957
  type: Component,
1883
1958
  args: [{
1884
1959
  selector: 'lib-branch-form',
@@ -2101,8 +2176,8 @@ class BranchListComponent {
2101
2176
  },
2102
2177
  });
2103
2178
  }
2104
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BranchListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2105
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: BranchListComponent, isStandalone: true, selector: "lib-branch-list", ngImport: i0, template: `
2179
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BranchListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2180
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: BranchListComponent, isStandalone: true, selector: "lib-branch-list", ngImport: i0, template: `
2106
2181
  <p-card>
2107
2182
  <ng-template #header>
2108
2183
  <div class="flex justify-between items-center p-4">
@@ -2193,9 +2268,9 @@ class BranchListComponent {
2193
2268
  </ng-template>
2194
2269
  </p-table>
2195
2270
  </p-card>
2196
- `, 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: i1$2.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "component", type: i3.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: i3$1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: i4$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.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: i7.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: TagModule }] });
2271
+ `, 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: i3.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$1.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$2.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 }] });
2197
2272
  }
2198
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: BranchListComponent, decorators: [{
2273
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BranchListComponent, decorators: [{
2199
2274
  type: Component,
2200
2275
  args: [{
2201
2276
  selector: 'lib-branch-list',
@@ -2451,8 +2526,8 @@ class CompanyFormComponent {
2451
2526
  onCancel() {
2452
2527
  this.router.navigate(['/administration/company']);
2453
2528
  }
2454
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: CompanyFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2455
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.0", type: CompanyFormComponent, isStandalone: true, selector: "lib-company-form", ngImport: i0, template: `
2529
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CompanyFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2530
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: CompanyFormComponent, isStandalone: true, selector: "lib-company-form", ngImport: i0, template: `
2456
2531
  <p-card>
2457
2532
  <ng-template #header>
2458
2533
  <div class="flex justify-between items-center p-4">
@@ -2560,9 +2635,9 @@ class CompanyFormComponent {
2560
2635
  </div>
2561
2636
  </form>
2562
2637
  </p-card>
2563
- `, 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: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: i3.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: i4.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }] });
2638
+ `, 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: i3.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$1.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"] }] });
2564
2639
  }
2565
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: CompanyFormComponent, decorators: [{
2640
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CompanyFormComponent, decorators: [{
2566
2641
  type: Component,
2567
2642
  args: [{
2568
2643
  selector: 'lib-company-form',
@@ -2755,8 +2830,8 @@ class CompanyListComponent {
2755
2830
  },
2756
2831
  });
2757
2832
  }
2758
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: CompanyListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2759
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: CompanyListComponent, isStandalone: true, selector: "lib-company-list", ngImport: i0, template: `
2833
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CompanyListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2834
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: CompanyListComponent, isStandalone: true, selector: "lib-company-list", ngImport: i0, template: `
2760
2835
  <p-card>
2761
2836
  <ng-template #header>
2762
2837
  <div class="flex justify-between items-center p-4">
@@ -2837,9 +2912,9 @@ class CompanyListComponent {
2837
2912
  </ng-template>
2838
2913
  </p-table>
2839
2914
  </p-card>
2840
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i1$2.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "component", type: i3.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: i3$1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: i4$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.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "ngmodule", type: TagModule }] });
2915
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i3.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$1.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: i3$2.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 }] });
2841
2916
  }
2842
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: CompanyListComponent, decorators: [{
2917
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CompanyListComponent, decorators: [{
2843
2918
  type: Component,
2844
2919
  args: [{
2845
2920
  selector: 'lib-company-list',
@@ -2935,6 +3010,223 @@ var companyList_component = /*#__PURE__*/Object.freeze({
2935
3010
  CompanyListComponent: CompanyListComponent
2936
3011
  });
2937
3012
 
3013
+ class ForgotPasswordPageComponent {
3014
+ destroyRef = inject(DestroyRef);
3015
+ messageService = inject(MessageService);
3016
+ authApi = inject(AuthApiService);
3017
+ isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
3018
+ emailSent = signal(false, ...(ngDevMode ? [{ debugName: "emailSent" }] : []));
3019
+ submittedEmail = signal('', ...(ngDevMode ? [{ debugName: "submittedEmail" }] : []));
3020
+ formModel = signal({ email: '' }, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
3021
+ forgotForm = form(this.formModel, (f) => {
3022
+ required(f.email, { message: 'Email is required' });
3023
+ email(f.email, { message: 'Please enter a valid email address' });
3024
+ });
3025
+ isFormValid = computed(() => this.forgotForm().valid(), ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
3026
+ onSubmit() {
3027
+ if (!this.isFormValid()) {
3028
+ this.messageService.add({
3029
+ severity: 'error',
3030
+ summary: 'Validation Error',
3031
+ detail: 'Please enter a valid email address.',
3032
+ });
3033
+ return;
3034
+ }
3035
+ this.isLoading.set(true);
3036
+ const email = this.formModel().email;
3037
+ this.authApi
3038
+ .forgotPassword(email)
3039
+ .pipe(takeUntilDestroyed(this.destroyRef))
3040
+ .subscribe({
3041
+ next: () => {
3042
+ this.isLoading.set(false);
3043
+ this.submittedEmail.set(email);
3044
+ this.emailSent.set(true);
3045
+ },
3046
+ error: () => {
3047
+ this.isLoading.set(false);
3048
+ this.submittedEmail.set(email);
3049
+ this.emailSent.set(true);
3050
+ },
3051
+ });
3052
+ }
3053
+ resetForm() {
3054
+ this.emailSent.set(false);
3055
+ this.submittedEmail.set('');
3056
+ this.formModel.set({ email: '' });
3057
+ }
3058
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ForgotPasswordPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3059
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ForgotPasswordPageComponent, isStandalone: true, selector: "lib-forgot-password-page", ngImport: i0, template: `
3060
+ <app-floating-configurator />
3061
+ <div class="bg-surface-ground flex items-center justify-center min-h-screen">
3062
+ <div class="flex flex-col items-center justify-center w-full max-w-[32rem] px-4">
3063
+ <div
3064
+ class="w-full"
3065
+ style="border-radius: var(--p-content-border-radius); padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
3066
+ <div
3067
+ class="w-full py-16 px-12"
3068
+ style="border-radius: var(--p-content-border-radius); background: var(--p-content-background);">
3069
+
3070
+ @if (!emailSent()) {
3071
+ <div class="text-center mb-8">
3072
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
3073
+ Forgot Password
3074
+ </div>
3075
+ <span class="text-muted-color font-medium">
3076
+ Enter your email address and we'll send you a link to reset your password.
3077
+ </span>
3078
+ </div>
3079
+
3080
+ <form (ngSubmit)="onSubmit()">
3081
+ <label for="email" class="block text-lg font-medium mb-2" style="color: var(--p-content-color);">
3082
+ Email
3083
+ </label>
3084
+ <input
3085
+ pInputText
3086
+ id="email"
3087
+ type="email"
3088
+ placeholder="Enter your email address"
3089
+ class="w-full md:w-[25rem] mb-6"
3090
+ [formField]="forgotForm.email"
3091
+ autocomplete="email" />
3092
+
3093
+ <p-button
3094
+ label="Send Reset Link"
3095
+ styleClass="w-full mb-4"
3096
+ type="submit"
3097
+ [loading]="isLoading()"
3098
+ [disabled]="!isFormValid() || isLoading()" />
3099
+
3100
+ <div class="flex items-center justify-center gap-2">
3101
+ <span class="font-medium">Remember your password?</span>
3102
+ <a routerLink="/auth/login" class="font-semibold text-primary cursor-pointer">
3103
+ Sign In
3104
+ </a>
3105
+ </div>
3106
+ </form>
3107
+ } @else {
3108
+ <div class="text-center">
3109
+ <div class="flex justify-center mb-6">
3110
+ <i class="pi pi-envelope text-6xl text-primary"></i>
3111
+ </div>
3112
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
3113
+ Check Your Email
3114
+ </div>
3115
+ <p class="text-muted-color font-medium mb-6">
3116
+ We've sent a password reset link to <strong>{{ submittedEmail() }}</strong>.
3117
+ Please check your inbox and follow the instructions.
3118
+ </p>
3119
+ <p class="text-sm text-muted-color mb-6">
3120
+ Didn't receive the email? Check your spam folder or
3121
+ <span
3122
+ class="text-primary cursor-pointer font-semibold"
3123
+ (click)="resetForm()">
3124
+ try again
3125
+ </span>.
3126
+ </p>
3127
+ <a routerLink="/auth/login" class="font-semibold text-primary cursor-pointer">
3128
+ Back to Sign In
3129
+ </a>
3130
+ </div>
3131
+ }
3132
+ </div>
3133
+ </div>
3134
+ </div>
3135
+ </div>
3136
+ `, 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.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i3.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" }] });
3137
+ }
3138
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ForgotPasswordPageComponent, decorators: [{
3139
+ type: Component,
3140
+ args: [{
3141
+ selector: 'lib-forgot-password-page',
3142
+ standalone: true,
3143
+ imports: [AngularModule, PrimeModule, FormField, AppFloatingConfigurator],
3144
+ template: `
3145
+ <app-floating-configurator />
3146
+ <div class="bg-surface-ground flex items-center justify-center min-h-screen">
3147
+ <div class="flex flex-col items-center justify-center w-full max-w-[32rem] px-4">
3148
+ <div
3149
+ class="w-full"
3150
+ style="border-radius: var(--p-content-border-radius); padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
3151
+ <div
3152
+ class="w-full py-16 px-12"
3153
+ style="border-radius: var(--p-content-border-radius); background: var(--p-content-background);">
3154
+
3155
+ @if (!emailSent()) {
3156
+ <div class="text-center mb-8">
3157
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
3158
+ Forgot Password
3159
+ </div>
3160
+ <span class="text-muted-color font-medium">
3161
+ Enter your email address and we'll send you a link to reset your password.
3162
+ </span>
3163
+ </div>
3164
+
3165
+ <form (ngSubmit)="onSubmit()">
3166
+ <label for="email" class="block text-lg font-medium mb-2" style="color: var(--p-content-color);">
3167
+ Email
3168
+ </label>
3169
+ <input
3170
+ pInputText
3171
+ id="email"
3172
+ type="email"
3173
+ placeholder="Enter your email address"
3174
+ class="w-full md:w-[25rem] mb-6"
3175
+ [formField]="forgotForm.email"
3176
+ autocomplete="email" />
3177
+
3178
+ <p-button
3179
+ label="Send Reset Link"
3180
+ styleClass="w-full mb-4"
3181
+ type="submit"
3182
+ [loading]="isLoading()"
3183
+ [disabled]="!isFormValid() || isLoading()" />
3184
+
3185
+ <div class="flex items-center justify-center gap-2">
3186
+ <span class="font-medium">Remember your password?</span>
3187
+ <a routerLink="/auth/login" class="font-semibold text-primary cursor-pointer">
3188
+ Sign In
3189
+ </a>
3190
+ </div>
3191
+ </form>
3192
+ } @else {
3193
+ <div class="text-center">
3194
+ <div class="flex justify-center mb-6">
3195
+ <i class="pi pi-envelope text-6xl text-primary"></i>
3196
+ </div>
3197
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
3198
+ Check Your Email
3199
+ </div>
3200
+ <p class="text-muted-color font-medium mb-6">
3201
+ We've sent a password reset link to <strong>{{ submittedEmail() }}</strong>.
3202
+ Please check your inbox and follow the instructions.
3203
+ </p>
3204
+ <p class="text-sm text-muted-color mb-6">
3205
+ Didn't receive the email? Check your spam folder or
3206
+ <span
3207
+ class="text-primary cursor-pointer font-semibold"
3208
+ (click)="resetForm()">
3209
+ try again
3210
+ </span>.
3211
+ </p>
3212
+ <a routerLink="/auth/login" class="font-semibold text-primary cursor-pointer">
3213
+ Back to Sign In
3214
+ </a>
3215
+ </div>
3216
+ }
3217
+ </div>
3218
+ </div>
3219
+ </div>
3220
+ </div>
3221
+ `,
3222
+ }]
3223
+ }] });
3224
+
3225
+ var forgotPasswordPage_component = /*#__PURE__*/Object.freeze({
3226
+ __proto__: null,
3227
+ ForgotPasswordPageComponent: ForgotPasswordPageComponent
3228
+ });
3229
+
2938
3230
  /**
2939
3231
  * Login Page Component
2940
3232
  * Multi-step authentication flow:
@@ -2947,12 +3239,10 @@ class LoginPageComponent {
2947
3239
  messageService = inject(MessageService);
2948
3240
  authApi = inject(AuthApiService);
2949
3241
  authState = inject(AuthStateService);
2950
- /** Return URL after successful login */
2951
3242
  returnUrl = input('', ...(ngDevMode ? [{ debugName: "returnUrl" }] : []));
2952
- /** Current step in login flow */
2953
3243
  currentStep = signal('credentials', ...(ngDevMode ? [{ debugName: "currentStep" }] : []));
2954
- /** Loading state */
2955
3244
  isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
3245
+ unverifiedEmail = signal('', ...(ngDevMode ? [{ debugName: "unverifiedEmail" }] : []));
2956
3246
  // ============================================
2957
3247
  // Login Form (Signal Forms)
2958
3248
  // ============================================
@@ -3041,23 +3331,24 @@ class LoginPageComponent {
3041
3331
  };
3042
3332
  this.authApi
3043
3333
  .login(loginData)
3044
- .pipe(take(1), takeUntilDestroyed(this.destroyRef))
3334
+ .pipe(takeUntilDestroyed(this.destroyRef))
3045
3335
  .subscribe({
3046
3336
  next: (response) => {
3047
3337
  this.isLoading.set(false);
3048
- // Check if company selection is required
3338
+ if (isEmailVerificationRequired(response)) {
3339
+ this.unverifiedEmail.set(response.email);
3340
+ this.currentStep.set('email-verification');
3341
+ return;
3342
+ }
3049
3343
  if (isCompanySelectionResponse(response)) {
3050
- // Move to step 2 (company selection)
3051
3344
  this.sessionId = response.sessionId;
3052
3345
  this.companies.set(response.companies);
3053
3346
  this.userName.set(response.user.name ?? response.user.email);
3054
- // Store selection state for potential page refresh
3055
3347
  this.authState.setSelectionState(response);
3056
3348
  this.currentStep.set('company-selection');
3057
3349
  this.autoSelectIfSingle();
3058
3350
  }
3059
3351
  else {
3060
- // Direct login success
3061
3352
  this.authState.setLoginState(response);
3062
3353
  this.messageService.add({
3063
3354
  severity: 'success',
@@ -3123,7 +3414,7 @@ class LoginPageComponent {
3123
3414
  };
3124
3415
  this.authApi
3125
3416
  .select(selectData)
3126
- .pipe(take(1), takeUntilDestroyed(this.destroyRef))
3417
+ .pipe(takeUntilDestroyed(this.destroyRef))
3127
3418
  .subscribe({
3128
3419
  next: (response) => {
3129
3420
  this.isLoading.set(false);
@@ -3147,9 +3438,9 @@ class LoginPageComponent {
3147
3438
  });
3148
3439
  }
3149
3440
  goBackToCredentials() {
3150
- // Reset selection state
3151
3441
  this.sessionId = null;
3152
3442
  this.companies.set([]);
3443
+ this.unverifiedEmail.set('');
3153
3444
  this.selectionFormModel.set({
3154
3445
  companyId: '',
3155
3446
  branchId: '',
@@ -3158,6 +3449,33 @@ class LoginPageComponent {
3158
3449
  this.authState.resetState();
3159
3450
  this.currentStep.set('credentials');
3160
3451
  }
3452
+ onResendVerification() {
3453
+ const email = this.unverifiedEmail();
3454
+ if (!email)
3455
+ return;
3456
+ this.isLoading.set(true);
3457
+ this.authApi
3458
+ .resendVerification(email)
3459
+ .pipe(takeUntilDestroyed(this.destroyRef))
3460
+ .subscribe({
3461
+ next: (response) => {
3462
+ this.isLoading.set(false);
3463
+ this.messageService.add({
3464
+ severity: 'success',
3465
+ summary: 'Email Sent',
3466
+ detail: response.message || 'Verification email has been sent.',
3467
+ });
3468
+ },
3469
+ error: (error) => {
3470
+ this.isLoading.set(false);
3471
+ this.messageService.add({
3472
+ severity: 'error',
3473
+ summary: 'Failed to Send',
3474
+ detail: error.error?.message || 'Unable to send verification email.',
3475
+ });
3476
+ },
3477
+ });
3478
+ }
3161
3479
  // ============================================
3162
3480
  // Helpers
3163
3481
  // ============================================
@@ -3192,8 +3510,9 @@ class LoginPageComponent {
3192
3510
  }
3193
3511
  }
3194
3512
  }
3195
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LoginPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3196
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: LoginPageComponent, isStandalone: true, selector: "lib-login-page", inputs: { returnUrl: { classPropertyName: "returnUrl", publicName: "returnUrl", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
3513
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: LoginPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3514
+ 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: `
3515
+ <app-floating-configurator />
3197
3516
  <div class="bg-surface-ground flex items-center justify-center min-h-screen">
3198
3517
  <div class="flex flex-col items-center justify-center w-full max-w-[32rem] px-4">
3199
3518
  <div
@@ -3292,6 +3611,33 @@ class LoginPageComponent {
3292
3611
  </form>
3293
3612
  }
3294
3613
 
3614
+ <!-- Email Verification Required -->
3615
+ @if (currentStep() === 'email-verification') {
3616
+ <div class="text-center">
3617
+ <div class="flex justify-center mb-6">
3618
+ <i class="pi pi-envelope text-6xl text-orange-500"></i>
3619
+ </div>
3620
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
3621
+ Email Not Verified
3622
+ </div>
3623
+ <p class="text-muted-color font-medium mb-6">
3624
+ Please verify your email address <strong>{{ unverifiedEmail() }}</strong> before logging in.
3625
+ </p>
3626
+ <p-button
3627
+ label="Resend Verification Email"
3628
+ styleClass="w-full mb-4"
3629
+ [loading]="isLoading()"
3630
+ (onClick)="onResendVerification()" />
3631
+ <div class="mt-4">
3632
+ <span
3633
+ class="font-semibold text-primary cursor-pointer"
3634
+ (click)="goBackToCredentials()">
3635
+ Back to Sign In
3636
+ </span>
3637
+ </div>
3638
+ </div>
3639
+ }
3640
+
3295
3641
  <!-- Step 2: Company Selection -->
3296
3642
  @if (currentStep() === 'company-selection') {
3297
3643
  <div class="text-center mb-8">
@@ -3361,15 +3707,16 @@ class LoginPageComponent {
3361
3707
  </div>
3362
3708
  </div>
3363
3709
  </div>
3364
- `, 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: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: i3.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: FormField, selector: "[formField]", inputs: ["formField"] }] });
3710
+ `, 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.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i3.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" }] });
3365
3711
  }
3366
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: LoginPageComponent, decorators: [{
3712
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: LoginPageComponent, decorators: [{
3367
3713
  type: Component,
3368
3714
  args: [{
3369
3715
  selector: 'lib-login-page',
3370
3716
  standalone: true,
3371
- imports: [AngularModule, PrimeModule, FormField],
3717
+ imports: [AngularModule, PrimeModule, FormField, AppFloatingConfigurator],
3372
3718
  template: `
3719
+ <app-floating-configurator />
3373
3720
  <div class="bg-surface-ground flex items-center justify-center min-h-screen">
3374
3721
  <div class="flex flex-col items-center justify-center w-full max-w-[32rem] px-4">
3375
3722
  <div
@@ -3468,6 +3815,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
3468
3815
  </form>
3469
3816
  }
3470
3817
 
3818
+ <!-- Email Verification Required -->
3819
+ @if (currentStep() === 'email-verification') {
3820
+ <div class="text-center">
3821
+ <div class="flex justify-center mb-6">
3822
+ <i class="pi pi-envelope text-6xl text-orange-500"></i>
3823
+ </div>
3824
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
3825
+ Email Not Verified
3826
+ </div>
3827
+ <p class="text-muted-color font-medium mb-6">
3828
+ Please verify your email address <strong>{{ unverifiedEmail() }}</strong> before logging in.
3829
+ </p>
3830
+ <p-button
3831
+ label="Resend Verification Email"
3832
+ styleClass="w-full mb-4"
3833
+ [loading]="isLoading()"
3834
+ (onClick)="onResendVerification()" />
3835
+ <div class="mt-4">
3836
+ <span
3837
+ class="font-semibold text-primary cursor-pointer"
3838
+ (click)="goBackToCredentials()">
3839
+ Back to Sign In
3840
+ </span>
3841
+ </div>
3842
+ </div>
3843
+ }
3844
+
3471
3845
  <!-- Step 2: Company Selection -->
3472
3846
  @if (currentStep() === 'company-selection') {
3473
3847
  <div class="text-center mb-8">
@@ -3547,35 +3921,876 @@ var loginPage_component = /*#__PURE__*/Object.freeze({
3547
3921
  });
3548
3922
 
3549
3923
  /**
3550
- * Registration Page Component
3551
- * Handles user registration with optional company creation
3552
- * Adapts UI based on company feature configuration
3924
+ * Profile Page Component
3925
+ *
3926
+ * Allows users to view and update their profile information.
3927
+ * Features:
3928
+ * - Update name, phone, profile picture (if storage enabled)
3929
+ * - View company/branch info (read-only, if company feature enabled)
3930
+ * - View roles/actions (read-only, if IAM enabled via optional injection)
3931
+ *
3932
+ * Package Independence:
3933
+ * - Uses PROFILE_UPLOAD_PROVIDER (optional) for storage functionality
3934
+ * - Uses PROFILE_PERMISSION_PROVIDER (optional) for IAM functionality
3935
+ * - No direct imports from ng-storage or ng-iam
3553
3936
  */
3554
- class RegisterPageComponent {
3937
+ class ProfilePageComponent {
3555
3938
  destroyRef = inject(DestroyRef);
3556
3939
  appConfig = inject(APP_CONFIG);
3557
3940
  messageService = inject(MessageService);
3558
- authApi = inject(AuthApiService);
3559
3941
  authState = inject(AuthStateService);
3560
- route = inject(ActivatedRoute);
3561
- /** Return URL after successful registration */
3562
- returnUrl = input('', ...(ngDevMode ? [{ debugName: "returnUrl" }] : []));
3563
- /** Loading state */
3942
+ userService = inject(UserApiService);
3943
+ authApiService = inject(AuthApiService);
3944
+ fileUrlService = inject(FileUrlService);
3945
+ // Optional injection - null if storage not configured
3946
+ uploadProvider = inject(PROFILE_UPLOAD_PROVIDER, {
3947
+ optional: true,
3948
+ });
3949
+ // Optional injection - null if IAM not configured
3950
+ permissionProvider = inject(PROFILE_PERMISSION_PROVIDER, {
3951
+ optional: true,
3952
+ });
3953
+ // State
3564
3954
  isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
3565
- /** Whether company feature is enabled */
3566
- companyFeatureEnabled = computed(() => isCompanyFeatureEnabled(this.appConfig), ...(ngDevMode ? [{ debugName: "companyFeatureEnabled" }] : []));
3567
- // ============================================
3568
- // User Form (Signal Forms)
3569
- // ============================================
3570
- /** User form model */
3571
- userFormModel = signal({
3955
+ isLoadingPermissions = signal(false, ...(ngDevMode ? [{ debugName: "isLoadingPermissions" }] : []));
3956
+ _profilePictureUrl = signal(null, ...(ngDevMode ? [{ debugName: "_profilePictureUrl" }] : []));
3957
+ profilePictureUrl = this._profilePictureUrl.asReadonly();
3958
+ // Permission data
3959
+ _userRoles = signal([], ...(ngDevMode ? [{ debugName: "_userRoles" }] : []));
3960
+ userRoles = this._userRoles.asReadonly();
3961
+ _userActions = signal([], ...(ngDevMode ? [{ debugName: "_userActions" }] : []));
3962
+ userActions = this._userActions.asReadonly();
3963
+ // Computed from auth state
3964
+ userEmail = computed(() => this.authState.user()?.email ?? '', ...(ngDevMode ? [{ debugName: "userEmail" }] : []));
3965
+ userName = computed(() => this.authState.user()?.name ?? 'User', ...(ngDevMode ? [{ debugName: "userName" }] : []));
3966
+ userInitials = computed(() => {
3967
+ const name = this.authState.user()?.name ?? '';
3968
+ return name
3969
+ .split(' ')
3970
+ .map((n) => n[0])
3971
+ .join('')
3972
+ .toUpperCase()
3973
+ .slice(0, 2);
3974
+ }, ...(ngDevMode ? [{ debugName: "userInitials" }] : []));
3975
+ companyName = computed(() => this.authState.companyName(), ...(ngDevMode ? [{ debugName: "companyName" }] : []));
3976
+ branchName = computed(() => this.authState.branchName(), ...(ngDevMode ? [{ debugName: "branchName" }] : []));
3977
+ // Feature flags - Storage feature check
3978
+ showUploadSection = computed(() => isFeatureEnabled(this.appConfig, 'storage') &&
3979
+ this.uploadProvider !== null, ...(ngDevMode ? [{ debugName: "showUploadSection" }] : []));
3980
+ showCompanySection = computed(() => isCompanyFeatureEnabled(this.appConfig), ...(ngDevMode ? [{ debugName: "showCompanySection" }] : []));
3981
+ showPermissionsSection = computed(() => isFeatureEnabled(this.appConfig, 'iam') &&
3982
+ this.permissionProvider !== null, ...(ngDevMode ? [{ debugName: "showPermissionsSection" }] : []));
3983
+ permissionMode = computed(() => getPermissionMode(this.appConfig), ...(ngDevMode ? [{ debugName: "permissionMode" }] : []));
3984
+ showRoles = computed(() => {
3985
+ const mode = this.permissionMode();
3986
+ return mode === 'rbac' || mode === 'full';
3987
+ }, ...(ngDevMode ? [{ debugName: "showRoles" }] : []));
3988
+ showActions = computed(() => {
3989
+ const mode = this.permissionMode();
3990
+ return mode === 'direct' || mode === 'full';
3991
+ }, ...(ngDevMode ? [{ debugName: "showActions" }] : []));
3992
+ // Show bottom row only if at least one section is visible
3993
+ showBottomRow = computed(() => this.showCompanySection() || this.showPermissionsSection(), ...(ngDevMode ? [{ debugName: "showBottomRow" }] : []));
3994
+ // Form
3995
+ formModel = signal({
3572
3996
  name: '',
3573
- email: '',
3574
- password: '',
3575
- confirmPassword: '',
3576
3997
  phone: '',
3577
- }, ...(ngDevMode ? [{ debugName: "userFormModel" }] : []));
3578
- /** User form with validation schema */
3998
+ }, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
3999
+ formTree = form(this.formModel, (f) => {
4000
+ required(f.name, { message: 'Name is required' });
4001
+ });
4002
+ isFormValid = computed(() => {
4003
+ const model = this.formModel();
4004
+ return model.name.trim().length > 0;
4005
+ }, ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
4006
+ // Password form
4007
+ passwordModel = signal({
4008
+ currentPassword: '',
4009
+ newPassword: '',
4010
+ confirmPassword: '',
4011
+ }, ...(ngDevMode ? [{ debugName: "passwordModel" }] : []));
4012
+ isPasswordLoading = signal(false, ...(ngDevMode ? [{ debugName: "isPasswordLoading" }] : []));
4013
+ isPasswordFormValid = computed(() => {
4014
+ const model = this.passwordModel();
4015
+ return (model.currentPassword.length > 0 &&
4016
+ model.newPassword.length >= 6 &&
4017
+ model.newPassword === model.confirmPassword);
4018
+ }, ...(ngDevMode ? [{ debugName: "isPasswordFormValid" }] : []));
4019
+ passwordsMatch = computed(() => {
4020
+ const model = this.passwordModel();
4021
+ return model.confirmPassword.length === 0 || model.newPassword === model.confirmPassword;
4022
+ }, ...(ngDevMode ? [{ debugName: "passwordsMatch" }] : []));
4023
+ // Upload function for FileUploader - uses provider if available
4024
+ uploadFileFn = (file, options) => {
4025
+ if (!this.uploadProvider) {
4026
+ throw new Error('Upload provider not available');
4027
+ }
4028
+ return this.uploadProvider
4029
+ .uploadProfilePicture(file, {
4030
+ folderPath: options?.folderPath ?? 'profile-pictures',
4031
+ compress: options?.compress ?? true,
4032
+ maxWidth: options?.maxWidth ?? 400,
4033
+ maxHeight: options?.maxHeight ?? 400,
4034
+ })
4035
+ .pipe(map((response) => ({
4036
+ success: response.success,
4037
+ message: response.message,
4038
+ data: response.data
4039
+ ? this.mapUploadResultToUploadedFile(response.data)
4040
+ : undefined,
4041
+ })));
4042
+ };
4043
+ /** Map upload result to IUploadedFile format */
4044
+ mapUploadResultToUploadedFile(result) {
4045
+ return {
4046
+ id: result.id, // UUID for storing in profilePictureId
4047
+ name: result.name,
4048
+ key: result.key,
4049
+ size: result.size,
4050
+ contentType: result.contentType,
4051
+ };
4052
+ }
4053
+ ngOnInit() {
4054
+ this.loadUserData();
4055
+ if (this.showPermissionsSection()) {
4056
+ this.loadPermissions();
4057
+ }
4058
+ }
4059
+ loadUserData() {
4060
+ const user = this.authState.user();
4061
+ if (user) {
4062
+ this.formModel.set({
4063
+ name: user.name ?? '',
4064
+ phone: user.phone ?? '',
4065
+ });
4066
+ // Load profile picture URL (only if storage is enabled)
4067
+ if (user.profilePictureId && isFeatureEnabled(this.appConfig, 'storage')) {
4068
+ this.fileUrlService
4069
+ .fetchSingleFileUrl(user.profilePictureId)
4070
+ .pipe(takeUntilDestroyed(this.destroyRef))
4071
+ .subscribe((file) => {
4072
+ this._profilePictureUrl.set(file?.url ?? null);
4073
+ });
4074
+ }
4075
+ }
4076
+ }
4077
+ loadPermissions() {
4078
+ const user = this.authState.user();
4079
+ const branch = this.authState.branch();
4080
+ if (!user || !this.permissionProvider)
4081
+ return;
4082
+ const loadRoles = this.showRoles();
4083
+ const loadActions = this.showActions();
4084
+ if (!loadRoles && !loadActions)
4085
+ return;
4086
+ this.isLoadingPermissions.set(true);
4087
+ let rolesLoaded = !loadRoles;
4088
+ let actionsLoaded = !loadActions;
4089
+ const checkComplete = () => {
4090
+ if (rolesLoaded && actionsLoaded) {
4091
+ this.isLoadingPermissions.set(false);
4092
+ }
4093
+ };
4094
+ // Load roles (if applicable)
4095
+ if (loadRoles) {
4096
+ this.permissionProvider
4097
+ .getUserRoles(user.id, branch?.id)
4098
+ .pipe(takeUntilDestroyed(this.destroyRef))
4099
+ .subscribe({
4100
+ next: (response) => {
4101
+ this._userRoles.set(response.data ?? []);
4102
+ rolesLoaded = true;
4103
+ checkComplete();
4104
+ },
4105
+ error: () => {
4106
+ this._userRoles.set([]);
4107
+ rolesLoaded = true;
4108
+ checkComplete();
4109
+ },
4110
+ });
4111
+ }
4112
+ // Load actions (if applicable)
4113
+ if (loadActions) {
4114
+ this.permissionProvider
4115
+ .getUserActions(user.id, branch?.id)
4116
+ .pipe(takeUntilDestroyed(this.destroyRef))
4117
+ .subscribe({
4118
+ next: (response) => {
4119
+ this._userActions.set(response.data ?? []);
4120
+ actionsLoaded = true;
4121
+ checkComplete();
4122
+ },
4123
+ error: () => {
4124
+ this._userActions.set([]);
4125
+ actionsLoaded = true;
4126
+ checkComplete();
4127
+ },
4128
+ });
4129
+ }
4130
+ }
4131
+ onProfilePictureUploaded(file) {
4132
+ // Update user with new profile picture ID (file.id is the FileManager UUID)
4133
+ const user = this.authState.user();
4134
+ if (!user || !file.id)
4135
+ return;
4136
+ const fileManagerId = file.id;
4137
+ this.userService
4138
+ .updateProfile({ id: user.id, profilePictureId: fileManagerId })
4139
+ .pipe(takeUntilDestroyed(this.destroyRef))
4140
+ .subscribe({
4141
+ next: (response) => {
4142
+ if (response.success && response.data) {
4143
+ // Update auth state with new profile picture ID
4144
+ this.authState.user.set({
4145
+ ...user,
4146
+ profilePictureId: fileManagerId,
4147
+ });
4148
+ // Fetch new profile picture URL (force refresh to get fresh URL)
4149
+ this.fileUrlService
4150
+ .fetchSingleFileUrl(fileManagerId, true)
4151
+ .pipe(takeUntilDestroyed(this.destroyRef))
4152
+ .subscribe((fileInfo) => {
4153
+ this._profilePictureUrl.set(fileInfo?.url ?? null);
4154
+ });
4155
+ this.messageService.add({
4156
+ severity: 'success',
4157
+ summary: 'Success',
4158
+ detail: 'Profile picture updated',
4159
+ });
4160
+ }
4161
+ },
4162
+ error: () => {
4163
+ this.messageService.add({
4164
+ severity: 'error',
4165
+ summary: 'Error',
4166
+ detail: 'Failed to update profile picture',
4167
+ });
4168
+ },
4169
+ });
4170
+ }
4171
+ onSubmit() {
4172
+ if (!this.isFormValid())
4173
+ return;
4174
+ const user = this.authState.user();
4175
+ if (!user)
4176
+ return;
4177
+ this.isLoading.set(true);
4178
+ const model = this.formModel();
4179
+ const updateData = {
4180
+ id: user.id,
4181
+ name: model.name,
4182
+ phone: model.phone || undefined,
4183
+ };
4184
+ this.userService
4185
+ .updateProfile(updateData)
4186
+ .pipe(takeUntilDestroyed(this.destroyRef))
4187
+ .subscribe({
4188
+ next: (response) => {
4189
+ if (response.success && response.data) {
4190
+ // Update auth state with new user data (name and phone)
4191
+ this.authState.user.set({
4192
+ ...user,
4193
+ name: response.data.name,
4194
+ phone: response.data.phone ?? null,
4195
+ });
4196
+ this.messageService.add({
4197
+ severity: 'success',
4198
+ summary: 'Success',
4199
+ detail: 'Profile updated successfully',
4200
+ });
4201
+ }
4202
+ this.isLoading.set(false);
4203
+ },
4204
+ error: (error) => {
4205
+ const err = error;
4206
+ this.messageService.add({
4207
+ severity: 'error',
4208
+ summary: 'Error',
4209
+ detail: err.error?.message || 'Failed to update profile',
4210
+ });
4211
+ this.isLoading.set(false);
4212
+ },
4213
+ });
4214
+ }
4215
+ updatePasswordField(field, value) {
4216
+ this.passwordModel.update((model) => ({ ...model, [field]: value }));
4217
+ }
4218
+ onChangePassword() {
4219
+ if (!this.isPasswordFormValid())
4220
+ return;
4221
+ this.isPasswordLoading.set(true);
4222
+ const model = this.passwordModel();
4223
+ this.authApiService
4224
+ .changePassword({
4225
+ currentPassword: model.currentPassword,
4226
+ newPassword: model.newPassword,
4227
+ })
4228
+ .pipe(takeUntilDestroyed(this.destroyRef))
4229
+ .subscribe({
4230
+ next: () => {
4231
+ this.messageService.add({
4232
+ severity: 'success',
4233
+ summary: 'Success',
4234
+ detail: 'Password changed successfully',
4235
+ });
4236
+ // Reset password form
4237
+ this.passwordModel.set({
4238
+ currentPassword: '',
4239
+ newPassword: '',
4240
+ confirmPassword: '',
4241
+ });
4242
+ this.isPasswordLoading.set(false);
4243
+ },
4244
+ error: (error) => {
4245
+ const err = error;
4246
+ this.messageService.add({
4247
+ severity: 'error',
4248
+ summary: 'Error',
4249
+ detail: err.error?.message || 'Failed to change password',
4250
+ });
4251
+ this.isPasswordLoading.set(false);
4252
+ },
4253
+ });
4254
+ }
4255
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ProfilePageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4256
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ProfilePageComponent, isStandalone: true, selector: "lib-profile-page", ngImport: i0, template: `
4257
+ <!-- Page Header -->
4258
+ <div class="mb-4 md:mb-6">
4259
+ <h1 class="text-2xl font-bold text-color mb-2">My Profile</h1>
4260
+ <p class="text-muted-color">Manage your account settings and preferences.</p>
4261
+ </div>
4262
+
4263
+ <!-- Profile Form Card (full width) -->
4264
+ <div class="card mb-2 md:mb-4">
4265
+ <div class="flex flex-col md:flex-row gap-4 md:gap-6">
4266
+ <!-- Avatar Section -->
4267
+ <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">
4268
+ @if (profilePictureUrl()) {
4269
+ <p-avatar
4270
+ [image]="profilePictureUrl()!"
4271
+ size="xlarge"
4272
+ shape="circle"
4273
+ styleClass="w-28 h-28" />
4274
+ } @else {
4275
+ <p-avatar
4276
+ [label]="userInitials()"
4277
+ size="xlarge"
4278
+ shape="circle"
4279
+ styleClass="w-28 h-28 text-3xl bg-primary text-primary-contrast" />
4280
+ }
4281
+ <div class="text-center">
4282
+ <div class="font-semibold text-color">{{ userName() }}</div>
4283
+ <div class="text-muted-color text-sm">{{ userEmail() }}</div>
4284
+ </div>
4285
+ <!-- Upload section - only show if storage is enabled and provider is available -->
4286
+ @if (showUploadSection()) {
4287
+ <lib-file-uploader
4288
+ [uploadFile]="uploadFileFn"
4289
+ [acceptTypes]="['image/*']"
4290
+ [multiple]="false"
4291
+ [maxSizeMb]="5"
4292
+ [showPreview]="false"
4293
+ (fileUploaded)="onProfilePictureUploaded($event)"
4294
+ class="w-full" />
4295
+ } @else {
4296
+ <div class="w-full p-3 bg-surface-100 rounded-lg text-center">
4297
+ <i class="pi pi-info-circle text-muted-color mr-2"></i>
4298
+ <span class="text-sm text-muted-color">Storage feature not enabled</span>
4299
+ </div>
4300
+ }
4301
+ </div>
4302
+
4303
+ <!-- Form Section -->
4304
+ <div class="flex-1">
4305
+ <form (ngSubmit)="onSubmit()" class="flex flex-col gap-4">
4306
+ <!-- Email (read-only) -->
4307
+ <div class="flex flex-col gap-2">
4308
+ <label class="font-medium text-color">Email</label>
4309
+ <input
4310
+ pInputText
4311
+ [value]="userEmail()"
4312
+ disabled
4313
+ class="bg-surface-50" />
4314
+ </div>
4315
+
4316
+ <!-- Name -->
4317
+ <div class="flex flex-col gap-2">
4318
+ <label for="name" class="font-medium text-color">Name *</label>
4319
+ <input
4320
+ pInputText
4321
+ id="name"
4322
+ [formField]="formTree.name"
4323
+ placeholder="Your full name" />
4324
+ </div>
4325
+
4326
+ <!-- Phone -->
4327
+ <div class="flex flex-col gap-2">
4328
+ <label for="phone" class="font-medium text-color">Phone</label>
4329
+ <input
4330
+ pInputText
4331
+ id="phone"
4332
+ [formField]="formTree.phone"
4333
+ placeholder="+1 234 567 8900" />
4334
+ </div>
4335
+
4336
+ <!-- Submit -->
4337
+ <div class="flex justify-end pt-4">
4338
+ <p-button
4339
+ label="Save Changes"
4340
+ icon="pi pi-check"
4341
+ type="submit"
4342
+ [loading]="isLoading()"
4343
+ [disabled]="!isFormValid() || isLoading()" />
4344
+ </div>
4345
+ </form>
4346
+ </div>
4347
+ </div>
4348
+ </div>
4349
+
4350
+ <!-- Security Card -->
4351
+ <div class="card mb-2 md:mb-4">
4352
+ <div class="flex items-center gap-2 mb-4">
4353
+ <i class="pi pi-lock text-primary"></i>
4354
+ <span class="font-semibold text-color">Security</span>
4355
+ </div>
4356
+ <form (ngSubmit)="onChangePassword()" class="flex flex-col gap-4">
4357
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
4358
+ <!-- Current Password -->
4359
+ <div class="flex flex-col gap-2">
4360
+ <label for="currentPassword" class="font-medium text-color">Current Password *</label>
4361
+ <p-password
4362
+ id="currentPassword"
4363
+ name="currentPassword"
4364
+ [ngModel]="passwordModel().currentPassword"
4365
+ (ngModelChange)="updatePasswordField('currentPassword', $event)"
4366
+ [feedback]="false"
4367
+ [toggleMask]="true"
4368
+ placeholder="Enter current password"
4369
+ styleClass="w-full"
4370
+ inputStyleClass="w-full" />
4371
+ </div>
4372
+
4373
+ <!-- New Password -->
4374
+ <div class="flex flex-col gap-2">
4375
+ <label for="newPassword" class="font-medium text-color">New Password *</label>
4376
+ <p-password
4377
+ id="newPassword"
4378
+ name="newPassword"
4379
+ [ngModel]="passwordModel().newPassword"
4380
+ (ngModelChange)="updatePasswordField('newPassword', $event)"
4381
+ [feedback]="true"
4382
+ [toggleMask]="true"
4383
+ placeholder="Min 6 characters"
4384
+ styleClass="w-full"
4385
+ inputStyleClass="w-full" />
4386
+ </div>
4387
+
4388
+ <!-- Confirm Password -->
4389
+ <div class="flex flex-col gap-2">
4390
+ <label for="confirmPassword" class="font-medium text-color">Confirm Password *</label>
4391
+ <p-password
4392
+ id="confirmPassword"
4393
+ name="confirmPassword"
4394
+ [ngModel]="passwordModel().confirmPassword"
4395
+ (ngModelChange)="updatePasswordField('confirmPassword', $event)"
4396
+ [feedback]="false"
4397
+ [toggleMask]="true"
4398
+ placeholder="Confirm new password"
4399
+ styleClass="w-full"
4400
+ inputStyleClass="w-full" />
4401
+ @if (!passwordsMatch()) {
4402
+ <small class="text-red-500">Passwords do not match</small>
4403
+ }
4404
+ </div>
4405
+ </div>
4406
+
4407
+ <!-- Submit -->
4408
+ <div class="flex justify-end">
4409
+ <p-button
4410
+ label="Change Password"
4411
+ icon="pi pi-key"
4412
+ type="submit"
4413
+ [loading]="isPasswordLoading()"
4414
+ [disabled]="!isPasswordFormValid() || isPasswordLoading()" />
4415
+ </div>
4416
+ </form>
4417
+ </div>
4418
+
4419
+ <!-- Company & Permissions Row (50/50 on desktop, stacked on mobile) -->
4420
+ @if (showBottomRow()) {
4421
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-2 md:gap-4 flex-1">
4422
+ <!-- Company/Branch Info -->
4423
+ @if (showCompanySection()) {
4424
+ <div class="card h-48 md:h-56 flex flex-col">
4425
+ <div class="flex items-center gap-2 mb-4">
4426
+ <i class="pi pi-building text-primary"></i>
4427
+ <span class="font-semibold text-color">Company & Branch</span>
4428
+ </div>
4429
+ <div class="flex flex-col gap-4 flex-1 overflow-auto">
4430
+ <div class="flex items-center gap-3">
4431
+ <div class="w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center flex-shrink-0">
4432
+ <i class="pi pi-briefcase text-primary"></i>
4433
+ </div>
4434
+ <div>
4435
+ <div class="text-sm text-muted-color">Company</div>
4436
+ <div class="font-medium text-color">{{ companyName() || 'Not assigned' }}</div>
4437
+ </div>
4438
+ </div>
4439
+ <div class="flex items-center gap-3">
4440
+ <div class="w-10 h-10 rounded-lg bg-green-500/10 flex items-center justify-center flex-shrink-0">
4441
+ <i class="pi pi-map-marker text-green-500"></i>
4442
+ </div>
4443
+ <div>
4444
+ <div class="text-sm text-muted-color">Branch</div>
4445
+ <div class="font-medium text-color">{{ branchName() || 'Not assigned' }}</div>
4446
+ </div>
4447
+ </div>
4448
+ </div>
4449
+ </div>
4450
+ }
4451
+
4452
+ <!-- Permissions -->
4453
+ @if (showPermissionsSection()) {
4454
+ <div class="card h-48 md:h-56 flex flex-col">
4455
+ <div class="flex items-center justify-between mb-4">
4456
+ <div class="flex items-center gap-2">
4457
+ <i class="pi pi-shield text-primary"></i>
4458
+ <span class="font-semibold text-color">My Permissions</span>
4459
+ </div>
4460
+ <p-tag value="Read-only" severity="secondary" />
4461
+ </div>
4462
+ <div class="flex flex-col gap-4 flex-1 overflow-auto">
4463
+ <!-- Roles -->
4464
+ @if (showRoles()) {
4465
+ <div>
4466
+ <div class="text-sm text-muted-color mb-2 flex items-center gap-2">
4467
+ <i class="pi pi-users"></i> Roles
4468
+ </div>
4469
+ @if (isLoadingPermissions()) {
4470
+ <p-skeleton height="1.5rem" styleClass="mb-2" />
4471
+ } @else if (userRoles().length === 0) {
4472
+ <span class="text-muted-color text-sm">No roles assigned</span>
4473
+ } @else {
4474
+ <div class="flex flex-wrap gap-2">
4475
+ @for (role of userRoles(); track role.id) {
4476
+ <p-tag [value]="role.name" severity="info" />
4477
+ }
4478
+ </div>
4479
+ }
4480
+ </div>
4481
+ }
4482
+
4483
+ <!-- Actions -->
4484
+ @if (showActions()) {
4485
+ <div>
4486
+ <div class="text-sm text-muted-color mb-2 flex items-center gap-2">
4487
+ <i class="pi pi-bolt"></i> Direct Actions
4488
+ </div>
4489
+ @if (isLoadingPermissions()) {
4490
+ <p-skeleton height="1.5rem" styleClass="mb-2" />
4491
+ } @else if (userActions().length === 0) {
4492
+ <span class="text-muted-color text-sm">No actions assigned</span>
4493
+ } @else {
4494
+ <div class="flex flex-wrap gap-2">
4495
+ @for (action of userActions(); track action.id) {
4496
+ <p-tag [value]="action.name" severity="success" />
4497
+ }
4498
+ </div>
4499
+ }
4500
+ </div>
4501
+ }
4502
+ </div>
4503
+ </div>
4504
+ }
4505
+ </div>
4506
+ }
4507
+ `, 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$1.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "component", type: i3.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 });
4508
+ }
4509
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ProfilePageComponent, decorators: [{
4510
+ type: Component,
4511
+ args: [{
4512
+ selector: 'lib-profile-page',
4513
+ standalone: true,
4514
+ imports: [AngularModule, PrimeModule, FormField, FileUploaderComponent],
4515
+ template: `
4516
+ <!-- Page Header -->
4517
+ <div class="mb-4 md:mb-6">
4518
+ <h1 class="text-2xl font-bold text-color mb-2">My Profile</h1>
4519
+ <p class="text-muted-color">Manage your account settings and preferences.</p>
4520
+ </div>
4521
+
4522
+ <!-- Profile Form Card (full width) -->
4523
+ <div class="card mb-2 md:mb-4">
4524
+ <div class="flex flex-col md:flex-row gap-4 md:gap-6">
4525
+ <!-- Avatar Section -->
4526
+ <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">
4527
+ @if (profilePictureUrl()) {
4528
+ <p-avatar
4529
+ [image]="profilePictureUrl()!"
4530
+ size="xlarge"
4531
+ shape="circle"
4532
+ styleClass="w-28 h-28" />
4533
+ } @else {
4534
+ <p-avatar
4535
+ [label]="userInitials()"
4536
+ size="xlarge"
4537
+ shape="circle"
4538
+ styleClass="w-28 h-28 text-3xl bg-primary text-primary-contrast" />
4539
+ }
4540
+ <div class="text-center">
4541
+ <div class="font-semibold text-color">{{ userName() }}</div>
4542
+ <div class="text-muted-color text-sm">{{ userEmail() }}</div>
4543
+ </div>
4544
+ <!-- Upload section - only show if storage is enabled and provider is available -->
4545
+ @if (showUploadSection()) {
4546
+ <lib-file-uploader
4547
+ [uploadFile]="uploadFileFn"
4548
+ [acceptTypes]="['image/*']"
4549
+ [multiple]="false"
4550
+ [maxSizeMb]="5"
4551
+ [showPreview]="false"
4552
+ (fileUploaded)="onProfilePictureUploaded($event)"
4553
+ class="w-full" />
4554
+ } @else {
4555
+ <div class="w-full p-3 bg-surface-100 rounded-lg text-center">
4556
+ <i class="pi pi-info-circle text-muted-color mr-2"></i>
4557
+ <span class="text-sm text-muted-color">Storage feature not enabled</span>
4558
+ </div>
4559
+ }
4560
+ </div>
4561
+
4562
+ <!-- Form Section -->
4563
+ <div class="flex-1">
4564
+ <form (ngSubmit)="onSubmit()" class="flex flex-col gap-4">
4565
+ <!-- Email (read-only) -->
4566
+ <div class="flex flex-col gap-2">
4567
+ <label class="font-medium text-color">Email</label>
4568
+ <input
4569
+ pInputText
4570
+ [value]="userEmail()"
4571
+ disabled
4572
+ class="bg-surface-50" />
4573
+ </div>
4574
+
4575
+ <!-- Name -->
4576
+ <div class="flex flex-col gap-2">
4577
+ <label for="name" class="font-medium text-color">Name *</label>
4578
+ <input
4579
+ pInputText
4580
+ id="name"
4581
+ [formField]="formTree.name"
4582
+ placeholder="Your full name" />
4583
+ </div>
4584
+
4585
+ <!-- Phone -->
4586
+ <div class="flex flex-col gap-2">
4587
+ <label for="phone" class="font-medium text-color">Phone</label>
4588
+ <input
4589
+ pInputText
4590
+ id="phone"
4591
+ [formField]="formTree.phone"
4592
+ placeholder="+1 234 567 8900" />
4593
+ </div>
4594
+
4595
+ <!-- Submit -->
4596
+ <div class="flex justify-end pt-4">
4597
+ <p-button
4598
+ label="Save Changes"
4599
+ icon="pi pi-check"
4600
+ type="submit"
4601
+ [loading]="isLoading()"
4602
+ [disabled]="!isFormValid() || isLoading()" />
4603
+ </div>
4604
+ </form>
4605
+ </div>
4606
+ </div>
4607
+ </div>
4608
+
4609
+ <!-- Security Card -->
4610
+ <div class="card mb-2 md:mb-4">
4611
+ <div class="flex items-center gap-2 mb-4">
4612
+ <i class="pi pi-lock text-primary"></i>
4613
+ <span class="font-semibold text-color">Security</span>
4614
+ </div>
4615
+ <form (ngSubmit)="onChangePassword()" class="flex flex-col gap-4">
4616
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
4617
+ <!-- Current Password -->
4618
+ <div class="flex flex-col gap-2">
4619
+ <label for="currentPassword" class="font-medium text-color">Current Password *</label>
4620
+ <p-password
4621
+ id="currentPassword"
4622
+ name="currentPassword"
4623
+ [ngModel]="passwordModel().currentPassword"
4624
+ (ngModelChange)="updatePasswordField('currentPassword', $event)"
4625
+ [feedback]="false"
4626
+ [toggleMask]="true"
4627
+ placeholder="Enter current password"
4628
+ styleClass="w-full"
4629
+ inputStyleClass="w-full" />
4630
+ </div>
4631
+
4632
+ <!-- New Password -->
4633
+ <div class="flex flex-col gap-2">
4634
+ <label for="newPassword" class="font-medium text-color">New Password *</label>
4635
+ <p-password
4636
+ id="newPassword"
4637
+ name="newPassword"
4638
+ [ngModel]="passwordModel().newPassword"
4639
+ (ngModelChange)="updatePasswordField('newPassword', $event)"
4640
+ [feedback]="true"
4641
+ [toggleMask]="true"
4642
+ placeholder="Min 6 characters"
4643
+ styleClass="w-full"
4644
+ inputStyleClass="w-full" />
4645
+ </div>
4646
+
4647
+ <!-- Confirm Password -->
4648
+ <div class="flex flex-col gap-2">
4649
+ <label for="confirmPassword" class="font-medium text-color">Confirm Password *</label>
4650
+ <p-password
4651
+ id="confirmPassword"
4652
+ name="confirmPassword"
4653
+ [ngModel]="passwordModel().confirmPassword"
4654
+ (ngModelChange)="updatePasswordField('confirmPassword', $event)"
4655
+ [feedback]="false"
4656
+ [toggleMask]="true"
4657
+ placeholder="Confirm new password"
4658
+ styleClass="w-full"
4659
+ inputStyleClass="w-full" />
4660
+ @if (!passwordsMatch()) {
4661
+ <small class="text-red-500">Passwords do not match</small>
4662
+ }
4663
+ </div>
4664
+ </div>
4665
+
4666
+ <!-- Submit -->
4667
+ <div class="flex justify-end">
4668
+ <p-button
4669
+ label="Change Password"
4670
+ icon="pi pi-key"
4671
+ type="submit"
4672
+ [loading]="isPasswordLoading()"
4673
+ [disabled]="!isPasswordFormValid() || isPasswordLoading()" />
4674
+ </div>
4675
+ </form>
4676
+ </div>
4677
+
4678
+ <!-- Company & Permissions Row (50/50 on desktop, stacked on mobile) -->
4679
+ @if (showBottomRow()) {
4680
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-2 md:gap-4 flex-1">
4681
+ <!-- Company/Branch Info -->
4682
+ @if (showCompanySection()) {
4683
+ <div class="card h-48 md:h-56 flex flex-col">
4684
+ <div class="flex items-center gap-2 mb-4">
4685
+ <i class="pi pi-building text-primary"></i>
4686
+ <span class="font-semibold text-color">Company & Branch</span>
4687
+ </div>
4688
+ <div class="flex flex-col gap-4 flex-1 overflow-auto">
4689
+ <div class="flex items-center gap-3">
4690
+ <div class="w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center flex-shrink-0">
4691
+ <i class="pi pi-briefcase text-primary"></i>
4692
+ </div>
4693
+ <div>
4694
+ <div class="text-sm text-muted-color">Company</div>
4695
+ <div class="font-medium text-color">{{ companyName() || 'Not assigned' }}</div>
4696
+ </div>
4697
+ </div>
4698
+ <div class="flex items-center gap-3">
4699
+ <div class="w-10 h-10 rounded-lg bg-green-500/10 flex items-center justify-center flex-shrink-0">
4700
+ <i class="pi pi-map-marker text-green-500"></i>
4701
+ </div>
4702
+ <div>
4703
+ <div class="text-sm text-muted-color">Branch</div>
4704
+ <div class="font-medium text-color">{{ branchName() || 'Not assigned' }}</div>
4705
+ </div>
4706
+ </div>
4707
+ </div>
4708
+ </div>
4709
+ }
4710
+
4711
+ <!-- Permissions -->
4712
+ @if (showPermissionsSection()) {
4713
+ <div class="card h-48 md:h-56 flex flex-col">
4714
+ <div class="flex items-center justify-between mb-4">
4715
+ <div class="flex items-center gap-2">
4716
+ <i class="pi pi-shield text-primary"></i>
4717
+ <span class="font-semibold text-color">My Permissions</span>
4718
+ </div>
4719
+ <p-tag value="Read-only" severity="secondary" />
4720
+ </div>
4721
+ <div class="flex flex-col gap-4 flex-1 overflow-auto">
4722
+ <!-- Roles -->
4723
+ @if (showRoles()) {
4724
+ <div>
4725
+ <div class="text-sm text-muted-color mb-2 flex items-center gap-2">
4726
+ <i class="pi pi-users"></i> Roles
4727
+ </div>
4728
+ @if (isLoadingPermissions()) {
4729
+ <p-skeleton height="1.5rem" styleClass="mb-2" />
4730
+ } @else if (userRoles().length === 0) {
4731
+ <span class="text-muted-color text-sm">No roles assigned</span>
4732
+ } @else {
4733
+ <div class="flex flex-wrap gap-2">
4734
+ @for (role of userRoles(); track role.id) {
4735
+ <p-tag [value]="role.name" severity="info" />
4736
+ }
4737
+ </div>
4738
+ }
4739
+ </div>
4740
+ }
4741
+
4742
+ <!-- Actions -->
4743
+ @if (showActions()) {
4744
+ <div>
4745
+ <div class="text-sm text-muted-color mb-2 flex items-center gap-2">
4746
+ <i class="pi pi-bolt"></i> Direct Actions
4747
+ </div>
4748
+ @if (isLoadingPermissions()) {
4749
+ <p-skeleton height="1.5rem" styleClass="mb-2" />
4750
+ } @else if (userActions().length === 0) {
4751
+ <span class="text-muted-color text-sm">No actions assigned</span>
4752
+ } @else {
4753
+ <div class="flex flex-wrap gap-2">
4754
+ @for (action of userActions(); track action.id) {
4755
+ <p-tag [value]="action.name" severity="success" />
4756
+ }
4757
+ </div>
4758
+ }
4759
+ </div>
4760
+ }
4761
+ </div>
4762
+ </div>
4763
+ }
4764
+ </div>
4765
+ }
4766
+ `,
4767
+ changeDetection: ChangeDetectionStrategy.OnPush,
4768
+ }]
4769
+ }] });
4770
+
4771
+ var profilePage_component = /*#__PURE__*/Object.freeze({
4772
+ __proto__: null,
4773
+ ProfilePageComponent: ProfilePageComponent
4774
+ });
4775
+
4776
+ class RegisterPageComponent {
4777
+ destroyRef = inject(DestroyRef);
4778
+ appConfig = inject(APP_CONFIG);
4779
+ messageService = inject(MessageService);
4780
+ authApi = inject(AuthApiService);
4781
+ authState = inject(AuthStateService);
4782
+ route = inject(ActivatedRoute);
4783
+ router = inject(Router);
4784
+ returnUrl = input('', ...(ngDevMode ? [{ debugName: "returnUrl" }] : []));
4785
+ isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
4786
+ companyFeatureEnabled = computed(() => isCompanyFeatureEnabled(this.appConfig), ...(ngDevMode ? [{ debugName: "companyFeatureEnabled" }] : []));
4787
+ userFormModel = signal({
4788
+ name: '',
4789
+ email: '',
4790
+ password: '',
4791
+ confirmPassword: '',
4792
+ phone: '',
4793
+ }, ...(ngDevMode ? [{ debugName: "userFormModel" }] : []));
3579
4794
  userForm = form(this.userFormModel, (f) => {
3580
4795
  required(f.name, { message: 'Name is required' });
3581
4796
  minLength(f.name, 2, { message: 'Name must be at least 2 characters' });
@@ -3585,10 +4800,6 @@ class RegisterPageComponent {
3585
4800
  minLength(f.password, 6, { message: 'Password must be at least 6 characters' });
3586
4801
  required(f.confirmPassword, { message: 'Please confirm your password' });
3587
4802
  });
3588
- // ============================================
3589
- // Company Form (Signal Forms)
3590
- // ============================================
3591
- /** Company form model */
3592
4803
  companyFormModel = signal({
3593
4804
  createNewCompany: false,
3594
4805
  companySlug: '',
@@ -3597,59 +4808,35 @@ class RegisterPageComponent {
3597
4808
  newCompanyPhone: '',
3598
4809
  newCompanyAddress: '',
3599
4810
  }, ...(ngDevMode ? [{ debugName: "companyFormModel" }] : []));
3600
- /** Company form with conditional validation schema */
3601
- companyForm = form(this.companyFormModel, (f) => {
3602
- // Validation is conditional based on createNewCompany flag
3603
- // We'll handle this in isFormValid() computed
3604
- });
3605
- // ============================================
3606
- // Lifecycle
3607
- // ============================================
3608
- ngOnInit() {
3609
- // Read companySlug from query params and prefill the form
3610
- const companySlug = this.route.snapshot.queryParamMap.get('companySlug');
3611
- if (companySlug) {
3612
- this.companyFormModel.update((model) => ({
3613
- ...model,
3614
- companySlug,
3615
- }));
3616
- }
3617
- }
3618
- // ============================================
3619
- // Form Validation
3620
- // ============================================
3621
- /** Check if passwords match */
4811
+ companyForm = form(this.companyFormModel, (f) => { });
3622
4812
  passwordsMatch = computed(() => {
3623
4813
  const model = this.userFormModel();
3624
4814
  return model.password === model.confirmPassword;
3625
4815
  }, ...(ngDevMode ? [{ debugName: "passwordsMatch" }] : []));
3626
- /** Check if form is valid */
3627
4816
  isFormValid = computed(() => {
3628
4817
  const userModel = this.userFormModel();
3629
- // User validation
3630
4818
  const userValid = userModel.name.trim().length >= 2 &&
3631
4819
  userModel.email.includes('@') &&
3632
4820
  userModel.password.length >= 6 &&
3633
4821
  userModel.confirmPassword.length > 0 &&
3634
4822
  this.passwordsMatch();
3635
- if (!isCompanyFeatureEnabled(this.appConfig)) {
4823
+ if (!isCompanyFeatureEnabled(this.appConfig))
3636
4824
  return userValid;
3637
- }
3638
4825
  const companyModel = this.companyFormModel();
3639
- // Company validation
3640
4826
  if (companyModel.createNewCompany) {
3641
4827
  return userValid && companyModel.newCompanyName.trim().length > 0;
3642
4828
  }
3643
4829
  return userValid;
3644
4830
  }, ...(ngDevMode ? [{ debugName: "isFormValid" }] : []));
3645
- // ============================================
3646
- // Event Handlers
3647
- // ============================================
4831
+ ngOnInit() {
4832
+ const companySlug = this.route.snapshot.queryParamMap.get('companySlug');
4833
+ if (companySlug) {
4834
+ this.companyFormModel.update((model) => ({ ...model, companySlug }));
4835
+ }
4836
+ }
3648
4837
  onCreateCompanyToggle() {
3649
4838
  const currentValue = this.companyFormModel().createNewCompany;
3650
- // Reset fields when toggling
3651
4839
  if (!currentValue) {
3652
- // Toggling to create new company
3653
4840
  this.companyFormModel.update((model) => ({
3654
4841
  ...model,
3655
4842
  createNewCompany: true,
@@ -3658,7 +4845,6 @@ class RegisterPageComponent {
3658
4845
  }));
3659
4846
  }
3660
4847
  else {
3661
- // Toggling to join existing company
3662
4848
  this.companyFormModel.update((model) => ({
3663
4849
  ...model,
3664
4850
  createNewCompany: false,
@@ -3686,7 +4872,6 @@ class RegisterPageComponent {
3686
4872
  password: userModel.password,
3687
4873
  phone: userModel.phone || undefined,
3688
4874
  };
3689
- // Add company fields if company feature enabled
3690
4875
  if (isCompanyFeatureEnabled(this.appConfig)) {
3691
4876
  if (companyModel.createNewCompany) {
3692
4877
  registrationData.newCompanyName =
@@ -3703,13 +4888,21 @@ class RegisterPageComponent {
3703
4888
  }
3704
4889
  this.authApi
3705
4890
  .register(registrationData)
3706
- .pipe(take(1), takeUntilDestroyed(this.destroyRef))
4891
+ .pipe(takeUntilDestroyed(this.destroyRef))
3707
4892
  .subscribe({
3708
4893
  next: (response) => {
3709
4894
  this.isLoading.set(false);
3710
- // Backend returns RegistrationResponse directly (not wrapped)
3711
- if (response && response.accessToken) {
3712
- // Set auth state with registration response
4895
+ if (response.requiresEmailVerification) {
4896
+ this.messageService.add({
4897
+ severity: 'success',
4898
+ summary: 'Account Created',
4899
+ detail: 'Please check your email to verify your account.',
4900
+ life: 5000,
4901
+ });
4902
+ this.router.navigate(['/auth/login']);
4903
+ return;
4904
+ }
4905
+ if (response.accessToken) {
3713
4906
  this.authState.setLoginState({
3714
4907
  accessToken: response.accessToken,
3715
4908
  refreshToken: response.refreshToken,
@@ -3725,27 +4918,20 @@ class RegisterPageComponent {
3725
4918
  });
3726
4919
  this.authState.navigateAfterLogin(this.returnUrl());
3727
4920
  }
3728
- else {
3729
- this.messageService.add({
3730
- severity: 'error',
3731
- summary: 'Registration Failed',
3732
- detail: 'Unable to create account. Please try again.',
3733
- });
3734
- }
3735
4921
  },
3736
4922
  error: (error) => {
3737
4923
  this.isLoading.set(false);
3738
4924
  this.messageService.add({
3739
4925
  severity: 'error',
3740
4926
  summary: 'Registration Failed',
3741
- detail: error.error?.message ||
3742
- 'Unable to create account. Please try again.',
4927
+ detail: error.error?.message || 'Unable to create account. Please try again.',
3743
4928
  });
3744
4929
  },
3745
4930
  });
3746
4931
  }
3747
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: RegisterPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3748
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: RegisterPageComponent, isStandalone: true, selector: "lib-register-page", inputs: { returnUrl: { classPropertyName: "returnUrl", publicName: "returnUrl", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
4932
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: RegisterPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4933
+ 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: `
4934
+ <app-floating-configurator />
3749
4935
  <div
3750
4936
  class="bg-surface-ground flex items-center justify-center min-h-screen py-8"
3751
4937
  >
@@ -3770,7 +4956,6 @@ class RegisterPageComponent {
3770
4956
  </div>
3771
4957
 
3772
4958
  <form (ngSubmit)="onSubmit()">
3773
- <!-- User Information -->
3774
4959
  <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
3775
4960
  <div>
3776
4961
  <label for="name" class="block font-medium mb-2"
@@ -3853,7 +5038,6 @@ class RegisterPageComponent {
3853
5038
  </div>
3854
5039
  </div>
3855
5040
 
3856
- <!-- Company Feature Section -->
3857
5041
  @if (companyFeatureEnabled()) {
3858
5042
  <div
3859
5043
  class="border-t pt-6 mt-6"
@@ -3881,9 +5065,7 @@ class RegisterPageComponent {
3881
5065
  </label>
3882
5066
  </div>
3883
5067
 
3884
- <!-- Fixed height container to prevent height changes -->
3885
5068
  @if (!companyFormModel().createNewCompany) {
3886
- <!-- Join Existing Company -->
3887
5069
  <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
3888
5070
  <div>
3889
5071
  <label for="companySlug" class="block font-medium mb-2"
@@ -3915,7 +5097,6 @@ class RegisterPageComponent {
3915
5097
  </div>
3916
5098
  </div>
3917
5099
  } @else {
3918
- <!-- Create New Company -->
3919
5100
  <div class="mb-4">
3920
5101
  <label for="newCompanyName" class="block font-medium mb-2"
3921
5102
  >Company Name *</label
@@ -3962,7 +5143,6 @@ class RegisterPageComponent {
3962
5143
  </div>
3963
5144
  }
3964
5145
 
3965
- <!-- Submit -->
3966
5146
  <p-button
3967
5147
  label="Create Account"
3968
5148
  styleClass="w-full mt-4"
@@ -3985,15 +5165,16 @@ class RegisterPageComponent {
3985
5165
  </div>
3986
5166
  </div>
3987
5167
  </div>
3988
- `, 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: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: i3.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: FormField, selector: "[formField]", inputs: ["formField"] }] });
5168
+ `, 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.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i3.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" }] });
3989
5169
  }
3990
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: RegisterPageComponent, decorators: [{
5170
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: RegisterPageComponent, decorators: [{
3991
5171
  type: Component,
3992
5172
  args: [{
3993
5173
  selector: 'lib-register-page',
3994
5174
  standalone: true,
3995
- imports: [AngularModule, PrimeModule, FormField],
5175
+ imports: [AngularModule, PrimeModule, FormField, AppFloatingConfigurator],
3996
5176
  template: `
5177
+ <app-floating-configurator />
3997
5178
  <div
3998
5179
  class="bg-surface-ground flex items-center justify-center min-h-screen py-8"
3999
5180
  >
@@ -4018,7 +5199,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
4018
5199
  </div>
4019
5200
 
4020
5201
  <form (ngSubmit)="onSubmit()">
4021
- <!-- User Information -->
4022
5202
  <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
4023
5203
  <div>
4024
5204
  <label for="name" class="block font-medium mb-2"
@@ -4101,7 +5281,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
4101
5281
  </div>
4102
5282
  </div>
4103
5283
 
4104
- <!-- Company Feature Section -->
4105
5284
  @if (companyFeatureEnabled()) {
4106
5285
  <div
4107
5286
  class="border-t pt-6 mt-6"
@@ -4129,9 +5308,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
4129
5308
  </label>
4130
5309
  </div>
4131
5310
 
4132
- <!-- Fixed height container to prevent height changes -->
4133
5311
  @if (!companyFormModel().createNewCompany) {
4134
- <!-- Join Existing Company -->
4135
5312
  <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
4136
5313
  <div>
4137
5314
  <label for="companySlug" class="block font-medium mb-2"
@@ -4149,97 +5326,402 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
4149
5326
  >
4150
5327
  </div>
4151
5328
 
4152
- <div>
4153
- <label for="branchSlug" class="block font-medium mb-2"
4154
- >Branch Code</label
4155
- >
4156
- <input
4157
- pInputText
4158
- id="branchSlug"
4159
- [formField]="companyForm.branchSlug"
4160
- placeholder="Branch code (optional)"
4161
- class="w-full"
4162
- />
5329
+ <div>
5330
+ <label for="branchSlug" class="block font-medium mb-2"
5331
+ >Branch Code</label
5332
+ >
5333
+ <input
5334
+ pInputText
5335
+ id="branchSlug"
5336
+ [formField]="companyForm.branchSlug"
5337
+ placeholder="Branch code (optional)"
5338
+ class="w-full"
5339
+ />
5340
+ </div>
5341
+ </div>
5342
+ } @else {
5343
+ <div class="mb-4">
5344
+ <label for="newCompanyName" class="block font-medium mb-2"
5345
+ >Company Name *</label
5346
+ >
5347
+ <input
5348
+ pInputText
5349
+ id="newCompanyName"
5350
+ [formField]="companyForm.newCompanyName"
5351
+ placeholder="Your company name"
5352
+ class="w-full"
5353
+ />
5354
+ </div>
5355
+
5356
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
5357
+ <div>
5358
+ <label for="newCompanyPhone" class="block font-medium mb-2"
5359
+ >Company Phone</label
5360
+ >
5361
+ <input
5362
+ pInputText
5363
+ id="newCompanyPhone"
5364
+ [formField]="companyForm.newCompanyPhone"
5365
+ placeholder="Company phone"
5366
+ class="w-full"
5367
+ />
5368
+ </div>
5369
+
5370
+ <div>
5371
+ <label
5372
+ for="newCompanyAddress"
5373
+ class="block font-medium mb-2"
5374
+ >Address</label
5375
+ >
5376
+ <input
5377
+ pInputText
5378
+ id="newCompanyAddress"
5379
+ [formField]="companyForm.newCompanyAddress"
5380
+ placeholder="Company address"
5381
+ class="w-full"
5382
+ />
5383
+ </div>
5384
+ </div>
5385
+ }
5386
+ </div>
5387
+ }
5388
+
5389
+ <p-button
5390
+ label="Create Account"
5391
+ styleClass="w-full mt-4"
5392
+ type="submit"
5393
+ [loading]="isLoading()"
5394
+ [disabled]="!isFormValid() || isLoading()"
5395
+ />
5396
+
5397
+ <div class="flex items-center justify-center mt-4 gap-2">
5398
+ <span class="font-medium">Already have an account?</span>
5399
+ <a
5400
+ routerLink="/auth/login"
5401
+ class="font-semibold text-primary cursor-pointer"
5402
+ >
5403
+ Sign In
5404
+ </a>
5405
+ </div>
5406
+ </form>
5407
+ </div>
5408
+ </div>
5409
+ </div>
5410
+ </div>
5411
+ `,
5412
+ }]
5413
+ }], propDecorators: { returnUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "returnUrl", required: false }] }] } });
5414
+
5415
+ var registerPage_component = /*#__PURE__*/Object.freeze({
5416
+ __proto__: null,
5417
+ RegisterPageComponent: RegisterPageComponent
5418
+ });
5419
+
5420
+ class ResetPasswordPageComponent {
5421
+ destroyRef = inject(DestroyRef);
5422
+ route = inject(ActivatedRoute);
5423
+ messageService = inject(MessageService);
5424
+ authApi = inject(AuthApiService);
5425
+ token = '';
5426
+ isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
5427
+ pageState = signal('form', ...(ngDevMode ? [{ debugName: "pageState" }] : []));
5428
+ formModel = signal({ newPassword: '', confirmPassword: '' }, ...(ngDevMode ? [{ debugName: "formModel" }] : []));
5429
+ resetForm = form(this.formModel, (f) => {
5430
+ required(f.newPassword, { message: 'New password is required' });
5431
+ minLength(f.newPassword, 6, { message: 'Password must be at least 6 characters' });
5432
+ required(f.confirmPassword, { message: 'Please confirm your password' });
5433
+ });
5434
+ passwordMismatch = computed(() => {
5435
+ const model = this.formModel();
5436
+ return model.confirmPassword.length > 0 && model.newPassword !== model.confirmPassword;
5437
+ }, ...(ngDevMode ? [{ debugName: "passwordMismatch" }] : []));
5438
+ canSubmit = computed(() => this.resetForm().valid() && !this.passwordMismatch(), ...(ngDevMode ? [{ debugName: "canSubmit" }] : []));
5439
+ ngOnInit() {
5440
+ this.route.queryParams.pipe(take(1)).subscribe((params) => {
5441
+ this.token = params['token'] || '';
5442
+ if (!this.token) {
5443
+ this.pageState.set('invalid-token');
5444
+ }
5445
+ });
5446
+ }
5447
+ onSubmit() {
5448
+ if (!this.canSubmit()) {
5449
+ this.messageService.add({
5450
+ severity: 'error',
5451
+ summary: 'Validation Error',
5452
+ detail: 'Please fill in all fields correctly.',
5453
+ });
5454
+ return;
5455
+ }
5456
+ this.isLoading.set(true);
5457
+ const newPassword = this.formModel().newPassword;
5458
+ this.authApi
5459
+ .resetPassword(this.token, newPassword)
5460
+ .pipe(takeUntilDestroyed(this.destroyRef))
5461
+ .subscribe({
5462
+ next: () => {
5463
+ this.isLoading.set(false);
5464
+ this.messageService.add({
5465
+ severity: 'success',
5466
+ summary: 'Success',
5467
+ detail: 'Your password has been reset successfully.',
5468
+ });
5469
+ this.pageState.set('success');
5470
+ },
5471
+ error: (error) => {
5472
+ this.isLoading.set(false);
5473
+ const message = error.error?.message || 'Failed to reset password';
5474
+ if (message.toLowerCase().includes('expired') || message.toLowerCase().includes('invalid')) {
5475
+ this.pageState.set('invalid-token');
5476
+ }
5477
+ else {
5478
+ this.messageService.add({
5479
+ severity: 'error',
5480
+ summary: 'Error',
5481
+ detail: message,
5482
+ });
5483
+ }
5484
+ },
5485
+ });
5486
+ }
5487
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ResetPasswordPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5488
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ResetPasswordPageComponent, isStandalone: true, selector: "lib-reset-password-page", ngImport: i0, template: `
5489
+ <app-floating-configurator />
5490
+ <div class="bg-surface-ground flex items-center justify-center min-h-screen">
5491
+ <div class="flex flex-col items-center justify-center w-full max-w-[32rem] px-4">
5492
+ <div
5493
+ class="w-full"
5494
+ style="border-radius: var(--p-content-border-radius); padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
5495
+ <div
5496
+ class="w-full py-16 px-12"
5497
+ style="border-radius: var(--p-content-border-radius); background: var(--p-content-background);">
5498
+
5499
+ @switch (pageState()) {
5500
+ @case ('form') {
5501
+ <div class="text-center mb-8">
5502
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
5503
+ Reset Password
5504
+ </div>
5505
+ <span class="text-muted-color font-medium">
5506
+ Enter your new password below.
5507
+ </span>
5508
+ </div>
5509
+
5510
+ <form (ngSubmit)="onSubmit()">
5511
+ <label for="newPassword" class="block text-lg font-medium mb-2" style="color: var(--p-content-color);">
5512
+ New Password
5513
+ </label>
5514
+ <input
5515
+ pInputText
5516
+ id="newPassword"
5517
+ type="password"
5518
+ placeholder="Enter new password"
5519
+ class="w-full md:w-[25rem] mb-4"
5520
+ [formField]="resetForm.newPassword"
5521
+ autocomplete="new-password" />
5522
+
5523
+ <label for="confirmPassword" class="block text-lg font-medium mb-2" style="color: var(--p-content-color);">
5524
+ Confirm Password
5525
+ </label>
5526
+ <input
5527
+ pInputText
5528
+ id="confirmPassword"
5529
+ type="password"
5530
+ placeholder="Confirm new password"
5531
+ class="w-full md:w-[25rem] mb-2"
5532
+ [formField]="resetForm.confirmPassword"
5533
+ autocomplete="new-password" />
5534
+
5535
+ @if (passwordMismatch()) {
5536
+ <small class="text-red-500 block mb-4">Passwords do not match</small>
5537
+ }
5538
+
5539
+ <p-button
5540
+ label="Reset Password"
5541
+ styleClass="w-full mt-4 mb-4"
5542
+ type="submit"
5543
+ [loading]="isLoading()"
5544
+ [disabled]="!canSubmit() || isLoading()" />
5545
+
5546
+ <div class="flex items-center justify-center gap-2">
5547
+ <a routerLink="/auth/login" class="font-semibold text-primary cursor-pointer">
5548
+ Back to Sign In
5549
+ </a>
5550
+ </div>
5551
+ </form>
5552
+ }
5553
+
5554
+ @case ('success') {
5555
+ <div class="text-center">
5556
+ <div class="flex justify-center mb-6">
5557
+ <i class="pi pi-check-circle text-6xl text-green-500"></i>
5558
+ </div>
5559
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
5560
+ Password Reset Successful
5561
+ </div>
5562
+ <p class="text-muted-color font-medium mb-6">
5563
+ Your password has been reset successfully.
5564
+ You can now sign in with your new password.
5565
+ </p>
5566
+ <a routerLink="/auth/login">
5567
+ <p-button label="Sign In" styleClass="w-full" />
5568
+ </a>
5569
+ </div>
5570
+ }
5571
+
5572
+ @case ('invalid-token') {
5573
+ <div class="text-center">
5574
+ <div class="flex justify-center mb-6">
5575
+ <i class="pi pi-times-circle text-6xl text-red-500"></i>
5576
+ </div>
5577
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
5578
+ Invalid or Expired Link
5579
+ </div>
5580
+ <p class="text-muted-color font-medium mb-6">
5581
+ This password reset link is invalid or has expired.
5582
+ Please request a new one.
5583
+ </p>
5584
+ <a routerLink="/auth/forgot-password">
5585
+ <p-button label="Request New Link" styleClass="w-full mb-4" />
5586
+ </a>
5587
+ <div class="mt-4">
5588
+ <a routerLink="/auth/login" class="font-semibold text-primary cursor-pointer">
5589
+ Back to Sign In
5590
+ </a>
5591
+ </div>
5592
+ </div>
5593
+ }
5594
+ }
5595
+ </div>
5596
+ </div>
5597
+ </div>
5598
+ </div>
5599
+ `, 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.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i3.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" }] });
5600
+ }
5601
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ResetPasswordPageComponent, decorators: [{
5602
+ type: Component,
5603
+ args: [{
5604
+ selector: 'lib-reset-password-page',
5605
+ standalone: true,
5606
+ imports: [AngularModule, PrimeModule, FormField, AppFloatingConfigurator],
5607
+ template: `
5608
+ <app-floating-configurator />
5609
+ <div class="bg-surface-ground flex items-center justify-center min-h-screen">
5610
+ <div class="flex flex-col items-center justify-center w-full max-w-[32rem] px-4">
5611
+ <div
5612
+ class="w-full"
5613
+ style="border-radius: var(--p-content-border-radius); padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
5614
+ <div
5615
+ class="w-full py-16 px-12"
5616
+ style="border-radius: var(--p-content-border-radius); background: var(--p-content-background);">
5617
+
5618
+ @switch (pageState()) {
5619
+ @case ('form') {
5620
+ <div class="text-center mb-8">
5621
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
5622
+ Reset Password
4163
5623
  </div>
5624
+ <span class="text-muted-color font-medium">
5625
+ Enter your new password below.
5626
+ </span>
4164
5627
  </div>
4165
- } @else {
4166
- <!-- Create New Company -->
4167
- <div class="mb-4">
4168
- <label for="newCompanyName" class="block font-medium mb-2"
4169
- >Company Name *</label
4170
- >
5628
+
5629
+ <form (ngSubmit)="onSubmit()">
5630
+ <label for="newPassword" class="block text-lg font-medium mb-2" style="color: var(--p-content-color);">
5631
+ New Password
5632
+ </label>
4171
5633
  <input
4172
5634
  pInputText
4173
- id="newCompanyName"
4174
- [formField]="companyForm.newCompanyName"
4175
- placeholder="Your company name"
4176
- class="w-full"
4177
- />
4178
- </div>
5635
+ id="newPassword"
5636
+ type="password"
5637
+ placeholder="Enter new password"
5638
+ class="w-full md:w-[25rem] mb-4"
5639
+ [formField]="resetForm.newPassword"
5640
+ autocomplete="new-password" />
4179
5641
 
4180
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
4181
- <div>
4182
- <label for="newCompanyPhone" class="block font-medium mb-2"
4183
- >Company Phone</label
4184
- >
4185
- <input
4186
- pInputText
4187
- id="newCompanyPhone"
4188
- [formField]="companyForm.newCompanyPhone"
4189
- placeholder="Company phone"
4190
- class="w-full"
4191
- />
5642
+ <label for="confirmPassword" class="block text-lg font-medium mb-2" style="color: var(--p-content-color);">
5643
+ Confirm Password
5644
+ </label>
5645
+ <input
5646
+ pInputText
5647
+ id="confirmPassword"
5648
+ type="password"
5649
+ placeholder="Confirm new password"
5650
+ class="w-full md:w-[25rem] mb-2"
5651
+ [formField]="resetForm.confirmPassword"
5652
+ autocomplete="new-password" />
5653
+
5654
+ @if (passwordMismatch()) {
5655
+ <small class="text-red-500 block mb-4">Passwords do not match</small>
5656
+ }
5657
+
5658
+ <p-button
5659
+ label="Reset Password"
5660
+ styleClass="w-full mt-4 mb-4"
5661
+ type="submit"
5662
+ [loading]="isLoading()"
5663
+ [disabled]="!canSubmit() || isLoading()" />
5664
+
5665
+ <div class="flex items-center justify-center gap-2">
5666
+ <a routerLink="/auth/login" class="font-semibold text-primary cursor-pointer">
5667
+ Back to Sign In
5668
+ </a>
4192
5669
  </div>
5670
+ </form>
5671
+ }
4193
5672
 
4194
- <div>
4195
- <label
4196
- for="newCompanyAddress"
4197
- class="block font-medium mb-2"
4198
- >Address</label
4199
- >
4200
- <input
4201
- pInputText
4202
- id="newCompanyAddress"
4203
- [formField]="companyForm.newCompanyAddress"
4204
- placeholder="Company address"
4205
- class="w-full"
4206
- />
5673
+ @case ('success') {
5674
+ <div class="text-center">
5675
+ <div class="flex justify-center mb-6">
5676
+ <i class="pi pi-check-circle text-6xl text-green-500"></i>
5677
+ </div>
5678
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
5679
+ Password Reset Successful
4207
5680
  </div>
5681
+ <p class="text-muted-color font-medium mb-6">
5682
+ Your password has been reset successfully.
5683
+ You can now sign in with your new password.
5684
+ </p>
5685
+ <a routerLink="/auth/login">
5686
+ <p-button label="Sign In" styleClass="w-full" />
5687
+ </a>
4208
5688
  </div>
4209
- }
4210
- </div>
4211
5689
  }
4212
5690
 
4213
- <!-- Submit -->
4214
- <p-button
4215
- label="Create Account"
4216
- styleClass="w-full mt-4"
4217
- type="submit"
4218
- [loading]="isLoading()"
4219
- [disabled]="!isFormValid() || isLoading()"
4220
- />
4221
-
4222
- <div class="flex items-center justify-center mt-4 gap-2">
4223
- <span class="font-medium">Already have an account?</span>
4224
- <a
4225
- routerLink="/auth/login"
4226
- class="font-semibold text-primary cursor-pointer"
4227
- >
4228
- Sign In
4229
- </a>
4230
- </div>
4231
- </form>
5691
+ @case ('invalid-token') {
5692
+ <div class="text-center">
5693
+ <div class="flex justify-center mb-6">
5694
+ <i class="pi pi-times-circle text-6xl text-red-500"></i>
5695
+ </div>
5696
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
5697
+ Invalid or Expired Link
5698
+ </div>
5699
+ <p class="text-muted-color font-medium mb-6">
5700
+ This password reset link is invalid or has expired.
5701
+ Please request a new one.
5702
+ </p>
5703
+ <a routerLink="/auth/forgot-password">
5704
+ <p-button label="Request New Link" styleClass="w-full mb-4" />
5705
+ </a>
5706
+ <div class="mt-4">
5707
+ <a routerLink="/auth/login" class="font-semibold text-primary cursor-pointer">
5708
+ Back to Sign In
5709
+ </a>
5710
+ </div>
5711
+ </div>
5712
+ }
5713
+ }
4232
5714
  </div>
4233
5715
  </div>
4234
5716
  </div>
4235
5717
  </div>
4236
5718
  `,
4237
5719
  }]
4238
- }], propDecorators: { returnUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "returnUrl", required: false }] }] } });
5720
+ }] });
4239
5721
 
4240
- var registerPage_component = /*#__PURE__*/Object.freeze({
5722
+ var resetPasswordPage_component = /*#__PURE__*/Object.freeze({
4241
5723
  __proto__: null,
4242
- RegisterPageComponent: RegisterPageComponent
5724
+ ResetPasswordPageComponent: ResetPasswordPageComponent
4243
5725
  });
4244
5726
 
4245
5727
  /**
@@ -4440,24 +5922,18 @@ class UserFormComponent {
4440
5922
  this.permissionService.assignUserToBranch(userId, branch.id)
4441
5923
  .pipe(takeUntilDestroyed(this.destroyRef))
4442
5924
  .subscribe({
4443
- error: (error) => {
4444
- // Log but don't fail - user was created successfully
4445
- console.warn('Failed to auto-assign user to branch:', error);
4446
- },
5925
+ // Silently fail - user was created successfully
4447
5926
  });
4448
5927
  }
4449
5928
  },
4450
- error: (error) => {
4451
- // Log but don't fail - user was created successfully
4452
- console.warn('Failed to auto-assign user to company:', error);
4453
- },
5929
+ // Silently fail - user was created successfully
4454
5930
  });
4455
5931
  }
4456
5932
  onCancel() {
4457
5933
  this.router.navigate(['/administration/users']);
4458
5934
  }
4459
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: UserFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4460
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: UserFormComponent, isStandalone: true, selector: "lib-user-form", ngImport: i0, template: `
5935
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5936
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: UserFormComponent, isStandalone: true, selector: "lib-user-form", ngImport: i0, template: `
4461
5937
  <p-card>
4462
5938
  <ng-template #header>
4463
5939
  <div class="flex justify-between items-center p-4">
@@ -4559,9 +6035,9 @@ class UserFormComponent {
4559
6035
  </div>
4560
6036
  </form>
4561
6037
  </p-card>
4562
- `, 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: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: i3.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: i4.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }] });
6038
+ `, 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: i3.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$1.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"] }] });
4563
6039
  }
4564
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: UserFormComponent, decorators: [{
6040
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserFormComponent, decorators: [{
4565
6041
  type: Component,
4566
6042
  args: [{
4567
6043
  selector: 'lib-user-form',
@@ -4801,8 +6277,8 @@ class UserCompanyPermissionDialogComponent {
4801
6277
  onClose() {
4802
6278
  this.closed.emit();
4803
6279
  }
4804
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: UserCompanyPermissionDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4805
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", 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: `
6280
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserCompanyPermissionDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6281
+ 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: `
4806
6282
  <p-dialog
4807
6283
  [visible]="visible()"
4808
6284
  [modal]="true"
@@ -4852,9 +6328,9 @@ class UserCompanyPermissionDialogComponent {
4852
6328
  [disabled]="isSaving()" />
4853
6329
  </ng-template>
4854
6330
  </p-dialog>
4855
- `, 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: "directive", type: i2$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: i3.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: i4$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: i5.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: i6.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }] });
6331
+ `, 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: "directive", type: i2$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: i3.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: i4$3.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: i5$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: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "component", type: i6$1.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }] });
4856
6332
  }
4857
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: UserCompanyPermissionDialogComponent, decorators: [{
6333
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserCompanyPermissionDialogComponent, decorators: [{
4858
6334
  type: Component,
4859
6335
  args: [{
4860
6336
  selector: 'lib-user-company-permission-dialog',
@@ -5087,8 +6563,8 @@ class UserBranchPermissionDialogComponent {
5087
6563
  onClose() {
5088
6564
  this.closed.emit();
5089
6565
  }
5090
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: UserBranchPermissionDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5091
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", 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: `
6566
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserBranchPermissionDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6567
+ 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: `
5092
6568
  <p-dialog
5093
6569
  [visible]="visible()"
5094
6570
  [modal]="true"
@@ -5157,9 +6633,9 @@ class UserBranchPermissionDialogComponent {
5157
6633
  [disabled]="isSaving()" />
5158
6634
  </ng-template>
5159
6635
  </p-dialog>
5160
- `, 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: "directive", type: i2$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: i3.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: i4$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: i7.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.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: i6.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }] });
6636
+ `, 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: "directive", type: i2$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: i3.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: i4$3.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: i5$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: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "component", type: i6$1.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }] });
5161
6637
  }
5162
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: UserBranchPermissionDialogComponent, decorators: [{
6638
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserBranchPermissionDialogComponent, decorators: [{
5163
6639
  type: Component,
5164
6640
  args: [{
5165
6641
  selector: 'lib-user-branch-permission-dialog',
@@ -5318,8 +6794,8 @@ class UserListComponent {
5318
6794
  },
5319
6795
  });
5320
6796
  }
5321
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: UserListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5322
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: UserListComponent, isStandalone: true, selector: "lib-user-list", ngImport: i0, template: `
6797
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6798
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: UserListComponent, isStandalone: true, selector: "lib-user-list", ngImport: i0, template: `
5323
6799
  <p-card>
5324
6800
  <ng-template #header>
5325
6801
  <div class="flex justify-between items-center p-4">
@@ -5423,9 +6899,9 @@ class UserListComponent {
5423
6899
  (closed)="showBranchDialog.set(false)"
5424
6900
  (permissionsChanged)="loadUsers()" />
5425
6901
  }
5426
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i1$2.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "component", type: i3.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: i3$1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: i4$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.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "ngmodule", type: TagModule }, { 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"] }] });
6902
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: AngularModule }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i3.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$1.Card, selector: "p-card", inputs: ["header", "subheader", "style", "styleClass"] }, { kind: "component", type: i3$2.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: "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"] }] });
5427
6903
  }
5428
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: UserListComponent, decorators: [{
6904
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UserListComponent, decorators: [{
5429
6905
  type: Component,
5430
6906
  args: [{
5431
6907
  selector: 'lib-user-list',
@@ -5550,6 +7026,375 @@ var userList_component = /*#__PURE__*/Object.freeze({
5550
7026
  UserListComponent: UserListComponent
5551
7027
  });
5552
7028
 
7029
+ const VERIFY_EMAIL_KEY = makeStateKey('verify-email-result');
7030
+ class VerifyEmailPageComponent {
7031
+ platformId = inject(PLATFORM_ID);
7032
+ transferState = inject(TransferState);
7033
+ destroyRef = inject(DestroyRef);
7034
+ route = inject(ActivatedRoute);
7035
+ messageService = inject(MessageService);
7036
+ authApi = inject(AuthApiService);
7037
+ isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
7038
+ pageState = signal('verifying', ...(ngDevMode ? [{ debugName: "pageState" }] : []));
7039
+ resendSuccess = signal(false, ...(ngDevMode ? [{ debugName: "resendSuccess" }] : []));
7040
+ submittedEmail = signal('', ...(ngDevMode ? [{ debugName: "submittedEmail" }] : []));
7041
+ resendFormModel = signal({ email: '' }, ...(ngDevMode ? [{ debugName: "resendFormModel" }] : []));
7042
+ resendForm = form(this.resendFormModel, (f) => {
7043
+ required(f.email, { message: 'Email is required' });
7044
+ email(f.email, { message: 'Please enter a valid email address' });
7045
+ });
7046
+ isResendFormValid = computed(() => this.resendForm().valid(), ...(ngDevMode ? [{ debugName: "isResendFormValid" }] : []));
7047
+ ngOnInit() {
7048
+ this.route.queryParams.pipe(take(1)).subscribe((params) => {
7049
+ const token = params['token'] || '';
7050
+ if (!token) {
7051
+ this.pageState.set('resend');
7052
+ return;
7053
+ }
7054
+ // Check if we already have result from SSR (avoid duplicate API call)
7055
+ const cachedResult = this.transferState.get(VERIFY_EMAIL_KEY, null);
7056
+ if (cachedResult) {
7057
+ this.transferState.remove(VERIFY_EMAIL_KEY);
7058
+ this.handleVerificationResult(cachedResult === 'success');
7059
+ return;
7060
+ }
7061
+ this.verifyEmail(token);
7062
+ });
7063
+ }
7064
+ verifyEmail(token) {
7065
+ this.authApi
7066
+ .verifyEmail(token)
7067
+ .pipe(takeUntilDestroyed(this.destroyRef))
7068
+ .subscribe({
7069
+ next: () => {
7070
+ // Store result for browser hydration (SSR only)
7071
+ if (!isPlatformBrowser(this.platformId)) {
7072
+ this.transferState.set(VERIFY_EMAIL_KEY, 'success');
7073
+ }
7074
+ this.handleVerificationResult(true);
7075
+ },
7076
+ error: () => {
7077
+ if (!isPlatformBrowser(this.platformId)) {
7078
+ this.transferState.set(VERIFY_EMAIL_KEY, 'error');
7079
+ }
7080
+ this.handleVerificationResult(false);
7081
+ },
7082
+ });
7083
+ }
7084
+ handleVerificationResult(success) {
7085
+ if (success) {
7086
+ this.pageState.set('success');
7087
+ if (isPlatformBrowser(this.platformId)) {
7088
+ this.messageService.add({
7089
+ severity: 'success',
7090
+ summary: 'Success',
7091
+ detail: 'Your email has been verified successfully.',
7092
+ });
7093
+ }
7094
+ }
7095
+ else {
7096
+ this.pageState.set('invalid-token');
7097
+ }
7098
+ }
7099
+ showResendForm() {
7100
+ this.pageState.set('resend');
7101
+ this.resendSuccess.set(false);
7102
+ }
7103
+ onResend() {
7104
+ if (!this.isResendFormValid()) {
7105
+ this.messageService.add({
7106
+ severity: 'error',
7107
+ summary: 'Validation Error',
7108
+ detail: 'Please enter a valid email address.',
7109
+ });
7110
+ return;
7111
+ }
7112
+ this.isLoading.set(true);
7113
+ const email = this.resendFormModel().email;
7114
+ this.authApi
7115
+ .resendVerification(email)
7116
+ .pipe(takeUntilDestroyed(this.destroyRef))
7117
+ .subscribe({
7118
+ next: () => this.handleResendComplete(email),
7119
+ error: () => this.handleResendComplete(email),
7120
+ });
7121
+ }
7122
+ handleResendComplete(email) {
7123
+ this.isLoading.set(false);
7124
+ this.messageService.add({
7125
+ severity: 'success',
7126
+ summary: 'Email Sent',
7127
+ detail: 'If the email exists, a verification link has been sent.',
7128
+ });
7129
+ this.submittedEmail.set(email);
7130
+ this.resendSuccess.set(true);
7131
+ }
7132
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: VerifyEmailPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7133
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: VerifyEmailPageComponent, isStandalone: true, selector: "lib-verify-email-page", ngImport: i0, template: `
7134
+ <app-floating-configurator />
7135
+ <div class="bg-surface-ground flex items-center justify-center min-h-screen">
7136
+ <div class="flex flex-col items-center justify-center w-full max-w-[32rem] px-4">
7137
+ <div
7138
+ class="w-full"
7139
+ style="border-radius: var(--p-content-border-radius); padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
7140
+ <div
7141
+ class="w-full py-16 px-12"
7142
+ style="border-radius: var(--p-content-border-radius); background: var(--p-content-background);">
7143
+
7144
+ @switch (pageState()) {
7145
+ @case ('verifying') {
7146
+ <div class="text-center">
7147
+ <div class="flex justify-center mb-6">
7148
+ <i class="pi pi-spin pi-spinner text-8xl text-primary"></i>
7149
+ </div>
7150
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
7151
+ Verifying Email
7152
+ </div>
7153
+ <p class="text-muted-color font-medium">
7154
+ Please wait while we verify your email address...
7155
+ </p>
7156
+ </div>
7157
+ }
7158
+
7159
+ @case ('success') {
7160
+ <div class="text-center">
7161
+ <div class="flex justify-center mb-6">
7162
+ <i class="pi pi-check-circle text-8xl text-green-500"></i>
7163
+ </div>
7164
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
7165
+ Email Verified
7166
+ </div>
7167
+ <p class="text-muted-color font-medium mb-6">
7168
+ Your email address has been verified successfully.
7169
+ You can now access all features of your account.
7170
+ </p>
7171
+ <a routerLink="/auth/login">
7172
+ <p-button label="Sign In" styleClass="w-full" />
7173
+ </a>
7174
+ </div>
7175
+ }
7176
+
7177
+ @case ('invalid-token') {
7178
+ <div class="text-center">
7179
+ <div class="flex justify-center mb-6">
7180
+ <i class="pi pi-times-circle text-8xl text-red-500"></i>
7181
+ </div>
7182
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
7183
+ Verification Failed
7184
+ </div>
7185
+ <p class="text-muted-color font-medium mb-6">
7186
+ This verification link is invalid or has expired.
7187
+ </p>
7188
+ <p-button
7189
+ label="Resend Verification Email"
7190
+ styleClass="w-full mb-4"
7191
+ (onClick)="showResendForm()" />
7192
+ <div class="mt-4">
7193
+ <a routerLink="/auth/login" class="font-semibold text-primary cursor-pointer">
7194
+ Back to Sign In
7195
+ </a>
7196
+ </div>
7197
+ </div>
7198
+ }
7199
+
7200
+ @case ('resend') {
7201
+ <div class="text-center mb-8">
7202
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
7203
+ Resend Verification
7204
+ </div>
7205
+ <span class="text-muted-color font-medium">
7206
+ Enter your email to receive a new verification link.
7207
+ </span>
7208
+ </div>
7209
+
7210
+ @if (!resendSuccess()) {
7211
+ <form (ngSubmit)="onResend()">
7212
+ <label for="email" class="block text-lg font-medium mb-2" style="color: var(--p-content-color);">
7213
+ Email
7214
+ </label>
7215
+ <input
7216
+ pInputText
7217
+ id="email"
7218
+ type="email"
7219
+ placeholder="Enter your email address"
7220
+ class="w-full md:w-[25rem] mb-6"
7221
+ [formField]="resendForm.email"
7222
+ autocomplete="email" />
7223
+
7224
+ <p-button
7225
+ label="Resend Verification"
7226
+ styleClass="w-full mb-4"
7227
+ type="submit"
7228
+ [loading]="isLoading()"
7229
+ [disabled]="!isResendFormValid() || isLoading()" />
7230
+
7231
+ <div class="flex items-center justify-center gap-2">
7232
+ <a routerLink="/auth/login" class="font-semibold text-primary cursor-pointer">
7233
+ Back to Sign In
7234
+ </a>
7235
+ </div>
7236
+ </form>
7237
+ } @else {
7238
+ <div class="text-center">
7239
+ <div class="flex justify-center mb-6">
7240
+ <i class="pi pi-envelope text-8xl text-primary"></i>
7241
+ </div>
7242
+ <p class="text-muted-color font-medium mb-6">
7243
+ We've sent a new verification link to <strong>{{ submittedEmail() }}</strong>.
7244
+ Please check your inbox.
7245
+ </p>
7246
+ <a routerLink="/auth/login" class="font-semibold text-primary cursor-pointer">
7247
+ Back to Sign In
7248
+ </a>
7249
+ </div>
7250
+ }
7251
+ }
7252
+ }
7253
+ </div>
7254
+ </div>
7255
+ </div>
7256
+ </div>
7257
+ `, 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.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: PrimeModule }, { kind: "component", type: i3.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" }] });
7258
+ }
7259
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: VerifyEmailPageComponent, decorators: [{
7260
+ type: Component,
7261
+ args: [{
7262
+ selector: 'lib-verify-email-page',
7263
+ standalone: true,
7264
+ imports: [AngularModule, PrimeModule, FormField, AppFloatingConfigurator],
7265
+ template: `
7266
+ <app-floating-configurator />
7267
+ <div class="bg-surface-ground flex items-center justify-center min-h-screen">
7268
+ <div class="flex flex-col items-center justify-center w-full max-w-[32rem] px-4">
7269
+ <div
7270
+ class="w-full"
7271
+ style="border-radius: var(--p-content-border-radius); padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
7272
+ <div
7273
+ class="w-full py-16 px-12"
7274
+ style="border-radius: var(--p-content-border-radius); background: var(--p-content-background);">
7275
+
7276
+ @switch (pageState()) {
7277
+ @case ('verifying') {
7278
+ <div class="text-center">
7279
+ <div class="flex justify-center mb-6">
7280
+ <i class="pi pi-spin pi-spinner text-8xl text-primary"></i>
7281
+ </div>
7282
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
7283
+ Verifying Email
7284
+ </div>
7285
+ <p class="text-muted-color font-medium">
7286
+ Please wait while we verify your email address...
7287
+ </p>
7288
+ </div>
7289
+ }
7290
+
7291
+ @case ('success') {
7292
+ <div class="text-center">
7293
+ <div class="flex justify-center mb-6">
7294
+ <i class="pi pi-check-circle text-8xl text-green-500"></i>
7295
+ </div>
7296
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
7297
+ Email Verified
7298
+ </div>
7299
+ <p class="text-muted-color font-medium mb-6">
7300
+ Your email address has been verified successfully.
7301
+ You can now access all features of your account.
7302
+ </p>
7303
+ <a routerLink="/auth/login">
7304
+ <p-button label="Sign In" styleClass="w-full" />
7305
+ </a>
7306
+ </div>
7307
+ }
7308
+
7309
+ @case ('invalid-token') {
7310
+ <div class="text-center">
7311
+ <div class="flex justify-center mb-6">
7312
+ <i class="pi pi-times-circle text-8xl text-red-500"></i>
7313
+ </div>
7314
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
7315
+ Verification Failed
7316
+ </div>
7317
+ <p class="text-muted-color font-medium mb-6">
7318
+ This verification link is invalid or has expired.
7319
+ </p>
7320
+ <p-button
7321
+ label="Resend Verification Email"
7322
+ styleClass="w-full mb-4"
7323
+ (onClick)="showResendForm()" />
7324
+ <div class="mt-4">
7325
+ <a routerLink="/auth/login" class="font-semibold text-primary cursor-pointer">
7326
+ Back to Sign In
7327
+ </a>
7328
+ </div>
7329
+ </div>
7330
+ }
7331
+
7332
+ @case ('resend') {
7333
+ <div class="text-center mb-8">
7334
+ <div class="text-3xl font-medium mb-4" style="color: var(--p-content-color);">
7335
+ Resend Verification
7336
+ </div>
7337
+ <span class="text-muted-color font-medium">
7338
+ Enter your email to receive a new verification link.
7339
+ </span>
7340
+ </div>
7341
+
7342
+ @if (!resendSuccess()) {
7343
+ <form (ngSubmit)="onResend()">
7344
+ <label for="email" class="block text-lg font-medium mb-2" style="color: var(--p-content-color);">
7345
+ Email
7346
+ </label>
7347
+ <input
7348
+ pInputText
7349
+ id="email"
7350
+ type="email"
7351
+ placeholder="Enter your email address"
7352
+ class="w-full md:w-[25rem] mb-6"
7353
+ [formField]="resendForm.email"
7354
+ autocomplete="email" />
7355
+
7356
+ <p-button
7357
+ label="Resend Verification"
7358
+ styleClass="w-full mb-4"
7359
+ type="submit"
7360
+ [loading]="isLoading()"
7361
+ [disabled]="!isResendFormValid() || isLoading()" />
7362
+
7363
+ <div class="flex items-center justify-center gap-2">
7364
+ <a routerLink="/auth/login" class="font-semibold text-primary cursor-pointer">
7365
+ Back to Sign In
7366
+ </a>
7367
+ </div>
7368
+ </form>
7369
+ } @else {
7370
+ <div class="text-center">
7371
+ <div class="flex justify-center mb-6">
7372
+ <i class="pi pi-envelope text-8xl text-primary"></i>
7373
+ </div>
7374
+ <p class="text-muted-color font-medium mb-6">
7375
+ We've sent a new verification link to <strong>{{ submittedEmail() }}</strong>.
7376
+ Please check your inbox.
7377
+ </p>
7378
+ <a routerLink="/auth/login" class="font-semibold text-primary cursor-pointer">
7379
+ Back to Sign In
7380
+ </a>
7381
+ </div>
7382
+ }
7383
+ }
7384
+ }
7385
+ </div>
7386
+ </div>
7387
+ </div>
7388
+ </div>
7389
+ `,
7390
+ }]
7391
+ }] });
7392
+
7393
+ var verifyEmailPage_component = /*#__PURE__*/Object.freeze({
7394
+ __proto__: null,
7395
+ VerifyEmailPageComponent: VerifyEmailPageComponent
7396
+ });
7397
+
5553
7398
  // =============================================================================
5554
7399
  // @flusys/ng-auth - Authentication Package
5555
7400
  // =============================================================================
@@ -5559,5 +7404,5 @@ var userList_component = /*#__PURE__*/Object.freeze({
5559
7404
  * Generated bundle index. Do not edit.
5560
7405
  */
5561
7406
 
5562
- export { ADMINISTRATION_ROUTES, AUTH_ENDPOINTS, AUTH_ROUTES, AdministrationPageComponent, AuthApiService, AuthCompanyApiProviderAdapter, AuthInitService, AuthLayoutApiAdapter, AuthLayoutStateAdapter, AuthStateService, AuthUserPermissionProviderAdapter, AuthUserProviderAdapter, BranchApiService, BranchFormComponent, BranchListComponent, CompanyApiService, CompanyFormComponent, CompanyListComponent, LoginPageComponent, RegisterPageComponent, TokenRefreshStateService, UserApiService, UserBranchPermissionDialogComponent, UserCompanyPermissionDialogComponent, UserFormComponent, UserListComponent, UserPermissionApiService, authGuard, authInterceptor, companyFeatureGuard, guestGuard, isAuthEndpoint, isCompanySelectionResponse, isEndpoint, isLoginResponse, provideAuthLayoutIntegration, provideAuthProviders, tokenRefreshInterceptor };
7407
+ export { ADMINISTRATION_ROUTES, AUTH_ENDPOINTS, AUTH_ROUTES, AdministrationPageComponent, AuthApiService, AuthCompanyApiProviderAdapter, AuthInitService, AuthLayoutApiAdapter, AuthLayoutStateAdapter, 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, isAuthEndpoint, isCompanySelectionResponse, isEmailVerificationRequired, isEndpoint, isLoginResponse, provideAuthLayoutIntegration, provideAuthProviders, tokenRefreshInterceptor };
5563
7408
  //# sourceMappingURL=flusys-ng-auth.mjs.map