mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
fix(visits): keep the since-last-visit card on a failed read
A failed read replaced the card and its title with a bare row, so the section changed height and the reader lost what had failed. The card now keeps its header and shows the error inside. The visit card's header moves onto TileHeader instead of its own icon and title row.
This commit is contained in:
1 parent
3fbd16a0a6
commit
a1b56f0b75
4 files changed
+43
-26
No files matched your search
@@ -194,14 +194,31 @@ export function SinceLastVisit({
|
||||
})
|
||||
: [];
|
||||
|
||||
const lastLabel = fmt.dateShortSmartCalendar(lastDay);
|
||||
|
||||
// A failed read keeps the card and its title, so the page does not jump
|
||||
// and the reader still sees what could not be loaded.
|
||||
if (window.isError && rows.length === 0) {
|
||||
return (
|
||||
<QueryErrorRow
|
||||
error={window.error}
|
||||
slot="since-last-visit-error"
|
||||
message={t("day.sinceLastVisit.loadError")}
|
||||
onRetry={() => void window.refetch()}
|
||||
/>
|
||||
<Card className="gap-2 py-3 md:py-4">
|
||||
<CardHeader>
|
||||
<TileHeader
|
||||
size="sm"
|
||||
icon={Stethoscope}
|
||||
titleAs="h3"
|
||||
title={t("day.sinceLastVisit.title", { date: lastLabel })}
|
||||
/>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<QueryErrorRow
|
||||
inset
|
||||
error={window.error}
|
||||
slot="since-last-visit-error"
|
||||
message={t("day.sinceLastVisit.loadError")}
|
||||
onRetry={() => void window.refetch()}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
// Nothing to show is nothing drawn: still loading, or a quiet window. The
|
||||
@@ -209,7 +226,6 @@ export function SinceLastVisit({
|
||||
if (rows.length === 0) return null;
|
||||
|
||||
const visible = showAll ? rows : rows.slice(0, VISIBLE_ROWS);
|
||||
const lastLabel = fmt.dateShortSmartCalendar(lastDay);
|
||||
const nextDay = dateKeyOfInstant(next.occurredAt, timeZone);
|
||||
|
||||
return (
|
||||
|
||||
@@ -164,7 +164,7 @@ describe("<ProceduresSection>", () => {
|
||||
bodySites: [],
|
||||
total: 1,
|
||||
});
|
||||
expect(html).toMatch(/font-medium">Meniscus repair</);
|
||||
expect(html).toMatch(/card-title"[^>]*>Meniscus repair</);
|
||||
expect(html).toContain("Sample clinic");
|
||||
expect(html.match(/Meniscus repair/g)).toHaveLength(1);
|
||||
});
|
||||
|
||||
@@ -261,7 +261,10 @@ describe("<VisitsSection> since the last visit", () => {
|
||||
expect(html).toContain('data-slot="since-last-visit-error"');
|
||||
expect(html).toContain('role="alert"');
|
||||
expect(html).not.toContain('data-slot="since-last-visit"');
|
||||
expect(upcomingCards(html)).toBe(upcomingCards(baseline));
|
||||
// The failed window keeps its own card and title, so the page does not
|
||||
// jump; the visit cards beside it stay as they were.
|
||||
expect(upcomingCards(html)).toBe(upcomingCards(baseline) + 1);
|
||||
expect(html).toContain("Since the last visit on");
|
||||
});
|
||||
|
||||
// Visits need the profile section, the window reads measurements, and a
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
encounterKindText,
|
||||
encounterStatusText,
|
||||
} from "./encounter-labels";
|
||||
import { TileHeader } from "@/components/insights/tile-header";
|
||||
|
||||
/** The two statuses worth calling out on a row; the rest the section implies. */
|
||||
function isNoteworthy(status: EncounterStatus): boolean {
|
||||
@@ -97,23 +98,20 @@ export function VisitCard({
|
||||
>
|
||||
<CardContent className="space-y-2">
|
||||
<Body onOpen={onOpen} encounter={encounter}>
|
||||
<div className="flex items-start gap-2">
|
||||
<CalendarClock
|
||||
className="text-foreground mt-0.5 size-5 shrink-0"
|
||||
aria-hidden
|
||||
/>
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="text-foreground truncate text-sm font-medium">
|
||||
{heading}
|
||||
</p>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{format.dateTime(encounter.occurredAt)}
|
||||
</p>
|
||||
</div>
|
||||
<Badge variant="outline" className="shrink-0">
|
||||
{encounterKindText(t, encounter.kind as EncounterKind)}
|
||||
</Badge>
|
||||
</div>
|
||||
<TileHeader
|
||||
size="sm"
|
||||
icon={CalendarClock}
|
||||
title={heading}
|
||||
titleClassName="min-w-0 truncate"
|
||||
right={
|
||||
<Badge variant="outline" className="shrink-0">
|
||||
{encounterKindText(t, encounter.kind as EncounterKind)}
|
||||
</Badge>
|
||||
}
|
||||
/>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{format.dateTime(encounter.occurredAt)}
|
||||
</p>
|
||||
|
||||
{reasonLine ? (
|
||||
<p className="text-foreground line-clamp-1 text-sm">{reasonLine}</p>
|
||||
|
||||
Reference in new issue
Block a user