create apiEnum components

This commit is contained in:
2026-03-10 20:23:56 +03:30
parent b379787002
commit d61a5a6250
20 changed files with 207 additions and 6 deletions
+4
View File
@@ -8,6 +8,10 @@ export interface IPaginatedResponse<T> {
data: T[]; data: T[];
} }
export interface IListingResponse<T> {
data: T[];
}
export interface IResponseMetadata { export interface IResponseMetadata {
page: number; page: number;
perPage: number; perPage: number;
@@ -20,6 +20,7 @@ export class GuildGoodCategoriesListComponent extends AbstractList<IGoodCategori
@Input() header: IColumn[] = [ @Input() header: IColumn[] = [
{ field: 'id', header: 'شناسه' }, { field: 'id', header: 'شناسه' },
{ field: 'name', header: 'عنوان' }, { field: 'name', header: 'عنوان' },
{ field: 'goods_count', header: 'تعداد کالاها' },
{ {
field: 'created_at', field: 'created_at',
header: 'تاریخ ایجاد', header: 'تاریخ ایجاد',
@@ -0,0 +1,12 @@
<uikit-field [label]="label" [control]="control" [showLabel]="showLabel" [showErrors]="showErrors">
<p-select
[loading]="loading()"
[options]="items()"
optionLabel="name"
[optionValue]="selectOptionValue"
[formControl]="control"
[showClear]="showClear"
[filter]="true"
appendTo="body"
/>
</uikit-field>
@@ -0,0 +1,33 @@
import { IPaginatedResponse } from '@/core/models/service.model';
import { AbstractSelectComponent } from '@/shared/abstractClasses';
import { UikitFieldComponent } from '@/uikit';
import { Component, inject, Input } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { Select } from 'primeng/select';
import { IGoodCategoriesResponse } from '../../models';
import { GuildGoodCategoriesService } from '../../services/goodCategories.service';
@Component({
selector: 'admin-guild-categories-select',
templateUrl: './select.component.html',
imports: [UikitFieldComponent, Select, ReactiveFormsModule],
})
export class GuildCategoriesSelectComponent extends AbstractSelectComponent<
IGoodCategoriesResponse,
IPaginatedResponse<IGoodCategoriesResponse>
> {
@Input() override showClear: boolean = false;
@Input() label: string = '';
@Input() guildId!: string;
private readonly service = inject(GuildGoodCategoriesService);
ngOnChanges() {
if (this.guildId) {
this.getData();
}
}
getDataService() {
return this.service.getAll(this.guildId);
}
}
@@ -3,7 +3,6 @@
<app-input label="عنوان" [control]="form.controls.name" name="name" /> <app-input label="عنوان" [control]="form.controls.name" name="name" />
<app-input label="کد" [control]="form.controls.code" name="code" /> <app-input label="کد" [control]="form.controls.code" name="code" />
{{ editMode }}
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="form.disabled" (onCancel)="close()" /> <app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="form.disabled" (onCancel)="close()" />
</form> </form>
</p-dialog> </p-dialog>
@@ -1,7 +1,17 @@
<p-dialog header="فرم صنف" [(visible)]="visible" [modal]="true" [style]="{ width: '500px' }" [closable]="true"> <p-dialog header="فرم صنف" [(visible)]="visible" [modal]="true" [style]="{ width: '500px' }" [closable]="true">
<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.sku" name="sku" />
<admin-guild-categories-select
[guildId]="guildId"
label="دسته‌بندی"
[control]="form.controls.category_id"
name="category_id"
/>
<app-enum-select type="unitType" [control]="form.controls.unit_type" />
<app-enum-select type="goodPricingModel" [control]="form.controls.pricing_model" />
<app-input label="توضیحات" [control]="form.controls.description" name="description" />
<app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="form.disabled" (onCancel)="close()" /> <app-form-footer-actions [submitLabel]="'ذخیره'" [loading]="submitLoading()" (onCancel)="close()" />
</form> </form>
</p-dialog> </p-dialog>
@@ -5,13 +5,22 @@ 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 { EnumSelectComponent } from '@/shared/apiEnum/select.component';
import { IGuildGoodRequest, IGuildGoodsResponse } from '../../models'; import { IGuildGoodRequest, IGuildGoodsResponse } from '../../models';
import { GuildGoodsService } from '../../services/goods.service'; import { GuildGoodsService } from '../../services/goods.service';
import { GuildCategoriesSelectComponent } from '../categories/select.component';
@Component({ @Component({
selector: 'admin-guild-good-form', selector: 'admin-guild-good-form',
templateUrl: './form.component.html', templateUrl: './form.component.html',
imports: [ReactiveFormsModule, Dialog, InputComponent, FormFooterActionsComponent], imports: [
ReactiveFormsModule,
Dialog,
InputComponent,
FormFooterActionsComponent,
EnumSelectComponent,
GuildCategoriesSelectComponent,
],
}) })
export class GuildGoodCategoryFormComponent extends AbstractFormDialog< export class GuildGoodCategoryFormComponent extends AbstractFormDialog<
IGuildGoodRequest, IGuildGoodRequest,
@@ -24,6 +33,11 @@ export class GuildGoodCategoryFormComponent extends AbstractFormDialog<
form = this.fb.group({ form = this.fb.group({
name: [this.initialValues?.name || '', [Validators.required]], name: [this.initialValues?.name || '', [Validators.required]],
sku: [this.initialValues?.sku || '', [Validators.required]],
unit_type: [this.initialValues?.unit_type || '', [Validators.required]],
pricing_model: [this.initialValues?.pricing_model || '', [Validators.required]],
category_id: [this.initialValues?.category.id || '', [Validators.required]],
description: [this.initialValues?.description || ''],
}); });
override submitForm(payload: IGuildGoodRequest) { override submitForm(payload: IGuildGoodRequest) {
@@ -9,6 +9,16 @@
[loading]="loading()" [loading]="loading()"
[showDetails]="true" [showDetails]="true"
[showAdd]="true" [showAdd]="true"
[showEdit]="true"
[fullHeight]="fullHeight"
(onEdit)="onEditClick($event)"
(onAdd)="openAddForm()" (onAdd)="openAddForm()"
/> />
<admin-guild-good-form [(visible)]="visibleForm" (onSubmit)="refresh()" /> <admin-guild-good-form
[guildId]="guildId"
[(visible)]="visibleForm"
[initialValues]="selectedItemForEdit() || undefined"
[categoryId]="selectedItemForEdit()?.id"
[editMode]="editMode()"
(onSubmit)="refresh()"
/>
@@ -5,6 +5,8 @@ export interface IGuildGoodsRawResponse {
name: string; name: string;
sku: string; sku: string;
category: ISummary; category: ISummary;
unit_type: string;
pricing_model: string;
description?: string; description?: string;
created_at: string; created_at: string;
updated_at: string; updated_at: string;
@@ -14,5 +16,8 @@ export interface IGuildGoodsResponse extends IGuildGoodsRawResponse {}
export interface IGuildGoodRequest { export interface IGuildGoodRequest {
name: string; name: string;
sku: string; sku: string;
category_id: string;
unit_type: string;
pricing_model: string;
description?: string; description?: string;
} }
@@ -14,7 +14,7 @@ import { PartnersService } from '../services/main.service';
templateUrl: './select.component.html', templateUrl: './select.component.html',
imports: [UikitFieldComponent, Select, Button, ReactiveFormsModule, GuildFormComponent], imports: [UikitFieldComponent, Select, Button, ReactiveFormsModule, GuildFormComponent],
}) })
export class InventoryBankAccountSelectComponent extends AbstractSelectComponent< export class PartnerSelectComponent extends AbstractSelectComponent<
IPartnerResponse, IPartnerResponse,
IPaginatedResponse<IPartnerResponse> IPaginatedResponse<IPartnerResponse>
> { > {
@@ -13,7 +13,7 @@ export interface ISelectItem {
template: '', template: '',
}) })
export abstract class AbstractSelectComponent<T = ISelectItem, serviceResponse = T[]> { export abstract class AbstractSelectComponent<T = ISelectItem, serviceResponse = T[]> {
@Input() control = new FormControl<Maybe<number | T>>(null); @Input() control = new FormControl<Maybe<number | string | T>>(null);
@Input() canInsert: boolean = false; @Input() canInsert: boolean = false;
@Input() showLabel: boolean = true; @Input() showLabel: boolean = true;
@Input() showErrors: boolean = true; @Input() showErrors: boolean = true;
@@ -39,6 +39,7 @@ export abstract class AbstractSelectComponent<T = ISelectItem, serviceResponse =
} }
abstract getDataService(): Observable<serviceResponse>; abstract getDataService(): Observable<serviceResponse>;
getData() { getData() {
this.loading.set(true); this.loading.set(true);
this.getDataService().subscribe({ this.getDataService().subscribe({
@@ -0,0 +1,20 @@
import { TEnumApi } from '../models';
export const apiEnumTranslates = {
goldKarat: '',
userStatus: 'وضعیت کاربر',
accountRole: 'نقش',
accountStatus: 'وضعیت',
posStatus: 'وضعیت',
posRole: 'نقش',
licenseType: 'نوع لایسنس',
licenseStatus: 'وضعیت لایسنس',
posType: 'نوع پایانه',
userType: 'نوع کاربر',
accountType: 'نوع کاربر',
partnerRole: 'نقش',
businessRole: 'نقش',
providerRole: 'نقش',
unitType: 'واحد اندازه‌گیری',
goodPricingModel: 'مدل محاسبه',
} as Record<TEnumApi, string>;
@@ -0,0 +1,21 @@
const baseUrl = '/api/v1/enums';
export const ENUMS_API_ROUTES = {
goldKarat: `${baseUrl}/gold_karat`,
userStatus: `${baseUrl}/user_status`,
accountRole: `${baseUrl}/account_role`,
accountStatus: `${baseUrl}/account_status`,
posStatus: `${baseUrl}/pos_status`,
posRole: `${baseUrl}/pos_role`,
licenseType: `${baseUrl}/license_type`,
licenseStatus: `${baseUrl}/license_status`,
posType: `${baseUrl}/pos_type`,
userType: `${baseUrl}/user_type`,
accountType: `${baseUrl}/account_type`,
partnerRole: `${baseUrl}/partner_role`,
businessRole: `${baseUrl}/business_role`,
providerRole: `${baseUrl}/provider_role`,
tokenType: `${baseUrl}/token_type`,
unitType: `${baseUrl}/unit_type`,
goodPricingModel: `${baseUrl}/good_pricing_model`,
};
@@ -0,0 +1,2 @@
export * from './apiEnumTranslates';
export * from './apiRoutes';
+2
View File
@@ -0,0 +1,2 @@
export * from './io';
export * from './types';
+4
View File
@@ -0,0 +1,4 @@
export interface IApiEnumResponse {
name: string;
value: string;
}
+3
View File
@@ -0,0 +1,3 @@
import { ENUMS_API_ROUTES } from '../constants/apiRoutes';
export type TEnumApi = keyof typeof ENUMS_API_ROUTES;
@@ -0,0 +1,12 @@
<uikit-field [label]="label()" [control]="control" [showLabel]="showLabel" [showErrors]="showErrors">
<p-select
[loading]="loading()"
[options]="items()"
optionLabel="name"
optionValue="value"
[formControl]="control"
[showClear]="showClear"
[filter]="true"
appendTo="body"
/>
</uikit-field>
@@ -0,0 +1,31 @@
import { UikitFieldComponent } from '@/uikit';
import { Component, computed, inject, Input } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { Select } from 'primeng/select';
import { Observable } from 'rxjs';
import { AbstractSelectComponent } from '../abstractClasses';
import { apiEnumTranslates } from './constants';
import { IApiEnumResponse, TEnumApi } from './models';
import { EnumsService } from './services';
@Component({
selector: 'app-enum-select',
templateUrl: './select.component.html',
imports: [UikitFieldComponent, Select, ReactiveFormsModule],
})
export class EnumSelectComponent extends AbstractSelectComponent<string, IApiEnumResponse[]> {
@Input() type!: TEnumApi;
@Input() customLabel?: string;
private readonly service = inject(EnumsService);
label = computed(() => this.customLabel ?? apiEnumTranslates[this.type]);
override getDataService(): Observable<IApiEnumResponse[]> {
return this.service.getAll(this.type);
}
ngOnInit() {
this.getData();
}
}
+17
View File
@@ -0,0 +1,17 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { ENUMS_API_ROUTES } from './constants/apiRoutes';
import { TEnumApi } from './models';
import { IApiEnumResponse } from './models/io';
@Injectable({ providedIn: 'root' })
export class EnumsService {
constructor(private http: HttpClient) {}
private apiRoutes = ENUMS_API_ROUTES;
getAll(type: TEnumApi): Observable<IApiEnumResponse[]> {
return this.http.get<IApiEnumResponse[]>(this.apiRoutes[type]);
}
}