Improved auth views and imrpoved default settings handling #70

This commit is contained in:
Sven Heidemann 2022-10-18 18:04:53 +02:00
parent f553779797
commit a51efa641d
21 changed files with 569 additions and 376 deletions

3
kdb-web/.gitignore vendored
View File

@ -41,3 +41,6 @@ testem.log
# System files
.DS_Store
Thumbs.db
ignore
ignore/*

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { PrimeNGConfig } from 'primeng/api';
import { AuthService } from './services/auth/auth.service';
import { SocketService } from './services/socket/socket.service';
import { ThemeService } from './services/theme/theme.service';
@ -18,10 +20,10 @@ export class AppComponent implements OnInit {
constructor(
private authService: AuthService,
private themeService: ThemeService,
private socket: SocketService
) { }
ngOnInit(): void {
private socket: SocketService,
private translateService: TranslateService,
private config: PrimeNGConfig
) {
this.themeService.sidebarWidth$.subscribe(value => {
this.sidebarWidth = value;
});
@ -31,11 +33,33 @@ export class AppComponent implements OnInit {
this.authService.isLoggedIn$.subscribe(value => {
this.isLoggedIn = value;
});
}
ngOnInit(): void {
this.translateService.setDefaultLang('en');
this.themeService.loadTheme();
this.socket.startSocket();
}
loadLang(): void {
let lang = localStorage.getItem(`default_lang`);
if (!lang) {
lang = 'en';
this.setLang(lang);
}
this.translate(lang);
}
setLang(lang: string): void {
localStorage.setItem(`default_lang`, lang);
}
translate(lang: string) {
this.translateService.use(lang);
this.translateService.get('primeng').subscribe(res => this.config.setTranslation(res));
}
setSideWidth($event: any): void {
this.themeService.setSideWidth($event);

View File

@ -29,7 +29,6 @@ export class HeaderComponent implements OnInit {
) { }
ngOnInit(): void {
this.translateService.setDefaultLang('en');
this.initMenuLists();
this.loadLang();
this.translateService.onLangChange.subscribe((event: LangChangeEvent) => {

View File

@ -1,18 +1,20 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { SharedModule } from '../shared/shared.module';
import { AuthRoutingModule } from './auth-routing.module';
import { AuthHeaderComponent } from './components/auth-header/auth-header.component';
import { ForgetPasswordComponent } from './components/forget-password/forget-password.component';
import { LoginComponent } from './components/login/login.component';
import { RegistrationComponent } from './components/registration/registration.component';
import { SharedModule } from '../shared/shared.module';
@NgModule({
declarations: [
ForgetPasswordComponent,
LoginComponent,
RegistrationComponent
RegistrationComponent,
AuthHeaderComponent
],
imports: [
CommonModule,

View File

@ -0,0 +1,10 @@
<div class="auth-header">
<div class="logo-button-wrapper">
<button type="button" pButton icon="pi pi-globe" class="btn icon-btn p-button-text" (click)="authLangMenu.toggle($event)"></button>
<p-menu #authLangMenu [popup]="true" [model]="langList" class="lang-menu"></p-menu>
</div>
<div class="logo-button-wrapper">
<button type="button" pButton icon="pi pi-palette" class="btn icon-btn p-button-text" (click)="authThemeMenu.toggle($event)"></button>
<p-menu #authThemeMenu [popup]="true" [model]="themeList" class="theme-menu"></p-menu>
</div>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AuthHeaderComponent } from './auth-header.component';
describe('AuthHeaderComponent', () => {
let component: AuthHeaderComponent;
let fixture: ComponentFixture<AuthHeaderComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AuthHeaderComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(AuthHeaderComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,83 @@
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { TranslateService, LangChangeEvent } from '@ngx-translate/core';
import { MenuItem, PrimeNGConfig } from 'primeng/api';
import { catchError } from 'rxjs';
import { AuthService } from 'src/app/services/auth/auth.service';
import { SettingsService } from 'src/app/services/settings/settings.service';
import { SpinnerService } from 'src/app/services/spinner/spinner.service';
import { ThemeService } from 'src/app/services/theme/theme.service';
@Component({
selector: 'app-auth-header',
templateUrl: './auth-header.component.html',
styleUrls: ['./auth-header.component.scss']
})
export class AuthHeaderComponent implements OnInit {
langList: MenuItem[] = [];
themeList: MenuItem[] = [];
userMenuList!: MenuItem[];
constructor(
private router: Router,
private themeService: ThemeService,
private spinnerService: SpinnerService,
private settings: SettingsService,
private translateService: TranslateService,
private config: PrimeNGConfig
) { }
ngOnInit(): void {
this.initMenuLists();
this.loadLang();
}
initMenuLists(): void {
this.langList = [
{
label: 'English', command: () => {
this.translate('en');
this.setLang('en');
},
},
{
label: 'Deutsch', command: () => {
this.translate('de');
this.setLang('de');
},
},
];
this.settings.getThemes()?.forEach(theme => {
this.themeList.push({
label: theme.Label,
command: () => {
this.changeTheme(theme.Name);
}
});
});
}
changeTheme(name: string): void {
this.themeService.setTheme(name, true);
}
translate(lang: string) {
this.translateService.use(lang);
this.translateService.get('primeng').subscribe(res => this.config.setTranslation(res));
}
loadLang(): void {
let lang = localStorage.getItem(`default_lang`);
if (!lang) {
lang = 'en';
this.setLang(lang);
}
this.translate(lang);
}
setLang(lang: string): void {
localStorage.setItem(`default_lang`, lang);
}
}

View File

@ -5,24 +5,26 @@
<form [formGroup]="emailForm">
<h1>{{'auth.header' | translate}}</h1>
<div *ngIf="!ready" class="input-field">
<input type="email" pInputText formControlName="email" placeholder="{{'auth.forgot_password.e_mail' | translate}}"
autocomplete="username email">
<input type="email" pInputText formControlName="email"
placeholder="{{'auth.forgot_password.e_mail' | translate}}" autocomplete="username email">
</div>
<div *ngIf="ready" class="input-field-info-text">
{{'auth.forgot_password.send_confirmation_url' | translate}}
</div>
<div class="login-form-submit">
<button pButton label="{{'auth.forgot_password.reset_password' | translate}}" class="btn login-form-submit-btn"
(click)="forgotPassword()" [disabled]="emailForm.invalid || ready"></button>
<button pButton label="{{'auth.forgot_password.reset_password' | translate}}"
class="btn login-form-submit-btn" (click)="forgotPassword()"
[disabled]="emailForm.invalid || ready"></button>
</div>
<div class="login-form-sub-button-wrapper">
<div class="login-form-sub-btn-wrapper">
<button pButton label="{{'auth.forgot_password.login' | translate}}" class="btn login-form-sub-btn" (click)="login()"></button>
<button pButton label="{{'auth.forgot_password.login' | translate}}"
class="btn login-form-sub-btn" (click)="login()"></button>
</div>
<div class="login-form-sub-btn-wrapper">
<button pButton label="{{'auth.forgot_password.register' | translate}}" class="btn login-form-sub-btn"
(click)="register()"></button>
<button pButton label="{{'auth.forgot_password.register' | translate}}"
class="btn login-form-sub-btn" (click)="register()"></button>
</div>
</div>
</form>
@ -33,8 +35,8 @@
<h1>{{'auth.header' | translate}}</h1>
<div class="input-field">
<input type="password" pInputText formControlName="password" placeholder="{{'auth.forgot_password.password' | translate}}"
autocomplete="new-password">
<input type="password" pInputText formControlName="password"
placeholder="{{'auth.forgot_password.password' | translate}}" autocomplete="new-password">
</div>
<div class="input-field">
@ -42,16 +44,20 @@
placeholder="{{'auth.forgot_password.repeat_password' | translate}}"
[ngClass]="{ 'invalid-feedback-input': submitted && repeatErrors.password}">
<div *ngIf="submitted" class="invalid-feedback">
<div *ngIf="repeatErrors.password">{{'auth.forgot_password.passwords_do_not_match' | translate}}</div>
<div *ngIf="repeatErrors.password">{{'auth.forgot_password.passwords_do_not_match' |
translate}}</div>
</div>
</div>
<div class="login-form-submit">
<button pButton label="{{'auth.forgot_password.reset_password' | translate}}" class="btn login-form-submit-btn"
(click)="resetPassword()" [disabled]="passwordForm.invalid || ready"></button>
<button pButton label="{{'auth.forgot_password.reset_password' | translate}}"
class="btn login-form-submit-btn" (click)="resetPassword()"
[disabled]="passwordForm.invalid || ready"></button>
</div>
</form>
</ng-template>
</div>
</div>
<app-auth-header></app-auth-header>
</section>

View File

@ -4,7 +4,7 @@
<form [formGroup]="loginForm">
<h1>sh-edraft.de</h1>
<div class="input-field">
<input type="email" pInputText formControlName="email" placeholder="E-Mail" [ngClass]="{ 'invalid-feedback-input': submitted && (
<input type="email" pInputText formControlName="email" placeholder="{{'auth.login.e_mail' | translate}}" [ngClass]="{ 'invalid-feedback-input': submitted && (
(loginForm.controls.email.errors && loginForm.controls.email.errors['required'] || authUserAtrErrors.email.required) ||
(authUserAtrErrors.email.wrongData) ||
(authUserAtrErrors.email.notConfirmed)
@ -12,9 +12,9 @@
<div *ngIf="submitted" class="invalid-feedback">
<div
*ngIf="loginForm.controls.email.errors && loginForm.controls.email.errors['required'] || authUserAtrErrors.email.required">
E-Mail wird benötigt</div>
<div *ngIf="authUserAtrErrors.email.wrongData">Benutzer nicht gefunden</div>
<div *ngIf="authUserAtrErrors.email.notConfirmed">E-Mail wurde nicht bestätigt</div>
{{'auth.login.e_mail_required' | translate}}</div>
<div *ngIf="authUserAtrErrors.email.wrongData">{{'auth.login.user_not_found' | translate}}</div>
<div *ngIf="authUserAtrErrors.email.notConfirmed">{{'auth.login.e_mail_not_confirmed' | translate}}</div>
</div>
</div>
<div class="input-field">
@ -24,7 +24,7 @@
styleClass="p-password p-component p-inputwrapper p-input-icon-right"
Remove after update!
-->
<p-password type="password" formControlName="password" placeholder="Passwort" [ngClass]="{ 'invalid-feedback-input': submitted && (
<p-password type="password" formControlName="password" placeholder="{{'auth.login.password' | translate}}" [ngClass]="{ 'invalid-feedback-input': submitted && (
(loginForm.controls.password.errors && loginForm.controls.password.errors['required'] || authUserAtrErrors.password.required) ||
(authUserAtrErrors.password.wrongData)
)}" autocomplete="current-password" [toggleMask]="true" [feedback]="false"
@ -33,21 +33,21 @@
<div *ngIf="submitted" class="invalid-feedback">
<div
*ngIf="loginForm.controls.password.errors && loginForm.controls.password.errors['required'] || authUserAtrErrors.password.required">
Password wird benötigt</div>
<div *ngIf="authUserAtrErrors.password.wrongData">Falsches passwort</div>
{{'auth.login.password_required' | translate}}</div>
<div *ngIf="authUserAtrErrors.password.wrongData">{{'auth.login.wrong_password' | translate}}</div>
</div>
</div>
<div class="login-form-submit">
<button pButton label="Anmelden" class="btn login-form-submit-btn" (click)="login()"
<button pButton label="{{'auth.login.login' | translate}}" class="btn login-form-submit-btn" (click)="login()"
[disabled]="loginForm.invalid"></button>
</div>
<div class="login-form-sub-button-wrapper">
<div class="login-form-sub-btn-wrapper">
<button pButton label="Registrieren" class="btn login-form-sub-btn"
<button pButton label="{{'auth.login.register' | translate}}" class="btn login-form-sub-btn"
(click)="register()"></button>
</div>
<div class="login-form-sub-btn-wrapper">
<button pButton label="Passwort vergessen?"
<button pButton label="{{'auth.login.forgot_password' | translate}}"
class="btn login-form-sub-btn login-form-sub-login-btn p-button-text"
(click)="forgotPassword()"></button>
</div>
@ -55,4 +55,6 @@
</form>
</div>
</div>
<app-auth-header></app-auth-header>
</section>

View File

@ -4,80 +4,82 @@
<form [formGroup]="loginForm">
<h1>sh-edraft.de</h1>
<div class="input-field">
<input type="text" pInputText formControlName="firstName" placeholder="Vorname"
<input type="text" pInputText formControlName="firstName" placeholder="{{'auth.register.first_name' | translate}}"
autocomplete="given-name">
<div *ngIf="submitted" class="invalid-feedback">
<div
*ngIf="loginForm.controls.firstName.errors && loginForm.controls.firstName.errors['required'] || authUserAtrErrors.firstName.required">
Vorname wird benötigt</div>
<div *ngIf="authUserAtrErrors.firstName.wrongData">Vorname ist ungültig</div>
{{'auth.register.first_name_required' | translate}}</div>
<div *ngIf="authUserAtrErrors.firstName.wrongData">{{'auth.register.first_name_invalid' | translate}}</div>
</div>
</div>
<div class="input-field">
<input type="text" pInputText formControlName="lastName" placeholder="Nachname"
<input type="text" pInputText formControlName="lastName" placeholder="{{'auth.register.last_name' | translate}}"
autocomplete="family-name">
<div *ngIf="submitted" class="invalid-feedback">
<div
*ngIf="loginForm.controls.lastName.errors && loginForm.controls.lastName.errors['required'] || authUserAtrErrors.lastName.required">
Nachname wird benötigt</div>
<div *ngIf="authUserAtrErrors.lastName.wrongData">Nachname ist ungültig</div>
{{'auth.register.last_name_required' | translate}}</div>
<div *ngIf="authUserAtrErrors.lastName.wrongData">{{'auth.register.last_name_invalid' | translate}}</div>
</div>
</div>
<div class="input-field">
<input type="email" pInputText formControlName="email" placeholder="E-Mail"
<input type="email" pInputText formControlName="email" placeholder="{{'auth.register.e_mail' | translate}}"
[ngClass]="{ 'invalid-feedback-input': submitted && (authUserAtrErrors.email.wrongData || loginForm.controls.email.errors && loginForm.controls.email.errors['required'] || authUserAtrErrors.email.required)}"
autocomplete="username email">
<div *ngIf="submitted" class="invalid-feedback">
<div
*ngIf="loginForm.controls.email.errors && loginForm.controls.email.errors['required'] || authUserAtrErrors.email.required">
E-Mail wird benötigt</div>
<div *ngIf="authUserAtrErrors.email.wrongData">Benutzer existiert bereits</div>
{{'auth.register.e_mail_required' | translate}}</div>
<div *ngIf="authUserAtrErrors.email.wrongData">{{'auth.register.user_already_exists' | translate}}</div>
</div>
</div>
<div class="input-field">
<input type="email" pInputText formControlName="emailRepeat" placeholder="E-Mail wiederholen"
<input type="email" pInputText formControlName="emailRepeat" placeholder="{{'auth.register.repeat_e_mail' | translate}}"
[ngClass]="{ 'invalid-feedback-input': submitted && repeatErrors.email}">
<div *ngIf="submitted" class="invalid-feedback">
<div *ngIf="repeatErrors.email">Die E-Mails stimmen nicht überein</div>
<div *ngIf="repeatErrors.email">{{'auth.register.e_mails_not_match' | translate}}</div>
</div>
</div>
<div class="input-field">
<p-password type="password" formControlName="password" placeholder="Passwort"
<p-password type="password" formControlName="password" placeholder="{{'auth.register.password' | translate}}"
ngClass="{ 'invalid-feedback': submitted && loginForm.controls.password.errors && loginForm.controls.password.errors['required'] || authUserAtrErrors.password.required}"
autocomplete="new-password" [toggleMask]="true" [feedback]="false"
styleClass="p-password p-component p-inputwrapper p-input-icon-right"></p-password>
<div *ngIf="submitted" class="invalid-feedback">
<div
*ngIf="loginForm.controls.password.errors && loginForm.controls.password.errors['required'] || authUserAtrErrors.password.required">
Password wird benötigt</div>
{{'auth.register.password_required' | translate}}</div>
</div>
</div>
<div class="input-field">
<p-password type="password" formControlName="passwordRepeat" placeholder="Passwort wiederholen"
<p-password type="password" formControlName="passwordRepeat" placeholder="{{'auth.register.repeat_password' | translate}}"
[ngClass]="{ 'invalid-feedback-input': submitted && repeatErrors.password}" [toggleMask]="true"
[feedback]="false" styleClass="p-password p-component p-inputwrapper p-input-icon-right">
</p-password>
<div *ngIf="submitted" class="invalid-feedback">
<div *ngIf="repeatErrors.password">Die Passwörter stimmen nicht überein</div>
<div *ngIf="repeatErrors.password">{{'auth.register.passwords_not_match' | translate}}</div>
</div>
</div>
<div class="login-form-submit">
<button pButton label="Registrieren" class="btn login-form-submit-btn" (click)="register()"
<button pButton label="{{'auth.register.register' | translate}}" class="btn login-form-submit-btn" (click)="register()"
[disabled]="loginForm.invalid"></button>
</div>
<div class="login-form-sub-button-wrapper">
<div class="login-form-sub-btn-wrapper">
<button pButton label="Einloggen" class="btn login-form-sub-btn" (click)="login()"></button>
<button pButton label="{{'auth.register.login' | translate}}" class="btn login-form-sub-btn" (click)="login()"></button>
</div>
</div>
</form>
</div>
</div>
<app-auth-header></app-auth-header>
</section>

View File

@ -41,7 +41,7 @@ export class ThemeService {
const mail = this.authService.getEMailFromDecodedToken(token);
let defaultThemeName = localStorage.getItem(`default_themeName`);
if (!defaultThemeName || defaultThemeName != Themes.Default) {
if (!defaultThemeName) {
defaultThemeName = Themes.Default;
}
@ -58,7 +58,13 @@ export class ThemeService {
this.setTheme(userThemeName);
}
setTheme(name: string): void {
setTheme(name: string, isDefault: boolean = false): void {
if (isDefault) {
localStorage.setItem(`default_themeName`, name);
this.themeName$.next(name);
return;
}
this.authService.isUserLoggedInAsync().then(result => {
if (!result) {
localStorage.setItem(`default_themeName`, Themes.Default);

View File

@ -89,8 +89,37 @@
},
"auth": {
"header": "Krümmelmonster WI",
"login": {},
"register": {},
"login": {
"e_mail": "E-Mail",
"password": "Passwort",
"login": "Einloggen",
"register": "Registrieren",
"forgot_password": "Passwort vergessen?",
"e_mail_required": "E-Mail benötigt",
"user_not_found": "Benutzer nicht gefunden",
"e_mail_not_confirmed": "E-Mail nicht bestätigt",
"password_required": "Passwort benötigt",
"wrong_password": "Falsches passwort"
},
"register": {
"first_name": "Vorname",
"last_name": "Nachname",
"e_mail": "E-Mail",
"repeat_e_mail": "E-mail wiederholen",
"password": "Password",
"repeat_password": "password wiederholen",
"register": "Registrieren",
"login": "Einloggen",
"user_already_exists": "Benutzer existiert bereits",
"passwords_not_match": "Passwörter sitmmen nicht überein",
"e_mails_not_match": "E-Mails sitmmen nicht überein",
"first_name_required": "Vorname benötigt",
"last_name_required": "Nachname benötigt",
"e_mail_required": "E-Mail benötigt",
"password_required": "Passwort benötigt",
"first_name_invalid": "Vorname ungültig",
"last_name_invalid": "Nachname ungültig"
},
"forgot_password": {
"e_mail": "E-Mail",
"send_confirmation_url": "Falls ein Benutzer mit der E-Mail gefunden wurde, wurde Betstätigungslink versendet",

View File

@ -92,7 +92,7 @@
"password": "Password",
"login": "Login",
"register": "Register",
"forgot_password": "Forgot password",
"forgot_password": "Forgot password?",
"e_mail_required": "E-Mail required",
"user_not_found": "User not found",
"e_mail_not_confirmed": "Email was not confirmed",
@ -114,7 +114,7 @@
"first_name_required": "Forename required",
"last_name_required": "Surname required",
"e_mail_required": "E-Mail required",
"password_required": "Passwort required",
"password_required": "Password required",
"first_name_invalid": "Forename invalid",
"last_name_invalid": "Surname invalid"
},

View File

@ -68,6 +68,12 @@ header {
}
}
.auth-header {
.p-menu-overlay {
width: 180px !important;
}
}
.app {
height: 100%;
display: flex;
@ -361,8 +367,11 @@ footer {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 15px;
.login-form-wrapper {
.login-form-wrapper,
.auth-header {
width: 350px;
height: 350px;
@ -418,6 +427,11 @@ footer {
.register-confirm-form-wrapper {
height: 250px;
}
.auth-header {
width: 350px;
height: 75px;
}
}
.input-field {

View File

@ -23,8 +23,11 @@
}
}
.p-menu-overlay {
header,
.app {
.p-menu-overlay {
top: $headerHeight !important;
}
}
.p-panelmenu {

View File

@ -194,7 +194,8 @@
.login-wrapper {
background-color: $secondaryBackgroundColor;
.login-form-wrapper {
.login-form-wrapper,
.auth-header {
background-color: $primaryBackgroundColor;
.login-form {
@ -424,7 +425,7 @@
}
input,
.p-password {
.p-password input {
border-radius: 10px;
border: $default-border;

View File

@ -194,7 +194,8 @@
.login-wrapper {
background-color: $secondaryBackgroundColor;
.login-form-wrapper {
.login-form-wrapper,
.auth-header {
background-color: $primaryBackgroundColor;
.login-form {
@ -424,7 +425,7 @@
}
input,
.p-password {
.p-password input {
border-radius: 10px;
border: $default-border;

View File

@ -196,7 +196,8 @@
.login-wrapper {
background-color: $secondaryBackgroundColor;
.login-form-wrapper {
.login-form-wrapper,
.auth-header {
background-color: $primaryBackgroundColor;
.login-form {
@ -426,7 +427,7 @@
}
input,
.p-password {
.p-password input {
border-radius: 10px;
border: $default-border;

View File

@ -194,7 +194,8 @@
.login-wrapper {
background-color: $secondaryBackgroundColor;
.login-form-wrapper {
.login-form-wrapper,
.auth-header {
background-color: $primaryBackgroundColor;
.login-form {
@ -424,7 +425,7 @@
}
input,
.p-password {
.p-password input {
border-radius: 10px;
border: $default-border;