import { formatDate, formatNumber } from '../lib/utils'; import BackButton from './ui/BackButton'; import { ArrowLeftD, FilesServicePhone, FilesServiceCalendar, FilesServiceNotification, FilesServiceMessage, } from './icons/FilesServiceIcons'; interface Tag { uuid: string; name: string; color: string } /** پرونده > {name} breadcrumb, ported from tauri BreadcrumbHeader. */ export function Breadcrumb({ name, backTo }: { name: string; backTo: string }) { return (
پرونده {name}
); } function TagDots({ tags }: { tags?: Tag[] }) { if (!tags || tags.length === 0) return ; return ( {tags.slice(0, 4).map((t, i) => ( ))} ); } const InfoLine = ({ icon, label, value }: { icon: React.ReactNode; label: string; value: string }) => (
{icon} {label} {value}
); /** * The patient case-file banner — ported pixel-for-pixel from tauri * FileServicesHeader (name + status chip, file number, tags, contact/date, * next appointment, یادداشت button). */ export default function PatientCaseBanner({ name, recordNumber, mobile, createdAt, tags, nextAppointment, nextSession, hasDebt, noShows, onAddNote }: { name: string; recordNumber?: string | null; mobile?: string | null; createdAt?: number; tags?: Tag[]; nextAppointment?: number | null; /** * جلسهٔ بعدیِ دوره وقتی نوبتی رزرو نشده. * * جدا از `nextAppointment` است و باید هم باشد: این هنوز نوبت نیست، برنامه است. * یکی کردنشان یعنی بنر چیزی را «نوبت» بنامد که کسی رزروش نکرده. */ nextSession?: number | null; hasDebt?: boolean; /** خلاصهٔ عدم حضور در پنجرهٔ سیاست — `null` یعنی هنوز نیامده. */ noShows?: { count: number; threshold: number; window_days: number; at_risk: boolean } | null; onAddNote: () => void; }) { const complete = !hasDebt; return (
{/* right — name + tags */}
{name} {complete ? 'تکمیل شده' : 'تکمیل نشده'}
شماره پرونده: {recordNumber || '—'}
برچسب ها:
{/* شمار عدم حضور فقط وقتی می‌آید که واقعاً اتفاقی افتاده باشد. «۰ غیبت» روی پروندهٔ هر بیمار سالم، اتهام بی‌جاست. عبور از آستانه فقط رنگش را عوض می‌کند — مسدودسازی کارِ قانون `eligibility` است، نه این نشان. */} {noShows && noShows.count > 0 && ( {formatNumber(noShows.count)} بار عدم حضور {noShows.at_risk && ' — پرریسک'} )}
{/* middle — contact + file date */}
} label="شماره تماس:" value={mobile || '—'} /> } label="تاریخ تشکیل پرونده:" value={createdAt ? formatDate(createdAt) : '—'} />
{/* left — next appointment + note */}
} label={nextAppointment || !nextSession ? 'نوبت بعدی:' : 'جلسهٔ بعدی:'} value={ nextAppointment ? formatDate(nextAppointment) : nextSession ? formatDate(nextSession) : '—' } />
); }