feat: add repeat daily reminder functionality with UI updates and translations
This commit is contained in:
@@ -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<Language, TranslationKeys> = {
|
||||
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<Language, TranslationKeys> = {
|
||||
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<Language, TranslationKeys> = {
|
||||
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<Language, TranslationKeys> = {
|
||||
pillsLeft: "{count} Tabletten",
|
||||
daysLeft: "{count} Tage übrig",
|
||||
pillsAt: "{count} Tabletten um {time}",
|
||||
repeatDailyNote: "(Tägliche Erinnerung aktiviert)",
|
||||
},
|
||||
common: {
|
||||
pill: "Tablette",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
<p style="color: #9ca3af; font-size: 11px; margin: 0;">
|
||||
${tr.stockReminder.footer}
|
||||
</p>
|
||||
${isRepeatDaily ? `<p style="color: #9ca3af; font-size: 11px; margin: 8px 0 0 0; font-style: italic;">${tr.stockReminder.repeatDailyNote}</p>` : ""}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user