feat: create EmailRequestComponent and integrate into ForgotPasswordComponent to separate responsibilities

This commit is contained in:
Chneemann 2025-05-07 10:52:28 +02:00
parent 927e58dd10
commit 14bb6c520c
6 changed files with 143 additions and 43 deletions

View file

@ -0,0 +1,36 @@
<div class="note">
<p>We will send you an email with instructions to reset your password.</p>
</div>
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div class="email-field">
<input
formControlName="email"
type="email"
id="email"
placeholder="Email Address"
autocomplete="email"
[class.error-border]="
form.controls['email'].invalid && form.controls['email'].touched
"
/>
<img class="email-icon" src="./assets/img/email.svg" />
</div>
<div class="error-container">
@if (form.controls['email'].touched && form.controls['email'].invalid) {
<div class="error-msg">
@if (form.controls['email'].errors?.['required']) {
<p role="alert">Please enter your email</p>
} @if (form.controls['email'].errors?.['invalidEmailFormat']) {
<p role="alert">This is not a valid email format</p>
}
</div>
}
</div>
<app-btn-large
[value]="'Send Email'"
[disabled]="form.invalid || form.disabled"
></app-btn-large>
</form>

View file

@ -0,0 +1,3 @@
@use "./../../../../../assets/style/backgrounds.scss" as *;
@use "./../../../../../assets/style/form.scss" as *;
@use "./../../../../../assets/style/auth-layout.scss" as *;

View file

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

View file

@ -0,0 +1,66 @@
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { BtnLargeComponent } from '../../../../shared/components/buttons/btn-large/btn-large.component';
import {
FormBuilder,
FormGroup,
FormsModule,
ReactiveFormsModule,
Validators,
} from '@angular/forms';
import { ErrorService } from '../../../../services/error.service';
import { AuthService } from '../../../../services/auth.service';
import { emailFormatValidator } from '../../../../validators/email-format.validator';
@Component({
selector: 'app-email-request',
imports: [BtnLargeComponent, FormsModule, ReactiveFormsModule],
templateUrl: './email-request.component.html',
styleUrl: './email-request.component.scss',
})
export class EmailRequestComponent implements OnInit {
@Output() submittedChange = new EventEmitter<boolean>();
form: FormGroup = new FormGroup({});
constructor(
private errorService: ErrorService,
private authService: AuthService,
private fb: FormBuilder
) {}
ngOnInit(): void {
this.createForm();
}
async onSubmit(): Promise<void> {
if (this.form.valid) {
const body = this.createFormRequestBody();
this.form.disable();
try {
await this.authService.forgotPassword(body);
this.emitFormSubmitted();
} catch (error) {
this.errorService.handleError(error);
} finally {
this.form.enable();
}
}
}
private createForm(): void {
this.form = this.fb.group({
email: ['', [Validators.required, emailFormatValidator()]],
});
}
private createFormRequestBody(): { email: string } {
return {
email: this.form.value.email.toLowerCase(),
};
}
private emitFormSubmitted(): void {
this.submittedChange.emit(true);
}
}

View file

@ -2,48 +2,9 @@
<div class="content">
<div class="headline">Forgot your password?</div>
@if (!queryEmail && !sendEmailSuccess && !queryEmailSuccess) {
<div class="note">
<p>We will send you an email with instructions to reset your password.</p>
</div>
<form
#taskForm="ngForm"
(ngSubmit)="onSubmit(taskForm, email)"
onsubmit="return false"
>
<div class="email-field">
<input
type="email"
id="email"
name="email"
#email="ngModel"
placeholder="Email Address"
class="custom-input"
autocomplete="email"
[(ngModel)]="authData.email"
[class.error-border]="
(!email.valid && email.touched) ||
(email.touched &&
!isUserEmailValid(authData.email.toLowerCase()) &&
authData.email.length > 0)
"
(click)="this.errorService.clearError()"
required
/>
<img class="email-icon" src="./assets/img/email.svg" />
</div>
<div class="error-msg">
@if (!email.valid && email.touched) {
<p>Please enter your email</p>
} @else { @if (email.touched && authData.email.length > 0 &&
!isUserEmailValid(authData.email.toLowerCase())) {
<p>This is not a valid email format</p>
}}
</div>
<app-btn-large
[value]="'Send Email'"
[disabled]="!isUserEmailValid(authData.email) || authData.send"
></app-btn-large>
</form>
<app-email-request
(submittedChange)="submittedChange($event)"
></app-email-request>
} @else { @if (sendEmailSuccess) {
<div class="note">
<p>

View file

@ -5,11 +5,18 @@ import { FormsModule, NgForm } from '@angular/forms';
import { ActivatedRoute, Params, RouterLink } from '@angular/router';
import { AuthService } from '../../../services/auth.service';
import { ErrorService } from '../../../services/error.service';
import { EmailRequestComponent } from './email-request/email-request.component';
@Component({
selector: 'app-forgot-password',
standalone: true,
imports: [CommonModule, BtnLargeComponent, FormsModule, RouterLink],
imports: [
CommonModule,
BtnLargeComponent,
FormsModule,
RouterLink,
EmailRequestComponent,
],
templateUrl: './forgot-password.component.html',
styleUrl: './forgot-password.component.scss',
})
@ -43,6 +50,10 @@ export class ForgotPasswordComponent implements OnInit {
this.handleQueryParams();
}
submittedChange(value: boolean): void {
this.sendEmailSuccess = value;
}
/**
* Subscribes to query parameters and sets internal flags based on them.
*/