feat: add current password field to change password form and update service payload structure

This commit is contained in:
2026-06-11 17:53:06 +03:30
parent b4cd4c05f2
commit 72954fb5d1
8 changed files with 74 additions and 25 deletions
@@ -1 +1,5 @@
<shared-change-password-form-dialog [(visible)]="visible" [loading]="submitLoading()" (onSubmit)="submit($event)" /> <shared-change-password-form-dialog
[(visible)]="visible"
[showCurrentPasswordField]="true"
[loading]="submitLoading()"
(onSubmit)="submit($event)" />
@@ -23,7 +23,7 @@ export class PosChangePasswordComponent extends AbstractDialog {
this.submitLoading.set(true); this.submitLoading.set(true);
this.service this.service
.changePassword(payload.password) .changePassword(payload)
.pipe(finalize(() => this.submitLoading.set(false))) .pipe(finalize(() => this.submitLoading.set(false)))
.subscribe(() => { .subscribe(() => {
this.toastService.success({ this.toastService.success({
+7 -2
View File
@@ -2,13 +2,18 @@ import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
interface IChangePasswordSubmitPayload {
currentPassword: string;
password: string;
}
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
}) })
export class PosChangePasswordService { export class PosChangePasswordService {
constructor(private readonly http: HttpClient) {} constructor(private readonly http: HttpClient) {}
changePassword(password: string): Observable<unknown> { changePassword(payload: IChangePasswordSubmitPayload): Observable<unknown> {
return this.http.put('/api/v1/pos/update-password', { password }); return this.http.put('/api/v1/pos/update-password', payload);
} }
} }
@@ -4,13 +4,26 @@
[modal]="true" [modal]="true"
[style]="{ width: '500px' }" [style]="{ width: '500px' }"
[closable]="true" [closable]="true"
(onHide)="close()" (onHide)="close()">
>
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4"> <form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
@if (showCurrentPasswordField && form.controls.currentPassword) {
<uikit-field label="رمز عبور فعلی" pSize="large" [control]="form.controls.currentPassword">
<p-password
id="password1"
name="password"
[formControl]="form.controls.currentPassword"
autocomplete="password"
[toggleMask]="true"
[fluid]="true"
[feedback]="false"
size="large"
[invalid]="form.controls.currentPassword.touched && form.controls.currentPassword.invalid" />
</uikit-field>
}
<shared-password-input <shared-password-input
[passwordControl]="form.controls.password" [passwordControl]="form.controls.password"
[confirmPasswordControl]="form.controls.confirmPassword" [confirmPasswordControl]="form.controls.confirmPassword"
/> [isRenewal]="true" />
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="loading()" (onCancel)="close()" /> <app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="loading()" (onCancel)="close()" />
</form> </form>
@@ -2,11 +2,14 @@ import { MustMatch, password } from '@/core/validators';
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog'; import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component'; import { SharedDialogComponent } from '@/shared/components/dialog/dialog.component';
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component'; import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
import { Component, EventEmitter, Output, input } from '@angular/core'; import { UikitFieldComponent } from '@/uikit';
import { Component, EventEmitter, Input, Output, input } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { Password } from 'primeng/password';
import { SharedPasswordInputComponent } from '../passwordInput/password-input.component'; import { SharedPasswordInputComponent } from '../passwordInput/password-input.component';
export interface IChangePasswordSubmitPayload { export interface IChangePasswordSubmitPayload {
currentPassword: string;
password: string; password: string;
confirmPassword: string; confirmPassword: string;
} }
@@ -19,9 +22,13 @@ export interface IChangePasswordSubmitPayload {
SharedDialogComponent, SharedDialogComponent,
FormFooterActionsComponent, FormFooterActionsComponent,
SharedPasswordInputComponent, SharedPasswordInputComponent,
UikitFieldComponent,
Password,
], ],
}) })
export class ChangePasswordFormDialogComponent extends AbstractDialog { export class ChangePasswordFormDialogComponent extends AbstractDialog {
@Input() showCurrentPasswordField = false;
title = input<string>(''); title = input<string>('');
loading = input<boolean>(false); loading = input<boolean>(false);
@@ -29,8 +36,10 @@ export class ChangePasswordFormDialogComponent extends AbstractDialog {
private readonly fb = new FormBuilder(); private readonly fb = new FormBuilder();
form = this.fb.group( initForm() {
const form = this.fb.group(
{ {
currentPassword: ['', [Validators.required]],
password: ['', [Validators.required, password()]], password: ['', [Validators.required, password()]],
confirmPassword: ['', [Validators.required]], confirmPassword: ['', [Validators.required]],
}, },
@@ -39,6 +48,16 @@ export class ChangePasswordFormDialogComponent extends AbstractDialog {
} }
); );
if (!this.showCurrentPasswordField) {
// @ts-ignore
form.removeControl('currentPassword');
}
return form;
}
form = this.initForm();
get dialogHeader() { get dialogHeader() {
return this.title() ? `تغییر رمز عبور ${this.title()}` : 'تغییر رمز عبور'; return this.title() ? `تغییر رمز عبور ${this.title()}` : 'تغییر رمز عبور';
} }
@@ -56,4 +75,8 @@ export class ChangePasswordFormDialogComponent extends AbstractDialog {
this.form.reset(); this.form.reset();
super.close(); super.close();
} }
ngOnChanges() {
this.form = this.initForm();
}
} }
@@ -1,4 +1,4 @@
<uikit-field label="رمز عبور" [pSize]="size" [control]="passwordControl"> <uikit-field [label]="passwordFieldLabel()" [pSize]="size" [control]="passwordControl">
<p-password <p-password
id="password1" id="password1"
name="password" name="password"
@@ -8,14 +8,13 @@
[fluid]="fluid" [fluid]="fluid"
[feedback]="false" [feedback]="false"
[size]="size" [size]="size"
[invalid]="passwordControl.touched && passwordControl.invalid" [invalid]="passwordControl.touched && passwordControl.invalid" />
/> <span class="text-muted-color mt-1 text-xs">
<span class="text-xs mt-1 text-muted-color">
{{ hint }} {{ hint }}
</span> </span>
</uikit-field> </uikit-field>
<uikit-field label="تکرار رمز عبور" [pSize]="size" [control]="confirmPasswordControl"> <uikit-field [label]="confirmPasswordFieldLabel()" [pSize]="size" [control]="confirmPasswordControl">
<p-password <p-password
id="confirmPassword" id="confirmPassword"
name="confirmPassword" name="confirmPassword"
@@ -25,6 +24,5 @@
[fluid]="fluid" [fluid]="fluid"
[feedback]="false" [feedback]="false"
[size]="size" [size]="size"
[invalid]="confirmPasswordControl.touched && confirmPasswordControl.invalid" [invalid]="confirmPasswordControl.touched && confirmPasswordControl.invalid" />
/>
</uikit-field> </uikit-field>
@@ -1,5 +1,5 @@
import { UikitFieldComponent } from '@/uikit'; import { UikitFieldComponent } from '@/uikit';
import { Component, Input } from '@angular/core'; import { Component, computed, Input } from '@angular/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { Password } from 'primeng/password'; import { Password } from 'primeng/password';
@@ -14,4 +14,10 @@ export class SharedPasswordInputComponent {
@Input() hint: string = 'رمز باید حداقل ۶ کاراکتر باشد.'; @Input() hint: string = 'رمز باید حداقل ۶ کاراکتر باشد.';
@Input() fluid: boolean = true; @Input() fluid: boolean = true;
@Input() size: 'small' | 'large' = 'large'; @Input() size: 'small' | 'large' = 'large';
@Input() isRenewal = false;
passwordFieldLabel = computed(() => (this.isRenewal ? 'رمز عبور جدید' : 'رمز عبور'));
confirmPasswordFieldLabel = computed(() =>
this.isRenewal ? 'تکرار رمز عبور جدید' : 'تکرار رمز عبور'
);
} }
@@ -1,4 +1,4 @@
<div class="border-surface-border bg-surface-card flex items-center gap-2 overflow-hidden rounded-lg border p-2"> <div class="border-surface-border bg-surface-card flex h-11 items-center gap-2 overflow-hidden rounded-lg border p-2">
<p-button <p-button
icon="pi pi-chevron-right" icon="pi pi-chevron-right"
size="small" size="small"