@flusys/ng-auth 9.1.2 → 9.2.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.
@@ -1 +1 @@
1
- {"version":3,"file":"flusys-ng-auth-administration-page.component-DmN4KqiR.mjs","names":[],"sources":["../../../projects/ng-auth/pages/administration/administration-page.component.ts"],"sourcesContent":["import { Component, computed, inject } from '@angular/core';\nimport { RouterOutlet } from '@angular/router';\nimport { APP_CONFIG, isCompanyFeatureEnabled } from '@flusys/ng-core';\nimport {\n BRANCH_PERMISSIONS,\n COMPANY_PERMISSIONS,\n PermissionValidatorService,\n RouterTabItem,\n RouterTabsComponent,\n SOCIAL_AUTH_CONFIG_PERMISSIONS,\n TranslatePipe,\n TranslateService,\n USER_PERMISSIONS,\n} from '@flusys/ng-shared';\n\ninterface ITab {\n id: string;\n labelKey: string;\n icon: string;\n route: string;\n permission: string;\n requiresCompanyFeature?: boolean;\n}\n\n/**\n * Administration Page Component\n * Unified administration page with tabs for:\n * - Users (always visible) - includes permission management via dialogs\n * - Companies (only if company feature enabled)\n * - Branches (only if company feature enabled)\n * - Social Config (social sign-in provider credentials)\n */\n@Component({\n selector: 'lib-administration-page',\n imports: [RouterOutlet, TranslatePipe, RouterTabsComponent],\n template: `\n <div class=\"p-4\">\n <div class=\"mb-4\">\n <h1 class=\"text-2xl font-bold m-0\">{{ 'administrative.title' | translate }}</h1>\n <p class=\"text-muted-color mt-1\">{{ 'administrative.subtitle' | translate }}</p>\n </div>\n\n <lib-router-tabs [tabs]=\"visibleTabs()\" class=\"mb-4\" />\n\n <div>\n <router-outlet />\n </div>\n </div>\n `,\n})\nexport class AdministrationPageComponent {\n private readonly appConfig = inject(APP_CONFIG);\n private readonly permissionValidator = inject(PermissionValidatorService);\n private readonly translateService = inject(TranslateService);\n\n /** All available tabs */\n private readonly allTabs: ITab[] = [\n {\n id: 'users',\n labelKey: 'administrative.user.title',\n icon: 'users',\n route: 'users',\n permission: USER_PERMISSIONS.READ,\n },\n {\n id: 'companies',\n labelKey: 'administrative.company.title',\n icon: 'building',\n route: 'company',\n permission: COMPANY_PERMISSIONS.READ,\n requiresCompanyFeature: true,\n },\n {\n id: 'branches',\n labelKey: 'administrative.branch.title',\n icon: 'sitemap',\n route: 'branch',\n permission: BRANCH_PERMISSIONS.READ,\n requiresCompanyFeature: true,\n },\n {\n id: 'social-config',\n labelKey: 'social.config.title',\n icon: 'key',\n route: 'social-config',\n permission: SOCIAL_AUTH_CONFIG_PERMISSIONS.READ,\n },\n ];\n\n /** Check if company feature is enabled */\n readonly companyFeatureEnabled = computed(() => isCompanyFeatureEnabled(this.appConfig));\n\n /** Visible tabs based on config and permissions */\n readonly visibleTabs = computed<RouterTabItem[]>(() => {\n return this.allTabs\n .filter((tab) => {\n const hasCompanyFeature = !tab.requiresCompanyFeature || this.companyFeatureEnabled();\n const hasPermission = this.permissionValidator.hasPermission(tab.permission);\n return hasCompanyFeature && hasPermission;\n })\n .map((tab) => ({\n id: tab.id,\n label: this.translateService.translate(tab.labelKey),\n icon: tab.icon,\n route: tab.route,\n }));\n });\n}\n"],"mappings":";;;;;AAkDA,IAAa,8BAAb,MAAa,4BAA2B;CACrB,YAAY,OAAO,UAAU;CAC7B,sBAAsB,OAAO,0BAA0B;CACvD,mBAAmB,OAAO,gBAAgB;CAG1C,UAAkB;EACjC;GACE,IAAI;GACJ,UAAU;GACV,MAAM;GACN,OAAO;GACP,YAAY,iBAAiB;EAC9B;EACD;GACE,IAAI;GACJ,UAAU;GACV,MAAM;GACN,OAAO;GACP,YAAY,oBAAoB;GAChC,wBAAwB;EACzB;EACD;GACE,IAAI;GACJ,UAAU;GACV,MAAM;GACN,OAAO;GACP,YAAY,mBAAmB;GAC/B,wBAAwB;EACzB;EACD;GACE,IAAI;GACJ,UAAU;GACV,MAAM;GACN,OAAO;GACP,YAAY,+BAA+B;EAC5C;CACF;CAGQ,wBAAwB,eAAe,wBAAwB,KAAK,SAAS,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,wBAAA,CAAA,+BAAA,CAAA,CAAA;CAG/E,cAAc,eAA+B;EACpD,OAAO,KAAK,QACT,QAAQ,QAAO;GACd,MAAM,oBAAoB,CAAC,IAAI,0BAA0B,KAAK,sBAAqB;GACnF,MAAM,gBAAgB,KAAK,oBAAoB,cAAc,IAAI,UAAU;GAC3E,OAAO,qBAAqB;EAC9B,CAAC,CAAC,CACD,KAAK,SAAS;GACb,IAAI,IAAI;GACR,OAAO,KAAK,iBAAiB,UAAU,IAAI,QAAQ;GACnD,MAAM,IAAI;GACV,OAAO,IAAI;EACZ,EAAC;CACN,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAxDS,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAA2B,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAA3B,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAA2B,cAAA;EAAA,UAAA;EAAA,UAAA;EAAA,UAf5B;;;;;;;;;;;;;;EAaT,UAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MAdS;IAAY,UAAA;IAAA,QAAA,CAAA,QAAA,kBAAA;IAAA,SAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,UAAA,CAAA,QAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAiB;IAAmB,UAAA;IAAA,QAAA,CAAA,MAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAlC;IAAa,MAAA;GAAA;EAAA;CAAA,CAAA;;AAgB1B,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAA2B,YAAA,CAAA;EAlBvC,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,SAAS;IAAC;IAAc;IAAe;GAAmB;GAC1D,UAAU;;;;;;;;;;;;;;EAcX,CAAA"}
1
+ {"version":3,"file":"flusys-ng-auth-administration-page.component-DmN4KqiR.mjs","names":[],"sources":["../../../projects/ng-auth/pages/administration/administration-page.component.ts"],"sourcesContent":["import { Component, computed, inject } from '@angular/core';\nimport { RouterOutlet } from '@angular/router';\nimport { APP_CONFIG, isCompanyFeatureEnabled } from '@flusys/ng-core';\nimport {\n BRANCH_PERMISSIONS,\n COMPANY_PERMISSIONS,\n PermissionValidatorService,\n RouterTabItem,\n RouterTabsComponent,\n SOCIAL_AUTH_CONFIG_PERMISSIONS,\n TranslatePipe,\n TranslateService,\n USER_PERMISSIONS,\n} from '@flusys/ng-shared';\n\ninterface ITab {\n id: string;\n labelKey: string;\n icon: string;\n route: string;\n permission: string;\n requiresCompanyFeature?: boolean;\n}\n\n/**\n * Administration Page Component\n * Unified administration page with tabs for:\n * - Users (always visible) - includes permission management via dialogs\n * - Companies (only if company feature enabled)\n * - Branches (only if company feature enabled)\n * - Social Config (social sign-in provider credentials)\n */\n@Component({\n selector: 'lib-administration-page',\n imports: [RouterOutlet, TranslatePipe, RouterTabsComponent],\n template: `\n <div class=\"p-4\">\n <div class=\"mb-4\">\n <h1 class=\"text-2xl font-bold m-0\">{{ 'administrative.title' | translate }}</h1>\n <p class=\"text-muted-color mt-1\">{{ 'administrative.subtitle' | translate }}</p>\n </div>\n\n <lib-router-tabs [tabs]=\"visibleTabs()\" class=\"mb-4\" />\n\n <div>\n <router-outlet />\n </div>\n </div>\n `,\n})\nexport class AdministrationPageComponent {\n private readonly appConfig = inject(APP_CONFIG);\n private readonly permissionValidator = inject(PermissionValidatorService);\n private readonly translateService = inject(TranslateService);\n\n private readonly allTabs: ITab[] = [\n {\n id: 'users',\n labelKey: 'administrative.user.title',\n icon: 'users',\n route: 'users',\n permission: USER_PERMISSIONS.READ,\n },\n {\n id: 'companies',\n labelKey: 'administrative.company.title',\n icon: 'building',\n route: 'company',\n permission: COMPANY_PERMISSIONS.READ,\n requiresCompanyFeature: true,\n },\n {\n id: 'branches',\n labelKey: 'administrative.branch.title',\n icon: 'sitemap',\n route: 'branch',\n permission: BRANCH_PERMISSIONS.READ,\n requiresCompanyFeature: true,\n },\n {\n id: 'social-config',\n labelKey: 'social.config.title',\n icon: 'key',\n route: 'social-config',\n permission: SOCIAL_AUTH_CONFIG_PERMISSIONS.READ,\n },\n ];\n\n readonly companyFeatureEnabled = computed(() => isCompanyFeatureEnabled(this.appConfig));\n\n readonly visibleTabs = computed<RouterTabItem[]>(() => {\n return this.allTabs\n .filter((tab) => {\n const hasCompanyFeature = !tab.requiresCompanyFeature || this.companyFeatureEnabled();\n const hasPermission = this.permissionValidator.hasPermission(tab.permission);\n return hasCompanyFeature && hasPermission;\n })\n .map((tab) => ({\n id: tab.id,\n label: this.translateService.translate(tab.labelKey),\n icon: tab.icon,\n route: tab.route,\n }));\n });\n}\n"],"mappings":";;;;;AAkDA,IAAa,8BAAb,MAAa,4BAA2B;CACrB,YAAY,OAAO,UAAU;CAC7B,sBAAsB,OAAO,0BAA0B;CACvD,mBAAmB,OAAO,gBAAgB;CAE1C,UAAkB;EACjC;GACE,IAAI;GACJ,UAAU;GACV,MAAM;GACN,OAAO;GACP,YAAY,iBAAiB;EAC9B;EACD;GACE,IAAI;GACJ,UAAU;GACV,MAAM;GACN,OAAO;GACP,YAAY,oBAAoB;GAChC,wBAAwB;EACzB;EACD;GACE,IAAI;GACJ,UAAU;GACV,MAAM;GACN,OAAO;GACP,YAAY,mBAAmB;GAC/B,wBAAwB;EACzB;EACD;GACE,IAAI;GACJ,UAAU;GACV,MAAM;GACN,OAAO;GACP,YAAY,+BAA+B;EAC5C;CACF;CAEQ,wBAAwB,eAAe,wBAAwB,KAAK,SAAS,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,wBAAA,CAAA,+BAAA,CAAA,CAAA;CAE/E,cAAc,eAA+B;EACpD,OAAO,KAAK,QACT,QAAQ,QAAO;GACd,MAAM,oBAAoB,CAAC,IAAI,0BAA0B,KAAK,sBAAqB;GACnF,MAAM,gBAAgB,KAAK,oBAAoB,cAAc,IAAI,UAAU;GAC3E,OAAO,qBAAqB;EAC9B,CAAC,CAAC,CACD,KAAK,SAAS;GACb,IAAI,IAAI;GACR,OAAO,KAAK,iBAAiB,UAAU,IAAI,QAAQ;GACnD,MAAM,IAAI;GACV,OAAO,IAAI;EACZ,EAAC;CACN,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CArDS,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAA2B,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAA3B,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAA2B,cAAA;EAAA,UAAA;EAAA,UAAA;EAAA,UAf5B;;;;;;;;;;;;;;EAaT,UAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MAdS;IAAY,UAAA;IAAA,QAAA,CAAA,QAAA,kBAAA;IAAA,SAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,UAAA,CAAA,QAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAiB;IAAmB,UAAA;IAAA,QAAA,CAAA,MAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAlC;IAAa,MAAA;GAAA;EAAA;CAAA,CAAA;;AAgB1B,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAA2B,YAAA,CAAA;EAlBvC,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,SAAS;IAAC;IAAc;IAAe;GAAmB;GAC1D,UAAU;;;;;;;;;;;;;;EAcX,CAAA"}
@@ -64,7 +64,9 @@ var SocialCallbackPageComponent = class SocialCallbackPageComponent {
64
64
  detail: response.messageKey ? this.translate(response.messageKey, response.messageVariables) : response.message ?? this.translate("auth.login.success")
65
65
  });
