"use client"; import type { ReactNode } from "react"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Separator } from "@/components/ui/separator"; import { Skeleton } from "@/components/ui/skeleton"; import { Sparkline } from "@/components/chat/sparkline"; import { cn } from "@/lib/utils"; import type { AllergySeverity, LabFlag, Patient, Trend } from "@/lib/patients"; type BadgeVariant = "default" | "secondary" | "destructive" | "outline"; type PatientResultProps = { status: "loading" | "ready" | "not-found"; fileNumber: string; patient?: Patient; }; const severityVariant: Record = { mild: "outline", moderate: "secondary", severe: "destructive", }; const labFlagVariant: Record = { normal: "outline", low: "secondary", high: "secondary", critical: "destructive", }; const statusVariant: Record = { active: "secondary", inpatient: "destructive", discharged: "outline", }; const sexLabel: Record = { F: "Female", M: "Male" }; // Fixed width so the cards sit in a horizontal scroll row instead of squashing, // plus a subtle clickable affordance (they open a detail dialog). const rowCard = "w-80 shrink-0 cursor-pointer text-left outline-none transition hover:ring-foreground/20 focus-visible:ring-2 focus-visible:ring-ring"; function SectionLabel({ children }: { children: ReactNode }) { return (

{children}

); } function Stat({ label, value }: { label: string; value: ReactNode }) { return (
{label} {value}
); } function Row({ label, value }: { label: ReactNode; value: ReactNode }) { return (
{label} {value}
); } function Empty({ children }: { children: ReactNode }) { return

{children}

; } function TrendBlock({ trend }: { trend: Trend }) { if (trend.points.length === 0) { return No trend data yet.; } return (
{`${trend.label} · last ${trend.points.length}`} {trend.points.at(-1)} {trend.unit}
); } function TrendDetail({ trend }: { trend: Trend }) { if (trend.points.length === 0) { return No trend data yet.; } const min = Math.min(...trend.points); const max = Math.max(...trend.points); return (
{`${trend.label} · last ${trend.points.length} readings`}
Latest{" "} {trend.points.at(-1)} {trend.unit} Min {min} Max {max}
); } function AlertBadges({ alerts }: { alerts: string[] }) { if (alerts.length === 0) { return null; } return (
{alerts.map((alert) => ( {alert} ))}
); } // A card that previews `children` and opens a roomier dialog of `detail` on click. function ExpandableCard({ title, description, detail, children, }: { title: ReactNode; description?: ReactNode; detail: ReactNode; children: ReactNode; }) { return ( } > {children} {title} {description ? {description} : null} {detail} ); } function SummaryCard({ patient }: { patient: Patient }) { const idLine = `${patient.age} · ${sexLabel[patient.sex]} · MRN ${patient.fileNumber}`; return (
{patient.status}} />
} title={patient.name} >
{patient.initials}
{patient.name} {idLine}
{patient.status}
); } function VitalsCard({ patient }: { patient: Patient }) { const { vitals } = patient; const vitalItems = [ { label: "BP", value: vitals.bp }, { label: "HR", value: vitals.hr }, { label: "Temp", value: vitals.temp }, { label: "SpO₂", value: vitals.spo2 }, ]; const vitalsGrid = (gapY: string) => (
{vitalItems.map((item) => ( ))}
); return ( {vitalsGrid("gap-y-3")} } title="Vitals" > Vitals Taken {vitals.takenAt} {vitalsGrid("gap-y-3")} ); } function labValue(value: string, flag: LabFlag) { return ( {value} {flag} ); } function LabsCard({ patient }: { patient: Patient }) { return ( No labs on file. ) : (
{patient.labs.map((lab) => (
{lab.name} {lab.takenAt}
{labValue(lab.value, lab.flag)}
))}
) } title="Labs" > Labs As of {patient.labs[0]?.takenAt ?? "—"} {patient.labs.length === 0 ? ( No labs on file. ) : ( <>
{patient.labs.map((lab) => ( ))}
)}
); } function MedicationsCard({ patient }: { patient: Patient }) { const list = patient.medications.length === 0 ? ( No active medications. ) : (
{patient.medications.map((med) => ( ))}
); return ( Medications {patient.medications.length} active {list} ); } function ProblemsCard({ patient }: { patient: Patient }) { const list = patient.problems.length === 0 ? ( No active problems. ) : (
{patient.problems.map((problem) => ( ))}
); return ( Problems {patient.problems.length} active {list} ); } function AllergiesList({ patient }: { patient: Patient }) { return (
Allergies {patient.allergies.length === 0 ? (

No known allergies.

) : ( patient.allergies.map((allergy) => ( {allergy.substance} {" "} — {allergy.reaction} } value={ {allergy.severity} } /> )) )}
); } function AllergiesCard({ patient }: { patient: Patient }) { return ( } title="Allergies & alerts" > Allergies & alerts ); } function VisitsList({ patient }: { patient: Patient }) { if (patient.encounters.length === 0) { return No visits yet.; } return (
{patient.encounters.map((encounter) => (
{encounter.type} {encounter.date}
{encounter.summary} {encounter.provider}
))}
); } function VisitsCard({ patient }: { patient: Patient }) { return ( } title="Recent visits" > Recent visits ); } function LoadingCards() { return ( <>
{[0, 1, 2, 3].map((cell) => ( ))}
{[0, 1, 2, 3, 4, 5].map((card) => ( {[0, 1, 2].map((row) => ( ))} {card % 2 === 1 && } ))} ); } export function PatientResult({ status, fileNumber, patient }: PatientResultProps) { if (status === "not-found") { return (

No patient found for file #{fileNumber}.

); } return (
{status === "loading" || !patient ? ( ) : ( <> )}
); }