added pw reset

This commit is contained in:
Chneemann 2024-05-20 18:23:09 +02:00
parent 7464e8e265
commit d2e5d7bde4
10 changed files with 284 additions and 16 deletions

View file

@ -1,5 +1,10 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Router, RouterOutlet } from '@angular/router'; import {
ActivatedRoute,
NavigationEnd,
Router,
RouterOutlet,
} from '@angular/router';
import { HeaderComponent } from './shared/components/header/header.component'; import { HeaderComponent } from './shared/components/header/header.component';
import { SidebarComponent } from './shared/components/sidebar/sidebar.component'; import { SidebarComponent } from './shared/components/sidebar/sidebar.component';
import { LanguageService } from './services/language.service'; import { LanguageService } from './services/language.service';
@ -10,6 +15,7 @@ import { SharedService } from './services/shared.service';
import { ContactDeleteComponent } from './components/contacts/contact-delete/contact-delete.component'; import { ContactDeleteComponent } from './components/contacts/contact-delete/contact-delete.component';
import { OverlayComponent } from './shared/components/overlay/overlay.component'; import { OverlayComponent } from './shared/components/overlay/overlay.component';
import { FirebaseService } from './services/firebase.service'; import { FirebaseService } from './services/firebase.service';
import { filter } from 'rxjs';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -35,6 +41,7 @@ export class AppComponent {
public langService: LanguageService, public langService: LanguageService,
public sharedService: SharedService, public sharedService: SharedService,
private firebaseService: FirebaseService, private firebaseService: FirebaseService,
private route: ActivatedRoute,
private router: Router private router: Router
) { ) {
this.isLoggedIn = this.firebaseService.getCurrentUserId(); this.isLoggedIn = this.firebaseService.getCurrentUserId();
@ -42,9 +49,23 @@ export class AppComponent {
ngOnInit() { ngOnInit() {
if (this.isLoggedIn === undefined) { if (this.isLoggedIn === undefined) {
this.router.navigate(['/login']); this.checkPwResetRoute();
} else { } else {
this.router.navigate(['/summary']); this.router.navigate(['/summary']);
} }
} }
checkPwResetRoute() {
this.router.events
.pipe(filter((event) => event instanceof NavigationEnd))
.subscribe(() => {
const urlTree = this.router.parseUrl(this.router.url);
if (
urlTree.root.children['primary']?.segments[0]?.path !== 'pw-reset'
) {
this.router.navigate(['/login']);
}
});
}
} }

View file

@ -11,6 +11,7 @@ import { TaskEditOverlayComponent } from './shared/components/overlay/task-edit-
import { LoginComponent } from './components/login/login.component'; import { LoginComponent } from './components/login/login.component';
import { RegisterComponent } from './components/login/register/register.component'; import { RegisterComponent } from './components/login/register/register.component';
import { ForgotPwComponent } from './components/login/forgot-pw/forgot-pw.component'; import { ForgotPwComponent } from './components/login/forgot-pw/forgot-pw.component';
import { PwResetComponent } from './components/login/forgot-pw/pw-reset/pw-reset.component';
export const routes: Routes = [ export const routes: Routes = [
{ path: '', component: SummaryComponent }, { path: '', component: SummaryComponent },
@ -19,6 +20,7 @@ export const routes: Routes = [
{ path: 'login/privacy-policy', component: PrivacyPolicyComponent }, { path: 'login/privacy-policy', component: PrivacyPolicyComponent },
{ path: 'register', component: RegisterComponent }, { path: 'register', component: RegisterComponent },
{ path: 'forgot-pw', component: ForgotPwComponent }, { path: 'forgot-pw', component: ForgotPwComponent },
{ path: 'pw-reset', component: PwResetComponent },
{ path: 'summary', component: SummaryComponent }, { path: 'summary', component: SummaryComponent },
{ path: 'add-task', component: AddTaskComponent }, { path: 'add-task', component: AddTaskComponent },
{ path: 'add-task/:id', component: AddTaskComponent }, { path: 'add-task/:id', component: AddTaskComponent },

View file

@ -7,7 +7,9 @@
onsubmit="return false" onsubmit="return false"
> >
<div class="content"> <div class="content">
<p>{{ "login.login" | translate }}</p> <div class="header">
<div class="headline">{{ "forgotPW.forgot" | translate }}</div>
</div>
<div class="line"> <div class="line">
<img src="./../../../assets/img/login/blue-line.svg" alt="" /> <img src="./../../../assets/img/login/blue-line.svg" alt="" />
</div> </div>
@ -17,7 +19,7 @@
id="password" id="password"
name="password" name="password"
#password="ngModel" #password="ngModel"
[type]="loginSerivce.passwordFieldType" [type]="loginService.passwordFieldType"
placeholder="{{ 'register.password' | translate }}" placeholder="{{ 'register.password' | translate }}"
class="custom-input" class="custom-input"
autocomplete="new-password" autocomplete="new-password"
@ -33,8 +35,8 @@
} @else { } @else {
<img <img
class="passwordEye" class="passwordEye"
(click)="loginSerivce.togglePasswordVisibility()" (click)="loginService.togglePasswordVisibility()"
[src]="loginSerivce.passwordIcon" [src]="loginService.passwordIcon"
/> />
} }
<div class="error-msg"> <div class="error-msg">
@ -49,7 +51,7 @@
id="passwordConfirm" id="passwordConfirm"
name="passwordConfirm" name="passwordConfirm"
#passwordConfirm="ngModel" #passwordConfirm="ngModel"
[type]="loginSerivce.passwordFieldType" [type]="loginService.passwordFieldType"
placeholder="{{ 'register.passwordConfirm' | translate }}" placeholder="{{ 'register.passwordConfirm' | translate }}"
class="custom-input" class="custom-input"
autocomplete="new-password" autocomplete="new-password"
@ -65,8 +67,8 @@
} @else { } @else {
<img <img
class="passwordEyeConfirm" class="passwordEyeConfirm"
(click)="loginSerivce.togglePasswordVisibility()" (click)="loginService.togglePasswordVisibility()"
[src]="loginSerivce.passwordIcon" [src]="loginService.passwordIcon"
/> />
} }
<div class="error-msg"> <div class="error-msg">
@ -82,10 +84,12 @@
<app-form-btn <app-form-btn
[class]="'btn-login'" [class]="'btn-login'"
[type]="'submit'" [type]="'submit'"
[value]="'register.signup' | translate" [value]="'forgotPW.pwChange' | translate"
[disabled]=" [disabled]="
password.invalid || password.invalid ||
!pwResetData.password || !pwResetData.password ||
passwordConfirm.invalid ||
!pwResetData.passwordConfirm ||
sharedService.isBtnDisabled || sharedService.isBtnDisabled ||
pwResetData.password.length < 6 || pwResetData.password.length < 6 ||
pwResetData.password !== pwResetData.passwordConfirm pwResetData.password !== pwResetData.passwordConfirm
@ -96,4 +100,3 @@
</form> </form>
<app-footer></app-footer> <app-footer></app-footer>
</section> </section>
<app-loading-dialog></app-loading-dialog>

