update pos consumer

This commit is contained in:
2026-03-29 18:07:10 +03:30
parent 1e2f94261e
commit c10623bc3f
86 changed files with 2935 additions and 385 deletions
@@ -16,6 +16,7 @@
[class]="` w-full ${size === 'large' ? 'p-inputtext-lg' : size === 'small' ? 'p-inputtext-sm' : ''}`"
[required]="isRequired"
[invalid]="control.invalid && (control.touched || control.dirty)"
(onInput)="onPriceInput($event)"
(onBlur)="blur.emit()"
/>
<!-- (input)="onInput($event)" -->
@@ -39,7 +40,9 @@
(input)="onInput($event)"
/>
}
@if (preparedSuffix()) {
@if (suffixTemp) {
<ng-container [ngTemplateOutlet]="suffixTemp" />
} @else if (preparedSuffix()) {
<p-inputgroup-addon>{{ preparedSuffix() }}</p-inputgroup-addon>
}
</p-inputgroup>
@@ -2,12 +2,21 @@ import { Maybe } from '@/core';
import { ToastService } from '@/core/services/toast.service';
import { UikitFieldComponent } from '@/uikit/uikit-field.component';
import { CommonModule } from '@angular/common';
import { Component, computed, EventEmitter, inject, Input, Output } from '@angular/core';
import {
Component,
computed,
ContentChild,
EventEmitter,
inject,
Input,
Output,
TemplateRef,
} from '@angular/core';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
import { InputGroupModule } from 'primeng/inputgroup';
import { InputGroupAddon } from 'primeng/inputgroupaddon';
import { InputMaskModule } from 'primeng/inputmask';
import { InputNumberModule } from 'primeng/inputnumber';
import { InputNumberInputEvent, InputNumberModule } from 'primeng/inputnumber';
import { InputTextModule } from 'primeng/inputtext';
import { KeyFilterModule } from 'primeng/keyfilter';
import { ToggleSwitch } from 'primeng/toggleswitch';
@@ -33,6 +42,7 @@ export class InputComponent {
@Input() type:
| 'simple'
| 'postalCode'
| 'nationalId'
| 'mobile'
| 'phone'
| 'email'
@@ -58,6 +68,8 @@ export class InputComponent {
@Output() valueChange = new EventEmitter<string | number>();
@Output() blur = new EventEmitter<void>();
@ContentChild('suffixTemp', { static: true }) suffixTemp!: TemplateRef<any> | null;
private readonly toastService = inject(ToastService);
// onInput(ev: Event) {
@@ -80,6 +92,8 @@ export class InputComponent {
return '09xxxxxxxx';
case 'postalCode':
return 'کد پستی (۱۰ رقم)';
case 'nationalId':
return 'کد ملی (۱۰ رقم)';
case 'phone':
return 'شماره تلفن';
case 'email':
@@ -96,6 +110,7 @@ export class InputComponent {
case 'mobile':
case 'phone':
case 'postalCode':
case 'nationalId':
case 'price':
case 'number':
return 'numeric';
@@ -113,6 +128,7 @@ export class InputComponent {
case 'mobile':
return 11;
case 'postalCode':
case 'nationalId':
return 10;
case 'phone':
return 11;
@@ -132,6 +148,7 @@ export class InputComponent {
break;
case 'email':
case 'postalCode':
case 'nationalId':
inputClass.push('ltrInput', 'rtlPlaceholder');
break;
}
@@ -150,6 +167,7 @@ export class InputComponent {
case 'phone':
case 'price':
case 'postalCode':
case 'nationalId':
case 'number':
return 'number';
case 'checkbox':
@@ -165,11 +183,22 @@ export class InputComponent {
return this.required || this.control.hasValidator(Validators.required);
}
onInput($event: Event) {
onPriceInput($event: InputNumberInputEvent) {
console.log($event);
this.onInput($event.originalEvent, true);
}
onInput($event: Event, isPriceFormat?: boolean) {
// @ts-ignore
const value = $event.target.value as string;
if (this.type === 'number') {
let value = $event.target.value as string;
if (isPriceFormat) {
value = value.replace(/,/g, '');
}
if (this.inputMode === 'numeric') {
let newValue = parseFloat(value);
// console.log(value, newValue);
const minValidator = (this.min || this.min === 0) && parseFloat(value) < this.min!;
const maxValidator = (this.max || this.max === 0) && parseFloat(value) > this.max;
@@ -187,10 +216,20 @@ export class InputComponent {
}
newValue = parseFloat(value.slice(0, value.length - 1));
// @ts-ignore
$event.target.value = newValue;
if (newValue < 0 || isNaN(newValue)) {
newValue = 0;
}
if (isPriceFormat) {
// @ts-ignore
$event.target.value = newValue.toLocaleString('en-US');
} else {
// @ts-ignore
$event.target.value = newValue;
}
this.control.setValue(newValue);
}
this.control.setValue(newValue);
}
if (this.preparedMaxLength && this.preparedMaxLength < value.length) {
@@ -1,6 +1,17 @@
<div class="inline-flex gap-2 items-center w-full">
<span class="text-muted-color text-base font-normal shrink-0">{{ label }}:</span>
<ng-content>
<span class="text-text-color text-base font-bold grow">{{ value || "-" }}</span>
</ng-content>
<div class="inline-flex flex-col gap-1 w-full">
<div class="inline-flex gap-2 items-center w-full">
<span class="text-muted-color text-base font-normal flex-auto grow-0">{{ label }}:</span>
<div class="shrink-0 grow">
<ng-content>
@if (valueType() === "badge") {
<p-badge [value]="valueToShow()?.toString()" [severity]="value ? 'success' : 'danger'" />
} @else {
<span class="text-text-color text-base font-bold grow"> {{ valueToShow() }}</span>
}
</ng-content>
</div>
</div>
@if (hint) {
<span class="text-muted-color text-sm font-normal">{{ hint }}</span>
}
</div>
@@ -1,10 +1,13 @@
import { formatDurationToText, formatJalali, JALALI_DATE_FORMATS } from '@/utils';
import priceMaskUtils from '@/utils/price-mask.utils';
import { CommonModule } from '@angular/common';
import { Component, Input } from '@angular/core';
import { Component, computed, Input, signal } from '@angular/core';
import { Badge } from 'primeng/badge';
@Component({
selector: 'app-key-value',
standalone: true,
imports: [CommonModule],
imports: [CommonModule, Badge],
templateUrl: './key-value.component.html',
host: {
class: 'w-full block',
@@ -12,5 +15,86 @@ import { Component, Input } from '@angular/core';
})
export class KeyValueComponent {
@Input() label!: string;
@Input() value?: string = '-';
@Input() value?: string | boolean | number;
@Input() hint?: string;
@Input() type:
| 'price'
| 'active'
| 'boolean'
| 'has'
| 'date'
| 'dateTime'
| 'duration'
| 'simple' = 'simple';
@Input() trueValueToShow?: string;
@Input() falseValueToShow?: string;
@Input() variant?: 'badge' | 'text';
valueToShow = signal(this.setValueToShow());
ngOnChanges() {
this.valueToShow.set(this.setValueToShow());
}
setValueToShow() {
let value = this.value;
if (this.type !== 'simple') {
if (this.value) {
if (this.trueValueToShow) {
value = this.trueValueToShow;
} else {
switch (this.type) {
case 'date':
if (typeof this.value === 'boolean') return '-';
// @ts-ignore
return formatJalali(this.value);
case 'dateTime':
if (typeof this.value === 'boolean') return '-';
// @ts-ignore
return formatJalali(this.value, JALALI_DATE_FORMATS.NUMERIC_WITH_TIME);
case 'duration':
return formatDurationToText(this.value as string);
case 'price':
return priceMaskUtils.formatWithCurrency(this.value as number);
case 'active':
value = 'فعال';
break;
case 'boolean':
value = 'بله';
break;
case 'has':
value = 'دارد';
break;
}
}
} else {
if (this.falseValueToShow) {
value = this.falseValueToShow;
} else {
switch (this.type) {
case 'active':
value = 'غیر فعال';
break;
case 'boolean':
value = 'خیر';
break;
case 'has':
value = 'ندارد';
break;
}
}
}
}
switch (this.type) {
case 'simple':
return this.value || '';
}
return value;
}
valueType = computed(() =>
this.variant || ['boolean', 'has', 'active'].includes(this.type) ? 'badge' : 'text',
);
}