const isOvernight = (shift) => shift.end_time <= shift.start_time const nextDay = (dateStr) => { const date = new Date(`${dateStr}T00:00:00`) date.setDate(date.getDate() + 1) return date.toISOString().slice(0, 10) } const extendPastMidnight = (time) => { const [hours, minutes] = time.split(':') return `${parseInt(hours, 10) + 24}:${minutes}` } export function buildShiftEvent(shift, overrides = {}) { const base = { id: String(shift.id), extendedProps: { shift }, ...overrides, } if (shift.date_raw) { const endDate = isOvernight(shift) ? nextDay(shift.date_raw) : shift.date_raw return { ...base, start: `${shift.date_raw}T${shift.start_time}`, end: `${endDate}T${shift.end_time}`, } } return { ...base, daysOfWeek: [shift.day_index], startTime: shift.start_time, endTime: isOvernight(shift) ? extendPastMidnight(shift.end_time) : shift.end_time, } } const WEEKDAY_NAMES = { 6: 'شنبه', 0: 'یکشنبه', 1: 'دوشنبه', 2: 'سه‌شنبه', 3: 'چهارشنبه', 4: 'پنج‌شنبه', 5: 'جمعه', } export function weekdayName(dayIndex) { return WEEKDAY_NAMES[dayIndex] ?? null } export function formatJalaliDay(date) { return new Intl.DateTimeFormat('fa-IR', { day: 'numeric', month: 'short' }).format(date) } export function formatJalaliRange(start, end) { const formatter = new Intl.DateTimeFormat('fa-IR', { day: 'numeric', month: 'long', year: 'numeric' }) const inclusiveEnd = new Date(end.getTime() - 1) return `${formatter.format(start)} تا ${formatter.format(inclusiveEnd)}` }