Skip to content
Snippets Groups Projects
Commit f7e80a58 authored by Rémi PAILHAREY's avatar Rémi PAILHAREY :fork_knife_plate:
Browse files

feat: update forgotten password form

parent f5889f65
No related branches found
No related tags found
2 merge requests!783V3.0.0,!721feat: update forgotten password form
Showing
with 297 additions and 558 deletions
...@@ -11,9 +11,8 @@ import { LoginComponent } from './login/login.component'; ...@@ -11,9 +11,8 @@ import { LoginComponent } from './login/login.component';
import { NewsletterSubscriptionComponent } from './newsletter-subscription/newsletter-subscription.component'; import { NewsletterSubscriptionComponent } from './newsletter-subscription/newsletter-subscription.component';
import { PageComponent } from './page/page.component'; import { PageComponent } from './page/page.component';
import { ResetEmailComponent } from './reset-email/reset-email.component'; import { ResetEmailComponent } from './reset-email/reset-email.component';
import { ResetPasswordComponent } from './reset-password/reset-password.component'; import { ForgotPasswordComponent } from './reset-password/forgot-password.component';
import { StructureResolver } from './resolvers/structure.resolver'; import { StructureResolver } from './resolvers/structure.resolver';
import { PasswordFormComponent } from './shared/components';
import { StructureDetailsComponent } from './structure-list/components/structure-details/structure-details.component'; import { StructureDetailsComponent } from './structure-list/components/structure-details/structure-details.component';
import { StructureListSearchPrintComponent } from './structure-list/components/structure-list-search-print/structure-list-search-print.component'; import { StructureListSearchPrintComponent } from './structure-list/components/structure-list-search-print/structure-list-search-print.component';
import { StructureListComponent } from './structure-list/structure-list.component'; import { StructureListComponent } from './structure-list/structure-list.component';
...@@ -183,15 +182,10 @@ const routes: Routes = [ ...@@ -183,15 +182,10 @@ const routes: Routes = [
children: [ children: [
{ {
path: '', path: '',
component: ResetPasswordComponent, component: ForgotPasswordComponent,
}, },
footerOutletRoute,
], ],
}, },
{
path: 'new-password',
component: PasswordFormComponent,
},
{ {
path: 'newsletter', path: 'newsletter',
title: buildTitle('Newsletter'), title: buildTitle('Newsletter'),
......
...@@ -31,6 +31,7 @@ import { MapModule } from './map/map.module'; ...@@ -31,6 +31,7 @@ import { MapModule } from './map/map.module';
import { NewsletterSubscriptionComponent } from './newsletter-subscription/newsletter-subscription.component'; import { NewsletterSubscriptionComponent } from './newsletter-subscription/newsletter-subscription.component';
import { PageComponent } from './page/page.component'; import { PageComponent } from './page/page.component';
import { ResetEmailComponent } from './reset-email/reset-email.component'; import { ResetEmailComponent } from './reset-email/reset-email.component';
import { ForgotPasswordComponent } from './reset-password/forgot-password.component';
import { ResetPasswordComponent } from './reset-password/reset-password.component'; import { ResetPasswordComponent } from './reset-password/reset-password.component';
import { PersonalOfferResolver } from './resolvers/personal-offer.resolver'; import { PersonalOfferResolver } from './resolvers/personal-offer.resolver';
import { StructureResolver } from './resolvers/structure.resolver'; import { StructureResolver } from './resolvers/structure.resolver';
...@@ -53,6 +54,7 @@ import { StructureJoinComponent } from './structure/structure-join/structure-joi ...@@ -53,6 +54,7 @@ import { StructureJoinComponent } from './structure/structure-join/structure-joi
PageComponent, PageComponent,
ContactComponent, ContactComponent,
ResetEmailComponent, ResetEmailComponent,
ForgotPasswordComponent,
ResetPasswordComponent, ResetPasswordComponent,
StructureJoinComponent, StructureJoinComponent,
NewsletterSubscriptionComponent, NewsletterSubscriptionComponent,
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
autocomplete="on" autocomplete="on"
size="large" size="large"
[disabled]="isAccountMode" [disabled]="isAccountMode"
[status]="accountForm.get('email').value ? (accountForm.get('email').invalid ? 'error' : 'success') : null" [status]="getStatus(accountForm.get('email'))"
[statusText]="accountForm.get('email').hasError('alreadyExist') ? 'Cet email est déjà utilisé' : null" [statusText]="accountForm.get('email').hasError('alreadyExist') ? 'Cet email est déjà utilisé' : null"
[value]="accountForm.get('email').value" [value]="accountForm.get('email').value"
(valueChange)="accountForm.get('email').setValue($event); setValidationsForm(); verifyUserExist($event)" (valueChange)="accountForm.get('email').setValue($event); setValidationsForm(); verifyUserExist($event)"
......
<div *ngIf="!token" class="resetPage">
<div class="title">
<h1>Mot de passe oublié</h1>
<p>Saisissez votre email afin de réinitialiser votre mot de passe</p>
</div>
<form [formGroup]="forgotPasswordForm" (ngSubmit)="onSubmit()">
<app-input
size="large"
[placeholder]="'exemple@mail.com'"
[label]="'Email du compte'"
[value]="email.value"
[status]="email.value ? (email.invalid ? 'error' : 'success') : null"
(valueChange)="email.setValue($event)"
/>
<div class="footer">
<app-button [variant]="'secondary'" [label]="'Annuler'" (action)="goLogin()" />
<app-button
[variant]="'primary'"
[label]="'Envoyer'"
[type]="'submit'"
[disabled]="loading || forgotPasswordForm.invalid"
/>
</div>
</form>
</div>
<app-password-form *ngIf="token" [token]="token" />
import { Component, OnInit } from '@angular/core';
import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { AuthService } from '../services/auth.service';
import { NotificationService } from '../services/notification.service';
import { CustomRegExp } from '../utils/CustomRegExp';
@Component({
selector: 'app-reset-password',
templateUrl: './forgot-password.component.html',
styleUrls: ['./reset-password.component.scss'],
})
export class ForgotPasswordComponent implements OnInit {
public forgotPasswordForm = new FormGroup({
email: new FormControl('', [Validators.required, Validators.pattern(CustomRegExp.EMAIL)]),
});
public loading = false;
public token: string;
constructor(
private authService: AuthService,
private router: Router,
private notificationService: NotificationService,
private activatedRoute: ActivatedRoute,
) {}
ngOnInit(): void {
this.activatedRoute.queryParams.subscribe((params) => {
this.token = params.token;
});
}
/** Getter for email control */
get email(): AbstractControl<string, string> {
return this.forgotPasswordForm.get('email');
}
public onSubmit(): void {
// stop here if form is invalid
if (this.forgotPasswordForm.invalid) return;
this.loading = true;
this.authService.resetPassword(this.email.value).subscribe({
next: () => {
this.notificationService.showSuccess(
'Un mail de confirmation de modification de votre mot de passe vous a été envoyé.',
);
this.goLogin();
},
complete: () => {
this.loading = false;
},
});
}
public goLogin(): void {
this.router.navigateByUrl('/login');
}
}
<div *ngIf="!token" class="resetPage"> <div class="resetPage">
<div class="resetPasswordForm"> <div class="title">
<div class="title"> <h1>Réinitialisation du mot de passe</h1>
<h1>Mot de passe oublié</h1> </div>
<p>Saisissez votre email afin de réinitialiser votre mot de passe</p> <form [formGroup]="resetPasswordForm" (ngSubmit)="onSubmit()">
</div>
<div class="fields"> <div class="fields">
<form [formGroup]="resetForm" (ngSubmit)="onSubmit()"> <app-input
<div class="form-group"> id="password"
<label for="email">Email du compte</label> label="Création du mot de passe"
<div fxLayout="row" fxLayoutGap="13px"> size="large"
<input type="password"
type="text" [value]="password.value"
autocomplete="on" (valueChange)="password.setValue($event)"
formControlName="email" />
class="form-input" <div class="passwordConditions">
[ngClass]="{ inputInvalid: submitted && f.email.errors }" <p>Le mot de passe doit obligatoirement contenir&nbsp;:</p>
<ul>
<li [ngClass]="checkIfPasswordHasEnoughChar(password.value) ? 'valid' : 'invalid'">
<app-svg-icon
[iconClass]="'icon-16'"
[folder]="'form'"
[icon]="checkIfPasswordHasEnoughChar(password.value) ? 'validate' : 'notValidate'"
/>
<p>8 caractères</p>
</li>
<li [ngClass]="checkIfPasswordHasSpecialChar(password.value) ? 'valid' : 'invalid'">
<app-svg-icon
[iconClass]="'icon-16'"
[folder]="'form'"
[icon]="checkIfPasswordHasSpecialChar(password.value) ? 'validate' : 'notValidate'"
/>
<p>1 caractère spécial</p>
</li>
<li [ngClass]="checkIfPasswordHasLowerCase(password.value) ? 'valid' : 'invalid'">
<app-svg-icon
[iconClass]="'icon-16'"
[folder]="'form'"
[icon]="checkIfPasswordHasLowerCase(password.value) ? 'validate' : 'notValidate'"
/> />
</div> <p>1 caractère en minuscule</p>
<div *ngIf="submitted && f.email.errors" class="incorrectId"> </li>
<div *ngIf="f.email.errors.required">L'adresse e-mail est requise</div> <li [ngClass]="checkIfPasswordHasUpperCase(password.value) ? 'valid' : 'invalid'">
</div> <app-svg-icon
</div> [iconClass]="'icon-16'"
<div class="footer" fxLayout="row" fxLayoutAlign="space-between center"> [folder]="'form'"
<app-button [variant]="'secondary'" [label]="'Annuler'" (action)="goLogin()" /> [icon]="checkIfPasswordHasUpperCase(password.value) ? 'validate' : 'notValidate'"
<app-button [variant]="'primary'" [label]="'Envoyer'" [type]="'submit'" [disabled]="loading" /> />
</div> <p>1 caractère en majuscule</p>
</form> </li>
<li [ngClass]="checkIfPasswordHasDigit(password.value) ? 'valid' : 'invalid'">
<app-svg-icon
[iconClass]="'icon-16'"
[folder]="'form'"
[icon]="checkIfPasswordHasDigit(password.value) ? 'validate' : 'notValidate'"
/>
<p>1 chiffre</p>
</li>
</ul>
</div>
<app-input
id="confirmPassword"
label="Vérification du mot de passe"
size="large"
type="password"
[status]="confirmPassword.value ? (confirmPassword.invalid ? 'error' : 'success') : null"
[value]="confirmPassword.value"
(valueChange)="confirmPassword.setValue($event)"
/>
</div> </div>
</div> <div class="footer">
<app-button
[variant]="'primary'"
[label]="'Confirmer'"
[type]="'submit'"
[disabled]="loading || resetPasswordForm.invalid"
/>
</div>
</form>
</div> </div>
<app-password-form *ngIf="token" />
@import 'color'; @import 'color';
@import 'typography'; @import 'typography';
@import 'breakpoint'; @import 'breakpoint';
@import 'layout';
:host {
height: 100%;
}
.resetPage { .resetPage {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
height: 100%;
width: 100%; width: 100%;
max-width: 980px; max-width: 980px;
box-sizing: border-box; box-sizing: border-box;
margin: auto; margin: auto;
margin-top: 2rem; padding: 96px 48px 40px 48px;
min-height: 450px; gap: 40px;
max-height: 75vh;
overflow-y: auto;
background: $white;
border-radius: 8px;
border: 1px solid $grey-6;
padding: 32px 24px 32px 48px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.resetPasswordForm {
display: flex;
flex-direction: column;
align-items: center;
h1,
p {
text-align: center;
margin: 0.5rem 0;
}
h1 {
@include font-bold-24;
}
p {
@include font-regular-14;
}
}
.form-group {
max-width: 320px;
margin-top: 2rem;
label { @media #{$phone} {
color: $grey-2; padding: 32px 16px 32px 16px;
}
.button {
margin-top: 20px;
} }
.form-input {
width: 320px; .title {
} display: flex;
.inputInvalid { flex-direction: column;
border-color: $orange-warning; gap: 16px;
text-align: center;
h1 {
@include font-bold-24;
}
p {
@include font-regular-18;
}
} }
.incorrectId {
@include font-regular-14; form {
color: $orange-warning; display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
.fields {
display: flex;
flex-direction: column;
gap: 16px;
.passwordConditions {
ul {
padding-left: 12px;
margin: 0.5rem 0;
}
li {
display: flex;
align-items: center;
color: $red-error;
gap: 8px;
&.valid {
color: $info-success;
}
}
}
}
.footer {
display: flex;
justify-content: center;
margin-top: 16px;
padding-top: 32px;
border-top: 1px solid $grey-6;
gap: 32px;
}
} }
} }
.footer {
width: 340px;
margin-top: 2rem;
}
import { Component, OnInit } from '@angular/core'; import { HttpErrorResponse } from '@angular/common/http';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { Component, Input } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router'; import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { AuthService } from '../services/auth.service'; import { AuthService } from '../services/auth.service';
import { NotificationService } from '../services/notification.service'; import { NotificationService } from '../services/notification.service';
import { MustMatch } from '../shared/validator/form';
import { CustomRegExp } from '../utils/CustomRegExp';
@Component({ @Component({
selector: 'app-reset-password', selector: 'app-password-form',
templateUrl: './reset-password.component.html', templateUrl: './reset-password.component.html',
styleUrls: ['./reset-password.component.scss'], styleUrls: ['./reset-password.component.scss'],
}) })
export class ResetPasswordComponent implements OnInit { export class ResetPasswordComponent {
public resetForm: UntypedFormGroup; @Input({ required: true }) token: string;
public loading = false;
public submitted = false; public resetPasswordForm = new FormGroup(
public token: string; {
password: new FormControl('', [Validators.required, Validators.pattern(CustomRegExp.PASSWORD)]),
confirmPassword: new FormControl('', [Validators.required, Validators.pattern(CustomRegExp.PASSWORD)]),
},
{ validators: MustMatch('password', 'confirmPassword') },
);
public loading: boolean;
constructor( constructor(
private formBuilder: UntypedFormBuilder,
private authService: AuthService,
private router: Router, private router: Router,
private authService: AuthService,
private notificationService: NotificationService, private notificationService: NotificationService,
private activatedRoute: ActivatedRoute,
) {} ) {}
ngOnInit(): void { /** Getter for password control */
this.activatedRoute.queryParams.subscribe((params) => { get password(): AbstractControl<string, string> {
this.token = params.token; return this.resetPasswordForm.get('password');
});
this.resetForm = this.formBuilder.group({
email: ['', Validators.required],
});
} }
// getter for form fields /** Getter for confirmPassword control */
get f(): Record<string, AbstractControl> { get confirmPassword(): AbstractControl<string, string> {
return this.resetForm.controls; return this.resetPasswordForm.get('confirmPassword');
} }
public onSubmit(): void { public checkIfPasswordHasEnoughChar(password: string): boolean {
this.submitted = true; return password.length >= 8;
}
public checkIfPasswordHasSpecialChar(password: string): boolean {
return Boolean(RegExp(CustomRegExp.SPECHAR).exec(password));
}
public checkIfPasswordHasDigit(password: string): boolean {
return Boolean(RegExp(CustomRegExp.DIGIT).exec(password));
}
public checkIfPasswordHasUpperCase(password: string): boolean {
return Boolean(RegExp(CustomRegExp.UPPERCASE).exec(password));
}
public checkIfPasswordHasLowerCase(password: string): boolean {
return Boolean(RegExp(CustomRegExp.LOWERCASE).exec(password));
}
public passwordIsValid(password: string): boolean {
return (
this.checkIfPasswordHasEnoughChar(password) &&
this.checkIfPasswordHasSpecialChar(password) &&
this.checkIfPasswordHasDigit(password) &&
this.checkIfPasswordHasUpperCase(password) &&
this.checkIfPasswordHasLowerCase(password)
);
}
public onSubmit(): void {
// stop here if form is invalid // stop here if form is invalid
if (this.resetForm.invalid) { if (this.resetPasswordForm.invalid) return;
return;
}
this.loading = true; this.loading = true;
this.authService.resetPassword(this.f.email.value).subscribe({ this.authService.resetPasswordApply(this.token, this.resetPasswordForm.value.password).subscribe({
next: () => { next: () => {
this.notificationService.showSuccess( this.notificationService.showSuccess('Votre mot de passe a été réinitialisé avec succès.');
'Un mail de confirmation de modification de votre mot de passe vous a été envoyé.', },
); error: (error: HttpErrorResponse) => {
this.router.navigate(['/login']); this.loading = false;
if (error.status === 401) {
this.notificationService.showError('Lien de réinitialisation de mot de passe invalide');
} else {
this.notificationService.showError('Échec de la réinitialisation de votre mot de passe');
}
}, },
complete: () => { complete: () => {
this.loading = false; this.loading = false;
this.router.navigate(['']);
}, },
}); });
} }
public goLogin(): void {
this.router.navigateByUrl('/login');
}
} }
...@@ -20,7 +20,6 @@ import { InputComponent } from './input/input.component'; ...@@ -20,7 +20,6 @@ import { InputComponent } from './input/input.component';
import { LogoCardComponent } from './logo-card/logo-card.component'; import { LogoCardComponent } from './logo-card/logo-card.component';
import { MemberCardComponent } from './member-card/member-card.component'; import { MemberCardComponent } from './member-card/member-card.component';
import { ModalComponent } from './modal/modal.component'; import { ModalComponent } from './modal/modal.component';
import { PasswordFormComponent } from './password-form/password-form.component';
import { RadioOptionComponent } from './radio-option/radio-option.component'; import { RadioOptionComponent } from './radio-option/radio-option.component';
import { RadioComponent } from './radio/radio.component'; import { RadioComponent } from './radio/radio.component';
import { SearchBarComponent } from './search-bar/search-bar.component'; import { SearchBarComponent } from './search-bar/search-bar.component';
...@@ -50,7 +49,6 @@ export { ...@@ -50,7 +49,6 @@ export {
LogoCardComponent, LogoCardComponent,
MemberCardComponent, MemberCardComponent,
ModalComponent, ModalComponent,
PasswordFormComponent,
ProgressBarComponent, ProgressBarComponent,
RadioOptionComponent, RadioOptionComponent,
StructureDetailPrintComponent, StructureDetailPrintComponent,
...@@ -85,7 +83,6 @@ export const SharedComponents = [ ...@@ -85,7 +83,6 @@ export const SharedComponents = [
MemberCardComponent, MemberCardComponent,
LogoCardComponent, LogoCardComponent,
ModalComponent, ModalComponent,
PasswordFormComponent,
ProgressBarComponent, ProgressBarComponent,
RadioOptionComponent, RadioOptionComponent,
RadioComponent, RadioComponent,
......
<div class="content">
<div class="resetPage">
<h1>Réinitialisation du mot de passe</h1>
<form [formGroup]="accountForm" (ngSubmit)="onSubmitPassword()">
<div *ngIf="oldPasswordNeeded" class="form-group" fxLayout="column">
<label for="oldPassword">Ancien mot de passe</label>
<div fxLayout="row" fxLayoutGap="13px">
<input
formControlName="oldPassword"
class="form-input password"
autocomplete="on"
[type]="isShowOldPassword ? 'text' : 'password'"
/>
<app-svg-icon
tabindex="0"
[folder]="'form'"
[iconClass]="'grey'"
[icon]="'visibility'"
(click)="showOldPassword()"
(keyup.enter)="showOldPassword()"
/>
<app-svg-icon
*ngIf="!checkOldPassword(accountForm.value.oldPassword)"
[folder]="'form'"
[icon]="'notValidate'"
/>
</div>
<p *ngIf="passwordError" class="special invalid">Votre ancien mot de passe est incorrect.</p>
</div>
<div class="form-group" fxLayout="column">
<label for="password"> Le mot de passe doit contenir au minimum :</label>
<ul>
<li
class=""
[ngClass]="{
invalid: accountForm.get('password').value.length < 8,
valid: accountForm.get('password').value.length >= 8
}"
>
<app-svg-icon
*ngIf="accountForm.get('password').value.length >= 8"
[iconClass]="'validation-small'"
[folder]="'form'"
[icon]="'validate'"
/>
<app-svg-icon
*ngIf="accountForm.get('password').value.length < 8"
[iconClass]="'validation-small'"
[folder]="'form'"
[icon]="'notValidate'"
/>
<p>8 caractères</p>
</li>
<li
[ngClass]="{
invalid: !checkIfPasswordHasSpecialChar(accountForm.get('password').value),
valid: checkIfPasswordHasSpecialChar(accountForm.get('password').value)
}"
>
<app-svg-icon
*ngIf="checkIfPasswordHasSpecialChar(accountForm.get('password').value)"
[iconClass]="'validation-small'"
[folder]="'form'"
[icon]="'validate'"
/>
<app-svg-icon
*ngIf="!checkIfPasswordHasSpecialChar(accountForm.get('password').value)"
[iconClass]="'validation-small'"
[folder]="'form'"
[icon]="'notValidate'"
/>
<p>un caractère spécial</p>
</li>
<li
[ngClass]="{
invalid: !checkIfPasswordHasLowerCase(accountForm.get('password').value),
valid: checkIfPasswordHasLowerCase(accountForm.get('password').value)
}"
>
<app-svg-icon
*ngIf="checkIfPasswordHasLowerCase(accountForm.get('password').value)"
[iconClass]="'validation-small'"
[folder]="'form'"
[icon]="'validate'"
/>
<app-svg-icon
*ngIf="!checkIfPasswordHasLowerCase(accountForm.get('password').value)"
[iconClass]="'validation-small'"
[folder]="'form'"
[icon]="'notValidate'"
/>
<p>un caractère en minuscule</p>
</li>
<li
[ngClass]="{
invalid: !checkIfPasswordHasUpperCase(accountForm.get('password').value),
valid: checkIfPasswordHasUpperCase(accountForm.get('password').value)
}"
>
<app-svg-icon
*ngIf="checkIfPasswordHasUpperCase(accountForm.get('password').value)"
[iconClass]="'validation-small'"
[folder]="'form'"
[icon]="'validate'"
/>
<app-svg-icon
*ngIf="!checkIfPasswordHasUpperCase(accountForm.get('password').value)"
[iconClass]="'validation-small'"
[folder]="'form'"
[icon]="'notValidate'"
/>
<p>un caractère en majuscule</p>
</li>
<li
[ngClass]="{
invalid: !checkIfPasswordHasDigit(accountForm.get('password').value),
valid: checkIfPasswordHasDigit(accountForm.get('password').value)
}"
>
<app-svg-icon
*ngIf="checkIfPasswordHasDigit(accountForm.get('password').value)"
[iconClass]="'validation-small'"
[folder]="'form'"
[icon]="'validate'"
/>
<app-svg-icon
*ngIf="!checkIfPasswordHasDigit(accountForm.get('password').value)"
[iconClass]="'validation-small'"
[folder]="'form'"
[icon]="'notValidate'"
/>
<p>un chiffre</p>
</li>
</ul>
<div fxLayout="row" fxLayoutAlign="none center" fxLayoutGap="13px">
<input
formControlName="password"
class="form-input password"
autocomplete="on"
[type]="isShowPassword ? 'text' : 'password'"
/>
<app-svg-icon
tabindex="0"
[iconClass]="'validation grey hover'"
[folder]="'form'"
[icon]="'visibility'"
(click)="showPassword()"
(keyup.enter)="showPassword()"
/>
<app-svg-icon
*ngIf="accountForm.get('password').valid"
[iconClass]="'validation'"
[folder]="'form'"
[icon]="'validate'"
/>
<app-svg-icon
*ngIf="accountForm.get('password').invalid && accountForm.get('password').value"
[iconClass]="'validation'"
[folder]="'form'"
[icon]="'notValidate'"
/>
</div>
</div>
<div class="form-group" fxLayout="column">
<label for="confirmPassword">Vérification du mot de passe</label>
<div fxLayout="row" fxLayoutAlign="none center" fxLayoutGap="13px">
<input
formControlName="confirmPassword"
class="form-input password"
autocomplete="on"
[type]="isShowConfirmPassword ? 'text' : 'password'"
/>
<app-svg-icon
tabindex="0"
[iconClass]="'validation grey hover'"
[folder]="'form'"
[icon]="'visibility'"
(click)="showConfirmPassword()"
(keyup.enter)="showConfirmPassword()"
/>
<app-svg-icon
*ngIf="accountForm.get('confirmPassword').valid && accountForm.get('confirmPassword').value"
[iconClass]="'validation'"
[folder]="'form'"
[icon]="'validate'"
/>
<app-svg-icon
*ngIf="accountForm.get('confirmPassword').invalid && accountForm.get('confirmPassword').value"
[iconClass]="'validation'"
[folder]="'form'"
[icon]="'notValidate'"
/>
</div>
</div>
<div class="form-group" fxLayout="row" fxLayoutAlign="center center" fxLayoutGap="20px">
<app-button [variant]="'secondary'" [label]="'Annuler'" (action)="goHome()" />
<app-button
[type]="'submit'"
[disabled]="
accountForm.get('confirmPassword').invalid ||
accountForm.get('password').invalid ||
(oldPasswordNeeded && passwordError)
"
[variant]="'primary'"
[label]="'Envoyer'"
/>
</div>
</form>
</div>
</div>
@import 'color';
@import 'layout';
@import 'breakpoint';
@import 'typography';
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
.resetPage {
width: 100%;
max-width: 1000px;
box-sizing: border-box;
margin: auto;
min-height: 450px;
max-height: 75vh;
overflow-y: auto;
color: $grey-1;
background: $white;
border-radius: 8px;
border: 1px solid $grey-6;
padding: 1.5rem 2.5rem;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
h1 {
@include font-bold-24;
}
.form-group {
margin-bottom: 20px;
label {
color: $grey-2;
}
.resetPasswordForm {
max-width: 500px;
}
.button {
margin-top: 20px;
}
ul {
padding-left: 0;
margin: 0.5rem 0;
}
li {
display: flex;
margin-left: 1%;
align-items: center;
p {
margin: 0 8px;
}
&.valid {
color: $green;
}
}
.special {
margin: 0;
}
.invalid {
color: $orange-warning;
}
}
import { Component, OnInit } from '@angular/core';
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { ProfileService } from '../../../profile/services/profile.service';
import { AuthService } from '../../../services/auth.service';
import { NotificationService } from '../../../services/notification.service';
import { CustomRegExp } from '../../../utils/CustomRegExp';
import { MustMatch } from '../../validator/form';
@Component({
selector: 'app-password-form',
templateUrl: './password-form.component.html',
styleUrls: ['./password-form.component.scss'],
})
export class PasswordFormComponent implements OnInit {
public accountForm: UntypedFormGroup;
public token: string;
public passwordError = false;
// Condition form
public isShowOldPassword = false;
public isShowConfirmPassword = false;
public isShowPassword = false;
// Form output
public oldPasswordNeeded = false;
constructor(
private formBuilder: UntypedFormBuilder,
private router: Router,
private auth: AuthService,
private activatedRoute: ActivatedRoute,
private authService: AuthService,
private profileService: ProfileService,
private notificationService: NotificationService,
) {}
ngOnInit(): void {
this.activatedRoute.queryParams.subscribe((params) => {
this.token = params.token;
});
if (this.auth.isLoggedIn()) {
this.oldPasswordNeeded = true;
}
this.initPasswordForm();
}
private initPasswordForm(): void {
if (!this.oldPasswordNeeded) {
this.accountForm = this.formBuilder.group(
{
password: ['', [Validators.required, Validators.pattern(CustomRegExp.PASSWORD)]],
confirmPassword: [''],
},
{ validator: MustMatch('password', 'confirmPassword') },
);
} else {
this.accountForm = this.formBuilder.group(
{
oldPassword: ['', [Validators.required, Validators.pattern(CustomRegExp.PASSWORD)]],
password: ['', [Validators.required, Validators.pattern(CustomRegExp.PASSWORD)]],
confirmPassword: [''],
},
{ validator: MustMatch('password', 'confirmPassword') },
);
}
}
get fPassword(): Record<string, AbstractControl> {
return this.accountForm.controls;
}
public showPassword(): void {
this.isShowPassword = !this.isShowPassword;
}
public showConfirmPassword(): void {
this.isShowConfirmPassword = !this.isShowConfirmPassword;
}
public showOldPassword(): void {
this.isShowOldPassword = !this.isShowOldPassword;
}
public checkIfPasswordHasSpecialChar(password: string): boolean {
return Boolean(password.match(CustomRegExp.SPECHAR));
}
public checkIfPasswordHasDigit(password: string): boolean {
return Boolean(password.match(CustomRegExp.DIGIT));
}
public checkIfPasswordHasUpperCase(password: string): boolean {
return Boolean(password.match(CustomRegExp.UPPERCASE));
}
public checkIfPasswordHasLowerCase(password: string): boolean {
return Boolean(password.match(CustomRegExp.LOWERCASE));
}
public checkOldPassword(password: string): boolean {
if (
password !== '' &&
(!this.checkIfPasswordHasSpecialChar(password) ||
!this.checkIfPasswordHasDigit(password) ||
!this.checkIfPasswordHasUpperCase(password) ||
!this.checkIfPasswordHasLowerCase(password))
) {
return false;
} else return true;
}
public onSubmitPassword(): void {
// stop here if form is invalid
if (this.oldPasswordNeeded && !this.checkOldPassword(this.accountForm.value.oldPassword)) {
this.passwordError = true;
} else if (this.oldPasswordNeeded) {
// stop here if form is invalid
this.passwordError = false;
this.profileService
.changePassword(this.accountForm.value.password, this.accountForm.value.oldPassword)
.subscribe({
next: () => {
this.notificationService.showSuccess(
'Votre mot de passe a été réinitialisé avec succès.',
'Veuillez vous connecter',
);
this.passwordError = false;
},
error: () => {
this.notificationService.showError('Échec de la réinitialisation de votre mot de passe');
this.passwordError = true;
},
complete: () => {
this.router.navigate(['/login']);
},
});
} else {
this.authService.resetPasswordApply(this.token, this.accountForm.value.password).subscribe({
next: () => {
this.notificationService.showSuccess('Votre mot de passe a été réinitialisé avec succès.');
},
error: () => {
this.notificationService.showError('Échec de la réinitialisation de votre mot de passe');
},
complete: () => {
this.router.navigate(['']);
},
});
}
}
public goHome(): void {
this.router.navigateByUrl('news');
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment