fix(medications): replace the list loading spinner with card skeletons

The bare centred spinner reserved a 32-unit-tall box that the resolved
card grid then displaced, jumping the layout. Render a grid of card
skeletons built on the real Card shell + shared Skeleton primitive so the
loading state matches the loaded footprint.
This commit is contained in:
Marc-André Bombeck committed 2026-06-04 15:36:12 +02:00
1 parent 0c3c80a4f6
commit 3c7d12f9c1
1 file changed
+52 -2
+52 -2
View File
@@ -13,7 +13,9 @@ import type { MedicationPayload } from "@/components/medications/wizard/wizard-p
import { MedicationCard } from "@/components/medications/medication-card";
import { Glp1MedicationCard } from "@/components/medications/glp1-medication-card";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { EmptyState } from "@/components/ui/empty-state";
import { Skeleton } from "@/components/ui/skeleton";
import { Loader2, Pill, Plus } from "lucide-react";
interface Schedule {
@@ -71,6 +73,44 @@ interface Medication {
schedules: Schedule[];
}
/**
* v1.11.3 C4 — loading placeholder for one medication card. Renders the
* real `Card`/`CardContent` shell (so padding, radius and gap match the
* loaded card exactly) with the shared `Skeleton` primitive standing in
* for each populated slot: header title + dose, status pill, next / last
* line, the two compliance bars and the action row. Replacing the bare
* centred spinner with a grid of these stops the layout jump when the
* cards resolve.
*/
function MedicationCardSkeleton() {
return (
<Card className="h-full" aria-hidden="true">
<div className="flex items-start justify-between gap-2 px-4 md:px-6">
<div className="space-y-2">
<Skeleton className="h-5 w-32" />
<Skeleton className="h-3.5 w-20" />
</div>
<Skeleton className="size-8 rounded-md" />
</div>
<CardContent className="flex flex-col space-y-3.5">
<Skeleton className="h-6 w-40 rounded-full" />
<div className="space-y-2">
<Skeleton className="h-3.5 w-48" />
<Skeleton className="h-3.5 w-36" />
</div>
<div className="space-y-2">
<Skeleton className="h-3.5 w-full" />
<Skeleton className="h-3.5 w-full" />
</div>
<div className="flex gap-2 pt-1">
<Skeleton className="h-9 flex-1" />
<Skeleton className="h-9 flex-1" />
</div>
</CardContent>
</Card>
);
}
export default function MedicationsPage() {
const { isAuthenticated, isLoading: authLoading } = useAuth();
const { t } = useTranslations();
@@ -223,8 +263,18 @@ export default function MedicationsPage() {
</div>
{isLoading ? (
<div className="flex h-32 items-center justify-center">
<Loader2 className="text-primary h-6 w-6 animate-spin motion-reduce:animate-none" />
// v1.11.3 C4 — card skeletons instead of a bare centred spinner so
// the page reserves the loaded layout and does not jump when the
// medications resolve.
<div
className="grid gap-4 sm:grid-cols-2"
role="status"
aria-busy="true"
aria-label={t("medications.title")}
>
{Array.from({ length: 4 }).map((_, i) => (
<MedicationCardSkeleton key={i} />
))}
</div>
) : isError ? (
<div className="bg-card border-border flex h-64 items-center justify-center rounded-xl border">