/* 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)) && (
{sendingReminder ? t("common.sending") : t("dashboard.reorder.sendReminder")}
{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")}
{
const val = Number(e.target.value);
setScheduleDays(val);
if (user?.id) localStorage.setItem(userStorageKey(user.id, "scheduleDays"), String(val));
}}
>
{t("dashboard.schedules.1month")}
{t("dashboard.schedules.3months")}
{t("dashboard.schedules.6months")}
{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 ? (
undoDoseTaken(doseId)}
title={t("common.undo")}
>
{isAutomaticallyTaken && (
🤖
)}
↩
) : (
markDoseTaken(doseId)}
title={t("dose.markAsTaken")}
disabled={isEmpty}
>
{t("dose.take")}
✓
)}
);
})}
);
})}
);
})}
);
})}
{/* 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 && (
{
e.stopPropagation();
setShowClearMissedConfirm(true);
}}
title={t("dashboard.schedules.clearMissed")}
>
{t("dashboard.schedules.clearMissed")}
)}
);
})()}
{/* 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 ? (
undoDoseTaken(doseId)}
title={t("common.undo")}
>
{isAutomaticallyTaken && (
🤖
)}
↩
) : (
markDoseTaken(doseId)}
title={t("dose.markAsTaken")}
disabled={isEmpty}
>
{t("dose.take")}
✓
)}
);
})}
);
})}
);
})}
);
})()}
{/* 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 ? (
undoDoseTaken(doseId)}
title={t("common.undo")}
>
{isAutomaticallyTaken && (
🤖
)}
↩
) : (
markDoseTaken(doseId)}
title={t("dose.markAsTaken")}
disabled={true}
>
{t("dose.take")}
✓
)}
);
})}
);
})}
);
})}
);
})}
{/* Clear Missed Doses Confirmation Modal */}
{showClearMissedConfirm && (
dismissMissedDoses(missedPastDoseIds)}
onCancel={() => setShowClearMissedConfirm(false)}
isLoading={clearingMissed}
/>
)}
>
);
}