@flusys/ng-auth 9.2.2 → 9.3.0
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/fesm2022/{flusys-ng-auth-administration-page.component-C9cMjTFU.mjs → flusys-ng-auth-administration-page.component-CxQYkCc1.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-administration-page.component-C9cMjTFU.mjs.map → flusys-ng-auth-administration-page.component-CxQYkCc1.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-auth-branch-form.component-xttRMwxT.mjs → flusys-ng-auth-branch-form.component-DtoM4SET.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-branch-form.component-xttRMwxT.mjs.map → flusys-ng-auth-branch-form.component-DtoM4SET.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-auth-branch-list.component-SeGvWdUO.mjs → flusys-ng-auth-branch-list.component-CP9VFx_8.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-branch-list.component-SeGvWdUO.mjs.map → flusys-ng-auth-branch-list.component-CP9VFx_8.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-auth-company-form.component-BPrFxqto.mjs → flusys-ng-auth-company-form.component-C1HXjgn-.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-company-form.component-BPrFxqto.mjs.map → flusys-ng-auth-company-form.component-C1HXjgn-.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-auth-company-list.component-jEtVFxYE.mjs → flusys-ng-auth-company-list.component-jkyaG-hS.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-company-list.component-jEtVFxYE.mjs.map → flusys-ng-auth-company-list.component-jkyaG-hS.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-auth-forgot-password-page.component-JnLtR304.mjs → flusys-ng-auth-forgot-password-page.component-D92hBmWF.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-forgot-password-page.component-JnLtR304.mjs.map → flusys-ng-auth-forgot-password-page.component-D92hBmWF.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-auth-login-page.component-R8gMWdLZ.mjs → flusys-ng-auth-login-page.component-Bz-bbY3U.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-login-page.component-R8gMWdLZ.mjs.map → flusys-ng-auth-login-page.component-Bz-bbY3U.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-auth-profile-page.component-Cd4bhDRV.mjs → flusys-ng-auth-profile-page.component-Dg25DA0i.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-profile-page.component-Cd4bhDRV.mjs.map → flusys-ng-auth-profile-page.component-Dg25DA0i.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-auth-register-page.component-B0me9tCm.mjs → flusys-ng-auth-register-page.component-Cb-ycJHR.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-register-page.component-B0me9tCm.mjs.map → flusys-ng-auth-register-page.component-Cb-ycJHR.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-auth-reset-password-page.component-DnULwTow.mjs → flusys-ng-auth-reset-password-page.component-C33Lu6ST.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-reset-password-page.component-DnULwTow.mjs.map → flusys-ng-auth-reset-password-page.component-C33Lu6ST.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-auth-social-callback-page.component-DTrdtpbR.mjs → flusys-ng-auth-social-callback-page.component-CDb3VVWf.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-social-callback-page.component-DTrdtpbR.mjs.map → flusys-ng-auth-social-callback-page.component-CDb3VVWf.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-auth-social-config-page.component-Ce7yrJtX.mjs → flusys-ng-auth-social-config-page.component-mkFaxN4w.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-social-config-page.component-Ce7yrJtX.mjs.map → flusys-ng-auth-social-config-page.component-mkFaxN4w.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-auth-user-form.component-cY4cmjV_.mjs → flusys-ng-auth-user-form.component-o0MbxMQn.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-user-form.component-cY4cmjV_.mjs.map → flusys-ng-auth-user-form.component-o0MbxMQn.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-auth-user-list.component-Dhq8Hygo.mjs → flusys-ng-auth-user-list.component-MHHsLH9r.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-user-list.component-Dhq8Hygo.mjs.map → flusys-ng-auth-user-list.component-MHHsLH9r.mjs.map} +1 -1
- package/fesm2022/{flusys-ng-auth-verify-email-page.component-C3CLhAip.mjs → flusys-ng-auth-verify-email-page.component-3qcv2X_u.mjs} +4 -4
- package/fesm2022/{flusys-ng-auth-verify-email-page.component-C3CLhAip.mjs.map → flusys-ng-auth-verify-email-page.component-3qcv2X_u.mjs.map} +1 -1
- package/fesm2022/flusys-ng-auth.mjs +87 -87
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flusys-ng-auth-user-form.component-cY4cmjV_.mjs","names":[],"sources":["../../../projects/ng-auth/pages/users/user-form.component.ts"],"sourcesContent":["import {\n Component,\n computed,\n DestroyRef,\n effect,\n inject,\n Injector,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';\nimport { NgComponentOutlet, NgTemplateOutlet } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport {\n email as emailValidator,\n form,\n FormField,\n required,\n} from '@angular/forms/signals';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { APP_CONFIG, isCompanyFeatureEnabled } from '@flusys/ng-core';\nimport {\n TranslatePipe,\n TranslateService,\n} from '@flusys/ng-shared';\nimport {\n CardComponent,\n CheckboxComponent,\n FButtonDirective,\n InputTextDirective,\n MessageService,\n PasswordComponent,\n SelectComponent,\n SkeletonComponent,\n TextareaDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport { finalize, firstValueFrom } from 'rxjs';\nimport {\n ICreateUserRequest,\n IUpdateUserRequest,\n IUser,\n} from '../../interfaces/user.interface';\nimport {\n AUTH_USER_FORM_EXTENSION,\n IUserFormExtraField,\n IUserFormFieldTemplateContext,\n USER_FORM_FIELD_CONTEXT,\n} from '../../providers/auth-extension.providers';\nimport { sortByOrder } from '../../providers/extension-order.util';\nimport { AuthStateService } from '../../services/auth-state.service';\nimport { PasswordPolicyService } from '../../services/password-policy.service';\nimport { UserApiService } from '../../services/user-api.service';\nimport { UserPermissionApiService } from '../../services/user-permission-api.service';\n\ninterface IUserFormModel {\n name: string;\n email: string;\n password: string;\n phone: string;\n isActive: boolean;\n emailVerified: boolean;\n}\n\n@Component({\n selector: 'lib-user-form',\n imports: [\n CardComponent,\n CheckboxComponent,\n FButtonDirective,\n InputTextDirective,\n PasswordComponent,\n SelectComponent,\n SkeletonComponent,\n TextareaDirective,\n UiIconComponent,\n FormsModule,\n NgComponentOutlet,\n NgTemplateOutlet,\n FormField,\n TranslatePipe,\n ],\n template: `\n <f-card>\n <ng-template #header>\n <div class=\"flex justify-between items-center p-4\">\n <h2 class=\"text-xl font-semibold m-0\">\n {{\n isEditMode()\n ? ('administrative.user.edit' | translate)\n : ('administrative.user.new' | translate)\n }}\n </h2>\n </div>\n </ng-template>\n\n <form\n (ngSubmit)=\"onSubmit()\"\n class=\"grid grid-cols-1 md:grid-cols-2 gap-4\"\n >\n <div class=\"flex flex-col gap-2\">\n <label for=\"name\" class=\"font-medium\"\n >{{ 'administrative.user.name' | translate }} *</label\n >\n <input\n fInputText\n id=\"name\"\n [formField]=\"formTree.name\"\n [placeholder]=\"'administrative.user.name.placeholder' | translate\"\n />\n </div>\n\n <div class=\"flex flex-col gap-2\">\n <label for=\"email\" class=\"font-medium\"\n >{{ 'administrative.email.label' | translate }} *</label\n >\n <input\n fInputText\n id=\"email\"\n type=\"email\"\n [formField]=\"formTree.email\"\n [placeholder]=\"'auth.email.placeholder' | translate\"\n />\n </div>\n\n <div class=\"flex flex-col gap-2\">\n <label for=\"password\" class=\"font-medium\">\n {{ 'administrative.user.password' | translate }}\n {{\n isEditMode()\n ? ('administrative.user.password.optional' | translate)\n : '*'\n }}\n </label>\n <f-password\n [inputId]=\"'password'\"\n [formField]=\"formTree.password\"\n [placeholder]=\"\n 'administrative.user.password.placeholder' | translate\n \"\n autocomplete=\"new-password\"\n />\n @if (passwordError()) {\n <small class=\"text-danger\">{{ passwordError() }}</small>\n }\n </div>\n\n <div class=\"flex flex-col gap-2\">\n <label for=\"phone\" class=\"font-medium\">{{\n 'administrative.phone.label' | translate\n }}</label>\n <input\n fInputText\n id=\"phone\"\n [formField]=\"formTree.phone\"\n [placeholder]=\"'auth.phone.placeholder' | translate\"\n />\n </div>\n\n @if (hasExtraFields()) {\n <div class=\"md:col-span-2 border-t border-surface pt-4 mt-2\">\n <div class=\"text-sm font-medium text-muted-color mb-4\">\n <ui-icon name=\"sliders-h\" class=\"mr-2\"></ui-icon\n >{{ 'profile.additional.info' | translate }}\n </div>\n @if (isLoadingExtraFields()) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <f-skeleton height=\"2.5rem\" />\n <f-skeleton height=\"2.5rem\" />\n </div>\n } @else {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n @for (field of extraFields(); track field.key) {\n <div class=\"flex flex-col gap-2\">\n <label [for]=\"field.key\" class=\"font-medium text-color\">\n {{ field.labelKey | translate: null : field.label\n }}{{ field.required ? ' *' : '' }}\n </label>\n @if (field.component) {\n <ng-container\n [ngComponentOutlet]=\"field.component\"\n [ngComponentOutletInjector]=\"getFieldInjector(field)\"\n />\n } @else if (field.template) {\n <ng-container\n [ngTemplateOutlet]=\"field.template\"\n [ngTemplateOutletContext]=\"\n getFieldTemplateContext(field)\n \"\n />\n } @else {\n @switch (field.type) {\n @case ('text') {\n <input\n fInputText\n [id]=\"field.key\"\n [placeholder]=\"\n field.placeholderKey\n | translate: null : field.placeholder ?? ''\n \"\n [value]=\"getExtraFieldValue(field.key) ?? ''\"\n (input)=\"\n updateExtraField(\n field.key,\n $any($event.target).value\n )\n \"\n class=\"w-full\"\n />\n }\n @case ('number') {\n <input\n fInputText\n type=\"number\"\n [id]=\"field.key\"\n [placeholder]=\"\n field.placeholderKey\n | translate: null : field.placeholder ?? ''\n \"\n [value]=\"getExtraFieldValue(field.key) ?? ''\"\n (input)=\"\n updateExtraField(\n field.key,\n $any($event.target).valueAsNumber\n )\n \"\n class=\"w-full\"\n />\n }\n @case ('textarea') {\n <textarea\n fTextarea\n [id]=\"field.key\"\n [placeholder]=\"\n field.placeholderKey\n | translate: null : field.placeholder ?? ''\n \"\n [value]=\"getExtraFieldValue(field.key) ?? ''\"\n (input)=\"\n updateExtraField(\n field.key,\n $any($event.target).value\n )\n \"\n class=\"w-full\"\n rows=\"3\"\n ></textarea>\n }\n @case ('select') {\n <f-select\n [id]=\"field.key\"\n class=\"w-full\"\n [options]=\"field.options ?? []\"\n optionValue=\"value\"\n [ngModel]=\"getExtraFieldValue(field.key) ?? ''\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"\n updateExtraField(field.key, $event)\n \"\n [placeholder]=\"\n field.placeholderKey\n | translate\n : null\n : field.placeholder ??\n ('shared.select' | translate)\n \"\n >\n <ng-template #item let-opt>{{\n opt.labelKey | translate: null : opt.label\n }}</ng-template>\n <ng-template #selectedItem let-opt>{{\n opt.labelKey | translate: null : opt.label\n }}</ng-template>\n </f-select>\n }\n @case ('checkbox') {\n <f-checkbox\n [inputId]=\"field.key\"\n [checked]=\"\n $any(getExtraFieldValue(field.key) ?? false)\n \"\n (onChange)=\"\n updateExtraField(field.key, $event.checked)\n \"\n [label]=\"\n field.placeholderKey\n | translate\n : null\n : field.placeholder ??\n (field.labelKey\n | translate: null : field.label)\n \"\n />\n }\n @case ('date') {\n <input\n fInputText\n type=\"date\"\n [id]=\"field.key\"\n [value]=\"getExtraFieldValue(field.key) ?? ''\"\n (input)=\"\n updateExtraField(\n field.key,\n $any($event.target).value\n )\n \"\n class=\"w-full\"\n />\n }\n }\n }\n </div>\n }\n </div>\n @if (extraFieldsValidationError()) {\n <small class=\"text-danger block mt-2\">{{\n extraFieldsValidationError()\n }}</small>\n }\n }\n </div>\n }\n\n <div class=\"flex items-center gap-6 md:col-span-2 pt-4\">\n <f-checkbox\n [formField]=\"formTree.isActive\"\n [label]=\"'shared.active' | translate\"\n />\n <f-checkbox\n [formField]=\"formTree.emailVerified\"\n [label]=\"'administrative.user.email.verified' | translate\"\n />\n </div>\n\n @if (companyFeatureEnabled() && !isEditMode()) {\n <div\n class=\"md:col-span-2 p-3 bg-primary/10 rounded-lg border border-primary/20\"\n >\n <div class=\"flex items-center gap-2 text-primary\">\n <ui-icon name=\"info-circle\"></ui-icon>\n <span class=\"text-sm\">\n {{ 'administrative.user.auto.assign.to' | translate }}\n <strong>{{ currentCompanyName() }}</strong>\n @if (currentBranchName()) {\n / <strong>{{ currentBranchName() }}</strong>\n }\n </span>\n </div>\n </div>\n }\n\n <div class=\"flex justify-end gap-4 md:col-span-2 pt-4\">\n <button\n fButton\n type=\"button\"\n severity=\"secondary\"\n [outlined]=\"true\"\n (click)=\"onCancel()\"\n >\n <span pButtonLabel>{{ 'shared.cancel' | translate }}</span>\n </button>\n <button\n fButton\n type=\"submit\"\n [disabled]=\"!isFormValid() || isLoading()\"\n >\n @if (isLoading()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n }\n <span pButtonLabel>{{\n isEditMode()\n ? ('shared.update' | translate)\n : ('shared.create' | translate)\n }}</span>\n </button>\n </div>\n </form>\n </f-card>\n `,\n})\nexport class UserFormComponent {\n private readonly destroyRef = inject(DestroyRef);\n private readonly router = inject(Router);\n private readonly route = inject(ActivatedRoute);\n private readonly appConfig = inject(APP_CONFIG);\n private readonly messageService = inject(MessageService);\n private readonly userService = inject(UserApiService);\n private readonly permissionService = inject(UserPermissionApiService);\n private readonly authState = inject(AuthStateService);\n private readonly passwordPolicy = inject(PasswordPolicyService);\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\n private readonly userFormExtension = inject(AUTH_USER_FORM_EXTENSION, {\n optional: true,\n });\n private readonly parentInjector = inject(Injector);\n\n private translate(\n key: string,\n vars?: Record<string, unknown>,\n ): string {\n return this.translateAdapter?.translate(key, vars) ?? key;\n }\n\n private readonly routeParams = toSignal(this.route.paramMap);\n private userLoadTriggered = false;\n\n readonly isLoading = signal(false);\n readonly existingUser = signal<IUser | null>(null);\n readonly isEditMode = computed(() => !!this.existingUser());\n readonly companyFeatureEnabled = computed(() =>\n isCompanyFeatureEnabled(this.appConfig),\n );\n readonly currentCompanyName = computed(() => this.authState.companyName());\n readonly currentBranchName = computed(() => this.authState.branchName());\n\n readonly formModel = signal<IUserFormModel>({\n name: '',\n email: '',\n password: '',\n phone: '',\n isActive: true,\n emailVerified: false,\n });\n\n readonly formTree = form(this.formModel, (f) => {\n required(f.name, {\n message: this.translate('shared.name.required'),\n });\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\n readonly isLoadingExtraFields = signal(false);\n readonly extraFieldsModel = signal<Record<string, unknown>>({});\n readonly originalExtraFieldsModel = signal<Record<string, unknown>>({});\n\n readonly extraFields = computed<IUserFormExtraField[]>(() => {\n if (!this.userFormExtension?.getExtraFields) return [];\n return sortByOrder(this.userFormExtension.getExtraFields());\n });\n\n readonly hasExtraFields = computed(() => this.extraFields().length > 0);\n\n readonly extraFieldsValidationError = computed(() => {\n if (!this.userFormExtension?.validateExtraFields) return null;\n return this.userFormExtension.validateExtraFields(this.extraFieldsModel());\n });\n\n readonly isExtraFieldsDirty = computed(() => {\n const current = this.extraFieldsModel();\n const original = this.originalExtraFieldsModel();\n return JSON.stringify(current) !== JSON.stringify(original);\n });\n\n updateExtraField(key: string, value: unknown): void {\n this.extraFieldsModel.update((model) => ({ ...model, [key]: value }));\n }\n\n getExtraFieldValue(key: string): unknown {\n return this.extraFieldsModel()[key];\n }\n\n getFieldTemplateContext(\n field: IUserFormExtraField,\n ): IUserFormFieldTemplateContext {\n return {\n field,\n value: this.extraFieldsModel()[field.key],\n updateValue: (value: unknown) => this.updateExtraField(field.key, value),\n };\n }\n\n private readonly fieldInjectors = new Map<\n string,\n { injector: Injector; setField: (field: IUserFormExtraField) => void }\n >();\n\n getFieldInjector(field: IUserFormExtraField): Injector {\n const cached = this.fieldInjectors.get(field.key);\n if (cached) {\n cached.setField(field);\n return cached.injector;\n }\n\n let currentField = field;\n const extraFieldsModel = this.extraFieldsModel;\n const context: IUserFormFieldTemplateContext = {\n get field() {\n return currentField;\n },\n get value() {\n return extraFieldsModel()[currentField.key];\n },\n updateValue: (value: unknown) =>\n this.updateExtraField(currentField.key, value),\n };\n\n const injector = Injector.create({\n providers: [{ provide: USER_FORM_FIELD_CONTEXT, useValue: context }],\n parent: field.injector ?? this.parentInjector,\n });\n this.fieldInjectors.set(field.key, {\n injector,\n setField: (next) => (currentField = next),\n });\n return injector;\n }\n\n readonly passwordError = computed(() =>\n this.passwordPolicy.validate(this.formModel().password),\n );\n\n readonly isFormValid = computed(() => {\n const model = this.formModel();\n const isEdit = this.isEditMode();\n const nameValid = model.name.trim().length > 0;\n const emailValid = model.email.includes('@');\n\n const passwordValid = model.password ? !this.passwordError() : isEdit;\n\n return nameValid && emailValid && passwordValid && !this.extraFieldsValidationError();\n });\n\n constructor() {\n effect(() => {\n const params = this.routeParams();\n if (!params || this.userLoadTriggered) return;\n\n this.userLoadTriggered = true;\n const id = params.get('id');\n if (id && id !== 'new') {\n this.loadUser(id);\n }\n });\n }\n\n async loadUser(id: string): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await this.userService.findById(id);\n if (response.success && response.data) {\n this.existingUser.set(response.data);\n this.formModel.set(this.toFormModel(response.data));\n this.loadExtraFields(id);\n }\n } catch {\n this.router.navigate(['/administration/users']);\n } finally {\n this.isLoading.set(false);\n }\n }\n\n private loadExtraFields(userId: string): void {\n if (!this.userFormExtension?.getExtraFieldValues) return;\n\n this.isLoadingExtraFields.set(true);\n this.userFormExtension\n .getExtraFieldValues(userId)\n .pipe(\n takeUntilDestroyed(this.destroyRef),\n finalize(() => this.isLoadingExtraFields.set(false)),\n )\n .subscribe({\n next: (values) => {\n this.extraFieldsModel.set(values as Record<string, unknown>);\n this.originalExtraFieldsModel.set(values as Record<string, unknown>);\n },\n error: () => {\n const defaults: Record<string, unknown> = {};\n for (const field of this.extraFields()) {\n if (field.key) defaults[field.key] = undefined;\n }\n this.extraFieldsModel.set(defaults);\n this.originalExtraFieldsModel.set(defaults);\n },\n });\n }\n\n private toFormModel(user: IUser): IUserFormModel {\n return {\n name: user.name,\n email: user.email,\n password: '',\n phone: user.phone || '',\n isActive: user.isActive,\n emailVerified: user.emailVerified,\n };\n }\n\n onSubmit(): void {\n if (!this.isFormValid()) {\n this.messageService.add({\n severity: 'error',\n summary: this.translate('shared.validation.error'),\n detail: this.translate('shared.fill.required.fields'),\n });\n return;\n }\n\n this.isLoading.set(true);\n\n if (this.isEditMode() && this.existingUser()) {\n this.updateUser();\n } else {\n this.createUser();\n }\n }\n\n private async updateUser(): Promise<void> {\n const model = this.formModel();\n const userId = this.existingUser()!.id;\n const updateData: IUpdateUserRequest = {\n id: userId,\n name: model.name,\n email: model.email,\n phone: model.phone || undefined,\n isActive: model.isActive,\n emailVerified: model.emailVerified,\n };\n\n if (model.password) {\n updateData.password = model.password;\n }\n\n try {\n const [userResponse] = await Promise.all([\n this.userService.update(updateData),\n this.isExtraFieldsDirty() &&\n this.userFormExtension?.saveExtraFieldValues\n ? firstValueFrom(\n this.userFormExtension.saveExtraFieldValues(\n userId,\n this.extraFieldsModel(),\n ),\n )\n : Promise.resolve(undefined),\n ]);\n this.onSaveSuccess(\n userResponse.messageKey\n ? this.translate(\n userResponse.messageKey,\n userResponse.messageVariables,\n )\n : userResponse.message,\n );\n } catch {\n } finally {\n this.isLoading.set(false);\n }\n }\n\n private async createUser(): Promise<void> {\n const model = this.formModel();\n const createData: ICreateUserRequest = {\n name: model.name,\n email: model.email,\n password: model.password,\n phone: model.phone || undefined,\n isActive: model.isActive,\n emailVerified: model.emailVerified,\n };\n\n try {\n const response = await this.userService.insert(createData);\n if (response.success && response.data) {\n const userId = response.data.id;\n if (this.companyFeatureEnabled()) {\n this.assignUserToCompanyAndBranch(userId);\n }\n this.saveExtraFieldsForNewUser(userId);\n }\n this.onSaveSuccess(\n response.messageKey\n ? this.translate(\n response.messageKey,\n response.messageVariables,\n )\n : response.message,\n );\n } catch {\n } finally {\n this.isLoading.set(false);\n }\n }\n\n private saveExtraFieldsForNewUser(userId: string): void {\n const extraFields = this.extraFieldsModel();\n const hasExtraData =\n Object.keys(extraFields).length > 0 &&\n Object.values(extraFields).some((v) => v !== undefined && v !== '');\n\n if (!hasExtraData || !this.userFormExtension?.saveExtraFieldValues) return;\n\n this.userFormExtension\n .saveExtraFieldValues(userId, extraFields)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({ error: () => {} });\n }\n\n private onSaveSuccess(message: string): void {\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: message,\n });\n this.router.navigate(['/administration/users']);\n }\n\n private assignUserToCompanyAndBranch(userId: string): void {\n const company = this.authState.company();\n const branch = this.authState.branch();\n\n if (!company) return;\n\n this.permissionService\n .assignUserToCompany(userId, company.id)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: () => {\n if (branch) {\n this.permissionService\n .assignUserToBranch(userId, branch.id)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({ error: () => {} });\n }\n },\n error: () => {},\n });\n }\n\n onCancel(): void {\n this.router.navigate(['/administration/users']);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"flusys-ng-auth-user-form.component-o0MbxMQn.mjs","names":[],"sources":["../../../projects/ng-auth/pages/users/user-form.component.ts"],"sourcesContent":["import {\n Component,\n computed,\n DestroyRef,\n effect,\n inject,\n Injector,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';\nimport { NgComponentOutlet, NgTemplateOutlet } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport {\n email as emailValidator,\n form,\n FormField,\n required,\n} from '@angular/forms/signals';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { APP_CONFIG, isCompanyFeatureEnabled } from '@flusys/ng-core';\nimport {\n TranslatePipe,\n TranslateService,\n} from '@flusys/ng-shared';\nimport {\n CardComponent,\n CheckboxComponent,\n FButtonDirective,\n InputTextDirective,\n MessageService,\n PasswordComponent,\n SelectComponent,\n SkeletonComponent,\n TextareaDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport { finalize, firstValueFrom } from 'rxjs';\nimport {\n ICreateUserRequest,\n IUpdateUserRequest,\n IUser,\n} from '../../interfaces/user.interface';\nimport {\n AUTH_USER_FORM_EXTENSION,\n IUserFormExtraField,\n IUserFormFieldTemplateContext,\n USER_FORM_FIELD_CONTEXT,\n} from '../../providers/auth-extension.providers';\nimport { sortByOrder } from '../../providers/extension-order.util';\nimport { AuthStateService } from '../../services/auth-state.service';\nimport { PasswordPolicyService } from '../../services/password-policy.service';\nimport { UserApiService } from '../../services/user-api.service';\nimport { UserPermissionApiService } from '../../services/user-permission-api.service';\n\ninterface IUserFormModel {\n name: string;\n email: string;\n password: string;\n phone: string;\n isActive: boolean;\n emailVerified: boolean;\n}\n\n@Component({\n selector: 'lib-user-form',\n imports: [\n CardComponent,\n CheckboxComponent,\n FButtonDirective,\n InputTextDirective,\n PasswordComponent,\n SelectComponent,\n SkeletonComponent,\n TextareaDirective,\n UiIconComponent,\n FormsModule,\n NgComponentOutlet,\n NgTemplateOutlet,\n FormField,\n TranslatePipe,\n ],\n template: `\n <f-card>\n <ng-template #header>\n <div class=\"flex justify-between items-center p-4\">\n <h2 class=\"text-xl font-semibold m-0\">\n {{\n isEditMode()\n ? ('administrative.user.edit' | translate)\n : ('administrative.user.new' | translate)\n }}\n </h2>\n </div>\n </ng-template>\n\n <form\n (ngSubmit)=\"onSubmit()\"\n class=\"grid grid-cols-1 md:grid-cols-2 gap-4\"\n >\n <div class=\"flex flex-col gap-2\">\n <label for=\"name\" class=\"font-medium\"\n >{{ 'administrative.user.name' | translate }} *</label\n >\n <input\n fInputText\n id=\"name\"\n [formField]=\"formTree.name\"\n [placeholder]=\"'administrative.user.name.placeholder' | translate\"\n />\n </div>\n\n <div class=\"flex flex-col gap-2\">\n <label for=\"email\" class=\"font-medium\"\n >{{ 'administrative.email.label' | translate }} *</label\n >\n <input\n fInputText\n id=\"email\"\n type=\"email\"\n [formField]=\"formTree.email\"\n [placeholder]=\"'auth.email.placeholder' | translate\"\n />\n </div>\n\n <div class=\"flex flex-col gap-2\">\n <label for=\"password\" class=\"font-medium\">\n {{ 'administrative.user.password' | translate }}\n {{\n isEditMode()\n ? ('administrative.user.password.optional' | translate)\n : '*'\n }}\n </label>\n <f-password\n [inputId]=\"'password'\"\n [formField]=\"formTree.password\"\n [placeholder]=\"\n 'administrative.user.password.placeholder' | translate\n \"\n autocomplete=\"new-password\"\n />\n @if (passwordError()) {\n <small class=\"text-danger\">{{ passwordError() }}</small>\n }\n </div>\n\n <div class=\"flex flex-col gap-2\">\n <label for=\"phone\" class=\"font-medium\">{{\n 'administrative.phone.label' | translate\n }}</label>\n <input\n fInputText\n id=\"phone\"\n [formField]=\"formTree.phone\"\n [placeholder]=\"'auth.phone.placeholder' | translate\"\n />\n </div>\n\n @if (hasExtraFields()) {\n <div class=\"md:col-span-2 border-t border-surface pt-4 mt-2\">\n <div class=\"text-sm font-medium text-muted-color mb-4\">\n <ui-icon name=\"sliders-h\" class=\"mr-2\"></ui-icon\n >{{ 'profile.additional.info' | translate }}\n </div>\n @if (isLoadingExtraFields()) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <f-skeleton height=\"2.5rem\" />\n <f-skeleton height=\"2.5rem\" />\n </div>\n } @else {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n @for (field of extraFields(); track field.key) {\n <div class=\"flex flex-col gap-2\">\n <label [for]=\"field.key\" class=\"font-medium text-color\">\n {{ field.labelKey | translate: null : field.label\n }}{{ field.required ? ' *' : '' }}\n </label>\n @if (field.component) {\n <ng-container\n [ngComponentOutlet]=\"field.component\"\n [ngComponentOutletInjector]=\"getFieldInjector(field)\"\n />\n } @else if (field.template) {\n <ng-container\n [ngTemplateOutlet]=\"field.template\"\n [ngTemplateOutletContext]=\"\n getFieldTemplateContext(field)\n \"\n />\n } @else {\n @switch (field.type) {\n @case ('text') {\n <input\n fInputText\n [id]=\"field.key\"\n [placeholder]=\"\n field.placeholderKey\n | translate: null : field.placeholder ?? ''\n \"\n [value]=\"getExtraFieldValue(field.key) ?? ''\"\n (input)=\"\n updateExtraField(\n field.key,\n $any($event.target).value\n )\n \"\n class=\"w-full\"\n />\n }\n @case ('number') {\n <input\n fInputText\n type=\"number\"\n [id]=\"field.key\"\n [placeholder]=\"\n field.placeholderKey\n | translate: null : field.placeholder ?? ''\n \"\n [value]=\"getExtraFieldValue(field.key) ?? ''\"\n (input)=\"\n updateExtraField(\n field.key,\n $any($event.target).valueAsNumber\n )\n \"\n class=\"w-full\"\n />\n }\n @case ('textarea') {\n <textarea\n fTextarea\n [id]=\"field.key\"\n [placeholder]=\"\n field.placeholderKey\n | translate: null : field.placeholder ?? ''\n \"\n [value]=\"getExtraFieldValue(field.key) ?? ''\"\n (input)=\"\n updateExtraField(\n field.key,\n $any($event.target).value\n )\n \"\n class=\"w-full\"\n rows=\"3\"\n ></textarea>\n }\n @case ('select') {\n <f-select\n [id]=\"field.key\"\n class=\"w-full\"\n [options]=\"field.options ?? []\"\n optionValue=\"value\"\n [ngModel]=\"getExtraFieldValue(field.key) ?? ''\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"\n updateExtraField(field.key, $event)\n \"\n [placeholder]=\"\n field.placeholderKey\n | translate\n : null\n : field.placeholder ??\n ('shared.select' | translate)\n \"\n >\n <ng-template #item let-opt>{{\n opt.labelKey | translate: null : opt.label\n }}</ng-template>\n <ng-template #selectedItem let-opt>{{\n opt.labelKey | translate: null : opt.label\n }}</ng-template>\n </f-select>\n }\n @case ('checkbox') {\n <f-checkbox\n [inputId]=\"field.key\"\n [checked]=\"\n $any(getExtraFieldValue(field.key) ?? false)\n \"\n (onChange)=\"\n updateExtraField(field.key, $event.checked)\n \"\n [label]=\"\n field.placeholderKey\n | translate\n : null\n : field.placeholder ??\n (field.labelKey\n | translate: null : field.label)\n \"\n />\n }\n @case ('date') {\n <input\n fInputText\n type=\"date\"\n [id]=\"field.key\"\n [value]=\"getExtraFieldValue(field.key) ?? ''\"\n (input)=\"\n updateExtraField(\n field.key,\n $any($event.target).value\n )\n \"\n class=\"w-full\"\n />\n }\n }\n }\n </div>\n }\n </div>\n @if (extraFieldsValidationError()) {\n <small class=\"text-danger block mt-2\">{{\n extraFieldsValidationError()\n }}</small>\n }\n }\n </div>\n }\n\n <div class=\"flex items-center gap-6 md:col-span-2 pt-4\">\n <f-checkbox\n [formField]=\"formTree.isActive\"\n [label]=\"'shared.active' | translate\"\n />\n <f-checkbox\n [formField]=\"formTree.emailVerified\"\n [label]=\"'administrative.user.email.verified' | translate\"\n />\n </div>\n\n @if (companyFeatureEnabled() && !isEditMode()) {\n <div\n class=\"md:col-span-2 p-3 bg-primary/10 rounded-lg border border-primary/20\"\n >\n <div class=\"flex items-center gap-2 text-primary\">\n <ui-icon name=\"info-circle\"></ui-icon>\n <span class=\"text-sm\">\n {{ 'administrative.user.auto.assign.to' | translate }}\n <strong>{{ currentCompanyName() }}</strong>\n @if (currentBranchName()) {\n / <strong>{{ currentBranchName() }}</strong>\n }\n </span>\n </div>\n </div>\n }\n\n <div class=\"flex justify-end gap-4 md:col-span-2 pt-4\">\n <button\n fButton\n type=\"button\"\n severity=\"secondary\"\n [outlined]=\"true\"\n (click)=\"onCancel()\"\n >\n <span pButtonLabel>{{ 'shared.cancel' | translate }}</span>\n </button>\n <button\n fButton\n type=\"submit\"\n [disabled]=\"!isFormValid() || isLoading()\"\n >\n @if (isLoading()) {\n <ui-icon pButtonIcon name=\"spinner\" [spin]=\"true\"></ui-icon>\n }\n <span pButtonLabel>{{\n isEditMode()\n ? ('shared.update' | translate)\n : ('shared.create' | translate)\n }}</span>\n </button>\n </div>\n </form>\n </f-card>\n `,\n})\nexport class UserFormComponent {\n private readonly destroyRef = inject(DestroyRef);\n private readonly router = inject(Router);\n private readonly route = inject(ActivatedRoute);\n private readonly appConfig = inject(APP_CONFIG);\n private readonly messageService = inject(MessageService);\n private readonly userService = inject(UserApiService);\n private readonly permissionService = inject(UserPermissionApiService);\n private readonly authState = inject(AuthStateService);\n private readonly passwordPolicy = inject(PasswordPolicyService);\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\n private readonly userFormExtension = inject(AUTH_USER_FORM_EXTENSION, {\n optional: true,\n });\n private readonly parentInjector = inject(Injector);\n\n private translate(\n key: string,\n vars?: Record<string, unknown>,\n ): string {\n return this.translateAdapter?.translate(key, vars) ?? key;\n }\n\n private readonly routeParams = toSignal(this.route.paramMap);\n private userLoadTriggered = false;\n\n readonly isLoading = signal(false);\n readonly existingUser = signal<IUser | null>(null);\n readonly isEditMode = computed(() => !!this.existingUser());\n readonly companyFeatureEnabled = computed(() =>\n isCompanyFeatureEnabled(this.appConfig),\n );\n readonly currentCompanyName = computed(() => this.authState.companyName());\n readonly currentBranchName = computed(() => this.authState.branchName());\n\n readonly formModel = signal<IUserFormModel>({\n name: '',\n email: '',\n password: '',\n phone: '',\n isActive: true,\n emailVerified: false,\n });\n\n readonly formTree = form(this.formModel, (f) => {\n required(f.name, {\n message: this.translate('shared.name.required'),\n });\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\n readonly isLoadingExtraFields = signal(false);\n readonly extraFieldsModel = signal<Record<string, unknown>>({});\n readonly originalExtraFieldsModel = signal<Record<string, unknown>>({});\n\n readonly extraFields = computed<IUserFormExtraField[]>(() => {\n if (!this.userFormExtension?.getExtraFields) return [];\n return sortByOrder(this.userFormExtension.getExtraFields());\n });\n\n readonly hasExtraFields = computed(() => this.extraFields().length > 0);\n\n readonly extraFieldsValidationError = computed(() => {\n if (!this.userFormExtension?.validateExtraFields) return null;\n return this.userFormExtension.validateExtraFields(this.extraFieldsModel());\n });\n\n readonly isExtraFieldsDirty = computed(() => {\n const current = this.extraFieldsModel();\n const original = this.originalExtraFieldsModel();\n return JSON.stringify(current) !== JSON.stringify(original);\n });\n\n updateExtraField(key: string, value: unknown): void {\n this.extraFieldsModel.update((model) => ({ ...model, [key]: value }));\n }\n\n getExtraFieldValue(key: string): unknown {\n return this.extraFieldsModel()[key];\n }\n\n getFieldTemplateContext(\n field: IUserFormExtraField,\n ): IUserFormFieldTemplateContext {\n return {\n field,\n value: this.extraFieldsModel()[field.key],\n updateValue: (value: unknown) => this.updateExtraField(field.key, value),\n };\n }\n\n private readonly fieldInjectors = new Map<\n string,\n { injector: Injector; setField: (field: IUserFormExtraField) => void }\n >();\n\n getFieldInjector(field: IUserFormExtraField): Injector {\n const cached = this.fieldInjectors.get(field.key);\n if (cached) {\n cached.setField(field);\n return cached.injector;\n }\n\n let currentField = field;\n const extraFieldsModel = this.extraFieldsModel;\n const context: IUserFormFieldTemplateContext = {\n get field() {\n return currentField;\n },\n get value() {\n return extraFieldsModel()[currentField.key];\n },\n updateValue: (value: unknown) =>\n this.updateExtraField(currentField.key, value),\n };\n\n const injector = Injector.create({\n providers: [{ provide: USER_FORM_FIELD_CONTEXT, useValue: context }],\n parent: field.injector ?? this.parentInjector,\n });\n this.fieldInjectors.set(field.key, {\n injector,\n setField: (next) => (currentField = next),\n });\n return injector;\n }\n\n readonly passwordError = computed(() =>\n this.passwordPolicy.validate(this.formModel().password),\n );\n\n readonly isFormValid = computed(() => {\n const model = this.formModel();\n const isEdit = this.isEditMode();\n const nameValid = model.name.trim().length > 0;\n const emailValid = model.email.includes('@');\n\n const passwordValid = model.password ? !this.passwordError() : isEdit;\n\n return nameValid && emailValid && passwordValid && !this.extraFieldsValidationError();\n });\n\n constructor() {\n effect(() => {\n const params = this.routeParams();\n if (!params || this.userLoadTriggered) return;\n\n this.userLoadTriggered = true;\n const id = params.get('id');\n if (id && id !== 'new') {\n this.loadUser(id);\n }\n });\n }\n\n async loadUser(id: string): Promise<void> {\n this.isLoading.set(true);\n try {\n const response = await this.userService.findById(id);\n if (response.success && response.data) {\n this.existingUser.set(response.data);\n this.formModel.set(this.toFormModel(response.data));\n this.loadExtraFields(id);\n }\n } catch {\n this.router.navigate(['/administration/users']);\n } finally {\n this.isLoading.set(false);\n }\n }\n\n private loadExtraFields(userId: string): void {\n if (!this.userFormExtension?.getExtraFieldValues) return;\n\n this.isLoadingExtraFields.set(true);\n this.userFormExtension\n .getExtraFieldValues(userId)\n .pipe(\n takeUntilDestroyed(this.destroyRef),\n finalize(() => this.isLoadingExtraFields.set(false)),\n )\n .subscribe({\n next: (values) => {\n this.extraFieldsModel.set(values as Record<string, unknown>);\n this.originalExtraFieldsModel.set(values as Record<string, unknown>);\n },\n error: () => {\n const defaults: Record<string, unknown> = {};\n for (const field of this.extraFields()) {\n if (field.key) defaults[field.key] = undefined;\n }\n this.extraFieldsModel.set(defaults);\n this.originalExtraFieldsModel.set(defaults);\n },\n });\n }\n\n private toFormModel(user: IUser): IUserFormModel {\n return {\n name: user.name,\n email: user.email,\n password: '',\n phone: user.phone || '',\n isActive: user.isActive,\n emailVerified: user.emailVerified,\n };\n }\n\n onSubmit(): void {\n if (!this.isFormValid()) {\n this.messageService.add({\n severity: 'error',\n summary: this.translate('shared.validation.error'),\n detail: this.translate('shared.fill.required.fields'),\n });\n return;\n }\n\n this.isLoading.set(true);\n\n if (this.isEditMode() && this.existingUser()) {\n this.updateUser();\n } else {\n this.createUser();\n }\n }\n\n private async updateUser(): Promise<void> {\n const model = this.formModel();\n const userId = this.existingUser()!.id;\n const updateData: IUpdateUserRequest = {\n id: userId,\n name: model.name,\n email: model.email,\n phone: model.phone || undefined,\n isActive: model.isActive,\n emailVerified: model.emailVerified,\n };\n\n if (model.password) {\n updateData.password = model.password;\n }\n\n try {\n const [userResponse] = await Promise.all([\n this.userService.update(updateData),\n this.isExtraFieldsDirty() &&\n this.userFormExtension?.saveExtraFieldValues\n ? firstValueFrom(\n this.userFormExtension.saveExtraFieldValues(\n userId,\n this.extraFieldsModel(),\n ),\n )\n : Promise.resolve(undefined),\n ]);\n this.onSaveSuccess(\n userResponse.messageKey\n ? this.translate(\n userResponse.messageKey,\n userResponse.messageVariables,\n )\n : userResponse.message,\n );\n } catch {\n } finally {\n this.isLoading.set(false);\n }\n }\n\n private async createUser(): Promise<void> {\n const model = this.formModel();\n const createData: ICreateUserRequest = {\n name: model.name,\n email: model.email,\n password: model.password,\n phone: model.phone || undefined,\n isActive: model.isActive,\n emailVerified: model.emailVerified,\n };\n\n try {\n const response = await this.userService.insert(createData);\n if (response.success && response.data) {\n const userId = response.data.id;\n if (this.companyFeatureEnabled()) {\n this.assignUserToCompanyAndBranch(userId);\n }\n this.saveExtraFieldsForNewUser(userId);\n }\n this.onSaveSuccess(\n response.messageKey\n ? this.translate(\n response.messageKey,\n response.messageVariables,\n )\n : response.message,\n );\n } catch {\n } finally {\n this.isLoading.set(false);\n }\n }\n\n private saveExtraFieldsForNewUser(userId: string): void {\n const extraFields = this.extraFieldsModel();\n const hasExtraData =\n Object.keys(extraFields).length > 0 &&\n Object.values(extraFields).some((v) => v !== undefined && v !== '');\n\n if (!hasExtraData || !this.userFormExtension?.saveExtraFieldValues) return;\n\n this.userFormExtension\n .saveExtraFieldValues(userId, extraFields)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({ error: () => {} });\n }\n\n private onSaveSuccess(message: string): void {\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: message,\n });\n this.router.navigate(['/administration/users']);\n }\n\n private assignUserToCompanyAndBranch(userId: string): void {\n const company = this.authState.company();\n const branch = this.authState.branch();\n\n if (!company) return;\n\n this.permissionService\n .assignUserToCompany(userId, company.id)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: () => {\n if (branch) {\n this.permissionService\n .assignUserToBranch(userId, branch.id)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({ error: () => {} });\n }\n },\n error: () => {},\n });\n }\n\n onCancel(): void {\n this.router.navigate(['/administration/users']);\n }\n}\n"],"mappings":"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"}
|
|
@@ -128,7 +128,7 @@ var UserListComponent = class UserListComponent {
|
|
|
128
128
|
}
|
|
129
129
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
130
130
|
minVersion: "12.0.0",
|
|
131
|
-
version: "22.2.
|
|
131
|
+
version: "22.2.3",
|
|
132
132
|
ngImport: i0,
|
|
133
133
|
type: UserListComponent,
|
|
134
134
|
deps: [],
|
|
@@ -136,7 +136,7 @@ var UserListComponent = class UserListComponent {
|
|
|
136
136
|
});
|
|
137
137
|
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
138
138
|
minVersion: "17.0.0",
|
|
139
|
-
version: "22.2.
|
|
139
|
+
version: "22.2.3",
|
|
140
140
|
type: UserListComponent,
|
|
141
141
|
isStandalone: true,
|
|
142
142
|
selector: "lib-user-list",
|
|
@@ -710,7 +710,7 @@ var UserListComponent = class UserListComponent {
|
|
|
710
710
|
};
|
|
711
711
|
i0.ɵɵngDeclareClassMetadata({
|
|
712
712
|
minVersion: "12.0.0",
|
|
713
|
-
version: "22.2.
|
|
713
|
+
version: "22.2.3",
|
|
714
714
|
ngImport: i0,
|
|
715
715
|
type: UserListComponent,
|
|
716
716
|
decorators: [{
|
|
@@ -1043,4 +1043,4 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
1043
1043
|
});
|
|
1044
1044
|
export { UserListComponent };
|
|
1045
1045
|
|
|
1046
|
-
//# sourceMappingURL=flusys-ng-auth-user-list.component-
|
|
1046
|
+
//# sourceMappingURL=flusys-ng-auth-user-list.component-MHHsLH9r.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flusys-ng-auth-user-list.component-Dhq8Hygo.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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"}
|
|
1
|
+
{"version":3,"file":"flusys-ng-auth-user-list.component-MHHsLH9r.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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"}
|
|
@@ -108,7 +108,7 @@ var VerifyEmailPageComponent = class VerifyEmailPageComponent {
|
|
|
108
108
|
}
|
|
109
109
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
110
110
|
minVersion: "12.0.0",
|
|
111
|
-
version: "22.2.
|
|
111
|
+
version: "22.2.3",
|
|
112
112
|
ngImport: i0,
|
|
113
113
|
type: VerifyEmailPageComponent,
|
|
114
114
|
deps: [],
|
|
@@ -116,7 +116,7 @@ var VerifyEmailPageComponent = class VerifyEmailPageComponent {
|
|
|
116
116
|
});
|
|
117
117
|
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
118
118
|
minVersion: "17.0.0",
|
|
119
|
-
version: "22.2.
|
|
119
|
+
version: "22.2.3",
|
|
120
120
|
type: VerifyEmailPageComponent,
|
|
121
121
|
isStandalone: true,
|
|
122
122
|
selector: "lib-verify-email-page",
|
|
@@ -366,7 +366,7 @@ var VerifyEmailPageComponent = class VerifyEmailPageComponent {
|
|
|
366
366
|
};
|
|
367
367
|
i0.ɵɵngDeclareClassMetadata({
|
|
368
368
|
minVersion: "12.0.0",
|
|
369
|
-
version: "22.2.
|
|
369
|
+
version: "22.2.3",
|
|
370
370
|
ngImport: i0,
|
|
371
371
|
type: VerifyEmailPageComponent,
|
|
372
372
|
decorators: [{
|
|
@@ -542,4 +542,4 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
542
542
|
});
|
|
543
543
|
export { VerifyEmailPageComponent };
|
|
544
544
|
|
|
545
|
-
//# sourceMappingURL=flusys-ng-auth-verify-email-page.component-
|
|
545
|
+
//# sourceMappingURL=flusys-ng-auth-verify-email-page.component-3qcv2X_u.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flusys-ng-auth-verify-email-page.component-C3CLhAip.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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"}
|
|
1
|
+
{"version":3,"file":"flusys-ng-auth-verify-email-page.component-3qcv2X_u.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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"}
|