diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 22d47f3..b7c73f4 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -799,7 +799,7 @@ function AppContent() {
{settings.emailEnabled && settings.shoutrrrEnabled ? "🔔" : settings.emailEnabled ? "📧" : "🔔"}
- {t('dashboard.reminders.active')} — {getReminderStatusText(settings.reminderDaysBefore, coverage.low, settings.lastAutoEmailSent, settings.lastNotificationType, settings.lastNotificationChannel, t, i18n.language)}
+ {t('dashboard.reminders.active')} — {getReminderStatusText(settings.reminderDaysBefore, settings.lowStockDays, coverage.low, coverage.all, settings.lastAutoEmailSent, settings.lastNotificationType, settings.lastNotificationChannel, t, i18n.language)}
{settings.emailEnabled && settings.notificationEmail && → {settings.notificationEmail}}
@@ -2153,8 +2153,10 @@ function calculateCoverage(meds: Medication[], events: Array<{ medName: string;
}
function getReminderStatusText(
- reminderDaysBefore: number,
+ reminderDaysBefore: number,
+ lowStockDays: number,
lowStock: Coverage[],
+ allCoverage: Coverage[],
lastSent: string | null,
lastType: "stock" | "intake" | null,
lastChannel: "email" | "push" | "both" | null,
@@ -2199,6 +2201,23 @@ function getReminderStatusText(
return ⚠{t('dashboard.reminders.needReorder', { count: medsNeedingReminder.length })} — {t('dashboard.reminders.waitingFirstCheck')};
}
+ // Check if there are low stock medications (not yet needing reminder but running low)
+ const lowStockNotYetCritical = allCoverage.filter(
+ (c) => c.daysLeft !== null && c.daysLeft > reminderDaysBefore && c.daysLeft < lowStockDays
+ );
+
+ if (lowStockNotYetCritical.length > 0) {
+ // There are low stock meds but not critical yet
+ const nextMed = lowStockNotYetCritical.sort((a, b) => (a.daysLeft ?? 0) - (b.daysLeft ?? 0))[0];
+ const daysUntilReminder = (nextMed.daysLeft ?? 0) - reminderDaysBefore;
+ return (
+ <>
+ {t('dashboard.reminders.lowWarning', { count: lowStockNotYetCritical.length })}
+ {" · "}{t('dashboard.reminders.nextIn')}: {nextMed.name} {t('dashboard.reminders.inDays', { days: daysUntilReminder })}
+ >
+ );
+ }
+
// Calculate when next reminder would be triggered
const allWithDepletion = lowStock
.filter((c) => c.depletionTime !== null && c.daysLeft !== null)
diff --git a/frontend/src/i18n/de.json b/frontend/src/i18n/de.json
index 88d19b8..e98f55e 100644
--- a/frontend/src/i18n/de.json
+++ b/frontend/src/i18n/de.json
@@ -43,6 +43,8 @@
"noRemindersNeeded": "keine Erinnerungen nötig",
"needReorder": "{{count}} Medikament nachbestellen",
"needReorder_other": "{{count}} Medikamente nachbestellen",
+ "lowWarning": "{{count}} Medikament wird knapp",
+ "lowWarning_other": "{{count}} Medikamente werden knapp",
"waitingFirstCheck": "warte auf erste Prüfung",
"typeStock": "Bestand",
"typeIntake": "Einnahme",
diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json
index 1c8388c..100be8f 100644
--- a/frontend/src/i18n/en.json
+++ b/frontend/src/i18n/en.json
@@ -45,6 +45,8 @@
"noRemindersNeeded": "no reminders needed",
"needReorder": "{{count}} med needs reorder",
"needReorder_other": "{{count}} meds need reorder",
+ "lowWarning": "{{count}} medication running low",
+ "lowWarning_other": "{{count}} medications running low",
"waitingFirstCheck": "waiting for first check",
"typeStock": "Stock",
"typeIntake": "Intake",