mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
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:
1 parent
0c3c80a4f6
commit
3c7d12f9c1
1 file changed
+52
-2
@@ -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">
|
||||
|
||||
Reference in new issue
Block a user