From 9c8c7051aa023a42e5869b7f475ba7819bd338e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?=
Date: Tue, 16 Jun 2026 23:12:04 +0200
Subject: [PATCH] fix(labs): pin add-entry action bars to the sheet footer;
tighten header
The lab and biomarker forms portal their Cancel/Save row into the
ResponsiveSheet sticky footer (footerSlot pattern) so Save stays reachable
on mobile instead of scrolling away. The Labs header folds Manage
biomarkers into an overflow kebab beside the primary Add, mirroring the
medication header. The biomarker detail gains a self-edit Pencil opening
the pre-filled form. Add buttons on the labs detail and measurements page
meet the min-h-11 sm:min-h-9 tap floor.
---
src/app/labs/page.tsx | 46 ++++++++----
src/app/measurements/page.tsx | 5 +-
src/components/labs/biomarker-form.tsx | 58 +++++++++------
src/components/labs/biomarker-manager.tsx | 5 ++
src/components/labs/lab-biomarker-detail.tsx | 74 ++++++++++++++++++--
src/components/labs/lab-form.tsx | 72 +++++++++++++------
6 files changed, 202 insertions(+), 58 deletions(-)
diff --git a/src/app/labs/page.tsx b/src/app/labs/page.tsx
index d0b685f1c..8ef9835e3 100644
--- a/src/app/labs/page.tsx
+++ b/src/app/labs/page.tsx
@@ -3,12 +3,18 @@
import { useCallback, useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { useQueryClient } from "@tanstack/react-query";
-import { FlaskConical, Loader2, Plus } from "lucide-react";
+import { FlaskConical, Loader2, MoreVertical, Plus } from "lucide-react";
import { BiomarkerManager } from "@/components/labs/biomarker-manager";
import { LabForm } from "@/components/labs/lab-form";
import { LabList } from "@/components/labs/lab-list";
import { Button } from "@/components/ui/button";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu";
import { PullToRefreshIndicator } from "@/components/ui/pull-to-refresh-indicator";
import { ResponsiveSheet } from "@/components/ui/responsive-sheet";
import { useAuth } from "@/hooks/use-auth";
@@ -25,6 +31,9 @@ export default function LabsPage() {
const { t } = useTranslations();
const [dialogOpen, setDialogOpen] = useState(false);
const [manageOpen, setManageOpen] = useState(false);
+ // Sticky-footer slot element for the add-result sheet (filled by the
+ // ResponsiveSheet `footer` ref so the form portals its action row there).
+ const [addFooterEl, setAddFooterEl] = useState(null);
const refreshVisible = useCallback(
() => queryClient.invalidateQueries({ type: "active" }),
@@ -61,17 +70,7 @@ export default function LabsPage() {
{t("labs.subtitle")}
-
-
+
+ {/* Secondary actions fold into one overflow kebab beside the primary
+ Add, mirroring the medication-card header (one cluster, not a
+ two-button row). */}
+
+
+
+
+
+ setManageOpen(true)}>
+
+ {t("labs.biomarker.manage")}
+
+
+
@@ -87,8 +107,10 @@ export default function LabsPage() {
onOpenChange={setDialogOpen}
title={t("labs.addResult")}
description={t("labs.addDescription")}
+ footer={}
>
{
setDialogOpen(false);
queryClient.invalidateQueries({
diff --git a/src/app/measurements/page.tsx b/src/app/measurements/page.tsx
index c1dfcfacd..1689ed852 100644
--- a/src/app/measurements/page.tsx
+++ b/src/app/measurements/page.tsx
@@ -120,7 +120,10 @@ export default function MeasurementsPage() {
{t("measurements.subtitle")}
-