feat: update app version and build details in ngsw-config.json
fix: add baseZIndex to p-toast component in app.component.ts feat: enhance pagination support in saleInvoices list component refactor: modify saleInvoices service to accept pagination query feat: update API routes for saleInvoices to support pagination fix: adjust layout for consumer accounts in partner module style: improve layout for consumer business activities in partner module fix: update license info display in dashboard component fix: ensure price info card displays default values for discount and tax refactor: clean up gold payload form component fix: adjust root component layout for mobile view refactor: unify consumer account list configuration across modules chore: remove deprecated partner consumer account list config chore: remove deprecated superAdmin consumer account list config feat: add new consumer account list configuration style: add summary list styling in customize.scss chore: switch API base URL for TIS environment
This commit is contained in:
+3
-3
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
|
||||
"appData": {
|
||||
"appVersion": "0.0.10",
|
||||
"buildDate": "2026-05-13T09:21:01.165Z",
|
||||
"buildNumber": 10
|
||||
"appVersion": "0.0.12",
|
||||
"buildDate": "2026-05-16T08:49:47.932Z",
|
||||
"buildNumber": 12
|
||||
},
|
||||
"assetGroups": [
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ import { brandingConfig } from './app/branding/branding.config';
|
||||
standalone: true,
|
||||
imports: [RouterModule, ToastModule, ConfirmDialog],
|
||||
template: `
|
||||
<p-toast [position]="toastPosition" />
|
||||
<p-toast [position]="toastPosition" [baseZIndex]="3000" />
|
||||
<p-confirmDialog />
|
||||
<router-outlet />
|
||||
`,
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
emptyPlaceholderTitle="فاکتوری یافت نشد"
|
||||
[items]="items()"
|
||||
[loading]="loading()"
|
||||
[perPage]="responseMetaData()?.perPage"
|
||||
[currentPage]="responseMetaData()?.page"
|
||||
[totalRecords]="responseMetaData()?.totalRecords || items().length"
|
||||
[showDetails]="true"
|
||||
(onDetails)="toSinglePage($event)"
|
||||
(onRefresh)="refresh()"
|
||||
(onChangePage)="changePage($event)"
|
||||
/>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// import { CatalogRoleTagComponent } from '@/shared/catalog/roles';
|
||||
import { Maybe } from '@/core';
|
||||
import { AbstractList } from '@/shared/abstractClasses/abstract-list';
|
||||
import {
|
||||
IColumn,
|
||||
PageDataListComponent,
|
||||
} from '@/shared/components/pageDataList/page-data-list.component';
|
||||
import { IPaginatedQuery } from '@/core/models/service.model';
|
||||
import { saleInvoiceListConfig } from '@/shared/constants/list-configs';
|
||||
import { Component, inject, Input } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
@@ -16,7 +18,10 @@ import { ConsumerSaleInvoicesService } from '../services/main.service';
|
||||
templateUrl: './list.component.html',
|
||||
imports: [PageDataListComponent],
|
||||
})
|
||||
export class ConsumerSaleInvoiceListComponent extends AbstractList<IConsumerSaleInvoicesResponse> {
|
||||
export class ConsumerSaleInvoiceListComponent extends AbstractList<
|
||||
IConsumerSaleInvoicesResponse,
|
||||
IPaginatedQuery
|
||||
> {
|
||||
@Input() fullHeight?: boolean;
|
||||
@Input() header: IColumn[] = saleInvoiceListConfig.columns;
|
||||
|
||||
@@ -27,8 +32,8 @@ export class ConsumerSaleInvoiceListComponent extends AbstractList<IConsumerSale
|
||||
this.columns = this.header;
|
||||
}
|
||||
|
||||
override getDataRequest() {
|
||||
return this.service.getAll();
|
||||
override getDataRequest(payload: Maybe<IPaginatedQuery>) {
|
||||
return this.service.getAll(payload || undefined);
|
||||
}
|
||||
|
||||
toSinglePage(item: IConsumerSaleInvoicesResponse) {
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
import { IPaginatedQuery } from '@/core/models/service.model';
|
||||
|
||||
const baseUrl = () => `/api/v1/consumer/sale-invoices`;
|
||||
|
||||
export const CONSUMER_SALE_INVOICES_API_ROUTES = {
|
||||
list: () => baseUrl(),
|
||||
list: (paginationQuery?: IPaginatedQuery) => {
|
||||
if (!paginationQuery) return baseUrl();
|
||||
const params = new URLSearchParams();
|
||||
if (paginationQuery.page) params.set('page', String(paginationQuery.page));
|
||||
if (paginationQuery.pageSize) params.set('perPage', String(paginationQuery.pageSize));
|
||||
const query = params.toString();
|
||||
return query ? `${baseUrl()}?${query}` : baseUrl();
|
||||
},
|
||||
single: (id: string) => `${baseUrl()}/${id}`,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IPaginatedResponse } from '@/core/models/service.model';
|
||||
import { IPaginatedQuery, IPaginatedResponse } from '@/core/models/service.model';
|
||||
import { ISaleInvoiceFullRawResponse, ISaleInvoiceFullResponse } from '@/domains/consumer/models';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
@@ -12,9 +12,9 @@ export class ConsumerSaleInvoicesService {
|
||||
|
||||
private apiRoutes = CONSUMER_SALE_INVOICES_API_ROUTES;
|
||||
|
||||
getAll(): Observable<IPaginatedResponse<IConsumerSaleInvoicesResponse>> {
|
||||
getAll(paginationQuery?: IPaginatedQuery): Observable<IPaginatedResponse<IConsumerSaleInvoicesResponse>> {
|
||||
return this.http.get<IPaginatedResponse<IConsumerSaleInvoicesRawResponse>>(
|
||||
this.apiRoutes.list(),
|
||||
this.apiRoutes.list(paginationQuery),
|
||||
);
|
||||
}
|
||||
getSingle(invoiceId: string): Observable<ISaleInvoiceFullResponse> {
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
IColumn,
|
||||
PageDataListComponent,
|
||||
} from '@/shared/components/pageDataList/page-data-list.component';
|
||||
import { partnerConsumerAccountListConfig } from '@/shared/constants/list-configs';
|
||||
import { consumerAccountListConfig } from '@/shared/constants/list-configs';
|
||||
import { Component, inject, Input } from '@angular/core';
|
||||
import { IConsumerAccountResponse } from '../../models';
|
||||
import { PartnerConsumerAccountsService } from '../../services/accounts.service';
|
||||
@@ -18,7 +18,7 @@ import { ConsumerAccountFormComponent } from './form.component';
|
||||
export class ConsumerAccountListComponent extends AbstractList<IConsumerAccountResponse> {
|
||||
@Input({ required: true }) consumerId!: string;
|
||||
@Input() fullHeight?: boolean;
|
||||
@Input() header: IColumn[] = partnerConsumerAccountListConfig.columns;
|
||||
@Input() header: IColumn[] = consumerAccountListConfig.columns;
|
||||
private readonly service = inject(PartnerConsumerAccountsService);
|
||||
|
||||
override setColumns(): void {
|
||||
|
||||
@@ -16,8 +16,12 @@
|
||||
</div>
|
||||
</app-card-data>
|
||||
|
||||
<div class="summaryList">
|
||||
<partner-consumer-businessActivities-list [consumerId]="consumerId()" />
|
||||
</div>
|
||||
<div class="summaryList">
|
||||
<partner-consumer-account-list [consumerId]="consumerId()" />
|
||||
</div>
|
||||
|
||||
<partner-consumer-form
|
||||
[(visible)]="editMode"
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
<p-card class="border border-surface-border bg-surface-card rounded-2xl p-4 text-text-color">
|
||||
<div class="w-full flex items-center justify-between gap-1">
|
||||
<span class="text-xl font-semibold">وضعیت {{ title }}</span>
|
||||
<p-badge [value]="`تعداد کل: ${total}`" severity="secondary" size="large"></p-badge>
|
||||
<p-badge [value]="`تعداد کل: ${total}`" severity="secondary" size="large" class="shrink-0"></p-badge>
|
||||
</div>
|
||||
<hr class="mb-6!" />
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
|
||||
@@ -8,6 +8,7 @@ import { MenuItem } from 'primeng/api';
|
||||
import { Button, ButtonDirective } from 'primeng/button';
|
||||
import { Card } from 'primeng/card';
|
||||
import { Menu } from 'primeng/menu';
|
||||
import { finalize } from 'rxjs';
|
||||
import images from 'src/assets/images';
|
||||
import { PosInfoStore, PosProfileStore } from '../../store';
|
||||
import { DeviceInfoStore } from '../../store/device.store';
|
||||
@@ -85,19 +86,22 @@ export class PosPagesLayoutComponent {
|
||||
homeRouteLink = '/pos';
|
||||
|
||||
async getData() {
|
||||
// await this.layoutService.changeFullPageLoading(true);
|
||||
// await this.posProfileStore.getData().subscribe({
|
||||
// next: () => {
|
||||
// this.posInfoStore
|
||||
// .getData()
|
||||
// .pipe(
|
||||
// finalize(() => {
|
||||
// this.layoutService.changeFullPageLoading(false);
|
||||
// }),
|
||||
// )
|
||||
// .subscribe();
|
||||
// },
|
||||
// });
|
||||
if (!this.posInfo() || !this.posProfile()) {
|
||||
await this.layoutService.changeFullPageLoading(true);
|
||||
await this.layoutService.changeFullPageLoading(true);
|
||||
await this.posProfileStore.getData().subscribe({
|
||||
next: () => {
|
||||
this.posInfoStore
|
||||
.getData()
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
this.layoutService.changeFullPageLoading(false);
|
||||
}),
|
||||
)
|
||||
.subscribe();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
toggleMenu() {
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
</div>
|
||||
<div class="flex justify-between items-center">
|
||||
<span>تخفیف</span>
|
||||
<span [appPriceMask]="priceInfo().discountAmount"></span>
|
||||
<span [appPriceMask]="priceInfo().discountAmount || 0"></span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center">
|
||||
<span>مالیات</span>
|
||||
<span [appPriceMask]="priceInfo().taxAmount"></span>
|
||||
<span [appPriceMask]="priceInfo().taxAmount || 0"></span>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="flex justify-between items-center font-bold text-lg">
|
||||
|
||||
@@ -31,16 +31,16 @@ export class PosGoldPayloadFormComponent extends AbstractForm<
|
||||
IPosOrderItem<IGoldPayload>,
|
||||
IPosOrderItem<IGoldPayload>
|
||||
> {
|
||||
override defaultValues: Partial<IPosOrderItem<IGoldPayload>> = {
|
||||
unit_price: 200_000_000,
|
||||
quantity: 2,
|
||||
payload: {
|
||||
commission: 10_000,
|
||||
wages: 10_000,
|
||||
profit: 10_000,
|
||||
karat: '18' as TGoldKarat,
|
||||
} as any,
|
||||
};
|
||||
// override defaultValues: Partial<IPosOrderItem<IGoldPayload>> = {
|
||||
// unit_price: 200_000_000,
|
||||
// quantity: 2,
|
||||
// payload: {
|
||||
// commission: 10_000,
|
||||
// wages: 10_000,
|
||||
// profit: 10_000,
|
||||
// karat: '18' as TGoldKarat,
|
||||
// } as any,
|
||||
// };
|
||||
|
||||
@Output() onSubmitForm = new EventEmitter<IGoldPayload>();
|
||||
@Output() onChangeTotalAmount = new EventEmitter<number>();
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
type="button"
|
||||
pButton
|
||||
class="sticky! bottom-0 inset-x-0 w-full right-0 z-1200 border-t border-surface-border bg-surface-0 px-4 py-3 shadow-[0_-4px_16px_rgba(0,0,0,0.08)] md:hidden! rounded-b-none!"
|
||||
[style.paddingBottom]="'calc(0.75rem + {{env(safe-area-inset-bottom)}})'"
|
||||
(click)="openInvoiceBottomSheet()"
|
||||
>
|
||||
<!-- [style.paddingBottom]="'calc(0.75rem + {{env(safe-area-inset-bottom)}})'" -->
|
||||
<div class="mx-auto flex w-full max-w-3xl items-center justify-between">
|
||||
<div class="flex flex-col items-start gap-1">
|
||||
<span class="text-base">مبلغ کل فاکتور</span>
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
IColumn,
|
||||
PageDataListComponent,
|
||||
} from '@/shared/components/pageDataList/page-data-list.component';
|
||||
import { superAdminConsumerAccountListConfig } from '@/shared/constants/list-configs';
|
||||
import { consumerAccountListConfig } from '@/shared/constants/list-configs';
|
||||
import { Component, inject, Input } from '@angular/core';
|
||||
import { IConsumerAccountResponse } from '../../models';
|
||||
import { AdminConsumerAccountsService } from '../../services/accounts.service';
|
||||
@@ -18,7 +18,7 @@ import { ConsumerAccountFormComponent } from './form.component';
|
||||
export class ConsumerAccountListComponent extends AbstractList<IConsumerAccountResponse> {
|
||||
@Input({ required: true }) consumerId!: string;
|
||||
@Input() fullHeight?: boolean;
|
||||
@Input() header: IColumn[] = superAdminConsumerAccountListConfig.columns;
|
||||
@Input() header: IColumn[] = consumerAccountListConfig.columns;
|
||||
private readonly service = inject(AdminConsumerAccountsService);
|
||||
|
||||
override setColumns(): void {
|
||||
|
||||
+10
-1
@@ -1,12 +1,14 @@
|
||||
import ISummary from '@/core/models/summary';
|
||||
|
||||
export interface IBusinessActivityRawResponse {
|
||||
id: string;
|
||||
name: string;
|
||||
economic_code: string;
|
||||
fiscal_id: string;
|
||||
partner_token: string;
|
||||
guild: ISummary;
|
||||
id: string;
|
||||
created_at: string;
|
||||
license_info: LicenseInfo;
|
||||
}
|
||||
export interface IBusinessActivityResponse extends IBusinessActivityRawResponse {}
|
||||
|
||||
@@ -17,3 +19,10 @@ export interface IBusinessActivityRequest {
|
||||
partner_token: string;
|
||||
guild_id: string;
|
||||
}
|
||||
|
||||
interface LicenseInfo {
|
||||
id: string;
|
||||
starts_at: string;
|
||||
expires_at: string;
|
||||
accounts_limit: number;
|
||||
}
|
||||
|
||||
+3
@@ -3,7 +3,10 @@
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="listKeyValue">
|
||||
<app-key-value label="عنوان" [value]="businessActivity()?.name" />
|
||||
<app-key-value label="کد اقتصادی" [value]="businessActivity()?.economic_code" />
|
||||
<app-key-value label="صنف" [value]="businessActivity()?.guild?.name" />
|
||||
<app-key-value label="تاریخ انقضا مجوز" [value]="businessActivity()?.license_info?.expires_at" type="date" />
|
||||
<app-key-value label="تعداد کاربران مجاز" [value]="businessActivity()?.license_info?.accounts_limit" />
|
||||
</div>
|
||||
</div>
|
||||
</app-card-data>
|
||||
|
||||
@@ -4,21 +4,24 @@
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="listKeyValue">
|
||||
<app-key-value label="نام مشتری" [value]="consumer()?.name" />
|
||||
<app-key-value label="وضعیت" [value]="consumer()?.status?.translate" />
|
||||
<app-key-value label="نوع مشتری" [value]="consumer()?.type?.translate" />
|
||||
|
||||
@if (consumer()?.type?.value === "LEGAL") {
|
||||
<app-key-value label="شناسه ملی" [value]="consumer()?.legal?.registration_code" />
|
||||
} @else {
|
||||
<app-key-value label="شماره موبایل" [value]="consumer()?.individual?.mobile_number" />
|
||||
<app-key-value label="کد ملی" [value]="consumer()?.individual?.national_code" />
|
||||
}
|
||||
<app-key-value label="وضعیت" [value]="consumer()?.status?.value === 'ACTIVE'" type="active" />
|
||||
</div>
|
||||
</div>
|
||||
</app-card-data>
|
||||
|
||||
<superAdmin-consumer-account-list [consumerId]="consumerId()" />
|
||||
<div class="summaryList">
|
||||
<superAdmin-consumer-businessActivities-list [consumerId]="consumerId()" />
|
||||
</div>
|
||||
<div class="summaryList">
|
||||
<superAdmin-consumer-account-list [consumerId]="consumerId()" />
|
||||
</div>
|
||||
|
||||
<superAdmin-consumer-form
|
||||
[(visible)]="editMode"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Maybe } from '@/core';
|
||||
import {
|
||||
IListingResponse,
|
||||
IPaginatedQuery,
|
||||
IPaginatedResponse,
|
||||
IResponseMetadata,
|
||||
} from '@/core/models/service.model';
|
||||
@@ -82,6 +83,16 @@ export abstract class AbstractList<ResponseModel, RequestParams = null> {
|
||||
}
|
||||
|
||||
changePage(page: number) {
|
||||
// this.
|
||||
const perPage = this.responseMetaData()?.perPage;
|
||||
this.requestPayload.update(
|
||||
(prev) =>
|
||||
({
|
||||
...(prev || {}),
|
||||
page,
|
||||
...(perPage ? ({ pageSize: perPage } as IPaginatedQuery) : {}),
|
||||
}) as any,
|
||||
);
|
||||
this.responseMetaData.update((prev) => (prev ? { ...prev, page } : prev));
|
||||
this.getData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,9 +28,7 @@
|
||||
[inputStyleClass]="` w-full hasSuffix text-left ${size === 'large' ? 'p-inputtext-lg' : size === 'small' ? 'p-inputtext-sm' : ''}`"
|
||||
[required]="required"
|
||||
[invalid]="amountControl.invalid && (amountControl.touched || amountControl.dirty)"
|
||||
(onInput)="onPriceInput($event)"
|
||||
/>
|
||||
<!-- (input)="onInput($event)" -->
|
||||
} @else {
|
||||
<input
|
||||
pInputText
|
||||
@@ -50,7 +48,6 @@
|
||||
"
|
||||
[required]="required"
|
||||
[invalid]="percentageControl.invalid && (percentageControl.touched || percentageControl.dirty)"
|
||||
(input)="onInput($event)"
|
||||
/>
|
||||
}
|
||||
|
||||
|
||||
+97
-76
@@ -19,7 +19,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { InputGroup } from 'primeng/inputgroup';
|
||||
import { InputGroupAddon } from 'primeng/inputgroupaddon';
|
||||
import { InputNumberInputEvent, InputNumberModule } from 'primeng/inputnumber';
|
||||
import { InputNumberModule } from 'primeng/inputnumber';
|
||||
import { InputText } from 'primeng/inputtext';
|
||||
import { Select } from 'primeng/select';
|
||||
|
||||
@@ -90,83 +90,85 @@ export class AmountPercentageInputComponent {
|
||||
});
|
||||
|
||||
preparedLabel = signal(this.label);
|
||||
private lastValidAmount = 0;
|
||||
private lastValidPercentage = 0;
|
||||
|
||||
onPriceInput($event: InputNumberInputEvent) {
|
||||
this.onInput($event.originalEvent, true);
|
||||
private parseValue(value: Maybe<any>) {
|
||||
const normalized = `${value ?? ''}`.replace(/,/g, '');
|
||||
const parsed = parseFloat(normalized);
|
||||
return Number.isFinite(parsed) ? parsed : 0;
|
||||
}
|
||||
|
||||
onInput($event: Event, isPriceType: boolean = false) {
|
||||
// @ts-ignore
|
||||
let value = $event.target.value as string;
|
||||
// @ts-ignore
|
||||
const isDotInput = $event.data === '.';
|
||||
private getRangeLabel(value: number, isPercentageType: boolean) {
|
||||
return isPercentageType ? `${value}%` : formatWithCurrency(value);
|
||||
}
|
||||
|
||||
if (isDotInput) {
|
||||
private isInRange(value: number, min = 0, max = Number.MAX_SAFE_INTEGER) {
|
||||
return value >= min && value <= max;
|
||||
}
|
||||
|
||||
private showOutOfRangeToast(value: number, isPercentageType: boolean, min = 0, max = Number.MAX_SAFE_INTEGER) {
|
||||
if (value < min) {
|
||||
this.toastService.warn({
|
||||
text: `مقدار ${this.label} باید بیشتر از ${this.getRangeLabel(min, isPercentageType)} باشد.`,
|
||||
});
|
||||
}
|
||||
if (value > max) {
|
||||
this.toastService.warn({
|
||||
text: `مقدار ${this.label} باید کمتر از ${this.getRangeLabel(max, isPercentageType)} باشد.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private getAmountRange() {
|
||||
const min = this.minAmount ?? 0;
|
||||
const maxFromInput = this.maxAmount;
|
||||
const max = maxFromInput ?? (this.baseAmount > 0 ? this.baseAmount : Number.MAX_SAFE_INTEGER);
|
||||
return { min, max };
|
||||
}
|
||||
|
||||
private getPercentageRange() {
|
||||
const min = this.minPercentage ?? 0;
|
||||
const max = this.maxPercentage ?? 100;
|
||||
return { min, max };
|
||||
}
|
||||
|
||||
private syncFromPercentage(rawValue: Maybe<any>) {
|
||||
const { min, max } = this.getPercentageRange();
|
||||
const percentageValue = this.parseValue(rawValue);
|
||||
if (!this.isInRange(percentageValue, min, max)) {
|
||||
this.showOutOfRangeToast(percentageValue, true, min, max);
|
||||
this.percentageControl.setValue(this.lastValidPercentage, { emitEvent: false });
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPriceType) {
|
||||
value = value.replace(/,/g, '');
|
||||
this.lastValidPercentage = percentageValue;
|
||||
const amountValue = (this.baseAmount * percentageValue) / 100;
|
||||
this.lastValidAmount = Number.isFinite(amountValue) ? amountValue : 0;
|
||||
|
||||
this.percentageControl.setValue(this.lastValidPercentage, { emitEvent: false });
|
||||
this.amountControl.setValue(this.lastValidAmount, { emitEvent: false });
|
||||
this.preparedLabel.set(this.prepareLabel(true));
|
||||
}
|
||||
|
||||
const newValueToSet = this.modifyControlsData(value);
|
||||
|
||||
if (newValueToSet !== null) {
|
||||
// @ts-ignore
|
||||
$event.target.value = newValueToSet;
|
||||
}
|
||||
private syncFromAmount(rawValue: Maybe<any>) {
|
||||
const { min, max } = this.getAmountRange();
|
||||
const amountValue = this.parseValue(rawValue);
|
||||
if (!this.isInRange(amountValue, min, max)) {
|
||||
this.showOutOfRangeToast(amountValue, false, min, max);
|
||||
this.amountControl.setValue(this.lastValidAmount, { emitEvent: false });
|
||||
return;
|
||||
}
|
||||
|
||||
private modifyControlsData(value: string) {
|
||||
let newValueToSet: Maybe<string> = null;
|
||||
let newValue = parseFloat(value);
|
||||
const isPercentageType = this.selectedType.value === 'percentage';
|
||||
this.lastValidAmount = amountValue;
|
||||
const percentageValue = this.baseAmount
|
||||
? ((amountValue / this.baseAmount) * 100).toFixed(2)
|
||||
: '0';
|
||||
this.lastValidPercentage = this.parseValue(percentageValue);
|
||||
|
||||
const min = (isPercentageType ? this.minPercentage : this.minAmount) || 0;
|
||||
const max = (isPercentageType ? this.maxPercentage : this.maxAmount) || Number.MAX_SAFE_INTEGER;
|
||||
|
||||
const maxValidator = max < newValue;
|
||||
const minValidator = min > newValue;
|
||||
|
||||
const notValid = minValidator || maxValidator;
|
||||
|
||||
if (notValid) {
|
||||
if (minValidator) {
|
||||
this.toastService.warn({
|
||||
text: `مقدار ${this.label} باید بیشتر از ${formatWithCurrency(min)} باشد.`,
|
||||
});
|
||||
}
|
||||
if (maxValidator) {
|
||||
this.toastService.warn({
|
||||
text: `مقدار ${this.label} باید کمتر از ${formatWithCurrency(max)} باشد.`,
|
||||
});
|
||||
}
|
||||
|
||||
newValue = parseFloat(value.slice(0, value.length - 1));
|
||||
if (newValue < 0 || isNaN(newValue)) {
|
||||
newValue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (isPercentageType) {
|
||||
const amountValue = (this.baseAmount * newValue) / 100;
|
||||
newValueToSet = newValue + '';
|
||||
this.amountControl.setValue(isNaN(amountValue) ? 0 : amountValue, { emitEvent: false });
|
||||
if (notValid) {
|
||||
this.percentageControl.setValue(newValue, { emitEvent: false });
|
||||
}
|
||||
} else {
|
||||
const percentageValue = ((newValue / this.baseAmount) * 100).toFixed(2);
|
||||
newValueToSet = newValue + '';
|
||||
this.amountControl.setValue(this.lastValidAmount, { emitEvent: false });
|
||||
this.percentageControl.setValue(percentageValue, { emitEvent: false });
|
||||
this.preparedLabel.set(`${this.label} (${percentageValue} درصد)`);
|
||||
if (notValid) {
|
||||
this.amountControl.setValue(newValue, { emitEvent: false });
|
||||
}
|
||||
}
|
||||
this.preparedLabel.set(this.prepareLabel(isPercentageType));
|
||||
|
||||
return newValue;
|
||||
this.preparedLabel.set(this.prepareLabel(false));
|
||||
}
|
||||
|
||||
private prepareLabel(isPercentageType: boolean) {
|
||||
@@ -177,25 +179,44 @@ export class AmountPercentageInputComponent {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
const amountValue = Number(this.amountControl.value || 0);
|
||||
const percentageValue = Number(this.percentageControl.value || 0);
|
||||
const isPercentageType = percentageValue > 0 && amountValue <= 0;
|
||||
|
||||
console.log(amountValue, percentageValue, isPercentageType);
|
||||
|
||||
this.preparedLabel.set(this.prepareLabel(isPercentageType));
|
||||
const isPercentageType = this.defaultType === 'percentage';
|
||||
|
||||
this.selectedType.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((value) => {
|
||||
this.preparedLabel.set(this.prepareLabel(value === 'percentage'));
|
||||
});
|
||||
|
||||
this.selectedType.setValue(isPercentageType ? 'percentage' : 'amount');
|
||||
this.percentageControl.valueChanges
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((value) => {
|
||||
if (this.selectedType.value === 'percentage') {
|
||||
this.syncFromPercentage(value);
|
||||
}
|
||||
});
|
||||
|
||||
this.amountControl.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((value) => {
|
||||
if (this.selectedType.value === 'amount') {
|
||||
this.syncFromAmount(value);
|
||||
}
|
||||
});
|
||||
|
||||
this.selectedType.setValue(isPercentageType ? 'percentage' : 'amount', { emitEvent: false });
|
||||
this.lastValidAmount = this.parseValue(this.amountControl.value);
|
||||
this.lastValidPercentage = this.parseValue(this.percentageControl.value);
|
||||
if (isPercentageType) {
|
||||
this.syncFromPercentage(this.percentageControl.value);
|
||||
} else {
|
||||
this.syncFromAmount(this.amountControl.value);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
const amountValue = Number(this.amountControl.value || 0);
|
||||
const percentageValue = Number(this.percentageControl.value || 0);
|
||||
const isPercentageType = percentageValue > 0 && amountValue <= 0;
|
||||
const isPercentageType = this.selectedType.value === 'percentage';
|
||||
if (isPercentageType) {
|
||||
this.syncFromPercentage(this.percentageControl.value);
|
||||
} else {
|
||||
this.syncFromAmount(this.amountControl.value);
|
||||
}
|
||||
|
||||
this.preparedLabel.set(this.prepareLabel(isPercentageType));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
}
|
||||
@if (showIndex) {
|
||||
<td>
|
||||
{{ i * (currentPage || 1) + 1 }}
|
||||
{{ i + 1 + (currentPage && perPage ? (currentPage - 1) * perPage : 0) }}
|
||||
</td>
|
||||
}
|
||||
@for (col of columns; track col.field) {
|
||||
|
||||
@@ -18,8 +18,8 @@ import { SkeletonModule } from 'primeng/skeleton';
|
||||
import { TableModule } from 'primeng/table';
|
||||
import { KeyValueComponent } from '../key-value.component/key-value.component';
|
||||
import { TableActionRowComponent } from '../table-action-row.component';
|
||||
import { PageDataValueComponent } from './page-data-value.component';
|
||||
import { IColumn } from './page-data-list.component';
|
||||
import { PageDataValueComponent } from './page-data-value.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-page-data-list-table-view',
|
||||
@@ -50,6 +50,7 @@ export class AppPageDataListTableView<I = any> {
|
||||
@Input() emptyPlaceholderDescription?: string = '';
|
||||
@Input() emptyPlaceholderCtaLabel?: string;
|
||||
@Input() currentPage?: number = 1;
|
||||
@Input() perPage?: number = 1;
|
||||
@Input() showEdit: boolean = false;
|
||||
@Input() showDelete: boolean = false;
|
||||
@Input() showDetails: boolean = false;
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
[emptyPlaceholderCtaLabel]="emptyPlaceholderCtaLabel || addNewCtaLabel"
|
||||
[addNewCtaLabel]="addNewCtaLabel"
|
||||
[currentPage]="currentPage"
|
||||
[perPage]="perPage"
|
||||
[showEdit]="showEdit"
|
||||
[showDelete]="showDelete"
|
||||
[showDetails]="showDetails"
|
||||
@@ -84,9 +85,11 @@
|
||||
[expandable]="expandable"
|
||||
[expandableItemKey]="expandableItemKey"
|
||||
[expandColumns]="expandColumns"
|
||||
[showPaginator]="showPaginator"
|
||||
(onEdit)="edit($event)"
|
||||
(onDelete)="remove($event)"
|
||||
(onDetails)="details($event)"
|
||||
(onChangePage)="onPage($event)"
|
||||
>
|
||||
@if (pageTitle || showAdd || filter || showRefresh || moreActions) {
|
||||
<ng-template #captionBox>
|
||||
|
||||
@@ -176,6 +176,8 @@ export class PageDataListComponent<I = any> {
|
||||
};
|
||||
|
||||
onPage = ($event: any) => {
|
||||
console.log('$event', $event);
|
||||
|
||||
this.onChangePage.emit($event);
|
||||
};
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { IListConfig } from './list-config.model';
|
||||
|
||||
export const partnerConsumerAccountListConfig: IListConfig = {
|
||||
export const consumerAccountListConfig: IListConfig = {
|
||||
pageTitle: 'مدیریت حسابهای مشتری',
|
||||
addNewCtaLabel: 'افزودن حساب',
|
||||
emptyPlaceholderTitle: 'حسابی یافت نشد',
|
||||
@@ -27,7 +27,7 @@ export const partnerConsumerAccountListConfig: IListConfig = {
|
||||
field: 'status',
|
||||
header: 'وضعیت',
|
||||
type: 'nested',
|
||||
nestedOption: { path: 'account.status.translate' },
|
||||
nestedOption: { path: 'status.translate' },
|
||||
variant: 'tag',
|
||||
},
|
||||
],
|
||||
@@ -2,6 +2,7 @@ export * from './account-list.const';
|
||||
export * from './business-activity-list.const';
|
||||
export * from './category-list.const';
|
||||
export * from './complex-list.const';
|
||||
export * from './consumer-account-list.const';
|
||||
export * from './consumer-list.const';
|
||||
export * from './device-brand-list.const';
|
||||
export * from './device-list.const';
|
||||
@@ -9,12 +10,10 @@ export * from './good-list.const';
|
||||
export * from './license-list.const';
|
||||
export * from './list-config.model';
|
||||
export * from './partner-account-list.const';
|
||||
export * from './partner-consumer-account-list.const';
|
||||
export * from './partner-customer-list.const';
|
||||
export * from './partner-list.const';
|
||||
export * from './pos-list.const';
|
||||
export * from './provider-list.const';
|
||||
export * from './sale-invoice-list.const';
|
||||
export * from './sku-list.const';
|
||||
export * from './superAdmin-consumer-account-list.const';
|
||||
export * from './user-list.const';
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { IListConfig } from './list-config.model';
|
||||
|
||||
export const superAdminConsumerAccountListConfig: IListConfig = {
|
||||
pageTitle: 'مدیریت حسابهای مشتری',
|
||||
addNewCtaLabel: 'افزودن حساب',
|
||||
emptyPlaceholderTitle: 'حسابی یافت نشد',
|
||||
emptyPlaceholderDescription: 'برای افزودن حساب، روی دکمهٔ بالا کلیک کنید.',
|
||||
columns: [
|
||||
{
|
||||
field: 'account',
|
||||
header: 'نام کاربری',
|
||||
type: 'nested',
|
||||
nestedOption: { path: 'account.username' },
|
||||
},
|
||||
{ field: 'role', header: 'نوع حساب', type: 'nested', nestedOption: { path: 'role.translate' } },
|
||||
{
|
||||
field: 'pos',
|
||||
header: 'پایانه',
|
||||
customDataModel(item: any) {
|
||||
return `${item.pos.name} (${item.pos.complex.name} - ${item.pos.complex.business_activity.name})`;
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
header: 'وضعیت',
|
||||
type: 'nested',
|
||||
nestedOption: { path: 'account.status.translate' },
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
header: 'تاریخ ایجاد',
|
||||
type: 'date',
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -9,3 +9,10 @@
|
||||
.cardShadow {
|
||||
box-shadow: var(--p-card-shadow) !important;
|
||||
}
|
||||
|
||||
.summaryList {
|
||||
@apply max-h-125 flex;
|
||||
> * {
|
||||
@apply w-full;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// TIS tenant environment configuration
|
||||
export const environment = {
|
||||
production: true,
|
||||
apiBaseUrl: 'https://psp-api.shift-am.ir',
|
||||
// apiBaseUrl: 'http://192.168.128.73:5002',
|
||||
// apiBaseUrl: 'https://psp-api.shift-am.ir',
|
||||
apiBaseUrl: 'http://192.168.128.73:5002',
|
||||
host: 'localhost',
|
||||
port: 5000,
|
||||
enableLogging: false,
|
||||
|
||||
Reference in New Issue
Block a user