import React, { useState } from 'react'; import { PlusIcon } from '@heroicons/react/24/outline'; import PageHeader from '../components/ui/PageHeader'; import DataTable, { type Column } from '../components/ui/DataTable'; import Modal from '../components/ui/Modal'; import ConfirmDialog from '../components/ui/ConfirmDialog'; import SearchableSelect from '../components/ui/SearchableSelect'; import PersianDateInput from '../components/ui/PersianDateInput'; import { useUrlState } from '../hooks/useUrlState'; import { useNationalHolidays } from '../hooks/useNationalHolidays'; import { formatDate, currentJalaliYear } from '../lib/utils'; import type { NationalHoliday } from '../types'; // eslint-disable-next-line @typescript-eslint/no-var-requires const jalaali = require('jalaali-js') as { toJalaali: (date: Date) => { jy: number; jm: number; jd: number }; }; /** تاریخ میلادیِ `PersianDateInput` → رشتهٔ شمسیِ `1405-01-13` که API می‌خواهد. */ function toJalaliString(gregorian: string): string | null { if (!/^\d{4}-\d{2}-\d{2}$/.test(gregorian)) return null; const [y, m, d] = gregorian.split('-').map(Number); const { jy, jm, jd } = jalaali.toJalaali(new Date(y, m - 1, d)); return `${String(jy).padStart(4, '0')}-${String(jm).padStart(2, '0')}-${String(jd).padStart(2, '0')}`; } const fa = (n: number) => n.toLocaleString('fa-IR', { useGrouping: false }); /** * تقویم تعطیلات رسمی کشور — فقط مدیر سیستم. * * تعطیل رسمی به هیچ کلینیکی تعلق ندارد: یک بار اینجا ثبت می‌شود و همهٔ محیط‌ها، هر * پزشک و هر منبع، از همان ارث می‌برند. کلینیکی که آن روز باز است در تنظیمات خودش * استثنا می‌زند و به این تقویم دست نمی‌زند. */ export default function NationalHolidaysPage() { const thisYear = currentJalaliYear(); const [urlState, setUrlState] = useUrlState({ year: String(thisYear), search: '' }); const year = Number(urlState.year) || thisYear; const { holidays, loading, create, update, remove } = useNationalHolidays(year); const [editing, setEditing] = useState<{ open: boolean; holiday: NationalHoliday | null }>({ open: false, holiday: null }); const [toDelete, setToDelete] = useState(null); const query = urlState.search.trim(); const rows = query === '' ? holidays : holidays.filter((h) => h.title.includes(query)); // سه سال عقب و جلو کافی است؛ تقویم رسمی آن‌قدر جلوتر منتشر نمی‌شود. const years = Array.from({ length: 7 }, (_, i) => thisYear - 3 + i); const columns: Column[] = [ { key: 'jalali_date', header: 'تاریخ', render: (h) => {formatDate(h.date)} }, { key: 'title', header: 'مناسبت', render: (h) => {h.title} }, ]; return (
setEditing({ open: true, holiday: null })}> افزودن تعطیلی } /> columns={columns} data={rows} loading={loading} searchValue={urlState.search} onSearchChange={(v) => setUrlState({ search: v })} searchPlaceholder="جستجو در مناسبت‌ها..." emptyMessage={`برای سال ${fa(year)} تعطیلی رسمی ثبت نشده است`} headerExtra={
({ value: String(y), label: `سال ${fa(y)}` }))} value={String(year)} onChange={(v) => setUrlState({ year: v ? String(v) : String(thisYear) })} placeholder="سال" height={36} />
} actions={(h) => (
)} /> setEditing({ open: false, holiday: null })} onSave={(payload) => { const done = { onSuccess: () => setEditing({ open: false, holiday: null }) }; if (editing.holiday) { update.mutate({ uuid: editing.holiday.uuid, title: payload.title }, done); } else if (payload.jalali_date) { create.mutate({ jalali_date: payload.jalali_date, title: payload.title }, done); } }} /> toDelete && remove.mutate(toDelete.uuid, { onSuccess: () => setToDelete(null) })} onCancel={() => setToDelete(null)} />
); } function HolidayFormModal({ open, holiday, saving, onClose, onSave }: { open: boolean; holiday: NationalHoliday | null; saving: boolean; onClose: () => void; onSave: (payload: { jalali_date: string | null; title: string }) => void; }) { const [date, setDate] = useState(''); const [title, setTitle] = useState(''); React.useEffect(() => { if (!open) return; setDate(''); setTitle(holiday?.title ?? ''); }, [open, holiday]); const jalaliDate = holiday ? holiday.jalali_date : toJalaliString(date); const invalid = title.trim() === '' || (!holiday && jalaliDate === null); return (
{holiday ? ( // تاریخ کلید یکتاست؛ جابه‌جا کردنش یعنی یک تعطیلِ دیگر، پس فقط عنوان ویرایش می‌شود.
تاریخ {formatDate(holiday.date)} تاریخ تغییر نمی‌کند؛ برای جابه‌جایی، این را حذف و روز درست را ثبت کنید.
) : (
تاریخ {jalaliDate && ( ثبت می‌شود: {jalaliDate} )}
)}
setTitle(e.target.value)} placeholder="مثلاً: سیزده‌بدر" />
); }