View file

@ -0,0 +1,212 @@
section {
width: 100vw;
height: 100vh;
position: relative;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
position: fixed;
top: 50%;
right: 50%;
transform: translate(50%, -50%);
width: 482px;
height: fit-content;
background: var(--white);
box-shadow: 0px 0px 12px 3px rgba(0, 0, 0, 0.05);
border-radius: 30px;
padding: 48px 64px;
}
.header {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.headline {
text-align: center;
font-size: 61px;
font-weight: 700;
}
}
.line {
img {
padding: 12px 0 24px 0;
}
}
.input-fields {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
width: 90%;
.custom-input::-webkit-contacts-auto-fill-button {
visibility: hidden;
}
.custom-input {
font-size: 20px;
font-weight: 400;
width: 100%;
border-radius: 10px;
border: 1px solid var(--light-gray);
padding: 12px 16px;
}
.custom-img {
&:nth-child(2) {
position: absolute;
right: 0;
top: 15px;
}
&:nth-child(5) {
position: absolute;
right: 0;
top: 102px;
}
}
.passwordEye {
position: absolute;
right: -5px;
top: 15px;
cursor: pointer;
}
.passwordEyeConfirm {
position: absolute;
right: -5px;
top: 102px;
cursor: pointer;
}
.custom-input:focus + .custom-img {
display: none;
}
}
.error-msg {
display: flex;
align-items: center;
justify-content: center;
height: 24px;
padding: 6px;
width: 120%;
p {
color: var(--red);
font-size: 12px !important;
font-weight: 400 !important;
}
}
.form-buttons {
display: flex;
justify-content: end;
}
/*------------- RESPONSIVE -------------*/
@media (max-height: 800px) {
.content {
top: 45%;
}
}
@media screen and (max-width: 650px) {
.content {
width: 352px;
height: fit-content;
padding: 24px 36px;
}
.header {
.headline {
font-size: 47px;
}
}
.line {
img {
width: 125px;
}
}
}
@media screen and (max-width: 450px) {
.content {
width: calc(100vw - 96px);
padding: 24px 36px;
}
.header {
.headline {
font-size: 36px;
}
}
.line {
img {
width: 112px;
}
}
}
@media screen and (max-width: 380px) {
.content {
width: calc(100vw - 72px);
padding: 12px 24px;
}
.header {
.headline {
font-size: 32px;
}
}
.line {
img {
width: 100px;
}
}
.input-fields {
.custom-input {
font-size: 16px;
padding: 12px;
}
.custom-img {
&:nth-child(2) {
top: 15px;
}
&:nth-child(5) {
top: 90px;
}
&:nth-child(8) {
top: 162px;
}
&:nth-child(11) {
top: 237px;
}
}
.passwordEye {
top: 162px;
}
.passwordEyeConfirm {
top: 237px;
}
}
.error-msg {
height: 18px;
p {
font-size: 10px !important;
}
}
.privacy-policy {
.label {
p {
font-size: 12px;
}
}
}
}

View file

