feat: update POS and account components to use new field names and improve form handling

This commit is contained in:
2026-04-24 04:27:40 +03:30
parent d857361cb7
commit 5bb5f10dbf
26 changed files with 323 additions and 73 deletions
@@ -5,7 +5,7 @@ import { IPosInitialValues } from './pos.model';
export const columns: IColumn[] = [ export const columns: IColumn[] = [
// { field: 'id', header: 'شناسه', type: 'id' }, // { field: 'id', header: 'شناسه', type: 'id' },
{ field: 'name', header: 'عنوان' }, { field: 'name', header: 'عنوان' },
{ field: 'serial', header: 'شماره سریال' }, { field: 'serial_number', header: 'شماره سریال' },
{ field: 'pos_type', header: 'نوع دستگاه' }, { field: 'pos_type', header: 'نوع دستگاه' },
{ field: 'device', header: 'دستگاه', type: 'nested', nestedOption: { path: 'device.name' } }, { field: 'device', header: 'دستگاه', type: 'nested', nestedOption: { path: 'device.name' } },
{ {
@@ -14,7 +14,7 @@ export const columns: IColumn[] = [
type: 'nested', type: 'nested',
nestedOption: { path: 'provider.name' }, nestedOption: { path: 'provider.name' },
}, },
{ field: 'status', header: 'وضعیت' }, { field: 'account', header: 'کاربر', type: 'nested', nestedOption: { path: 'account.username' } },
{ {
field: 'created_at', field: 'created_at',
header: 'تاریخ ایجاد', header: 'تاریخ ایجاد',
@@ -3,6 +3,7 @@ export interface IAccountRawResponse {
role: string; role: string;
created_at: string; created_at: string;
account: Account; account: Account;
pos: PosComplex;
} }
export interface IAccountResponse extends IAccountRawResponse {} export interface IAccountResponse extends IAccountRawResponse {}
@@ -18,3 +19,9 @@ interface Account {
username: string; username: string;
status: string; status: string;
} }
interface PosComplex {
name: string;
branch_code: string;
business_activity: { name: string };
}
@@ -3,9 +3,7 @@
[columns]="columns" [columns]="columns"
emptyPlaceholderTitle="حساب‌ کاربری‌ای یافت نشد" emptyPlaceholderTitle="حساب‌ کاربری‌ای یافت نشد"
[items]="items()" [items]="items()"
[showDetails]="true"
[loading]="loading()" [loading]="loading()"
(onDetails)="toSinglePage($event)"
/> />
@if (selectedItemForEdit()) { @if (selectedItemForEdit()) {
@@ -26,12 +26,12 @@ export class ConsumerAccountsComponent extends AbstractList<IAccountResponse> {
type: 'nested', type: 'nested',
nestedOption: { path: 'account.username' }, nestedOption: { path: 'account.username' },
}, },
{ field: 'role', header: 'نقش' },
{ {
field: 'status', field: 'pos',
header: 'وضعیت', header: 'پایانه',
type: 'nested', customDataModel(item) {
nestedOption: { path: 'account.status' }, return `${item.pos.name} - ${item.pos.complex.name} - ${item.pos.complex.business_activity.name}`;
},
}, },
{ {
field: 'created_at', field: 'created_at',
@@ -3,11 +3,9 @@
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<div class="grid grid-cols-3 gap-4 items-center"> <div class="grid grid-cols-3 gap-4 items-center">
<app-key-value label="نام کاربری" [value]="account()?.account?.username" /> <app-key-value label="نام کاربری" [value]="account()?.account?.username" />
<app-key-value label="نقش" [value]="account()?.role" />
<app-key-value label="وضعیت" [value]="account()?.account?.status" />
</div> </div>
</div> </div>
</app-card-data> </app-card-data>
<consumer-account-permission-list /> <!-- <consumer-account-permission-list /> -->
</div> </div>
@@ -20,7 +20,7 @@ export class ConsumerComplexFormComponent extends AbstractFormDialog<
private readonly service = inject(ConsumerComplexesService); private readonly service = inject(ConsumerComplexesService);
@Input({ required: true }) businessActivityId!: string; @Input({ required: true }) businessActivityId!: string;
@Input({ required: true }) complexId!: string; @Input() complexId!: string;
initForm = () => { initForm = () => {
return this.fb.group({ return this.fb.group({
@@ -33,7 +33,7 @@ export class ConsumerComplexFormComponent extends AbstractFormDialog<
form = this.initForm(); form = this.initForm();
get preparedTitle() { get preparedTitle() {
return `ویرایش شعبه ${this.initialValues?.name}`; return `${this.editMode ? 'ویرایش' : 'ایجاد'} شعبه`;
} }
override ngOnChanges(): void { override ngOnChanges(): void {
@@ -42,6 +42,9 @@ export class ConsumerComplexFormComponent extends AbstractFormDialog<
submitForm() { submitForm() {
const formValue = this.form.value as IComplexRequest; const formValue = this.form.value as IComplexRequest;
return this.service.update(this.businessActivityId, this.complexId, formValue); if (this.editMode) {
return this.service.update(this.businessActivityId, this.complexId, formValue);
}
return this.service.create(this.businessActivityId, formValue);
} }
} }
@@ -1,11 +1,16 @@
<app-page-data-list <app-page-data-list
pageTitle="لیست شعب" pageTitle="مدیریت شعب"
[addNewCtaLabel]="'افزودن شعبه‌ جدید'"
[showAdd]="true"
[columns]="columns" [columns]="columns"
[showAdd]="true"
emptyPlaceholderTitle="شعبه‌ای یافت نشد." emptyPlaceholderTitle="شعبه‌ای یافت نشد."
emptyPlaceholderDescription="برای افزودن شعبه‌ جدید، روی دکمهٔ بالا کلیک کنید."
[items]="items()" [items]="items()"
[loading]="loading()" [loading]="loading()"
[showDetails]="true" [showDetails]="true"
[showEdit]="true" [showEdit]="true"
(onAdd)="openAddForm()"
(onEdit)="onEditClick($event)" (onEdit)="onEditClick($event)"
(onDetails)="toSinglePage($event)" (onDetails)="toSinglePage($event)"
> >
@@ -8,6 +8,55 @@
> >
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4"> <form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
<app-input label="عنوان" [control]="form.controls.name" name="name" /> <app-input label="عنوان" [control]="form.controls.name" name="name" />
<app-enum-select [control]="form.controls.pos_type" type="posType" name="pos_type" />
@if (!editMode) {
<p-divider align="center"> اطلاعات ورود </p-divider>
<app-input label="نام کاربری" [control]="form.controls.username" name="username" [isLtrInput]="true" />
<uikit-field label="رمز عبور" [control]="form.controls.password">
<p-password
id="password"
name="password"
formControlName="password"
autocomplete="new-password"
class="w-full"
[toggleMask]="true"
[feedback]="false"
[invalid]="form.controls.password.touched && form.controls.password.invalid"
[inputStyle]="{
width: '100%',
}"
/>
<span class="text-xs mt-1 text-muted-color">
رمز باید حداقل ۸ کاراکتر بوده و شامل حداقل یک حرف بزرگ، یک حرف کوچک، یک عدد و یک کاراکتر ویژه باشد.
</span>
</uikit-field>
<uikit-field label="تکرار رمز عبور" [control]="form.controls.confirmPassword">
<p-password
id="confirmPassword"
name="confirmPassword"
formControlName="confirmPassword"
autocomplete="new-password"
class="w-full"
[toggleMask]="true"
[feedback]="false"
[invalid]="form.controls.confirmPassword.touched && form.controls.confirmPassword.invalid"
[inputStyle]="{
width: '100%',
}"
/>
</uikit-field>
}
@if (form.controls.pos_type.value === "PSP") {
<app-input label="سریال دستگاه" [control]="form.controls.serial_number" name="serial_number" />
<catalog-device-select [control]="form.controls.device_id" />
<catalog-provider-select [control]="form.controls.provider_id" />
}
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="submitLoading()" (onCancel)="close()" /> <app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="submitLoading()" (onCancel)="close()" />
</form> </form>
</p-dialog> </p-dialog>
@@ -1,18 +1,35 @@
// import { CatalogRolesComponent } from '@/shared/catalog/roles'; // import { CatalogRolesComponent } from '@/shared/catalog/roles';
import { CONSUMER_COMPONENTS_CONST } from '@/domains/consumer/constants'; import { MustMatch } from '@/core/validators';
import { AbstractFormDialog } from '@/shared/abstractClasses'; import { AbstractFormDialog } from '@/shared/abstractClasses';
import { EnumSelectComponent } from '@/shared/apiEnum/select.component';
import { CatalogProviderSelectComponent } from '@/shared/catalog';
import { CatalogDeviceSelectComponent } from '@/shared/catalog/devices';
import { InputComponent } from '@/shared/components'; import { InputComponent } from '@/shared/components';
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component'; import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
import { UikitFieldComponent } from '@/uikit';
import { Component, inject, Input } from '@angular/core'; import { Component, inject, Input } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms'; import { ReactiveFormsModule, Validators } from '@angular/forms';
import { Dialog } from 'primeng/dialog'; import { Dialog } from 'primeng/dialog';
import { Divider } from 'primeng/divider';
import { Password } from 'primeng/password';
import { IPosRequest, IPosResponse } from '../../models'; import { IPosRequest, IPosResponse } from '../../models';
import { ConsumerPosesService } from '../../services/poses.service'; import { ConsumerPosesService } from '../../services/poses.service';
@Component({ @Component({
selector: 'consumer-pos-form', selector: 'consumer-pos-form',
templateUrl: './form.component.html', templateUrl: './form.component.html',
imports: [ReactiveFormsModule, Dialog, InputComponent, FormFooterActionsComponent], imports: [
ReactiveFormsModule,
Dialog,
InputComponent,
FormFooterActionsComponent,
CatalogDeviceSelectComponent,
CatalogProviderSelectComponent,
EnumSelectComponent,
UikitFieldComponent,
Password,
Divider,
],
}) })
export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IPosResponse> { export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IPosResponse> {
private readonly service = inject(ConsumerPosesService); private readonly service = inject(ConsumerPosesService);
@@ -21,14 +38,84 @@ export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IP
@Input({ required: true }) complexId!: string; @Input({ required: true }) complexId!: string;
@Input({ required: true }) posId!: string; @Input({ required: true }) posId!: string;
initForm() { initForm = () => {
return CONSUMER_COMPONENTS_CONST.pos.initForm(this.fb, this.initialValues); const form = this.fb.group({
} name: [this.initialValues?.name || '', [Validators.required]],
pos_type: [this.initialValues?.pos_type || '', [Validators.required]],
serial_number: [this.initialValues?.serial_number || ''],
device_id: [this.initialValues?.device?.id || ''],
provider_id: [this.initialValues?.provider?.id || ''],
username: [''],
password: [''],
confirmPassword: [''],
});
form.controls.pos_type.valueChanges.subscribe((value) => {
if (value === 'PSP') {
form.controls.serial_number.setValidators([Validators.required]);
form.controls.device_id.setValidators([Validators.required]);
form.controls.provider_id.setValidators([Validators.required]);
form.controls.serial_number.enable({ emitEvent: false });
form.controls.device_id.enable({ emitEvent: false });
form.controls.provider_id.enable({ emitEvent: false });
} else {
form.controls.serial_number.clearValidators();
form.controls.device_id.clearValidators();
form.controls.provider_id.clearValidators();
form.controls.serial_number.reset('');
form.controls.device_id.reset('');
form.controls.provider_id.reset('');
form.controls.serial_number.disable({ emitEvent: false });
form.controls.device_id.disable({ emitEvent: false });
form.controls.provider_id.disable({ emitEvent: false });
}
form.controls.serial_number.updateValueAndValidity({ emitEvent: false });
form.controls.device_id.updateValueAndValidity({ emitEvent: false });
form.controls.provider_id.updateValueAndValidity({ emitEvent: false });
});
form.controls.pos_type.updateValueAndValidity({ emitEvent: true });
if (this.editMode) {
// @ts-ignore
form.removeControl('username');
// @ts-ignore
form.removeControl('password');
// @ts-ignore
form.removeControl('confirmPassword');
form.removeValidators([MustMatch('password', 'confirmPassword')]);
} else {
form.addControl(
'username',
this.fb.control<string>('', {
nonNullable: true,
validators: [Validators.required],
}),
);
form.addControl(
'password',
this.fb.control<string>('', {
nonNullable: true,
validators: [Validators.required],
}),
);
form.addControl(
'confirmPassword',
this.fb.control<string>('', {
nonNullable: true,
validators: [Validators.required],
}),
);
form.addValidators([MustMatch('password', 'confirmPassword')]);
}
return form;
};
form = this.initForm(); form = this.initForm();
get preparedTitle() { get preparedTitle() {
return `ویرایش پایانه فروش ${this.initialValues?.name}`; return `${this.editMode ? 'ویرایش' : 'ایجاد'} پایانه فروش`;
} }
override ngOnChanges(): void { override ngOnChanges(): void {
@@ -36,7 +123,11 @@ export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IP
} }
submitForm() { submitForm() {
const formValue = this.form.value as IPosRequest; const formValue = this.form.value as IPosRequest & { confirmPassword?: string };
return this.service.update(this.businessActivityId, this.complexId, this.posId, formValue); const { confirmPassword, ...rest } = formValue;
if (this.editMode) {
return this.service.update(this.businessActivityId, this.complexId, this.posId!, rest);
}
return this.service.create(this.businessActivityId, this.complexId, rest);
} }
} }
@@ -1,11 +1,15 @@
<app-page-data-list <app-page-data-list
pageTitle="لیست پایانه‌های فروش" pageTitle="لیست پایانه‌های فروش"
[columns]="columns" [columns]="columns"
[addNewCtaLabel]="'افزودن پایانه‌ی فروش جدید'"
emptyPlaceholderTitle="پایانه‌ی فروشی یافت نشد." emptyPlaceholderTitle="پایانه‌ی فروشی یافت نشد."
emptyPlaceholderDescription="برای افزودن پایانه‌ی فروش جدید، روی دکمهٔ بالا کلیک کنید."
[items]="items()" [items]="items()"
[loading]="loading()" [loading]="loading()"
[showDetails]="true" [showDetails]="true"
[showEdit]="true" [showEdit]="true"
[showAdd]="true"
(onAdd)="openAddForm()"
(onEdit)="onEditClick($event)" (onEdit)="onEditClick($event)"
(onDetails)="toSinglePage($event)" (onDetails)="toSinglePage($event)"
> >
@@ -20,4 +20,5 @@ interface LicenseInfo {
starts_at: string; starts_at: string;
expires_at: string; expires_at: string;
accounts_limit: number; accounts_limit: number;
allocated_account_count: number;
} }
@@ -3,7 +3,7 @@ import ISummary from '@/core/models/summary';
export interface IPosRawResponse { export interface IPosRawResponse {
id: string; id: string;
name: string; name: string;
serial: string; serial_number: string;
model?: string; model?: string;
status: string; status: string;
pos_type: string; pos_type: string;
@@ -15,4 +15,10 @@ export interface IPosResponse extends IPosRawResponse {}
export interface IPosRequest { export interface IPosRequest {
name: string; name: string;
serial_number: string;
pos_type: string;
device_id?: string;
provider_id?: string;
username?: string;
password?: string;
} }
@@ -20,6 +20,10 @@ export class ConsumerComplexesService {
return this.http.get<IComplexRawResponse>(this.apiRoutes.single(businessActivityId, complexId)); return this.http.get<IComplexRawResponse>(this.apiRoutes.single(businessActivityId, complexId));
} }
create(businessActivityId: string, data: IComplexRequest): Observable<IComplexResponse> {
return this.http.post<IComplexRawResponse>(this.apiRoutes.list(businessActivityId), data);
}
update( update(
businessActivityId: string, businessActivityId: string,
complexId: string, complexId: string,
@@ -29,6 +29,17 @@ export class ConsumerPosesService {
); );
} }
create(
businessActivityId: string,
complexId: string,
data: IPosRequest,
): Observable<IPosResponse> {
return this.http.post<IPosRawResponse>(
this.apiRoutes.list(businessActivityId, complexId),
data,
);
}
update( update(
businessActivityId: string, businessActivityId: string,
complexId: string, complexId: string,
@@ -6,8 +6,8 @@
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<div class="grid grid-cols-3 gap-4 items-center"> <div class="grid grid-cols-3 gap-4 items-center">
<app-key-value label="عنوان" [value]="pos()?.name" /> <app-key-value label="عنوان" [value]="pos()?.name" />
<app-key-value label="شماره سریال" [value]="pos()?.serial" />
<app-key-value label="نوع پایانه" [value]="pos()?.pos_type" /> <app-key-value label="نوع پایانه" [value]="pos()?.pos_type" />
<app-key-value label="شماره سریال" [value]="pos()?.serial_number" />
<app-key-value label="نوع دستگاه" [value]="pos()?.device?.name" /> <app-key-value label="نوع دستگاه" [value]="pos()?.device?.name" />
<app-key-value label="مدل دستگاه" [value]="pos()?.model" /> <app-key-value label="مدل دستگاه" [value]="pos()?.model" />
<app-key-value label="ارایه‌دهنده" [value]="pos()?.provider?.name" /> <app-key-value label="ارایه‌دهنده" [value]="pos()?.provider?.name" />
@@ -7,6 +7,12 @@
<app-key-value label="کد اقتصادی" [value]="business()?.economic_code" /> <app-key-value label="کد اقتصادی" [value]="business()?.economic_code" />
<app-key-value label="صنف" [value]="business()?.guild?.name" /> <app-key-value label="صنف" [value]="business()?.guild?.name" />
</div> </div>
<p-divider align="center">اطلاعات لایسنس</p-divider>
<div class="grid grid-cols-3 gap-4 items-center">
<app-key-value label="تاریخ پایان لایسنس" [value]="business()?.license_info?.expires_at" type="date" />
<app-key-value label="محدودیت کاربر" [value]="business()?.license_info?.accounts_limit" />
<app-key-value label="تعداد کاربران ایجاد شده" [value]="business()?.license_info?.allocated_account_count" />
</div>
</div> </div>
</app-card-data> </app-card-data>
@@ -2,6 +2,7 @@ import { BreadcrumbService } from '@/core/services';
import { AppCardComponent, KeyValueComponent } from '@/shared/components'; import { AppCardComponent, KeyValueComponent } from '@/shared/components';
import { Component, computed, effect, inject, signal } from '@angular/core'; import { Component, computed, effect, inject, signal } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { Divider } from 'primeng/divider';
import { ConsumerComplexListComponent } from '../components/complexes/list.component'; import { ConsumerComplexListComponent } from '../components/complexes/list.component';
import { ConsumerBusinessActivityFormComponent } from '../components/form.component'; import { ConsumerBusinessActivityFormComponent } from '../components/form.component';
import { BusinessActivityStore } from '../store/businessActivity.store'; import { BusinessActivityStore } from '../store/businessActivity.store';
@@ -14,6 +15,7 @@ import { BusinessActivityStore } from '../store/businessActivity.store';
KeyValueComponent, KeyValueComponent,
ConsumerBusinessActivityFormComponent, ConsumerBusinessActivityFormComponent,
ConsumerComplexListComponent, ConsumerComplexListComponent,
Divider,
], ],
}) })
export class ConsumerBusinessActivityComponent { export class ConsumerBusinessActivityComponent {
@@ -33,7 +33,7 @@ export class ConsumerPosListComponent extends AbstractList<IPosResponse> {
override setColumns(): void { override setColumns(): void {
this.columns = [ this.columns = [
...this.header.filter((header) => ...this.header.filter((header) =>
['name', 'status', 'pos_type'].includes(header.field as string), ['name', 'account', 'pos_type', 'status'].includes(header.field as string),
), ),
{ {
field: 'complex.business_activity', field: 'complex.business_activity',
+1 -1
View File
@@ -3,7 +3,7 @@ import ISummary from '@/core/models/summary';
export interface IPosRawResponse { export interface IPosRawResponse {
id: string; id: string;
name: string; name: string;
serial: string; serial_number: string;
model?: string; model?: string;
status: string; status: string;
pos_type: string; pos_type: string;
@@ -6,8 +6,8 @@
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<div class="grid grid-cols-3 gap-4 items-center"> <div class="grid grid-cols-3 gap-4 items-center">
<app-key-value label="عنوان" [value]="pos()?.name" /> <app-key-value label="عنوان" [value]="pos()?.name" />
<app-key-value label="شماره سریال" [value]="pos()?.serial" />
<app-key-value label="نوع پایانه" [value]="pos()?.pos_type" /> <app-key-value label="نوع پایانه" [value]="pos()?.pos_type" />
<app-key-value label="شماره سریال" [value]="pos()?.serial_number" />
<app-key-value label="نوع دستگاه" [value]="pos()?.device?.name" /> <app-key-value label="نوع دستگاه" [value]="pos()?.device?.name" />
<app-key-value label="مدل دستگاه" [value]="pos()?.model" /> <app-key-value label="مدل دستگاه" [value]="pos()?.model" />
<app-key-value label="ارایه‌دهنده" [value]="pos()?.provider?.name" /> <app-key-value label="ارایه‌دهنده" [value]="pos()?.provider?.name" />
@@ -8,10 +8,39 @@
> >
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4"> <form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
<app-input label="عنوان" [control]="form.controls.name" name="name" /> <app-input label="عنوان" [control]="form.controls.name" name="name" />
<!-- <app-input label="مدل دستگاه" [control]="form.controls.model" name="model" /> -->
<app-enum-select [control]="form.controls.pos_type" type="posType" name="pos_type" /> <app-enum-select [control]="form.controls.pos_type" type="posType" name="pos_type" />
@if (!editMode) {
<app-input label="نام کاربری" [control]="form.controls.username" name="username" [isLtrInput]="true" />
<uikit-field label="رمز عبور" [control]="form.controls.password">
<p-password
id="password"
name="password"
formControlName="password"
autocomplete="new-password"
styleClass="w-full"
[toggleMask]="true"
[feedback]="false"
[invalid]="form.controls.password.touched && form.controls.password.invalid"
/>
</uikit-field>
<uikit-field label="تکرار رمز عبور" [control]="form.controls.confirmPassword">
<p-password
id="confirmPassword"
name="confirmPassword"
formControlName="confirmPassword"
autocomplete="new-password"
styleClass="w-full"
[toggleMask]="true"
[feedback]="false"
[invalid]="form.controls.confirmPassword.touched && form.controls.confirmPassword.invalid"
/>
</uikit-field>
}
@if (form.controls.pos_type.value === "PSP") { @if (form.controls.pos_type.value === "PSP") {
<app-input label="سریال دستگاه" [control]="form.controls.serial" name="serial" /> <app-input label="سریال دستگاه" [control]="form.controls.serial_number" name="serial_number" />
<catalog-device-select [control]="form.controls.device_id" /> <catalog-device-select [control]="form.controls.device_id" />
<catalog-provider-select [control]="form.controls.provider_id" /> <catalog-provider-select [control]="form.controls.provider_id" />
} }
@@ -1,13 +1,16 @@
// import { CatalogRolesComponent } from '@/shared/catalog/roles'; // import { CatalogRolesComponent } from '@/shared/catalog/roles';
import { MustMatch } from '@/core/validators';
import { AbstractFormDialog } from '@/shared/abstractClasses'; import { AbstractFormDialog } from '@/shared/abstractClasses';
import { EnumSelectComponent } from '@/shared/apiEnum/select.component'; import { EnumSelectComponent } from '@/shared/apiEnum/select.component';
import { CatalogProviderSelectComponent } from '@/shared/catalog'; import { CatalogProviderSelectComponent } from '@/shared/catalog';
import { CatalogDeviceSelectComponent } from '@/shared/catalog/devices'; import { CatalogDeviceSelectComponent } from '@/shared/catalog/devices';
import { InputComponent } from '@/shared/components'; import { InputComponent } from '@/shared/components';
import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component'; import { FormFooterActionsComponent } from '@/shared/components/formFooterActions/form-footer-actions.component';
import { UikitFieldComponent } from '@/uikit';
import { Component, inject, Input } from '@angular/core'; import { Component, inject, Input } from '@angular/core';
import { ReactiveFormsModule, Validators } from '@angular/forms'; import { ReactiveFormsModule, Validators } from '@angular/forms';
import { Dialog } from 'primeng/dialog'; import { Dialog } from 'primeng/dialog';
import { Password } from 'primeng/password';
import { IPosRequest, IPosResponse } from '../../models'; import { IPosRequest, IPosResponse } from '../../models';
import { PartnerPosesService } from '../../services/poses.service'; import { PartnerPosesService } from '../../services/poses.service';
@@ -22,6 +25,8 @@ import { PartnerPosesService } from '../../services/poses.service';
CatalogDeviceSelectComponent, CatalogDeviceSelectComponent,
CatalogProviderSelectComponent, CatalogProviderSelectComponent,
EnumSelectComponent, EnumSelectComponent,
UikitFieldComponent,
Password,
], ],
}) })
export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IPosResponse> { export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IPosResponse> {
@@ -35,44 +40,74 @@ export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IP
initForm = () => { initForm = () => {
const form = this.fb.group({ const form = this.fb.group({
name: [this.initialValues?.name || '', [Validators.required]], name: [this.initialValues?.name || '', [Validators.required]],
serial: [this.initialValues?.serial || '', [Validators.required]],
// model: [this.initialValues?.model || '', [Validators.required]],
pos_type: [this.initialValues?.pos_type || '', [Validators.required]], pos_type: [this.initialValues?.pos_type || '', [Validators.required]],
serial_number: [this.initialValues?.serial_number || ''],
device_id: [this.initialValues?.device?.id || ''], device_id: [this.initialValues?.device?.id || ''],
provider_id: [this.initialValues?.provider?.id || ''], provider_id: [this.initialValues?.provider?.id || ''],
username: [''],
password: [''],
confirmPassword: [''],
}); });
form.controls.pos_type.valueChanges.subscribe((value) => { form.controls.pos_type.valueChanges.subscribe((value) => {
if (value === 'PSP') { if (value === 'PSP') {
form.addControl( form.controls.serial_number.setValidators([Validators.required]);
'serial', form.controls.device_id.setValidators([Validators.required]);
this.fb.control<string>(this.initialValues?.serial ?? '', { form.controls.provider_id.setValidators([Validators.required]);
nonNullable: true, form.controls.serial_number.enable({ emitEvent: false });
validators: [Validators.required], form.controls.device_id.enable({ emitEvent: false });
}), form.controls.provider_id.enable({ emitEvent: false });
);
form.addControl(
'device_id',
this.fb.control<string>(this.initialValues?.device?.id ?? '', {
nonNullable: true,
validators: [Validators.required],
}),
);
form.addControl(
'provider_id',
this.fb.control<string>(this.initialValues?.provider?.id ?? '', {
nonNullable: true,
validators: [Validators.required],
}),
);
} else { } else {
// @ts-ignore form.controls.serial_number.clearValidators();
form.removeControl('serial'); form.controls.device_id.clearValidators();
// @ts-ignore form.controls.provider_id.clearValidators();
form.removeControl('device_id'); form.controls.serial_number.reset('');
// @ts-ignore form.controls.device_id.reset('');
form.removeControl('provider_id'); form.controls.provider_id.reset('');
form.controls.serial_number.disable({ emitEvent: false });
form.controls.device_id.disable({ emitEvent: false });
form.controls.provider_id.disable({ emitEvent: false });
} }
form.controls.serial_number.updateValueAndValidity({ emitEvent: false });
form.controls.device_id.updateValueAndValidity({ emitEvent: false });
form.controls.provider_id.updateValueAndValidity({ emitEvent: false });
}); });
form.controls.pos_type.updateValueAndValidity({ emitEvent: true });
if (this.editMode) {
// @ts-ignore
form.removeControl('username');
// @ts-ignore
form.removeControl('password');
// @ts-ignore
form.removeControl('confirmPassword');
form.removeValidators([MustMatch('password', 'confirmPassword')]);
} else {
form.addControl(
'username',
this.fb.control<string>('', {
nonNullable: true,
validators: [Validators.required],
}),
);
form.addControl(
'password',
this.fb.control<string>('', {
nonNullable: true,
validators: [Validators.required],
}),
);
form.addControl(
'confirmPassword',
this.fb.control<string>('', {
nonNullable: true,
validators: [Validators.required],
}),
);
form.addValidators([MustMatch('password', 'confirmPassword')]);
}
return form; return form;
}; };
@@ -87,10 +122,11 @@ export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IP
} }
submitForm() { submitForm() {
const formValue = this.form.value as IPosRequest; const formValue = this.form.value as IPosRequest & { confirmPassword?: string };
if (this.editMode) { if (this.editMode) {
return this.service.update(this.businessActivityId, this.complexId, this.posId, formValue); return this.service.update(this.businessActivityId, this.complexId, this.posId, formValue);
} }
return this.service.create(this.businessActivityId, this.complexId, formValue); const { confirmPassword, ...rest } = formValue;
return this.service.create(this.businessActivityId, this.complexId, rest);
} }
} }
@@ -3,7 +3,7 @@ import ISummary from '@/core/models/summary';
export interface IPosRawResponse { export interface IPosRawResponse {
id: string; id: string;
name: string; name: string;
serial: string; serial_number?: string;
model?: string; model?: string;
status: string; status: string;
pos_type: string; pos_type: string;
@@ -15,10 +15,10 @@ export interface IPosResponse extends IPosRawResponse {}
export interface IPosRequest { export interface IPosRequest {
name: string; name: string;
serial: string; serial_number: string;
model?: string;
status: string;
pos_type: string; pos_type: string;
device_id: string; device_id?: string;
provider_id: string; provider_id?: string;
username?: string;
password?: string;
} }
@@ -8,7 +8,7 @@
> >
<form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4"> <form [formGroup]="form" (submit)="submit()" class="flex flex-col gap-4">
<app-input label="عنوان" [control]="form.controls.name" name="name" /> <app-input label="عنوان" [control]="form.controls.name" name="name" />
<app-input label="سریال دستگاه" [control]="form.controls.serial" name="serial" /> <app-input label="سریال دستگاه" [control]="form.controls.serial_number" name="serial_number" />
<!-- <app-input label="مدل دستگاه" [control]="form.controls.model" name="model" /> --> <!-- <app-input label="مدل دستگاه" [control]="form.controls.model" name="model" /> -->
<app-enum-select [control]="form.controls.pos_type" type="posType" name="pos_type" /> <app-enum-select [control]="form.controls.pos_type" type="posType" name="pos_type" />
@if (form.controls.pos_type.value === "PSP") { @if (form.controls.pos_type.value === "PSP") {
@@ -35,7 +35,7 @@ export class ConsumerPosFormComponent extends AbstractFormDialog<IPosRequest, IP
initForm = () => { initForm = () => {
const form = this.fb.group({ const form = this.fb.group({
name: [this.initialValues?.name || '', [Validators.required]], name: [this.initialValues?.name || '', [Validators.required]],
serial: [this.initialValues?.serial || '', [Validators.required]], serial_number: [this.initialValues?.serial_number || '', [Validators.required]],
// model: [this.initialValues?.model || '', [Validators.required]], // model: [this.initialValues?.model || '', [Validators.required]],
pos_type: [this.initialValues?.pos_type || '', [Validators.required]], pos_type: [this.initialValues?.pos_type || '', [Validators.required]],
device_id: [this.initialValues?.device?.id || ''], device_id: [this.initialValues?.device?.id || ''],
@@ -3,7 +3,7 @@ import ISummary from '@/core/models/summary';
export interface IPosRawResponse { export interface IPosRawResponse {
id: string; id: string;
name: string; name: string;
serial: string; serial_number: string;
model?: string; model?: string;
status: string; status: string;
pos_type: string; pos_type: string;
@@ -15,7 +15,7 @@ export interface IPosResponse extends IPosRawResponse {}
export interface IPosRequest { export interface IPosRequest {
name: string; name: string;
serial: string; serial_number: string;
model?: string; model?: string;
status: string; status: string;
pos_type: string; pos_type: string;