update input

This commit is contained in:
2026-06-02 13:45:57 +03:30
parent 1f9166bed3
commit 8d6fa8860b
8 changed files with 69 additions and 31 deletions
@@ -0,0 +1,3 @@
<shared-light-bottomsheet [(visible)]="visible" [closable]="true" header="جزییات صورت‌حساب‌">
<pos-order-section (onAddMoreGoods)="closeInvoiceBottomSheet()" (onSubmit)="submitOrder()" />
</shared-light-bottomsheet>
@@ -0,0 +1,21 @@
import { AbstractDialog } from '@/shared/abstractClasses/abstract-dialog';
import { SharedLightBottomsheetComponent } from '@/shared/components';
import { Component, EventEmitter, Output } from '@angular/core';
import { PosOrderSectionComponent } from './order-section.component';
@Component({
selector: 'pos-order-section-dialog',
templateUrl: 'order-section-dialog.component.html',
imports: [SharedLightBottomsheetComponent, PosOrderSectionComponent],
})
export class PosOrderSectionDialogComponent extends AbstractDialog {
@Output() onCloseInvoiceBottomSheet = new EventEmitter();
@Output() onSubmitOrder = new EventEmitter();
closeInvoiceBottomSheet = () => {
this.onCloseInvoiceBottomSheet.emit();
};
submitOrder = () => {
this.onSubmitOrder.emit();
};
}
@@ -33,10 +33,12 @@
</div> </div>
</button> </button>
} }
<shared-light-bottomsheet [(visible)]="showInvoiceBottomSheet" [closable]="true" header="جزییات صورت‌حساب‌"> @if (showInvoiceBottomSheet()) {
<pos-order-section (onAddMoreGoods)="closeInvoiceBottomSheet()" (onSubmit)="submitOrder()" /> <pos-order-section-dialog
</shared-light-bottomsheet> [(visible)]="showInvoiceBottomSheet"
(onAddMoreGoods)="closeInvoiceBottomSheet()"
(onSubmit)="submitOrder()" />
}
@if (isVisiblePaymentForm()) { @if (isVisiblePaymentForm()) {
<pos-payment-form-dialog [(visible)]="isVisiblePaymentForm" (onSubmit)="submitPayment($event)" /> <pos-payment-form-dialog [(visible)]="isVisiblePaymentForm" (onSubmit)="submitPayment($event)" />
} }
@@ -2,11 +2,11 @@
import { Maybe } from '@/core'; import { Maybe } from '@/core';
import { PosInfoStore } from '@/domains/pos/store/pos.store'; import { PosInfoStore } from '@/domains/pos/store/pos.store';
import { AbstractIsMobileComponent } from '@/shared/abstractClasses/abstract-is-mobile'; import { AbstractIsMobileComponent } from '@/shared/abstractClasses/abstract-is-mobile';
import { SharedLightBottomsheetComponent } from '@/shared/components/dialog/light-bottomsheet.component';
import { PageLoadingComponent } from '@/shared/components/page-loading.component'; import { PageLoadingComponent } from '@/shared/components/page-loading.component';
import { PriceMaskDirective } from '@/shared/directives'; import { PriceMaskDirective } from '@/shared/directives';
import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@angular/core'; import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@angular/core';
import { ButtonDirective } from 'primeng/button'; import { ButtonDirective } from 'primeng/button';
import { PosOrderSectionDialogComponent } from '../components/order/order-section-dialog.component';
import { PosOrderSectionComponent } from '../components/order/order-section.component'; import { PosOrderSectionComponent } from '../components/order/order-section.component';
import { PosOrderSubmittedDialogComponent } from '../components/order/order-submitted-dialog.component'; import { PosOrderSubmittedDialogComponent } from '../components/order/order-submitted-dialog.component';
import { PosPaymentFormDialogComponent } from '../components/payment/form-dialog.component'; import { PosPaymentFormDialogComponent } from '../components/payment/form-dialog.component';
@@ -25,10 +25,10 @@ import { PosLandingStore } from '../store/main.store';
PosOrderSectionComponent, PosOrderSectionComponent,
PageLoadingComponent, PageLoadingComponent,
PriceMaskDirective, PriceMaskDirective,
SharedLightBottomsheetComponent,
ButtonDirective, ButtonDirective,
PosOrderSubmittedDialogComponent, PosOrderSubmittedDialogComponent,
PosPaymentFormDialogComponent, PosPaymentFormDialogComponent,
PosOrderSectionDialogComponent,
], ],
}) })
export class PosShopComponent extends AbstractIsMobileComponent { export class PosShopComponent extends AbstractIsMobileComponent {
@@ -97,13 +97,15 @@ export class AmountPercentageInputComponent {
private lastValidAmount = 0; private lastValidAmount = 0;
private lastValidPercentage = 0; private lastValidPercentage = 0;
private toEnglishDigits(value: string): string { private toEnglishDigits(value: Maybe<string | number>): string {
return value const normalizedValue = value === null || value === undefined ? '' : String(value);
return normalizedValue
.replace(/[۰-۹]/g, (digit) => String(digit.charCodeAt(0) - 1776)) .replace(/[۰-۹]/g, (digit) => String(digit.charCodeAt(0) - 1776))
.replace(/[٠-٩]/g, (digit) => String(digit.charCodeAt(0) - 1632)); .replace(/[٠-٩]/g, (digit) => String(digit.charCodeAt(0) - 1632));
} }
private sanitizeNumericValue(value: string, allowDecimal: boolean): string { private sanitizeNumericValue(value: string = '', allowDecimal: boolean): string {
const normalized = this.toEnglishDigits(value).replace(/,/g, ''); const normalized = this.toEnglishDigits(value).replace(/,/g, '');
const cleaned = normalized.replace(allowDecimal ? /[^0-9.]/g : /[^0-9]/g, ''); const cleaned = normalized.replace(allowDecimal ? /[^0-9.]/g : /[^0-9]/g, '');
@@ -114,15 +116,25 @@ export class AmountPercentageInputComponent {
return decimalParts.length ? `${integerPart}.${mergedDecimals}` : integerPart; return decimalParts.length ? `${integerPart}.${mergedDecimals}` : integerPart;
} }
private parseValue(value: Maybe<string>) { private normalizeLeadingZeros(value: string, allowDecimal: boolean): string {
const cleanedValue = this.sanitizeNumericValue( if (!value) return value;
value || '', if (!allowDecimal) return value.replace(/^0+(?=\d)/, '');
this.selectedType.value === 'percentage'
);
console.log('cleaned', cleanedValue); if (value.includes('.')) {
const [integerPart = '0', decimalPart = ''] = value.split('.');
const normalizedInteger = integerPart.replace(/^0+(?=\d)/, '') || '0';
return `${normalizedInteger}.${decimalPart}`;
}
return Number.isFinite(cleanedValue) ? Number(cleanedValue) : 0; return value.replace(/^0+(?=\d)/, '');
}
private makeCleanValue(value: Maybe<string>) {
const allowDecimal = this.selectedType.value === 'percentage';
const cleanedValue = this.sanitizeNumericValue(value || '', allowDecimal);
const normalizedValue = this.normalizeLeadingZeros(cleanedValue, allowDecimal);
return !Number.isNaN(normalizedValue) ? normalizedValue : '0';
} }
private getRangeLabel(value: number, isPercentageType: boolean) { private getRangeLabel(value: number, isPercentageType: boolean) {
@@ -157,7 +169,7 @@ export class AmountPercentageInputComponent {
inputEl.value = value ? value.toLocaleString('en-US') : '0'; inputEl.value = value ? value.toLocaleString('en-US') : '0';
} }
private resetPercentageInputView(value: number) { private resetPercentageInputView(value: string) {
const inputEl = this.percentageInput?.nativeElement; const inputEl = this.percentageInput?.nativeElement;
if (!inputEl) return; if (!inputEl) return;
inputEl.value = `${value}`; inputEl.value = `${value}`;
@@ -178,26 +190,28 @@ export class AmountPercentageInputComponent {
private syncFromPercentage(rawValue: Maybe<any>) { private syncFromPercentage(rawValue: Maybe<any>) {
const { min, max } = this.getPercentageRange(); const { min, max } = this.getPercentageRange();
const percentageValue = this.parseValue(rawValue); const percentageValue = this.makeCleanValue(rawValue);
if (!this.isInRange(percentageValue, min, max)) {
this.showOutOfRangeToast(percentageValue, true, min, max); if (!this.isInRange(Number(percentageValue), min, max)) {
this.showOutOfRangeToast(Number(percentageValue), true, min, max);
this.percentageControl.setValue(this.lastValidPercentage); this.percentageControl.setValue(this.lastValidPercentage);
this.resetPercentageInputView(this.lastValidPercentage); this.resetPercentageInputView(this.lastValidPercentage.toString());
return; return;
} }
this.lastValidPercentage = percentageValue; this.lastValidPercentage = Number(percentageValue);
const amountValue = (this.baseAmount * percentageValue) / 100; const amountValue = (this.baseAmount * Number(percentageValue)) / 100;
this.lastValidAmount = Number.isFinite(amountValue) ? amountValue : 0; this.lastValidAmount = Number.isFinite(amountValue) ? amountValue : 0;
this.percentageControl.setValue(this.lastValidPercentage, { emitEvent: false }); this.percentageControl.setValue(this.lastValidPercentage, { emitEvent: false });
this.amountControl.setValue(this.lastValidAmount, { emitEvent: false }); this.amountControl.setValue(this.lastValidAmount, { emitEvent: false });
this.preparedLabel.set(this.prepareLabel(true)); this.preparedLabel.set(this.prepareLabel(true));
this.resetPercentageInputView(percentageValue);
} }
private syncFromAmount(rawValue: Maybe<any>) { private syncFromAmount(rawValue: Maybe<any>) {
const { min, max } = this.getAmountRange(); const { min, max } = this.getAmountRange();
const amountValue = this.parseValue(rawValue); const amountValue = Number(this.makeCleanValue(rawValue));
if (!this.isInRange(amountValue, min, max)) { if (!this.isInRange(amountValue, min, max)) {
this.showOutOfRangeToast(amountValue, false, min, max); this.showOutOfRangeToast(amountValue, false, min, max);
this.amountControl.setValue(this.lastValidAmount); this.amountControl.setValue(this.lastValidAmount);
@@ -209,7 +223,7 @@ export class AmountPercentageInputComponent {
const percentageValue = this.baseAmount const percentageValue = this.baseAmount
? ((amountValue / this.baseAmount) * 100).toFixed(2) ? ((amountValue / this.baseAmount) * 100).toFixed(2)
: '0'; : '0';
this.lastValidPercentage = this.parseValue(percentageValue); this.lastValidPercentage = Number(this.makeCleanValue(percentageValue));
this.amountControl.setValue(this.lastValidAmount, { emitEvent: false }); this.amountControl.setValue(this.lastValidAmount, { emitEvent: false });
this.percentageControl.setValue(percentageValue, { emitEvent: false }); this.percentageControl.setValue(percentageValue, { emitEvent: false });
@@ -244,8 +258,8 @@ export class AmountPercentageInputComponent {
} }
}); });
this.lastValidAmount = this.parseValue(this.amountControl.value); this.lastValidAmount = Number(this.makeCleanValue(this.amountControl.value));
this.lastValidPercentage = this.parseValue(this.percentageControl.value); this.lastValidPercentage = Number(this.makeCleanValue(this.percentageControl.value));
if (isPercentageType) { if (isPercentageType) {
this.syncFromPercentage(this.percentageControl.value); this.syncFromPercentage(this.percentageControl.value);
} else { } else {
@@ -268,6 +268,7 @@ export class InputComponent {
private writeControlAndViewValue(target: HTMLInputElement, value: string, numericValue: number) { private writeControlAndViewValue(target: HTMLInputElement, value: string, numericValue: number) {
const isIdentifierField = this.isIdentifierField(); const isIdentifierField = this.isIdentifierField();
const controlValue = isIdentifierField ? value : value === '' ? '' : numericValue; const controlValue = isIdentifierField ? value : value === '' ? '' : numericValue;
this.control.setValue(controlValue); this.control.setValue(controlValue);
target.value = value; target.value = value;
@@ -289,6 +290,7 @@ export class InputComponent {
value = this.enforceMaxLength(value); value = this.enforceMaxLength(value);
let numericValue = this.parseNumericValue(value); let numericValue = this.parseNumericValue(value);
const range = this.isOutOfRange(numericValue); const range = this.isOutOfRange(numericValue);
if (value !== '' && (range.min || range.max)) { if (value !== '' && (range.min || range.max)) {
this.notifyRangeError(range); this.notifyRangeError(range);
@@ -62,8 +62,6 @@ export class PriceInputComponent {
} }
onInput(event: InputNumberInputEvent) { onInput(event: InputNumberInputEvent) {
console.log('event', event);
const eventValue = Number(event.value ?? 0); const eventValue = Number(event.value ?? 0);
const min = this.min ?? undefined; const min = this.min ?? undefined;
const max = this.max ?? undefined; const max = this.max ?? undefined;
@@ -181,8 +181,6 @@ export class PageDataListComponent<I = any> {
}; };
onPage = ($event: any) => { onPage = ($event: any) => {
console.log('$event', $event);
this.onChangePage.emit($event); this.onChangePage.emit($event);
}; };