import React, { useState } from 'react'; import { useParams } from 'react-router'; import { PencilIcon } from '@heroicons/react/24/outline'; import PageHeader from '../components/ui/PageHeader'; import ConfirmDialog from '../components/ui/ConfirmDialog'; import { ActiveBadge } from '../components/ui/StatusBadge'; import ResourceFormModal from '../components/resources/ResourceFormModal'; import ResourceWorkingHoursPanel from '../components/resources/ResourceWorkingHoursPanel'; import ResourceExceptionsPanel from '../components/resources/ResourceExceptionsPanel'; import ResourceServicesPanel from '../components/resources/ResourceServicesPanel'; import ResourceSkillsPanel from '../components/resources/ResourceSkillsPanel'; import ResourceBlocksPanel from '../components/resources/ResourceBlocksPanel'; import { useUrlState } from '../hooks/useUrlState'; import { usePermissions } from '../hooks/usePermissions'; import { useResourceDetail, useResourceServices, useResources, useResourceTypes, useSkills } from '../hooks/useResources'; import { useAllServiceItems } from '../hooks/useServiceCatalog'; import type { ClinicResource } from '../types'; const TABS = [ { id: 'info', label: 'اطلاعات' }, { id: 'hours', label: 'ساعات کاری' }, { id: 'exceptions', label: 'تعطیلات و استثنا' }, { id: 'services', label: 'سرویس‌ها' }, { id: 'skills', label: 'مهارت‌ها' }, { id: 'blocks', label: 'غیرفعال‌سازی موقت' }, ] as const; type TabId = typeof TABS[number]['id']; const SUBJECT_LABEL: Record = { doctor: 'پزشک', staff: 'پرسنل', room: 'اتاق', }; /** * یک منبع و همهٔ تنظیمات مستقلش، در یک صفحهٔ تب‌بندی‌شده — همان ساختار صفحهٔ * «مدیریت نوبت‌دهی» کلینیک. * * منبع در مدل Resource-First واحدِ ظرفیت است، پس ساعت کاری و تعطیلات را خودش دارد نه * فقط پزشکِ پشتش؛ تقویم منبع درون برنامهٔ هفتگی تنگ‌تر می‌شود، آن را گشاد نمی‌کند. */ export default function ResourceDetailPage() { const { resourceUuid } = useParams<{ resourceUuid: string }>(); const [urlState, setUrlState] = useUrlState({ tab: 'info' }); const tab = (TABS.some((t) => t.id === urlState.tab) ? urlState.tab : 'info') as TabId; const { resource, loading } = useResourceDetail(resourceUuid); const { types } = useResourceTypes(); const { skills } = useSkills(); const { update, setSkills } = useResources(); const { offerings, save: saveServices } = useResourceServices(resourceUuid); const { items: serviceOptions } = useAllServiceItems(); const { can } = usePermissions(); const canUpdate = can('resources', 'update'); const [editOpen, setEditOpen] = useState(false); const [confirmDeactivate, setConfirmDeactivate] = useState(false); // حالت‌های بارگذاری و نبودِ منبع هم داخل پوستهٔ تنظیمات می‌مانند، وگرنه منوی کناری // یک لحظه می‌پرد و دوباره برمی‌گردد. if (loading || !resource) { return (
{loading ? 'در حال بارگذاری...' : 'منبع یافت نشد.'}
); } return (
setEditOpen(true)}> ویرایش ) : undefined } />
{TABS.map((t) => ( ))}
{tab === 'info' && ( { if (resource.active) setConfirmDeactivate(true); else update.mutate({ uuid: resource.uuid, d: { active: true } }); }} /> )} {tab === 'hours' && } {tab === 'exceptions' && } {tab === 'services' && (
saveServices.mutate({ uuid: resource.uuid, services: lines })} />
)} {tab === 'skills' && (
setSkills.mutate({ uuid: resource.uuid, skills: lines })} />
)} {tab === 'blocks' && } update.mutate( { uuid: resource.uuid, d: { active: false } }, { onSuccess: () => setConfirmDeactivate(false) }, ) } onCancel={() => setConfirmDeactivate(false)} /> setEditOpen(false)} onSave={(payload) => update.mutate({ uuid: resource.uuid, d: payload }, { onSuccess: () => setEditOpen(false) }) } />
); } function Row({ label, children }: { label: string; children: React.ReactNode }) { return (
{label} {children}
); } /** * اطلاعات منبع + وضعیت فعال/غیرفعالش. * * حذفِ منبع عمداً در رابط کاربری نیست: منبع به نوبت‌های ثبت‌شده گره خورده و راهِ * درستِ «دیگر لازمش ندارم» غیرفعال کردن است، نه پاک کردن. */ function InfoTab({ resource, canUpdate, toggling, onToggleActive }: { resource: ClinicResource; canUpdate: boolean; toggling: boolean; onToggleActive: () => void; }) { const attributes = Object.entries(resource.attributes ?? {}); return (
{resource.type_name} {resource.capacity} نفر {resource.setup_minutes} / {resource.cleanup_minutes} دقیقه {resource.skills.length === 0 ? '—' : ( {resource.skills.map((s) => ( {s.skill_name} · {s.level} ))} )} {attributes.map(([key, value]) => ( {String(value)} ))}
{canUpdate && (

وضعیت منبع

منبع غیرفعال در نوبت‌دهی پیشنهاد نمی‌شود. برای بستن فقط یک بازهٔ مشخص، از تب «غیرفعال‌سازی موقت» استفاده کنید.

{resource.active ? 'این منبع فعال است' : 'این منبع غیرفعال است'}
{resource.active ? 'در جستجوی وقت و رزرو نوبت در دسترس است.' : 'در جستجوی وقت و رزرو نوبت ظاهر نمی‌شود.'}
)}
); }