const persianDigits = '۰۱۲۳۴۵۶۷۸۹' const numberFormatter = new Intl.NumberFormat('fa-IR', { useGrouping: true }) export function normalizeDigits(input: string): string { return input.replace(/[۰-۹]/g, (digit) => String(persianDigits.indexOf(digit))) } export function extractNumericString(input: string): string { return normalizeDigits(input).replace(/[^\d]/g, '') } export function parseFormattedNumber(value: string): number { const numeric = extractNumericString(value) return numeric ? Number(numeric) : 0 } export function formatNumber(value: number): string { if (!Number.isFinite(value)) return '—' return numberFormatter.format(value) } export function formatCurrency(value: number): string { return `${formatNumber(value)} تومان` } export function formatMeterage(value: number): string { return `${formatNumber(value)} متر` } import { parseISODate } from '@/utils/jalali' const persianDateFormatter = new Intl.DateTimeFormat('fa-IR-u-ca-persian', { year: 'numeric', month: '2-digit', day: '2-digit', }) const persianDateTimeFormatter = new Intl.DateTimeFormat('fa-IR-u-ca-persian', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', }) function isJalaliDateString(value: string): boolean { const normalized = normalizeDigits(value.trim()).replace(/-/g, '/') const match = normalized.match(/^(\d{4})\/(\d{1,2})\/(\d{1,2})/) if (!match) return false const year = Number(match[1]) return year >= 1300 && year <= 1500 } function toDateValue(date: string | Date): Date { if (typeof date !== 'string') return date const trimmed = date.trim() // فقط تاریخ بدون ساعت؛ رشتهٔ دارای زمان باید کامل پارس شود if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) return parseISODate(trimmed) const parsed = new Date(trimmed) if (Number.isNaN(parsed.getTime())) return new Date(NaN) return parsed } export function formatDate(date: string | Date | null | undefined): string { if (!date) return '—' if (typeof date === 'string' && isJalaliDateString(date)) { const normalized = normalizeDigits(date.trim()).replace(/-/g, '/') const match = normalized.match(/^(\d{4})\/(\d{1,2})\/(\d{1,2})/) if (!match) return toPersianDigits(normalized) const [, y, m, d] = match return toPersianDigits(`${y}/${m!.padStart(2, '0')}/${d!.padStart(2, '0')}`) } const value = toDateValue(date) if (Number.isNaN(value.getTime())) return '—' return persianDateFormatter.format(value) } export function formatDateTime(date: string | Date | null | undefined): string { if (!date) return '—' if (typeof date === 'string' && isJalaliDateString(date) && !/[T\s]\d/.test(date)) { return formatDate(date) } const value = toDateValue(date) if (Number.isNaN(value.getTime())) return '—' return persianDateTimeFormatter.format(value) } export function formatTime(date: string | Date): string { const d = typeof date === 'string' ? new Date(date) : date if (Number.isNaN(d.getTime())) return '—' return new Intl.DateTimeFormat('fa-IR', { hour: '2-digit', minute: '2-digit', }).format(d) } export function toPersianDigits(input: string): string { return input.replace(/\d/g, (d) => persianDigits[Number(d)]!) } export function normalizePhone(phone: string): string { let digits = extractNumericString(phone) if (digits.startsWith('98')) digits = '0' + digits.slice(2) else if (digits.startsWith('9') && digits.length === 10) digits = '0' + digits return digits.slice(0, 11) } export function generateId(): string { return crypto.randomUUID() } export function generateOrderNumber(): string { const year = new Intl.DateTimeFormat('fa-IR-u-ca-persian', { year: 'numeric' }).format(new Date()) const persianYear = year.replace(/[^\d]/g, '') || '1403' const seq = Math.floor(Math.random() * 9000) + 1000 return `ORD-${persianYear}-${seq}` }