feat: update app version in ngsw-config.json; refactor input component for leading zero normalization and improve payment dialog handling

This commit is contained in:
2026-05-16 20:17:26 +03:30
parent fda318add5
commit 29c5c50d62
8 changed files with 90 additions and 54 deletions
+5 -13
View File
@@ -1,9 +1,9 @@
{ {
"$schema": "./node_modules/@angular/service-worker/config/schema.json", "$schema": "./node_modules/@angular/service-worker/config/schema.json",
"appData": { "appData": {
"appVersion": "0.0.14", "appVersion": "0.0.17",
"buildDate": "2026-05-16T13:47:08.720Z", "buildDate": "2026-05-16T16:43:54.103Z",
"buildNumber": 14 "buildNumber": 17
}, },
"assetGroups": [ "assetGroups": [
{ {
@@ -12,9 +12,7 @@
"resources": { "resources": {
"files": [ "files": [
"/favicon.ico", "/favicon.ico",
"/index.html", "/index.html"
"/*.css",
"/*.js"
] ]
}, },
"updateMode": "prefetch" "updateMode": "prefetch"
@@ -42,11 +40,5 @@
} }
], ],
"dataGroups": [], "dataGroups": [],
"index": "/index.html", "index": "/index.html"
"navigationUrls": [
"/**",
"!/**/*.*",
"!/**/*__*",
"!/**/*__*/**"
]
} }
@@ -119,6 +119,15 @@ export class PosPagesLayoutComponent {
this.layoutService.setTopbarEndSlot(this.topbarEnd); this.layoutService.setTopbarEndSlot(this.topbarEnd);
} }
// ngAfterViewInit() {
// // @ts-ignore
// window.WebV = {
// onPaymentResult: (payload: unknown) => {
// console.log('payload', payload);
// },
// };
// }
ngOnDestroy() { ngOnDestroy() {
this.layoutService.changeIsFullPage(false); this.layoutService.changeIsFullPage(false);
this.layoutService.setTopbarStartSlot(null); this.layoutService.setTopbarStartSlot(null);
@@ -31,16 +31,16 @@ export class PosGoldPayloadFormComponent extends AbstractForm<
IPosOrderItem<IGoldPayload>, IPosOrderItem<IGoldPayload>,
IPosOrderItem<IGoldPayload> IPosOrderItem<IGoldPayload>
> { > {
// override defaultValues: Partial<IPosOrderItem<IGoldPayload>> = { override defaultValues: Partial<IPosOrderItem<IGoldPayload>> = {
// unit_price: 200_000_000, unit_price: 200_000_000,
// quantity: 2, quantity: 2,
// payload: { payload: {
// commission: 10_000, // commission: 10_000,
// wages: 10_000, // wages: 10_000,
// profit: 10_000, // profit: 10_000,
// karat: '18' as TGoldKarat, karat: 'KARAT_18' as TGoldKarat,
// } as any, } as any,
// }; };
@Output() onSubmitForm = new EventEmitter<IGoldPayload>(); @Output() onSubmitForm = new EventEmitter<IGoldPayload>();
@Output() onChangeTotalAmount = new EventEmitter<number>(); @Output() onChangeTotalAmount = new EventEmitter<number>();
@@ -27,6 +27,6 @@
[discountAmount]="discountAmount()" [discountAmount]="discountAmount()"
[taxAmount]="taxAmount()" [taxAmount]="taxAmount()"
/> />
<p-button class="sm:w-auto w-full" (onClick)="submit()"> {{ preparedCTAText() }} </p-button> <button pButton class="sm:w-auto w-full" (onClick)="submit()">{{ preparedCTAText() }}</button>
</div> </div>
</form> </form>
@@ -6,7 +6,7 @@ import { formatWithCurrency } from '@/utils';
import { Component, computed, EventEmitter, Input, Output, signal } from '@angular/core'; import { Component, computed, EventEmitter, Input, Output, signal } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ReactiveFormsModule, Validators } from '@angular/forms'; import { ReactiveFormsModule, Validators } from '@angular/forms';
import { Button } from 'primeng/button'; import { ButtonDirective } from 'primeng/button';
import { IPosOrderItem, IStandardPayload } from '../../../models'; import { IPosOrderItem, IStandardPayload } from '../../../models';
import { PosFormDialogAmountCardTemplateComponent } from '../form-dialog-amount-card-template.component'; import { PosFormDialogAmountCardTemplateComponent } from '../form-dialog-amount-card-template.component';
@@ -16,9 +16,9 @@ import { PosFormDialogAmountCardTemplateComponent } from '../form-dialog-amount-
imports: [ imports: [
ReactiveFormsModule, ReactiveFormsModule,
InputComponent, InputComponent,
Button,
PosFormDialogAmountCardTemplateComponent, PosFormDialogAmountCardTemplateComponent,
AmountPercentageInputComponent, AmountPercentageInputComponent,
ButtonDirective,
], ],
}) })
export class PosStandardPayloadFormComponent extends AbstractForm< export class PosStandardPayloadFormComponent extends AbstractForm<
@@ -57,12 +57,16 @@ export class PosPaymentFormDialogComponent extends AbstractFormDialog<IPayment,
payedInTerminal = signal<Array<number>>([]); payedInTerminal = signal<Array<number>>([]);
private restorePaymentCallback: Maybe<() => void> = null; private restorePaymentCallback: Maybe<() => void> = null;
private readonly injectedPaymentResultHandler = (payload: unknown) => { private readonly injectedPaymentResultHandler = (payload: unknown) => {
alert('پرداخت با موفقیت انجام شد');
this.toastServices.success({ text: 'شد شد شد شد شد' }); this.toastServices.success({ text: 'شد شد شد شد شد' });
// this.handlePaymentResult(payload); // this.handlePaymentResult(payload);
}; };
ngOnViewInit() { ngAfterViewInit() {
console.log('ngOnViewInit');
this.restorePaymentCallback = this.paymentBridge.registerPaymentResultListener( this.restorePaymentCallback = this.paymentBridge.registerPaymentResultListener(
this.injectedPaymentResultHandler, this.injectedPaymentResultHandler,
); );
@@ -1,36 +1,33 @@
import { Injectable } from '@angular/core'; import { ToastService } from '@/core/services/toast.service';
import { inject, Injectable } from '@angular/core';
import { PosPaymentBridgeAbstract } from './payment-bridge.abstract'; import { PosPaymentBridgeAbstract } from './payment-bridge.abstract';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class PosPaymentBridgeService extends PosPaymentBridgeAbstract { export class PosPaymentBridgeService extends PosPaymentBridgeAbstract {
private readonly toastServices = inject(ToastService);
registerPaymentResultListener(handler: (payload: unknown) => void): () => void { registerPaymentResultListener(handler: (payload: unknown) => void): () => void {
const w = window as unknown as { // const w = window as unknown as {
WebV: { // WebV?: {
onPaymentResult?: (payload: unknown) => void; // onPaymentResult?: (payload: unknown) => void;
AndroidBridge?: { // AndroidBridge?: {
onPaymentResult?: (payload: unknown) => void; // onPaymentResult?: (payload: unknown) => void;
}; // };
}; // };
// };
this.toastServices.error({ text: '@@@@@@@@@@@@@' });
// @ts-ignore
window.webV = {
onPaymentResult: () => {
this.toastServices.error({ text: 'asdasdsadassadasdas' });
},
}; };
const previousGlobal = w.WebV.onPaymentResult; return () => {};
const previousBridge = w.WebV.AndroidBridge?.onPaymentResult;
w.WebV.onPaymentResult = handler;
if (w.WebV.AndroidBridge) {
w.WebV.AndroidBridge.onPaymentResult = handler;
}
return () => {
w.WebV.onPaymentResult = previousGlobal;
if (w.WebV.AndroidBridge) {
w.WebV.AndroidBridge.onPaymentResult = previousBridge;
}
};
} }
emitPaymentResultForTest(payload: unknown): void { emitPaymentResultForTest(payload: unknown): void {
const w = window as unknown as { WebV: { onPaymentResult?: (payload: unknown) => void } }; const w = window as unknown as { WebV?: { onPaymentResult?: (payload: unknown) => void } };
w.WebV.onPaymentResult?.(payload); w.WebV?.onPaymentResult?.(payload);
} }
} }
@@ -41,6 +41,7 @@ import { ToggleSwitch } from 'primeng/toggleswitch';
templateUrl: './input.component.html', templateUrl: './input.component.html',
}) })
export class InputComponent { export class InputComponent {
private lastValidNumericValue = '';
@Input() type: @Input() type:
| 'simple' | 'simple'
| 'postalCode' | 'postalCode'
@@ -226,6 +227,21 @@ export class InputComponent {
return `${normalizedInteger}.${fixedDecimal}`; return `${normalizedInteger}.${fixedDecimal}`;
} }
private normalizeLeadingZeros(value: string, allowDecimal: boolean): string {
if (!value) return value;
if (!allowDecimal) {
return value.replace(/^0+(?=\d)/, '');
}
if (value.includes('.')) {
const [integerPart = '0', decimalPart = ''] = value.split('.');
const normalizedInteger = integerPart.replace(/^0+(?=\d)/, '') || '0';
return `${normalizedInteger}.${decimalPart}`;
}
return value.replace(/^0+(?=\d)/, '');
}
onInput($event: Event, isPriceFormat?: boolean) { onInput($event: Event, isPriceFormat?: boolean) {
const target = $event.target as HTMLInputElement | null; const target = $event.target as HTMLInputElement | null;
if (!target) return; if (!target) return;
@@ -236,6 +252,7 @@ export class InputComponent {
if (this.inputMode === 'numeric' || this.inputMode === 'decimal' || isPriceFormat) { if (this.inputMode === 'numeric' || this.inputMode === 'decimal' || isPriceFormat) {
value = this.sanitizeNumericValue(value, allowDecimal); value = this.sanitizeNumericValue(value, allowDecimal);
value = this.applyFixed(value); value = this.applyFixed(value);
value = this.normalizeLeadingZeros(value, allowDecimal);
} }
if (this.preparedMaxLength && value.length > this.preparedMaxLength) { if (this.preparedMaxLength && value.length > this.preparedMaxLength) {
@@ -260,12 +277,23 @@ export class InputComponent {
text: `مقدار ${this.label} نمی‌تواند کمتر از ${this.min} باشد.`, text: `مقدار ${this.label} نمی‌تواند کمتر از ${this.min} باشد.`,
}); });
} }
value = value.slice(0, -1); value = this.lastValidNumericValue;
numericValue = Number.isNaN(parseFloat(value)) ? 0 : parseFloat(value); numericValue = Number.isNaN(parseFloat(value)) ? 0 : parseFloat(value);
const isIdentifierField = ['mobile', 'phone', 'postalCode', 'nationalId'].includes(this.type);
const restoredControlValue = isIdentifierField ? value : value === '' ? '' : numericValue;
this.control.setValue(restoredControlValue);
target.value = isPriceFormat && value !== '' ? numericValue.toLocaleString('en-US') : value;
return;
} else if (this.inputMode === 'numeric' || this.inputMode === 'decimal') {
this.lastValidNumericValue = value;
} }
const isIdentifierField = !this.numericValue; const isIdentifierField = ['mobile', 'phone', 'postalCode', 'nationalId'].includes(this.type);
this.control.setValue(isIdentifierField ? value : value === '' ? '' : numericValue); const controlValue = isIdentifierField ? value : value === '' ? '' : numericValue;
this.control.setValue(controlValue);
const viewValue = isPriceFormat && value !== '' ? numericValue.toLocaleString('en-US') : value; const viewValue = isPriceFormat && value !== '' ? numericValue.toLocaleString('en-US') : value;
@@ -277,4 +305,10 @@ export class InputComponent {
this.valueChange.emit(isIdentifierField ? value : numericValue); this.valueChange.emit(isIdentifierField ? value : numericValue);
} }
} }
ngOnInit() {
const allowDecimal = this.type === 'price' || this.type === 'number';
const initial = this.sanitizeNumericValue(`${this.control?.value ?? ''}`, allowDecimal);
this.lastValidNumericValue = initial;
}
} }