@ -8,8 +8,9 @@ import { TranslateModule } from '@ngx-translate/core';
import { LoadingDialogComponent } from '../../loading-dialog/loading-dialog.component'; import { LoadingDialogComponent } from '../../loading-dialog/loading-dialog.component';
import { FirebaseService } from '../../../../services/firebase.service'; import { FirebaseService } from '../../../../services/firebase.service';
import { LoginService } from '../../../../services/login.service'; import { LoginService } from '../../../../services/login.service';
import { Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { SharedService } from '../../../../services/shared.service'; import { SharedService } from '../../../../services/shared.service';
import { Subscription } from 'rxjs';
@Component({ @Component({
selector: 'app-pw-reset', selector: 'app-pw-reset',
@ -27,6 +28,9 @@ import { SharedService } from '../../../../services/shared.service';
styleUrl: './pw-reset.component.scss', styleUrl: './pw-reset.component.scss',
}) })
export class PwResetComponent { export class PwResetComponent {
oobCode: string = '';
private queryParamsSubscription: Subscription = new Subscription();
pwResetData = { pwResetData = {
password: '', password: '',
passwordConfirm: '', passwordConfirm: '',
@ -34,15 +38,24 @@ export class PwResetComponent {
constructor( constructor(
private firebaseService: FirebaseService, private firebaseService: FirebaseService,
public loginSerivce: LoginService, public loginService: LoginService,
public sharedService: SharedService, public sharedService: SharedService,
private route: ActivatedRoute,
private router: Router private router: Router
) {} ) {}
ngOnInit(): void {
this.queryParamsSubscription = this.route.queryParams.subscribe(
(params) => {
this.oobCode = params['oobCode'];
}
);
}
onSubmit(ngForm: NgForm) { onSubmit(ngForm: NgForm) {
this.sharedService.isBtnDisabled = true; this.sharedService.isBtnDisabled = true;
if (ngForm.submitted && ngForm.form.valid) { if (ngForm.submitted && ngForm.form.valid) {
// this.loginSerivce.login(this.pwResetData); this.loginService.newPassword(this.pwResetData.password, this.oobCode);
} }
} }
} }

View file

@ -59,6 +59,7 @@ section {
position: absolute; position: absolute;
right: -5px; right: -5px;
top: 88px; top: 88px;
cursor: pointer;
} }
.custom-input:focus + .custom-img { .custom-input:focus + .custom-img {
display: none; display: none;

View file

@ -84,11 +84,13 @@ section {
position: absolute; position: absolute;
right: -5px; right: -5px;
top: 186px; top: 186px;
cursor: pointer;
} }
.passwordEyeConfirm { .passwordEyeConfirm {
position: absolute; position: absolute;
right: -5px; right: -5px;
top: 272px; top: 272px;
cursor: pointer;
} }
.custom-input:focus + .custom-img { .custom-input:focus + .custom-img {
display: none; display: none;

View file

@ -6,6 +6,7 @@ import {
GoogleAuthProvider, GoogleAuthProvider,
createUserWithEmailAndPassword, createUserWithEmailAndPassword,
sendPasswordResetEmail, sendPasswordResetEmail,
confirmPasswordReset,
} from 'firebase/auth'; } from 'firebase/auth';
import { FirebaseService } from './firebase.service'; import { FirebaseService } from './firebase.service';
import { import {
@ -208,8 +209,6 @@ export class LoginService {
// FORGOT PASSWORD // FORGOT PASSWORD
passwordReset(email: string) { passwordReset(email: string) {
console.log(email);
const auth = getAuth(); const auth = getAuth();
sendPasswordResetEmail(auth, email) sendPasswordResetEmail(auth, email)
.then(() => { .then(() => {
@ -222,4 +221,17 @@ export class LoginService {
this.sharedService.isBtnDisabled = false; this.sharedService.isBtnDisabled = false;
}); });
} }
newPassword(newPW: string, oobCode: string) {
const auth = getAuth();
confirmPasswordReset(auth, oobCode, newPW)
.then(() => {
this.router.navigate(['/login']);
this.sharedService.isBtnDisabled = false;
})
.catch((error) => {
console.error('Fehler beim Zurücksetzen des Passworts:', error);
this.sharedService.isBtnDisabled = false;
});
}
} }

View file

@ -16,6 +16,7 @@
"forgot": "Passwort zurücksetzen", "forgot": "Passwort zurücksetzen",
"email": "Ihre E-Mail", "email": "Ihre E-Mail",
"sendMail": "E-Mail senden", "sendMail": "E-Mail senden",
"pwChange": "Passwort ändern",
"notice": "Wir senden Ihnen eine E-Mail, über die Sie Ihr Passwort ändern können" "notice": "Wir senden Ihnen eine E-Mail, über die Sie Ihr Passwort ändern können"
}, },
"register": { "register": {

View file

@ -16,6 +16,7 @@
"forgot": "Reset Password", "forgot": "Reset Password",
"email": "Your Email", "email": "Your Email",
"sendMail": "Send Mail", "sendMail": "Send Mail",
"pwChange": "Change Password",
"notice": "We will send you an email to change your password." "notice": "We will send you an email to change your password."
}, },
"register": { "register": {