import React from 'react'; import PageHeader from '../components/ui/PageHeader'; import DataTable, { type Column } from '../components/ui/DataTable'; import SearchableSelect from '../components/ui/SearchableSelect'; import { useUrlState } from '../hooks/useUrlState'; import { usePermissions } from '../hooks/usePermissions'; import { useHolidays } from '../hooks/useResourceCalendar'; import { formatDate } from '../lib/utils'; import type { NationalHoliday } from '../types'; /** سالِ شمسی جاری از همان فرمت‌کنندهٔ شمسیِ مرورگر گرفته می‌شود، نه با محاسبهٔ دستی. */ function currentJalaliYear(): number { const formatted = new Intl.DateTimeFormat('en-u-ca-persian', { year: 'numeric' }).format(new Date()); return Number(formatted.replace(/\D/g, '')) || 1405; } /** * تعطیلات رسمی و استثناهای این محیط. * * خودِ تعطیلات کشوری‌اند و اینجا فقط دیده می‌شوند؛ آنچه محیط تغییر می‌دهد «باز بودن * یا نبودنِ» همان روز برای خودش است. */ export default function HolidaysSettingsPage() { const thisYear = currentJalaliYear(); const [urlState, setUrlState] = useUrlState({ year: String(thisYear) }); const year = Number(urlState.year) || thisYear; const { holidays, overrides, loading, setOverride, removeOverride } = useHolidays(year); const { can } = usePermissions(); const canUpdate = can('appointment_settings', 'update'); const overrideByDate = new Map(overrides.map((o) => [o.date, o])); const columns: Column[] = [ { key: 'jalali_date', header: 'تاریخ', render: (h) => {h.jalali_date} }, { key: 'title', header: 'مناسبت', render: (h) => {h.title} }, { key: 'gregorian', header: 'میلادی', render: (h) => {formatDate(h.date * 1000)}, }, { key: 'status', header: 'وضعیت این محیط', render: (h) => overrideByDate.get(h.date)?.is_working ? ( باز است ) : ( تعطیل ), }, ]; const years = Array.from({ length: 5 }, (_, i) => thisYear - 1 + i); return (
({ value: String(y), label: String(y) }))} value={String(year)} onChange={(v) => setUrlState({ year: v ? String(v) : String(thisYear) })} placeholder="سال" height={36} />
} actions={ canUpdate ? (h) => { const override = overrideByDate.get(h.date); return (
{override?.is_working ? ( ) : ( )}
); } : undefined } /> !o.is_working)} canUpdate={canUpdate} saving={setOverride.isPending} onAdd={(date, note) => setOverride.mutate({ date, is_working: false, note })} onRemove={(uuid) => removeOverride.mutate(uuid)} /> ); } /** * جهت دوم: روزی که تعطیل رسمی نیست ولی این محیط بسته است. * این با «استثنای منبع» فرق دارد — آن روی یک منبع است و این روی کل محیط. */ function ClosureCard({ overrides, canUpdate, saving, onAdd, onRemove, }: { overrides: { uuid: string; date: number; note: string | null }[]; canUpdate: boolean; saving: boolean; onAdd: (date: number, note: string | null) => void; onRemove: (uuid: string) => void; }) { const [date, setDate] = React.useState(''); const [note, setNote] = React.useState(''); const timestamp = date === '' ? null : Math.floor(new Date(`${date}T00:00:00`).getTime() / 1000); return (

تعطیلی‌های این محیط

روزهایی که تعطیل رسمی نیستند ولی این محیط بسته است. برای مرخصی یک نفر یا سرویس یک دستگاه، از تقویم همان منبع استفاده کنید.

{overrides.length === 0 ? (

موردی ثبت نشده است.

) : (
{overrides.map((o) => (
{formatDate(o.date * 1000)}{o.note ? ` · ${o.note}` : ''} {canUpdate && ( )}
))}
)} {canUpdate && (
setDate(e.target.value)} style={{ minWidth: 170 }} /> setNote(e.target.value)} placeholder="توضیح (اختیاری)" style={{ flex: 1, minWidth: 180 }} />
)}
); }