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, 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 { InputNumberInputEvent, InputNumberModule } from 'primeng/inputnumber'; import { InputTextModule } from 'primeng/inputtext'; import { KeyFilterModule } from 'primeng/keyfilter'; import { ToggleSwitch } from 'primeng/toggleswitch'; @Component({ selector: 'app-input', standalone: true, imports: [ CommonModule, ReactiveFormsModule, InputTextModule, InputGroupModule, UikitFieldComponent, ToggleSwitch, InputGroupAddon, InputNumberModule, KeyFilterModule, InputMaskModule, ], templateUrl: './input.component.html', }) export class InputComponent { @Input() type: | 'simple' | 'postalCode' | 'nationalId' | 'mobile' | 'phone' | 'email' | 'checkbox' | 'switch' | 'number' | 'price' = 'simple'; @Input() control!: FormControl>; @Input() name!: string; @Input() label: string = ''; @Input() placeholder?: string; @Input() required = false; @Input() disabled = false; @Input() size?: 'small' | 'large'; @Input() autocomplete?: string = 'off'; @Input() showErrors = true; @Input() hint?: string; @Input() isLtrInput = false; @Input() suffix: string = ''; @Input() maxLength?: number; @Input() min?: number; @Input() max?: number; @Output() valueChange = new EventEmitter(); @Output() blur = new EventEmitter(); @ContentChild('suffixTemp', { static: true }) suffixTemp!: TemplateRef | null; private readonly toastService = inject(ToastService); // onInput(ev: Event) { // const v = (ev.target as HTMLInputElement).value; // const newLocal = v || v == '0'; // // this.valueChange.emit(this.type === 'price' && newLocal ? parseFloat(v) : v); // } preparedSuffix = computed(() => { if (this.type === 'price') { return 'ریال'; } else return this.suffix; }); get preparedPlaceholder(): string | null { if (this.placeholder) return this.placeholder; switch (this.type) { case 'mobile': return '09xxxxxxxx'; case 'postalCode': return 'کد پستی (۱۰ رقم)'; case 'nationalId': return 'کد ملی (۱۰ رقم)'; case 'phone': return 'شماره تلفن'; case 'email': return 'آدرس ایمیل خود را وارد کنید'; case 'price': return 'مبلغ'; default: return ''; } } get inputMode(): string | null { switch (this.type) { case 'mobile': case 'phone': case 'postalCode': case 'nationalId': case 'price': case 'number': return 'numeric'; default: return 'text'; } } get isNumeric(): boolean { return this.inputMode === 'numeric'; } get preparedMaxLength(): number | null { switch (this.type) { case 'mobile': return 11; case 'postalCode': case 'nationalId': return 10; case 'phone': return 11; default: return this.maxLength || null; } } get inputClass(): string { let inputClass = []; switch (this.type) { case 'mobile': case 'phone': case 'price': case 'number': inputClass.push('ltrInput'); break; case 'email': case 'postalCode': case 'nationalId': inputClass.push('ltrInput', 'rtlPlaceholder'); break; } if (this.isLtrInput) { inputClass.push('ltrInput', 'rtlPlaceholder'); } return inputClass.join(' '); } get htmlType(): string { switch (this.type) { case 'email': return 'email'; case 'mobile': case 'phone': case 'price': case 'postalCode': case 'nationalId': case 'number': return 'number'; case 'checkbox': return 'checkbox'; case 'switch': return 'radio'; default: return 'text'; } } get isRequired(): boolean { return this.required || this.control.hasValidator(Validators.required); } onPriceInput($event: InputNumberInputEvent) { this.onInput($event.originalEvent, true); } onInput($event: Event, isPriceFormat?: boolean) { // @ts-ignore let value = $event.target.value as string; // @ts-ignore const isDotInput = $event.data === '.'; if (isPriceFormat) { value = value.replace(/,/g, ''); } let replacedTargetValue: Maybe = null; if (this.inputMode === 'numeric' && !isDotInput) { let newValue = parseFloat(value || '0'); const minValidator = (this.min || this.min === 0) && parseFloat(value) < this.min!; const maxValidator = (this.max || this.max === 0) && parseFloat(value) > this.max; if (minValidator || maxValidator) { if (minValidator) { this.toastService.warn({ text: `مقدار ${this.label} نمی‌تواند بیشتر از ${this.min} باشد.`, }); } if (maxValidator) { this.toastService.warn({ text: `مقدار ${this.label} نمی‌تواند کمتر از ${this.max} باشد.`, }); } newValue = parseFloat(value.slice(0, value.length - 1)); if (newValue < 0 || isNaN(newValue)) { newValue = 0; } replacedTargetValue = isPriceFormat ? newValue.toLocaleString('en-US') : newValue; this.control.setValue(newValue); } if (!['nationalId', 'phone', 'postalCode', 'mobile'].includes(this.type)) { this.control.setValue(newValue); } } if (this.preparedMaxLength && this.preparedMaxLength < value.length) { let newValue = value.slice(0, value.length - 1); // @ts-ignore replacedTargetValue = newValue; this.control.setValue(newValue); } if (replacedTargetValue !== null) { // @ts-ignore this.$event.value = replacedTargetValue; } } }