diff --git a/backend/src/i18n/translations.ts b/backend/src/i18n/translations.ts index 1260dc3..47e9358 100644 --- a/backend/src/i18n/translations.ts +++ b/backend/src/i18n/translations.ts @@ -16,6 +16,7 @@ type TranslationKeys = { runsOut: string; }; footer: string; + repeatDailyNote: string; }; // Intake reminder email intakeReminder: { @@ -40,6 +41,7 @@ type TranslationKeys = { pillsLeft: string; daysLeft: string; pillsAt: string; + repeatDailyNote: string; }; // Common common: { @@ -66,6 +68,7 @@ const translations: Record = { runsOut: "Runs Out", }, footer: "🤖 Automatic reminder from MedAssist-ng", + repeatDailyNote: "You are receiving this daily reminder because 'Repeat Daily' is enabled in settings.", }, intakeReminder: { subject: "MedAssist-ng: Medication Reminder - {medications}", @@ -88,6 +91,7 @@ const translations: Record = { pillsLeft: "{count} pills", daysLeft: "{count} days left", pillsAt: "{count} pills at {time}", + repeatDailyNote: "(Daily reminder enabled)", }, common: { pill: "pill", @@ -111,6 +115,7 @@ const translations: Record = { runsOut: "Aufgebraucht", }, footer: "🤖 Automatische Erinnerung von MedAssist-ng", + repeatDailyNote: "Sie erhalten diese tägliche Erinnerung, weil 'Täglich wiederholen' in den Einstellungen aktiviert ist.", }, intakeReminder: { subject: "MedAssist-ng: Einnahme-Erinnerung - {medications}", @@ -133,6 +138,7 @@ const translations: Record = { pillsLeft: "{count} Tabletten", daysLeft: "{count} Tage übrig", pillsAt: "{count} Tabletten um {time}", + repeatDailyNote: "(Tägliche Erinnerung aktiviert)", }, common: { pill: "Tablette", diff --git a/backend/src/routes/settings.ts b/backend/src/routes/settings.ts index 0312163..ec0420e 100644 --- a/backend/src/routes/settings.ts +++ b/backend/src/routes/settings.ts @@ -149,12 +149,20 @@ export async function settingsRoutes(app: FastifyInstance) { app.put<{ Body: SettingsBody }>("/settings", async (request, reply) => { const body = request.body; + // Check if any stock reminders are configured + const hasEmailStock = body.emailEnabled && body.emailStockReminders && body.notificationEmail; + const hasShoutrrrStock = body.shoutrrrEnabled && body.shoutrrrStockReminders && body.shoutrrrUrl; + const hasAnyStockReminder = hasEmailStock || hasShoutrrrStock; + + // Disable repeatDailyReminders if no stock reminders are configured + const repeatDailyReminders = hasAnyStockReminder ? (body.repeatDailyReminders ?? false) : false; + // Save notification settings to JSON file saveNotificationSettings({ emailEnabled: body.emailEnabled, notificationEmail: body.notificationEmail, reminderDaysBefore: body.reminderDaysBefore, - repeatDailyReminders: body.repeatDailyReminders ?? false, + repeatDailyReminders, lowStockDays: body.lowStockDays ?? 30, normalStockDays: body.normalStockDays ?? 90, highStockDays: body.highStockDays ?? 180, diff --git a/backend/src/services/reminder-scheduler.ts b/backend/src/services/reminder-scheduler.ts index dc6f87f..2299ca2 100644 --- a/backend/src/services/reminder-scheduler.ts +++ b/backend/src/services/reminder-scheduler.ts @@ -255,7 +255,7 @@ async function getMedicationsNeedingReminder(reminderDaysBefore: number, languag return lowStock; } -async function sendReminderEmail(email: string, lowStock: LowStockItem[], language: Language): Promise<{ success: boolean; error?: string }> { +async function sendReminderEmail(email: string, lowStock: LowStockItem[], language: Language, isRepeatDaily: boolean = false): Promise<{ success: boolean; error?: string }> { const smtpHost = process.env.SMTP_HOST; const smtpUser = process.env.SMTP_USER; const smtpPass = process.env.SMTP_PASS; @@ -317,6 +317,7 @@ async function sendReminderEmail(email: string, lowStock: LowStockItem[], langua

${tr.stockReminder.footer}

+ ${isRepeatDaily ? `

${tr.stockReminder.repeatDailyNote}

` : ""} `; @@ -328,7 +329,7 @@ ${tr.stockReminder.description} ${lowStock.map((r) => `${r.name}: ${r.medsLeft} ${tr.common.pills}, ${r.daysLeft ?? 0} ${tr.common.days}, ${tr.stockReminder.tableHeaders.runsOut}: ${r.depletionDate ?? tr.common.soon}`).join("\n")} --- -${tr.stockReminder.footer}`; +${tr.stockReminder.footer}${isRepeatDaily ? `\n\n${tr.stockReminder.repeatDailyNote}` : ""}`; const subjectPlural = lowStock.length === 1 ? "" : (language === "de" ? "e" : "s"); const subject = t(tr.stockReminder.subject, { count: lowStock.length, s: subjectPlural, e: subjectPlural }); @@ -427,7 +428,7 @@ async function checkAndSendReminder(logger: { info: (msg: string) => void; error // Send email if enabled if (emailEnabled) { - const result = await sendReminderEmail(settings.notificationEmail, medsToNotify, language); + const result = await sendReminderEmail(settings.notificationEmail, medsToNotify, language, settings.repeatDailyReminders); emailSuccess = result.success; if (result.success) { logger.info(`[Reminder] Email sent successfully to ${settings.notificationEmail}`); @@ -441,10 +442,14 @@ async function checkAndSendReminder(logger: { info: (msg: string) => void; error const title = medsToNotify.length === 1 ? tr.push.stockTitle : t(tr.push.stockTitleMultiple, { count: medsToNotify.length }); - const message = medsToNotify + let message = medsToNotify .map((m) => `• ${m.name}: ${t(tr.push.pillsLeft, { count: m.medsLeft })}, ${t(tr.push.daysLeft, { count: m.daysLeft ?? 0 })}`) .join("\n"); + if (settings.repeatDailyReminders) { + message += `\n\n${tr.push.repeatDailyNote}`; + } + const result = await sendShoutrrrNotification(settings.shoutrrrUrl, title, message); shoutrrrSuccess = result.success; if (result.success) { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index a7877fa..67393bd 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1250,11 +1250,12 @@ export default function App() { {t('settings.stock.repeatDaily')} ⓘ -