init
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
import { ToastService } from '@/core/services/toast.service';
|
||||
import { Component, effect, EventEmitter, inject, Input, Output, signal } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { AbstractForm } from './abstract-form';
|
||||
|
||||
@Component({
|
||||
selector: 'abstract-form-dialog',
|
||||
template: '',
|
||||
imports: [ReactiveFormsModule],
|
||||
})
|
||||
export abstract class AbstractFormDialog<Response, Request> extends AbstractForm<
|
||||
Response,
|
||||
Request
|
||||
> {
|
||||
@Input()
|
||||
set visible(v: boolean) {
|
||||
this.visibleSignal.set(!!v);
|
||||
this.visibleChange.emit(!!v);
|
||||
}
|
||||
get visible() {
|
||||
return this.visibleSignal();
|
||||
}
|
||||
private visibleSignal = signal(false);
|
||||
|
||||
@Output() visibleChange = new EventEmitter<boolean>();
|
||||
|
||||
constructor() {
|
||||
super(inject(ToastService));
|
||||
effect(() => {
|
||||
const v = this.visibleSignal();
|
||||
if (!v) this.form.reset(this.defaultValues);
|
||||
});
|
||||
this.submit.bind(() => {
|
||||
this.close();
|
||||
});
|
||||
}
|
||||
|
||||
override close() {
|
||||
this.visibleSignal.set(false);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import { ToastService } from '@/core/services/toast.service';
|
||||
import { Component, EventEmitter, inject, Input, Output, signal } from '@angular/core';
|
||||
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
|
||||
import { Subscribable } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'abstract-form-dialog',
|
||||
template: '',
|
||||
imports: [ReactiveFormsModule],
|
||||
})
|
||||
export abstract class AbstractForm<Response, Request> {
|
||||
@Input() initialValues?: Response;
|
||||
|
||||
@Output() onSubmit = new EventEmitter<Response>();
|
||||
@Output() onClose = new EventEmitter<void>();
|
||||
|
||||
protected readonly fb = inject(FormBuilder);
|
||||
constructor(private toastService: ToastService) {}
|
||||
|
||||
abstract form: ReturnType<FormBuilder['group']>;
|
||||
defaultValues: Partial<Request> = {};
|
||||
|
||||
abstract submitForm(payload: Request): Subscribable<Response> | void;
|
||||
|
||||
submitLoading = signal(false);
|
||||
|
||||
submit() {
|
||||
this.form.markAllAsTouched();
|
||||
if (this.form.valid) {
|
||||
this.form.disable();
|
||||
this.submitLoading.set(true);
|
||||
this.submitForm(this.form.value as Request)?.subscribe({
|
||||
next: (res) => {
|
||||
this.toastService.success({
|
||||
text: `با موفقیت ایجاد شد`,
|
||||
});
|
||||
this.submitLoading.set(false);
|
||||
this.form.enable();
|
||||
this.form.reset();
|
||||
this.onSubmit.emit(res);
|
||||
},
|
||||
error: () => {
|
||||
this.submitLoading.set(false);
|
||||
this.form.enable();
|
||||
},
|
||||
complete: () => {
|
||||
this.submitLoading.set(false);
|
||||
this.form.enable();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
this.onClose.emit();
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { Component, EventEmitter, Input, model, Output, signal } from '@angular/core';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
export interface ISelectItem {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'abstract-select-field',
|
||||
template: '',
|
||||
})
|
||||
export abstract class AbstractSelectComponent<T = ISelectItem, serviceResponse = T[]> {
|
||||
@Input() control = new FormControl<Maybe<number | T>>(null);
|
||||
@Input() canInsert: boolean = false;
|
||||
@Input() showLabel: boolean = true;
|
||||
@Input() showErrors: boolean = true;
|
||||
@Input() showClear: boolean = true;
|
||||
@Input() isFullDataOptionValue: boolean = false;
|
||||
@Input() optionValue = 'id';
|
||||
@Output() onChange = new EventEmitter<Maybe<T>>();
|
||||
@Output() onSetDefaultDataItem = new EventEmitter<T>();
|
||||
|
||||
loading = signal(false);
|
||||
items = signal<Maybe<T[]>>(null);
|
||||
isOpenFormDialog = signal(false);
|
||||
value = model<Maybe<T>>(null);
|
||||
|
||||
constructor() {
|
||||
if (this.value()) {
|
||||
this.control.setValue(this.value());
|
||||
}
|
||||
|
||||
this.control.valueChanges.subscribe((val) => {
|
||||
this.value.set(val as Maybe<T>);
|
||||
});
|
||||
}
|
||||
|
||||
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() {
|
||||
this.getData();
|
||||
}
|
||||
|
||||
onOpenForm() {
|
||||
this.isOpenFormDialog.set(true);
|
||||
}
|
||||
|
||||
get selectOptionValue() {
|
||||
if (this.isFullDataOptionValue) {
|
||||
return undefined;
|
||||
}
|
||||
return this.optionValue;
|
||||
}
|
||||
|
||||
change(value: Maybe<T>) {
|
||||
console.log('first');
|
||||
|
||||
if (typeof value !== 'object') {
|
||||
// @ts-ignore
|
||||
this.onChange.emit(this.items()?.find((item) => item[this.optionValue] === value));
|
||||
} else {
|
||||
this.onChange.emit(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
<ng-template #title>
|
||||
<ng-container [ngTemplateOutlet]="header">
|
||||
<div class="flex items-center gap-10 justify-between">
|
||||
<span>{{ cardTitle }}</span>
|
||||
<h5 class="font-bold">{{ cardTitle }}</h5>
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<ng-container [ngTemplateOutlet]="moreAction"></ng-container>
|
||||
@if (editable) {
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import { Maybe } from '@/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, ContentChild, EventEmitter, Input, Output, TemplateRef } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
ContentChild,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output,
|
||||
signal,
|
||||
TemplateRef,
|
||||
} from '@angular/core';
|
||||
import { ButtonDirective } from 'primeng/button';
|
||||
import { Card } from 'primeng/card';
|
||||
|
||||
@@ -13,22 +21,30 @@ import { Card } from 'primeng/card';
|
||||
export class AppCardComponent {
|
||||
@Input() cardTitle!: string;
|
||||
@Input() editable: boolean = false;
|
||||
@Input() editMode: boolean = false;
|
||||
|
||||
@Output() onEdit = new EventEmitter<void>();
|
||||
@Input()
|
||||
set editMode(v: boolean) {
|
||||
this.editModeSignal.set(!!v);
|
||||
this.editModeChange.emit(!!v);
|
||||
}
|
||||
get editMode() {
|
||||
return this.editModeSignal();
|
||||
}
|
||||
private editModeSignal = signal(false);
|
||||
@Output() editModeChange = new EventEmitter<boolean>();
|
||||
|
||||
@ContentChild('header', { static: true }) header?: Maybe<TemplateRef<any>>;
|
||||
@ContentChild('moreAction', { static: true }) moreAction?: Maybe<TemplateRef<any>>;
|
||||
|
||||
constructor() {
|
||||
if (this.editable) {
|
||||
if (!this.onEdit) {
|
||||
throw new Error('onEdit output must be bound when editable is true');
|
||||
}
|
||||
}
|
||||
}
|
||||
// constructor() {
|
||||
// if (this.editable) {
|
||||
// if (!this.ed) {
|
||||
// throw new Error('onEdit output must be bound when editable is true');
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
onEditClick() {
|
||||
this.onEdit.emit();
|
||||
this.editModeChange.emit(!this.editMode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
<p-table
|
||||
stripedRows
|
||||
[value]="items"
|
||||
[loading]="loading"
|
||||
showGridlines
|
||||
tableStyleClass="table-fixed border-collapse"
|
||||
scrollable
|
||||
>
|
||||
<ng-template #header>
|
||||
<tr>
|
||||
<th rowspan="2" [style]="{ textAlign: 'center', width: '4rem' }">ردیف</th>
|
||||
<th rowspan="2" [style]="{ textAlign: 'center', width: '8rem' }">تاریخ</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', minWidth: '14rem', width: '14rem' }">طرف حساب</th>
|
||||
<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="1" class="text-center!" [style]="{ width: '5rem' }">مانده</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th [style]="{ textAlign: 'center', width: '5rem' }">تعداد</th>
|
||||
<th [style]="{ textAlign: 'center', width: '10rem' }">فی</th>
|
||||
<th [style]="{ textAlign: 'center', width: '5rem' }">تعداد</th>
|
||||
<th [style]="{ textAlign: 'center', width: '10rem' }">فی</th>
|
||||
<th [style]="{ textAlign: 'center', width: '5rem' }">تعداد</th>
|
||||
<!-- <th [style]="{ textAlign: 'center', width: '10rem' }">فی</th>
|
||||
<th [style]="{ textAlign: 'center', width: '10rem' }">مجموع قیمت</th> -->
|
||||
</tr>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #body let-item let-i="rowIndex">
|
||||
<tr>
|
||||
<td class="text-center!">{{ i + 1 }}</td>
|
||||
<td class="text-center!" [jalaliDate]="item.createdAt"></td>
|
||||
<td class="text-center!">
|
||||
<catalog-movement-reference-tag [type]="item.referenceType" [movementType]="item.type" />
|
||||
</td>
|
||||
<td class="text-center!">{{ item.referenceId || "-" }}</td>
|
||||
<td class="text-center!">{{ item.supplier?.name || "-" }}</td>
|
||||
<td class="text-center!">{{ item.inventory.name || "-" }}</td>
|
||||
<td class="text-center!">
|
||||
{{ item.type === "IN" ? item.quantity : 0 }}
|
||||
</td>
|
||||
<td class="text-center!">
|
||||
@if (item.type === "IN") {
|
||||
<span [appPriceMask]="item.unitPrice"></span>
|
||||
} @else {
|
||||
0
|
||||
}
|
||||
</td>
|
||||
<td class="text-center!">
|
||||
{{ item.type === "OUT" ? item.quantity : 0 }}
|
||||
</td>
|
||||
<td class="text-center!">
|
||||
@if (item.type === "OUT") {
|
||||
<span [appPriceMask]="item.unitPrice"></span>
|
||||
} @else {
|
||||
0
|
||||
}
|
||||
</td>
|
||||
<td class="text-center!">{{ item.remainedInStock }}</td>
|
||||
<!-- <td class="text-center!"><span [appPriceMask]="item.unitPrice"></span></td>
|
||||
<td class="text-center!"><span [appPriceMask]="item.totalCost"></span></td> -->
|
||||
</tr>
|
||||
</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>
|
||||
@@ -1,24 +0,0 @@
|
||||
import { CatalogMovementReferenceTagComponent } from '@/shared/catalog/movementReferenceTypes';
|
||||
import { JalaliDateDirective, PriceMaskDirective } from '@/shared/directives';
|
||||
import { UikitEmptyStateComponent } from '@/uikit';
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { TableModule } from 'primeng/table';
|
||||
import { ICardexItem } from './type';
|
||||
|
||||
@Component({
|
||||
selector: 'shared-cardex',
|
||||
templateUrl: './cardex.component.html',
|
||||
imports: [
|
||||
TableModule,
|
||||
JalaliDateDirective,
|
||||
CatalogMovementReferenceTagComponent,
|
||||
PriceMaskDirective,
|
||||
UikitEmptyStateComponent,
|
||||
],
|
||||
hostDirectives: [PriceMaskDirective],
|
||||
})
|
||||
export class CardexComponent {
|
||||
@Input() items: ICardexItem[] = [];
|
||||
@Input() loading: boolean = false;
|
||||
constructor() {}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
import { IInventoryStockMovementResponse } from '@/modules/inventories/models';
|
||||
|
||||
export interface ICardexItem extends IInventoryStockMovementResponse {}
|
||||
@@ -1,4 +1,4 @@
|
||||
export * from './abstract-select.component';
|
||||
// export * from './abstract-select.component';
|
||||
export * from './breadcrumb.component';
|
||||
export * from './card-data.component';
|
||||
export * from './inlineConfirmation/inline-confirmation.component';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="h-full bg-surface-overlay">
|
||||
<div class="h-full bg-surface-overlay rounded-(--p-card-border-radius) overflow-hidden">
|
||||
<div class="h-full flex flex-col gap-4">
|
||||
<p-table
|
||||
[columns]="columns"
|
||||
|
||||
@@ -5,9 +5,11 @@ import {
|
||||
Component,
|
||||
computed,
|
||||
ContentChild,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output,
|
||||
Renderer2,
|
||||
signal,
|
||||
TemplateRef,
|
||||
} from '@angular/core';
|
||||
@@ -32,6 +34,9 @@ export interface IColumn<T = any> {
|
||||
@Component({
|
||||
selector: 'app-page-data-list',
|
||||
templateUrl: './page-data-list.component.html',
|
||||
// host: {
|
||||
// class: 'inline-block w-full',
|
||||
// },
|
||||
imports: [
|
||||
CommonModule,
|
||||
TableActionRowComponent,
|
||||
@@ -46,7 +51,10 @@ export interface IColumn<T = any> {
|
||||
],
|
||||
})
|
||||
export class PageDataListComponent<I> {
|
||||
constructor() {}
|
||||
constructor(
|
||||
private host: ElementRef,
|
||||
private renderer: Renderer2,
|
||||
) {}
|
||||
|
||||
@Input() pageTitle!: string;
|
||||
@Input() addNewCtaLabel?: string;
|
||||
@@ -64,7 +72,8 @@ export class PageDataListComponent<I> {
|
||||
@Input() showDetails: boolean = false;
|
||||
@Input() showAdd: boolean = false;
|
||||
@Input() isFiltered: boolean = false;
|
||||
@Input() fullHeight: boolean = false;
|
||||
@Input() fullHeight?: boolean = false;
|
||||
@Input() height: string = '500px';
|
||||
|
||||
@ContentChild('filter', { static: true }) filter!: TemplateRef<any> | null;
|
||||
@ContentChild('caption', { static: true }) caption!: TemplateRef<any> | null;
|
||||
@@ -78,8 +87,15 @@ export class PageDataListComponent<I> {
|
||||
filterDrawerVisible = signal<boolean>(false);
|
||||
|
||||
ngOnInit() {
|
||||
console.log(this.fullHeight);
|
||||
console.log(this.height);
|
||||
|
||||
this.renderer.setStyle(
|
||||
this.host.nativeElement,
|
||||
'height',
|
||||
this.fullHeight ? '100cqmin' : this.height,
|
||||
);
|
||||
// if (this.fullHeight) {
|
||||
// this.renderer.setStyle(this.host.nativeElement, 'height', '100cqmin');
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@if (showPaymentForm()) {
|
||||
<!-- @if (showPaymentForm()) {
|
||||
<app-supplier-invoice-pay-form
|
||||
[(visible)]="showPaymentForm"
|
||||
[debtAmount]="purchaseReceipt.totalAmount"
|
||||
@@ -7,4 +7,4 @@
|
||||
[invoiceId]="purchaseReceipt.id.toString()"
|
||||
(onSubmit)="submitted()"
|
||||
/>
|
||||
}
|
||||
} -->
|
||||
|
||||
@@ -1,55 +1,55 @@
|
||||
import { ToastService } from '@/core/services/toast.service';
|
||||
import { SupplierInvoicePayFormComponent } from '@/modules/suppliers/components/invoices/pay-form.component';
|
||||
import { Component, EventEmitter, Input, Output, signal } from '@angular/core';
|
||||
import { IPurchaseReceiptResponse } from '../../../modules/purchases/models';
|
||||
import { ConfirmationDialogService } from '../confirmationDialog/confirmation-dialog.service';
|
||||
// import { ToastService } from '@/core/services/toast.service';
|
||||
// import { SupplierInvoicePayFormComponent } from '@/modules/suppliers/components/invoices/pay-form.component';
|
||||
// import { Component, EventEmitter, Input, Output, signal } from '@angular/core';
|
||||
// import { IPurchaseReceiptResponse } from '../../../modules/purchases/models';
|
||||
// import { ConfirmationDialogService } from '../confirmationDialog/confirmation-dialog.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-purchase-receipt-payment-wrapper',
|
||||
templateUrl: './wrapper.component.html',
|
||||
imports: [SupplierInvoicePayFormComponent],
|
||||
})
|
||||
export class PurchaseReceiptPaymentWrapperComponent {
|
||||
@Input() purchaseReceipt!: IPurchaseReceiptResponse;
|
||||
// @Component({
|
||||
// selector: 'app-purchase-receipt-payment-wrapper',
|
||||
// templateUrl: './wrapper.component.html',
|
||||
// imports: [SupplierInvoicePayFormComponent],
|
||||
// })
|
||||
// export class PurchaseReceiptPaymentWrapperComponent {
|
||||
// @Input() purchaseReceipt!: IPurchaseReceiptResponse;
|
||||
|
||||
@Output() onSubmit = new EventEmitter<void>();
|
||||
// @Output() onSubmit = new EventEmitter<void>();
|
||||
|
||||
showPaymentForm = signal(false);
|
||||
constructor(
|
||||
private confirmService: ConfirmationDialogService,
|
||||
private toastService: ToastService,
|
||||
) {
|
||||
setTimeout(() => {
|
||||
this.showConfirm();
|
||||
}, 1);
|
||||
}
|
||||
// showPaymentForm = signal(false);
|
||||
// constructor(
|
||||
// private confirmService: ConfirmationDialogService,
|
||||
// private toastService: ToastService,
|
||||
// ) {
|
||||
// setTimeout(() => {
|
||||
// this.showConfirm();
|
||||
// }, 1);
|
||||
// }
|
||||
|
||||
showConfirm() {
|
||||
this.confirmService.confirm({
|
||||
message: 'آیا پرداخت فاکتور انجام شده است؟',
|
||||
header: 'وضعیت پرداخت فاکتور',
|
||||
acceptLabel: 'بله',
|
||||
rejectLabel: 'خیر',
|
||||
accept: () => {
|
||||
this.toPaymentForm();
|
||||
},
|
||||
reject: () => {
|
||||
this.toastService.info({
|
||||
text: 'میتوانید از طریق منوی پرداخت فاکتور، در آینده اقدام به پرداخت نمایید.',
|
||||
title: 'پرداخت فاکتور انجام نشد',
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
// showConfirm() {
|
||||
// this.confirmService.confirm({
|
||||
// message: 'آیا پرداخت فاکتور انجام شده است؟',
|
||||
// header: 'وضعیت پرداخت فاکتور',
|
||||
// acceptLabel: 'بله',
|
||||
// rejectLabel: 'خیر',
|
||||
// accept: () => {
|
||||
// this.toPaymentForm();
|
||||
// },
|
||||
// reject: () => {
|
||||
// this.toastService.info({
|
||||
// text: 'میتوانید از طریق منوی پرداخت فاکتور، در آینده اقدام به پرداخت نمایید.',
|
||||
// title: 'پرداخت فاکتور انجام نشد',
|
||||
// });
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
submitted() {
|
||||
console.log('submitted');
|
||||
// submitted() {
|
||||
// console.log('submitted');
|
||||
|
||||
this.showPaymentForm.set(false);
|
||||
this.onSubmit.emit();
|
||||
}
|
||||
// this.showPaymentForm.set(false);
|
||||
// this.onSubmit.emit();
|
||||
// }
|
||||
|
||||
toPaymentForm() {
|
||||
this.showPaymentForm.set(true);
|
||||
}
|
||||
}
|
||||
// toPaymentForm() {
|
||||
// this.showPaymentForm.set(true);
|
||||
// }
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user