import {
ChangeDetectionStrategy,
Component,
computed,
HostListener,
inject,
input,
output,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import {
passwordMatchValidator,
PasswordPolicy,
} from './change-password-modal.validators';
export type ChangePasswordMode = 'self' | 'admin-reset';
export interface ChangePasswordSubmitPayload {
oldPassword: string;
newPassword: string;
confirmNewPassword: string;
}
const DEFAULT_POLICY: PasswordPolicy = {
minLength: 12,
requireMixed: true,
description: 'At least 12 characters with upper, lower, digit and symbol',
};
@Component({
selector: 'app-change-password-modal',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, ReactiveFormsModule],
template: `
@if (open()) {
}
`,
})
export class ChangePasswordModalComponent {
private readonly fb = inject(FormBuilder);
readonly open = input(false);
readonly mode = input('self');
readonly policy = input(DEFAULT_POLICY);
readonly errorMessage = input(null);
readonly submitting = input(false);
readonly fieldErrors = input | null>(null);
readonly cancel = output();
readonly submit = output();
readonly form = this.fb.nonNullable.group(
{
oldPassword: this.fb.nonNullable.control(''),
newPassword: this.fb.nonNullable.control('', [Validators.required]),
confirmNewPassword: this.fb.nonNullable.control('', [Validators.required]),
},
{ validators: passwordMatchValidator },
);
readonly formError = computed(() => {
const errs = this.form.errors;
if (errs?.['passwordMismatch']) return 'Passwords do not match';
return null;
});
fieldErrorFor(path: string): string | null {
const map = this.fieldErrors();
if (!map) return null;
return map[path] ?? null;
}
@HostListener('document:keydown.escape')
onEscape(): void {
if (this.open() && !this.submitting()) this.onCancel();
}
onCancel(): void {
if (this.submitting()) return;
this.form.reset({ oldPassword: '', newPassword: '', confirmNewPassword: '' });
this.cancel.emit();
}
onSubmit(): void {
if (this.submitting()) return;
const v = this.form.getRawValue();
if (this.mode() === 'self' && !v.oldPassword) return;
if (!v.newPassword || !v.confirmNewPassword) return;
if (this.form.invalid) return;
this.submit.emit({
oldPassword: v.oldPassword,
newPassword: v.newPassword,
confirmNewPassword: v.confirmNewPassword,
});
}
}