mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 04:07:31 +00:00
fix: user init mail (for wrong email) (#891)
* add resendInitialMail * disable email notifications (when not initialised) * fix resend init mail * add tests * cleanup * cleanup * fix tests * add resend trigger, dialog * refactor contact component, add sendinitmail fnc * skip email if empty * reload user on phone email changes, i18n warndialog on dl * lint * rebuild mgmt proto * remove initial focus * Update console/src/assets/i18n/de.json Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
padding: 1.5rem;
|
||||
border-radius: .5rem;
|
||||
padding-top: 1rem;
|
||||
min-width: 350px;
|
||||
|
||||
.header {
|
||||
margin-top: 0;
|
||||
|
@@ -11,6 +11,10 @@
|
||||
.action {
|
||||
display: flex;
|
||||
|
||||
button {
|
||||
border-radius: .5rem;
|
||||
}
|
||||
|
||||
.ok-button {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
|
@@ -40,10 +40,15 @@
|
||||
|
||||
<app-card *ngIf="user" title="{{ 'USER.LOGINMETHODS.TITLE' | translate }}"
|
||||
description="{{ 'USER.LOGINMETHODS.DESCRIPTION' | translate }}">
|
||||
<app-contact *ngIf="user?.human" [human]="user.human" (savedPhone)="savePhone($event)"
|
||||
(savedEmail)="saveEmail($event)" (enteredPhoneCode)="enteredPhoneCode($event)"
|
||||
(deletedPhone)="deletePhone()" (resendEmailVerification)="resendEmailVerification()"
|
||||
(resendPhoneVerification)="resendPhoneVerification()"></app-contact>
|
||||
<button card-actions mat-icon-button (click)="refreshUser()">
|
||||
<mat-icon>refresh</mat-icon>
|
||||
</button>
|
||||
<app-contact *ngIf="user?.human" [human]="user.human" [state]="user.state" canWrite="true"
|
||||
[userStateEnum]="UserState" (editType)="openEditDialog($event)"
|
||||
(enteredPhoneCode)="enteredPhoneCode($event)" (deletedPhone)="deletePhone()"
|
||||
(resendEmailVerification)="resendEmailVerification()"
|
||||
(resendPhoneVerification)="resendPhoneVerification()">
|
||||
</app-contact>
|
||||
</app-card>
|
||||
|
||||
<app-auth-user-mfa *ngIf="user" #mfaComponent></app-auth-user-mfa>
|
||||
|
@@ -98,3 +98,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.resendemail {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
@@ -1,12 +1,24 @@
|
||||
import { Component, OnDestroy } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||
import { UserGrantContext } from 'src/app/modules/user-grants/user-grants-datasource';
|
||||
import { Gender, UserAddress, UserEmail, UserPhone, UserProfile, UserView } from 'src/app/proto/generated/auth_pb';
|
||||
import {
|
||||
Gender,
|
||||
UserAddress,
|
||||
UserEmail,
|
||||
UserPhone,
|
||||
UserProfile,
|
||||
UserState,
|
||||
UserView,
|
||||
} from 'src/app/proto/generated/auth_pb';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { EditDialogType } from '../user-detail/user-detail.component';
|
||||
import { EditDialogComponent } from './edit-dialog/edit-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-auth-user-detail',
|
||||
templateUrl: './auth-user-detail.component.html',
|
||||
@@ -26,6 +38,7 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
|
||||
public ChangeType: any = ChangeType;
|
||||
public userLoginMustBeDomain: boolean = false;
|
||||
public UserState: any = UserState;
|
||||
|
||||
public USERGRANTCONTEXT: UserGrantContext = UserGrantContext.USER;
|
||||
|
||||
@@ -33,8 +46,13 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
public translate: TranslateService,
|
||||
private toast: ToastService,
|
||||
public userService: GrpcAuthService,
|
||||
private dialog: MatDialog,
|
||||
) {
|
||||
this.loading = true;
|
||||
this.refreshUser();
|
||||
}
|
||||
|
||||
refreshUser(): void {
|
||||
this.userService.GetMyUser().then(user => {
|
||||
this.user = user.toObject();
|
||||
this.loading = false;
|
||||
@@ -81,6 +99,7 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
this.toast.showInfo('USER.TOAST.EMAILSAVED', true);
|
||||
if (this.user.human) {
|
||||
this.user.human.email = data.toObject().email;
|
||||
this.refreshUser();
|
||||
}
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
@@ -90,6 +109,7 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
public enteredPhoneCode(code: string): void {
|
||||
this.userService.VerifyMyUserPhone(code).then(() => {
|
||||
this.toast.showInfo('USER.TOAST.PHONESAVED', true);
|
||||
this.refreshUser();
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
@@ -99,14 +119,6 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
this.translate.use(language);
|
||||
}
|
||||
|
||||
public resendEmailVerification(): void {
|
||||
this.userService.ResendEmailVerification().then(() => {
|
||||
this.toast.showInfo('USER.TOAST.EMAILSAVED', true);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
public resendPhoneVerification(): void {
|
||||
this.userService.ResendPhoneVerification().then(() => {
|
||||
this.toast.showInfo('USER.TOAST.PHONEVERIFICATIONSENT', true);
|
||||
@@ -115,11 +127,20 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
public resendEmailVerification(): void {
|
||||
this.userService.ResendMyEmailVerificationMail().then(() => {
|
||||
this.toast.showInfo('USER.TOAST.EMAILVERIFICATIONSENT', true);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
||||
public deletePhone(): void {
|
||||
this.userService.RemoveMyUserPhone().then(() => {
|
||||
this.toast.showInfo('USER.TOAST.PHONEREMOVED', true);
|
||||
if (this.user.human) {
|
||||
this.user.human.phone = '';
|
||||
this.refreshUser();
|
||||
}
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
@@ -133,10 +154,54 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
this.toast.showInfo('USER.TOAST.PHONESAVED', true);
|
||||
if (this.user.human) {
|
||||
this.user.human.phone = data.toObject().phone;
|
||||
this.refreshUser();
|
||||
}
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public openEditDialog(type: EditDialogType): void {
|
||||
switch (type) {
|
||||
case EditDialogType.PHONE:
|
||||
const dialogRefPhone = this.dialog.open(EditDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.SAVE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
labelKey: 'ACTIONS.NEWVALUE',
|
||||
titleKey: 'USER.LOGINMETHODS.PHONE.EDITTITLE',
|
||||
descriptionKey: 'USER.LOGINMETHODS.PHONE.EDITDESC',
|
||||
value: this.user.human?.phone,
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRefPhone.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
this.savePhone(resp);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case EditDialogType.EMAIL:
|
||||
const dialogRefEmail = this.dialog.open(EditDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.SAVE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
labelKey: 'ACTIONS.NEWVALUE',
|
||||
titleKey: 'USER.LOGINMETHODS.EMAIL.EDITTITLE',
|
||||
descriptionKey: 'USER.LOGINMETHODS.EMAIL.EDITDESC',
|
||||
value: this.user.human?.email,
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRefEmail.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
this.saveEmail(resp);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,20 @@
|
||||
<h1 mat-dialog-title>
|
||||
<span class="title">{{data.titleKey | translate}}</span>
|
||||
</h1>
|
||||
<p class="desc">{{data.descriptionKey | translate}}</p>
|
||||
<div mat-dialog-content>
|
||||
<mat-form-field class="formfield">
|
||||
<mat-label>{{data.labelKey | translate }}</mat-label>
|
||||
<input matInput [(ngModel)]="value" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div mat-dialog-actions class="action">
|
||||
<button cdkFocusInitial color="primary" mat-button class="ok-button" (click)="closeDialog()">
|
||||
{{data.cancelKey | translate}}
|
||||
</button>
|
||||
|
||||
<button [disabled]="!value" cdkFocusInitial color="primary" mat-raised-button class="ok-button"
|
||||
(click)="closeDialogWithValue(value)">
|
||||
{{data.confirmKey | translate}}
|
||||
</button>
|
||||
</div>
|
@@ -0,0 +1,21 @@
|
||||
.formfield {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 14px;
|
||||
color: var(--grey);
|
||||
}
|
||||
|
||||
.action {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
.ok-button {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CodeDialogComponent } from './code-dialog.component';
|
||||
|
||||
describe('CodeDialogComponent', () => {
|
||||
let component: CodeDialogComponent;
|
||||
let fixture: ComponentFixture<CodeDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [CodeDialogComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CodeDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,23 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-email-dialog',
|
||||
templateUrl: './edit-dialog.component.html',
|
||||
styleUrls: ['./edit-dialog.component.scss'],
|
||||
})
|
||||
export class EditDialogComponent {
|
||||
public value: string = '';
|
||||
constructor(public dialogRef: MatDialogRef<EditDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any) {
|
||||
this.value = data.value;
|
||||
}
|
||||
|
||||
closeDialog(email: string = ''): void {
|
||||
this.dialogRef.close(email);
|
||||
}
|
||||
|
||||
closeDialogWithValue(value: string = ''): void {
|
||||
this.dialogRef.close(value);
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
<h1 mat-dialog-title>
|
||||
<span class="title">{{'USER.SENDEMAILDIALOG.TITLE' | translate}} {{data?.number}}</span>
|
||||
</h1>
|
||||
<p class="desc">{{'USER.SENDEMAILDIALOG.DESCRIPTION' | translate}}</p>
|
||||
<div mat-dialog-content>
|
||||
<mat-form-field class="formfield">
|
||||
<mat-label>{{ 'USER.SENDEMAILDIALOG.NEWEMAIL' | translate }}</mat-label>
|
||||
<input matInput [(ngModel)]="email" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div mat-dialog-actions class="action">
|
||||
<button color="primary" mat-button class="ok-button" (click)="closeDialog()">
|
||||
{{'ACTIONS.CLOSE' | translate}}
|
||||
</button>
|
||||
|
||||
<button cdkFocusInitial color="primary" mat-raised-button class="ok-button" (click)="closeDialogWithSend(email)">
|
||||
{{'ACTIONS.SEND' | translate}}
|
||||
</button>
|
||||
</div>
|
@@ -0,0 +1,21 @@
|
||||
.formfield {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 14px;
|
||||
color: var(--grey);
|
||||
}
|
||||
|
||||
.action {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
.ok-button {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CodeDialogComponent } from './code-dialog.component';
|
||||
|
||||
describe('CodeDialogComponent', () => {
|
||||
let component: CodeDialogComponent;
|
||||
let fixture: ComponentFixture<CodeDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [CodeDialogComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CodeDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,21 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'app-resend-email-dialog',
|
||||
templateUrl: './resend-email-dialog.component.html',
|
||||
styleUrls: ['./resend-email-dialog.component.scss'],
|
||||
})
|
||||
export class ResendEmailDialogComponent {
|
||||
public email: string = '';
|
||||
constructor(public dialogRef: MatDialogRef<ResendEmailDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any) { }
|
||||
|
||||
closeDialog(email: string = ''): void {
|
||||
this.dialogRef.close(email);
|
||||
}
|
||||
|
||||
closeDialogWithSend(email: string = ''): void {
|
||||
this.dialogRef.close({ send: true, email });
|
||||
}
|
||||
}
|
@@ -1,69 +1,55 @@
|
||||
<div class="method-col">
|
||||
<div class="method-row">
|
||||
<span class="label">{{ 'USER.PROFILE.PASSWORD' | translate }}</span>
|
||||
<div class="left">
|
||||
<span class="label">{{ 'USER.PROFILE.PASSWORD' | translate }}</span>
|
||||
<span class="name">*********</span>
|
||||
|
||||
<span>*********</span>
|
||||
<div class="overflow">
|
||||
<ng-content select="[phoneAction]"></ng-content>
|
||||
<a [disabled]="!canWrite" [routerLink]="['password']" mat-icon-button>
|
||||
<mat-icon class="icon">chevron_right</mat-icon>
|
||||
<ng-content select="[pwdAction]"></ng-content>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
<a matTooltip="{{'USER.PASSWORD.SET' | translate}}" [disabled]="!canWrite" [routerLink]="['password']"
|
||||
mat-icon-button>
|
||||
<i class="las la-edit"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="method-row">
|
||||
<span class="label">{{ 'USER.EMAIL' | translate }}</span>
|
||||
<div class="left">
|
||||
<span class="label">{{ 'USER.EMAIL' | translate }}</span>
|
||||
<span class="name">{{human?.email}}</span>
|
||||
<span *ngIf="human?.isEmailVerified" class="state verified">{{'USER.EMAILVERIFIED' | translate}}</span>
|
||||
<div *ngIf="!human?.isEmailVerified" class="block">
|
||||
<span class="state notverified">{{'USER.NOTVERIFIED' | translate}}</span>
|
||||
|
||||
<ng-container *ngIf="!emailEditState; else emailEdit">
|
||||
<div class="actions">
|
||||
<span class="name">{{human?.email}}</span>
|
||||
<mat-icon class="icon" *ngIf="human?.isEmailVerified" color="primary" aria-hidden="false"
|
||||
aria-label="verified icon">
|
||||
check_circle_outline</mat-icon>
|
||||
<ng-container *ngIf="human?.email && !human?.isEmailVerified">
|
||||
<mat-icon class="icon" color="warn" aria-hidden="false" aria-label="not verified icon">
|
||||
highlight_off
|
||||
</mat-icon>
|
||||
<a *ngIf="canWrite" class="verify" matTooltip="{{'USER.LOGINMETHODS.EMAIL.RESEND' | translate}}"
|
||||
<ng-container *ngIf="human?.email">
|
||||
<a *ngIf="canWrite && state != userStateEnum?.USERSTATE_INITIAL" class="verify"
|
||||
matTooltip="{{'USER.LOGINMETHODS.EMAIL.RESEND' | translate}}"
|
||||
(click)="emitEmailVerification()">{{'USER.LOGINMETHODS.RESENDCODE' | translate}}</a>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button [disabled]="!canWrite" (click)="emailEditState = true" mat-icon-button>
|
||||
<mat-icon class="icon">edit</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-template #emailEdit>
|
||||
<mat-form-field class="name">
|
||||
<mat-label>{{ 'USER.EMAIL' | translate }}</mat-label>
|
||||
<input *ngIf="human && human.email !== undefined && human.email !== null" matInput
|
||||
[(ngModel)]="human.email" />
|
||||
</mat-form-field>
|
||||
<button (click)="emailEditState = false" mat-icon-button>
|
||||
<mat-icon class="icon">close</mat-icon>
|
||||
<ng-content select="[emailAction]"></ng-content>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
<button [disabled]="!canWrite" (click)="openEditDialog(EditDialogType.EMAIL)" mat-icon-button>
|
||||
<i class="las la-edit"></i>
|
||||
</button>
|
||||
<button *ngIf="human" [disabled]="!human.email" type="button" color="primary" (click)="saveEmail()"
|
||||
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="method-row">
|
||||
<span class="label">{{ 'USER.PHONE' | translate }}</span>
|
||||
<div class="left">
|
||||
<span class="label">{{ 'USER.PHONE' | translate }}</span>
|
||||
<span class="name">{{human?.phone ? human.phone : ('USER.PHONEEMPTY' | translate)}}</span>
|
||||
<span *ngIf="human?.isPhoneVerified" class="state verified">{{'USER.PHONEVERIFIED' | translate}}</span>
|
||||
<div *ngIf="!human?.isPhoneVerified" class="block">
|
||||
<span class="state notverified">{{'USER.NOTVERIFIED' | translate}}</span>
|
||||
|
||||
<ng-container *ngIf="!phoneEditState; else phoneEdit">
|
||||
<div class="actions">
|
||||
<span class="name">{{human?.phone}}</span>
|
||||
<mat-icon class="icon" *ngIf="human?.isPhoneVerified" color="primary" aria-hidden="false"
|
||||
aria-label="verified icon">
|
||||
check_circle_outline</mat-icon>
|
||||
<ng-container *ngIf="human?.phone && !human?.isPhoneVerified">
|
||||
<mat-icon class="icon" matTooltip="not verified" color="warn" aria-hidden="false"
|
||||
aria-label="not verified icon">
|
||||
highlight_off
|
||||
</mat-icon>
|
||||
<a *ngIf="!disablePhoneCode && !canWrite" class="verify"
|
||||
<ng-container *ngIf="human?.phone">
|
||||
<a *ngIf="!disablePhoneCode && canWrite" class="verify"
|
||||
matTooltip="{{'USER.LOGINMETHODS.ENTERCODE_DESC' | translate}}"
|
||||
(click)="enterCode()">{{'USER.LOGINMETHODS.ENTERCODE' | translate}}</a>
|
||||
<a *ngIf="canWrite" class="verify" matTooltip="{{'USER.LOGINMETHODS.PHONE.RESEND' | translate}}"
|
||||
@@ -71,27 +57,18 @@
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button [disabled]="!canWrite" (click)="phoneEditState = true" mat-icon-button>
|
||||
<mat-icon class="icon">edit</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-content select="[phoneAction]"></ng-content>
|
||||
</div>
|
||||
|
||||
<ng-template #phoneEdit>
|
||||
<mat-form-field class="name">
|
||||
<mat-label>{{ 'USER.PHONE' | translate }}</mat-label>
|
||||
<input *ngIf="human && human.phone !== undefined && human.phone !== null" matInput
|
||||
[(ngModel)]="human.phone" />
|
||||
</mat-form-field>
|
||||
<button (click)="phoneEditState = false" mat-icon-button>
|
||||
<mat-icon class="icon">close</mat-icon>
|
||||
</button>
|
||||
<button *ngIf="human && human.phone" color="warn" (click)="emitDeletePhone()" mat-icon-button>
|
||||
<div class="right">
|
||||
<button matTooltip="{{'ACTIONS.DELETE' | translate}}" *ngIf="human && human.phone" color="warn"
|
||||
(click)="emitDeletePhone()" mat-icon-button>
|
||||
<i class="las la-trash"></i>
|
||||
</button>
|
||||
<button *ngIf="human" [disabled]="!human.phone" type="button" color="primary" (click)="savePhone()"
|
||||
mat-raised-button>{{ 'ACTIONS.SAVE' | translate }}</button>
|
||||
</ng-template>
|
||||
<button matTooltip="{{'ACTIONS.EDIT' | translate}}" [disabled]="!canWrite"
|
||||
(click)="openEditDialog(EditDialogType.PHONE)" mat-icon-button>
|
||||
<i class="las la-edit"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -5,29 +5,57 @@
|
||||
|
||||
.method-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: .5rem;
|
||||
border-bottom: 1px solid #ffffff20;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.actions {
|
||||
flex: 1;
|
||||
.left {
|
||||
.label {
|
||||
font-size: 13px;
|
||||
margin-bottom: .5rem;
|
||||
min-width: 100px;
|
||||
color: var(--grey);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.name {
|
||||
display: block;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
.state {
|
||||
font-size: 14px;
|
||||
margin-bottom: .5rem;
|
||||
|
||||
&.verified {
|
||||
color: #85d996;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&.notverified {
|
||||
color: #ff4436;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
flex-basis: 70px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: .9rem;
|
||||
max-width: 100px;
|
||||
color: var(--grey);
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin: .5rem;
|
||||
.verified-icon {
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.2rem;
|
||||
height: 1.2rem;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.verify {
|
||||
@@ -38,6 +66,7 @@
|
||||
cursor: pointer;
|
||||
word-wrap: none;
|
||||
white-space: nowrap;
|
||||
margin-right: 1rem;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
@@ -46,6 +75,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.overflow {
|
||||
overflow: auto;
|
||||
.mat-form-field-wrapper {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
@@ -1,46 +1,48 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { HumanView as AuthHumanView } from 'src/app/proto/generated/auth_pb';
|
||||
import { HumanView as MgmtHumanView } from 'src/app/proto/generated/management_pb';
|
||||
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
|
||||
import { HumanView as AuthHumanView, UserState as AuthUserState } from 'src/app/proto/generated/auth_pb';
|
||||
import { HumanView as MgmtHumanView, UserState as MgmtUserState } from 'src/app/proto/generated/management_pb';
|
||||
|
||||
import { CodeDialogComponent } from '../auth-user-detail/code-dialog/code-dialog.component';
|
||||
import { EditDialogType } from '../user-detail/user-detail.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-contact',
|
||||
templateUrl: './contact.component.html',
|
||||
styleUrls: ['./contact.component.scss'],
|
||||
})
|
||||
export class ContactComponent implements OnInit {
|
||||
export class ContactComponent {
|
||||
@Input() disablePhoneCode: boolean = false;
|
||||
@Input() canWrite: boolean = false;
|
||||
@Input() human!: AuthHumanView.AsObject | MgmtHumanView.AsObject;
|
||||
@Output() savedPhone: EventEmitter<string> = new EventEmitter();
|
||||
@Output() savedEmail: EventEmitter<string> = new EventEmitter();
|
||||
@Input() state!: AuthUserState | MgmtUserState;
|
||||
@Output() editType: EventEmitter<EditDialogType> = new EventEmitter();
|
||||
@Output() resendEmailVerification: EventEmitter<void> = new EventEmitter();
|
||||
@Output() resendPhoneVerification: EventEmitter<void> = new EventEmitter();
|
||||
@Output() enteredPhoneCode: EventEmitter<string> = new EventEmitter();
|
||||
@Output() deletedPhone: EventEmitter<void> = new EventEmitter();
|
||||
@Input() public userStateEnum: any;
|
||||
|
||||
public emailEditState: boolean = false;
|
||||
public phoneEditState: boolean = false;
|
||||
public EditDialogType: any = EditDialogType;
|
||||
constructor(private dialog: MatDialog) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
savePhone(): void {
|
||||
this.phoneEditState = false;
|
||||
this.savedPhone.emit(this.human.phone);
|
||||
}
|
||||
|
||||
emitDeletePhone(): void {
|
||||
this.phoneEditState = false;
|
||||
this.deletedPhone.emit();
|
||||
}
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.DELETE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
titleKey: 'USER.LOGINMETHODS.PHONE.DELETETITLE',
|
||||
descriptionKey: 'USER.LOGINMETHODS.PHONE.DELETEDESC',
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
saveEmail(): void {
|
||||
this.emailEditState = false;
|
||||
this.savedEmail.emit(this.human.email);
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
this.deletedPhone.emit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
emitEmailVerification(): void {
|
||||
@@ -67,4 +69,8 @@ export class ContactComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public openEditDialog(type: EditDialogType): void {
|
||||
this.editType.emit(type);
|
||||
}
|
||||
}
|
||||
|
@@ -34,7 +34,10 @@ import { AuthUserDetailComponent } from './auth-user-detail/auth-user-detail.com
|
||||
import { AuthUserMfaComponent } from './auth-user-detail/auth-user-mfa/auth-user-mfa.component';
|
||||
import { CodeDialogComponent } from './auth-user-detail/code-dialog/code-dialog.component';
|
||||
import { DialogOtpComponent } from './auth-user-detail/dialog-otp/dialog-otp.component';
|
||||
import { EditDialogComponent } from './auth-user-detail/edit-dialog/edit-dialog.component';
|
||||
import { ResendEmailDialogComponent } from './auth-user-detail/resend-email-dialog/resend-email-dialog.component';
|
||||
import { ThemeSettingComponent } from './auth-user-detail/theme-setting/theme-setting.component';
|
||||
import { ContactComponent } from './contact/contact.component';
|
||||
import { DetailFormMachineModule } from './detail-form-machine/detail-form-machine.module';
|
||||
import { DetailFormModule } from './detail-form/detail-form.module';
|
||||
import { ExternalIdpsComponent } from './external-idps/external-idps.component';
|
||||
@@ -46,13 +49,13 @@ import { PasswordComponent } from './password/password.component';
|
||||
import { UserDetailRoutingModule } from './user-detail-routing.module';
|
||||
import { UserDetailComponent } from './user-detail/user-detail.component';
|
||||
import { UserMfaComponent } from './user-detail/user-mfa/user-mfa.component';
|
||||
import { ContactComponent } from './contact/contact.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AuthUserDetailComponent,
|
||||
UserDetailComponent,
|
||||
DialogOtpComponent,
|
||||
EditDialogComponent,
|
||||
AuthUserMfaComponent,
|
||||
UserMfaComponent,
|
||||
ThemeSettingComponent,
|
||||
@@ -62,6 +65,7 @@ import { ContactComponent } from './contact/contact.component';
|
||||
MachineKeysComponent,
|
||||
ExternalIdpsComponent,
|
||||
ContactComponent,
|
||||
ResendEmailDialogComponent,
|
||||
],
|
||||
imports: [
|
||||
UserDetailRoutingModule,
|
||||
|
@@ -67,15 +67,20 @@
|
||||
|
||||
<app-card *ngIf="user.human" title="{{ 'USER.LOGINMETHODS.TITLE' | translate }}"
|
||||
description="{{ 'USER.LOGINMETHODS.DESCRIPTION' | translate }}">
|
||||
|
||||
<button card-actions mat-icon-button (click)="refreshUser()">
|
||||
<mat-icon>refresh</mat-icon>
|
||||
</button>
|
||||
<app-contact disablePhoneCode="true"
|
||||
[canWrite]="(['user.write:' + user?.id, 'user.write$'] | hasRole | async)" *ngIf="user?.human"
|
||||
[human]="user.human" (savedPhone)="savePhone($event)" (savedEmail)="saveEmail($event)"
|
||||
(deletedPhone)="deletePhone()" (resendEmailVerification)="resendEmailVerification()"
|
||||
[human]="user.human" (editType)="openEditDialog($event)" (deletedPhone)="deletePhone()"
|
||||
(resendEmailVerification)="resendEmailVerification()"
|
||||
(resendPhoneVerification)="resendPhoneVerification()">
|
||||
<button phoneAction [disabled]="(canWrite$ | async) == false" (click)="sendSetPasswordNotification()"
|
||||
<button pwdAction [disabled]="(canWrite$ | async) == false" (click)="sendSetPasswordNotification()"
|
||||
mat-stroked-button color="primary"
|
||||
*ngIf="user.state === UserState.USERSTATE_INITIAL">{{ 'USER.PASSWORD.RESENDNOTIFICATION' | translate }}</button>
|
||||
<button emailAction class="resendemail" *ngIf="user.state == UserState.USERSTATE_INITIAL"
|
||||
mat-stroked-button color="primary"
|
||||
(click)="resendInitEmail()">{{'USER.RESENDINITIALEMAIL' | translate}}</button>
|
||||
</app-contact>
|
||||
</app-card>
|
||||
|
||||
|
@@ -1,9 +1,9 @@
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||
import { UserGrantContext } from 'src/app/modules/user-grants/user-grants-datasource';
|
||||
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
|
||||
@@ -21,18 +21,24 @@ import {
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { EditDialogComponent } from '../auth-user-detail/edit-dialog/edit-dialog.component';
|
||||
import { ResendEmailDialogComponent } from '../auth-user-detail/resend-email-dialog/resend-email-dialog.component';
|
||||
|
||||
export enum EditDialogType {
|
||||
PHONE = 1,
|
||||
EMAIL = 2,
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-detail',
|
||||
templateUrl: './user-detail.component.html',
|
||||
styleUrls: ['./user-detail.component.scss'],
|
||||
})
|
||||
export class UserDetailComponent implements OnInit, OnDestroy {
|
||||
export class UserDetailComponent implements OnInit {
|
||||
public user!: UserView.AsObject;
|
||||
public genders: Gender[] = [Gender.GENDER_MALE, Gender.GENDER_FEMALE, Gender.GENDER_DIVERSE];
|
||||
public languages: string[] = ['de', 'en'];
|
||||
|
||||
private subscription: Subscription = new Subscription();
|
||||
|
||||
public ChangeType: any = ChangeType;
|
||||
public loading: boolean = false;
|
||||
|
||||
@@ -40,6 +46,8 @@ export class UserDetailComponent implements OnInit, OnDestroy {
|
||||
public copied: string = '';
|
||||
public USERGRANTCONTEXT: UserGrantContext = UserGrantContext.USER;
|
||||
|
||||
public EditDialogType: any = EditDialogType;
|
||||
|
||||
constructor(
|
||||
public translate: TranslateService,
|
||||
private route: ActivatedRoute,
|
||||
@@ -49,8 +57,8 @@ export class UserDetailComponent implements OnInit, OnDestroy {
|
||||
private dialog: MatDialog,
|
||||
) { }
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.subscription = this.route.params.subscribe(params => {
|
||||
refreshUser(): void {
|
||||
this.route.params.pipe(take(1)).subscribe(params => {
|
||||
const { id } = params;
|
||||
this.mgmtUserService.GetUserByID(id).then(user => {
|
||||
this.user = user.toObject();
|
||||
@@ -60,8 +68,8 @@ export class UserDetailComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.subscription.unsubscribe();
|
||||
public ngOnInit(): void {
|
||||
this.refreshUser();
|
||||
}
|
||||
|
||||
public changeState(newState: UserState): void {
|
||||
@@ -149,6 +157,7 @@ export class UserDetailComponent implements OnInit, OnDestroy {
|
||||
this.toast.showInfo('USER.TOAST.PHONEREMOVED', true);
|
||||
if (this.user.human) {
|
||||
this.user.human.phone = '';
|
||||
this.refreshUser();
|
||||
}
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
@@ -158,9 +167,10 @@ export class UserDetailComponent implements OnInit, OnDestroy {
|
||||
public saveEmail(email: string): void {
|
||||
if (this.user.id && email) {
|
||||
this.mgmtUserService.SaveUserEmail(this.user.id, email).then((data: UserEmail) => {
|
||||
this.toast.showInfo('USER.TOAST.EMAILSENT', true);
|
||||
this.toast.showInfo('USER.TOAST.EMAILSAVED', true);
|
||||
if (this.user.human) {
|
||||
this.user.human.email = data.toObject().email;
|
||||
this.refreshUser();
|
||||
}
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
@@ -175,6 +185,7 @@ export class UserDetailComponent implements OnInit, OnDestroy {
|
||||
this.toast.showInfo('USER.TOAST.PHONESAVED', true);
|
||||
if (this.user.human) {
|
||||
this.user.human.phone = data.toObject().phone;
|
||||
this.refreshUser();
|
||||
}
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
@@ -217,4 +228,63 @@ export class UserDetailComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public resendInitEmail(): void {
|
||||
const dialogRef = this.dialog.open(ResendEmailDialogComponent, {
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
if (resp.send && this.user.id) {
|
||||
this.mgmtUserService.ResendInitialMail(this.user.id, resp.email ?? '').then(() => {
|
||||
this.toast.showInfo('USER.TOAST.INITEMAILSENT', true);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public openEditDialog(type: EditDialogType): void {
|
||||
switch (type) {
|
||||
case EditDialogType.PHONE:
|
||||
const dialogRefPhone = this.dialog.open(EditDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.SAVE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
labelKey: 'ACTIONS.NEWVALUE',
|
||||
titleKey: 'USER.LOGINMETHODS.PHONE.EDITTITLE',
|
||||
descriptionKey: 'USER.LOGINMETHODS.PHONE.EDITDESC',
|
||||
value: this.user.human?.phone,
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRefPhone.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
this.savePhone(resp);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case EditDialogType.EMAIL:
|
||||
const dialogRefEmail = this.dialog.open(EditDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.SAVE',
|
||||
cancelKey: 'ACTIONS.CANCEL',
|
||||
labelKey: 'ACTIONS.NEWVALUE',
|
||||
titleKey: 'USER.LOGINMETHODS.EMAIL.EDITTITLE',
|
||||
descriptionKey: 'USER.LOGINMETHODS.EMAIL.EDITDESC',
|
||||
value: this.user.human?.email,
|
||||
},
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRefEmail.afterClosed().subscribe(resp => {
|
||||
if (resp) {
|
||||
this.saveEmail(resp);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -249,6 +249,12 @@ export class GrpcAuthService {
|
||||
return this.grpcService.auth.changeMyUserEmail(req);
|
||||
}
|
||||
|
||||
public ResendMyEmailVerificationMail(): Promise<Empty> {
|
||||
return this.grpcService.auth.resendMyEmailVerificationMail(
|
||||
new Empty(),
|
||||
);
|
||||
}
|
||||
|
||||
public RemoveMyUserPhone(): Promise<Empty> {
|
||||
return this.grpcService.auth.removeMyUserPhone(
|
||||
new Empty(),
|
||||
|
@@ -40,6 +40,7 @@ import {
|
||||
IdpSearchResponse,
|
||||
IdpUpdate,
|
||||
IdpView,
|
||||
InitialMailRequest,
|
||||
LoginName,
|
||||
LoginPolicy,
|
||||
LoginPolicyRequest,
|
||||
@@ -786,6 +787,16 @@ export class ManagementService {
|
||||
return this.grpcService.mgmt.resendEmailVerificationMail(req);
|
||||
}
|
||||
|
||||
public ResendInitialMail(userId: string, newemail: string): Promise<Empty> {
|
||||
const req = new InitialMailRequest();
|
||||
if (newemail) {
|
||||
req.setEmail(newemail);
|
||||
}
|
||||
req.setId(userId);
|
||||
|
||||
return this.grpcService.mgmt.resendInitialMail(req);
|
||||
}
|
||||
|
||||
public ResendPhoneVerification(id: string): Promise<any> {
|
||||
const req = new UserID();
|
||||
req.setId(id);
|
||||
|
@@ -77,7 +77,9 @@
|
||||
"LOGIN":"Einloggen",
|
||||
"EDIT":"Bearbeiten",
|
||||
"PIN":"Anpinnen",
|
||||
"CONFIGURE":"Konfigurieren"
|
||||
"CONFIGURE":"Konfigurieren",
|
||||
"SEND":"Senden",
|
||||
"NEWVALUE":"Neuer Wert"
|
||||
},
|
||||
"ERRORS": {
|
||||
"REQUIRED": "Bitte fülle alle benötigten Felder aus.",
|
||||
@@ -112,6 +114,11 @@
|
||||
"DELETE_TITLE":"User löschen",
|
||||
"DELETE_DESCRIPTION":"Sie sind im Begriff einen Benutzer endgültig zu löschen. Wollen Sie dies wirklich tun?"
|
||||
},
|
||||
"SENDEMAILDIALOG":{
|
||||
"TITLE":"Email Benachrichtigung senden",
|
||||
"DESCRIPTION":"Klicken Sie den untenstehenden Button um ein verifizierungs Email an die aktuelle Adresse zu versenden oder ändern Sie die Emailadresse in dem Feld.",
|
||||
"NEWEMAIL":"Neue Email"
|
||||
},
|
||||
"TABLE":{
|
||||
"DEACTIVATE":"Deaktivieren",
|
||||
"ACTIVATE":"Aktivieren",
|
||||
@@ -241,6 +248,10 @@
|
||||
},
|
||||
"EMAIL": "E-Mail",
|
||||
"PHONE": "Telefonnummer",
|
||||
"PHONEEMPTY":"Keine Telefonnummer hinterlegt",
|
||||
"PHONEVERIFIED":"Telefonnummer bestätigt.",
|
||||
"EMAILVERIFIED":"Email verifiziert",
|
||||
"NOTVERIFIED":"nicht verifiziert",
|
||||
"PREFERRED_LOGINNAME":"Bevorzugter Loginname",
|
||||
"LOGINMETHODS": {
|
||||
"TITLE": "Kontaktinformationen",
|
||||
@@ -248,12 +259,18 @@
|
||||
"EMAIL": {
|
||||
"TITLE": "E-Mail",
|
||||
"VALID": "Validiert",
|
||||
"RESEND": "Verifikationsmail erneut senden"
|
||||
"RESEND": "Verifikationsmail erneut senden",
|
||||
"EDITTITLE":"Email ändern",
|
||||
"EDITDESC":"Geben Sie die neue Email in dem darunterliegenden Feld ein!"
|
||||
},
|
||||
"PHONE": {
|
||||
"TITLE": "Telefon",
|
||||
"VALID": "Validiert",
|
||||
"RESEND": "Verifikationsnachricht erneut senden"
|
||||
"RESEND": "Verifikationsnachricht erneut senden",
|
||||
"EDITTITLE":"Nummer ändern",
|
||||
"EDITDESC":"Geben Sie die neue Nummer in dem darunterliegenden Feld ein!",
|
||||
"DELETETITLE":"Telefonnummer löschen",
|
||||
"DELETEDESC":"Wollen Sie die Telefonnummer wirklich löschen?"
|
||||
},
|
||||
"RESENDCODE": "Code erneut senden",
|
||||
"ENTERCODE":"Verifizieren",
|
||||
@@ -294,10 +311,13 @@
|
||||
"SIGNEDOUT_BTN":"Anmelden",
|
||||
"EDITACCOUNT":"Konto bearbeiten",
|
||||
"ADDACCOUNT":"Konto hinzufügen",
|
||||
"RESENDINITIALEMAIL":"Neue Initialisierungsmail senden",
|
||||
"RESENDEMAILNOTIFICATION":"Benachrichtigungsmail senden",
|
||||
"TOAST": {
|
||||
"CREATED":"Benutzer erfolgreich erstellt.",
|
||||
"SAVED":"Profil gespeichert.",
|
||||
"EMAILSAVED":"E-Mail gespeichert.",
|
||||
"INITEMAILSENT":"Initialisierung Email gesendet.",
|
||||
"PHONESAVED":"Telefonnummer gespeichert.",
|
||||
"PHONEREMOVED":"Telefonnummer gelöscht.",
|
||||
"PHONEVERIFIED":"Telefonnummer bestätigt.",
|
||||
|
@@ -77,7 +77,9 @@
|
||||
"LOGIN":"Login",
|
||||
"EDIT":"Edit",
|
||||
"PIN":"Pin / Unpin",
|
||||
"CONFIGURE":"Configure"
|
||||
"CONFIGURE":"Configure",
|
||||
"SEND":"Send",
|
||||
"NEWVALUE":"New Value"
|
||||
},
|
||||
"ERRORS": {
|
||||
"REQUIRED": "Some required fields are missing.",
|
||||
@@ -112,6 +114,11 @@
|
||||
"DELETE_TITLE":"Delete User",
|
||||
"DELETE_DESCRIPTION":"You are about to permanently delete a user. Are you sure?"
|
||||
},
|
||||
"SENDEMAILDIALOG":{
|
||||
"TITLE":"Send Email Notification",
|
||||
"DESCRIPTION":"Click the button below to send a notification to the current email address or change the email address in the field.",
|
||||
"NEWEMAIL":"New email address"
|
||||
},
|
||||
"TABLE":{
|
||||
"DEACTIVATE":"Deactivate",
|
||||
"ACTIVATE":"Activate",
|
||||
@@ -240,7 +247,11 @@
|
||||
"NOTEQUAL":"The passwords provided do not match."
|
||||
},
|
||||
"EMAIL": "E-mail",
|
||||
"PHONE": "Phone Number",
|
||||
"PHONE": "Phonenumber",
|
||||
"PHONEEMPTY":"No phonenumber defined",
|
||||
"PHONEVERIFIED":"Phonenumber verified.",
|
||||
"EMAILVERIFIED":"Email verified",
|
||||
"NOTVERIFIED":"not verified",
|
||||
"PREFERRED_LOGINNAME":"Preferred Loginname",
|
||||
"LOGINMETHODS": {
|
||||
"TITLE": "Contact Information",
|
||||
@@ -248,12 +259,18 @@
|
||||
"EMAIL": {
|
||||
"TITLE": "E-mail",
|
||||
"VALID": "validated",
|
||||
"RESEND": "Resend Verification E-mail"
|
||||
"RESEND": "Resend Verification E-mail",
|
||||
"EDITTITLE":"Change Email",
|
||||
"EDITDESC":"Enter the new email in the field below."
|
||||
},
|
||||
"PHONE": {
|
||||
"TITLE": "Phone",
|
||||
"VALID": "validated",
|
||||
"RESEND": "Resend Verification Text Message"
|
||||
"RESEND": "Resend Verification Text Message",
|
||||
"EDITTITLE":"Change number",
|
||||
"EDITDESC":"Enter the new phonenumber in the field below.",
|
||||
"DELETETITLE":"Delete Phonenumber",
|
||||
"DELETEDESC":"Do you really want to delete the phonenumber"
|
||||
},
|
||||
"RESENDCODE": "Resend Code",
|
||||
"ENTERCODE":"Verify",
|
||||
@@ -294,10 +311,13 @@
|
||||
"SIGNEDOUT_BTN":"Sign In",
|
||||
"EDITACCOUNT":"Edit Account",
|
||||
"ADDACCOUNT":"Log in With Another Account",
|
||||
"RESENDINITIALEMAIL":"Send new initialisation mail",
|
||||
"RESENDEMAILNOTIFICATION":"Resend Email notification",
|
||||
"TOAST": {
|
||||
"CREATED":"User created successfully.",
|
||||
"SAVED":"Profile saved successfully.",
|
||||
"EMAILSAVED":"E-mail saved successfully.",
|
||||
"INITEMAILSENT":"Initializing mail sent.",
|
||||
"PHONESAVED":"Phone saved successfully.",
|
||||
"PHONEREMOVED":"Phone has been removed.",
|
||||
"PHONEVERIFIED":"Phone verified successfully.",
|
||||
|
@@ -11,6 +11,7 @@
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons|Material+Icons+Outlined" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Lato&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="https://maxst.icons8.com/vue-static/landings/line-awesome/line-awesome/1.3.0/css/line-awesome.min.css">
|
||||
<link rel="manifest" href="manifest.webmanifest">
|
||||
|
Reference in New Issue
Block a user