fix: stabilize dashboard modal and image click behavior (#267)

* feat: make medication names clickable in Dashboard dose schedule

Add click handlers to med-name-stack divs in all three dose schedule
sections (past, current/overdue, future) on DashboardPage, opening the
MedDetail modal on click.

Add early-return guards to all four modal openers in AppContext
(openMedDetail, openImageLightbox, openScheduleLightbox, openUserFilter)
to prevent duplicate pushState entries on double-click, which caused
unexpected navigation to the Medications page.

Closes #266

* fix: stabilize dashboard modal and image click handling

* fix: close medication detail on first backdrop click
This commit is contained in:
Daniel Volz
2026-02-22 10:50:58 +01:00
committed by GitHub
parent 088a6c1a05
commit 9a2d42b8b9
7 changed files with 147 additions and 39 deletions
+42 -4
View File
@@ -512,7 +512,21 @@ export function DashboardPage() {
>
<span data-label={t("table.name")} className="cell-with-avatar">
<span className="med-name-line">
<MedicationAvatar name={row.name} imageUrl={med?.imageUrl} />
<span
className={med?.imageUrl ? "med-avatar-clickable" : undefined}
onClick={(e) => {
e.stopPropagation();
if (med?.imageUrl) openScheduleLightbox(`/api/images/${med.imageUrl}`);
}}
onKeyDown={(e) => {
e.stopPropagation();
if (e.key === "Enter" || e.key === " ") {
if (med?.imageUrl) openScheduleLightbox(`/api/images/${med.imageUrl}`);
}
}}
>
<MedicationAvatar name={row.name} imageUrl={med?.imageUrl} />
</span>
<span className="med-name-block-dash">
<span className="med-name-text">
{row.name}
@@ -730,7 +744,15 @@ export function DashboardPage() {
>
<MedicationAvatar name={item.medName} imageUrl={med?.imageUrl} size="sm" />
</div>
<div className="med-name-stack">
<div
className="med-name-stack clickable"
onClick={() => med && openMedDetail(med)}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
if (med) openMedDetail(med);
}
}}
>
<span className="med-name-text">{item.medName}</span>
{med?.genericName && <span className="med-generic-inline">{med.genericName}</span>}
</div>
@@ -982,7 +1004,15 @@ export function DashboardPage() {
>
<MedicationAvatar name={item.medName} imageUrl={med?.imageUrl} size="sm" />
</div>
<div className="med-name-stack">
<div
className="med-name-stack clickable"
onClick={() => med && openMedDetail(med)}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
if (med) openMedDetail(med);
}
}}
>
<span className="med-name-text">{item.medName}</span>
{med?.genericName && <span className="med-generic-inline">{med.genericName}</span>}
</div>
@@ -1205,7 +1235,15 @@ export function DashboardPage() {
>
<MedicationAvatar name={item.medName} imageUrl={med?.imageUrl} size="sm" />
</div>
<div className="med-name-stack">
<div
className="med-name-stack clickable"
onClick={() => med && openMedDetail(med)}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
if (med) openMedDetail(med);
}
}}
>
<span className="med-name-text">{item.medName}</span>
{med?.genericName && <span className="med-generic-inline">{med.genericName}</span>}
</div>
+6
View File
@@ -74,6 +74,10 @@ export function MedicationsPage() {
// Mobile modal state (declared early because it's used in useEffect below)
const [showEditModal, setShowEditModal] = useState(false);
const showEditModalRef = useRef(false);
useEffect(() => {
showEditModalRef.current = showEditModal;
}, [showEditModal]);
const processedEditMedIdRef = useRef<string | null>(null);
const hasDesktopFormHistoryState = useRef(false);
@@ -199,6 +203,8 @@ export function MedicationsPage() {
// Open mobile edit modal
function openEditModal() {
if (showEditModalRef.current) return;
showEditModalRef.current = true;
setShowEditModal(true);
window.history.pushState({ modal: "edit" }, "");
}