Merge branch 'RED-10183' into 'master'
RED-10183: use the user preferred language + component refactoring. See merge request redactmanager/red-ui!610
This commit is contained in:
commit
9836c2aab5
@ -20,6 +20,7 @@
|
|||||||
<label [translate]="'top-bar.navigation-items.my-account.children.language.label'"></label>
|
<label [translate]="'top-bar.navigation-items.my-account.children.language.label'"></label>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
<mat-select formControlName="language">
|
<mat-select formControlName="language">
|
||||||
|
<mat-select-trigger>{{ languageSelectLabel() | translate }}</mat-select-trigger>
|
||||||
<mat-option *ngFor="let language of languages" [value]="language">
|
<mat-option *ngFor="let language of languages" [value]="language">
|
||||||
{{ translations[language] | translate }}
|
{{ translations[language] | translate }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
@ -41,7 +42,7 @@
|
|||||||
|
|
||||||
<div class="dialog-actions">
|
<div class="dialog-actions">
|
||||||
<iqser-icon-button
|
<iqser-icon-button
|
||||||
[disabled]="form.invalid || !(profileChanged || languageChanged || themeChanged)"
|
[disabled]="disabled"
|
||||||
[label]="'user-profile-screen.actions.save' | translate"
|
[label]="'user-profile-screen.actions.save' | translate"
|
||||||
[submit]="true"
|
[submit]="true"
|
||||||
[type]="iconButtonTypes.primary"
|
[type]="iconButtonTypes.primary"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed } from '@angular/core';
|
||||||
import { ReactiveFormsModule, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
import { FormGroup, ReactiveFormsModule, UntypedFormBuilder, Validators } from '@angular/forms';
|
||||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||||
import {
|
import {
|
||||||
BaseFormComponent,
|
BaseFormComponent,
|
||||||
@ -19,22 +19,49 @@ import { firstValueFrom } from 'rxjs';
|
|||||||
import { UserProfileDialogService } from '../services/user-profile-dialog.service';
|
import { UserProfileDialogService } from '../services/user-profile-dialog.service';
|
||||||
import { NgForOf, NgIf } from '@angular/common';
|
import { NgForOf, NgIf } from '@angular/common';
|
||||||
import { MatFormField } from '@angular/material/form-field';
|
import { MatFormField } from '@angular/material/form-field';
|
||||||
import { MatOption, MatSelect } from '@angular/material/select';
|
import { MatOption, MatSelect, MatSelectTrigger } from '@angular/material/select';
|
||||||
import { MatSlideToggle } from '@angular/material/slide-toggle';
|
import { MatSlideToggle } from '@angular/material/slide-toggle';
|
||||||
import { PdfViewer } from '../../../../pdf-viewer/services/pdf-viewer.service';
|
import { PdfViewer } from '../../../../pdf-viewer/services/pdf-viewer.service';
|
||||||
|
import { formControlToSignal } from '@utils/functions';
|
||||||
|
import { AsControl } from '@common-ui/utils';
|
||||||
|
|
||||||
|
interface UserProfileForm {
|
||||||
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
language: string;
|
||||||
|
darkTheme: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './user-profile-screen.component.html',
|
templateUrl: './user-profile-screen.component.html',
|
||||||
styleUrls: ['./user-profile-screen.component.scss'],
|
styleUrls: ['./user-profile-screen.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [ReactiveFormsModule, NgIf, MatFormField, MatSelect, MatOption, NgForOf, TranslateModule, MatSlideToggle, IconButtonComponent],
|
imports: [
|
||||||
|
ReactiveFormsModule,
|
||||||
|
NgIf,
|
||||||
|
MatFormField,
|
||||||
|
MatSelect,
|
||||||
|
MatOption,
|
||||||
|
NgForOf,
|
||||||
|
TranslateModule,
|
||||||
|
MatSlideToggle,
|
||||||
|
IconButtonComponent,
|
||||||
|
MatSelectTrigger,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class UserProfileScreenComponent extends BaseFormComponent implements OnInit {
|
export class UserProfileScreenComponent extends BaseFormComponent {
|
||||||
#profileModel: IProfile;
|
readonly form: FormGroup<AsControl<UserProfileForm>> = this.#getForm();
|
||||||
|
initialFormValue = this.form.getRawValue();
|
||||||
readonly translations = languagesTranslations;
|
readonly translations = languagesTranslations;
|
||||||
readonly devMode = this._userPreferenceService.isIqserDevMode;
|
readonly devMode = this._userPreferenceService.isIqserDevMode;
|
||||||
|
|
||||||
|
readonly profileKeys = ['email', 'firstName', 'lastName'];
|
||||||
|
readonly languages = this._translateService.langs;
|
||||||
|
readonly language = formControlToSignal<UserProfileForm['language']>(this.form.controls.language);
|
||||||
|
readonly languageSelectLabel = computed(() => this.translations[this.language()]);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _userService: UserService,
|
private readonly _userService: UserService,
|
||||||
private readonly _loadingService: LoadingService,
|
private readonly _loadingService: LoadingService,
|
||||||
@ -49,41 +76,26 @@ export class UserProfileScreenComponent extends BaseFormComponent implements OnI
|
|||||||
private readonly _pdfViewer: PdfViewer,
|
private readonly _pdfViewer: PdfViewer,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this._loadingService.start();
|
if (!this._permissionsService.has(Roles.updateMyProfile)) {
|
||||||
|
this.form.disable();
|
||||||
|
}
|
||||||
|
this._loadingService.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
get languageChanged(): boolean {
|
get languageChanged(): boolean {
|
||||||
return this.#profileModel['language'] !== this.form.get('language').value;
|
return this.initialFormValue['language'] !== this.form.controls.language.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get themeChanged(): boolean {
|
get themeChanged(): boolean {
|
||||||
return this.#profileModel['darkTheme'] !== this.form.get('darkTheme').value;
|
return this.initialFormValue['darkTheme'] !== this.form.controls.darkTheme.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get emailChanged(): boolean {
|
get emailChanged(): boolean {
|
||||||
return this.#profileModel['email'] !== this.form.get('email').value;
|
return this.initialFormValue['email'] !== this.form.controls.email.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get profileChanged(): boolean {
|
get profileChanged(): boolean {
|
||||||
const keys = Object.keys(this.form.getRawValue());
|
return this.profileKeys.some(key => this.initialFormValue[key] !== this.form.get(key).value);
|
||||||
keys.splice(keys.indexOf('language'), 1);
|
|
||||||
keys.splice(keys.indexOf('darkTheme'), 1);
|
|
||||||
|
|
||||||
for (const key of keys) {
|
|
||||||
if (this.#profileModel[key] !== this.form.get(key).value) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
get languages(): string[] {
|
|
||||||
return this._translateService.langs;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this._initializeForm();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async save(): Promise<void> {
|
async save(): Promise<void> {
|
||||||
@ -108,16 +120,17 @@ export class UserProfileScreenComponent extends BaseFormComponent implements OnI
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.languageChanged) {
|
if (this.languageChanged) {
|
||||||
await this._languageService.change(this.form.get('language').value);
|
await this._languageService.change(this.form.controls.language.value);
|
||||||
await this._pdfViewer.instance?.UI.setLanguage(this._languageService.currentLanguage);
|
await this._pdfViewer.instance?.UI.setLanguage(this._languageService.currentLanguage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.themeChanged) {
|
if (this.themeChanged) {
|
||||||
await this._userPreferenceService.saveTheme(this.form.get('darkTheme').value ? 'dark' : 'light');
|
await this._userPreferenceService.saveTheme(this.form.controls.darkTheme.value ? 'dark' : 'light');
|
||||||
}
|
}
|
||||||
|
|
||||||
this._initializeForm();
|
this.initialFormValue = this.form.getRawValue();
|
||||||
|
this._changeRef.markForCheck();
|
||||||
|
this._loadingService.stop();
|
||||||
this._toaster.success(_('user-profile-screen.update.success'));
|
this._toaster.success(_('user-profile-screen.update.success'));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._loadingService.stop();
|
this._loadingService.stop();
|
||||||
@ -128,35 +141,13 @@ export class UserProfileScreenComponent extends BaseFormComponent implements OnI
|
|||||||
await this._userService.createResetPasswordAction();
|
await this._userService.createResetPasswordAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getForm(): UntypedFormGroup {
|
#getForm() {
|
||||||
return this._formBuilder.group({
|
return this._formBuilder.group({
|
||||||
email: ['', [Validators.required, Validators.email]],
|
email: [this._userService.currentUser.email ?? '', [Validators.required, Validators.email]],
|
||||||
firstName: [''],
|
firstName: [this._userService.currentUser.firstName ?? ''],
|
||||||
lastName: [''],
|
lastName: [this._userService.currentUser.lastName ?? ''],
|
||||||
language: [''],
|
language: [this._userPreferenceService.getLanguage()],
|
||||||
darkTheme: [false],
|
darkTheme: [this._userPreferenceService.getTheme() === 'dark'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _initializeForm(): void {
|
|
||||||
try {
|
|
||||||
this.form = this._getForm();
|
|
||||||
if (!this._permissionsService.has(Roles.updateMyProfile)) {
|
|
||||||
this.form.disable();
|
|
||||||
}
|
|
||||||
this.#profileModel = {
|
|
||||||
email: this._userService.currentUser.email ?? '',
|
|
||||||
firstName: this._userService.currentUser.firstName ?? '',
|
|
||||||
lastName: this._userService.currentUser.lastName ?? '',
|
|
||||||
language: this._languageService.currentLanguage ?? '',
|
|
||||||
darkTheme: this._userPreferenceService.getTheme() === 'dark',
|
|
||||||
};
|
|
||||||
this.form.patchValue(this.#profileModel, { emitEvent: false });
|
|
||||||
this.initialFormValue = this.form.getRawValue();
|
|
||||||
} catch (e) {
|
|
||||||
} finally {
|
|
||||||
this._loadingService.stop();
|
|
||||||
this._changeRef.markForCheck();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@ import { ITrackable } from '@iqser/common-ui';
|
|||||||
import type { List } from '@iqser/common-ui/lib/utils';
|
import type { List } from '@iqser/common-ui/lib/utils';
|
||||||
import type { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
import type { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||||
import { Dayjs } from 'dayjs';
|
import { Dayjs } from 'dayjs';
|
||||||
|
import { FormControl } from '@angular/forms';
|
||||||
|
import { toSignal } from '@angular/core/rxjs-interop';
|
||||||
|
|
||||||
export function hexToRgb(hex: string) {
|
export function hexToRgb(hex: string) {
|
||||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||||
@ -143,3 +145,7 @@ export function urlFileId() {
|
|||||||
const fileId = splitUrl[splitUrl.length - 1];
|
const fileId = splitUrl[splitUrl.length - 1];
|
||||||
return fileId.split('?')[0];
|
return fileId.split('?')[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formControlToSignal<T>(control: FormControl<T>) {
|
||||||
|
return toSignal(control.valueChanges, { initialValue: control.value });
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { inject } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
import { Router, RouterStateSnapshot } from '@angular/router';
|
import { Router, RouterStateSnapshot } from '@angular/router';
|
||||||
import { AsyncGuard, IqserPermissionsService, LoadingService } from '@iqser/common-ui';
|
import { AsyncGuard, IqserPermissionsService, LanguageService, LoadingService } from '@iqser/common-ui';
|
||||||
import { TenantsService } from '@iqser/common-ui/lib/tenants';
|
import { TenantsService } from '@iqser/common-ui/lib/tenants';
|
||||||
import { ConfigService } from '@services/config.service';
|
import { ConfigService } from '@services/config.service';
|
||||||
import { DossiersChangesService } from '@services/dossiers/dossier-changes.service';
|
import { DossiersChangesService } from '@services/dossiers/dossier-changes.service';
|
||||||
@ -38,6 +38,7 @@ export function mainGuard(): AsyncGuard {
|
|||||||
const tenantsService = inject(TenantsService);
|
const tenantsService = inject(TenantsService);
|
||||||
const loadingService = inject(LoadingService);
|
const loadingService = inject(LoadingService);
|
||||||
const configService = inject(ConfigService);
|
const configService = inject(ConfigService);
|
||||||
|
const languageService = inject(LanguageService);
|
||||||
const baseHref = inject(APP_BASE_HREF);
|
const baseHref = inject(APP_BASE_HREF);
|
||||||
|
|
||||||
const generalConfig$ = inject(GeneralSettingsService).getGeneralConfigurations();
|
const generalConfig$ = inject(GeneralSettingsService).getGeneralConfigurations();
|
||||||
@ -51,6 +52,7 @@ export function mainGuard(): AsyncGuard {
|
|||||||
firstValueFrom(updatedDisplayName$),
|
firstValueFrom(updatedDisplayName$),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
await languageService.setInitialLanguage();
|
||||||
const lastDossierTemplate = userPreferenceService.getLastDossierTemplate();
|
const lastDossierTemplate = userPreferenceService.getLastDossierTemplate();
|
||||||
|
|
||||||
if (lastDossierTemplate && !isUsersAdminOnly) {
|
if (lastDossierTemplate && !isUsersAdminOnly) {
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
Subproject commit 3c89b8f7e71eb9253aa40f40c1598eac2c400c71
|
Subproject commit 32de7758599d887c4b574d70a11b4e0382f30f0c
|
||||||
Loading…
x
Reference in New Issue
Block a user