Files
clinicpro/assets/admin/hooks/useResourceTimeline.ts
T
hamedandClaude Opus 5 444ebc897a 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>
2026-08-02 14:14:10 +03:30

54 lines
1.7 KiB
TypeScript

import { useQuery } from '@tanstack/react-query';
import { api, type ApiResponse } from '../lib/api';
export type ResourceTimelineItem = {
uuid: string;
starts_at: number;
ends_at: number;
status: 'booked' | 'hold';
segment_name: string | null;
appointment_id: number | null;
patient_name: string | null;
appointment_uuid: string | null;
appointment_status: string | null;
};
export type ResourceTimelineLane = {
uuid: string;
name: string;
type_name: string;
address_name: string | null;
capacity: number;
shifts: { start_minute: number; end_minute: number }[];
items: ResourceTimelineItem[];
};
export type ResourceTimelineDay = {
date: number;
day_of_week: number;
resources: ResourceTimelineLane[];
};
/**
* «کدام منبع در این روز کِی گرفته است» — ورودی نمای منبع‌محورِ صفحهٔ نوبت‌ها.
*
* بازه‌ها از جدول اشغال می‌آیند نه از خودِ نوبت: آماده‌سازی و تمیزکاری دستگاه هم
* درونشان است و همان بازه‌ای است که موتور جستجو اشغال می‌بیند.
*/
export function useResourceTimeline(date: string, addressUuid?: string) {
const params = new URLSearchParams({ date });
if (addressUuid) params.set('address_uuid', addressUuid);
const query = useQuery({
queryKey: ['resource-timeline', date, addressUuid ?? null],
queryFn: () => api.get<ApiResponse<ResourceTimelineDay>>(`/api/v1/resources/timeline?${params}`),
enabled: !!date,
});
return {
day: query.data?.data,
loading: query.isLoading,
error: query.isError ? ((query.error as Error)?.message || 'خطای نامشخص') : null,
};
}