From 3b70e23da04fd7abe2636dd0c29e9c77934bd239 Mon Sep 17 00:00:00 2001 From: Mazdak Gibran <141390141+mazdakgibran@users.noreply.github.com> Date: Tue, 27 Jan 2026 11:29:39 +0500 Subject: [PATCH] Add reset password modal to user management Introduced a new ResetPasswordModalComponent for resetting user passwords from the setup user page. Updated the setup-user component and template to include a reset password button and modal, and refactored password-hide-show to support resetting its state. Also adjusted reset-password component to enable userId input. --- .../password-hide-show.component.ts | 5 +- .../reset-password-modal.component.html | 78 ++++++++++++ .../reset-password-modal.component.scss | 0 .../reset-password-modal.component.spec.ts | 23 ++++ .../reset-password-modal.component.ts | 112 ++++++++++++++++++ .../reset-password.component.ts | 2 +- .../setup-user/setup-user.component.html | 13 +- .../setup-user/setup-user.component.ts | 20 +++- 8 files changed, 244 insertions(+), 9 deletions(-) create mode 100644 src/app/user-management/reset-password-modal/reset-password-modal.component.html create mode 100644 src/app/user-management/reset-password-modal/reset-password-modal.component.scss create mode 100644 src/app/user-management/reset-password-modal/reset-password-modal.component.spec.ts create mode 100644 src/app/user-management/reset-password-modal/reset-password-modal.component.ts diff --git a/src/app/shared/components/password-hide-show/password-hide-show.component.ts b/src/app/shared/components/password-hide-show/password-hide-show.component.ts index c937edd..601af4d 100644 --- a/src/app/shared/components/password-hide-show/password-hide-show.component.ts +++ b/src/app/shared/components/password-hide-show/password-hide-show.component.ts @@ -13,7 +13,7 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms'; styleUrl: './password-hide-show.component.scss' }) export class PasswordHideShowComponent { -@Output() onEyeClick = new EventEmitter(); + @Output() onEyeClick = new EventEmitter(); @Input() showPassword : boolean = false; inputType : String = ''; constructor() { } @@ -26,4 +26,7 @@ export class PasswordHideShowComponent { this.showPassword = !this.showPassword; this.onEyeClick.emit(); } + reset() { + this.showPassword = true; + } } diff --git a/src/app/user-management/reset-password-modal/reset-password-modal.component.html b/src/app/user-management/reset-password-modal/reset-password-modal.component.html new file mode 100644 index 0000000..75546b7 --- /dev/null +++ b/src/app/user-management/reset-password-modal/reset-password-modal.component.html @@ -0,0 +1,78 @@ + diff --git a/src/app/user-management/reset-password-modal/reset-password-modal.component.scss b/src/app/user-management/reset-password-modal/reset-password-modal.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/user-management/reset-password-modal/reset-password-modal.component.spec.ts b/src/app/user-management/reset-password-modal/reset-password-modal.component.spec.ts new file mode 100644 index 0000000..ca43f40 --- /dev/null +++ b/src/app/user-management/reset-password-modal/reset-password-modal.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ResetPasswordModalComponent } from './reset-password-modal.component'; + +describe('ResetPasswordModalComponent', () => { + let component: ResetPasswordModalComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ResetPasswordModalComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ResetPasswordModalComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/user-management/reset-password-modal/reset-password-modal.component.ts b/src/app/user-management/reset-password-modal/reset-password-modal.component.ts new file mode 100644 index 0000000..602fb65 --- /dev/null +++ b/src/app/user-management/reset-password-modal/reset-password-modal.component.ts @@ -0,0 +1,112 @@ +import { Component, Input, OnInit, SimpleChanges, ViewChild } from '@angular/core'; +import { FormBuilder, FormGroup, Validators, AbstractControl, ValidationErrors, ReactiveFormsModule } from '@angular/forms'; +import { HttpURIService } from '../../app.http.uri.service'; +import { URIKey } from '../../utils/uri-enums'; +import { I18NService } from '../../services/i18n.service'; +import { StorageService } from '../../shared/services/storage.service'; +import { SuccessMessages } from '../../utils/enums'; +import { HttpErrorResponse } from '@angular/common/http'; +import { TranslateModule } from '@ngx-translate/core'; +import { CommonModule } from '@angular/common'; +import { PasswordHideShowComponent } from '../../shared/components/password-hide-show/password-hide-show.component'; + + +@Component({ + selector: 'app-reset-password-modal', + standalone: true, + imports: [TranslateModule, ReactiveFormsModule, CommonModule, PasswordHideShowComponent], + templateUrl: './reset-password-modal.component.html' +}) +export class ResetPasswordModalComponent implements OnInit { + newPasswordType: string = 'password' + confirmPasswordType: string = 'password' + @Input() userId!: string; + + resetPasswordForm!: FormGroup; + @ViewChild('newPasswordPsh') passwordHideShow?:PasswordHideShowComponent + @ViewChild('confirmPasswordPsh') confirmPasswordHideShow?:PasswordHideShowComponent + + constructor( + private fb: FormBuilder, + private httpURIService: HttpURIService, + private i18nService: I18NService, + private storageService: StorageService + ) {} + togglePasswordType() { + this.newPasswordType = this.passwordHideShow?.showPassword ? 'password' : 'text'; + } + toggleConfirmPasswordType() { + this.confirmPasswordType = this.confirmPasswordHideShow?.showPassword ? 'password' : 'text'; + } + ngOnInit(): void { + this.resetPasswordForm = this.fb.group({ + userId: [''], + newPassword: ['', [ + Validators.required, + Validators.minLength(8), + Validators.maxLength(20), + Validators.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&]).+$/) + ]], + confirmPassword: ['', Validators.required] + }, { validators: this.passwordMatchValidator }); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes['userId'] && this.resetPasswordForm) { + this.resetPasswordForm.reset({ + userId: this.userId, + newPassword: '', + confirmPassword: '' + }); + + this.newPasswordType = 'password'; + this.confirmPasswordType = 'password'; + + this.passwordHideShow?.reset(); + this.confirmPasswordHideShow?.reset(); + } +} + + + passwordMatchValidator(group: AbstractControl): ValidationErrors | null { + const newPassword = group.get('newPassword')?.value; + const confirmPassword = group.get('confirmPassword')?.value; + return newPassword === confirmPassword ? null : { passwordMismatch: true }; + } + + submit() { + if (this.resetPasswordForm.invalid) return; + + const payload = { + userId: this.userId, + newPassword: this.resetPasswordForm.get('newPassword')?.value, + porOrgaCode: this.storageService.getItem('POR_ORGACODE') + }; + + this.httpURIService.requestPOST(URIKey.RESET_PASSWORD_URI, payload) + .subscribe({ + next: (res) => { + if (!(res instanceof HttpErrorResponse)) { + this.i18nService.success(SuccessMessages.RESET_PASSWORD_SUCCESS, []); + this.closeModal(); + } + } + }); + } + + closeModal() { + this.resetPasswordForm.reset(); + this.newPasswordType = 'password'; + this.confirmPasswordType = 'password'; + + this.passwordHideShow?.reset(); + this.confirmPasswordHideShow?.reset(); + + const modal = document.getElementById('resetPasswordModal'); + modal?.classList.remove('show'); + modal?.setAttribute('aria-hidden', 'true'); + modal!.style.display = 'none'; + document.body.classList.remove('modal-open'); + document.querySelector('.modal-backdrop')?.remove(); + } +} diff --git a/src/app/user-management/reset-password/reset-password.component.ts b/src/app/user-management/reset-password/reset-password.component.ts index 99785ad..f82b82f 100644 --- a/src/app/user-management/reset-password/reset-password.component.ts +++ b/src/app/user-management/reset-password/reset-password.component.ts @@ -30,7 +30,7 @@ export class ResetPasswordComponent implements OnInit{ ngOnInit(): void { const userIdValue = this.storageService.getItem('USER_ID') this.resetPasswordForm = this.fb.group({ - userId: [{value: userIdValue || '', disabled: true}], + userId: [userIdValue], newPassword: ['', [ Validators.required, Validators.minLength(8), diff --git a/src/app/user-management/setup-user/setup-user.component.html b/src/app/user-management/setup-user/setup-user.component.html index 4948ea6..171dadf 100644 --- a/src/app/user-management/setup-user/setup-user.component.html +++ b/src/app/user-management/setup-user/setup-user.component.html @@ -253,10 +253,13 @@ - + + @@ -264,6 +267,8 @@ + +