diff --git a/frontend/src/pages/DashboardPage.tsx b/frontend/src/pages/DashboardPage.tsx index 651d3fe..31cdddb 100644 --- a/frontend/src/pages/DashboardPage.tsx +++ b/frontend/src/pages/DashboardPage.tsx @@ -1,5 +1,5 @@ /* biome-ignore-all lint/style/noNestedTernary: timeline rendering uses explicit UI-state branching */ -import { Bell, ClipboardList, NotebookPen, Share2 } from "lucide-react"; +import { Archive, Bell, ClipboardList, NotebookPen, Share2 } from "lucide-react"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { ConfirmModal, MedicationAvatar } from "../components"; @@ -85,18 +85,10 @@ export function DashboardPage() { } = useAppContext(); const [showClearMissedConfirm, setShowClearMissedConfirm] = useState(false); const [clearingMissed, setClearingMissed] = useState(false); + const [showObsoleteConfirm, setShowObsoleteConfirm] = useState(false); + const [obsoleteCandidate, setObsoleteCandidate] = useState<{ id: number; name: string } | null>(null); - const outOfStockMedicationIds = new Set( - meds.filter((med) => (coverageByMed[getMedDisplayName(med)]?.medsLeft ?? 1) <= 0).map((med) => med.id) - ); - - const isDoseTakenForDisplay = (doseId: string) => { - const medId = Number.parseInt(doseId.split("-")[0] ?? "", 10); - if (!Number.isNaN(medId) && outOfStockMedicationIds.has(medId)) { - return false; - } - return takenDoses.has(doseId); - }; + const isDoseTakenForDisplay = (doseId: string) => takenDoses.has(doseId); // Get structured reminder data const reminderData = getReminderStatusData( @@ -210,6 +202,32 @@ export function DashboardPage() { } }; + const requestMarkObsolete = (med: { id: number; name: string }) => { + setObsoleteCandidate(med); + setShowObsoleteConfirm(true); + }; + + const handleConfirmMarkObsolete = async () => { + if (!obsoleteCandidate) return; + try { + const res = await fetch(`/api/medications/${obsoleteCandidate.id}/obsolete`, { + method: "POST", + credentials: "include", + }); + if (!res.ok) throw new Error(`HTTP ${res.status}`); + await loadMeds(); + setShowObsoleteConfirm(false); + setObsoleteCandidate(null); + } catch { + alert(t("common.saveFailed")); + } + }; + + const handleCancelMarkObsolete = () => { + setShowObsoleteConfirm(false); + setObsoleteCandidate(null); + }; + const getTubeUnitLabel = (med: (typeof meds)[number] | undefined, value: number) => isLiquidContainerPackageType(med?.packageType) || med?.medicationForm === "liquid" ? t("form.packageAmountUnitMl") @@ -1034,8 +1052,12 @@ export function DashboardPage() { ? getStockStatus(medCov.daysLeft, medCov.medsLeft, stockThresholds, med?.packageType) : null; const status = getVisibleStockStatus(med, rawStatus); + const isLowStock = !isEmpty && status?.className === "warning"; + const rowClasses = ["time-row"]; + if (isEmpty) rowClasses.push("med-empty"); + else if (isLowStock) rowClasses.push("med-low"); return ( -