Upload via GUI (16 Dateien)

This commit is contained in:
2026-09-14 18:57:05 +00:00
parent 6733901d99
commit 98d23de73f
16 changed files with 1930 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
// reminders.js — native OS notifications for upcoming appointments.
// Checks once a minute; fires once per appointment when it enters the lead window
// (default 30 min before start_time, configurable via the "reminderLeadMinutes" setting).
"use strict";
const { Notification, BrowserWindow } = require("electron");
const db = require("./db");
const CHECK_INTERVAL_MS = 60 * 1000;
const DEFAULT_LEAD_MINUTES = 30;
const notified = new Set(); // appointment ids already notified
function pad(n) {
return String(n).padStart(2, "0");
}
function isoToday() {
const d = new Date();
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
}
function leadMinutes() {
const raw = db.getSetting("reminderLeadMinutes");
const n = raw ? Number(raw) : NaN;
return Number.isFinite(n) && n > 0 ? n : DEFAULT_LEAD_MINUTES;
}
function checkNow() {
if (!Notification.isSupported()) return;
let appointments;
try {
appointments = db.listAppointments(isoToday(), isoToday());
} catch {
return; // db not ready yet
}
const lead = leadMinutes();
const now = new Date();
for (const appt of appointments) {
if (!appt.start_time || notified.has(appt.id)) continue;
const [h, m] = appt.start_time.split(":").map(Number);
if (Number.isNaN(h) || Number.isNaN(m)) continue;
const start = new Date();
start.setHours(h, m, 0, 0);
const minutesUntil = (start - now) / 60000;
// Fire once the appointment enters the lead window, and up to 2 min after its
// start (covers the case where the app was closed/asleep right at the moment).
if (minutesUntil <= lead && minutesUntil >= -2) {
notified.add(appt.id);
const who = appt.animalName ? ` ${appt.animalName}${appt.ownerName ? " (" + appt.ownerName + ")" : ""}` : "";
const title = minutesUntil > 1 ? `Termin in ${Math.round(minutesUntil)} Min.` : "Termin jetzt";
const n = new Notification({
title,
body: `${appt.title}${who}${appt.location ? "\n" + appt.location : ""}`,
});
n.on("click", () => {
const win = BrowserWindow.getAllWindows()[0];
if (win) {
win.show();
win.focus();
}
});
n.show();
}
}
}
let timer = null;
function start() {
if (timer) return;
checkNow();
timer = setInterval(checkNow, CHECK_INTERVAL_MS);
}
function stop() {
if (timer) clearInterval(timer);
timer = null;
}
module.exports = { start, stop };