66
66
  this.authState.navigateAfterLogin(this.returnUrl());
67
+ return;
67
68
  }
69
+ this._error.set({ key: "auth.social.failed" });
68
70
  },
69
71
  error: (error) => {
70
72
  const messageKey = error?.error?.messageKey;
@@ -214,4 +216,4 @@ i0.ɵɵngDeclareClassMetadata({
214
216
  });
215
217
  export { SocialCallbackPageComponent };
216
218
 
217
- //# sourceMappingURL=flusys-ng-auth-social-callback-page.component-gTD7_LJY.mjs.map
219
+ //# sourceMappingURL=flusys-ng-auth-social-callback-page.component-uE6vIUtK.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"flusys-ng-auth-social-callback-page.component-gTD7_LJY.mjs","names":[],"sources":["../../../projects/ng-auth/pages/social-callback/social-callback-page.component.ts"],"sourcesContent":["import { Component, computed, DestroyRef, inject, signal } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { AppFloatingConfigurator } from '@flusys/ng-layout';\nimport { PlatformService, TranslatePipe, TranslateService } from '@flusys/ng-shared';\nimport { FButtonDirective, MessageService, UiIconComponent } from '@flusys/ng-ui';\nimport {\n isCompanySelectionResponse,\n isLoginResponse,\n} from '../../interfaces/auth.interface';\nimport { AuthStateService } from '../../services/auth-state.service';\nimport { SocialAuthApiService } from '../../services/social-auth-api.service';\n\n@Component({\n selector: 'lib-social-callback-page',\n imports: [FButtonDirective, UiIconComponent, TranslatePipe, AppFloatingConfigurator],\n template: `\n <app-floating-configurator />\n <div class=\"bg-surface-ground flex items-center justify-center min-h-screen\">\n <div class=\"flex flex-col items-center gap-4 text-center px-4\">\n @if (errorDetail()) {\n <ui-icon name=\"exclamation-circle\" class=\"text-6xl text-danger\"></ui-icon>\n <div class=\"text-2xl font-medium text-color\">\n {{ 'auth.social.failed' | translate }}\n </div>\n <p class=\"text-muted-color font-medium\">{{ errorDetail() }}</p>\n <button fButton severity=\"secondary\" [outlined]=\"true\" (click)=\"backToLogin()\">\n <span>{{ 'auth.login.back.to.sign.in' | translate }}</span>\n </button>\n } @else {\n <ui-icon name=\"spinner\" [spin]=\"true\" class=\"text-5xl text-primary\"></ui-icon>\n <div class=\"text-2xl font-medium text-color\">\n {{ 'auth.social.signing.in' | translate }}\n </div>\n }\n </div>\n </div>\n `,\n})\nexport class SocialCallbackPageComponent {\n private readonly destroyRef = inject(DestroyRef);\n private readonly route = inject(ActivatedRoute);\n private readonly router = inject(Router);\n private readonly platform = inject(PlatformService);\n private readonly socialApi = inject(SocialAuthApiService);\n private readonly authState = inject(AuthStateService);\n private readonly messageService = inject(MessageService);\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\n\n private readonly _error = signal<\n { key: string; vars?: Record<string, string | number> } | { raw: string } | null\n >(null);\n readonly errorDetail = computed(() => {\n const error = this._error();\n if (!error) return null;\n return 'key' in error ? this.translate(error.key, error.vars) : error.raw;\n });\n\n constructor() {\n if (this.platform.isServer) return;\n this.exchangeCode();\n }\n\n backToLogin(): void {\n this.router.navigate(['/auth/login']);\n }\n\n private exchangeCode(): void {\n const params = this.route.snapshot.queryParamMap;\n\n const providerError = params.get('error_description') ?? params.get('error');\n if (providerError) {\n this._error.set({ raw: providerError });\n return;\n }\n\n const code = params.get('code');\n const state = params.get('state');\n\n if (!code || !state) {\n this._error.set({ key: 'auth.social.state.invalid' });\n return;\n }\n\n this.socialApi\n .callback({ code, state, redirectUri: this.socialApi.redirectUri })\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: (response) => {\n if (!response.data) {\n this._error.set({ key: 'auth.social.failed' });\n return;\n }\n\n if (isCompanySelectionResponse(response)) {\n this.authState.setSelectionState(response.data);\n this.router.navigate(['/auth/login']);\n return;\n }\n\n if (isLoginResponse(response)) {\n this.authState.setLoginState(response.data);\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: response.messageKey\n ? this.translate(response.messageKey, response.messageVariables)\n : (response.message ?? this.translate('auth.login.success')),\n });\n this.authState.navigateAfterLogin(this.returnUrl());\n }\n },\n error: (error) => {\n const messageKey = error?.error?.messageKey;\n if (messageKey) {\n this._error.set({ key: messageKey, vars: error?.error?.messageVariables });\n } else if (error?.error?.message) {\n this._error.set({ raw: error.error.message });\n } else {\n this._error.set({ key: 'auth.social.failed' });\n }\n },\n });\n }\n\n private returnUrl(): string {\n return this.socialApi.consumeReturnUrl();\n }\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"],"mappings":"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"}
1
+ {"version":3,"file":"flusys-ng-auth-social-callback-page.component-uE6vIUtK.mjs","names":[],"sources":["../../../projects/ng-auth/pages/social-callback/social-callback-page.component.ts"],"sourcesContent":["import { Component, computed, DestroyRef, inject, signal } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { AppFloatingConfigurator } from '@flusys/ng-layout';\nimport { PlatformService, TranslatePipe, TranslateService } from '@flusys/ng-shared';\nimport { FButtonDirective, MessageService, UiIconComponent } from '@flusys/ng-ui';\nimport {\n isCompanySelectionResponse,\n isLoginResponse,\n} from '../../interfaces/auth.interface';\nimport { AuthStateService } from '../../services/auth-state.service';\nimport { SocialAuthApiService } from '../../services/social-auth-api.service';\n\n@Component({\n selector: 'lib-social-callback-page',\n imports: [FButtonDirective, UiIconComponent, TranslatePipe, AppFloatingConfigurator],\n template: `\n <app-floating-configurator />\n <div class=\"bg-surface-ground flex items-center justify-center min-h-screen\">\n <div class=\"flex flex-col items-center gap-4 text-center px-4\">\n @if (errorDetail()) {\n <ui-icon name=\"exclamation-circle\" class=\"text-6xl text-danger\"></ui-icon>\n <div class=\"text-2xl font-medium text-color\">\n {{ 'auth.social.failed' | translate }}\n </div>\n <p class=\"text-muted-color font-medium\">{{ errorDetail() }}</p>\n <button fButton severity=\"secondary\" [outlined]=\"true\" (click)=\"backToLogin()\">\n <span>{{ 'auth.login.back.to.sign.in' | translate }}</span>\n </button>\n } @else {\n <ui-icon name=\"spinner\" [spin]=\"true\" class=\"text-5xl text-primary\"></ui-icon>\n <div class=\"text-2xl font-medium text-color\">\n {{ 'auth.social.signing.in' | translate }}\n </div>\n }\n </div>\n </div>\n `,\n})\nexport class SocialCallbackPageComponent {\n private readonly destroyRef = inject(DestroyRef);\n private readonly route = inject(ActivatedRoute);\n private readonly router = inject(Router);\n private readonly platform = inject(PlatformService);\n private readonly socialApi = inject(SocialAuthApiService);\n private readonly authState = inject(AuthStateService);\n private readonly messageService = inject(MessageService);\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\n\n private readonly _error = signal<\n { key: string; vars?: Record<string, string | number> } | { raw: string } | null\n >(null);\n readonly errorDetail = computed(() => {\n const error = this._error();\n if (!error) return null;\n return 'key' in error ? this.translate(error.key, error.vars) : error.raw;\n });\n\n constructor() {\n if (this.platform.isServer) return;\n this.exchangeCode();\n }\n\n backToLogin(): void {\n this.router.navigate(['/auth/login']);\n }\n\n private exchangeCode(): void {\n const params = this.route.snapshot.queryParamMap;\n\n const providerError = params.get('error_description') ?? params.get('error');\n if (providerError) {\n this._error.set({ raw: providerError });\n return;\n }\n\n const code = params.get('code');\n const state = params.get('state');\n\n if (!code || !state) {\n this._error.set({ key: 'auth.social.state.invalid' });\n return;\n }\n\n this.socialApi\n .callback({ code, state, redirectUri: this.socialApi.redirectUri })\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: (response) => {\n if (!response.data) {\n this._error.set({ key: 'auth.social.failed' });\n return;\n }\n\n if (isCompanySelectionResponse(response)) {\n this.authState.setSelectionState(response.data);\n this.router.navigate(['/auth/login']);\n return;\n }\n\n if (isLoginResponse(response)) {\n this.authState.setLoginState(response.data);\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: response.messageKey\n ? this.translate(response.messageKey, response.messageVariables)\n : (response.message ?? this.translate('auth.login.success')),\n });\n this.authState.navigateAfterLogin(this.returnUrl());\n return;\n }\n\n this._error.set({ key: 'auth.social.failed' });\n },\n error: (error) => {\n const messageKey = error?.error?.messageKey;\n if (messageKey) {\n this._error.set({ key: messageKey, vars: error?.error?.messageVariables });\n } else if (error?.error?.message) {\n this._error.set({ raw: error.error.message });\n } else {\n this._error.set({ key: 'auth.social.failed' });\n }\n },\n });\n }\n\n private returnUrl(): string {\n return this.socialApi.consumeReturnUrl();\n }\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"],"mappings":";;;;;;;;AAuCA,IAAa,8BAAb,MAAa,4BAA2B;CACrB,aAAa,OAAO,UAAU;CAC9B,QAAQ,OAAO,cAAc;CAC7B,SAAS,OAAO,MAAM;CACtB,WAAW,OAAO,eAAe;CACjC,YAAY,OAAO,oBAAoB;CACvC,YAAY,OAAO,gBAAgB;CACnC,iBAAiB,OAAO,cAAc;CACtC,mBAAmB,OAAO,kBAAkB,EAC3D,UAAU,KACX,CAAA;CAEgB,SAAS,OAExB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CACE,cAAc,eAAc;EACnC,MAAM,QAAQ,KAAK,OAAM;EACzB,IAAI,CAAC,OAAO,OAAO;EACnB,OAAO,SAAS,QAAQ,KAAK,UAAU,MAAM,KAAK,MAAM,IAAI,IAAI,MAAM;CACxE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAEF,cAAA;EACE,IAAI,KAAK,SAAS,UAAU;EAC5B,KAAK,aAAY;CACnB;CAEA,cAAW;EACT,KAAK,OAAO,SAAS,CAAC,aAAa,CAAC;CACtC;CAEQ,eAAY;EAClB,MAAM,SAAS,KAAK,MAAM,SAAS;EAEnC,MAAM,gBAAgB,OAAO,IAAI,mBAAmB,KAAK,OAAO,IAAI,OAAO;EAC3E,IAAI,eAAe;GACjB,KAAK,OAAO,IAAI,EAAE,KAAK,cAAa,CAAE;GACtC;EACF;EAEA,MAAM,OAAO,OAAO,IAAI,MAAM;EAC9B,MAAM,QAAQ,OAAO,IAAI,OAAO;EAEhC,IAAI,CAAC,QAAQ,CAAC,OAAO;GACnB,KAAK,OAAO,IAAI,EAAE,KAAK,4BAA2B,CAAE;GACpD;EACF;EAEA,KAAK,UACF,SAAS;GAAE;GAAM;GAAO,aAAa,KAAK,UAAU;EAAW,CAAE,CAAC,CAClE,KAAK,mBAAmB,KAAK,UAAU,CAAC,CAAC,CACzC,UAAU;GACT,OAAO,aAAY;IACjB,IAAI,CAAC,SAAS,MAAM;KAClB,KAAK,OAAO,IAAI,EAAE,KAAK,qBAAoB,CAAE;KAC7C;IACF;IAEA,IAAI,2BAA2B,QAAQ,GAAG;KACxC,KAAK,UAAU,kBAAkB,SAAS,IAAI;KAC9C,KAAK,OAAO,SAAS,CAAC,aAAa,CAAC;KACpC;IACF;IAEA,IAAI,gBAAgB,QAAQ,GAAG;KAC7B,KAAK,UAAU,cAAc,SAAS,IAAI;KAC1C,KAAK,eAAe,IAAI;MACtB,UAAU;MACV,SAAS,KAAK,UAAU,gBAAgB;MACxC,QAAQ,SAAS,aACb,KAAK,UAAU,SAAS,YAAY,SAAS,gBAAgB,IAC5D,SAAS,WAAW,KAAK,UAAU,oBAAoB;KAC7D,CAAA;KACD,KAAK,UAAU,mBAAmB,KAAK,UAAS,CAAE;KAClD;IACF;IAEA,KAAK,OAAO,IAAI,EAAE,KAAK,qBAAoB,CAAE;GAC/C;GACA,QAAQ,UAAS;IACf,MAAM,aAAa,OAAO,OAAO;IACjC,IAAI,YACF,KAAK,OAAO,IAAI;KAAE,KAAK;KAAY,MAAM,OAAO,OAAO;IAAgB,CAAE;SACpE,IAAI,OAAO,OAAO,SACvB,KAAK,OAAO,IAAI,EAAE,KAAK,MAAM,MAAM,QAAO,CAAE;SAE5C,KAAK,OAAO,IAAI,EAAE,KAAK,qBAAoB,CAAE;GAEjD;EACD,CAAA;CACL;CAEQ,YAAS;EACf,OAAO,KAAK,UAAU,iBAAgB;CACxC;CAEQ,UACN,KACA,MAA8B;EAE9B,OAAO,KAAK,kBAAkB,UAAU,KAAK,IAAI,KAAK;CACxD;CApGW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAA2B,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAA3B,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAA2B,cAAA;EAAA,UAAA;EAAA,UAAA;EAAA,UAvB5B;;;;;;;;;;;;;;;;;;;;;;EAqBT,UAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MAtBS;IAAgB,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAe,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAiB;IAAuB,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAtC;IAAa,MAAA;GAAA;EAAA;CAAA,CAAA;;AAwB/C,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAA2B,YAAA,CAAA;EA1BvC,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,SAAS;IAAC;IAAkB;IAAiB;IAAe;GAAuB;GACnF,UAAU;;;;;;;;;;;;;;;;;;;;;;EAsBX,CAAA"}
@@ -86,7 +86,6 @@ var SocialConfigPageComponent = class SocialConfigPageComponent {
86
86
  type: SocialConfigPageComponent,
87
87
  isStandalone: true,
88
88
  selector: "lib-social-config-page",
89
- providers: [MessageService],
90
89
  ngImport: i0,
91
90
  template: `
92
91
  <div class="card">
@@ -359,7 +358,6 @@ i0.ɵɵngDeclareClassMetadata({
359
358
  FormsModule,
360
359
  TranslatePipe
361
360
  ],
362
- providers: [MessageService],
363
361
  template: `
364
362
  <div class="card">
365
363
  <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 mb-4">
@@ -538,4 +536,4 @@ function toUpdateDto(form) {
538
536
  }
539
537
  export { SocialConfigPageComponent };
540
538
 
541
- //# sourceMappingURL=flusys-ng-auth-social-config-page.component-DpGmcb9n.mjs.map
539
+ //# sourceMappingURL=flusys-ng-auth-social-config-page.component-DQvkiR7M.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flusys-ng-auth-social-config-page.component-DQvkiR7M.mjs","names":[],"sources":["../../../projects/ng-auth/pages/social-config/social-config-page.component.ts"],"sourcesContent":["import { Component, inject, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport {\n TranslatePipe,\n TranslateService,\n} from '@flusys/ng-shared';\nimport {\n FButtonDirective,\n InputTextDirective,\n MessageService,\n PasswordComponent,\n ToggleSwitchComponent,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport {\n SOCIAL_PROVIDERS,\n SocialProviderEnum,\n} from '../../enums/social-provider.enum';\nimport {\n ICreateSocialAuthConfigDto,\n ISocialAuthConfig,\n IUpdateSocialAuthConfigDto,\n} from '../../interfaces/social-auth.interface';\nimport { SocialAuthApiService } from '../../services/social-auth-api.service';\nimport { SocialAuthConfigApiService } from '../../services/social-auth-config-api.service';\n\ninterface IProviderFormModel {\n provider: SocialProviderEnum;\n id: string | null;\n isEnabled: boolean;\n clientId: string;\n /** A newly typed secret to save. Left blank keeps the previously stored one. */\n clientSecret: string;\n hasClientSecret: boolean;\n tenantId: string;\n scopes: string;\n}\n\nconst TENANT_PROVIDER = SocialProviderEnum.MICROSOFT;\n\n@Component({\n selector: 'lib-social-config-page',\n imports: [\n FButtonDirective,\n InputTextDirective,\n PasswordComponent,\n ToggleSwitchComponent,\n UiIconComponent,\n FormsModule,\n TranslatePipe,\n ],\n template: `\n <div class=\"card\">\n <div class=\"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 mb-4\">\n <div>\n <h3 class=\"text-lg sm:text-xl font-semibold m-0\">\n {{ 'social.config.title' | translate }}\n </h3>\n <p class=\"text-sm text-muted-color mt-1\">\n {{ 'social.config.subtitle' | translate }}\n </p>\n </div>\n <button fButton (click)=\"onSave()\" [disabled]=\"isSaving()\" [loading]=\"isSaving()\">\n @if (!isSaving()) {\n <ui-icon pButtonIcon name=\"save\"></ui-icon>\n }\n <span pButtonLabel>{{ 'shared.save' | translate }}</span>\n </button>\n </div>\n\n <p class=\"text-sm text-muted-color mb-4\">\n {{ 'social.config.redirect.uri' | translate }}:\n <code class=\"text-color\">{{ redirectUri }}</code>\n </p>\n\n @if (isLoading()) {\n <div class=\"flex justify-center py-8\">\n <ui-icon name=\"spinner\" [spin]=\"true\" class=\"text-3xl text-primary\"></ui-icon>\n </div>\n } @else {\n <div class=\"flex flex-col gap-4\">\n @for (form of forms(); track form.provider) {\n <div class=\"border border-surface rounded p-4\">\n <div class=\"flex items-center justify-between gap-3\">\n <div>\n <div class=\"font-semibold\">\n {{ 'auth.social.provider.' + form.provider | translate }}\n </div>\n <div class=\"text-sm text-muted-color\">\n {{ 'social.config.provider.hint.' + form.provider | translate }}\n </div>\n </div>\n <f-toggleswitch\n [ngModel]=\"form.isEnabled\"\n (ngModelChange)=\"updateField(form.provider, 'isEnabled', $event)\"\n />\n </div>\n\n @if (form.isEnabled) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4 mt-4 pt-4 border-t border-surface\">\n <div class=\"field\">\n <label [for]=\"form.provider + '-client-id'\" class=\"block font-medium mb-2\">\n {{ 'social.config.client.id' | translate }} *\n </label>\n <input\n fInputText\n [id]=\"form.provider + '-client-id'\"\n class=\"w-full\"\n [ngModel]=\"form.clientId\"\n (ngModelChange)=\"updateField(form.provider, 'clientId', $event)\"\n />\n </div>\n\n <div class=\"field\">\n <label [for]=\"form.provider + '-client-secret'\" class=\"block font-medium mb-2\">\n {{ 'social.config.client.secret' | translate }}\n @if (!form.hasClientSecret) {\n *\n }\n </label>\n <f-password\n [inputId]=\"form.provider + '-client-secret'\"\n styleClass=\"w-full\"\n [placeholder]=\"\n form.hasClientSecret\n ? ('social.config.client.secret.unchanged' | translate)\n : ''\n \"\n [ngModel]=\"form.clientSecret\"\n (ngModelChange)=\"updateField(form.provider, 'clientSecret', $event)\"\n />\n </div>\n\n @if (form.provider === tenantProvider) {\n <div class=\"field\">\n <label [for]=\"form.provider + '-tenant'\" class=\"block font-medium mb-2\">\n {{ 'social.config.tenant.id' | translate }}\n </label>\n <input\n fInputText\n [id]=\"form.provider + '-tenant'\"\n class=\"w-full\"\n [placeholder]=\"'social.config.tenant.id.example' | translate\"\n [ngModel]=\"form.tenantId\"\n (ngModelChange)=\"updateField(form.provider, 'tenantId', $event)\"\n />\n </div>\n }\n\n <div class=\"field\">\n <label [for]=\"form.provider + '-scopes'\" class=\"block font-medium mb-2\">\n {{ 'social.config.scopes' | translate }}\n </label>\n <input\n fInputText\n [id]=\"form.provider + '-scopes'\"\n class=\"w-full\"\n [placeholder]=\"'social.config.scopes.placeholder' | translate\"\n [ngModel]=\"form.scopes\"\n (ngModelChange)=\"updateField(form.provider, 'scopes', $event)\"\n />\n </div>\n\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n `,\n})\nexport class SocialConfigPageComponent {\n private readonly configService = inject(SocialAuthConfigApiService);\n private readonly socialApi = inject(SocialAuthApiService);\n private readonly messageService = inject(MessageService);\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\n\n readonly tenantProvider = TENANT_PROVIDER;\n\n private readonly _forms = signal<IProviderFormModel[]>(\n SOCIAL_PROVIDERS.map(emptyForm),\n );\n readonly forms = this._forms.asReadonly();\n\n private readonly _isLoading = signal(true);\n readonly isLoading = this._isLoading.asReadonly();\n\n private readonly _isSaving = signal(false);\n readonly isSaving = this._isSaving.asReadonly();\n\n readonly redirectUri = this.socialApi.redirectUri;\n\n constructor() {\n void this.loadConfigs();\n }\n\n updateField<K extends keyof IProviderFormModel>(\n provider: SocialProviderEnum,\n field: K,\n value: IProviderFormModel[K],\n ): void {\n this._forms.update((forms) =>\n forms.map((form) =>\n form.provider === provider ? { ...form, [field]: value } : form,\n ),\n );\n }\n\n async onSave(): Promise<void> {\n const invalid = this._forms().find(\n (form) =>\n form.isEnabled &&\n (!form.clientId.trim() || (!form.hasClientSecret && !form.clientSecret.trim())),\n );\n\n if (invalid) {\n this.messageService.add({\n severity: 'warn',\n summary: this.translate('shared.validation'),\n detail: this.translate('social.config.credentials.required', {\n provider: this.translate(`auth.social.provider.${invalid.provider}`),\n }),\n });\n return;\n }\n\n this._isSaving.set(true);\n try {\n const pending = this._forms().filter((form) => form.id || form.isEnabled);\n await this.configService.bulkUpsert(\n pending.filter((form) => !form.id).map(toCreateDto),\n pending.filter((form) => form.id).map(toUpdateDto),\n );\n\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: this.translate('social.config.save.success'),\n });\n await this.loadConfigs();\n } catch {\n // Error toast handled by global interceptor\n } finally {\n this._isSaving.set(false);\n }\n }\n\n private async loadConfigs(): Promise<void> {\n this._isLoading.set(true);\n try {\n const response = await this.configService.getAll({\n pagination: { currentPage: 0, pageSize: SOCIAL_PROVIDERS.length },\n filter: {},\n select: [],\n sort: {},\n });\n this._forms.set(mergeConfigs(response.data ?? []));\n } catch {\n // Error toast handled by global interceptor\n } finally {\n this._isLoading.set(false);\n }\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\nfunction emptyForm(provider: SocialProviderEnum): IProviderFormModel {\n return {\n provider,\n id: null,\n isEnabled: false,\n clientId: '',\n clientSecret: '',\n hasClientSecret: false,\n tenantId: '',\n scopes: '',\n };\n}\n\nfunction mergeConfigs(configs: ISocialAuthConfig[]): IProviderFormModel[] {\n return SOCIAL_PROVIDERS.map((provider) => {\n const config = configs.find((entry) => entry.provider === provider);\n if (!config) return emptyForm(provider);\n\n return {\n provider,\n id: config.id,\n isEnabled: config.isEnabled,\n clientId: config.clientId ?? '',\n clientSecret: '',\n hasClientSecret: config.hasClientSecret,\n tenantId: (config.extraConfig?.['tenantId'] as string) ?? '',\n scopes: (config.scopes ?? []).join(', '),\n };\n });\n}\n\n/** clientSecret is omitted here; callers decide whether to include a newly typed value. */\nfunction toBaseDto(form: IProviderFormModel): Omit<ICreateSocialAuthConfigDto, 'clientSecret'> {\n const scopes = form.scopes\n .split(',')\n .map((scope) => scope.trim())\n .filter(Boolean);\n\n return {\n provider: form.provider,\n isEnabled: form.isEnabled,\n clientId: form.clientId.trim(),\n ...(scopes.length ? { scopes } : {}),\n ...(form.provider === TENANT_PROVIDER && form.tenantId.trim()\n ? { extraConfig: { tenantId: form.tenantId.trim() } }\n : {}),\n };\n}\n\nfunction toCreateDto(form: IProviderFormModel): ICreateSocialAuthConfigDto {\n return { ...toBaseDto(form), clientSecret: form.clientSecret.trim() };\n}\n\nfunction toUpdateDto(form: IProviderFormModel): IUpdateSocialAuthConfigDto {\n const trimmedSecret = form.clientSecret.trim();\n return {\n id: form.id!,\n ...toBaseDto(form),\n // Blank means \"keep the previously stored secret\" - never overwrite it with an empty value.\n ...(trimmedSecret ? { clientSecret: trimmedSecret } : {}),\n };\n}\n"],"mappings":"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"}
@@ -119,7 +119,7 @@ var UserFormComponent = class UserFormComponent {
119
119
  const nameValid = model.name.trim().length > 0;
120
120
  const emailValid = model.email.includes("@");
121
121
  const passwordValid = model.password ? !this.passwordError() : isEdit;
122
- return nameValid && emailValid && passwordValid;
122
+ return nameValid && emailValid && passwordValid && !this.extraFieldsValidationError();
123
123
  }, ...ngDevMode ? [{ debugName: "isFormValid" }] : /* istanbul ignore next */ []);
124
124
  constructor() {
125
125
  effect(() => {
@@ -199,7 +199,7 @@ var UserFormComponent = class UserFormComponent {
199
199
  try {
200
200
  const [userResponse] = await Promise.all([this.userService.update(updateData), this.isExtraFieldsDirty() && this.userFormExtension?.saveExtraFieldValues ? firstValueFrom(this.userFormExtension.saveExtraFieldValues(userId, this.extraFieldsModel())) : Promise.resolve(void 0)]);
201
201
  this.onSaveSuccess(userResponse.messageKey ? this.translate(userResponse.messageKey, userResponse.messageVariables) : userResponse.message);
202
- } finally {
202
+ } catch {} finally {
203
203
  this.isLoading.set(false);
204
204
  }
205
205
  }
@@ -221,7 +221,7 @@ var UserFormComponent = class UserFormComponent {
221
221
  this.saveExtraFieldsForNewUser(userId);
222
222
  }
223
223
  this.onSaveSuccess(response.messageKey ? this.translate(response.messageKey, response.messageVariables) : response.message);
224
- } finally {
224
+ } catch {} finally {
225
225
  this.isLoading.set(false);
226
226
  }
227
227
  }
@@ -1168,4 +1168,4 @@ i0.ɵɵngDeclareClassMetadata({
1168
1168
  });
1169
1169
  export { UserFormComponent };
1170
1170
 
1171
- //# sourceMappingURL=flusys-ng-auth-user-form.component-CM9UYc0q.mjs.map
1171
+ //# sourceMappingURL=flusys-ng-auth-user-form.component-C5ncAjU9.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"flusys-ng-auth-user-form.component-CM9UYc0q.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;\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 } 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 } 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-C5ncAjU9.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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"}
@@ -80,7 +80,7 @@ var UserListComponent = class UserListComponent {
80
80
  }
81
81
  onLazyLoad(event) {
82
82
  const first = event.first ?? 0;
83
- const rows = event.rows ?? 10;
83
+ const rows = event.rows || 10;
84
84
  const page = Math.floor(first / rows);
85
85
  this.loadUsers(page, rows);
86
86
  }
@@ -1043,4 +1043,4 @@ i0.ɵɵngDeclareClassMetadata({
1043
1043
  });
1044
1044
  export { UserListComponent };
1045
1045
 
1046
- //# sourceMappingURL=flusys-ng-auth-user-list.component-Bew7gz-H.mjs.map
1046
+ //# sourceMappingURL=flusys-ng-auth-user-list.component-BNYmRTlN.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"flusys-ng-auth-user-list.component-Bew7gz-H.mjs","names":[],"sources":["../../../projects/ng-auth/pages/users/user-list.component.ts"],"sourcesContent":["import { Component, computed, inject, signal } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { Router } from '@angular/router';\nimport { APP_CONFIG, isCompanyFeatureEnabled } from '@flusys/ng-core';\nimport {\n CardComponent,\n ConfirmationService,\n DialogComponent,\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n MessageService,\n TableComponent,\n TagComponent,\n TooltipDirective,\n UiIconComponent,\n} from '@flusys/ng-ui';\nimport {\n HasPermissionDirective,\n TranslatePipe,\n TranslateService,\n USER_PERMISSIONS,\n} from '@flusys/ng-shared';\nimport { UserBranchPermissionDialogComponent } from '../../components/user-branch-permission-dialog.component';\nimport { UserCompanyPermissionDialogComponent } from '../../components/user-company-permission-dialog.component';\nimport { IUser } from '../../interfaces/user.interface';\nimport {\n AUTH_USER_DETAIL_CONFIG,\n AUTH_USER_LIST_EXTENSION,\n IUserListExtraAction,\n IUserListExtraColumn,\n} from '../../providers/auth-extension.providers';\nimport { sortByOrder } from '../../providers/extension-order.util';\nimport { UserApiService } from '../../services/user-api.service';\n\n@Component({\n selector: 'lib-user-list',\n imports: [\n NgTemplateOutlet,\n FormsModule,\n CardComponent,\n DialogComponent,\n FButtonDirective,\n IconFieldComponent,\n InputIconComponent,\n InputTextDirective,\n TableComponent,\n TagComponent,\n TooltipDirective,\n UiIconComponent,\n HasPermissionDirective,\n TranslatePipe,\n UserCompanyPermissionDialogComponent,\n UserBranchPermissionDialogComponent,\n ],\n template: `\n <f-card>\n <ng-template #header>\n <div\n class=\"flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 p-4\"\n >\n <h2 class=\"text-xl font-semibold m-0\">\n {{ 'administrative.user.title' | translate }}\n </h2>\n <div class=\"flex items-center gap-3 w-full sm:w-auto\">\n <f-iconfield class=\"w-full sm:w-64\">\n <f-inputicon icon=\"search\" />\n <input\n fInputText\n type=\"text\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"onSearchChange($event)\"\n [placeholder]=\"'shared.search' | translate\"\n />\n </f-iconfield>\n <button\n fButton\n *hasPermission=\"USER_PERMISSIONS.CREATE\"\n (click)=\"onCreate()\"\n >\n <ui-icon pButtonIcon name=\"plus\"></ui-icon>\n <span pButtonLabel>{{ 'administrative.user.add' | translate }}</span>\n </button>\n </div>\n </div>\n </ng-template>\n\n <div class=\"overflow-x-auto\">\n <f-table\n [value]=\"users()\"\n [loading]=\"isLoading()\"\n [paginator]=\"total() > 0\"\n [rows]=\"10\"\n [rowsPerPageOptions]=\"[10, 25, 50]\"\n [totalRecords]=\"total()\"\n [lazy]=\"true\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n [scrollable]=\"true\"\n >\n <ng-template #header>\n <tr>\n <th>{{ 'administrative.user.name' | translate }}</th>\n <th>{{ 'administrative.email.label' | translate }}</th>\n <th>{{ 'administrative.phone.label' | translate }}</th>\n <th>{{ 'administrative.user.email.verified' | translate }}</th>\n <th>{{ 'shared.status' | translate }}</th>\n @for (col of extraColumns(); track col.key) {\n <th\n [class]=\"col.styleClass ?? ''\"\n [style.width]=\"col.width ?? 'auto'\"\n >\n {{ col.headerKey | translate: null : col.header }}\n </th>\n }\n <th class=\"w-[180px]\">{{ 'shared.actions' | translate }}</th>\n </tr>\n </ng-template>\n <ng-template #body let-user>\n <tr>\n <td>{{ user.name }}</td>\n <td>{{ user.email }}</td>\n <td>{{ user.phone || '-' }}</td>\n <td>\n <f-tag\n [value]=\"\n user.emailVerified\n ? ('shared.verified' | translate)\n : ('shared.unverified' | translate)\n \"\n [severity]=\"user.emailVerified ? 'success' : 'warn'\"\n />\n </td>\n <td>\n <f-tag\n [value]=\"\n user.isActive\n ? ('shared.active' | translate)\n : ('shared.inactive' | translate)\n \"\n [severity]=\"user.isActive ? 'success' : 'danger'\"\n />\n </td>\n @for (col of extraColumns(); track col.key) {\n <td [class]=\"col.styleClass ?? ''\">\n @if (col.template) {\n <ng-container\n [ngTemplateOutlet]=\"col.template\"\n [ngTemplateOutletContext]=\"{ $implicit: user }\"\n />\n } @else if (col.field) {\n {{ getFieldValue(user, col.field) ?? '-' }}\n }\n </td>\n }\n <td>\n <div class=\"flex gap-1 flex-wrap\">\n @if (hasUserDetailView()) {\n <button\n fButton\n [rounded]=\"true\"\n [text]=\"true\"\n severity=\"info\"\n [fTooltip]=\"'shared.view.details' | translate\"\n (click)=\"onViewDetails(user)\"\n >\n <ui-icon pButtonIcon name=\"eye\"></ui-icon>\n </button>\n }\n <button\n fButton\n *hasPermission=\"USER_PERMISSIONS.UPDATE\"\n [rounded]=\"true\"\n [text]=\"true\"\n severity=\"info\"\n [fTooltip]=\"'shared.edit' | translate\"\n (click)=\"onEdit(user)\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n </button>\n @if (companyFeatureEnabled()) {\n <button\n fButton\n *hasPermission=\"USER_PERMISSIONS.UPDATE\"\n [rounded]=\"true\"\n [text]=\"true\"\n severity=\"secondary\"\n [fTooltip]=\"\n 'administrative.permission.company.permissions'\n | translate\n \"\n (click)=\"onManageCompanyPermissions(user)\"\n >\n <ui-icon pButtonIcon name=\"building\"></ui-icon>\n </button>\n <button\n fButton\n *hasPermission=\"USER_PERMISSIONS.UPDATE\"\n [rounded]=\"true\"\n [text]=\"true\"\n severity=\"secondary\"\n [fTooltip]=\"\n 'administrative.permission.branch.permissions'\n | translate\n \"\n (click)=\"onManageBranchPermissions(user)\"\n >\n <ui-icon pButtonIcon name=\"sitemap\"></ui-icon>\n </button>\n }\n @for (action of extraActions(); track action.key) {\n @if (isActionVisible(action, user)) {\n <button\n fButton\n [rounded]=\"true\"\n [text]=\"true\"\n [severity]=\"action.severity ?? 'secondary'\"\n [fTooltip]=\"\n action.labelKey | translate: null : action.label\n \"\n [disabled]=\"isActionDisabled(action, user)\"\n (click)=\"onExtraAction(action, user)\"\n >\n <ui-icon pButtonIcon [name]=\"action.icon\"></ui-icon>\n </button>\n }\n }\n <button\n fButton\n *hasPermission=\"USER_PERMISSIONS.DELETE\"\n [rounded]=\"true\"\n [text]=\"true\"\n severity=\"danger\"\n [fTooltip]=\"'shared.delete' | translate\"\n (click)=\"onDelete(user)\"\n >\n <ui-icon pButtonIcon name=\"trash\"></ui-icon>\n </button>\n </div>\n </td>\n </tr>\n </ng-template>\n <ng-template #emptymessage>\n <tr>\n <td [attr.colspan]=\"tableColspan()\" class=\"text-center py-8\">\n {{ 'administrative.user.no.users' | translate }}\n </td>\n </tr>\n </ng-template>\n </f-table>\n </div>\n </f-card>\n\n @if (companyFeatureEnabled()) {\n <lib-user-company-permission-dialog\n [visible]=\"showCompanyDialog()\"\n [user]=\"selectedUser()\"\n (closed)=\"showCompanyDialog.set(false)\"\n (permissionsChanged)=\"loadUsers()\"\n />\n\n <lib-user-branch-permission-dialog\n [visible]=\"showBranchDialog()\"\n [user]=\"selectedUser()\"\n (closed)=\"showBranchDialog.set(false)\"\n (permissionsChanged)=\"loadUsers()\"\n />\n }\n\n @if (hasUserDetailView() && showUserDetailDialog()) {\n <f-dialog\n [header]=\"'administrative.user.details' | translate\"\n [visible]=\"showUserDetailDialog()\"\n [modal]=\"true\"\n [style]=\"{ width: userDetailConfig?.width ?? '600px' }\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n (onHide)=\"closeUserDetailDialog()\"\n >\n @if (selectedUser(); as user) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div class=\"flex flex-col gap-2\">\n <label class=\"font-medium text-muted-color\">{{\n 'administrative.user.name' | translate\n }}</label>\n <span class=\"text-color\">{{ user.name }}</span>\n </div>\n <div class=\"flex flex-col gap-2\">\n <label class=\"font-medium text-muted-color\">{{\n 'administrative.email.label' | translate\n }}</label>\n <span class=\"text-color\">{{ user.email }}</span>\n </div>\n <div class=\"flex flex-col gap-2\">\n <label class=\"font-medium text-muted-color\">{{\n 'administrative.phone.label' | translate\n }}</label>\n <span class=\"text-color\">{{ user.phone || '-' }}</span>\n </div>\n <div class=\"flex flex-col gap-2\">\n <label class=\"font-medium text-muted-color\">{{\n 'shared.status' | translate\n }}</label>\n <f-tag\n [value]=\"\n user.isActive\n ? ('shared.active' | translate)\n : ('shared.inactive' | translate)\n \"\n [severity]=\"user.isActive ? 'success' : 'danger'\"\n />\n </div>\n <div class=\"flex flex-col gap-2\">\n <label class=\"font-medium text-muted-color\">{{\n 'administrative.user.email.verified' | translate\n }}</label>\n <f-tag\n [value]=\"\n user.emailVerified\n ? ('shared.verified' | translate)\n : ('shared.unverified' | translate)\n \"\n [severity]=\"user.emailVerified ? 'success' : 'warn'\"\n />\n </div>\n @for (col of extraColumns(); track col.key) {\n <div class=\"flex flex-col gap-2\">\n <label class=\"font-medium text-muted-color\">{{\n col.headerKey | translate: null : col.header\n }}</label>\n <span class=\"text-color\">{{\n getFieldValue(user, col.field ?? col.key) ?? '-'\n }}</span>\n </div>\n }\n </div>\n <div class=\"flex justify-end gap-2 mt-6\">\n @if (userDetailConfig?.allowEdit) {\n <button\n fButton\n (click)=\"onEdit(user); closeUserDetailDialog()\"\n >\n <ui-icon pButtonIcon name=\"pencil\"></ui-icon>\n <span pButtonLabel>{{ 'shared.edit' | translate }}</span>\n </button>\n }\n <button\n fButton\n severity=\"secondary\"\n [outlined]=\"true\"\n (click)=\"closeUserDetailDialog()\"\n >\n <span pButtonLabel>{{ 'shared.close' | translate }}</span>\n </button>\n </div>\n }\n </f-dialog>\n }\n `,\n})\nexport class UserListComponent {\n readonly USER_PERMISSIONS = USER_PERMISSIONS;\n\n private readonly router = inject(Router);\n private readonly appConfig = inject(APP_CONFIG);\n private readonly messageService = inject(MessageService);\n private readonly confirmationService = inject(ConfirmationService);\n private readonly userService = inject(UserApiService);\n\n private readonly userListExtension = inject(AUTH_USER_LIST_EXTENSION, {\n optional: true,\n });\n readonly userDetailConfig = inject(AUTH_USER_DETAIL_CONFIG, {\n optional: true,\n });\n private readonly translateAdapter = inject(TranslateService, {\n optional: true,\n });\n\n private translate(\n key: string,\n vars?: Record<string, string | number>,\n ): string {\n return this.translateAdapter?.translate(key, vars) ?? key;\n }\n\n readonly users = this.userService.data;\n readonly isLoading = this.userService.isLoading;\n readonly total = this.userService.total;\n readonly companyFeatureEnabled = computed(() =>\n isCompanyFeatureEnabled(this.appConfig),\n );\n\n readonly extraColumns = computed<IUserListExtraColumn[]>(() => {\n if (!this.userListExtension) return [];\n return sortByOrder(this.userListExtension.getExtraColumns());\n });\n\n readonly extraActions = computed<IUserListExtraAction[]>(() => {\n if (!this.userListExtension) return [];\n return sortByOrder(this.userListExtension.getExtraActions());\n });\n\n readonly hasUserDetailView = computed(() => !!this.userDetailConfig);\n readonly tableColspan = computed(() => 6 + this.extraColumns().length);\n\n readonly showCompanyDialog = signal(false);\n readonly showBranchDialog = signal(false);\n readonly showUserDetailDialog = signal(false);\n readonly selectedUser = signal<IUser | null>(null);\n\n private readonly _searchTerm = signal('');\n readonly searchTerm = this._searchTerm.asReadonly();\n\n getFieldValue(user: IUser, field: string): unknown {\n const parts = field.split('.');\n let value: unknown = user;\n for (const part of parts) {\n if (value === null || value === undefined) return undefined;\n value = (value as Record<string, unknown>)[part];\n }\n return value;\n }\n\n isActionVisible(action: IUserListExtraAction, user: IUser): boolean {\n return action.isVisible ? action.isVisible(user) : true;\n }\n\n isActionDisabled(action: IUserListExtraAction, user: IUser): boolean {\n return action.isDisabled ? action.isDisabled(user) : false;\n }\n\n onExtraAction(action: IUserListExtraAction, user: IUser): void {\n action.onClick(user);\n }\n\n onViewDetails(user: IUser): void {\n if (!this.userDetailConfig) return;\n\n if (this.userDetailConfig.viewMode === 'page') {\n this.router.navigate(['/administration/users', user.id]);\n } else {\n this.selectedUser.set(user);\n this.showUserDetailDialog.set(true);\n }\n }\n\n closeUserDetailDialog(): void {\n this.showUserDetailDialog.set(false);\n this.selectedUser.set(null);\n }\n\n loadUsers(page = 0, pageSize = 10): void {\n this.userService.fetchList(this._searchTerm(), {\n pagination: { currentPage: page, pageSize },\n });\n }\n\n onLazyLoad(event: { first?: number | null; rows?: number | null }): void {\n const first = event.first ?? 0;\n const rows = event.rows ?? 10;\n const page = Math.floor(first / rows);\n this.loadUsers(page, rows);\n }\n\n onSearchChange(value: string): void {\n this._searchTerm.set(value);\n this.loadUsers(0);\n }\n\n onCreate(): void {\n this.router.navigate(['/administration/users/new']);\n }\n\n onEdit(user: IUser): void {\n this.router.navigate(['/administration/users', user.id]);\n }\n\n onManageCompanyPermissions(user: IUser): void {\n this.openPermissionDialog(user, this.showCompanyDialog);\n }\n\n onManageBranchPermissions(user: IUser): void {\n this.openPermissionDialog(user, this.showBranchDialog);\n }\n\n private openPermissionDialog(\n user: IUser,\n dialogSignal: typeof this.showCompanyDialog,\n ): void {\n this.selectedUser.set(user);\n dialogSignal.set(true);\n }\n\n onDelete(user: IUser): void {\n this.confirmationService.confirm({\n message: this.translate('shared.confirm.delete.item', {\n name: user.name,\n }),\n header: this.translate('administrative.user.delete.title'),\n icon: 'exclamation-triangle',\n acceptButtonStyleClass: 'p-button-danger',\n accept: async () => {\n try {\n const response = await this.userService.delete({\n id: user.id,\n type: 'delete',\n });\n this.messageService.add({\n severity: 'success',\n summary: this.translate('shared.success'),\n detail: response.messageKey\n ? this.translate(\n response.messageKey,\n response.messageVariables as Record<string, string | number>,\n )\n : response.message,\n });\n this.userService.reload();\n } catch {}\n },\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"flusys-ng-auth-user-list.component-BNYmRTlN.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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"}