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 PersianDateInput from '../components/ui/PersianDateInput'; import { useUrlState } from '../hooks/useUrlState'; import { usePermissions } from '../hooks/usePermissions'; import { useHolidays } from '../hooks/useResourceCalendar'; import { formatDate, currentJalaliYear } from '../lib/utils'; import type { NationalHoliday } from '../types'; import SettingsLayout from '../components/layout/SettingsLayout'; /** سال بدون جداکنندهٔ هزارگان — `formatNumber` «۱٬۴۰۵» می‌داد. */ const faYear = (y: number) => y.toLocaleString('fa-IR', { useGrouping: false }); /** * تعطیلات رسمی و استثناهای این محیط. * * خودِ تعطیلات کشوری‌اند و اینجا فقط دیده می‌شوند؛ آنچه محیط تغییر می‌دهد «باز بودن * یا نبودنِ» همان روز برای خودش است. ساخت و حذفِ خودِ تعطیلی کارِ مدیر سیستم است * (`/admin/national-holidays`). */ export default function HolidaysSettingsPage() { const thisYear = currentJalaliYear(); const [urlState, setUrlState] = useUrlState({ year: String(thisYear) }); const year = Number(urlState.year) || thisYear; const { holidays, overrides, loading, error, 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[] = [ // یک ستون تاریخ، نه دو تا: پیش‌تر «تاریخ» رشتهٔ خامِ `1405-05-13` بود و ستونِ // «میلادی» با formatDate همان روز را **شمسی** نشان می‌داد — یک تاریخ، دو بار، // با برچسبی که دروغ می‌گفت. { key: 'date', header: 'تاریخ', render: (h) => {formatDate(h.date)} }, { key: 'title', header: 'مناسبت', render: (h) => {h.title} }, { key: 'status', header: 'وضعیت این محیط', render: (h) => overrideByDate.get(h.date)?.is_working ? ( باز است ) : ( تعطیل ), }, ]; const years = Array.from({ length: 5 }, (_, i) => thisYear - 1 + i); return (
{error && (
{error}
)}
({ value: String(y), label: faYear(y) }))} value={String(year)} onChange={(v) => setUrlState({ year: v ? String(v) : String(thisYear) })} placeholder="سال" ariaLabelledBy="holidays-year-label" 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)}{o.note ? ` · ${o.note}` : ''} {canUpdate && ( )}
))}
)} {canUpdate && (
{/* تقویم شمسی، نه `input type=date`: آن میلادی است، placeholderش انگلیسی (`mm/dd/yyyy`) و در دارک‌مود سفید می‌ماند چون کنترل نیتیو تم را نمی‌شناسد. */}
تاریخ
setNote(e.target.value)} placeholder="اختیاری" />
)}
); }