hellth-hub/apps/admin/app/_components/reminder-runner.tsx

87 lines
2.6 KiB
TypeScript
Raw Normal View History

"use client";
import { useEffect, useRef } from "react";
import { useSession } from "@/lib/auth-client";
import { ReminderKind, loadHellthData } from "@/lib/hellth-data";
const labels: Record<ReminderKind, string> = {
water: "Wasser",
snack: "Snack",
movement: "Bewegung",
};
function minutesOfDay(value: string) {
const [hours = "0", minutes = "0"] = value.split(":");
return Number(hours) * 60 + Number(minutes);
}
function canNotifyNow(startTime: string, endTime: string) {
const now = new Date();
const current = now.getHours() * 60 + now.getMinutes();
return current >= minutesOfDay(startTime) && current <= minutesOfDay(endTime);
}
async function showReminder(kind: ReminderKind, message: string) {
if (typeof window === "undefined" || !("Notification" in window)) return;
if (Notification.permission !== "granted") return;
const title = `Hellth Hub: ${labels[kind]}`;
if ("serviceWorker" in navigator) {
try {
const registration = await navigator.serviceWorker.ready;
await registration.showNotification(title, {
body: message,
tag: `hellth-${kind}`,
badge: "/icon-192.png",
});
return;
} catch {
// Fall through to regular notification.
}
}
new Notification(title, { body: message, tag: `hellth-${kind}` });
}
export function ReminderRunner() {
const { data: session } = useSession();
const userKey = session?.user?.id ?? session?.user?.email ?? null;
const lastSentRef = useRef<Record<string, number>>({});
useEffect(() => {
if (!("serviceWorker" in navigator)) return;
void navigator.serviceWorker.register("/hellth-sw.js").catch(() => undefined);
}, []);
useEffect(() => {
if (!userKey) return;
function tick() {
const data = loadHellthData(userKey);
const reminders = data.reminders;
if (!reminders.enabled) return;
if (typeof Notification === "undefined" || Notification.permission !== "granted") return;
const now = Date.now();
(Object.keys(reminders.rules) as ReminderKind[]).forEach((kind) => {
const rule = reminders.rules[kind];
if (!rule.enabled) return;
if (!canNotifyNow(rule.startTime, rule.endTime)) return;
const lastSentKey = `${userKey}:${kind}`;
const lastSent = lastSentRef.current[lastSentKey] ?? 0;
if (now - lastSent < rule.intervalMinutes * 60_000) return;
lastSentRef.current[lastSentKey] = now;
void showReminder(kind, rule.message);
});
}
tick();
const interval = window.setInterval(tick, 60_000);
return () => window.clearInterval(interval);
}, [userKey]);
return null;
}