Add Persian date input and refine admin category/check screens.
Introduce shared PersianDateInput with jalali utilities and align categories and check management views with updated form patterns.
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
import { jalaaliMonthLength, toGregorian, toJalaali } from 'jalaali-js'
|
||||
|
||||
const persianDigits = '۰۱۲۳۴۵۶۷۸۹'
|
||||
|
||||
function toPersianDigits(input: string): string {
|
||||
return input.replace(/\d/g, (d) => persianDigits[Number(d)]!)
|
||||
}
|
||||
|
||||
export const JALALI_MONTH_NAMES = [
|
||||
'فروردین',
|
||||
'اردیبهشت',
|
||||
'خرداد',
|
||||
'تیر',
|
||||
'مرداد',
|
||||
'شهریور',
|
||||
'مهر',
|
||||
'آبان',
|
||||
'آذر',
|
||||
'دی',
|
||||
'بهمن',
|
||||
'اسفند',
|
||||
] as const
|
||||
|
||||
export const JALALI_WEEKDAY_NAMES = ['ش', 'ی', 'د', 'س', 'چ', 'پ', 'ج'] as const
|
||||
|
||||
export interface JalaliDate {
|
||||
jy: number
|
||||
jm: number
|
||||
jd: number
|
||||
}
|
||||
|
||||
export function parseISODate(iso: string): Date {
|
||||
const match = iso.trim().match(/^(\d{4})-(\d{2})-(\d{2})/)
|
||||
if (match) {
|
||||
return new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]))
|
||||
}
|
||||
|
||||
const parsed = new Date(iso)
|
||||
if (Number.isNaN(parsed.getTime())) {
|
||||
return new Date(NaN)
|
||||
}
|
||||
|
||||
return new Date(parsed.getFullYear(), parsed.getMonth(), parsed.getDate())
|
||||
}
|
||||
|
||||
export function toISODate(date: Date): string {
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
|
||||
export function toJalali(date: Date): JalaliDate {
|
||||
const { jy, jm, jd } = toJalaali(date.getFullYear(), date.getMonth() + 1, date.getDate())
|
||||
return { jy, jm, jd }
|
||||
}
|
||||
|
||||
export function fromJalali(jy: number, jm: number, jd: number): Date {
|
||||
const { gy, gm, gd } = toGregorian(jy, jm, jd)
|
||||
return new Date(gy, gm - 1, gd)
|
||||
}
|
||||
|
||||
export function isoToJalali(iso: string): JalaliDate | null {
|
||||
if (!iso) return null
|
||||
return toJalali(parseISODate(iso))
|
||||
}
|
||||
|
||||
export function jalaliToISO(jy: number, jm: number, jd: number): string {
|
||||
return toISODate(fromJalali(jy, jm, jd))
|
||||
}
|
||||
|
||||
export function formatJalaliDate(jy: number, jm: number, jd: number): string {
|
||||
const month = String(jm).padStart(2, '0')
|
||||
const day = String(jd).padStart(2, '0')
|
||||
return toPersianDigits(`${jy}/${month}/${day}`)
|
||||
}
|
||||
|
||||
export function formatJalaliLabel(jy: number, jm: number, jd: number): string {
|
||||
return `${toPersianDigits(String(jd))} ${JALALI_MONTH_NAMES[jm - 1]} ${toPersianDigits(String(jy))}`
|
||||
}
|
||||
|
||||
export function getPersianWeekday(jy: number, jm: number, jd: number): number {
|
||||
const { gy, gm, gd } = toGregorian(jy, jm, jd)
|
||||
const jsDay = new Date(gy, gm - 1, gd).getDay()
|
||||
return (jsDay + 1) % 7
|
||||
}
|
||||
|
||||
export function getMonthLength(jy: number, jm: number): number {
|
||||
return jalaaliMonthLength(jy, jm)
|
||||
}
|
||||
|
||||
export function buildCalendarDays(jy: number, jm: number): Array<number | null> {
|
||||
const length = getMonthLength(jy, jm)
|
||||
const startWeekday = getPersianWeekday(jy, jm, 1)
|
||||
const cells: Array<number | null> = Array.from({ length: startWeekday }, () => null)
|
||||
|
||||
for (let day = 1; day <= length; day += 1) {
|
||||
cells.push(day)
|
||||
}
|
||||
|
||||
while (cells.length % 7 !== 0) {
|
||||
cells.push(null)
|
||||
}
|
||||
|
||||
return cells
|
||||
}
|
||||
|
||||
export function todayJalali(): JalaliDate {
|
||||
return toJalali(new Date())
|
||||
}
|
||||
Reference in New Issue
Block a user