@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.
- package/README.md +45 -5
- package/fesm2022/flusys-ng-auth.mjs +2163 -318
- package/fesm2022/flusys-ng-auth.mjs.map +1 -1
- package/package.json +4 -4
- package/types/flusys-ng-auth.d.ts +201 -44
|
@@ -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
|
|
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
|
|
20
|
-
import * as
|
|
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
|
|
23
|
-
import * as
|
|
24
|
-
import * as
|
|
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
|
|
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$
|
|
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
|
-
|
|
152
|
-
|
|
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.
|
|
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.
|
|
278
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
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.
|
|
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((
|
|
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.
|
|
393
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
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.
|
|
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.
|
|
462
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
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.
|
|
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.
|
|
493
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
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.
|
|
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.
|
|
546
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
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.
|
|
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.
|
|
605
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
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.
|
|
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.
|
|
744
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
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.
|
|
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
|
|
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
|
|
948
|
-
const needsCredentials = isEndpoint(req.url,
|
|
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
|
-
|
|
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.
|
|
1220
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
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.
|
|
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.
|
|
1309
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
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.
|
|
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.
|
|
1359
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
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.
|
|
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.
|
|
1399
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
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.
|
|
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.
|
|
1423
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.
|
|
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.
|
|
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.
|
|
1528
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.
|
|
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.
|
|
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.
|
|
1765
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.
|
|
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: "
|
|
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.
|
|
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.
|
|
2105
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.
|
|
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:
|
|
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.
|
|
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.
|
|
2455
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.
|
|
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: "
|
|
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.
|
|
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.
|
|
2759
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.
|
|
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:
|
|
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.
|
|
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(
|
|
3334
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
3045
3335
|
.subscribe({
|
|
3046
3336
|
next: (response) => {
|
|
3047
3337
|
this.isLoading.set(false);
|
|
3048
|
-
|
|
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(
|
|
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.
|
|
3196
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.
|
|
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
|
|
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.
|
|
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
|
-
*
|
|
3551
|
-
*
|
|
3552
|
-
*
|
|
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
|
|
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
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
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
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
//
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
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: "
|
|
3578
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
4891
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
3707
4892
|
.subscribe({
|
|
3708
4893
|
next: (response) => {
|
|
3709
4894
|
this.isLoading.set(false);
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
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.
|
|
3748
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.
|
|
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
|
|
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.
|
|
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
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
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="
|
|
4174
|
-
|
|
4175
|
-
placeholder="
|
|
4176
|
-
class="w-full"
|
|
4177
|
-
|
|
4178
|
-
|
|
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
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
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
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
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
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
routerLink="/auth/
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
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
|
-
}]
|
|
5720
|
+
}] });
|
|
4239
5721
|
|
|
4240
|
-
var
|
|
5722
|
+
var resetPasswordPage_component = /*#__PURE__*/Object.freeze({
|
|
4241
5723
|
__proto__: null,
|
|
4242
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
4460
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.
|
|
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: "
|
|
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.
|
|
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.
|
|
4805
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.
|
|
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$
|
|
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.
|
|
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.
|
|
5091
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.
|
|
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$
|
|
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.
|
|
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.
|
|
5322
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.
|
|
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:
|
|
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.
|
|
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
|