import React, { useMemo } from 'react'; import { TrashIcon } from '@heroicons/react/24/outline'; import PageHeader from '../components/ui/PageHeader'; import DataTable, { type Column } from '../components/ui/DataTable'; import SearchableSelect from '../components/ui/SearchableSelect'; import { formatDate } from '../lib/utils'; import { useUrlState } from '../hooks/useUrlState'; import { usePermissions } from '../hooks/usePermissions'; import { useWaitlist } from '../hooks/useCancellation'; import type { WaitlistEntry } from '../types'; /** * مرزهای ساعتش در بک‌اند است (`WaitlistEntry::DAY_PARTS`)؛ اینجا فقط ترجمهٔ نمایش. * تعریف مرز در دو جا یعنی روزی که یکی عوض شود، بیمار برای ساعتی خبر شود که رد کرده بود. */ const DAY_PART_LABELS: Record = { morning: 'صبح', afternoon: 'بعدازظهر', evening: 'عصر', }; const STATUS: Record = { waiting: { label: 'در انتظار', className: 'badge' }, notified: { label: 'خبر داده شد', className: 'badge amber' }, converted: { label: 'رزرو شد', className: 'badge green' }, expired: { label: 'منقضی', className: 'badge red' }, }; /** * لیست انتظار. * * ستون «تعداد اطلاع» عمداً دیده می‌شود: وقتی ظرفیتی آزاد می‌شود همه خبر می‌گیرند و * اولین رزروکننده می‌برد، پس اپراتور باید بداند چه کسی چند بار خبر شده. */ export default function WaitlistPage() { const [urlState, setUrlState] = useUrlState({ search: '', status: '' }); const { entries, loading, remove } = useWaitlist(urlState.status || undefined); const { can } = usePermissions(); const canManage = can('appointment_settings', 'update'); const rows = useMemo(() => { const q = urlState.search.trim(); return entries.filter((e) => q === '' || e.service_name.includes(q)); }, [entries, urlState.search]); const columns: Column[] = [ { key: 'service_name', header: 'خدمت', render: (e) => {e.service_name}, }, { key: 'window', header: 'بازهٔ دلخواه', render: (e) => ( {formatDate(e.desired_from)} تا {formatDate(e.desired_to)} ), }, { key: 'preferred_day_parts', header: 'زمان ترجیحی', render: (e) => ( {e.preferred_day_parts.length === 0 ? 'بی‌تفاوت' : e.preferred_day_parts.map((p) => DAY_PART_LABELS[p] ?? p).join('، ')} ), }, { key: 'notify_count', header: 'تعداد اطلاع', render: (e) => ( {e.notify_count} {e.notified_at !== null && ( · {formatDate(e.notified_at)} )} ), }, { key: 'status', header: 'وضعیت', render: (e) => ( {STATUS[e.status].label} ), }, ]; return (
setUrlState({ search: v })} searchPlaceholder="جستجو در خدمات..." emptyMessage="کسی در لیست انتظار نیست" headerExtra={
setUrlState({ status: String(v ?? '') })} options={[ { value: '', label: 'همهٔ وضعیت‌ها' }, ...Object.entries(STATUS).map(([value, meta]) => ({ value, label: meta.label })), ]} placeholder="وضعیت" />
} actions={(e) => canManage ? ( ) : null } />
); }