mirror of
https://github.com/temetro/temetro.git
synced 2026-07-26 11:58:14 +00:00
Redesign patient cards: 7 focused cards + sparklines; lighten input
- Split the overloaded card into 7 single-topic cards (Summary, Vitals, Labs, Medications, Problems, Allergies & alerts, Visits) so the equal-height row is evenly filled instead of stretched-and-empty. - Add a dependency-free inline-SVG shaded-area Sparkline; Vitals shows a heart-rate trend and Labs a headline-lab trend, fed by new vitalsTrend/ labTrend series in the fixture. - Lighten the chat input's two surfaces so it reads as a raised layer above the new (lighter) page background. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -192,10 +192,10 @@ export function ChatInput({ onSubmit, status, onStop }: ChatInputProps) {
|
||||
event.preventDefault();
|
||||
submit();
|
||||
}}
|
||||
className="w-full overflow-hidden rounded-[28px] border border-border/60 bg-[oklch(0.172_0.006_277)] shadow-sm"
|
||||
className="w-full overflow-hidden rounded-[28px] border border-border/60 bg-[oklch(0.195_0.006_277)] shadow-sm"
|
||||
>
|
||||
{/* Top (lighter) card: textarea + toolbar, with a slightly smaller bottom radius */}
|
||||
<div className="rounded-b-[22px] bg-card">
|
||||
<div className="rounded-b-[22px] bg-[oklch(0.218_0.006_277)]">
|
||||
<textarea
|
||||
aria-label="Message"
|
||||
className="field-sizing-content block max-h-48 min-h-16 w-full resize-none bg-transparent px-5 pt-5 pb-2 text-base text-foreground outline-none placeholder:text-muted-foreground"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import {
|
||||
@@ -11,7 +13,8 @@ import {
|
||||
} from "@/components/ui/card";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import type { AllergySeverity, LabFlag, Patient } from "@/lib/patients";
|
||||
import { Sparkline } from "@/components/chat/sparkline";
|
||||
import type { AllergySeverity, LabFlag, Patient, Trend } from "@/lib/patients";
|
||||
|
||||
type BadgeVariant = "default" | "secondary" | "destructive" | "outline";
|
||||
|
||||
@@ -45,7 +48,7 @@ const sexLabel: Record<Patient["sex"], string> = { F: "Female", M: "Male" };
|
||||
// Fixed width so the cards sit in a horizontal scroll row instead of squashing.
|
||||
const rowCard = "w-80 shrink-0 snap-start";
|
||||
|
||||
function SectionLabel({ children }: { children: string }) {
|
||||
function SectionLabel({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<p className="text-xs font-medium tracking-wide text-muted-foreground uppercase">
|
||||
{children}
|
||||
@@ -53,6 +56,40 @@ function SectionLabel({ children }: { children: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
function Stat({ label, value }: { label: string; value: ReactNode }) {
|
||||
return (
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<span className="text-xs text-muted-foreground">{label}</span>
|
||||
<span className="text-foreground">{value}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Row({ label, value }: { label: ReactNode; value: ReactNode }) {
|
||||
return (
|
||||
<div className="flex items-baseline justify-between gap-3">
|
||||
<span className="text-foreground">{label}</span>
|
||||
<span className="shrink-0 text-muted-foreground">{value}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TrendBlock({ trend }: { trend: Trend }) {
|
||||
const latest = trend.points.at(-1);
|
||||
return (
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<div className="flex items-baseline justify-between gap-2">
|
||||
<SectionLabel>{`${trend.label} · last ${trend.points.length}`}</SectionLabel>
|
||||
<span className="text-foreground">
|
||||
{latest}
|
||||
<span className="text-muted-foreground"> {trend.unit}</span>
|
||||
</span>
|
||||
</div>
|
||||
<Sparkline points={trend.points} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SummaryCard({ patient }: { patient: Patient }) {
|
||||
return (
|
||||
<Card className={rowCard} size="sm">
|
||||
@@ -72,9 +109,121 @@ function SummaryCard({ patient }: { patient: Patient }) {
|
||||
</Badge>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<span className="text-muted-foreground">Primary care: </span>
|
||||
<span className="text-foreground">{patient.pcp}</span>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<div className="grid grid-cols-2 gap-x-3 gap-y-3">
|
||||
<Stat label="Primary care" value={patient.pcp} />
|
||||
<Stat label="Last seen" value={patient.encounters[0]?.date ?? "—"} />
|
||||
<Stat label="Active meds" value={patient.medications.length} />
|
||||
<Stat label="Open problems" value={patient.problems.length} />
|
||||
</div>
|
||||
{patient.alerts.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{patient.alerts.map((alert) => (
|
||||
<Badge key={alert} variant="outline">
|
||||
{alert}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
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 },
|
||||
];
|
||||
|
||||
return (
|
||||
<Card className={rowCard} size="sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Vitals</CardTitle>
|
||||
<CardDescription>Taken {vitals.takenAt}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<div className="grid grid-cols-2 gap-x-3 gap-y-3">
|
||||
{vitalItems.map((item) => (
|
||||
<Stat key={item.label} label={item.label} value={item.value} />
|
||||
))}
|
||||
</div>
|
||||
<Separator />
|
||||
<TrendBlock trend={patient.vitalsTrend} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function LabsCard({ patient }: { patient: Patient }) {
|
||||
return (
|
||||
<Card className={rowCard} size="sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Labs</CardTitle>
|
||||
<CardDescription>As of {patient.labs[0]?.takenAt ?? "—"}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
{patient.labs.map((lab) => (
|
||||
<Row
|
||||
key={lab.name}
|
||||
label={lab.name}
|
||||
value={
|
||||
<span className="flex items-center gap-2">
|
||||
{lab.value}
|
||||
<Badge className="capitalize" variant={labFlagVariant[lab.flag]}>
|
||||
{lab.flag}
|
||||
</Badge>
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<Separator />
|
||||
<TrendBlock trend={patient.labTrend} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function MedicationsCard({ patient }: { patient: Patient }) {
|
||||
return (
|
||||
<Card className={rowCard} size="sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Medications</CardTitle>
|
||||
<CardDescription>{patient.medications.length} active</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-2">
|
||||
{patient.medications.map((med) => (
|
||||
<Row
|
||||
key={med.name}
|
||||
label={med.name}
|
||||
value={`${med.dose} · ${med.frequency}`}
|
||||
/>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function ProblemsCard({ patient }: { patient: Patient }) {
|
||||
return (
|
||||
<Card className={rowCard} size="sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Problems</CardTitle>
|
||||
<CardDescription>{patient.problems.length} active</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-2">
|
||||
{patient.problems.map((problem) => (
|
||||
<Row
|
||||
key={problem.label}
|
||||
label={problem.label}
|
||||
value={`since ${problem.since}`}
|
||||
/>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
@@ -102,24 +251,26 @@ function AllergiesCard({ patient }: { patient: Patient }) {
|
||||
<p className="text-muted-foreground">No known allergies.</p>
|
||||
) : (
|
||||
patient.allergies.map((allergy) => (
|
||||
<div
|
||||
className="flex items-center justify-between gap-3"
|
||||
<Row
|
||||
key={allergy.substance}
|
||||
>
|
||||
<span className="text-foreground">
|
||||
{allergy.substance}
|
||||
<span className="text-muted-foreground">
|
||||
{" "}
|
||||
— {allergy.reaction}
|
||||
</span>
|
||||
</span>
|
||||
<Badge
|
||||
className="capitalize"
|
||||
variant={severityVariant[allergy.severity]}
|
||||
>
|
||||
{allergy.severity}
|
||||
</Badge>
|
||||
</div>
|
||||
label={
|
||||
<>
|
||||
{allergy.substance}
|
||||
<span className="text-muted-foreground">
|
||||
{" "}
|
||||
— {allergy.reaction}
|
||||
</span>
|
||||
</>
|
||||
}
|
||||
value={
|
||||
<Badge
|
||||
className="capitalize"
|
||||
variant={severityVariant[allergy.severity]}
|
||||
>
|
||||
{allergy.severity}
|
||||
</Badge>
|
||||
}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
@@ -128,95 +279,30 @@ function AllergiesCard({ patient }: { patient: Patient }) {
|
||||
);
|
||||
}
|
||||
|
||||
function MedicationsCard({ patient }: { patient: Patient }) {
|
||||
function VisitsCard({ patient }: { patient: Patient }) {
|
||||
return (
|
||||
<Card className={rowCard} size="sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Medications & problems</CardTitle>
|
||||
<CardTitle>Recent visits</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
<SectionLabel>Active medications</SectionLabel>
|
||||
{patient.medications.map((med) => (
|
||||
<div className="flex items-baseline justify-between gap-3" key={med.name}>
|
||||
<span className="text-foreground">{med.name}</span>
|
||||
<span className="text-muted-foreground">
|
||||
{med.dose} · {med.frequency}
|
||||
<CardContent className="flex flex-col gap-3">
|
||||
{patient.encounters.map((encounter) => (
|
||||
<div
|
||||
className="flex flex-col gap-0.5"
|
||||
key={encounter.date + encounter.type}
|
||||
>
|
||||
<div className="flex items-baseline justify-between gap-3">
|
||||
<span className="text-foreground">{encounter.type}</span>
|
||||
<span className="shrink-0 text-xs text-muted-foreground">
|
||||
{encounter.date}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="flex flex-col gap-2">
|
||||
<SectionLabel>Problem list</SectionLabel>
|
||||
{patient.problems.map((problem) => (
|
||||
<div
|
||||
className="flex items-baseline justify-between gap-3"
|
||||
key={problem.label}
|
||||
>
|
||||
<span className="text-foreground">{problem.label}</span>
|
||||
<span className="text-muted-foreground">since {problem.since}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
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 },
|
||||
];
|
||||
|
||||
return (
|
||||
<Card className={rowCard} size="sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Vitals, labs & visits</CardTitle>
|
||||
<CardDescription>Vitals taken {vitals.takenAt}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
<div className="grid grid-cols-2 gap-2 sm:grid-cols-4">
|
||||
{vitalItems.map((item) => (
|
||||
<div className="flex flex-col gap-0.5" key={item.label}>
|
||||
<span className="text-xs text-muted-foreground">{item.label}</span>
|
||||
<span className="text-foreground">{item.value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="flex flex-col gap-2">
|
||||
<SectionLabel>Recent labs</SectionLabel>
|
||||
{patient.labs.map((lab) => (
|
||||
<div className="flex items-center justify-between gap-3" key={lab.name}>
|
||||
<span className="text-foreground">{lab.name}</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-muted-foreground">{lab.value}</span>
|
||||
<Badge className="capitalize" variant={labFlagVariant[lab.flag]}>
|
||||
{lab.flag}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="flex flex-col gap-3">
|
||||
<SectionLabel>Recent visits</SectionLabel>
|
||||
{patient.encounters.map((encounter) => (
|
||||
<div className="flex flex-col gap-0.5" key={encounter.date + encounter.type}>
|
||||
<div className="flex items-baseline justify-between gap-3">
|
||||
<span className="text-foreground">{encounter.type}</span>
|
||||
<span className="text-xs text-muted-foreground">{encounter.date}</span>
|
||||
</div>
|
||||
<span className="text-muted-foreground">{encounter.summary}</span>
|
||||
<span className="text-xs text-muted-foreground">{encounter.provider}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<span className="text-muted-foreground">{encounter.summary}</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{encounter.provider}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
@@ -231,20 +317,26 @@ function LoadingCards() {
|
||||
<Skeleton className="size-10 rounded-full" />
|
||||
<div className="grid flex-1 gap-1.5">
|
||||
<Skeleton className="h-4 w-40" />
|
||||
<Skeleton className="h-3 w-56" />
|
||||
<Skeleton className="h-3 w-52" />
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="grid grid-cols-2 gap-3">
|
||||
{[0, 1, 2, 3].map((cell) => (
|
||||
<Skeleton className="h-8 w-full" key={cell} />
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
{[0, 1, 2].map((card) => (
|
||||
{[0, 1, 2, 3, 4, 5].map((card) => (
|
||||
<Card className={rowCard} key={card} size="sm">
|
||||
<CardHeader>
|
||||
<Skeleton className="h-4 w-44" />
|
||||
<Skeleton className="h-4 w-28" />
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-2.5">
|
||||
{[0, 1, 2].map((row) => (
|
||||
<Skeleton className="h-3.5 w-full" key={row} />
|
||||
))}
|
||||
{card % 2 === 1 && <Skeleton className="mt-1.5 h-10 w-full" />}
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
@@ -272,9 +364,12 @@ export function PatientResult({ status, fileNumber, patient }: PatientResultProp
|
||||
) : (
|
||||
<>
|
||||
<SummaryCard patient={patient} />
|
||||
<AllergiesCard patient={patient} />
|
||||
<MedicationsCard patient={patient} />
|
||||
<VitalsCard patient={patient} />
|
||||
<LabsCard patient={patient} />
|
||||
<MedicationsCard patient={patient} />
|
||||
<ProblemsCard patient={patient} />
|
||||
<AllergiesCard patient={patient} />
|
||||
<VisitsCard patient={patient} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
"use client";
|
||||
|
||||
import { useId } from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
// A tiny dependency-free trend chart: a line with a soft shaded fill beneath it.
|
||||
// Stretches to its container width; colored via `currentColor` (default text-primary).
|
||||
export function Sparkline({
|
||||
points,
|
||||
className,
|
||||
}: {
|
||||
points: number[];
|
||||
className?: string;
|
||||
}) {
|
||||
const gradientId = useId();
|
||||
|
||||
if (points.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const width = 100;
|
||||
const top = 3;
|
||||
const bottom = 29;
|
||||
const baseline = 32;
|
||||
const min = Math.min(...points);
|
||||
const max = Math.max(...points);
|
||||
const range = max - min;
|
||||
|
||||
const coords = points.map((value, index) => {
|
||||
const x =
|
||||
points.length === 1 ? width / 2 : (index / (points.length - 1)) * width;
|
||||
const y =
|
||||
range === 0
|
||||
? (top + bottom) / 2
|
||||
: bottom - ((value - min) / range) * (bottom - top);
|
||||
return `${x.toFixed(2)},${y.toFixed(2)}`;
|
||||
});
|
||||
|
||||
const line = coords.map((c, i) => `${i === 0 ? "M" : "L"}${c}`).join(" ");
|
||||
const area = `${line} L${width},${baseline} L0,${baseline} Z`;
|
||||
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className={cn("h-10 w-full text-primary", className)}
|
||||
preserveAspectRatio="none"
|
||||
viewBox={`0 0 ${width} ${baseline}`}
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id={gradientId} x1="0" x2="0" y1="0" y2="1">
|
||||
<stop offset="0%" stopColor="currentColor" stopOpacity="0.28" />
|
||||
<stop offset="100%" stopColor="currentColor" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path d={area} fill={`url(#${gradientId})`} stroke="none" />
|
||||
<path
|
||||
d={line}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -45,6 +45,14 @@ export type Encounter = {
|
||||
summary: string;
|
||||
};
|
||||
|
||||
// A short series for a sparkline. `points` are most-recent-last, so the
|
||||
// latest reading is points.at(-1).
|
||||
export type Trend = {
|
||||
label: string;
|
||||
unit: string;
|
||||
points: number[];
|
||||
};
|
||||
|
||||
export type Patient = {
|
||||
fileNumber: string; // MRN / file number, e.g. "10293"
|
||||
name: string;
|
||||
@@ -58,7 +66,9 @@ export type Patient = {
|
||||
medications: Medication[];
|
||||
problems: Problem[];
|
||||
vitals: Vitals;
|
||||
vitalsTrend: Trend; // headline vital plotted as a sparkline
|
||||
labs: Lab[];
|
||||
labTrend: Trend; // headline lab plotted as a sparkline
|
||||
encounters: Encounter[];
|
||||
};
|
||||
|
||||
@@ -95,12 +105,22 @@ const PATIENTS: Record<string, Patient> = {
|
||||
spo2: "97%",
|
||||
takenAt: "May 28, 2026",
|
||||
},
|
||||
vitalsTrend: {
|
||||
label: "Heart rate",
|
||||
unit: "bpm",
|
||||
points: [72, 75, 74, 79, 83, 80, 78],
|
||||
},
|
||||
labs: [
|
||||
{ name: "HbA1c", value: "8.2 %", flag: "high", takenAt: "May 20, 2026" },
|
||||
{ name: "eGFR", value: "52 mL/min", flag: "low", takenAt: "May 20, 2026" },
|
||||
{ name: "Potassium", value: "4.4 mmol/L", flag: "normal", takenAt: "May 20, 2026" },
|
||||
{ name: "INR", value: "2.6", flag: "normal", takenAt: "May 20, 2026" },
|
||||
],
|
||||
labTrend: {
|
||||
label: "HbA1c",
|
||||
unit: "%",
|
||||
points: [9.4, 9.1, 8.8, 8.6, 8.2],
|
||||
},
|
||||
encounters: [
|
||||
{
|
||||
date: "May 28, 2026",
|
||||
@@ -151,12 +171,22 @@ const PATIENTS: Record<string, Patient> = {
|
||||
spo2: "92%",
|
||||
takenAt: "May 31, 2026",
|
||||
},
|
||||
vitalsTrend: {
|
||||
label: "Heart rate",
|
||||
unit: "bpm",
|
||||
points: [88, 91, 96, 99, 97, 95, 94],
|
||||
},
|
||||
labs: [
|
||||
{ name: "WBC", value: "14.8 ×10⁹/L", flag: "high", takenAt: "May 31, 2026" },
|
||||
{ name: "CRP", value: "112 mg/L", flag: "critical", takenAt: "May 31, 2026" },
|
||||
{ name: "Lactate", value: "1.8 mmol/L", flag: "normal", takenAt: "May 31, 2026" },
|
||||
{ name: "Hemoglobin", value: "11.9 g/dL", flag: "low", takenAt: "May 31, 2026" },
|
||||
],
|
||||
labTrend: {
|
||||
label: "CRP",
|
||||
unit: "mg/L",
|
||||
points: [38, 64, 98, 126, 112],
|
||||
},
|
||||
encounters: [
|
||||
{
|
||||
date: "May 30, 2026",
|
||||
@@ -197,11 +227,21 @@ const PATIENTS: Record<string, Patient> = {
|
||||
spo2: "99%",
|
||||
takenAt: "May 26, 2026",
|
||||
},
|
||||
vitalsTrend: {
|
||||
label: "Heart rate",
|
||||
unit: "bpm",
|
||||
points: [78, 80, 79, 83, 85, 84, 82],
|
||||
},
|
||||
labs: [
|
||||
{ name: "TSH", value: "2.1 mIU/L", flag: "normal", takenAt: "May 19, 2026" },
|
||||
{ name: "Hemoglobin", value: "11.2 g/dL", flag: "low", takenAt: "May 19, 2026" },
|
||||
{ name: "Fasting glucose", value: "84 mg/dL", flag: "normal", takenAt: "May 19, 2026" },
|
||||
],
|
||||
labTrend: {
|
||||
label: "Hemoglobin",
|
||||
unit: "g/dL",
|
||||
points: [12.4, 12.0, 11.7, 11.4, 11.2],
|
||||
},
|
||||
encounters: [
|
||||
{
|
||||
date: "May 26, 2026",
|
||||
|
||||
Reference in New Issue
Block a user