import { z } from 'zod'; // واحد ذخیره/API ریال است؛ نمایش تومان (÷۱۰) و ورودی ×۱۰. export const RIAL_PER_TOMAN = 10; export const rialToToman = (rial: number): number => Math.round((Number(rial) || 0) / RIAL_PER_TOMAN); export const tomanToRial = (toman: number): number => Math.round((Number(toman) || 0) * RIAL_PER_TOMAN); // ورودی مقدار ریال است (سازگاری با همهٔ فراخوانی‌ها) ولی خروجی به تومان نمایش داده می‌شود. export function formatRial(rial: number): string { return new Intl.NumberFormat('fa-IR').format(rialToToman(rial)) + ' تومان'; } export function formatNumber(n: number): string { return new Intl.NumberFormat('fa-IR').format(n); } export function toDate(val: string | number | null | undefined): Date | null { if (val == null || val === '') return null; if (typeof val === 'number') return new Date(val * 1000); // Y-m-d → treat as local noon to avoid UTC-off-by-one if (/^\d{4}-\d{2}-\d{2}$/.test(val)) return new Date(`${val}T12:00:00`); return new Date(val); } export function formatDate(val: string | number | null | undefined): string { const d = toDate(val); if (!d || isNaN(d.getTime())) return '—'; return new Intl.DateTimeFormat('fa-IR-u-ca-persian', { year: 'numeric', month: '2-digit', day: '2-digit', }).format(d); } export function formatDateTime(val: string | number | null | undefined): string { const d = toDate(val); if (!d || isNaN(d.getTime())) return '—'; return new Intl.DateTimeFormat('fa-IR-u-ca-persian', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', }).format(d); } export function toGregorianDate(d: Date): string { const y = d.getFullYear(); const m = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); return `${y}-${m}-${day}`; } // API stores contract dates as Unix seconds; the date input speaks Y-m-d strings. export function isoToUnix(iso: string): number | null { const d = toDate(iso); return d && !isNaN(d.getTime()) ? Math.floor(d.getTime() / 1000) : null; } export function unixToIso(ts: number | null | undefined): string { if (ts == null) return ''; return toGregorianDate(new Date(ts * 1000)); } export function maskMobile(mobile: string): string { if (mobile.length < 7) return mobile; return mobile.slice(0, 4) + '***' + mobile.slice(-3); } export function cn(...classes: (string | undefined | null | false)[]): string { return classes.filter(Boolean).join(' '); } // تبدیل ارقام فارسی/عربی به انگلیسی + حذف هر کاراکتر غیرعددی. export function toEnglishDigits(input: string): string { if (!input) return ''; return input .replace(/[۰-۹]/g, (d) => String(d.charCodeAt(0) - 0x06f0)) .replace(/[٠-٩]/g, (d) => String(d.charCodeAt(0) - 0x0660)); } // فقط ارقام انگلیسی، حداکثر ۱۱ رقم (برای فیلد موبایل). export function sanitizeMobileInput(input: string): string { return toEnglishDigits(input).replace(/\D/g, '').slice(0, 11); } // regex شماره موبایل ایران export const IRAN_MOBILE_RE = /^09\d{9}$/; export function isValidIranMobile(input: string): boolean { return IRAN_MOBILE_RE.test(toEnglishDigits(input || '')); } // schema قابل‌استفاده‌ی مشترک برای شماره موبایل ایران (ارقام فارسی/عربی را هم می‌پذیرد و نرمال می‌کند). export const iranMobileSchema = z .string() .transform((v) => toEnglishDigits(v).replace(/\D/g, '')) .refine((v) => IRAN_MOBILE_RE.test(v), 'شماره موبایل باید ۱۱ رقم و با 09 شروع شود'); // نسخه‌ی اختیاری (خالی یا معتبر) برای فیلدهای غیرالزامی. export const iranMobileOptionalSchema = z .string() .transform((v) => toEnglishDigits(v).replace(/\D/g, '')) .refine((v) => v === '' || IRAN_MOBILE_RE.test(v), 'شماره موبایل نامعتبر است');