Upload via GUI (16 Dateien)
This commit is contained in:
@@ -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 };
|
||||
Reference in New Issue
Block a user