From 90c51edad4b807b1ef4ef775d83a4d950d344052 Mon Sep 17 00:00:00 2001 From: ahasani194 Date: Sat, 30 May 2026 19:05:23 +0330 Subject: [PATCH] some ui fix --- src/app.component.ts | 6 +- .../components/list.component.html | 5 +- .../licenses/components/list.component.html | 5 +- .../components/filter-drawer.component.html | 51 ++++----- .../components/filter-drawer.component.ts | 12 ++- .../components/list.component.html | 30 +++--- .../saleInvoices/components/list.component.ts | 28 ++--- .../sale-invoice-card.component.html | 2 +- .../components/sale-invoice-card.component.ts | 6 +- .../modules/saleInvoices/models/filter.dto.ts | 7 +- .../modules/saleInvoices/models/fiscal.io.ts | 6 +- .../components/invoice-type-card.component.ts | 7 +- .../shared/catalog/taxProviderStatus/index.ts | 1 + .../tax-provider-status-tag.component.ts | 18 +--- .../tax-provider-status-translator.util.ts | 20 ++++ .../confirmation-dialog.component.html | 18 ++-- .../confirmation-dialog.component.ts | 43 +------- .../confirmation-dialog.service.ts | 94 +++++----------- .../sale-invoice-single-view.component.html | 13 +-- .../sale-invoice-single-view.component.ts | 100 ++++++++++++++++-- .../page-data-list.component.html | 2 +- .../pageDataList/page-data-list.component.ts | 4 +- src/app/uikit/paginator.component.html | 48 +++++---- src/app/uikit/paginator.component.ts | 27 +++-- src/app/utils/price-mask.utils.ts | 6 +- 25 files changed, 309 insertions(+), 250 deletions(-) create mode 100644 src/app/shared/catalog/taxProviderStatus/tax-provider-status-translator.util.ts diff --git a/src/app.component.ts b/src/app.component.ts index b0d2c5d..2f3aa52 100644 --- a/src/app.component.ts +++ b/src/app.component.ts @@ -1,17 +1,17 @@ import { PwaInstallService } from '@/core/services/pwa-install.service'; +import { ConfirmationDialogComponent } from '@/shared/components/confirmationDialog/confirmation-dialog.component'; import { Component, HostListener } from '@angular/core'; import { RouterModule } from '@angular/router'; -import { ConfirmDialog } from 'primeng/confirmdialog'; import { ToastModule } from 'primeng/toast'; import { brandingConfig } from './app/branding/branding.config'; @Component({ selector: 'app-root', standalone: true, - imports: [RouterModule, ToastModule, ConfirmDialog], + imports: [RouterModule, ToastModule, ConfirmationDialogComponent], template: ` - + `, }) diff --git a/src/app/domains/consumer/modules/saleInvoices/components/list.component.html b/src/app/domains/consumer/modules/saleInvoices/components/list.component.html index 66bea4b..c696274 100644 --- a/src/app/domains/consumer/modules/saleInvoices/components/list.component.html +++ b/src/app/domains/consumer/modules/saleInvoices/components/list.component.html @@ -6,9 +6,8 @@ [loading]="loading()" [perPage]="responseMetaData()?.perPage" [currentPage]="responseMetaData()?.page" - [totalRecords]="responseMetaData()?.totalRecords || items().length" + [totalPages]="responseMetaData()?.totalPages || 1" [showDetails]="true" (onDetails)="toSinglePage($event)" (onRefresh)="refresh()" - (onChangePage)="changePage($event)" -/> + (onChangePage)="changePage($event)" /> diff --git a/src/app/domains/partner/modules/licenses/components/list.component.html b/src/app/domains/partner/modules/licenses/components/list.component.html index adae212..0edadf7 100644 --- a/src/app/domains/partner/modules/licenses/components/list.component.html +++ b/src/app/domains/partner/modules/licenses/components/list.component.html @@ -3,13 +3,12 @@ [columns]="columns" emptyPlaceholderTitle="تا به حال لایسنسی نفروخته‌اید." [currentPage]="responseMetaData()?.page" - [totalRecords]="responseMetaData()?.totalRecords || items().length" + [totalPages]="responseMetaData()?.totalPages" [perPage]="responseMetaData()?.perPage" [items]="items()" [loading]="loading()" (onRefresh)="refresh()" - (onChangePage)="changePage($event)" -> + (onChangePage)="changePage($event)"> diff --git a/src/app/domains/pos/modules/saleInvoices/components/filter-drawer.component.html b/src/app/domains/pos/modules/saleInvoices/components/filter-drawer.component.html index f18a17a..f09ad49 100644 --- a/src/app/domains/pos/modules/saleInvoices/components/filter-drawer.component.html +++ b/src/app/domains/pos/modules/saleInvoices/components/filter-drawer.component.html @@ -6,24 +6,24 @@ [showCloseIcon]="true" header="فیلتر فاکتورها" styleClass="w-full md:w-[28rem]" - (visibleChange)="visibleChange.emit($event)" -> -
- + (visibleChange)="visibleChange.emit($event)"> +
+
+ + - + - - - - + + + + - -
- - +
+ + +
+ +
+
+
+ + +
- -
- - -
- +
diff --git a/src/app/domains/pos/modules/saleInvoices/components/filter-drawer.component.ts b/src/app/domains/pos/modules/saleInvoices/components/filter-drawer.component.ts index d99ed05..5bd1734 100644 --- a/src/app/domains/pos/modules/saleInvoices/components/filter-drawer.component.ts +++ b/src/app/domains/pos/modules/saleInvoices/components/filter-drawer.component.ts @@ -1,4 +1,6 @@ +import { Maybe } from '@/core'; import { EnumSelectComponent } from '@/shared/apiEnum/select.component'; +import { TspProviderResponseStatus } from '@/shared/catalog'; import { InputComponent } from '@/shared/components'; import { Component, @@ -45,12 +47,12 @@ export class PosSaleInvoicesFilterDrawerComponent implements OnChanges { invoice_date_to: this.fb.control(''), created_at_from: this.fb.control(''), created_at_to: this.fb.control(''), - code: this.fb.control(''), + invoice_number: this.fb.control>(null), customer_name: this.fb.control(''), customer_mobile: this.fb.control(''), customer_national_id: this.fb.control(''), customer_economic_code: this.fb.control(''), - status: this.fb.control<'NOT_SEND' | 'SUCCESS' | 'FAILURE' | 'QUEUED' | null>(null), + status: this.fb.control('NOT_SEND'), total_amount_from: this.fb.control(null), total_amount_to: this.fb.control(null), }); @@ -65,7 +67,7 @@ export class PosSaleInvoicesFilterDrawerComponent implements OnChanges { invoice_date_to: this.value.invoice_date_to ?? '', created_at_from: this.value.created_at_from ?? '', created_at_to: this.value.created_at_to ?? '', - code: this.value.code ?? '', + invoice_number: this.value.invoice_number ?? null, customer_name: this.value.customer_name ?? '', customer_mobile: this.value.customer_mobile ?? '', customer_national_id: this.value.customer_national_id ?? '', @@ -91,7 +93,7 @@ export class PosSaleInvoicesFilterDrawerComponent implements OnChanges { invoice_date_to: '', created_at_from: '', created_at_to: '', - code: '', + invoice_number: null, customer_name: '', customer_mobile: '', customer_national_id: '', @@ -113,7 +115,7 @@ export class PosSaleInvoicesFilterDrawerComponent implements OnChanges { invoice_date_to: raw.invoice_date_to || undefined, created_at_from: raw.created_at_from || undefined, created_at_to: raw.created_at_to || undefined, - code: raw.code?.trim() || undefined, + invoice_number: raw.invoice_number, customer_name: raw.customer_name?.trim() || undefined, customer_mobile: raw.customer_mobile?.trim() || undefined, customer_national_id: raw.customer_national_id?.trim() || undefined, diff --git a/src/app/domains/pos/modules/saleInvoices/components/list.component.html b/src/app/domains/pos/modules/saleInvoices/components/list.component.html index dbb620a..afd138b 100644 --- a/src/app/domains/pos/modules/saleInvoices/components/list.component.html +++ b/src/app/domains/pos/modules/saleInvoices/components/list.component.html @@ -7,21 +7,21 @@ type="button" size="small" [outlined]="!activeFilters().length" - (click)="toggleFilterVisible()" - > + (click)="toggleFilterVisible()">
@if (activeFilters().length) { -
+
@for (filter of activeFilters(); track filter.key) { - + @if (filter.key !== 'page') { + + } }
} @@ -34,7 +34,7 @@ } } @else if (!items() || items().length === 0) {
-

فاکتوری یافت نشد.

+

فاکتوری یافت نشد.

} @else { @for (item of items(); track item.id) { @@ -42,10 +42,16 @@ } }
+
+ +
+ (apply)="onFilterApply($event)" /> diff --git a/src/app/domains/pos/modules/saleInvoices/components/list.component.ts b/src/app/domains/pos/modules/saleInvoices/components/list.component.ts index 4fdeeef..5cd3052 100644 --- a/src/app/domains/pos/modules/saleInvoices/components/list.component.ts +++ b/src/app/domains/pos/modules/saleInvoices/components/list.component.ts @@ -1,5 +1,10 @@ +import { Maybe } from '@/core'; +import { IResponseMetadata } from '@/core/models/service.model'; import { POS_ROUTES } from '@/domains/pos/routes'; +import { TspProviderResponseStatus } from '@/shared/catalog'; +import taxProviderStatusTranslatorUtil from '@/shared/catalog/taxProviderStatus/tax-provider-status-translator.util'; import { InnerPagesHeaderComponent } from '@/shared/components/innerPagesHeader/inner-pages-header.component'; +import { PaginatorComponent } from '@/uikit'; import { gregorianToJalali } from '@/utils'; import { Component, computed, inject, signal } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; @@ -28,6 +33,7 @@ import { SaleInvoiceCardComponent } from './sale-invoice-card.component'; Button, Chip, SaleInvoiceCardComponent, + PaginatorComponent, ], }) export class PosSaleInvoiceListComponent { @@ -37,6 +43,7 @@ export class PosSaleInvoiceListComponent { loading = signal(true); items = signal([]); + paginationMeta = signal>(null); filterVisible = signal(false); filters = signal({}); activeFilters = computed(() => { @@ -45,7 +52,7 @@ export class PosSaleInvoiceListComponent { invoice_date_to: 'تا تاریخ فاکتور', created_at_from: 'از تاریخ ایجاد', created_at_to: 'تا تاریخ ایجاد', - code: 'کد', + invoice_number: 'شماره صورت‌حساب', customer_name: 'نام مشتری', customer_mobile: 'موبایل', customer_national_id: 'کد ملی', @@ -61,16 +68,7 @@ export class PosSaleInvoiceListComponent { const typedKey = key as keyof IPosSaleInvoicesFilterDto; let formattedValue = ''; if (typedKey === 'status') { - formattedValue = - value === 'NOT_SEND' - ? 'ارسال نشده' - : value === 'SUCCESS' - ? 'موفق' - : value === 'FAILURE' - ? 'ناموفق' - : value === 'QUEUED' - ? 'در انتظار ارسال' - : String(value); + formattedValue = taxProviderStatusTranslatorUtil(value as TspProviderResponseStatus); } else if ( key === 'invoice_date_from' || key === 'invoice_date_to' || @@ -92,12 +90,17 @@ export class PosSaleInvoiceListComponent { this.getData(); } + onChangePage(page: number) { + this.onFilterApply({ ...this.filters(), page }); + } + getData() { this.loading.set(true); this.service .getAll(this.filters()) .pipe(finalize(() => this.loading.set(false))) .subscribe((res) => { + this.paginationMeta.set(res.meta); this.items.set(res.data ?? []); }); } @@ -134,7 +137,7 @@ export class PosSaleInvoiceListComponent { 'invoice_date_to', 'created_at_from', 'created_at_to', - 'code', + 'invoice_number', 'customer_name', 'customer_mobile', 'customer_national_id', @@ -142,6 +145,7 @@ export class PosSaleInvoiceListComponent { 'status', 'total_amount_from', 'total_amount_to', + 'page', ]; const parsed = keys.reduce((acc, key) => { diff --git a/src/app/domains/pos/modules/saleInvoices/components/sale-invoice-card.component.html b/src/app/domains/pos/modules/saleInvoices/components/sale-invoice-card.component.html index 81ba6ae..eff7d3d 100644 --- a/src/app/domains/pos/modules/saleInvoices/components/sale-invoice-card.component.html +++ b/src/app/domains/pos/modules/saleInvoices/components/sale-invoice-card.component.html @@ -35,7 +35,7 @@ } @if (['queued', 'fiscal_queued'].includes(saleInvoice.status.value.toLowerCase())) { this.sendingLoading.set(false))) .subscribe((res) => { - if (res.status === 'FAILURE') { + if (res.status === 'SEND_FAILURE') { this.toastService.error({ text: res.message || 'خطا در ارسال فاکتور رخ داده است.', }); @@ -89,6 +90,9 @@ export class SaleInvoiceCardComponent { .getInquiry(this.saleInvoice.id) .pipe(finalize(() => this.gettingStatusLoading.set(false))) .subscribe((res) => { + this.toastService.info({ + text: `وضعیت فعلی فاکتور شماره‌ی ${this.saleInvoice.invoice_number}، ${taxProviderStatusTranslatorUtil(res.status)} می‌باشد.`, + }); this.refreshRequested.emit(); }); } diff --git a/src/app/domains/pos/modules/saleInvoices/models/filter.dto.ts b/src/app/domains/pos/modules/saleInvoices/models/filter.dto.ts index 738262a..ecef2d8 100644 --- a/src/app/domains/pos/modules/saleInvoices/models/filter.dto.ts +++ b/src/app/domains/pos/modules/saleInvoices/models/filter.dto.ts @@ -1,3 +1,6 @@ +import { Maybe } from '@/core'; +import { TspProviderResponseStatus } from '@/shared/catalog'; + export interface IPosSaleInvoicesFilterDto { page?: number | null; perPage?: number | null; @@ -5,12 +8,12 @@ export interface IPosSaleInvoicesFilterDto { invoice_date_to?: string; created_at_from?: string; created_at_to?: string; - code?: string; + invoice_number?: Maybe; customer_name?: string; customer_mobile?: string; customer_national_id?: string; customer_economic_code?: string; - status?: 'NOT_SEND' | 'SUCCESS' | 'FAILURE' | 'QUEUED'; + status?: TspProviderResponseStatus; total_amount?: number | null; total_amount_from?: number | null; total_amount_to?: number | null; diff --git a/src/app/domains/pos/modules/saleInvoices/models/fiscal.io.ts b/src/app/domains/pos/modules/saleInvoices/models/fiscal.io.ts index 6ac07cf..73e6392 100644 --- a/src/app/domains/pos/modules/saleInvoices/models/fiscal.io.ts +++ b/src/app/domains/pos/modules/saleInvoices/models/fiscal.io.ts @@ -1,10 +1,12 @@ +import { TspProviderResponseStatus } from '@/shared/catalog'; + export interface IPosSaleInvoiceFiscalActionResponse { message?: string; - status?: string; + status: TspProviderResponseStatus; } export interface IPosSaleInvoiceFiscalStatusResponse { - status?: string; + status: TspProviderResponseStatus; tracking_id?: string; message?: string; [key: string]: unknown; diff --git a/src/app/domains/pos/modules/statistics/components/invoice-type-card.component.ts b/src/app/domains/pos/modules/statistics/components/invoice-type-card.component.ts index aea996b..ac496f4 100644 --- a/src/app/domains/pos/modules/statistics/components/invoice-type-card.component.ts +++ b/src/app/domains/pos/modules/statistics/components/invoice-type-card.component.ts @@ -1,3 +1,4 @@ +import taxProviderStatusTranslatorUtil from '@/shared/catalog/taxProviderStatus/tax-provider-status-translator.util'; import { formatWithCurrency } from '@/utils'; import { CommonModule } from '@angular/common'; import { Component, computed, EventEmitter, Input, Output } from '@angular/core'; @@ -35,21 +36,21 @@ export class PosStatisticsInvoiceTypeCardComponent { }; case 'success': return { - title: 'تایید شده', + title: taxProviderStatusTranslatorUtil('SUCCESS'), icon: 'check-circle', bgColor: '#22C55E1A', borderColor: '#22C55E', }; case 'failure': return { - title: 'خطادار', + title: taxProviderStatusTranslatorUtil('FAILURE'), icon: 'ban', bgColor: '#EF44441A', borderColor: '#EF4444', }; case 'not_sended': return { - title: 'ارسال نشده', + title: taxProviderStatusTranslatorUtil('NOT_SEND'), icon: 'clock', bgColor: '#F59E0B1A', borderColor: '#F59E0B', diff --git a/src/app/shared/catalog/taxProviderStatus/index.ts b/src/app/shared/catalog/taxProviderStatus/index.ts index 23c9ca5..f936f53 100644 --- a/src/app/shared/catalog/taxProviderStatus/index.ts +++ b/src/app/shared/catalog/taxProviderStatus/index.ts @@ -1,2 +1,3 @@ export * from './tax-provider-status-tag.component'; +export * from './tax-provider-status-translator.util'; export * from './type'; diff --git a/src/app/shared/catalog/taxProviderStatus/tax-provider-status-tag.component.ts b/src/app/shared/catalog/taxProviderStatus/tax-provider-status-tag.component.ts index 1d29b30..9e293f4 100644 --- a/src/app/shared/catalog/taxProviderStatus/tax-provider-status-tag.component.ts +++ b/src/app/shared/catalog/taxProviderStatus/tax-provider-status-tag.component.ts @@ -1,5 +1,6 @@ import { Component, Input } from '@angular/core'; import { Tag } from 'primeng/tag'; +import taxProviderStatusTranslatorUtil from './tax-provider-status-translator.util'; import { TspProviderResponseStatus } from './type'; @Component({ @@ -29,21 +30,6 @@ export class CatalogTaxProviderStatusTagComponent { } get label() { - switch (this.status) { - case 'SUCCESS': - return 'موفق'; - case 'FAILURE': - return 'ناموفق'; - case 'NOT_SEND': - return 'ارسال نشده'; - case 'QUEUED': - return 'در صف ارسال'; - case 'FISCAL_QUEUED': - return 'در انتظار تایید سازمان'; - case 'SEND_FAILURE': - return 'خطا در ارسال'; - default: - return 'نامشخص'; - } + return taxProviderStatusTranslatorUtil(this.status); } } diff --git a/src/app/shared/catalog/taxProviderStatus/tax-provider-status-translator.util.ts b/src/app/shared/catalog/taxProviderStatus/tax-provider-status-translator.util.ts new file mode 100644 index 0000000..595b540 --- /dev/null +++ b/src/app/shared/catalog/taxProviderStatus/tax-provider-status-translator.util.ts @@ -0,0 +1,20 @@ +import { TspProviderResponseStatus } from './type'; + +export default (status: TspProviderResponseStatus) => { + switch (status) { + case 'SUCCESS': + return 'موفق'; + case 'FAILURE': + return 'ناموفق'; + case 'NOT_SEND': + return 'ارسال نشده'; + case 'QUEUED': + return 'در صف ارسال'; + case 'FISCAL_QUEUED': + return 'در انتظار تایید سازمان'; + case 'SEND_FAILURE': + return 'خطا در ارسال'; + default: + return 'نامشخص'; + } +}; diff --git a/src/app/shared/components/confirmationDialog/confirmation-dialog.component.html b/src/app/shared/components/confirmationDialog/confirmation-dialog.component.html index f495ba9..b209939 100644 --- a/src/app/shared/components/confirmationDialog/confirmation-dialog.component.html +++ b/src/app/shared/components/confirmationDialog/confirmation-dialog.component.html @@ -1,17 +1,21 @@ @if (message) { -
+
+ class="bg-primary text-primary-contrast -mt-20 inline-flex h-24 w-24 items-center justify-center rounded-full">
- {{ message.header }} + {{ message.header }}

{{ message.message }}

-
- - +
+ +
} diff --git a/src/app/shared/components/confirmationDialog/confirmation-dialog.component.ts b/src/app/shared/components/confirmationDialog/confirmation-dialog.component.ts index 4b69d67..27a8bd5 100644 --- a/src/app/shared/components/confirmationDialog/confirmation-dialog.component.ts +++ b/src/app/shared/components/confirmationDialog/confirmation-dialog.component.ts @@ -1,48 +1,11 @@ -import { Component, EventEmitter, Input, OnDestroy, Output } from '@angular/core'; -import { ConfirmationService } from 'primeng/api'; +import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { ConfirmDialog } from 'primeng/confirmdialog'; @Component({ selector: 'app-shared-confirmation-dialog', templateUrl: './confirmation-dialog.component.html', - providers: [ConfirmationService], + standalone: true, imports: [ConfirmDialog, Button], }) -export class ConfirmationDialogComponent implements OnDestroy { - @Input() message!: string; - @Input() header: string = 'تأیید عملیات'; - @Input() acceptLabel: string = 'بله'; - @Input() rejectLabel: string = 'خیر'; - @Output() onAccept = new EventEmitter(); - @Output() onReject = new EventEmitter(); - - constructor(private confirmationService: ConfirmationService) {} - - show() { - this.confirmationService.confirm({ - header: this.header, - message: this.message, - acceptLabel: this.acceptLabel, - rejectLabel: this.rejectLabel, - accept: () => { - this.accept(); - }, - reject: () => { - this.reject(); - }, - }); - } - - accept() { - this.onAccept.emit(); - } - - reject() { - this.onReject.emit(); - } - - ngOnDestroy() { - // Cleanup if needed - } -} +export class ConfirmationDialogComponent {} diff --git a/src/app/shared/components/confirmationDialog/confirmation-dialog.service.ts b/src/app/shared/components/confirmationDialog/confirmation-dialog.service.ts index 1c33315..1b21d74 100644 --- a/src/app/shared/components/confirmationDialog/confirmation-dialog.service.ts +++ b/src/app/shared/components/confirmationDialog/confirmation-dialog.service.ts @@ -1,78 +1,32 @@ -import { - ApplicationRef, - ComponentFactoryResolver, - ComponentRef, - Injectable, - Injector, -} from '@angular/core'; -import { ConfirmationDialogComponent } from './confirmation-dialog.component'; +import { Injectable, inject } from '@angular/core'; +import { Confirmation, ConfirmationService } from 'primeng/api'; + +export interface AppConfirmOptions { + header: string; + message: string; + acceptLabel?: string; + rejectLabel?: string; + accept?: () => void; + reject?: () => void; +} @Injectable({ providedIn: 'root', }) -export class ConfirmationDialogService { - private componentRef: ComponentRef | null = null; +export class AppConfirmationService { + private confirmationService = inject(ConfirmationService); - constructor( - private componentFactoryResolver: ComponentFactoryResolver, - private appRef: ApplicationRef, - private injector: Injector, - ) {} - - confirm(options: { - message: string; - header?: string; - acceptLabel?: string; - rejectLabel?: string; - accept?: () => void; - reject?: () => void; - }) { - // Create the component dynamically - const factory = this.componentFactoryResolver.resolveComponentFactory( - ConfirmationDialogComponent, - ); - this.componentRef = factory.create(this.injector); - - // Set inputs - this.componentRef.instance.message = options.message; - if (options.header) this.componentRef.instance.header = options.header; - if (options.acceptLabel) this.componentRef.instance.acceptLabel = options.acceptLabel; - if (options.rejectLabel) this.componentRef.instance.rejectLabel = options.rejectLabel; - - // Subscribe to outputs and close after - if (options.accept) { - this.componentRef.instance.onAccept.subscribe(() => { - options.accept!(); - this.close(); + ask(options: Confirmation): Promise { + return new Promise((resolve) => { + this.confirmationService.confirm({ + position: 'bottom', + acceptLabel: 'تایید', + rejectLabel: 'لغو', + ...options, + closeOnEscape: true, + accept: () => options.accept?.() || resolve(true), + reject: () => resolve(false), }); - } else { - this.componentRef.instance.onAccept.subscribe(() => this.close()); - } - if (options.reject) { - this.componentRef.instance.onReject.subscribe(() => { - options.reject!(); - this.close(); - }); - } else { - this.componentRef.instance.onReject.subscribe(() => this.close()); - } - - // Attach to the app - this.appRef.attachView(this.componentRef.hostView); - - // Append to body - document.body.appendChild(this.componentRef.location.nativeElement); - - // Trigger change detection and show - this.componentRef.changeDetectorRef.detectChanges(); - this.componentRef.instance.show(); - } - - close() { - if (this.componentRef) { - this.appRef.detachView(this.componentRef.hostView); - this.componentRef.destroy(); - this.componentRef = null; - } + }); } } diff --git a/src/app/shared/components/invoices/sale-invoice-single-view.component.html b/src/app/shared/components/invoices/sale-invoice-single-view.component.html index ecb1fbf..6af21d2 100644 --- a/src/app/shared/components/invoices/sale-invoice-single-view.component.html +++ b/src/app/shared/components/invoices/sale-invoice-single-view.component.html @@ -6,14 +6,10 @@
- +
+ + +
@@ -35,6 +31,7 @@ + @for (payment of invoice.payments; track $index) { ; @@ -67,6 +74,88 @@ export class SharedSaleInvoiceSingleViewComponent { @ViewChild('totalAmount', { static: false }) totalAmount!: TemplateRef; + moreActionMenuItems = signal([]); + + constructor() { + this.showErrors = this.showErrors.bind(this); + this.showRevokeConfirmation = this.showRevokeConfirmation.bind(this); + this.showCorrection = this.showCorrection.bind(this); + this.showBackFromSale = this.showBackFromSale.bind(this); + this.printInvoice = this.printInvoice.bind(this); + } + + showErrors() {} + showRevokeConfirmation() { + console.log('this.confirmationService', this.confirmationService); + + this.confirmationService.ask({ + header: `ابطال فاکتور شماره ${this.invoice!.invoice_number}`, + message: `در صورت تایید ابطال فاکتور شماره ${this.invoice!.invoice_number} بر روی دکمه‌ی ابطال کلیک کنید.`, + acceptLabel: 'ابطال', + acceptButtonProps: { + severity: 'dangerdock', + }, + + accept: () => { + console.log('here'); + // this.deferredInstallPrompt.prompt(); + // this.deferredInstallPrompt.userChoice.finally(() => { + // this.deferredInstallPrompt = null; + // this.canInstall.set(false); + // window.location.reload(); + // }); + // }, + }, + }); + } + showCorrection() {} + showBackFromSale() {} + + ngOnChanges(changes: SimpleChanges) { + if (changes['invoice'] && this.invoice) { + const invoiceStatus = this.invoice.status.value; + const actions: MenuItem[] = [ + { + label: 'دلایل خطا', + icon: 'pi pi-question', + neededStatus: 'FAILURE', + command: this.showErrors, + }, + { + label: 'ابطال', + icon: 'pi pi-eraser', + neededStatus: 'SUCCESS', + command: this.showRevokeConfirmation, + }, + { + label: 'اصلاح', + icon: 'pi pi-file-edit', + neededStatus: 'SUCCESS', + command: this.showCorrection, + }, + { + label: 'برگشت از فروش', + icon: 'pi pi-cart-minus', + neededStatus: 'SUCCESS', + command: this.showBackFromSale, + }, + { + label: 'چاپ', + icon: 'pi pi-print', + neededStatus: '', + command: this.printInvoice, + }, + ]; + + this.moreActionMenuItems.set( + actions.filter( + // @ts-ignore + (action) => !action.neededStatus || action.neededStatus === invoiceStatus + ) + ); + } + } + readonly posName = computed(() => { if (this.posInfoStore.entity()) { const { name, businessActivity, complex } = this.posInfoStore.entity()!; @@ -280,7 +369,7 @@ export class SharedSaleInvoiceSingleViewComponent { nestedOption: { path: 'payload.commission', type: 'price', - } + }, }, { field: 'wages', @@ -289,7 +378,7 @@ export class SharedSaleInvoiceSingleViewComponent { nestedOption: { path: 'payload.wages', type: 'price', - } + }, }, { field: 'profit', @@ -298,7 +387,7 @@ export class SharedSaleInvoiceSingleViewComponent { nestedOption: { path: 'payload.profit', type: 'price', - } + }, }, { field: 'discount_amount', @@ -315,7 +404,6 @@ export class SharedSaleInvoiceSingleViewComponent { header: 'مبلغ قابل پرداخت', type: 'price', }, - ]; refresh() { diff --git a/src/app/shared/components/pageDataList/page-data-list.component.html b/src/app/shared/components/pageDataList/page-data-list.component.html index 9fbea5a..39f691b 100644 --- a/src/app/shared/components/pageDataList/page-data-list.component.html +++ b/src/app/shared/components/pageDataList/page-data-list.component.html @@ -59,7 +59,7 @@ diff --git a/src/app/shared/components/pageDataList/page-data-list.component.ts b/src/app/shared/components/pageDataList/page-data-list.component.ts index 9901268..3201fe5 100644 --- a/src/app/shared/components/pageDataList/page-data-list.component.ts +++ b/src/app/shared/components/pageDataList/page-data-list.component.ts @@ -104,7 +104,7 @@ export class PageDataListComponent { @Input() emptyPlaceholderTitle: string = 'موردی برای نمایش وجود ندارد'; @Input() emptyPlaceholderDescription?: string = ''; @Input() emptyPlaceholderCtaLabel?: string; - @Input() totalRecords!: number; + @Input() totalPages?: number = 1; @Input() perPage?: number = 10; @Input() currentPage?: number = 1; @Input() showEdit: boolean = false; @@ -191,7 +191,7 @@ export class PageDataListComponent { }; get showPaginator() { - return !!(this.totalRecords && this.perPage && this.totalRecords > this.perPage); + return !!(this.totalPages && this.perPage && this.totalPages > this.perPage); } getPreviewClasses(item: Record, column: IColumn): any { diff --git a/src/app/uikit/paginator.component.html b/src/app/uikit/paginator.component.html index 1540f85..104be61 100644 --- a/src/app/uikit/paginator.component.html +++ b/src/app/uikit/paginator.component.html @@ -1,19 +1,29 @@ -
- - صفحه {{ currentPage }} از {{ totalPages() }} - -
+@if (totalPages > 1) { +
+ + @for (page of pagesToShow(); track page) { + + } + +
+} diff --git a/src/app/uikit/paginator.component.ts b/src/app/uikit/paginator.component.ts index 7fc8928..addd30c 100644 --- a/src/app/uikit/paginator.component.ts +++ b/src/app/uikit/paginator.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, Output, signal } from '@angular/core'; +import { Component, computed, EventEmitter, Input, Output } from '@angular/core'; import { ButtonModule } from 'primeng/button'; @Component({ @@ -7,17 +7,30 @@ import { ButtonModule } from 'primeng/button'; imports: [ButtonModule], }) export class PaginatorComponent { - @Input() totalRecords!: number; + @Input() totalPages: number = 1; @Input() currentPage: number = 1; @Input() perPage: number = 10; @Input() loading: boolean = false; @Output() onChange = new EventEmitter(); - totalPages = signal(0); + pagesToShow = computed(() => { + const maxVisible = 5; - ngOnChanges() { - this.totalPages.set(Math.ceil(this.totalRecords / this.perPage)); - } + if (this.totalPages <= maxVisible) { + return Array.from({ length: this.totalPages }, (_, i) => i + 1); + } + + let start = Math.max(1, this.currentPage - Math.floor(maxVisible / 2)); + + let end = start + maxVisible - 1; + + if (end > this.totalPages) { + end = this.totalPages; + start = end - maxVisible + 1; + } + + return Array.from({ length: end - start + 1 }, (_, i) => start + i); + }); onPageChange(newPage: number) { this.onChange.emit(newPage); @@ -29,7 +42,7 @@ export class PaginatorComponent { } } nextPage() { - if (this.currentPage < this.totalPages()) { + if (this.currentPage < this.totalPages) { this.onPageChange(this.currentPage + 1); } } diff --git a/src/app/utils/price-mask.utils.ts b/src/app/utils/price-mask.utils.ts index d132c40..28acdc3 100644 --- a/src/app/utils/price-mask.utils.ts +++ b/src/app/utils/price-mask.utils.ts @@ -41,7 +41,7 @@ export function normalizeToNumber(raw: number | string | null | undefined): numb export function formatNumber( value: number, - opts?: { locale?: string; useComma?: boolean; fraction?: number }, + opts?: { locale?: string; useComma?: boolean; fraction?: number } ): string { try { const fmtLocale = opts?.useComma ? 'en-US' : (opts?.locale ?? 'fa-IR'); @@ -59,9 +59,9 @@ export function formatWithCurrency( num: number | string | null, isInputHost: boolean = false, currency: string | null | undefined = 'ریال', - opts?: { locale?: string; useComma?: boolean; fraction?: number }, + opts?: { locale?: string; useComma?: boolean; fraction?: number } ): string { - if (num === null) return ''; + if (num === null) return '0 ریال'; const formatted = formatNumber(parseFloat(num + ''), opts); if (isInputHost) return formatted; if (currency && currency.trim()) return `${formatted} ${currency.trim()}`;