/* biome-ignore-all lint/style/noNestedTernary: timeline rendering uses explicit UI-state branching */ import { Bell, ClipboardList, NotebookPen, Share2 } from "lucide-react"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { ConfirmModal, MedicationAvatar } from "../components"; import { useAuth } from "../components/Auth"; import { useAppContext } from "../context"; import { useModalHistory } from "../hooks"; import { type Coverage, getMedDisplayName } from "../types"; import { formatNumber, getExpiryClass, getSystemLocale } from "../utils/formatters"; import { expandDoseIds, getStockStatus, isDoseDismissed } from "../utils/schedule"; import { formatFullBlisters, formatOpenBlisterAndLoose, getBlisterStock, getMedTotal, getReminderStatusData, userStorageKey, } from "./dashboard-helpers"; // Notification bell SVG icon (no emoji) function NotificationBellIcon() { return ( ); } export function DashboardPage() { const { t, i18n } = useTranslation(); const { user } = useAuth(); const { meds, settings, coverage, coverageByMed, depletionByMed, scheduleDays, setScheduleDays, showPastDays, setShowPastDays, showFutureDays, setShowFutureDays, pastDays, todayDay, futureDays, takenDoses, dismissedDoses, markDoseTaken, undoDoseTaken, manuallyCollapsedDays, manuallyExpandedDays, toggleDayCollapse, missedPastDoseIds, getDayStockStatus, getDoseId, isDoseTakenAutomatically, showClearMissedConfirm, setShowClearMissedConfirm, clearingMissed, dismissMissedDoses, openMedDetail, openUserFilter, openShareDialog, openScheduleLightbox, stockThresholds, loadSettings, } = useAppContext(); useModalHistory(showClearMissedConfirm, "clearMissed", () => setShowClearMissedConfirm(false)); // Get structured reminder data const reminderData = getReminderStatusData( settings.reminderDaysBefore, settings.lowStockDays, coverage.low, coverage.all, meds, settings.lastAutoEmailSent, settings.lastNotificationType, settings.lastNotificationChannel, settings.lastReminderMedName, settings.lastReminderTakenBy, settings.lastStockReminderSent, settings.lastStockReminderChannel, settings.lastStockReminderMedNames, t, getSystemLocale(i18n.language) ); // Check which reminder types are actually enabled (channel must be enabled too) const stockRemindersEnabled = (settings.emailEnabled && settings.emailStockReminders) || (settings.shoutrrrEnabled && settings.shoutrrrStockReminders); const intakeRemindersEnabled = (settings.emailEnabled && settings.emailIntakeReminders) || (settings.shoutrrrEnabled && settings.shoutrrrIntakeReminders); const prescriptionRemindersEnabled = (settings.emailEnabled && settings.emailPrescriptionReminders) || (settings.shoutrrrEnabled && settings.shoutrrrPrescriptionReminders); const prescriptionLowMeds = meds .filter((med) => { if (!med.prescriptionEnabled) return false; const remaining = med.prescriptionRemainingRefills ?? 0; const threshold = med.prescriptionLowRefillThreshold ?? 1; return remaining <= threshold; }) .map((med) => ({ id: med.id, name: getMedDisplayName(med), remainingRefills: med.prescriptionRemainingRefills ?? 0, threshold: med.prescriptionLowRefillThreshold ?? 1, })) .sort((a, b) => a.remainingRefills - b.remainingRefills); const anyRemindersEnabled = stockRemindersEnabled || intakeRemindersEnabled || prescriptionRemindersEnabled; const showOnlyToday = settings.upcomingTodayOnly; const prescriptionEmptyCount = prescriptionLowMeds.filter((med) => med.remainingRefills <= 0).length; const getTubeUnitLabel = (med: (typeof meds)[number] | undefined, value: number) => med?.packageType === "liquid_container" || med?.medicationForm === "liquid" ? t("form.packageAmountUnitMl") : t("form.blisters.applications", { count: Math.abs(value) }); const formatStockLabel = (med: (typeof meds)[number] | undefined, medsLeft: number) => { if (med?.packageType === "liquid_container") { return `${formatNumber(medsLeft)} ${t("form.packageAmountUnitMl")}`; } if (med?.packageType === "tube") { return `${formatNumber(medsLeft)} ${getTubeUnitLabel(med, medsLeft)}`; } return t("table.pillsCount", { count: Math.round(medsLeft) }); }; const convertLiquidUsageToMl = (usage: number, unit: "ml" | "tsp" | "tbsp" | null | undefined): number => { if (unit === "tsp") return usage * 5; if (unit === "tbsp") return usage * 15; return usage; }; const getLiquidCountUnitLabel = (unit: "ml" | "tsp" | "tbsp" | null | undefined, usage: number): string => { if (unit === "tsp") return t("form.blisters.teaspoons", { count: Math.abs(usage) }); if (unit === "tbsp") return t("form.blisters.tablespoons", { count: Math.abs(usage) }); return t("form.packageAmountUnitMl"); }; const formatLiquidUsageLabel = (usage: number, unit: "ml" | "tsp" | "tbsp" | null | undefined): string => { const normalizedUsage = Number(usage); if (!Number.isFinite(normalizedUsage) || normalizedUsage <= 0) { return `0 ${t("form.packageAmountUnitMl")}`; } if (unit === "ml" || unit == null) { return `${formatNumber(normalizedUsage)} ${t("form.packageAmountUnitMl")}`; } const mlTotal = convertLiquidUsageToMl(normalizedUsage, unit); return `${formatNumber(normalizedUsage)} ${getLiquidCountUnitLabel(unit, normalizedUsage)} ${formatNumber(mlTotal)} ${t("form.packageAmountUnitMl")}`; }; const formatDoseUsageLabel = ( med: (typeof meds)[number] | undefined, usage: number, intakeUnit?: "ml" | "tsp" | "tbsp" | null ) => { if (med?.packageType === "liquid_container") { return formatLiquidUsageLabel(usage, intakeUnit); } if (med?.packageType === "tube") { return `${usage} ${getTubeUnitLabel(med, usage)}`; } return `${usage} ${usage !== 1 ? t("common.pills") : t("common.pill")}`; }; const formatTotalUsageLabel = ( med: (typeof meds)[number] | undefined, total: number, intakeUnit?: "ml" | "tsp" | "tbsp" | null, doses?: Array<{ usage: number; intakeUnit?: "ml" | "tsp" | "tbsp" | null }> ) => { if (med?.packageType === "liquid_container") { if (doses && doses.length > 0) { const normalizedDoses = doses.filter((dose) => Number.isFinite(Number(dose.usage)) && Number(dose.usage) > 0); if (normalizedDoses.length > 0) { const allUnits = new Set(normalizedDoses.map((dose) => dose.intakeUnit ?? "ml")); const totalMl = normalizedDoses.reduce( (sum, dose) => sum + convertLiquidUsageToMl(Number(dose.usage), dose.intakeUnit ?? "ml"), 0 ); if (allUnits.size === 1) { const onlyUnit = normalizedDoses[0]?.intakeUnit ?? "ml"; const totalUsageInUnit = normalizedDoses.reduce((sum, dose) => sum + Number(dose.usage), 0); return formatLiquidUsageLabel(totalUsageInUnit, onlyUnit); } return `${formatNumber(totalMl)} ${t("form.packageAmountUnitMl")}`; } } return formatLiquidUsageLabel(total, intakeUnit); } if (med?.packageType === "tube") { return `${total} ${getTubeUnitLabel(med, total)}`; } return t("common.pillsTotal", { count: total }); }; const formatDailyConsumption = (med: (typeof meds)[number] | undefined) => { if (!med) return "-"; const intakes = med.intakes && med.intakes.length > 0 ? med.intakes : med.blisters.map((blister) => ({ usage: blister.usage, every: blister.every, intakeUnit: null as "ml" | "tsp" | "tbsp" | null, takenBy: null as string | null, })); if (intakes.length === 0) return "-"; let dailyTotal = 0; for (const intake of intakes) { const usage = Number(intake.usage); const every = Math.max(1, Number(intake.every) || 1); if (!Number.isFinite(usage) || usage <= 0) continue; const hasPerIntakeTakenBy = typeof intake.takenBy === "string" && intake.takenBy.trim().length > 0; const personMultiplier = hasPerIntakeTakenBy ? 1 : Math.max(1, med.takenBy?.length ?? 0); const normalizedUsage = (usage * personMultiplier) / every; if (med.packageType === "liquid_container") { dailyTotal += convertLiquidUsageToMl(normalizedUsage, intake.intakeUnit ?? "ml"); } else { dailyTotal += normalizedUsage; } } if (dailyTotal <= 0) return "-"; if (med.packageType === "liquid_container") { return t("table.perDayWithUnit", { value: formatNumber(dailyTotal), unit: t("form.packageAmountUnitMl") }); } if (med.packageType === "tube") { const tubeUnit = med.medicationForm === "liquid" ? t("form.packageAmountUnitMl") : t("form.blisters.applications", { count: Math.abs(dailyTotal) }); return t("table.perDayWithUnit", { value: formatNumber(dailyTotal), unit: tubeUnit }); } const pillUnit = dailyTotal === 1 ? t("common.pill") : t("common.pills"); return t("table.perDayWithUnit", { value: formatNumber(dailyTotal), unit: pillUnit }); }; const shouldHideNoScheduleStatusForTube = ( med: (typeof meds)[number] | undefined, status: { className: string; label: string } | null ) => med?.packageType === "tube" && status?.label === "status.noSchedule"; const getVisibleStockStatus = ( med: (typeof meds)[number] | undefined, status: { className: string; label: string } | null ) => (shouldHideNoScheduleStatusForTube(med, status) ? null : status); const getMedByName = (name: string) => meds.find((m) => getMedDisplayName(m) === name); const prescriptionStatus = prescriptionRemindersEnabled && prescriptionLowMeds.length > 0 ? { text: prescriptionEmptyCount > 0 ? t("dashboard.reminders.prescriptionCriticalMeds", { count: prescriptionEmptyCount }) : t("dashboard.reminders.prescriptionLowMeds", { count: prescriptionLowMeds.length }), className: prescriptionEmptyCount > 0 ? "danger" : "warning", } : null; // Manual reminder send state const [sendingReminder, setSendingReminder] = useState(false); const [reminderResult, setReminderResult] = useState<{ success: boolean; message: string } | null>(null); async function sendManualReminder() { const sendableStock = stockRemindersEnabled && reminderData.lowStockMeds.length > 0; const sendablePrescription = prescriptionRemindersEnabled && prescriptionLowMeds.length > 0; if (!sendableStock && !sendablePrescription) return; setSendingReminder(true); setReminderResult(null); try { const messages: string[] = []; const errors: string[] = []; if (sendableStock) { const lowStock = reminderData.lowStockMeds.map((m) => { const cov = coverage.all.find((c) => c.name === m.name); return { name: m.name, medsLeft: cov?.medsLeft ?? 0, daysLeft: m.daysLeft, depletionDate: cov?.depletionDate ?? null, isCritical: m.isCritical, }; }); const stockRes = await fetch("/api/reminder/send-email", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ email: settings.notificationEmail, lowStock, }), }); const stockData = await stockRes.json(); if (stockRes.ok) { messages.push(stockData.message || t("common.sent")); } else { errors.push(stockData.error || t("common.sendFailed")); } } if (sendablePrescription) { const prescriptionLow = prescriptionLowMeds.map((med) => { const fullMed = meds.find((m) => m.id === med.id); return { name: med.name, remainingRefills: med.remainingRefills, threshold: med.threshold, expiryDate: fullMed?.prescriptionExpiryDate ?? null, }; }); const prescriptionRes = await fetch("/api/reminder/send-prescription", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ email: settings.notificationEmail, prescriptionLow, }), }); const prescriptionData = await prescriptionRes.json(); if (prescriptionRes.ok) { messages.push(prescriptionData.message || t("common.sent")); } else { errors.push(prescriptionData.error || t("common.sendFailed")); } } if (messages.length > 0) { setReminderResult({ success: true, message: messages.join(" • ") }); loadSettings(); } else { setReminderResult({ success: false, message: errors.join(" • ") || t("common.sendFailed") }); } } catch { setReminderResult({ success: false, message: t("common.networkError") }); } setSendingReminder(false); } return ( <> {anyRemindersEnabled && (
{t("dashboard.reminders.active")} {stockRemindersEnabled && ( {reminderData.status.text} )} {prescriptionStatus && ( {prescriptionStatus.text} )}
{(reminderData.lowStockMeds.length > 0 || (prescriptionRemindersEnabled && prescriptionLowMeds.length > 0) || (stockRemindersEnabled && reminderData.lastStockSent) || (intakeRemindersEnabled && reminderData.lastIntakeSent)) && (
{stockRemindersEnabled && reminderData.lowStockMeds.length > 0 && (
{t("dashboard.reminders.needsRefill")}: {reminderData.lowStockMeds.map((med, idx) => { const medication = meds.find((m) => getMedDisplayName(m) === med.name); const cov = coverage.all.find((c) => c.name === med.name); const status = cov ? getStockStatus(cov.daysLeft, cov.medsLeft, stockThresholds, medication?.packageType) : null; const textClass = status?.className === "danger" ? "danger-text" : status?.className === "warning" ? "warning-text" : ""; return ( {idx > 0 && ", "} medication && openMedDetail(medication)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { if (medication) openMedDetail(medication); } }} > {med.name} {" "} {t("dashboard.reminders.daysLeft", { count: med.daysLeft, days: med.daysLeft })} ); })}
)} {prescriptionRemindersEnabled && prescriptionLowMeds.length > 0 && (
{t("dashboard.reminders.needsPrescriptionRefill")}: {prescriptionLowMeds.map((med, idx) => { const medication = meds.find((m) => m.id === med.id); const textClass = med.remainingRefills <= 0 ? "danger-text" : "warning-text"; return ( {idx > 0 && ", "} {t("prescription.remainingRefills")}: {med.remainingRefills} ·{" "} {t("dashboard.reminders.usedBy")}:{" "} medication && openMedDetail(medication)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { if (medication) openMedDetail(medication); } }} > {med.name} ); })}
)} {stockRemindersEnabled && reminderData.lastStockSent && (
{t("dashboard.reminders.lastStockSent")}: {reminderData.lastStockSent.medNames && (() => { const names = reminderData.lastStockSent!.medNames!.split(", "); return names.map((name, idx) => { const medication = meds.find((m) => getMedDisplayName(m) === name); return ( {idx > 0 && ", "} {medication ? ( openMedDetail(medication)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") openMedDetail(medication); }} > {name} ) : ( {name} )} ); }); })()} {reminderData.lastStockSent.date}
)} {intakeRemindersEnabled && reminderData.lastIntakeSent && (
{t("dashboard.reminders.lastSent")}: {reminderData.lastIntakeSent.medName && (() => { const medication = meds.find( (m) => getMedDisplayName(m) === reminderData.lastIntakeSent!.medName ); return medication ? ( openMedDetail(medication)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") openMedDetail(medication); }} > {reminderData.lastIntakeSent!.medName} ) : ( {reminderData.lastIntakeSent!.medName} ); })()} {reminderData.lastIntakeSent.takenBy && ( ({reminderData.lastIntakeSent.takenBy}) )} {reminderData.lastIntakeSent.date}
)}
)} {((stockRemindersEnabled && reminderData.lowStockMeds.length > 0) || (prescriptionRemindersEnabled && prescriptionLowMeds.length > 0)) && (
{reminderResult && ( {reminderResult.message} )}
)}
)} {/* Reorder Reminder card: Only show when reminders are NOT enabled (otherwise Reminder Bar shows the same info) */} {!anyRemindersEnabled && (

{t("dashboard.reorder.title")}

{(() => { if (meds.length === 0) { return

{t("dashboard.reorder.noMeds")}

; } // Count medications with low stock (based on lowStockDays setting), deduplicated by name const lowStockMap = new Map(); for (const c of coverage.all) { if (c.daysLeft === null && c.medsLeft > 0) continue; // no schedule, has stock const med = getMedByName(c.name); const status = getStockStatus(c.daysLeft, c.medsLeft, stockThresholds, med?.packageType); if (status.className === "danger" || status.className === "warning") { const existing = lowStockMap.get(c.name); if (!existing || (c.daysLeft ?? 0) < (existing.daysLeft ?? 0)) { lowStockMap.set(c.name, c); } } } const lowStockMeds = Array.from(lowStockMap.values()); const lowStockCount = lowStockMeds.length; if (lowStockCount === 0) { // All good - everything is Normal or High return

{t("dashboard.reorder.allGood")}

; } // Some meds are low - show simple text with clickable names and days left return (

{t("dashboard.reorder.lowWarningPrefix")}{" "} {lowStockMeds.map((c, idx) => { const med = meds.find((m) => getMedDisplayName(m) === c.name); const status = getStockStatus(c.daysLeft, c.medsLeft, stockThresholds, med?.packageType); const textClass = status.className === "danger" ? "danger-text" : status.className === "warning" ? "warning-text" : ""; return ( {idx > 0 && ", "} med && openMedDetail(med)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { if (med) openMedDetail(med); } }} > {c.name} {" "} ({t("dashboard.reminders.daysLeft", { count: c.daysLeft ?? 0, days: c.daysLeft ?? 0 })}) ); })}{" "} {t("dashboard.reorder.lowWarningSuffix", { count: lowStockCount })}

); })()}
)}

{t("dashboard.overview.title")}

{t("table.name")} {t("table.stock")} {t("table.dailyConsumption")} {t("table.stockDetails")} {t("table.daysLeft")} {t("table.runsOut")} {t("table.expiry")} {t("table.status")}
{coverage.all.map((row) => { const med = meds.find((m) => getMedDisplayName(m) === row.name); const rawStatus = getStockStatus(row.daysLeft, row.medsLeft, stockThresholds, med?.packageType); const status = getVisibleStockStatus(med, rawStatus); const expiryClass = getExpiryClass(med?.expiryDate, settings.expiryWarningDays); const textClass = rawStatus.className === "danger" ? "danger-text" : rawStatus.className === "warning" ? "warning-text" : "success-text"; const stock = getBlisterStock( Math.round(row.medsLeft), med?.pillsPerBlister ?? 1, med?.looseTablets ?? 0, med ? getMedTotal(med) : Math.round(row.medsLeft) ); return (
med && openMedDetail(med)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { if (med) openMedDetail(med); } }} > { 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}`); } }} > {row.name} {med?.notes && ( <> {" "} )} {med?.prescriptionEnabled && ( <> {" "} )} {med?.takenBy && med.takenBy.length > 0 && ( {med.takenBy.map((person) => ( { e.stopPropagation(); openUserFilter(person); }} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.stopPropagation(); openUserFilter(person); } }} > {person} {med.intakes?.some((i) => i.takenBy === person && i.intakeRemindersEnabled) && ( ))} )} {med?.packageType === "bottle" || med?.packageType === "tube" || med?.packageType === "liquid_container" ? formatStockLabel(med, row.medsLeft) : formatFullBlisters(stock.fullBlisters, t)} {formatDailyConsumption(med)} {med?.packageType === "bottle" || med?.packageType === "tube" || med?.packageType === "liquid_container" ? "—" : formatOpenBlisterAndLoose( stock.openBlisterPills, stock.loosePills, med?.pillsPerBlister ?? 1, t )} {formatNumber(row.daysLeft)} {row.depletionDate ?? "-"} {med?.expiryDate ? new Date(med.expiryDate).toLocaleDateString(getSystemLocale(i18n.language), { day: "2-digit", month: "short", year: "2-digit", }) : "-"} {status ? t(status.label) : "-"}
); })}

{t("dashboard.schedules.title")}

{meds.some((m) => m.takenBy && m.takenBy.length > 0) && ( )}
{/* Past days (when expanded) — rendered above toggle */} {!showOnlyToday && showPastDays && pastDays.map((day) => { // Get ALL dose IDs for this day (for total count and yellow styling) const allDoseIds = day.meds.flatMap((item) => item.doses.flatMap((d) => { const takenByArray = Array.isArray(d.takenBy) ? d.takenBy : []; return takenByArray.length > 0 ? takenByArray.map((p) => `${d.id}-${p}`) : [d.id]; }) ); // Really taken = all doses marked as taken by human (for green "All taken") const allReallyTaken = allDoseIds.length > 0 && allDoseIds.every((id) => takenDoses.has(id)); const takenCount = allDoseIds.filter((id) => takenDoses.has(id)).length; // Count missed doses that are NOT dismissed (for warning icon) const missedNotDismissedCount = day.meds.reduce((count, item) => { const med = meds.find((m) => getMedDisplayName(m) === item.medName); const dismissedUntilDate = med?.dismissedUntil ?? undefined; return ( count + item.doses.reduce((doseCount, d) => { if (isDoseDismissed(d.id, dismissedUntilDate)) return doseCount; const takenByArray = Array.isArray(d.takenBy) ? d.takenBy : []; const ids = takenByArray.length > 0 ? takenByArray.map((p) => `${d.id}-${p}`) : [d.id]; return doseCount + ids.filter((id) => !takenDoses.has(id) && !dismissedDoses.has(id)).length; }, 0) ); }, 0); const hasRealMissed = missedNotDismissedCount > 0; const isAutoCollapsed = true; // Past days are always auto-collapsed const isManuallyExpanded = manuallyExpandedDays.has(day.dateStr); const isCollapsed = !isManuallyExpanded; const _worstStatus = getDayStockStatus(day.meds); return (
0 ? "past-missed" : ""}`} >
toggleDayCollapse(day.dateStr, isAutoCollapsed)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") toggleDayCollapse(day.dateStr, isAutoCollapsed); }} title={isCollapsed ? t("common.expand") : t("common.collapse")} > {isCollapsed ? "▶" : "▼"} {day.dateStr} {allReallyTaken ? ( ✓ {t("dashboard.schedules.allTaken")} ) : ( <> {hasRealMissed && ( ⚠️ )} {takenCount}/{allDoseIds.length} )}
{!isCollapsed && day.meds.map((item) => { const med = meds.find((m) => getMedDisplayName(m) === item.medName); const medCov = coverageByMed[item.medName]; const isEmpty = medCov ? medCov.medsLeft <= 0 : false; const rawStatus = medCov ? getStockStatus(medCov.daysLeft, medCov.medsLeft, stockThresholds, med?.packageType) : null; const status = getVisibleStockStatus(med, rawStatus); const itemDoseIds = expandDoseIds(item.doses); const allTaken = itemDoseIds.every((id) => takenDoses.has(id)); return (
med?.imageUrl && openScheduleLightbox(`/api/images/${med.imageUrl}`)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { if (med?.imageUrl) openScheduleLightbox(`/api/images/${med.imageUrl}`); } }} >
med && openMedDetail(med)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { if (med) openMedDetail(med); } }} > {item.medName} {med?.genericName && {med.genericName}}
{formatTotalUsageLabel(med, item.total, item.doses[0]?.intakeUnit, item.doses)} {status && ( {t(status.label)} )}
{item.doses.map((dose) => { // If no takenBy, show single checkbox; otherwise show one per person const people = dose.takenBy.length > 0 ? dose.takenBy : [null]; return (
{dose.timeStr} {formatDoseUsageLabel(med, dose.usage, dose.intakeUnit)} {med?.packageType !== "tube" && med?.packageType !== "liquid_container" && med?.pillWeightMg && ( {`${dose.usage * med.pillWeightMg} ${med.doseUnit ?? "mg"}`} )} {dose.intakeRemindersEnabled && ( )}
{people.map((person) => { const doseId = getDoseId(dose.id, person); const isTaken = takenDoses.has(doseId); const isAutomaticallyTaken = isTaken && isDoseTakenAutomatically(doseId) && dose.when <= Date.now(); return (
{person && ( openUserFilter(person)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") openUserFilter(person); }} > {person} )} {isTaken ? ( ) : ( )}
); })}
); })}
); })}
); })} {/* Past days toggle */} {!showOnlyToday && pastDays.length > 0 && (() => { const missedCount = missedPastDoseIds.length; const totalPastDoses = pastDays.flatMap((d) => d.meds.flatMap((m) => expandDoseIds(m.doses))); return (
0 ? "has-missed" : ""}`} onClick={() => { const wasCollapsed = !showPastDays; setShowPastDays(!showPastDays); if (wasCollapsed) { setTimeout(() => { document .querySelector(".day-block.today") ?.scrollIntoView({ behavior: "smooth", block: "center" }); }, 50); } }} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { const wasCollapsed = !showPastDays; setShowPastDays(!showPastDays); if (wasCollapsed) { setTimeout(() => { document .querySelector(".day-block.today") ?.scrollIntoView({ behavior: "smooth", block: "center" }); }, 50); } } }} > {showPastDays ? "▼" : "▶"} {showPastDays ? t("dashboard.schedules.hidePastDays") : t("dashboard.schedules.showPastDays")} ({t("dashboard.schedules.pastDaysCount", { count: pastDays.length })}) {missedCount > 0 ? ( ⚠️ {missedCount} ) : totalPastDoses.length > 0 ? ( ) : null}
{missedCount > 0 && ( )}
); })()} {/* Today - always visible */} {todayDay && (() => { const day = todayDay; const allDoseIds = day.meds.flatMap((item) => expandDoseIds(item.doses)); const allDayTaken = allDoseIds.length > 0 && allDoseIds.every((id) => takenDoses.has(id)); const takenCount = allDoseIds.filter((id) => takenDoses.has(id)).length; const dayStockStatuses = day.meds.map((item) => { const medCoverage = coverageByMed[item.medName]; const depletionTime = depletionByMed[item.medName]; const willBeOutOfStock = typeof depletionTime === "number" && item.lastWhen > depletionTime; if (willBeOutOfStock) return "danger"; if (!medCoverage) return "success"; const med = getMedByName(item.medName); const status = getStockStatus( medCoverage.daysLeft, medCoverage.medsLeft, stockThresholds, med?.packageType ); return status.className; }); const worstStatus = dayStockStatuses.includes("danger") ? "danger" : dayStockStatuses.includes("warning") ? "warning" : "success"; // Today: expanded by default, can be manually collapsed const isAutoCollapsed = allDayTaken; const isManuallyExpanded = manuallyExpandedDays.has(day.dateStr); const isManuallyCollapsed = manuallyCollapsedDays.has(day.dateStr); const isCollapsed = isAutoCollapsed ? !isManuallyExpanded : isManuallyCollapsed; return (
toggleDayCollapse(day.dateStr, isAutoCollapsed)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") toggleDayCollapse(day.dateStr, isAutoCollapsed); }} title={isCollapsed ? t("common.expand") : t("common.collapse")} > {isCollapsed ? "▶" : "▼"} {day.dateStr} {allDayTaken ? ( ✓ {t("dashboard.schedules.allTaken")} ) : ( {takenCount}/{allDoseIds.length} )}
{!isCollapsed && day.meds.map((item) => { const medCoverage = coverageByMed[item.medName]; const med = meds.find((m) => getMedDisplayName(m) === item.medName); const depletionTime = depletionByMed[item.medName]; const isEmpty = medCoverage ? medCoverage.medsLeft <= 0 : false; const willBeOutOfStock = typeof depletionTime === "number" && item.lastWhen > depletionTime; const status = willBeOutOfStock ? { className: "danger", label: "status.outOfStock" } : medCoverage ? getStockStatus( medCoverage.daysLeft, medCoverage.medsLeft, stockThresholds, med?.packageType ) : null; const visibleStatus = getVisibleStockStatus(med, status); const itemDoseIds = expandDoseIds(item.doses); const allTaken = itemDoseIds.every((id) => takenDoses.has(id)); return (
med?.imageUrl && openScheduleLightbox(`/api/images/${med.imageUrl}`)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { if (med?.imageUrl) openScheduleLightbox(`/api/images/${med.imageUrl}`); } }} >
med && openMedDetail(med)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { if (med) openMedDetail(med); } }} > {item.medName} {med?.genericName && {med.genericName}}
{formatTotalUsageLabel(med, item.total, item.doses[0]?.intakeUnit, item.doses)} {visibleStatus && ( {t(visibleStatus.label)} )}
{item.doses.map((dose) => { const isOverdue = dose.when < Date.now(); const people = dose.takenBy.length > 0 ? dose.takenBy : [null]; const allTaken = people.every((person) => takenDoses.has(getDoseId(dose.id, person))); return (
{dose.timeStr} {formatDoseUsageLabel(med, dose.usage, dose.intakeUnit)} {med?.packageType !== "tube" && med?.packageType !== "liquid_container" && med?.pillWeightMg && ( {`${dose.usage * med.pillWeightMg} ${med.doseUnit ?? "mg"}`} )} {dose.intakeRemindersEnabled && ( )}
{people.map((person) => { const doseId = getDoseId(dose.id, person); const isTaken = takenDoses.has(doseId); const isAutomaticallyTaken = isTaken && isDoseTakenAutomatically(doseId) && dose.when <= Date.now(); return (
{person && ( openUserFilter(person)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") openUserFilter(person); }} > {person} )} {isTaken ? ( ) : ( )}
); })}
); })}
); })}
); })()} {/* Future days toggle */} {!showOnlyToday && futureDays.length > 0 && (() => { const totalFutureDoses = futureDays.flatMap((d) => d.meds.flatMap((m) => m.doses.flatMap((dose) => dose.takenBy.length > 0 ? dose.takenBy.map((p) => `${dose.id}-${p}`) : [dose.id] ) ) ); const takenFutureDoses = totalFutureDoses.filter((id) => takenDoses.has(id)).length; return (
setShowFutureDays(!showFutureDays)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") setShowFutureDays(!showFutureDays); }} > {showFutureDays ? "▼" : "▶"} {showFutureDays ? t("dashboard.schedules.hideFutureDays") : t("dashboard.schedules.showFutureDays")} ({t("dashboard.schedules.futureDaysCount", { count: futureDays.length })}) {takenFutureDoses > 0 && totalFutureDoses.length > 0 && ( {takenFutureDoses}/{totalFutureDoses.length} )}
); })()} {/* Future days */} {!showOnlyToday && showFutureDays && futureDays.map((day) => { const allDoseIds = day.meds.flatMap((item) => expandDoseIds(item.doses)); const allDayTaken = allDoseIds.length > 0 && allDoseIds.every((id) => takenDoses.has(id)); const takenCount = allDoseIds.filter((id) => takenDoses.has(id)).length; const dayStockStatuses = day.meds.map((item) => { const medCoverage = coverageByMed[item.medName]; const depletionTime = depletionByMed[item.medName]; const willBeOutOfStock = typeof depletionTime === "number" && item.lastWhen > depletionTime; if (willBeOutOfStock) return "danger"; if (!medCoverage) return "success"; const med = getMedByName(item.medName); const status = getStockStatus( medCoverage.daysLeft, medCoverage.medsLeft, stockThresholds, med?.packageType ); return status.className; }); const worstStatus = dayStockStatuses.includes("danger") ? "danger" : dayStockStatuses.includes("warning") ? "warning" : "success"; // Future days: collapsed by default const isAutoCollapsed = true; const isManuallyExpanded = manuallyExpandedDays.has(day.dateStr); const isCollapsed = !isManuallyExpanded; return (
toggleDayCollapse(day.dateStr, isAutoCollapsed)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") toggleDayCollapse(day.dateStr, isAutoCollapsed); }} title={isCollapsed ? t("common.expand") : t("common.collapse")} > {isCollapsed ? "▶" : "▼"} {day.dateStr} {allDayTaken ? ( ✓ {t("dashboard.schedules.allTaken")} ) : ( {takenCount}/{allDoseIds.length} )}
{!isCollapsed && day.meds.map((item) => { const medCoverage = coverageByMed[item.medName]; const med = meds.find((m) => getMedDisplayName(m) === item.medName); const depletionTime = depletionByMed[item.medName]; const _isEmpty = medCoverage ? medCoverage.medsLeft <= 0 : false; const willBeOutOfStock = typeof depletionTime === "number" && item.lastWhen > depletionTime; const status = willBeOutOfStock ? { className: "danger", label: "status.outOfStock" } : medCoverage ? getStockStatus( medCoverage.daysLeft, medCoverage.medsLeft, stockThresholds, med?.packageType ) : null; const visibleStatus = getVisibleStockStatus(med, status); const itemDoseIds = expandDoseIds(item.doses); const allTaken = itemDoseIds.every((id) => takenDoses.has(id)); return (
med?.imageUrl && openScheduleLightbox(`/api/images/${med.imageUrl}`)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { if (med?.imageUrl) openScheduleLightbox(`/api/images/${med.imageUrl}`); } }} >
med && openMedDetail(med)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { if (med) openMedDetail(med); } }} > {item.medName} {med?.genericName && {med.genericName}}
{formatTotalUsageLabel(med, item.total, item.doses[0]?.intakeUnit, item.doses)} {visibleStatus && ( {t(visibleStatus.label)} )}
{item.doses.map((dose) => { const people = dose.takenBy.length > 0 ? dose.takenBy : [null]; const allTaken = people.every((person) => takenDoses.has(getDoseId(dose.id, person))); return (
{dose.timeStr} {formatDoseUsageLabel(med, dose.usage, dose.intakeUnit)} {med?.packageType !== "tube" && med?.packageType !== "liquid_container" && med?.pillWeightMg && ( {`${dose.usage * med.pillWeightMg} ${med.doseUnit ?? "mg"}`} )} {dose.intakeRemindersEnabled && ( )}
{people.map((person) => { const doseId = getDoseId(dose.id, person); const isTaken = takenDoses.has(doseId); const isAutomaticallyTaken = isTaken && isDoseTakenAutomatically(doseId) && dose.when <= Date.now(); return (
{person && ( openUserFilter(person)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") openUserFilter(person); }} > {person} )} {isTaken ? ( ) : ( )}
); })}
); })}
); })}
); })}
{/* Clear Missed Doses Confirmation Modal */} {showClearMissedConfirm && ( dismissMissedDoses(missedPastDoseIds)} onCancel={() => setShowClearMissedConfirm(false)} isLoading={clearingMissed} /> )} ); }