Add tests and implementation for ServiceDetailPage and PriceInput components
- Implement PriceInput component tests to validate Persian and Arabic numeral handling, input formatting, and controlled behavior. - Create ServiceDetailPage component with detailed service information, including pricing, insurance coverage, and editing capabilities. - Add API tests for service item detail retrieval and coverage synchronization with insurance contracts. - Ensure proper error handling and user feedback for service item retrieval and coverage management.
This commit is contained in:
@@ -14,6 +14,11 @@ export function formatNumber(n: number): string {
|
||||
return new Intl.NumberFormat('fa-IR').format(n);
|
||||
}
|
||||
|
||||
// سال شمسی: رقم فارسی بدون جداکنندهی هزارگان («۱۴۰۴» نه «۱٬۴۰۴»).
|
||||
export function formatYear(year: number): string {
|
||||
return new Intl.NumberFormat('fa-IR', { useGrouping: false }).format(year);
|
||||
}
|
||||
|
||||
// تایمزون رسمی سراسری برنامه = ایران. همهٔ نمایش/تبدیل تاریخ باید با این tz باشد،
|
||||
// مستقل از تایمزون مرورگرِ کاربر (اجباری).
|
||||
export const APP_TZ = 'Asia/Tehran';
|
||||
@@ -122,6 +127,28 @@ export function sanitizeMobileInput(input: string): string {
|
||||
return digitsOnly(input, 11);
|
||||
}
|
||||
|
||||
/**
|
||||
* رشتهی ورودی کاربر (ارقام فارسی/عربی، جداکنندهی هزارگان، فاصله) را به عدد امن تبدیل میکند.
|
||||
* هرگز NaN برنمیگرداند؛ ورودی نامعتبر یا خالی ⇒ null.
|
||||
*/
|
||||
export function parseUserNumber(raw: string | number | null | undefined): number | null {
|
||||
if (raw == null || raw === '') return null;
|
||||
const s = toEnglishDigits(String(raw)).replace(/[,\s٫٬]/g, '');
|
||||
if (!/^-?(\d+\.?\d*|\.\d+)$/.test(s)) return null;
|
||||
const n = Number(s);
|
||||
return Number.isFinite(n) ? n : null;
|
||||
}
|
||||
|
||||
/** همان parseUserNumber با محدودکردن بازه — برای درصد (۰..۱۰۰) و مقادیر غیرمنفی. */
|
||||
export function parseUserNumberClamped(
|
||||
raw: string | number | null | undefined,
|
||||
min: number,
|
||||
max: number,
|
||||
): number | null {
|
||||
const n = parseUserNumber(raw);
|
||||
return n == null ? null : Math.min(max, Math.max(min, n));
|
||||
}
|
||||
|
||||
// z.coerce.number() روی رشتهی فارسی NaN میدهد. فیلدهای عددی پنل در مبدأ (numericField
|
||||
// در lib/forms.ts) نرمال میشوند، پس این wrapper فقط برای مصرفکنندههای خارج از آن مسیر است.
|
||||
// روی resolverهای React Hook Form استفاده نکن — z.preprocess تایپ ورودی را unknown میکند.
|
||||
|
||||
Reference in New Issue
Block a user