import { useEffect, useRef } from 'react';
import { UserIcon, PhoneIcon, DocumentTextIcon, PlusIcon } from '@heroicons/react/24/outline';
import type { Appointment } from '../../types';
import AppointmentStatusDropdown from '../ui/AppointmentStatusDropdown';
import AppointmentActionsMenu from '../AppointmentActions';
import { turnStatusConfig, EMPTY_SLOT_CONFIG } from './turnStatus';
import type { TimelineSlot } from './types';
/**
* نمای زمانبندی (زمانبندی) — بازسازیِ `Timeline.jsx` طرح tauri:
* هر ردیف: «ریل مارکر» بیرونی (نقطهٔ رنگی + ساعت شروع + خطچین) سمت راست + «کارت
* نوبت» چپِ آن. داخل کارت: مارکر زمانِ داخلی (نقطهٔ حلقهای شروع/پایان)، اطلاعات
* بیمار (نام/تلفن/سرویس) و در سمت چپ وضعیت + عملیات. اسلات خالی → «افزودن نوبت».
* ردیفها با max-width وسطچین میشوند. رنگها عیناً از طرح مبدأ.
*/
const ROW_MAX = 760;
// نقطهٔ حلقهای (حلقهٔ بیرونی + نقطهٔ داخلی) — مثل TimelineElement طرح tauri.
function RingDot({ color }: { color: string }) {
return (
);
}
// مارکر زمانِ داخلِ کارت (ساعت شروع بالا، ساعت پایان پایین + خطچین بین آنها).
function InnerTimes({ start, end, color }: { start: string; end: string; color: string }) {
return (
);
}
// ریل مارکر بیرونی (سمت راستِ ردیف): نقطهٔ رنگی + ساعت + خطچین عمودی.
function OuterMarker({ color, time, showLine }: { color: string; time: string; showLine: boolean }) {
return (
);
}
function EmptyCard({ slot, onBook }: { slot: TimelineSlot; onBook: (s: TimelineSlot) => void }) {
const cfg = EMPTY_SLOT_CONFIG;
const isPast = slot.start < Math.floor(Date.now() / 1000);
return (
!isPast && onBook(slot)}
style={{
background: isPast ? 'var(--surface-2)' : cfg.bgColor,
border: `1px dashed ${isPast ? 'var(--border-2)' : cfg.borderColor}`,
borderRadius: 8, padding: '12px 14px', display: 'flex', alignItems: 'center', gap: 14,
cursor: isPast ? 'not-allowed' : 'pointer', opacity: isPast ? 0.7 : 1, minHeight: 76,
}}
>
{isPast ? 'گذشته' : 'افزودن نوبت'}
{!isPast &&
}
{/* برچسب «نوبت جدید» سمت چپ (مطابق طرح) */}
{!isPast && (
نوبت جدید
)}
);
}
function OccupiedCard({
appointment: a, queryKey, onView,
}: {
appointment: Appointment; queryKey: unknown[]; onView: (a: Appointment) => void;
}) {
const cfg = turnStatusConfig(a.status);
return (
onView(a)}
style={{
background: cfg.bgColor, border: `1px solid ${cfg.borderColor}`, borderRadius: 8,
padding: '12px 14px', display: 'flex', alignItems: 'center', gap: 14, cursor: 'pointer', minHeight: 88,
}}
>
{/* اطلاعات بیمار */}
{a.patient_name || '—'}
سرویس: {a.service_item?.name || '—'}
{/* وضعیت + عملیات (کلیک روی این ناحیه نباید کارت را باز کند) */}
e.stopPropagation()} style={{ display: 'flex', alignItems: 'center', gap: 8, alignSelf: 'flex-start', flexShrink: 0 }}>
);
}
export default function TurnsTimeline({
slots, loading, queryKey, onView, onBook,
}: {
slots: TimelineSlot[];
loading: boolean;
queryKey: unknown[];
onView: (a: Appointment) => void;
onBook: (s: TimelineSlot) => void;
}) {
const activeRef = useRef(null);
const now = Math.floor(Date.now() / 1000);
const activeIndex = slots.findIndex(s => s.appointment && s.end >= now);
useEffect(() => {
if (!activeRef.current) return;
const el = activeRef.current;
const top = el.getBoundingClientRect().top + window.scrollY - window.innerHeight * 0.4;
window.scrollTo({ top: Math.max(0, top), behavior: 'smooth' });
}, [activeIndex]);
if (loading) return در حال بارگذاری...
;
if (!slots.length) return (
این روز تعطیل است
هیچ برنامه زمانبندی برای این روز تنظیم نشده است
);
return (
{slots.map((slot, i) => {
const color = slot.appointment ? turnStatusConfig(slot.appointment.status).dotColor : EMPTY_SLOT_CONFIG.dotColor;
return (
);
})}
);
}