@flusys/ng-auth 9.1.0 → 9.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/fesm2022/flusys-ng-auth-administration-page.component-DmN4KqiR.mjs +146 -0
- package/fesm2022/flusys-ng-auth-administration-page.component-DmN4KqiR.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-branch-form.component-Df_sMC2G.mjs +743 -0
- package/fesm2022/flusys-ng-auth-branch-form.component-Df_sMC2G.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-branch-list.component-CWat6QWN.mjs +775 -0
- package/fesm2022/flusys-ng-auth-branch-list.component-CWat6QWN.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-company-form.component-BvZ4Pn8j.mjs +198 -0
- package/fesm2022/flusys-ng-auth-company-form.component-BvZ4Pn8j.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-company-list.component-Corh9AIh.mjs +241 -0
- package/fesm2022/flusys-ng-auth-company-list.component-Corh9AIh.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-extension-order.util-2XWSLqii.mjs +6 -0
- package/fesm2022/flusys-ng-auth-extension-order.util-2XWSLqii.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-forgot-password-page.component-BRTVZPX6.mjs +384 -0
- package/fesm2022/flusys-ng-auth-forgot-password-page.component-BRTVZPX6.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-login-page.component-DQl52Qau.mjs +1074 -0
- package/fesm2022/flusys-ng-auth-login-page.component-DQl52Qau.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-profile-page.component-b-8rPEXQ.mjs +1792 -0
- package/fesm2022/flusys-ng-auth-profile-page.component-b-8rPEXQ.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-register-page.component-D99y1jiA.mjs +1513 -0
- package/fesm2022/flusys-ng-auth-register-page.component-D99y1jiA.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-reset-password-page.component-C0tN_AW1.mjs +538 -0
- package/fesm2022/flusys-ng-auth-reset-password-page.component-C0tN_AW1.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-social-callback-page.component-gTD7_LJY.mjs +217 -0
- package/fesm2022/flusys-ng-auth-social-callback-page.component-gTD7_LJY.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-social-config-page.component-DpGmcb9n.mjs +541 -0
- package/fesm2022/flusys-ng-auth-social-config-page.component-DpGmcb9n.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-user-form.component-CM9UYc0q.mjs +1171 -0
- package/fesm2022/flusys-ng-auth-user-form.component-CM9UYc0q.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-user-list.component-Bew7gz-H.mjs +1046 -0
- package/fesm2022/flusys-ng-auth-user-list.component-Bew7gz-H.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth-verify-email-page.component-DB9iKvt3.mjs +545 -0
- package/fesm2022/flusys-ng-auth-verify-email-page.component-DB9iKvt3.mjs.map +1 -0
- package/fesm2022/flusys-ng-auth.mjs +3030 -10735
- package/fesm2022/flusys-ng-auth.mjs.map +1 -1
- package/package.json +5 -5
- package/types/flusys-ng-auth.d.ts +978 -1558
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flusys-ng-auth-user-list.component-Bew7gz-H.mjs","names":[],"sources":["../../../projects/ng-auth/pages/users/user-list.component.ts"],"sourcesContent":["import { Component, computed, inject, signal } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { Router } from '@angular/router';\nimport { APP_CONFIG, isCompanyFeatureEnabled } from '@flusys/ng-core';\nimport {\n CardComponent,\n ConfirmationService,\n DialogComponent,\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n MessageService,\n TableComponent,\n TagComponent,\n TooltipDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport {\n HasPermissionDirective,\n TranslatePipe,\n TranslateService,\n USER_PERMISSIONS,\n} from '@flusys/ng-shared';\nimport { UserBranchPermissionDialogComponent } from '../../components/user-branch-permission-dialog.component';\nimport { UserCompanyPermissionDialogComponent } from '../../components/user-company-permission-dialog.component';\nimport { IUser } from '../../interfaces/user.interface';\nimport {\n AUTH_USER_DETAIL_CONFIG,\n AUTH_USER_LIST_EXTENSION,\n IUserListExtraAction,\n IUserListExtraColumn,\n} from '../../providers/auth-extension.providers';\nimport { sortByOrder } from '../../providers/extension-order.util';\nimport { UserApiService } from '../../services/user-api.service';\n\n@Component({\n selector: 'lib-user-list',\n imports: [\n NgTemplateOutlet,\n FormsModule,\n CardComponent,\n DialogComponent,\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TagComponent,\n TooltipDirective,\n UiIconComponent,\n HasPermissionDirective,\n TranslatePipe,\n UserCompanyPermissionDialogComponent,\n UserBranchPermissionDialogComponent,\n ],\n template: `\n <f-card>\n <ng-template #header>\n <div\n class=\"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 p-4\"\n >\n <h2 class=\"text-xl font-semibold m-0\">\n {{ 'administrative.user.title' | translate }}\n </h2>\n <div class=\"flex items-center gap-3 w-full sm:w-auto\">\n <f-iconfield class=\"w-full sm:w-64\">\n <f-inputicon icon=\"search\" />\n <input\n fInputText\n type=\"text\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchChange($event)\"\n [placeholder]=\"'shared.search' | translate\"\n />\n </f-iconfield>\n <button\n fButton\n *hasPermission=\"USER_PERMISSIONS.CREATE\"\n (click)=\"onCreate()\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{ 'administrative.user.add' | translate }}</span>\n </button>\n </div>\n </div>\n </ng-template>\n\n <div class=\"overflow-x-auto\">\n <f-table\n [value]=\"users()\"\n [loading]=\"isLoading()\"\n [paginator]=\"total() > 0\"\n [rows]=\"10\"\n [rowsPerPageOptions]=\"[10, 25, 50]\"\n [totalRecords]=\"total()\"\n [lazy]=\"true\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n [scrollable]=\"true\"\n >\n <ng-template #header>\n <tr>\n <th>{{ 'administrative.user.name' | translate }}</th>\n <th>{{ 'administrative.email.label' | translate }}</th>\n <th>{{ 'administrative.phone.label' | translate }}</th>\n <th>{{ 'administrative.user.email.verified' | translate }}</th>\n <th>{{ 'shared.status' | translate }}</th>\n @for (col of extraColumns(); track col.key) {\n <th\n [class]=\"col.styleClass ?? ''\"\n [style.width]=\"col.width ?? 'auto'\"\n >\n {{ col.headerKey | translate: null : col.header }}\n </th>\n }\n <th class=\"w-[180px]\">{{ 'shared.actions' | translate }}</th>\n </tr>\n </ng-template>\n <ng-template #body let-user>\n <tr>\n <td>{{ user.name }}</td>\n <td>{{ user.email }}</td>\n <td>{{ user.phone || '-' }}</td>\n <td>\n <f-tag\n [value]=\"\n user.emailVerified\n ? ('shared.verified' | translate)\n : ('shared.unverified' | translate)\n \"\n [severity]=\"user.emailVerified ? 'success' : 'warn'\"\n />\n </td>\n <td>\n <f-tag\n [value]=\"\n user.isActive\n ? ('shared.active' | translate)\n : ('shared.inactive' | translate)\n \"\n [severity]=\"user.isActive ? 'success' : 'danger'\"\n />\n </td>\n @for (col of extraColumns(); track col.key) {\n <td [class]=\"col.styleClass ?? ''\">\n @if (col.template) {\n <ng-container\n [ngTemplateOutlet]=\"col.template\"\n [ngTemplateOutletContext]=\"{ $implicit: user }\"\n />\n } @else if (col.field) {\n {{ getFieldValue(user, col.field) ?? '-' }}\n }\n </td>\n }\n <td>\n <div class=\"flex gap-1 flex-wrap\">\n @if (hasUserDetailView()) {\n <button\n fButton\n [rounded]=\"true\"\n [text]=\"true\"\n severity=\"info\"\n [fTooltip]=\"'shared.view.details' | translate\"\n (click)=\"onViewDetails(user)\"\n >\n <ui-icon pButtonIcon name=\"eye\"></ui-icon>\n </button>\n }\n <button\n fButton\n *hasPermission=\"USER_PERMISSIONS.UPDATE\"\n [rounded]=\"true\"\n [text]=\"true\"\n severity=\"info\"\n [fTooltip]=\"'shared.edit' | translate\"\n (click)=\"onEdit(user)\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n @if (companyFeatureEnabled()) {\n <button\n fButton\n *hasPermission=\"USER_PERMISSIONS.UPDATE\"\n [rounded]=\"true\"\n [text]=\"true\"\n severity=\"secondary\"\n [fTooltip]=\"\n 'administrative.permission.company.permissions'\n | translate\n \"\n (click)=\"onManageCompanyPermissions(user)\"\n >\n <ui-icon pButtonIcon name=\"building\"></ui-icon>\n </button>\n <button\n fButton\n *hasPermission=\"USER_PERMISSIONS.UPDATE\"\n [rounded]=\"true\"\n [text]=\"true\"\n severity=\"secondary\"\n [fTooltip]=\"\n 'administrative.permission.branch.permissions'\n | translate\n \"\n (click)=\"onManageBranchPermissions(user)\"\n >\n <ui-icon pButtonIcon name=\"sitemap\"></ui-icon>\n </button>\n }\n @for (action of extraActions(); track action.key) {\n @if (isActionVisible(action, user)) {\n <button\n fButton\n [rounded]=\"true\"\n [text]=\"true\"\n [severity]=\"action.severity ?? 'secondary'\"\n [fTooltip]=\"\n action.labelKey | translate: null : action.label\n \"\n [disabled]=\"isActionDisabled(action, user)\"\n (click)=\"onExtraAction(action, user)\"\n >\n <ui-icon pButtonIcon [name]=\"action.icon\"></ui-icon>\n </button>\n }\n }\n <button\n fButton\n *hasPermission=\"USER_PERMISSIONS.DELETE\"\n [rounded]=\"true\"\n [text]=\"true\"\n severity=\"danger\"\n [fTooltip]=\"'shared.delete' | translate\"\n (click)=\"onDelete(user)\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\n </div>\n </td>\n </tr>\n </ng-template>\n <ng-template #emptymessage>\n <tr>\n <td [attr.colspan]=\"tableColspan()\" class=\"text-center py-8\">\n {{ 'administrative.user.no.users' | translate }}\n </td>\n </tr>\n </ng-template>\n </f-table>\n </div>\n </f-card>\n\n @if (companyFeatureEnabled()) {\n <lib-user-company-permission-dialog\n [visible]=\"showCompanyDialog()\"\n [user]=\"selectedUser()\"\n (closed)=\"showCompanyDialog.set(false)\"\n (permissionsChanged)=\"loadUsers()\"\n />\n\n <lib-user-branch-permission-dialog\n [visible]=\"showBranchDialog()\"\n [user]=\"selectedUser()\"\n (closed)=\"showBranchDialog.set(false)\"\n (permissionsChanged)=\"loadUsers()\"\n />\n }\n\n @if (hasUserDetailView() && showUserDetailDialog()) {\n <f-dialog\n [header]=\"'administrative.user.details' | translate\"\n [visible]=\"showUserDetailDialog()\"\n [modal]=\"true\"\n [style]=\"{ width: userDetailConfig?.width ?? '600px' }\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n (onHide)=\"closeUserDetailDialog()\"\n >\n @if (selectedUser(); as user) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div class=\"flex flex-col gap-2\">\n <label class=\"font-medium text-muted-color\">{{\n 'administrative.user.name' | translate\n }}</label>\n <span class=\"text-color\">{{ user.name }}</span>\n </div>\n <div class=\"flex flex-col gap-2\">\n <label class=\"font-medium text-muted-color\">{{\n 'administrative.email.label' | translate\n }}</label>\n <span class=\"text-color\">{{ user.email }}</span>\n </div>\n <div class=\"flex flex-col gap-2\">\n <label class=\"font-medium text-muted-color\">{{\n 'administrative.phone.label' | translate\n }}</label>\n <span class=\"text-color\">{{ user.phone || '-' }}</span>\n </div>\n <div class=\"flex flex-col gap-2\">\n <label class=\"font-medium text-muted-color\">{{\n 'shared.status' | translate\n }}</label>\n <f-tag\n [value]=\"\n user.isActive\n ? ('shared.active' | translate)\n : ('shared.inactive' | translate)\n \"\n [severity]=\"user.isActive ? 'success' : 'danger'\"\n />\n </div>\n <div class=\"flex flex-col gap-2\">\n <label class=\"font-medium text-muted-color\">{{\n 'administrative.user.email.verified' | translate\n }}</label>\n <f-tag\n [value]=\"\n user.emailVerified\n ? ('shared.verified' | translate)\n : ('shared.unverified' | translate)\n \"\n [severity]=\"user.emailVerified ? 'success' : 'warn'\"\n />\n </div>\n @for (col of extraColumns(); track col.key) {\n <div class=\"flex flex-col gap-2\">\n <label class=\"font-medium text-muted-color\">{{\n col.headerKey | translate: null : col.header\n }}</label>\n <span class=\"text-color\">{{\n getFieldValue(user, col.field ?? col.key) ?? '-'\n }}</span>\n </div>\n }\n </div>\n <div class=\"flex justify-end gap-2 mt-6\">\n @if (userDetailConfig?.allowEdit) {\n <button\n fButton\n (click)=\"onEdit(user); closeUserDetailDialog()\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n <span pButtonLabel>{{ 'shared.edit' | translate }}</span>\n </button>\n }\n <button\n fButton\n severity=\"secondary\"\n [outlined]=\"true\"\n (click)=\"closeUserDetailDialog()\"\n >\n <span pButtonLabel>{{ 'shared.close' | translate }}</span>\n </button>\n </div>\n }\n </f-dialog>\n }\n `,\n})\nexport class UserListComponent {\n readonly USER_PERMISSIONS = USER_PERMISSIONS;\n\n private readonly router = inject(Router);\n private readonly appConfig = inject(APP_CONFIG);\n private readonly messageService = inject(MessageService);\n private readonly confirmationService = inject(ConfirmationService);\n private readonly userService = inject(UserApiService);\n\n private readonly userListExtension = inject(AUTH_USER_LIST_EXTENSION, {\n optional: true,\n });\n readonly userDetailConfig = inject(AUTH_USER_DETAIL_CONFIG, {\n optional: true,\n });\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\n\n private translate(\n key: string,\n vars?: Record<string, string | number>,\n ): string {\n return this.translateAdapter?.translate(key, vars) ?? key;\n }\n\n readonly users = this.userService.data;\n readonly isLoading = this.userService.isLoading;\n readonly total = this.userService.total;\n readonly companyFeatureEnabled = computed(() =>\n isCompanyFeatureEnabled(this.appConfig),\n );\n\n readonly extraColumns = computed<IUserListExtraColumn[]>(() => {\n if (!this.userListExtension) return [];\n return sortByOrder(this.userListExtension.getExtraColumns());\n });\n\n readonly extraActions = computed<IUserListExtraAction[]>(() => {\n if (!this.userListExtension) return [];\n return sortByOrder(this.userListExtension.getExtraActions());\n });\n\n readonly hasUserDetailView = computed(() => !!this.userDetailConfig);\n readonly tableColspan = computed(() => 6 + this.extraColumns().length);\n\n readonly showCompanyDialog = signal(false);\n readonly showBranchDialog = signal(false);\n readonly showUserDetailDialog = signal(false);\n readonly selectedUser = signal<IUser | null>(null);\n\n private readonly _searchTerm = signal('');\n readonly searchTerm = this._searchTerm.asReadonly();\n\n getFieldValue(user: IUser, field: string): unknown {\n const parts = field.split('.');\n let value: unknown = user;\n for (const part of parts) {\n if (value === null || value === undefined) return undefined;\n value = (value as Record<string, unknown>)[part];\n }\n return value;\n }\n\n isActionVisible(action: IUserListExtraAction, user: IUser): boolean {\n return action.isVisible ? action.isVisible(user) : true;\n }\n\n isActionDisabled(action: IUserListExtraAction, user: IUser): boolean {\n return action.isDisabled ? action.isDisabled(user) : false;\n }\n\n onExtraAction(action: IUserListExtraAction, user: IUser): void {\n action.onClick(user);\n }\n\n onViewDetails(user: IUser): void {\n if (!this.userDetailConfig) return;\n\n if (this.userDetailConfig.viewMode === 'page') {\n this.router.navigate(['/administration/users', user.id]);\n } else {\n this.selectedUser.set(user);\n this.showUserDetailDialog.set(true);\n }\n }\n\n closeUserDetailDialog(): void {\n this.showUserDetailDialog.set(false);\n this.selectedUser.set(null);\n }\n\n loadUsers(page = 0, pageSize = 10): void {\n this.userService.fetchList(this._searchTerm(), {\n pagination: { currentPage: page, pageSize },\n });\n }\n\n onLazyLoad(event: { first?: number | null; rows?: number | null }): void {\n const first = event.first ?? 0;\n const rows = event.rows ?? 10;\n const page = Math.floor(first / rows);\n this.loadUsers(page, rows);\n }\n\n onSearchChange(value: string): void {\n this._searchTerm.set(value);\n this.loadUsers(0);\n }\n\n onCreate(): void {\n this.router.navigate(['/administration/users/new']);\n }\n\n onEdit(user: IUser): void {\n this.router.navigate(['/administration/users', user.id]);\n }\n\n onManageCompanyPermissions(user: IUser): void {\n this.openPermissionDialog(user, this.showCompanyDialog);\n }\n\n onManageBranchPermissions(user: IUser): void {\n this.openPermissionDialog(user, this.showBranchDialog);\n }\n\n private openPermissionDialog(\n user: IUser,\n dialogSignal: typeof this.showCompanyDialog,\n ): void {\n this.selectedUser.set(user);\n dialogSignal.set(true);\n }\n\n onDelete(user: IUser): void {\n this.confirmationService.confirm({\n message: this.translate('shared.confirm.delete.item', {\n name: user.name,\n }),\n header: this.translate('administrative.user.delete.title'),\n icon: 'exclamation-triangle',\n acceptButtonStyleClass: 'p-button-danger',\n accept: async () => {\n try {\n const response = await this.userService.delete({\n id: user.id,\n type: 'delete',\n });\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: response.messageKey\n ? this.translate(\n response.messageKey,\n response.messageVariables as Record<string, string | number>,\n )\n : response.message,\n });\n this.userService.reload();\n } catch {}\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
import { AuthApiService } from "./flusys-ng-auth.mjs";
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
import { Component, DestroyRef, PLATFORM_ID, TransferState, computed, effect, inject, makeStateKey, signal } from "@angular/core";
|
|
4
|
+
import { ActivatedRoute, RouterLink } from "@angular/router";
|
|
5
|
+
import { TranslatePipe, TranslateService } from "@flusys/ng-shared";
|
|
6
|
+
import { isPlatformBrowser } from "@angular/common";
|
|
7
|
+
import { FButtonDirective, InputTextDirective, MessageService, UiIconComponent } from "@flusys/ng-ui";
|
|
8
|
+
import { AppFloatingConfigurator } from "@flusys/ng-layout";
|
|
9
|
+
import { takeUntilDestroyed, toSignal } from "@angular/core/rxjs-interop";
|
|
10
|
+
import { FormField, email, form, required } from "@angular/forms/signals";
|
|
11
|
+
const VERIFY_EMAIL_KEY = makeStateKey("verify-email-result");
|
|
12
|
+
var VerifyEmailPageComponent = class VerifyEmailPageComponent {
|
|
13
|
+
platformId = inject(PLATFORM_ID);
|
|
14
|
+
transferState = inject(TransferState);
|
|
15
|
+
destroyRef = inject(DestroyRef);
|
|
16
|
+
route = inject(ActivatedRoute);
|
|
17
|
+
messageService = inject(MessageService);
|
|
18
|
+
authApi = inject(AuthApiService);
|
|
19
|
+
translateAdapter = inject(TranslateService, { optional: true });
|
|
20
|
+
translate(key, vars) {
|
|
21
|
+
return this.translateAdapter?.translate(key, vars) ?? key;
|
|
22
|
+
}
|
|
23
|
+
queryParams = toSignal(this.route.queryParams);
|
|
24
|
+
verificationTriggered = false;
|
|
25
|
+
isLoading = signal(false, ...ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []);
|
|
26
|
+
pageState = signal("verifying", ...ngDevMode ? [{ debugName: "pageState" }] : /* istanbul ignore next */ []);
|
|
27
|
+
resendSuccess = signal(false, ...ngDevMode ? [{ debugName: "resendSuccess" }] : /* istanbul ignore next */ []);
|
|
28
|
+
submittedEmail = signal("", ...ngDevMode ? [{ debugName: "submittedEmail" }] : /* istanbul ignore next */ []);
|
|
29
|
+
resendFormModel = signal({ email: "" }, ...ngDevMode ? [{ debugName: "resendFormModel" }] : /* istanbul ignore next */ []);
|
|
30
|
+
resendForm = form(this.resendFormModel, (f) => {
|
|
31
|
+
required(f.email, { message: this.translate("auth.validation.email.required") });
|
|
32
|
+
email(f.email, { message: this.translate("shared.invalid.email") });
|
|
33
|
+
});
|
|
34
|
+
isResendFormValid = computed(() => this.resendForm().valid(), ...ngDevMode ? [{ debugName: "isResendFormValid" }] : /* istanbul ignore next */ []);
|
|
35
|
+
constructor() {
|
|
36
|
+
effect(() => {
|
|
37
|
+
const params = this.queryParams();
|
|
38
|
+
if (!params || this.verificationTriggered) return;
|
|
39
|
+
this.verificationTriggered = true;
|
|
40
|
+
const token = params["token"] || "";
|
|
41
|
+
if (!token) {
|
|
42
|
+
this.pageState.set("resend");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const cachedResult = this.transferState.get(VERIFY_EMAIL_KEY, null);
|
|
46
|
+
if (cachedResult) {
|
|
47
|
+
this.transferState.remove(VERIFY_EMAIL_KEY);
|
|
48
|
+
this.handleVerificationResult(cachedResult === "success");
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
this.verifyEmail(token);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
verifyEmail(token) {
|
|
55
|
+
this.authApi.verifyEmail(token).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
|
56
|
+
next: () => {
|
|
57
|
+
if (!isPlatformBrowser(this.platformId)) this.transferState.set(VERIFY_EMAIL_KEY, "success");
|
|
58
|
+
this.handleVerificationResult(true);
|
|
59
|
+
},
|
|
60
|
+
error: () => {
|
|
61
|
+
if (!isPlatformBrowser(this.platformId)) this.transferState.set(VERIFY_EMAIL_KEY, "error");
|
|
62
|
+
this.handleVerificationResult(false);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
handleVerificationResult(success) {
|
|
67
|
+
if (success) {
|
|
68
|
+
this.pageState.set("success");
|
|
69
|
+
if (isPlatformBrowser(this.platformId)) this.messageService.add({
|
|
70
|
+
severity: "success",
|
|
71
|
+
summary: this.translate("shared.success"),
|
|
72
|
+
detail: this.translate("auth.verify.email.success")
|
|
73
|
+
});
|
|
74
|
+
} else this.pageState.set("invalid-token");
|
|
75
|
+
}
|
|
76
|
+
showResendForm() {
|
|
77
|
+
this.pageState.set("resend");
|
|
78
|
+
this.resendSuccess.set(false);
|
|
79
|
+
}
|
|
80
|
+
onResend(event) {
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
if (!this.isResendFormValid()) {
|
|
83
|
+
this.messageService.add({
|
|
84
|
+
severity: "error",
|
|
85
|
+
summary: this.translate("shared.validation.error"),
|
|
86
|
+
detail: this.translate("shared.invalid.email")
|
|
87
|
+
});
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
this.isLoading.set(true);
|
|
91
|
+
const email = this.resendFormModel().email;
|
|
92
|
+
this.authApi.resendVerification(email).pipe(takeUntilDestroyed(this.destroyRef)).subscribe({
|
|
93
|
+
next: (response) => this.handleResendComplete(email, response.messageKey),
|
|
94
|
+
error: () => {
|
|
95
|
+
this.isLoading.set(false);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
handleResendComplete(email, messageKey) {
|
|
100
|
+
this.isLoading.set(false);
|
|
101
|
+
this.messageService.add({
|
|
102
|
+
severity: "success",
|
|
103
|
+
summary: this.translate("shared.success"),
|
|
104
|
+
detail: this.translate(messageKey ?? "auth.verify.email.sent")
|
|
105
|
+
});
|
|
106
|
+
this.submittedEmail.set(email);
|
|
107
|
+
this.resendSuccess.set(true);
|
|
108
|
+
}
|
|
109
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
110
|
+
minVersion: "12.0.0",
|
|
111
|
+
version: "22.2.1",
|
|
112
|
+
ngImport: i0,
|
|
113
|
+
type: VerifyEmailPageComponent,
|
|
114
|
+
deps: [],
|
|
115
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
116
|
+
});
|
|
117
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
118
|
+
minVersion: "17.0.0",
|
|
119
|
+
version: "22.2.1",
|
|
120
|
+
type: VerifyEmailPageComponent,
|
|
121
|
+
isStandalone: true,
|
|
122
|
+
selector: "lib-verify-email-page",
|
|
123
|
+
ngImport: i0,
|
|
124
|
+
template: `
|
|
125
|
+
<app-floating-configurator />
|
|
126
|
+
<div
|
|
127
|
+
class="bg-surface-ground flex items-center justify-center min-h-screen"
|
|
128
|
+
>
|
|
129
|
+
<div
|
|
130
|
+
class="flex flex-col items-center justify-center w-full max-w-[32rem] px-4"
|
|
131
|
+
>
|
|
132
|
+
<div
|
|
133
|
+
class="w-full"
|
|
134
|
+
style="border-radius: var(--f-content-border-radius); padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)"
|
|
135
|
+
>
|
|
136
|
+
<div
|
|
137
|
+
class="w-full py-8 px-4 sm:py-12 sm:px-8 md:py-16 md:px-12"
|
|
138
|
+
style="border-radius: var(--f-content-border-radius); background: var(--f-content-background)"
|
|
139
|
+
>
|
|
140
|
+
@switch (pageState()) {
|
|
141
|
+
@case ('verifying') {
|
|
142
|
+
<div class="text-center">
|
|
143
|
+
<div class="flex justify-center mb-6">
|
|
144
|
+
<ui-icon name="loader-circle" spin class="text-8xl text-primary"></ui-icon>
|
|
145
|
+
</div>
|
|
146
|
+
<div class="text-3xl font-medium mb-4 text-color">
|
|
147
|
+
{{ 'auth.verify.email.verifying' | translate }}
|
|
148
|
+
</div>
|
|
149
|
+
<p class="text-muted-color font-medium">
|
|
150
|
+
{{ 'auth.verify.email.please.wait' | translate }}
|
|
151
|
+
</p>
|
|
152
|
+
</div>
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@case ('success') {
|
|
156
|
+
<div class="text-center">
|
|
157
|
+
<div class="flex justify-center mb-6">
|
|
158
|
+
<ui-icon name="check-circle" class="text-8xl text-success"></ui-icon>
|
|
159
|
+
</div>
|
|
160
|
+
<div class="text-3xl font-medium mb-4 text-color">
|
|
161
|
+
{{ 'auth.verify.email.success' | translate }}
|
|
162
|
+
</div>
|
|
163
|
+
<p class="text-muted-color font-medium mb-6">
|
|
164
|
+
{{ 'auth.verify.email.success.message' | translate }}
|
|
165
|
+
</p>
|
|
166
|
+
<a routerLink="/auth/login">
|
|
167
|
+
<button
|
|
168
|
+
fButton
|
|
169
|
+
class="w-full"
|
|
170
|
+
>
|
|
171
|
+
<span pButtonLabel>{{ 'auth.login.sign.in' | translate }}</span>
|
|
172
|
+
</button>
|
|
173
|
+
</a>
|
|
174
|
+
</div>
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@case ('invalid-token') {
|
|
178
|
+
<div class="text-center">
|
|
179
|
+
<div class="flex justify-center mb-6">
|
|
180
|
+
<ui-icon name="times-circle" class="text-8xl text-danger"></ui-icon>
|
|
181
|
+
</div>
|
|
182
|
+
<div class="text-3xl font-medium mb-4 text-color">
|
|
183
|
+
{{ 'auth.verify.email.failed' | translate }}
|
|
184
|
+
</div>
|
|
185
|
+
<p class="text-muted-color font-medium mb-6">
|
|
186
|
+
{{ 'auth.verify.email.invalid.link' | translate }}
|
|
187
|
+
</p>
|
|
188
|
+
<button
|
|
189
|
+
fButton
|
|
190
|
+
class="w-full mb-4"
|
|
191
|
+
(click)="showResendForm()"
|
|
192
|
+
>
|
|
193
|
+
<span pButtonLabel>{{ 'auth.verify.email.resend.email' | translate }}</span>
|
|
194
|
+
</button>
|
|
195
|
+
<div class="mt-4">
|
|
196
|
+
<a
|
|
197
|
+
routerLink="/auth/login"
|
|
198
|
+
class="font-semibold text-primary cursor-pointer"
|
|
199
|
+
>
|
|
200
|
+
{{ 'auth.login.back.to.sign.in' | translate }}
|
|
201
|
+
</a>
|
|
202
|
+
</div>
|
|
203
|
+
</div>
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
@case ('resend') {
|
|
207
|
+
<div class="text-center mb-8">
|
|
208
|
+
<div class="text-3xl font-medium mb-4 text-color">
|
|
209
|
+
{{ 'auth.verify.email.resend.title' | translate }}
|
|
210
|
+
</div>
|
|
211
|
+
<span class="text-muted-color font-medium">
|
|
212
|
+
{{ 'auth.verify.email.resend.subtitle' | translate }}
|
|
213
|
+
</span>
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
@if (!resendSuccess()) {
|
|
217
|
+
<form (submit)="onResend($event)">
|
|
218
|
+
<label
|
|
219
|
+
for="email"
|
|
220
|
+
class="block text-lg font-medium mb-2 text-color"
|
|
221
|
+
>
|
|
222
|
+
{{ 'auth.email.label' | translate }}
|
|
223
|
+
</label>
|
|
224
|
+
<input
|
|
225
|
+
fInputText
|
|
226
|
+
id="email"
|
|
227
|
+
type="email"
|
|
228
|
+
[placeholder]="'auth.email.placeholder' | translate"
|
|
229
|
+
class="w-full mb-6"
|
|
230
|
+
[formField]="resendForm.email"
|
|
231
|
+
autocomplete="email"
|
|
232
|
+
/>
|
|
233
|
+
|
|
234
|
+
<button
|
|
235
|
+
fButton
|
|
236
|
+
class="w-full mb-4"
|
|
237
|
+
type="submit"
|
|
238
|
+
[disabled]="!isResendFormValid() || isLoading()"
|
|
239
|
+
>
|
|
240
|
+
@if (isLoading()) {
|
|
241
|
+
<ui-icon pButtonIcon name="spinner" [spin]="true"></ui-icon>
|
|
242
|
+
}
|
|
243
|
+
<span pButtonLabel>{{ 'auth.verify.email.resend' | translate }}</span>
|
|
244
|
+
</button>
|
|
245
|
+
|
|
246
|
+
<div class="flex items-center justify-center gap-2">
|
|
247
|
+
<a
|
|
248
|
+
routerLink="/auth/login"
|
|
249
|
+
class="font-semibold text-primary cursor-pointer"
|
|
250
|
+
>
|
|
251
|
+
{{ 'auth.login.back.to.sign.in' | translate }}
|
|
252
|
+
</a>
|
|
253
|
+
</div>
|
|
254
|
+
</form>
|
|
255
|
+
} @else {
|
|
256
|
+
<div class="text-center">
|
|
257
|
+
<div class="flex justify-center mb-6">
|
|
258
|
+
<ui-icon name="envelope" class="text-8xl text-primary"></ui-icon>
|
|
259
|
+
</div>
|
|
260
|
+
<p class="text-muted-color font-medium mb-6">
|
|
261
|
+
{{ 'auth.verify.email.sent' | translate }}
|
|
262
|
+
</p>
|
|
263
|
+
<a
|
|
264
|
+
routerLink="/auth/login"
|
|
265
|
+
class="font-semibold text-primary cursor-pointer"
|
|
266
|
+
>
|
|
267
|
+
{{ 'auth.login.back.to.sign.in' | translate }}
|
|
268
|
+
</a>
|
|
269
|
+
</div>
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
`,
|
|
278
|
+
isInline: true,
|
|
279
|
+
dependencies: [
|
|
280
|
+
{
|
|
281
|
+
kind: "directive",
|
|
282
|
+
type: RouterLink,
|
|
283
|
+
selector: "[routerLink]",
|
|
284
|
+
inputs: [
|
|
285
|
+
"target",
|
|
286
|
+
"queryParams",
|
|
287
|
+
"fragment",
|
|
288
|
+
"queryParamsHandling",
|
|
289
|
+
"state",
|
|
290
|
+
"info",
|
|
291
|
+
"relativeTo",
|
|
292
|
+
"preserveFragment",
|
|
293
|
+
"skipLocationChange",
|
|
294
|
+
"replaceUrl",
|
|
295
|
+
"browserUrl",
|
|
296
|
+
"routerLink"
|
|
297
|
+
]
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
kind: "directive",
|
|
301
|
+
type: FButtonDirective,
|
|
302
|
+
selector: "[fButton]",
|
|
303
|
+
inputs: [
|
|
304
|
+
"severity",
|
|
305
|
+
"text",
|
|
306
|
+
"outlined",
|
|
307
|
+
"link",
|
|
308
|
+
"variant",
|
|
309
|
+
"rounded",
|
|
310
|
+
"raised",
|
|
311
|
+
"fluid",
|
|
312
|
+
"disabled",
|
|
313
|
+
"loading",
|
|
314
|
+
"loadingIcon",
|
|
315
|
+
"size",
|
|
316
|
+
"label",
|
|
317
|
+
"icon",
|
|
318
|
+
"iconPos",
|
|
319
|
+
"ariaLabel",
|
|
320
|
+
"plain"
|
|
321
|
+
]
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
kind: "directive",
|
|
325
|
+
type: InputTextDirective,
|
|
326
|
+
selector: "[fInputText]",
|
|
327
|
+
inputs: [
|
|
328
|
+
"invalid",
|
|
329
|
+
"touched",
|
|
330
|
+
"variant",
|
|
331
|
+
"size",
|
|
332
|
+
"fluid"
|
|
333
|
+
]
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
kind: "component",
|
|
337
|
+
type: UiIconComponent,
|
|
338
|
+
selector: "ui-icon",
|
|
339
|
+
inputs: [
|
|
340
|
+
"name",
|
|
341
|
+
"size",
|
|
342
|
+
"spin",
|
|
343
|
+
"fill",
|
|
344
|
+
"severity"
|
|
345
|
+
]
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
kind: "directive",
|
|
349
|
+
type: FormField,
|
|
350
|
+
selector: "[formField]",
|
|
351
|
+
inputs: ["formField"],
|
|
352
|
+
exportAs: ["formField"]
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
kind: "component",
|
|
356
|
+
type: AppFloatingConfigurator,
|
|
357
|
+
selector: "app-floating-configurator"
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
kind: "pipe",
|
|
361
|
+
type: TranslatePipe,
|
|
362
|
+
name: "translate"
|
|
363
|
+
}
|
|
364
|
+
]
|
|
365
|
+
});
|
|
366
|
+
};
|
|
367
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
368
|
+
minVersion: "12.0.0",
|
|
369
|
+
version: "22.2.1",
|
|
370
|
+
ngImport: i0,
|
|
371
|
+
type: VerifyEmailPageComponent,
|
|
372
|
+
decorators: [{
|
|
373
|
+
type: Component,
|
|
374
|
+
args: [{
|
|
375
|
+
selector: "lib-verify-email-page",
|
|
376
|
+
imports: [
|
|
377
|
+
RouterLink,
|
|
378
|
+
FButtonDirective,
|
|
379
|
+
InputTextDirective,
|
|
380
|
+
UiIconComponent,
|
|
381
|
+
FormField,
|
|
382
|
+
AppFloatingConfigurator,
|
|
383
|
+
TranslatePipe
|
|
384
|
+
],
|
|
385
|
+
template: `
|
|
386
|
+
<app-floating-configurator />
|
|
387
|
+
<div
|
|
388
|
+
class="bg-surface-ground flex items-center justify-center min-h-screen"
|
|
389
|
+
>
|
|
390
|
+
<div
|
|
391
|
+
class="flex flex-col items-center justify-center w-full max-w-[32rem] px-4"
|
|
392
|
+
>
|
|
393
|
+
<div
|
|
394
|
+
class="w-full"
|
|
395
|
+
style="border-radius: var(--f-content-border-radius); padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)"
|
|
396
|
+
>
|
|
397
|
+
<div
|
|
398
|
+
class="w-full py-8 px-4 sm:py-12 sm:px-8 md:py-16 md:px-12"
|
|
399
|
+
style="border-radius: var(--f-content-border-radius); background: var(--f-content-background)"
|
|
400
|
+
>
|
|
401
|
+
@switch (pageState()) {
|
|
402
|
+
@case ('verifying') {
|
|
403
|
+
<div class="text-center">
|
|
404
|
+
<div class="flex justify-center mb-6">
|
|
405
|
+
<ui-icon name="loader-circle" spin class="text-8xl text-primary"></ui-icon>
|
|
406
|
+
</div>
|
|
407
|
+
<div class="text-3xl font-medium mb-4 text-color">
|
|
408
|
+
{{ 'auth.verify.email.verifying' | translate }}
|
|
409
|
+
</div>
|
|
410
|
+
<p class="text-muted-color font-medium">
|
|
411
|
+
{{ 'auth.verify.email.please.wait' | translate }}
|
|
412
|
+
</p>
|
|
413
|
+
</div>
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
@case ('success') {
|
|
417
|
+
<div class="text-center">
|
|
418
|
+
<div class="flex justify-center mb-6">
|
|
419
|
+
<ui-icon name="check-circle" class="text-8xl text-success"></ui-icon>
|
|
420
|
+
</div>
|
|
421
|
+
<div class="text-3xl font-medium mb-4 text-color">
|
|
422
|
+
{{ 'auth.verify.email.success' | translate }}
|
|
423
|
+
</div>
|
|
424
|
+
<p class="text-muted-color font-medium mb-6">
|
|
425
|
+
{{ 'auth.verify.email.success.message' | translate }}
|
|
426
|
+
</p>
|
|
427
|
+
<a routerLink="/auth/login">
|
|
428
|
+
<button
|
|
429
|
+
fButton
|
|
430
|
+
class="w-full"
|
|
431
|
+
>
|
|
432
|
+
<span pButtonLabel>{{ 'auth.login.sign.in' | translate }}</span>
|
|
433
|
+
</button>
|
|
434
|
+
</a>
|
|
435
|
+
</div>
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
@case ('invalid-token') {
|
|
439
|
+
<div class="text-center">
|
|
440
|
+
<div class="flex justify-center mb-6">
|
|
441
|
+
<ui-icon name="times-circle" class="text-8xl text-danger"></ui-icon>
|
|
442
|
+
</div>
|
|
443
|
+
<div class="text-3xl font-medium mb-4 text-color">
|
|
444
|
+
{{ 'auth.verify.email.failed' | translate }}
|
|
445
|
+
</div>
|
|
446
|
+
<p class="text-muted-color font-medium mb-6">
|
|
447
|
+
{{ 'auth.verify.email.invalid.link' | translate }}
|
|
448
|
+
</p>
|
|
449
|
+
<button
|
|
450
|
+
fButton
|
|
451
|
+
class="w-full mb-4"
|
|
452
|
+
(click)="showResendForm()"
|
|
453
|
+
>
|
|
454
|
+
<span pButtonLabel>{{ 'auth.verify.email.resend.email' | translate }}</span>
|
|
455
|
+
</button>
|
|
456
|
+
<div class="mt-4">
|
|
457
|
+
<a
|
|
458
|
+
routerLink="/auth/login"
|
|
459
|
+
class="font-semibold text-primary cursor-pointer"
|
|
460
|
+
>
|
|
461
|
+
{{ 'auth.login.back.to.sign.in' | translate }}
|
|
462
|
+
</a>
|
|
463
|
+
</div>
|
|
464
|
+
</div>
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
@case ('resend') {
|
|
468
|
+
<div class="text-center mb-8">
|
|
469
|
+
<div class="text-3xl font-medium mb-4 text-color">
|
|
470
|
+
{{ 'auth.verify.email.resend.title' | translate }}
|
|
471
|
+
</div>
|
|
472
|
+
<span class="text-muted-color font-medium">
|
|
473
|
+
{{ 'auth.verify.email.resend.subtitle' | translate }}
|
|
474
|
+
</span>
|
|
475
|
+
</div>
|
|
476
|
+
|
|
477
|
+
@if (!resendSuccess()) {
|
|
478
|
+
<form (submit)="onResend($event)">
|
|
479
|
+
<label
|
|
480
|
+
for="email"
|
|
481
|
+
class="block text-lg font-medium mb-2 text-color"
|
|
482
|
+
>
|
|
483
|
+
{{ 'auth.email.label' | translate }}
|
|
484
|
+
</label>
|
|
485
|
+
<input
|
|
486
|
+
fInputText
|
|
487
|
+
id="email"
|
|
488
|
+
type="email"
|
|
489
|
+
[placeholder]="'auth.email.placeholder' | translate"
|
|
490
|
+
class="w-full mb-6"
|
|
491
|
+
[formField]="resendForm.email"
|
|
492
|
+
autocomplete="email"
|
|
493
|
+
/>
|
|
494
|
+
|
|
495
|
+
<button
|
|
496
|
+
fButton
|
|
497
|
+
class="w-full mb-4"
|
|
498
|
+
type="submit"
|
|
499
|
+
[disabled]="!isResendFormValid() || isLoading()"
|
|
500
|
+
>
|
|
501
|
+
@if (isLoading()) {
|
|
502
|
+
<ui-icon pButtonIcon name="spinner" [spin]="true"></ui-icon>
|
|
503
|
+
}
|
|
504
|
+
<span pButtonLabel>{{ 'auth.verify.email.resend' | translate }}</span>
|
|
505
|
+
</button>
|
|
506
|
+
|
|
507
|
+
<div class="flex items-center justify-center gap-2">
|
|
508
|
+
<a
|
|
509
|
+
routerLink="/auth/login"
|
|
510
|
+
class="font-semibold text-primary cursor-pointer"
|
|
511
|
+
>
|
|
512
|
+
{{ 'auth.login.back.to.sign.in' | translate }}
|
|
513
|
+
</a>
|
|
514
|
+
</div>
|
|
515
|
+
</form>
|
|
516
|
+
} @else {
|
|
517
|
+
<div class="text-center">
|
|
518
|
+
<div class="flex justify-center mb-6">
|
|
519
|
+
<ui-icon name="envelope" class="text-8xl text-primary"></ui-icon>
|
|
520
|
+
</div>
|
|
521
|
+
<p class="text-muted-color font-medium mb-6">
|
|
522
|
+
{{ 'auth.verify.email.sent' | translate }}
|
|
523
|
+
</p>
|
|
524
|
+
<a
|
|
525
|
+
routerLink="/auth/login"
|
|
526
|
+
class="font-semibold text-primary cursor-pointer"
|
|
527
|
+
>
|
|
528
|
+
{{ 'auth.login.back.to.sign.in' | translate }}
|
|
529
|
+
</a>
|
|
530
|
+
</div>
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
</div>
|
|
535
|
+
</div>
|
|
536
|
+
</div>
|
|
537
|
+
</div>
|
|
538
|
+
`
|
|
539
|
+
}]
|
|
540
|
+
}],
|
|
541
|
+
ctorParameters: () => []
|
|
542
|
+
});
|
|
543
|
+
export { VerifyEmailPageComponent };
|
|
544
|
+
|
|
545
|
+
//# sourceMappingURL=flusys-ng-auth-verify-email-page.component-DB9iKvt3.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flusys-ng-auth-verify-email-page.component-DB9iKvt3.mjs","names":[],"sources":["../../../projects/ng-auth/pages/verify-email/verify-email-page.component.ts"],"sourcesContent":["import { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n computed,\n DestroyRef,\n effect,\n inject,\n makeStateKey,\n PLATFORM_ID,\n signal,\n TransferState,\n} from '@angular/core';\nimport { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';\nimport {\n email as emailValidator,\n form,\n FormField,\n required,\n} from '@angular/forms/signals';\nimport { ActivatedRoute, RouterLink } from '@angular/router';\nimport { AppFloatingConfigurator } from '@flusys/ng-layout';\nimport { FButtonDirective, InputTextDirective, MessageService, UiIconComponent } from '@flusys/ng-ui';\nimport {\n TranslatePipe,\n TranslateService,\n} from '@flusys/ng-shared';\nimport { AuthApiService } from '../../services/auth-api.service';\n\nconst VERIFY_EMAIL_KEY = makeStateKey<'success' | 'error'>(\n 'verify-email-result',\n);\n\ninterface IResendFormModel {\n email: string;\n}\n\ntype PageState = 'verifying' | 'success' | 'invalid-token' | 'resend';\n\n@Component({\n selector: 'lib-verify-email-page',\n imports: [\n RouterLink,\n FButtonDirective,\n InputTextDirective,\n UiIconComponent,\n FormField,\n AppFloatingConfigurator,\n TranslatePipe,\n ],\n template: `\n <app-floating-configurator />\n <div\n class=\"bg-surface-ground flex items-center justify-center min-h-screen\"\n >\n <div\n class=\"flex flex-col items-center justify-center w-full max-w-[32rem] px-4\"\n >\n <div\n class=\"w-full\"\n style=\"border-radius: var(--f-content-border-radius); padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)\"\n >\n <div\n class=\"w-full py-8 px-4 sm:py-12 sm:px-8 md:py-16 md:px-12\"\n style=\"border-radius: var(--f-content-border-radius); background: var(--f-content-background)\"\n >\n @switch (pageState()) {\n @case ('verifying') {\n <div class=\"text-center\">\n <div class=\"flex justify-center mb-6\">\n <ui-icon name=\"loader-circle\" spin class=\"text-8xl text-primary\"></ui-icon>\n </div>\n <div class=\"text-3xl font-medium mb-4 text-color\">\n {{ 'auth.verify.email.verifying' | translate }}\n </div>\n <p class=\"text-muted-color font-medium\">\n {{ 'auth.verify.email.please.wait' | translate }}\n </p>\n </div>\n }\n\n @case ('success') {\n <div class=\"text-center\">\n <div class=\"flex justify-center mb-6\">\n <ui-icon name=\"check-circle\" class=\"text-8xl text-success\"></ui-icon>\n </div>\n <div class=\"text-3xl font-medium mb-4 text-color\">\n {{ 'auth.verify.email.success' | translate }}\n </div>\n <p class=\"text-muted-color font-medium mb-6\">\n {{ 'auth.verify.email.success.message' | translate }}\n </p>\n <a routerLink=\"/auth/login\">\n <button\n fButton\n class=\"w-full\"\n >\n <span pButtonLabel>{{ 'auth.login.sign.in' | translate }}</span>\n </button>\n </a>\n </div>\n }\n\n @case ('invalid-token') {\n <div class=\"text-center\">\n <div class=\"flex justify-center mb-6\">\n <ui-icon name=\"times-circle\" class=\"text-8xl text-danger\"></ui-icon>\n </div>\n <div class=\"text-3xl font-medium mb-4 text-color\">\n {{ 'auth.verify.email.failed' | translate }}\n </div>\n <p class=\"text-muted-color font-medium mb-6\">\n {{ 'auth.verify.email.invalid.link' | translate }}\n </p>\n <button\n fButton\n class=\"w-full mb-4\"\n (click)=\"showResendForm()\"\n >\n <span pButtonLabel>{{ 'auth.verify.email.resend.email' | translate }}</span>\n </button>\n <div class=\"mt-4\">\n <a\n routerLink=\"/auth/login\"\n class=\"font-semibold text-primary cursor-pointer\"\n >\n {{ 'auth.login.back.to.sign.in' | translate }}\n </a>\n </div>\n </div>\n }\n\n @case ('resend') {\n <div class=\"text-center mb-8\">\n <div class=\"text-3xl font-medium mb-4 text-color\">\n {{ 'auth.verify.email.resend.title' | translate }}\n </div>\n <span class=\"text-muted-color font-medium\">\n {{ 'auth.verify.email.resend.subtitle' | translate }}\n </span>\n </div>\n\n @if (!resendSuccess()) {\n <form (submit)=\"onResend($event)\">\n <label\n for=\"email\"\n class=\"block text-lg font-medium mb-2 text-color\"\n >\n {{ 'auth.email.label' | translate }}\n </label>\n <input\n fInputText\n id=\"email\"\n type=\"email\"\n [placeholder]=\"'auth.email.placeholder' | translate\"\n class=\"w-full mb-6\"\n [formField]=\"resendForm.email\"\n autocomplete=\"email\"\n />\n\n <button\n fButton\n class=\"w-full mb-4\"\n type=\"submit\"\n [disabled]=\"!isResendFormValid() || isLoading()\"\n >\n @if (isLoading()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n }\n <span pButtonLabel>{{ 'auth.verify.email.resend' | translate }}</span>\n </button>\n\n <div class=\"flex items-center justify-center gap-2\">\n <a\n routerLink=\"/auth/login\"\n class=\"font-semibold text-primary cursor-pointer\"\n >\n {{ 'auth.login.back.to.sign.in' | translate }}\n </a>\n </div>\n </form>\n } @else {\n <div class=\"text-center\">\n <div class=\"flex justify-center mb-6\">\n <ui-icon name=\"envelope\" class=\"text-8xl text-primary\"></ui-icon>\n </div>\n <p class=\"text-muted-color font-medium mb-6\">\n {{ 'auth.verify.email.sent' | translate }}\n </p>\n <a\n routerLink=\"/auth/login\"\n class=\"font-semibold text-primary cursor-pointer\"\n >\n {{ 'auth.login.back.to.sign.in' | translate }}\n </a>\n </div>\n }\n }\n }\n </div>\n </div>\n </div>\n </div>\n `,\n})\nexport class VerifyEmailPageComponent {\n private readonly platformId = inject(PLATFORM_ID);\n private readonly transferState = inject(TransferState);\n private readonly destroyRef = inject(DestroyRef);\n private readonly route = inject(ActivatedRoute);\n private readonly messageService = inject(MessageService);\n private readonly authApi = inject(AuthApiService);\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\n\n private translate(\n key: string,\n vars?: Record<string, string | number>,\n ): string {\n return this.translateAdapter?.translate(key, vars) ?? key;\n }\n\n private readonly queryParams = toSignal(this.route.queryParams);\n private verificationTriggered = false;\n\n readonly isLoading = signal(false);\n readonly pageState = signal<PageState>('verifying');\n readonly resendSuccess = signal(false);\n readonly submittedEmail = signal('');\n readonly resendFormModel = signal<IResendFormModel>({ email: '' });\n readonly resendForm = form(this.resendFormModel, (f) => {\n required(f.email, {\n message: this.translate('auth.validation.email.required'),\n });\n emailValidator(f.email, {\n message: this.translate('shared.invalid.email'),\n });\n });\n readonly isResendFormValid = computed(() => this.resendForm().valid());\n\n constructor() {\n effect(() => {\n const params = this.queryParams();\n if (!params || this.verificationTriggered) return;\n\n this.verificationTriggered = true;\n const token = params['token'] || '';\n if (!token) {\n this.pageState.set('resend');\n return;\n }\n\n // Check if we already have result from SSR (avoid duplicate API call)\n const cachedResult = this.transferState.get(VERIFY_EMAIL_KEY, null);\n if (cachedResult) {\n this.transferState.remove(VERIFY_EMAIL_KEY);\n this.handleVerificationResult(cachedResult === 'success');\n return;\n }\n\n this.verifyEmail(token);\n });\n }\n\n private verifyEmail(token: string): void {\n this.authApi\n .verifyEmail(token)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: () => {\n // Store result for browser hydration (SSR only)\n if (!isPlatformBrowser(this.platformId)) {\n this.transferState.set(VERIFY_EMAIL_KEY, 'success');\n }\n this.handleVerificationResult(true);\n },\n error: () => {\n if (!isPlatformBrowser(this.platformId)) {\n this.transferState.set(VERIFY_EMAIL_KEY, 'error');\n }\n this.handleVerificationResult(false);\n },\n });\n }\n\n private handleVerificationResult(success: boolean): void {\n if (success) {\n this.pageState.set('success');\n if (isPlatformBrowser(this.platformId)) {\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: this.translate('auth.verify.email.success'),\n });\n }\n } else {\n this.pageState.set('invalid-token');\n }\n }\n\n showResendForm(): void {\n this.pageState.set('resend');\n this.resendSuccess.set(false);\n }\n\n onResend(event: Event): void {\n event.preventDefault();\n\n if (!this.isResendFormValid()) {\n this.messageService.add({\n severity: 'error',\n summary: this.translate('shared.validation.error'),\n detail: this.translate('shared.invalid.email'),\n });\n return;\n }\n\n this.isLoading.set(true);\n const email = this.resendFormModel().email;\n\n // Always show success (security: don't reveal if email exists)\n this.authApi\n .resendVerification(email)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: (response) =>\n this.handleResendComplete(email, response.messageKey),\n error: () => {\n //handle by interceptor\n this.isLoading.set(false);\n },\n });\n }\n\n private handleResendComplete(email: string, messageKey?: string): void {\n this.isLoading.set(false);\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: this.translate(messageKey ?? 'auth.verify.email.sent'),\n });\n this.submittedEmail.set(email);\n this.resendSuccess.set(true);\n }\n}\n"],"mappings":"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"}
|