feat(appointments): a resource-first view on the timeline
The appointments page only ever showed one doctor's row, but in the resource-first model a single appointment can hold a room and a device at the same time, and that — not the doctor's schedule — is what runs the capacity out. An hour could look free on the doctor's lane while the only alexandrite laser was already taken. A third view, "منابع", draws one lane per resource for the selected day. Blocks come from resource_occupancy rather than the appointment: that range includes the device's setup and cleanup minutes and is the same range the availability engine treats as busy. A multi-segment appointment therefore shows up on every resource it holds, and each block links to the appointment it belongs to. GET /api/v1/resources/timeline keeps a fixed query count — one for occupancy, one for shifts, one for the patient names — instead of one per resource. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,8 @@ import SearchableSelect from '../components/ui/SearchableSelect';
|
||||
import TurnsStatInfo from '../components/appointments/TurnsStatInfo';
|
||||
import TurnsViewToggle from '../components/appointments/TurnsViewToggle';
|
||||
import type { TurnsViewMode } from '../components/appointments/TurnsViewToggle';
|
||||
import ResourceTimeline from '../components/appointments/ResourceTimeline';
|
||||
import { useResourceTimeline } from '../hooks/useResourceTimeline';
|
||||
import DoctorTabs from '../components/appointments/DoctorTabs';
|
||||
import TurnsTimeline from '../components/appointments/TurnsTimeline';
|
||||
import TurnsTable from '../components/appointments/TurnsTable';
|
||||
@@ -616,6 +618,14 @@ export default function AppointmentsPage() {
|
||||
const adminLocation = adminLocations.find(l => locKey(l) === adminLocKey) ?? adminLocations[0] ?? null;
|
||||
const effectiveClinicUuid: string | null = isAdmin ? (adminLocation?.clinic_uuid ?? null) : clinicUuid;
|
||||
|
||||
// نمای منبعمحور فقط وقتی درخواست میفرستد که انتخاب شده باشد؛ در نمای جدولی
|
||||
// یک کوئری اضافه بهازای هر تغییر روز، بیمصرف است.
|
||||
const {
|
||||
day: resourceDay,
|
||||
loading: resourceTimelineLoading,
|
||||
error: resourceTimelineError,
|
||||
} = useResourceTimeline(viewMode === 'resources' ? selectedDate : '');
|
||||
|
||||
// ── Slots query (timeline)
|
||||
// effectiveClinicUuid باید در کلید کش باشد، وگرنه برنامهٔ یک محیط برای محیط دیگر نشان داده میشود.
|
||||
const slotsQueryKey = ['appt-slots', selectedDoctorUuid, selectedDate, effectiveClinicUuid];
|
||||
@@ -831,7 +841,14 @@ export default function AppointmentsPage() {
|
||||
<DoctorTabs doctors={doctors} selected={selectedDoctorUuid} onSelect={setSelectedDoctorUuid} showAll={isAdmin} />
|
||||
)}
|
||||
<div style={{ padding: 16 }}>
|
||||
{viewMode === 'table' ? (
|
||||
{viewMode === 'resources' ? (
|
||||
<ResourceTimeline
|
||||
lanes={resourceDay?.resources ?? []}
|
||||
dayStart={resourceDay?.date ?? 0}
|
||||
loading={resourceTimelineLoading}
|
||||
error={resourceTimelineError}
|
||||
/>
|
||||
) : viewMode === 'table' ? (
|
||||
<>
|
||||
<TurnsTable
|
||||
items={pagedAppointments}
|
||||
|
||||
Reference in New Issue
Block a user