Refactor SentComponent to VerifyMailDialogComponent for improved clarity and usability in email verification flow.

This commit is contained in:
2025-08-23 22:34:08 +02:00
parent 4ccce7e190
commit 523bf3d43f
4 changed files with 7 additions and 7 deletions
@@ -1,48 +0,0 @@
<h2 mat-dialog-title>Email Verification</h2>
<div mat-dialog-content>
<p>Please enter the 6-character verification code sent to: <strong>{{ email }}</strong></p>
<form [formGroup]="form">
<mat-form-field appearance="fill" style="width: 100%;">
<mat-label>Verification Code</mat-label>
<input matInput formControlName="code" placeholder="Enter 6-character code">
@if (form.controls.code.invalid && form.controls.code.touched) {
<mat-error>
@if (form.controls.code.errors?.['required']) {
Verification code is required
} @else if (form.controls.code.errors?.['minlength'] || form.controls.code.errors?.['maxlength']) {
Code must be exactly 6 characters
} @else {
Please enter the 6-character code we sent you.
}
</mat-error>
}
</mat-form-field>
</form>
@if (mailVerified()) {
<p class="success-message">Email verified successfully!</p>
}
</div>
<div mat-dialog-actions align="end">
<button mat-button (click)="onCancel()">Cancel</button>
<button mat-button
color="accent"
(click)="onResend()"
[disabled]="resendCooldown()">
@if (resendCooldown()) {
Resend ({{ cooldownSeconds() }}s)
} @else {
Resend Code
}
</button>
<button mat-flat-button
color="primary"
(click)="onSubmit()"
[disabled]="form.invalid">
Submit
</button>
</div>
@@ -1,23 +0,0 @@
:host {
display: block;
}
.mat-dialog-content {
min-height: 120px;
max-width: 400px;
}
.success-message {
color: #4caf50;
font-weight: 500;
margin-top: 16px;
}
mat-form-field {
width: 100%;
margin-bottom: 16px;
}
button {
margin-left: 8px;
}
@@ -1,161 +0,0 @@
import {Component, Inject, inject, input, signal} from '@angular/core';
import {FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators} from '@angular/forms';
import {MatInput, MatLabel} from '@angular/material/input';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MailService, SubmitEmail, VerifyCode} from '@api';
import {AuthService} from '@services/auth.service';
import {MatButtonModule} from '@angular/material/button';
import {
MAT_DIALOG_DATA,
MatDialogActions,
MatDialogContent,
MatDialogRef,
MatDialogTitle
} from '@angular/material/dialog';
import {interval, Subscription} from 'rxjs';
@Component({
selector: 'app-sent',
imports: [
FormsModule,
MatFormFieldModule,
MatInput,
MatLabel,
ReactiveFormsModule,
MatButtonModule,
MatDialogTitle,
MatDialogContent,
MatDialogActions
],
templateUrl: './sent.component.html',
styleUrl: './sent.component.scss'
})
export class SentComponent {
protected form: FormGroup<VerifyMail>;
protected readonly completionMessage = input<string>("Thank you for completing your form!");
protected readonly verifyMail = input<VerifyMailData | null>(null);
protected mailVerified = signal<boolean>(false);
// For resend cooldown
protected resendCooldown = signal<boolean>(false);
protected cooldownSeconds = signal<number>(60);
private cooldownSubscription: Subscription | null = null;
private mailService = inject(MailService);
private authService = inject(AuthService);
protected readonly email: string;
constructor(
public dialogRef: MatDialogRef<SentComponent>,
@Inject(MAT_DIALOG_DATA) public data: InputMail
) {
this.form = new FormGroup({
code: new FormControl('', {
nonNullable: true,
validators: [Validators.required, Validators.minLength(6), Validators.maxLength(6)]
})
});
this.email = data.email;
this.mailService.submitEmailForVerification({email: this.email.toLowerCase()}).subscribe();
}
public onSubmit() {
if (this.form === undefined) {
console.error('Form is undefined');
return;
}
if (this.form.valid) {
this.sendForm();
} else {
Object.keys(this.form.controls).forEach(field => {
const control = this.form!.get(field);
control?.markAsTouched({onlySelf: true});
});
}
}
public onCancel() {
this.dialogRef.close(false);
}
public onResend() {
if (this.resendCooldown()) {
return;
}
const submitEmail: SubmitEmail = {
email: this.email
};
this.mailService.resendVerificationEmail(submitEmail).subscribe({
next: (response) => {
this.startResendCooldown();
},
error: (error) => {
console.error('Error resending verification email', error);
}
});
}
private startResendCooldown() {
this.resendCooldown.set(true);
this.cooldownSeconds.set(60);
if (this.cooldownSubscription) {
this.cooldownSubscription.unsubscribe();
}
this.cooldownSubscription = interval(1000).subscribe(() => {
const currentSeconds = this.cooldownSeconds();
if (currentSeconds <= 1) {
this.resendCooldown.set(false);
this.cooldownSubscription?.unsubscribe();
this.cooldownSubscription = null;
} else {
this.cooldownSeconds.set(currentSeconds - 1);
}
});
}
private sendForm() {
const rawValue = this.form.getRawValue();
if (this.authService.isAuthenticated$()) {
const form: VerifyCode = {
code: rawValue.code,
};
this.mailService.verifyEmailCode(form).subscribe({
next: (mailResponse) => {
this.mailVerified.set(mailResponse.verified);
if (mailResponse.verified) {
this.dialogRef.close(true);
}
},
error: (error) => {
console.error('Error verifying email code', error);
}
});
} else {
throw new Error('User not logged in');
}
}
ngOnDestroy() {
if (this.cooldownSubscription) {
this.cooldownSubscription.unsubscribe();
}
}
}
interface VerifyMail {
code: FormControl<string>;
}
interface VerifyMailData {
verified: boolean;
mail: string;
}
interface InputMail {
email: string;
}