101 lines
3.6 KiB
TypeScript
101 lines
3.6 KiB
TypeScript
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)} متر`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function toPersianDigits(input: string | number): string {
|
|||
|
|
return String(input).replace(/\d/g, (d) => persianDigits[Number(d)]!)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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',
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
/** Detect already-Jalali date strings like 1403/07/30 or 1403-07-30 */
|
|||
|
|
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()
|
|||
|
|
// فقط تاریخِ بدون ساعت (YYYY-MM-DD) را بهصورت تقویم محلی بخوان تا شیفت UTC روز را جابهجا نکند.
|
|||
|
|
// رشتههای دارای ساعت (…T10:30:00 یا … 10:30) باید کامل پارس شوند.
|
|||
|
|
const dateOnly = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})$/)
|
|||
|
|
if (dateOnly && Number(dateOnly[1]) >= 1700) {
|
|||
|
|
return new Date(Number(dateOnly[1]), Number(dateOnly[2]) - 1, Number(dateOnly[3]))
|
|||
|
|
}
|
|||
|
|
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 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}`
|
|||
|
|
}
|