feat: Refactor select components to use IPaginatedResponse and streamline data fetching
- Updated select components for bank accounts, bank branches, customers, inventories, product brands, product categories, products, and suppliers to extend AbstractSelectComponent with IPaginatedResponse. - Replaced getData() method with getDataService() to return observables directly from service calls. - Enhanced filters component to set default inventory and product selections. - Modified inventory component to conditionally render columns based on variant type. - Introduced InventoryStore for managing inventory state and fetching single inventory details. - Added empty state messages in cardex and other components for better user experience. - Updated inner pages header to use h4 for titles and improved layout in empty state component.
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import { IPaginatedResponse } from '@/core/models/service.model';
|
||||||
import { AbstractSelectComponent } from '@/shared/components';
|
import { AbstractSelectComponent } from '@/shared/components';
|
||||||
import { UikitFieldComponent } from '@/uikit';
|
import { UikitFieldComponent } from '@/uikit';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
@@ -13,22 +14,16 @@ import { BankAccountFormComponent } from '../form.component';
|
|||||||
templateUrl: './select.component.html',
|
templateUrl: './select.component.html',
|
||||||
imports: [ReactiveFormsModule, Select, UikitFieldComponent, Button, BankAccountFormComponent],
|
imports: [ReactiveFormsModule, Select, UikitFieldComponent, Button, BankAccountFormComponent],
|
||||||
})
|
})
|
||||||
export class BankAccountsSelectComponent extends AbstractSelectComponent<IBankAccountsResponse> {
|
export class BankAccountsSelectComponent extends AbstractSelectComponent<
|
||||||
|
IBankAccountsResponse,
|
||||||
|
IPaginatedResponse<IBankAccountsResponse>
|
||||||
|
> {
|
||||||
constructor(private service: BankAccountsService) {
|
constructor(private service: BankAccountsService) {
|
||||||
super();
|
super();
|
||||||
this.getData();
|
this.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
getData() {
|
getDataService() {
|
||||||
this.loading.set(true);
|
return this.service.getAll();
|
||||||
this.service.getAll().subscribe({
|
|
||||||
next: (res) => {
|
|
||||||
this.items.set(res.data);
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
error: () => {
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { IPaginatedResponse } from '@/core/models/service.model';
|
||||||
import { AbstractSelectComponent } from '@/shared/components';
|
import { AbstractSelectComponent } from '@/shared/components';
|
||||||
import { UikitFieldComponent } from '@/uikit';
|
import { UikitFieldComponent } from '@/uikit';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
@@ -13,22 +14,16 @@ import { BankBranchFormComponent } from '../form.component';
|
|||||||
templateUrl: './select.component.html',
|
templateUrl: './select.component.html',
|
||||||
imports: [ReactiveFormsModule, Select, UikitFieldComponent, Button, BankBranchFormComponent],
|
imports: [ReactiveFormsModule, Select, UikitFieldComponent, Button, BankBranchFormComponent],
|
||||||
})
|
})
|
||||||
export class BankBranchesSelectComponent extends AbstractSelectComponent<IBankBranchResponse> {
|
export class BankBranchesSelectComponent extends AbstractSelectComponent<
|
||||||
|
IBankBranchResponse,
|
||||||
|
IPaginatedResponse<IBankBranchResponse>
|
||||||
|
> {
|
||||||
constructor(private service: BankBranchesService) {
|
constructor(private service: BankBranchesService) {
|
||||||
super();
|
super();
|
||||||
this.getData();
|
this.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
getData() {
|
getDataService() {
|
||||||
this.loading.set(true);
|
return this.service.getAll();
|
||||||
this.service.getAll().subscribe({
|
|
||||||
next: (res) => {
|
|
||||||
this.items.set(res.data);
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
error: () => {
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
<form [formGroup]="form" class="flex items-end gap-4">
|
<form [formGroup]="form" class="flex items-end gap-4">
|
||||||
<div class="grow grid grid-cols-4 gap-2">
|
<div class="grow grid grid-cols-4 gap-2">
|
||||||
<inventories-select-field [control]="form.controls.inventoryId" (onChange)="onChangeInventory($event)" />
|
<inventories-select-field
|
||||||
<products-select-field [control]="form.controls.productId" (onChange)="onChangeProduct($event)" />
|
[control]="form.controls.inventoryId"
|
||||||
<uikit-datepicker [control]="form.controls.startDate" />
|
(onChange)="onChangeInventory($event)"
|
||||||
<uikit-datepicker [control]="form.controls.endDate" />
|
(onSetDefaultDataItem)="setDefaultInventory($event)"
|
||||||
|
/>
|
||||||
|
<products-select-field
|
||||||
|
[control]="form.controls.productId"
|
||||||
|
(onChange)="onChangeProduct($event)"
|
||||||
|
(onSetDefaultDataItem)="setDefaultProduct($event)"
|
||||||
|
/>
|
||||||
|
<uikit-datepicker [control]="form.controls.startDate" label="از تاریخ" />
|
||||||
|
<uikit-datepicker [control]="form.controls.endDate" label="تا تاریخ" />
|
||||||
</div>
|
</div>
|
||||||
<div class="shrink-0">
|
<div class="shrink-0">
|
||||||
<button pButton (click)="search()">جستجو</button>
|
<button pButton (click)="search()">جستجو</button>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { Maybe } from '@/core';
|
import { Maybe } from '@/core';
|
||||||
import { InventoriesSelectComponent } from '@/modules/inventories/components';
|
import { InventoriesSelectComponent } from '@/modules/inventories/components';
|
||||||
|
import { IInventorySummaryResponse } from '@/modules/inventories/models';
|
||||||
import { ProductsSelectComponent } from '@/modules/products/components/select/select.component';
|
import { ProductsSelectComponent } from '@/modules/products/components/select/select.component';
|
||||||
|
import { IProductResponse } from '@/modules/products/models';
|
||||||
import { UikitFlatpickrJalaliComponent } from '@/uikit';
|
import { UikitFlatpickrJalaliComponent } from '@/uikit';
|
||||||
import { Component, EventEmitter, inject, Output } from '@angular/core';
|
import { Component, EventEmitter, inject, Output } from '@angular/core';
|
||||||
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
|
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
|
||||||
@@ -34,6 +36,7 @@ export class CardexFiltersComponent {
|
|||||||
|
|
||||||
constructor(private router: Router) {
|
constructor(private router: Router) {
|
||||||
this.filters = this.store.filters();
|
this.filters = this.store.filters();
|
||||||
|
this.form.patchValue(this.filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
form = this.fb.group({
|
form = this.fb.group({
|
||||||
@@ -55,4 +58,13 @@ export class CardexFiltersComponent {
|
|||||||
|
|
||||||
this.store.getCardex();
|
this.store.getCardex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setDefaultInventory(inventory: IInventorySummaryResponse) {
|
||||||
|
this.store.setDefaultInventory(inventory);
|
||||||
|
}
|
||||||
|
setDefaultProduct(product: IProductResponse) {
|
||||||
|
console.log('setDefaultProduct');
|
||||||
|
|
||||||
|
this.store.setDefaultProduct(product);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,11 @@
|
|||||||
<th rowspan="2" [style]="{ textAlign: 'center', width: '12rem' }">شرح</th>
|
<th rowspan="2" [style]="{ textAlign: 'center', width: '12rem' }">شرح</th>
|
||||||
<th rowspan="2" [style]="{ textAlign: 'center', width: '6rem' }">شماره</th>
|
<th rowspan="2" [style]="{ textAlign: 'center', width: '6rem' }">شماره</th>
|
||||||
<th rowspan="2" [style]="{ textAlign: 'center', minWidth: '14rem', width: '14rem' }">طرف حساب</th>
|
<th rowspan="2" [style]="{ textAlign: 'center', minWidth: '14rem', width: '14rem' }">طرف حساب</th>
|
||||||
|
@if (variant === "inventory") {
|
||||||
<th rowspan="2" [style]="{ textAlign: 'center', width: '12rem' }">کالا</th>
|
<th rowspan="2" [style]="{ textAlign: 'center', width: '12rem' }">کالا</th>
|
||||||
|
} @else if (variant === "product") {
|
||||||
|
<th rowspan="2" [style]="{ textAlign: 'center', width: '12rem' }">انبار</th>
|
||||||
|
}
|
||||||
<th colspan="2" class="text-center!" [style]="{ width: '15rem' }">ورودی</th>
|
<th colspan="2" class="text-center!" [style]="{ width: '15rem' }">ورودی</th>
|
||||||
<th colspan="2" class="text-center!" [style]="{ width: '15rem' }">خروجی</th>
|
<th colspan="2" class="text-center!" [style]="{ width: '15rem' }">خروجی</th>
|
||||||
<th colspan="1" class="text-center!" [style]="{ width: '5rem' }">مانده</th>
|
<th colspan="1" class="text-center!" [style]="{ width: '5rem' }">مانده</th>
|
||||||
@@ -44,7 +48,11 @@
|
|||||||
<td class="text-center!">
|
<td class="text-center!">
|
||||||
{{ (item.referenceType === "SALES" ? item.customer?.name : item.supplier?.name) || "-" }}
|
{{ (item.referenceType === "SALES" ? item.customer?.name : item.supplier?.name) || "-" }}
|
||||||
</td>
|
</td>
|
||||||
|
@if (variant === "inventory") {
|
||||||
<td class="text-center!">{{ item.product.name || "-" }}</td>
|
<td class="text-center!">{{ item.product.name || "-" }}</td>
|
||||||
|
} @else if (variant === "product") {
|
||||||
|
<td class="text-center!">{{ item.inventory.name || "-" }}</td>
|
||||||
|
}
|
||||||
<td class="text-center!">
|
<td class="text-center!">
|
||||||
{{ item.type === "IN" ? item.quantity : 0 }}
|
{{ item.type === "IN" ? item.quantity : 0 }}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -18,5 +18,6 @@ import { IInventoryCardex } from './types';
|
|||||||
export class CardexComponent {
|
export class CardexComponent {
|
||||||
@Input() items: IInventoryCardex[] = [];
|
@Input() items: IInventoryCardex[] = [];
|
||||||
@Input() loading: boolean = false;
|
@Input() loading: boolean = false;
|
||||||
|
@Input() variant: 'inventory' | 'product' | 'general' = 'inventory';
|
||||||
constructor() {}
|
constructor() {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export interface CardexState extends PaginatedState<ICardexResponse> {
|
|||||||
filters: ICardexRequestPayload;
|
filters: ICardexRequestPayload;
|
||||||
selectedInventory: Maybe<ICardexInventorySummary>;
|
selectedInventory: Maybe<ICardexInventorySummary>;
|
||||||
selectedProduct: Maybe<ICardexProductSummary>;
|
selectedProduct: Maybe<ICardexProductSummary>;
|
||||||
variant: 'inventory' | 'product' | 'both';
|
variant: 'inventory' | 'product' | 'general';
|
||||||
canChangeVariant: boolean;
|
canChangeVariant: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,17 +28,17 @@ export class CardexStore extends PaginatedStore<ICardexResponse, CardexState> {
|
|||||||
filters: {},
|
filters: {},
|
||||||
selectedInventory: null,
|
selectedInventory: null,
|
||||||
selectedProduct: null,
|
selectedProduct: null,
|
||||||
variant: 'both',
|
variant: 'general',
|
||||||
canChangeVariant: true,
|
canChangeVariant: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private activeRoute: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private service: CardexService,
|
private service: CardexService,
|
||||||
private toastService: ToastService,
|
private toastService: ToastService,
|
||||||
) {
|
) {
|
||||||
const queryParams = activeRoute.snapshot.queryParams;
|
const queryParams = route.snapshot.queryParams;
|
||||||
|
|
||||||
super({
|
super({
|
||||||
loading: false,
|
loading: false,
|
||||||
@@ -52,14 +52,16 @@ export class CardexStore extends PaginatedStore<ICardexResponse, CardexState> {
|
|||||||
totalPages: 0,
|
totalPages: 0,
|
||||||
hasMore: false,
|
hasMore: false,
|
||||||
filters: {
|
filters: {
|
||||||
inventoryId: queryParams['inventoryId'],
|
inventoryId: queryParams['inventoryId']
|
||||||
productId: queryParams['productId'],
|
? parseInt(queryParams['inventoryId'], 10)
|
||||||
|
: undefined,
|
||||||
|
productId: queryParams['productId'] ? parseInt(queryParams['productId'], 10) : undefined,
|
||||||
startDate: queryParams['startDate'],
|
startDate: queryParams['startDate'],
|
||||||
endDate: queryParams['endDate'],
|
endDate: queryParams['endDate'],
|
||||||
},
|
},
|
||||||
selectedInventory: null,
|
selectedInventory: null,
|
||||||
selectedProduct: null,
|
selectedProduct: null,
|
||||||
variant: 'both',
|
variant: 'general',
|
||||||
canChangeVariant: true,
|
canChangeVariant: true,
|
||||||
});
|
});
|
||||||
this.initial();
|
this.initial();
|
||||||
@@ -75,7 +77,9 @@ export class CardexStore extends PaginatedStore<ICardexResponse, CardexState> {
|
|||||||
case 'inventory':
|
case 'inventory':
|
||||||
return `کاردکس انبار ${this._state().selectedInventory?.name}`;
|
return `کاردکس انبار ${this._state().selectedInventory?.name}`;
|
||||||
default:
|
default:
|
||||||
return 'کاردکس';
|
return `کاردکس ${this._state().selectedProduct ? 'کالای ' + this._state().selectedProduct?.name : ''} ${
|
||||||
|
this._state().selectedInventory ? 'در انبار ' + this._state().selectedInventory?.name : ''
|
||||||
|
}`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -83,7 +87,7 @@ export class CardexStore extends PaginatedStore<ICardexResponse, CardexState> {
|
|||||||
* Reset state to initial values
|
* Reset state to initial values
|
||||||
*/
|
*/
|
||||||
reset(): void {
|
reset(): void {
|
||||||
const queryParams = this.activeRoute.snapshot.queryParams;
|
const queryParams = this.route.snapshot.queryParams;
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
initialized: false,
|
initialized: false,
|
||||||
@@ -103,7 +107,7 @@ export class CardexStore extends PaginatedStore<ICardexResponse, CardexState> {
|
|||||||
},
|
},
|
||||||
selectedInventory: null,
|
selectedInventory: null,
|
||||||
selectedProduct: null,
|
selectedProduct: null,
|
||||||
variant: 'both',
|
variant: 'general',
|
||||||
canChangeVariant: this.state().canChangeVariant,
|
canChangeVariant: this.state().canChangeVariant,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -132,7 +136,7 @@ export class CardexStore extends PaginatedStore<ICardexResponse, CardexState> {
|
|||||||
const { productId, inventoryId, startDate, endDate } = this.filters();
|
const { productId, inventoryId, startDate, endDate } = this.filters();
|
||||||
const filters = {} as Partial<ICardexRequestPayload>;
|
const filters = {} as Partial<ICardexRequestPayload>;
|
||||||
Object.entries(this.filters()).forEach(([key, value]) => {
|
Object.entries(this.filters()).forEach(([key, value]) => {
|
||||||
if (value) {
|
if (value && value !== '0') {
|
||||||
filters[key as keyof ICardexRequestPayload] = value;
|
filters[key as keyof ICardexRequestPayload] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -151,9 +155,18 @@ export class CardexStore extends PaginatedStore<ICardexResponse, CardexState> {
|
|||||||
updateFilter(filters: ICardexRequestPayload) {
|
updateFilter(filters: ICardexRequestPayload) {
|
||||||
this.updateVariant();
|
this.updateVariant();
|
||||||
|
|
||||||
this.router.navigate([], {
|
console.log('filters');
|
||||||
queryParams: filters,
|
console.log(filters);
|
||||||
skipLocationChange: true,
|
const cleanedFilters = this.validateFilters() || {};
|
||||||
|
|
||||||
|
this.router
|
||||||
|
.navigate([], {
|
||||||
|
relativeTo: this.route,
|
||||||
|
queryParams: cleanedFilters,
|
||||||
|
})
|
||||||
|
.then((res) => console.log(res))
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
});
|
});
|
||||||
this.patchState({ filters });
|
this.patchState({ filters });
|
||||||
}
|
}
|
||||||
@@ -169,10 +182,18 @@ export class CardexStore extends PaginatedStore<ICardexResponse, CardexState> {
|
|||||||
this.patchState({ canChangeVariant: status });
|
this.patchState({ canChangeVariant: status });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setDefaultInventory(inventory: ICardexInventorySummary) {
|
||||||
|
this.patchState({ selectedInventory: inventory });
|
||||||
|
}
|
||||||
|
|
||||||
|
setDefaultProduct(product: ICardexProductSummary) {
|
||||||
|
this.patchState({ selectedProduct: product });
|
||||||
|
}
|
||||||
|
|
||||||
private updateVariant() {
|
private updateVariant() {
|
||||||
const inventoryIsSelected = Boolean(this._state().selectedInventory);
|
const inventoryIsSelected = Boolean(this._state().selectedInventory);
|
||||||
const productIsSelected = Boolean(this._state().selectedProduct);
|
const productIsSelected = Boolean(this._state().selectedProduct);
|
||||||
let variant = 'both' as 'product' | 'inventory' | 'both';
|
let variant = 'general' as 'product' | 'inventory' | 'general';
|
||||||
if (inventoryIsSelected) {
|
if (inventoryIsSelected) {
|
||||||
if (!productIsSelected) {
|
if (!productIsSelected) {
|
||||||
variant = 'inventory';
|
variant = 'inventory';
|
||||||
|
|||||||
@@ -7,9 +7,8 @@
|
|||||||
<uikit-empty-state title="برای مشاهدهی کاردکس اطلاعات بالا را تکمیل کنید"> </uikit-empty-state>
|
<uikit-empty-state title="برای مشاهدهی کاردکس اطلاعات بالا را تکمیل کنید"> </uikit-empty-state>
|
||||||
} @else {
|
} @else {
|
||||||
<h3 class="mb-4">{{ cardexTitle }}</h3>
|
<h3 class="mb-4">{{ cardexTitle }}</h3>
|
||||||
@if (variant === "inventory") {
|
|
||||||
<cardex-templates-inventory [items]="items" [loading]="loading" />
|
<cardex-templates-inventory [items]="items" [loading]="loading" [variant]="variant" />
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</p-card>
|
</p-card>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { IPaginatedResponse } from '@/core/models/service.model';
|
||||||
import { AbstractSelectComponent } from '@/shared/components';
|
import { AbstractSelectComponent } from '@/shared/components';
|
||||||
import { UikitFieldComponent } from '@/uikit';
|
import { UikitFieldComponent } from '@/uikit';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
@@ -13,22 +14,16 @@ import { CustomerFormComponent } from '../form.component';
|
|||||||
templateUrl: './select.component.html',
|
templateUrl: './select.component.html',
|
||||||
imports: [ReactiveFormsModule, Select, UikitFieldComponent, Button, CustomerFormComponent],
|
imports: [ReactiveFormsModule, Select, UikitFieldComponent, Button, CustomerFormComponent],
|
||||||
})
|
})
|
||||||
export class CustomersSelectComponent extends AbstractSelectComponent<ICustomerResponse> {
|
export class CustomersSelectComponent extends AbstractSelectComponent<
|
||||||
|
ICustomerResponse,
|
||||||
|
IPaginatedResponse<ICustomerResponse>
|
||||||
|
> {
|
||||||
constructor(private service: CustomersService) {
|
constructor(private service: CustomersService) {
|
||||||
super();
|
super();
|
||||||
this.getData();
|
this.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
getData() {
|
getDataService() {
|
||||||
this.loading.set(true);
|
return this.service.getAll();
|
||||||
this.service.getAll().subscribe({
|
|
||||||
next: (res) => {
|
|
||||||
this.items.set(res.data);
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
error: () => {
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { IPaginatedResponse } from '@/core/models/service.model';
|
||||||
import { AbstractSelectComponent } from '@/shared/components';
|
import { AbstractSelectComponent } from '@/shared/components';
|
||||||
import { UikitFieldComponent } from '@/uikit';
|
import { UikitFieldComponent } from '@/uikit';
|
||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
@@ -19,27 +20,19 @@ import { InventoryBankAccountFormComponent } from './form.component';
|
|||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class InventoryBankAccountSelectComponent extends AbstractSelectComponent<IInventoryBankAccountResponse> {
|
export class InventoryBankAccountSelectComponent extends AbstractSelectComponent<
|
||||||
|
IInventoryBankAccountResponse,
|
||||||
|
IPaginatedResponse<IInventoryBankAccountResponse>
|
||||||
|
> {
|
||||||
@Input() inventoryId!: string;
|
@Input() inventoryId!: string;
|
||||||
@Input() override showClear: boolean = false;
|
@Input() override showClear: boolean = false;
|
||||||
|
|
||||||
constructor(private service: InventoryBankAccountsService) {
|
constructor(private service: InventoryBankAccountsService) {
|
||||||
super();
|
super();
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.getData();
|
this.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
getData(): void {
|
getDataService() {
|
||||||
this.loading.set(true);
|
return this.service.getBankAccounts(Number(this.inventoryId));
|
||||||
this.service.getBankAccounts(Number(this.inventoryId)).subscribe({
|
|
||||||
next: (res) => {
|
|
||||||
this.loading.set(false);
|
|
||||||
this.items.set(res.data);
|
|
||||||
},
|
|
||||||
error: () => {
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { IPaginatedResponse } from '@/core/models/service.model';
|
||||||
import { AbstractSelectComponent } from '@/shared/components';
|
import { AbstractSelectComponent } from '@/shared/components';
|
||||||
import { UikitFieldComponent } from '@/uikit';
|
import { UikitFieldComponent } from '@/uikit';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
@@ -11,22 +12,16 @@ import { InventoriesService } from '../../services/main.service';
|
|||||||
templateUrl: './select.component.html',
|
templateUrl: './select.component.html',
|
||||||
imports: [ReactiveFormsModule, Select, UikitFieldComponent],
|
imports: [ReactiveFormsModule, Select, UikitFieldComponent],
|
||||||
})
|
})
|
||||||
export class InventoriesSelectComponent extends AbstractSelectComponent<IInventorySummaryResponse> {
|
export class InventoriesSelectComponent extends AbstractSelectComponent<
|
||||||
|
IInventorySummaryResponse,
|
||||||
|
IPaginatedResponse<IInventorySummaryResponse>
|
||||||
|
> {
|
||||||
constructor(private service: InventoriesService) {
|
constructor(private service: InventoriesService) {
|
||||||
super();
|
super();
|
||||||
this.getData();
|
this.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
getData() {
|
getDataService() {
|
||||||
this.loading.set(true);
|
return this.service.getAll();
|
||||||
this.service.getAll().subscribe({
|
|
||||||
next: (res) => {
|
|
||||||
this.items.set(res.data);
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
error: () => {
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ISummary from '@/core/models/summary';
|
||||||
import { IInventoryBankAccountSummary } from './types';
|
import { IInventoryBankAccountSummary } from './types';
|
||||||
|
|
||||||
export interface IInventoryPosAccountRawResponse {
|
export interface IInventoryPosAccountRawResponse {
|
||||||
@@ -6,7 +7,7 @@ export interface IInventoryPosAccountRawResponse {
|
|||||||
code: string;
|
code: string;
|
||||||
description: string;
|
description: string;
|
||||||
bankAccountId: number;
|
bankAccountId: number;
|
||||||
inventoryId: number;
|
inventory: ISummary;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
deletedAt: null;
|
deletedAt: null;
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import { ToastService } from '@/core/services/toast.service';
|
||||||
|
import { EntityState, EntityStore } from '@/core/state';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { IInventoryDetailResponse } from '../models';
|
||||||
|
import { InventoriesService } from '../services';
|
||||||
|
|
||||||
|
export interface InventoryState extends EntityState<IInventoryDetailResponse> {}
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class InventoryStore extends EntityStore<IInventoryDetailResponse, InventoryState> {
|
||||||
|
private readonly _inventoryState = {
|
||||||
|
isRefreshing: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private activeRoute: ActivatedRoute,
|
||||||
|
private service: InventoriesService,
|
||||||
|
private toastService: ToastService,
|
||||||
|
) {
|
||||||
|
super({
|
||||||
|
loading: false,
|
||||||
|
initialized: false,
|
||||||
|
error: null,
|
||||||
|
isRefreshing: false,
|
||||||
|
entities: {},
|
||||||
|
selectedId: null,
|
||||||
|
ids: [],
|
||||||
|
});
|
||||||
|
this.initial();
|
||||||
|
}
|
||||||
|
|
||||||
|
supplierId!: string;
|
||||||
|
|
||||||
|
initial() {}
|
||||||
|
|
||||||
|
getSingle(inventoryId: string) {
|
||||||
|
if (this.entities()[inventoryId]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.patchState({ loading: true });
|
||||||
|
this.service.getSingle(inventoryId).subscribe({
|
||||||
|
next: (res) => {
|
||||||
|
this.patchState({
|
||||||
|
entities: { [res.id]: res },
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
this.patchState({ loading: false, error: err });
|
||||||
|
this.toastService.error({
|
||||||
|
text: 'خطا در دریافت اطلاعات انبار',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh(inventoryId: string) {
|
||||||
|
const { inventoryId: _, ...entities } = this.entities();
|
||||||
|
this.patchState({
|
||||||
|
entities,
|
||||||
|
});
|
||||||
|
this.getSingle(inventoryId);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset(): void {
|
||||||
|
const queryParams = this.activeRoute.snapshot.queryParams;
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
initialized: false,
|
||||||
|
error: null,
|
||||||
|
isRefreshing: false,
|
||||||
|
entities: {},
|
||||||
|
selectedId: null,
|
||||||
|
ids: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +1,22 @@
|
|||||||
<p-card class="">
|
<p-card class="">
|
||||||
<ng-template #header>
|
<ng-template #header>
|
||||||
<div class="p-4 flex items-center justify-between">
|
<app-inner-pages-header [pageTitle]="pageTitle()" [backRoute]="['/inventories', inventoryId]" class="p-4! block">
|
||||||
<span class="text-xl font-bold">نقاط فروش متصل به انبار</span>
|
<ng-template #actions>
|
||||||
<div class="flex gap-2">
|
|
||||||
<button pButton outlined (click)="openAddForm()">ایجاد نقطه فروش جدید</button>
|
<button pButton outlined (click)="openAddForm()">ایجاد نقطه فروش جدید</button>
|
||||||
<button pButton outlined icon="pi pi-refresh" [loading]="loading()" (click)="getItems()"></button>
|
<button pButton outlined icon="pi pi-refresh" [loading]="loading()" (click)="getItems()"></button>
|
||||||
</div>
|
</ng-template>
|
||||||
</div>
|
</app-inner-pages-header>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<app-page-data-list
|
<app-page-data-list
|
||||||
[columns]="columns"
|
[columns]="columns"
|
||||||
emptyPlaceholderTitle="نقطه فروش برای این انبار تعریف نشده است"
|
emptyPlaceholderTitle="نقطه فروش برای این انبار تعریف نشده است"
|
||||||
emptyPlaceholderDescription="برای تعریف نقطهی فروش، روی دکمهٔ بالا کلیک کنید."
|
emptyPlaceholderDescription="برای تعریف نقطهی فروش، روی دکمهٔ بالا کلیک کنید."
|
||||||
|
[showDetails]="true"
|
||||||
[items]="items()"
|
[items]="items()"
|
||||||
[loading]="loading()"
|
[loading]="loading()"
|
||||||
(onAdd)="openAddForm()"
|
(onAdd)="openAddForm()"
|
||||||
|
(onDetails)="toPos($event)"
|
||||||
/>
|
/>
|
||||||
@if (inventoryId) {
|
@if (inventoryId) {
|
||||||
<app-inventory-pos-account-form [(visible)]="visibleForm" [inventoryId]="inventoryId" />
|
<app-inventory-pos-account-form [(visible)]="visibleForm" [inventoryId]="inventoryId" />
|
||||||
|
|||||||
@@ -1,32 +1,44 @@
|
|||||||
|
import { InnerPagesHeaderComponent } from '@/shared/components/innerPagesHeader/inner-pages-header.component';
|
||||||
import {
|
import {
|
||||||
IColumn,
|
IColumn,
|
||||||
PageDataListComponent,
|
PageDataListComponent,
|
||||||
} from '@/shared/components/pageDataList/page-data-list.component';
|
} from '@/shared/components/pageDataList/page-data-list.component';
|
||||||
import { Component, inject, signal } from '@angular/core';
|
import { Component, computed, inject, signal } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { ButtonDirective } from 'primeng/button';
|
import { ButtonDirective } from 'primeng/button';
|
||||||
import { Card } from 'primeng/card';
|
import { Card } from 'primeng/card';
|
||||||
import { InventoryPosAccountFormComponent } from '../../components/posAccounts/form.component';
|
import { InventoryPosAccountFormComponent } from '../../components/posAccounts/form.component';
|
||||||
import { IInventoryPosAccountResponse } from '../../models';
|
import { IInventoryPosAccountResponse } from '../../models';
|
||||||
import { InventoryPosAccountsService } from '../../services/posAccounts.service';
|
import { InventoryPosAccountsService } from '../../services/posAccounts.service';
|
||||||
|
import { InventoryStore } from '../../store/inventory.store';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-inventory-pos-account-list',
|
selector: 'app-inventory-pos-account-list',
|
||||||
templateUrl: './list.component.html',
|
templateUrl: './list.component.html',
|
||||||
imports: [PageDataListComponent, Card, ButtonDirective, InventoryPosAccountFormComponent],
|
imports: [
|
||||||
|
PageDataListComponent,
|
||||||
|
Card,
|
||||||
|
ButtonDirective,
|
||||||
|
InventoryPosAccountFormComponent,
|
||||||
|
InnerPagesHeaderComponent,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class InventoryPosAccountListComponent {
|
export class InventoryPosAccountListComponent {
|
||||||
private readonly route = inject(ActivatedRoute);
|
private readonly route = inject(ActivatedRoute);
|
||||||
private readonly service = inject(InventoryPosAccountsService);
|
private readonly service = inject(InventoryPosAccountsService);
|
||||||
|
private readonly inventoryStore = inject(InventoryStore);
|
||||||
|
|
||||||
|
inventoryId = this.route.snapshot.params['inventoryId'];
|
||||||
items = signal<IInventoryPosAccountResponse[]>([]);
|
items = signal<IInventoryPosAccountResponse[]>([]);
|
||||||
loading = signal<boolean>(false);
|
loading = signal<boolean>(false);
|
||||||
visibleForm = signal<boolean>(false);
|
visibleForm = signal<boolean>(false);
|
||||||
inventoryId = this.route.snapshot.params['inventoryId'];
|
inventory = computed(() => this.inventoryStore.entities()[this.inventoryId]);
|
||||||
|
|
||||||
columns = [] as IColumn<IInventoryPosAccountResponse>[];
|
columns = [] as IColumn<IInventoryPosAccountResponse>[];
|
||||||
|
|
||||||
|
pageTitle = computed(() => `نقاط فروش متصل به انبار ${this.inventory()?.name || ''}`);
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.inventoryStore.getSingle(this.inventoryId);
|
||||||
this.getItems();
|
this.getItems();
|
||||||
this.columns = [
|
this.columns = [
|
||||||
{
|
{
|
||||||
@@ -73,4 +85,8 @@ export class InventoryPosAccountListComponent {
|
|||||||
openAddForm() {
|
openAddForm() {
|
||||||
this.visibleForm.set(true);
|
this.visibleForm.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toPos(item: IInventoryPosAccountResponse) {
|
||||||
|
window.open(`/pos/${item.id}`, '_blank');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { IPaginatedResponse } from '@/core/models/service.model';
|
||||||
import { AbstractSelectComponent } from '@/shared/components';
|
import { AbstractSelectComponent } from '@/shared/components';
|
||||||
import { UikitFieldComponent } from '@/uikit';
|
import { UikitFieldComponent } from '@/uikit';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
@@ -13,22 +14,16 @@ import { ProductBrandFormComponent } from '../form.component';
|
|||||||
templateUrl: './select.component.html',
|
templateUrl: './select.component.html',
|
||||||
imports: [ReactiveFormsModule, Select, UikitFieldComponent, Button, ProductBrandFormComponent],
|
imports: [ReactiveFormsModule, Select, UikitFieldComponent, Button, ProductBrandFormComponent],
|
||||||
})
|
})
|
||||||
export class ProductBrandsSelectComponent extends AbstractSelectComponent<IProductBrandResponse> {
|
export class ProductBrandsSelectComponent extends AbstractSelectComponent<
|
||||||
|
IProductBrandResponse,
|
||||||
|
IPaginatedResponse<IProductBrandResponse>
|
||||||
|
> {
|
||||||
constructor(private service: ProductBrandsService) {
|
constructor(private service: ProductBrandsService) {
|
||||||
super();
|
super();
|
||||||
this.getData();
|
this.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
getData() {
|
getDataService() {
|
||||||
this.loading.set(true);
|
return this.service.getAll();
|
||||||
this.service.getAll().subscribe({
|
|
||||||
next: (res) => {
|
|
||||||
this.items.set(res.data);
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
error: () => {
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { IPaginatedResponse } from '@/core/models/service.model';
|
||||||
import { AbstractSelectComponent } from '@/shared/components';
|
import { AbstractSelectComponent } from '@/shared/components';
|
||||||
import { UikitFieldComponent } from '@/uikit';
|
import { UikitFieldComponent } from '@/uikit';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
@@ -13,22 +14,16 @@ import { ProductCategoryFormComponent } from '../form.component';
|
|||||||
templateUrl: './select.component.html',
|
templateUrl: './select.component.html',
|
||||||
imports: [ReactiveFormsModule, Select, UikitFieldComponent, Button, ProductCategoryFormComponent],
|
imports: [ReactiveFormsModule, Select, UikitFieldComponent, Button, ProductCategoryFormComponent],
|
||||||
})
|
})
|
||||||
export class ProductCategoriesSelectComponent extends AbstractSelectComponent<IProductCategoryResponse> {
|
export class ProductCategoriesSelectComponent extends AbstractSelectComponent<
|
||||||
|
IProductCategoryResponse,
|
||||||
|
IPaginatedResponse<IProductCategoryResponse>
|
||||||
|
> {
|
||||||
constructor(private service: ProductCategoriesService) {
|
constructor(private service: ProductCategoriesService) {
|
||||||
super();
|
super();
|
||||||
this.getData();
|
this.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
getData() {
|
getDataService() {
|
||||||
this.loading.set(true);
|
return this.service.getAll();
|
||||||
this.service.getAll().subscribe({
|
|
||||||
next: (res) => {
|
|
||||||
this.items.set(res.data);
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
error: () => {
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { IPaginatedResponse } from '@/core/models/service.model';
|
||||||
import { AbstractSelectComponent } from '@/shared/components';
|
import { AbstractSelectComponent } from '@/shared/components';
|
||||||
import { UikitFieldComponent } from '@/uikit';
|
import { UikitFieldComponent } from '@/uikit';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
@@ -12,26 +13,16 @@ import { ProductsService } from '../../services/main.service';
|
|||||||
templateUrl: './select.component.html',
|
templateUrl: './select.component.html',
|
||||||
imports: [ReactiveFormsModule, Select, UikitFieldComponent, CommonModule],
|
imports: [ReactiveFormsModule, Select, UikitFieldComponent, CommonModule],
|
||||||
})
|
})
|
||||||
export class ProductsSelectComponent extends AbstractSelectComponent<IProductResponse> {
|
export class ProductsSelectComponent extends AbstractSelectComponent<
|
||||||
|
IProductResponse,
|
||||||
|
IPaginatedResponse<IProductResponse>
|
||||||
|
> {
|
||||||
constructor(private service: ProductsService) {
|
constructor(private service: ProductsService) {
|
||||||
super();
|
super();
|
||||||
this.getData();
|
this.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
getLabel(): string {
|
getDataService() {
|
||||||
return 'کالا';
|
return this.service.getAll();
|
||||||
}
|
|
||||||
|
|
||||||
getData() {
|
|
||||||
this.loading.set(true);
|
|
||||||
this.service.getAll().subscribe({
|
|
||||||
next: (res) => {
|
|
||||||
this.items.set(res.data);
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
error: () => {
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<p-card>
|
<p-card>
|
||||||
<ng-template pTemplate="header">
|
<ng-template pTemplate="header">
|
||||||
<div class="p-4 flex items-center justify-between">
|
<div class="p-4 flex items-center justify-between">
|
||||||
<span class="text-xl font-bold">تراکنشهای تامینکننده</span>
|
<span class="text-xl font-bold">دفتر کل تامینکننده</span>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
@if (showViewAllCTA) {
|
@if (showViewAllCTA) {
|
||||||
<button pButton outlined [routerLink]="['/suppliers', supplierId, 'ledger']">مشاهدهی تمامی تراکنشها</button>
|
<button pButton outlined [routerLink]="['/suppliers', supplierId, 'ledger']">مشاهدهی تمامی تراکنشها</button>
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
<ng-template pTemplate="body" let-item let-i="rowIndex">
|
<ng-template pTemplate="body" let-item let-i="rowIndex">
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ i + 1 }}</td>
|
<td>{{ i + 1 }}</td>
|
||||||
<td><span [appPriceMask]="item.debit"></span></td>
|
<td><span [appPriceMask]="item.debit" [class]="item.debit ? 'text-red-500' : ''"></span></td>
|
||||||
<td><span [appPriceMask]="item.credit"></span></td>
|
<td><span [appPriceMask]="item.credit" [class]="item.credit ? 'text-green-500' : ''"></span></td>
|
||||||
<td><span [appPriceMask]="item.balance"></span></td>
|
<td><span [appPriceMask]="item.balance"></span></td>
|
||||||
<td><span [jalaliDate]="item.createdAt"></span></td>
|
<td><span [jalaliDate]="item.createdAt"></span></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { IPaginatedResponse } from '@/core/models/service.model';
|
||||||
import { AbstractSelectComponent } from '@/shared/components';
|
import { AbstractSelectComponent } from '@/shared/components';
|
||||||
import { UikitFieldComponent } from '@/uikit';
|
import { UikitFieldComponent } from '@/uikit';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
@@ -11,21 +12,16 @@ import { SuppliersService } from '../../services/main.service';
|
|||||||
templateUrl: './select.component.html',
|
templateUrl: './select.component.html',
|
||||||
imports: [ReactiveFormsModule, SelectModule, UikitFieldComponent],
|
imports: [ReactiveFormsModule, SelectModule, UikitFieldComponent],
|
||||||
})
|
})
|
||||||
export class SuppliersSelectComponent extends AbstractSelectComponent<ISupplierResponse> {
|
export class SuppliersSelectComponent extends AbstractSelectComponent<
|
||||||
|
ISupplierResponse,
|
||||||
|
IPaginatedResponse<ISupplierResponse>
|
||||||
|
> {
|
||||||
constructor(private service: SuppliersService) {
|
constructor(private service: SuppliersService) {
|
||||||
super();
|
super();
|
||||||
this.getData();
|
this.getData();
|
||||||
}
|
}
|
||||||
getData() {
|
|
||||||
this.loading.set(true);
|
getDataService() {
|
||||||
this.service.getAll().subscribe({
|
return this.service.getAll();
|
||||||
next: (res) => {
|
|
||||||
this.items.set(res.data);
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
error: () => {
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,22 +11,13 @@ import { BanksStore } from '../../store/main.store';
|
|||||||
templateUrl: './select.component.html',
|
templateUrl: './select.component.html',
|
||||||
imports: [ReactiveFormsModule, Select, UikitFieldComponent],
|
imports: [ReactiveFormsModule, Select, UikitFieldComponent],
|
||||||
})
|
})
|
||||||
export class BanksSelectComponent extends AbstractSelectComponent<IBankResponse> {
|
export class BanksSelectComponent extends AbstractSelectComponent<IBankResponse, IBankResponse[]> {
|
||||||
constructor(private store: BanksStore) {
|
constructor(private store: BanksStore) {
|
||||||
super();
|
super();
|
||||||
this.getData();
|
this.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
getData() {
|
getDataService() {
|
||||||
this.loading.set(true);
|
return this.store.getItems();
|
||||||
this.store.getItems().subscribe({
|
|
||||||
next: (res) => {
|
|
||||||
this.items.set(res || []);
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
error: () => {
|
|
||||||
this.loading.set(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Maybe } from '@/core';
|
import { Maybe } from '@/core';
|
||||||
import { Component, EventEmitter, Input, model, Output, signal } from '@angular/core';
|
import { Component, EventEmitter, Input, model, Output, signal } from '@angular/core';
|
||||||
import { FormControl } from '@angular/forms';
|
import { FormControl } from '@angular/forms';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
export interface ISelectItem {
|
export interface ISelectItem {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -11,7 +12,7 @@ export interface ISelectItem {
|
|||||||
selector: 'abstract-select-field',
|
selector: 'abstract-select-field',
|
||||||
template: '',
|
template: '',
|
||||||
})
|
})
|
||||||
export abstract class AbstractSelectComponent<T = ISelectItem> {
|
export abstract class AbstractSelectComponent<T = ISelectItem, serviceResponse = T[]> {
|
||||||
@Input() control = new FormControl<Maybe<number | T>>(null);
|
@Input() control = new FormControl<Maybe<number | T>>(null);
|
||||||
@Input() canInsert: boolean = false;
|
@Input() canInsert: boolean = false;
|
||||||
@Input() showLabel: boolean = true;
|
@Input() showLabel: boolean = true;
|
||||||
@@ -20,6 +21,7 @@ export abstract class AbstractSelectComponent<T = ISelectItem> {
|
|||||||
@Input() isFullDataOptionValue: boolean = false;
|
@Input() isFullDataOptionValue: boolean = false;
|
||||||
@Input() optionValue = 'id';
|
@Input() optionValue = 'id';
|
||||||
@Output() onChange = new EventEmitter<Maybe<T>>();
|
@Output() onChange = new EventEmitter<Maybe<T>>();
|
||||||
|
@Output() onSetDefaultDataItem = new EventEmitter<T>();
|
||||||
|
|
||||||
loading = signal(false);
|
loading = signal(false);
|
||||||
items = signal<Maybe<T[]>>(null);
|
items = signal<Maybe<T[]>>(null);
|
||||||
@@ -36,7 +38,40 @@ export abstract class AbstractSelectComponent<T = ISelectItem> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract getData(): void;
|
abstract getDataService(): Observable<serviceResponse>;
|
||||||
|
getData() {
|
||||||
|
this.loading.set(true);
|
||||||
|
this.getDataService().subscribe({
|
||||||
|
next: (res) => {
|
||||||
|
if (Array.isArray(res)) {
|
||||||
|
this.items.set(res);
|
||||||
|
// @ts-ignore
|
||||||
|
} else if ('data' in res) {
|
||||||
|
// @ts-ignore
|
||||||
|
this.items.set(res.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultValue = this.control.value;
|
||||||
|
if (defaultValue) {
|
||||||
|
const selectedItem = this.items()?.find(
|
||||||
|
(item) => (item as Record<string, any>)[this.optionValue] == defaultValue,
|
||||||
|
) as T;
|
||||||
|
|
||||||
|
if (selectedItem) {
|
||||||
|
this.onSetDefaultDataItem.emit(selectedItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.loading.set(false);
|
||||||
|
},
|
||||||
|
error: () => {
|
||||||
|
this.loading.set(false);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setDefaultDataItem(item: T) {
|
||||||
|
this.onSetDefaultDataItem.emit(item);
|
||||||
|
}
|
||||||
|
|
||||||
refresh() {
|
refresh() {
|
||||||
this.getData();
|
this.getData();
|
||||||
@@ -54,6 +89,8 @@ export abstract class AbstractSelectComponent<T = ISelectItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
change(value: Maybe<T>) {
|
change(value: Maybe<T>) {
|
||||||
|
console.log('first');
|
||||||
|
|
||||||
if (typeof value !== 'object') {
|
if (typeof value !== 'object') {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.onChange.emit(this.items()?.find((item) => item[this.optionValue] === value));
|
this.onChange.emit(this.items()?.find((item) => item[this.optionValue] === value));
|
||||||
|
|||||||
@@ -64,4 +64,15 @@
|
|||||||
<td class="text-center!"><span [appPriceMask]="item.totalCost"></span></td> -->
|
<td class="text-center!"><span [appPriceMask]="item.totalCost"></span></td> -->
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template pTemplate="emptymessage">
|
||||||
|
<tr>
|
||||||
|
<td [attr.colspan]="11">
|
||||||
|
<uikit-empty-state
|
||||||
|
[title]="'هیچ رکوردی یافت نشد'"
|
||||||
|
[description]="'برای این بازه زمانی و فیلترهای انتخاب شده، رکوردی وجود ندارد.'"
|
||||||
|
></uikit-empty-state>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</ng-template>
|
||||||
</p-table>
|
</p-table>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { CatalogMovementReferenceTagComponent } from '@/shared/catalog/movementReferenceTypes';
|
import { CatalogMovementReferenceTagComponent } from '@/shared/catalog/movementReferenceTypes';
|
||||||
import { JalaliDateDirective, PriceMaskDirective } from '@/shared/directives';
|
import { JalaliDateDirective, PriceMaskDirective } from '@/shared/directives';
|
||||||
|
import { UikitEmptyStateComponent } from '@/uikit';
|
||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { TableModule } from 'primeng/table';
|
import { TableModule } from 'primeng/table';
|
||||||
import { ICardexItem } from './type';
|
import { ICardexItem } from './type';
|
||||||
@@ -12,6 +13,7 @@ import { ICardexItem } from './type';
|
|||||||
JalaliDateDirective,
|
JalaliDateDirective,
|
||||||
CatalogMovementReferenceTagComponent,
|
CatalogMovementReferenceTagComponent,
|
||||||
PriceMaskDirective,
|
PriceMaskDirective,
|
||||||
|
UikitEmptyStateComponent,
|
||||||
],
|
],
|
||||||
hostDirectives: [PriceMaskDirective],
|
hostDirectives: [PriceMaskDirective],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
@if (backRoute) {
|
@if (backRoute) {
|
||||||
<p-button icon="pi pi-arrow-right" aria-label="بازگشت" outlined [routerLink]="backRoute" />
|
<p-button icon="pi pi-arrow-right" aria-label="بازگشت" outlined [routerLink]="backRoute" />
|
||||||
}
|
}
|
||||||
<h3 class="m-0">{{ pageTitle }}</h3>
|
<h4 class="m-0">{{ pageTitle }}</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (actions) {
|
@if (actions) {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<div class="flex flex-col items-center justify-center py-12 text-center bg-surface-overlay">
|
<div class="block text-center py-12 bg-surface-overlay">
|
||||||
<ng-container>
|
<ng-container>
|
||||||
<i [class]="icon + '!text-6xl mb-4 text-surface-500'" aria-hidden="true"></i>
|
<i [class]="icon + '!text-6xl mb-4 text-surface-500'" aria-hidden="true"></i>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<span class="text-xl font-semibold mb-2 text-surface-500">{{ title }}</span>
|
<span class="text-xl font-semibold mb-2 text-surface-500 block">{{ title }}</span>
|
||||||
@if (description) {
|
@if (description) {
|
||||||
<p class="text-surface-500 inline-block">{{ description }}</p>
|
<p class="text-surface-500 inline-block">{{ description }}</p>
|
||||||
}
|
}
|
||||||
<ng-content select="[cta]" #cta class="mt-4"></ng-content>
|
<ng-content select="[cta]" #cta class="mt-4 block"></ng-content>
|
||||||
@if (!hasCtaContent && ctaLabel && showCTA) {
|
@if (!hasCtaContent && ctaLabel && showCTA) {
|
||||||
<p-button class="mt-2" size="small" (click)="ctaClick.emit()">
|
<p-button class="mt-2" size="small" (click)="ctaClick.emit()">
|
||||||
{{ ctaLabel }}
|
{{ ctaLabel }}
|
||||||
|
|||||||
Reference in New Issue
Block a user