refactor: put the input password in a separate component
Some checks failed
Build and Deploy Angular App / build (push) Failing after 1m17s

This commit is contained in:
2024-12-23 06:41:28 +03:00
parent 6e914caabc
commit 7830c5f21d
7 changed files with 153 additions and 121 deletions

View File

@ -0,0 +1,45 @@
<div [formGroup]="formGroup">
<mat-form-field color="accent">
<mat-label>Пароль</mat-label>
<input matInput
matTooltip="Укажите пароль"
formControlName="password"
required
[type]="hidePass ? 'password' : 'text'"
id="passwordNextFocus"
focusNext="focusNext">
<button mat-icon-button matSuffix (click)="togglePassword($event)" [attr.aria-label]="'Hide password'"
[attr.aria-pressed]="hidePass">
<mat-icon>{{ hidePass ? 'visibility_off' : 'visibility' }}</mat-icon>
</button>
@if (formGroup.get('password')?.hasError('required')) {
<mat-error>
Пароль является <i>обязательным</i>
</mat-error>
}
@if (formGroup.get('password')?.hasError('minlength')) {
<mat-error>
Пароль должен быть не менее {{ policy.minimumLength }} символов
</mat-error>
}
@if (formGroup.get('password')?.hasError('pattern')) {
<mat-error>
Пароль должен содержать:
@if (policy.requireLettersDifferentCase) {
Латинские символы разных регистров
} @else if (policy.requireLetter) {
Один латинский символ
} @else if (policy.requireDigit) {
Одну цифру
}
@if (policy.requireSpecialCharacter) {
Специальный символ
}
</mat-error>
}
</mat-form-field>
</div>

View File

@ -0,0 +1,77 @@
import {Component, Input} from '@angular/core';
import {MatFormFieldModule} from "@angular/material/form-field";
import {MatInput} from "@angular/material/input";
import {MatIconButton} from "@angular/material/button";
import {FormGroup, ReactiveFormsModule, ValidatorFn, Validators} from "@angular/forms";
import {MatSelectModule} from "@angular/material/select";
import {MatTooltip} from "@angular/material/tooltip";
import {MatIcon} from "@angular/material/icon";
import {PasswordPolicy} from "@model/passwordPolicy";
import SecurityService from "@api/v1/securityService";
import {FocusNextDirective} from "@/directives/focus-next.directive";
import SetupService from "@api/v1/setup.service";
@Component({
selector: 'password-input',
imports: [
ReactiveFormsModule,
MatFormFieldModule,
MatSelectModule,
MatInput,
MatTooltip,
MatIconButton,
MatIcon,
FocusNextDirective
],
templateUrl: './password-input.component.html',
styleUrl: './password-input.component.css',
providers: [SecurityService, SetupService]
})
export class PasswordInputComponent {
protected hidePass = true;
protected policy!: PasswordPolicy;
@Input() formGroup!: FormGroup;
@Input() focusNext: string | undefined;
@Input() isSetupMode: boolean = false;
constructor(securityApi: SecurityService, setupApi: SetupService) {
if (this.isSetupMode)
setupApi.passwordPolicyConfiguration().subscribe(policy => {
this.policy = policy;
this.updateValueAndValidity(policy);
});
else
securityApi.passwordPolicy().subscribe(policy => {
this.policy = policy;
this.updateValueAndValidity(policy);
});
}
private updateValueAndValidity(policy: PasswordPolicy): void {
const validators: ValidatorFn[] = [Validators.required];
if (policy.minimumLength) {
validators.push(Validators.minLength(policy.minimumLength));
}
if (policy.requireLettersDifferentCase) {
validators.push(Validators.pattern(/(?=.*[a-z])(?=.*[A-Z])/));
} else if (policy.requireLetter) {
validators.push(Validators.pattern(/[A-Za-z]/));
} else if (policy.requireDigit) {
validators.push(Validators.pattern(/\d/));
}
if (policy.requireSpecialCharacter) {
validators.push(Validators.pattern(/[!@#$%^&*(),.?":{}|<>]/));
}
this.formGroup.get('password')?.setValidators(validators);
this.formGroup.get('password')?.updateValueAndValidity();
}
protected togglePassword(event: MouseEvent) {
this.hidePass = !this.hidePass;
event.stopPropagation();
}
}