Add notification messages on click save of user profile

This commit is contained in:
apapachristou 2020-11-17 19:57:39 +02:00
parent af849b6c36
commit 644d616ef8
3 changed files with 94 additions and 21 deletions

View File

@ -20,14 +20,14 @@
<div class="row mb-5"> <div class="row mb-5">
<div class="col"> <div class="col">
<div class="row"> <div class="row">
<div class="col-auto field-title">{{'USER-PROFILE.SETTINGS.NAME' | translate}}</div> <div class="col-auto field-title">{{'USER-PROFILE.SETTINGS.NAME' | translate}} *</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col name-form"> <div class="col name-form">
<mat-form-field> <mat-form-field>
<input matInput type="text" name="name" [formControl]="formGroup.get('name')" required> <input matInput type="text" name="name" placeholder="{{'USER-PROFILE.SETTINGS.NAME' | translate}}" [formControl]="formGroup.get('name')" required>
<!-- <mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{formGroup.get('label').getError('backendError').message}}</mat-error> <!-- <mat-error *ngIf="formGroup.get('name').hasError('backendError')">{{formGroup.get('name').getError('backendError').message}}</mat-error> -->
<mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> --> <mat-error *ngIf="formGroup.get('name').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
@ -124,7 +124,7 @@
<div class="row mb-5"> <div class="row mb-5">
<div class="col"> <div class="col">
<div class="row"> <div class="row">
<div class="col-auto field-title">{{'USER-PROFILE.SETTINGS.TIMEZONE' | translate}}</div> <div class="col-auto field-title">{{'USER-PROFILE.SETTINGS.TIMEZONE' | translate}} *</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col timezone-form"> <div class="col timezone-form">
@ -135,6 +135,7 @@
{{ timezone | timezoneInfoDisplay }} {{ timezone | timezoneInfoDisplay }}
</mat-option> </mat-option>
</mat-autocomplete> </mat-autocomplete>
<mat-error *ngIf="this.formGroup.get('timezone').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
@ -144,7 +145,7 @@
<div class="row mb-5"> <div class="row mb-5">
<div class="col"> <div class="col">
<div class="row"> <div class="row">
<div class="col-auto field-title">{{'USER-PROFILE.SETTINGS.CULTURE' | translate}}</div> <div class="col-auto field-title">{{'USER-PROFILE.SETTINGS.CULTURE' | translate}} *</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col culture-form"> <div class="col culture-form">
@ -155,6 +156,7 @@
{{ culture.displayName }} - {{ culture.nativeName }} {{ culture.displayName }} - {{ culture.nativeName }}
</mat-option> </mat-option>
</mat-autocomplete> </mat-autocomplete>
<mat-error *ngIf="this.formGroup.get('culture').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
@ -164,7 +166,7 @@
<div class="row mb-5"> <div class="row mb-5">
<div class="col"> <div class="col">
<div class="row"> <div class="row">
<div class="col-auto field-title">{{'USER-PROFILE.SETTINGS.LANGUAGE' | translate}}</div> <div class="col-auto field-title">{{'USER-PROFILE.SETTINGS.LANGUAGE' | translate}} *</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col language-form"> <div class="col language-form">
@ -174,6 +176,7 @@
{{ language.label | translate }} {{ language.label | translate }}
</mat-option> </mat-option>
</mat-select> </mat-select>
<mat-error *ngIf="this.formGroup.get('language').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Params, Router } from '@angular/router'; import { ActivatedRoute, Params, Router } from '@angular/router';
import { CultureInfo } from '@app/core/model/culture-info'; import { CultureInfo } from '@app/core/model/culture-info';
import { DmpModel } from '@app/core/model/dmp/dmp'; import { DmpModel } from '@app/core/model/dmp/dmp';
@ -27,6 +27,8 @@ import { MatDialog } from '@angular/material';
import { UserCredentialModel } from '@app/core/model/user/user-credential'; import { UserCredentialModel } from '@app/core/model/user/user-credential';
import { AuthProvider } from '@app/core/common/enum/auth-provider'; import { AuthProvider } from '@app/core/common/enum/auth-provider';
import { MergeEmailConfirmationService } from '@app/core/services/merge-email-confirmation/merge-email-confirmation.service'; import { MergeEmailConfirmationService } from '@app/core/services/merge-email-confirmation/merge-email-confirmation.service';
import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component';
import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service';
const availableLanguages: any[] = require('../../../assets/resources/language.json'); const availableLanguages: any[] = require('../../../assets/resources/language.json');
@ -50,6 +52,9 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
roleOrganizationEnum = RoleOrganizationType; roleOrganizationEnum = RoleOrganizationType;
authProviderEnum = AuthProvider; authProviderEnum = AuthProvider;
private oauthLock: boolean; private oauthLock: boolean;
errorMessages = [];
nestedCount = [];
nestedIndex = 0;
organisationsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { organisationsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = {
filterFn: this.filterOrganisations.bind(this), filterFn: this.filterOrganisations.bind(this),
@ -72,6 +77,7 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
private languageService: LanguageService, private languageService: LanguageService,
private configurationService: ConfigurationService, private configurationService: ConfigurationService,
private oauth2DialogService: Oauth2DialogService, private oauth2DialogService: Oauth2DialogService,
private uiNotificationService: UiNotificationService,
private dialog: MatDialog, private dialog: MatDialog,
public enumUtils: EnumUtils, public enumUtils: EnumUtils,
private mergeEmailConfirmation: MergeEmailConfirmationService private mergeEmailConfirmation: MergeEmailConfirmationService
@ -98,20 +104,20 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
//this.formGroup.get('language').valueChanges.pipe(takeUntil(this._destroyed)).subscribe(x => { if (x) this.translate.use(x.value) }) //this.formGroup.get('language').valueChanges.pipe(takeUntil(this._destroyed)).subscribe(x => { if (x) this.translate.use(x.value) })
this.formGroup.get('timezone').valueChanges this.formGroup.get('timezone').valueChanges
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(x => { if (x) { this.timezones = this._filterTimezone(x); } }); .subscribe(x => { if (x) { this.timezones = this._filterTimezone(x); } });
this.formGroup.get('culture').valueChanges this.formGroup.get('culture').valueChanges
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(x => { if (x) { this.cultures = this._filterCulture(x); } }); .subscribe(x => { if (x) { this.cultures = this._filterCulture(x); } });
// this.initializeDisabledFormGroup(); // this.initializeDisabledFormGroup();
this.unlock(); this.unlock();
return result; return result;
})); }));
this.userService.getEmails(userId).pipe(takeUntil(this._destroyed)) this.userService.getEmails(userId).pipe(takeUntil(this._destroyed))
.subscribe(result => { .subscribe(result => {
this.userCredentials = result; this.userCredentials = result;
}); });
}); });
} }
@ -166,7 +172,14 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
} }
save() { save() {
if (!this.formGroup.valid) { return; } if (!this.formGroup.valid) {
this.printErrors(this.formGroup);
this.showValidationErrorsDialog();
this.nestedCount = [];
this.nestedIndex = 0;
this.errorMessages = [];
return;
}
this.userService.updateUserSettings(this.formGroup.value) this.userService.updateUserSettings(this.formGroup.value)
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe( .subscribe(
@ -176,7 +189,10 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
this.authService.current().culture = this.formGroup.value.culture.name; this.authService.current().culture = this.formGroup.value.culture.name;
this.authService.me() this.authService.me()
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(result => this.router.navigate(['/profile'])); .subscribe(result => {
this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
this.router.navigate(['/profile']);
});
// .subscribe(result => window.location.reload()); // .subscribe(result => window.location.reload());
}, },
error => { error => {
@ -213,6 +229,18 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
}); });
} }
private showValidationErrorsDialog(projectOnly?: boolean) {
const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, {
disableClose: true,
autoFocus: false,
restoreFocus: false,
data: {
errorMessages: this.errorMessages,
projectOnly: projectOnly
},
});
}
public applyFallbackAvatar(ev: Event) { public applyFallbackAvatar(ev: Event) {
(ev.target as HTMLImageElement).src = 'assets/images/profile-placeholder.png'; (ev.target as HTMLImageElement).src = 'assets/images/profile-placeholder.png';
} }
@ -253,8 +281,8 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
public RemoveZenodo() { public RemoveZenodo() {
this.userService.deleteDOIToken() this.userService.deleteDOIToken()
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(() => this.router.navigate(['/reload']).then(() => this.router.navigate(['/profile']))); .subscribe(() => this.router.navigate(['/reload']).then(() => this.router.navigate(['/profile'])));
} }
public removeAccount() { public removeAccount() {
@ -272,9 +300,49 @@ export class UserProfileComponent extends BaseComponent implements OnInit, OnDes
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
if (result) { if (result) {
this.mergeEmailConfirmation.sendConfirmationEmail(result).pipe(takeUntil(this._destroyed)) this.mergeEmailConfirmation.sendConfirmationEmail(result).pipe(takeUntil(this._destroyed))
.subscribe(res => {}, err => {}); .subscribe(res => { }, err => { });
} }
}); });
} }
printErrors(rootform: FormGroup) {
if (!rootform.valid) {
Object.keys(rootform.controls).forEach(key => {
const errors = rootform.get(key).errors;
if (errors !== null) {
let numbering: string = '';
for (let j = 0; j < this.nestedCount.length; j++) {
numbering += this.nestedCount[j];
if (j < this.nestedIndex) {
numbering += '.';
} else {
break;
}
}
Object.keys(errors).forEach(keyError => {
if (typeof errors[keyError] === 'boolean') {
this.errorMessages.push(numbering + ' ' + key + ' is ' + keyError);
} else {
this.errorMessages.push(numbering + ' ' + key + ': ' + keyError + ': ' + JSON.stringify(errors[keyError]));
}
});
} else {
if (rootform.get(key) instanceof FormGroup) {
this.printErrors(<FormGroup>rootform.get(key));
} else if (rootform.get(key) instanceof FormArray) {
this.nestedIndex++;
this.nestedCount[this.nestedIndex] = 0;
for (let childForm of (<FormArray>rootform.get(key)).controls) {
this.nestedCount[this.nestedIndex]++;
this.printErrors(<any>childForm);
}
this.nestedCount[this.nestedIndex] = 0;
this.nestedIndex--;
}
}
});
}
}
} }

View File

@ -2,6 +2,7 @@ import { NgModule } from '@angular/core';
import { FormattingModule } from '@app/core/formatting.module'; import { FormattingModule } from '@app/core/formatting.module';
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module';
import { CommonFormsModule } from '@common/forms/common-forms.module'; import { CommonFormsModule } from '@common/forms/common-forms.module';
import { FormValidationErrorsDialogModule } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.module';
import { CommonUiModule } from '@common/ui/common-ui.module'; import { CommonUiModule } from '@common/ui/common-ui.module';
import { LoginComponent } from '../auth/login/login.component'; import { LoginComponent } from '../auth/login/login.component';
import { LoginModule } from '../auth/login/login.module'; import { LoginModule } from '../auth/login/login.module';
@ -17,7 +18,8 @@ import { UserProfileRoutingModule } from './user-profile.routing';
FormattingModule, FormattingModule,
UserProfileRoutingModule, UserProfileRoutingModule,
AutoCompleteModule, AutoCompleteModule,
AddAccountDialogModule AddAccountDialogModule,
FormValidationErrorsDialogModule
], ],
declarations: [ declarations: [
UserProfileComponent UserProfileComponent