"use client"; import { useEffect } from "react"; import { localeHeader } from "@/lib/i18n"; import { buildReminderMessage } from "@/lib/reminder"; import { authHeaders } from "@/lib/settings"; /** * Keeps the reminder text the server holds in step with the notes. * * The reminder is written in the browser (lib/reminder.ts) because the notes * never leave it, and the due cards move all day: a nudge that still says * "3 cards are due" on a morning with nothing due is worse than no nudge. This * refreshes it when the app opens and whenever the tab is visible again, * throttled to twice a day. It does nothing at all when this browser is not * subscribed, has no push support, or the server has reminders switched off. */ const REFRESH_KEY = "freezmo.push.refresh.v1"; const REFRESH_MS = 6 * 60 * 60 * 1000; function fresh(): boolean { try { const at = Number(window.localStorage.getItem(REFRESH_KEY) ?? 0); return Number.isFinite(at) && Date.now() - at < REFRESH_MS; } catch { return false; } } function remember(): void { try { window.localStorage.setItem(REFRESH_KEY, String(Date.now())); } catch { /* private mode */ } } export function PushReminderSync() { useEffect(() => { if (typeof navigator === "undefined" || !("serviceWorker" in navigator) || !("PushManager" in window)) return; if (fresh()) return; let done = false; const sync = async () => { if (done) return; try { const registration = await navigator.serviceWorker.ready; const subscription = await registration.pushManager.getSubscription(); if (!subscription) return; // reminders are off for this browser const message = await buildReminderMessage(); const response = await fetch("/api/push", { method: "POST", headers: { "Content-Type": "application/json", ...authHeaders(), ...localeHeader() }, body: JSON.stringify({ ...subscription.toJSON(), message }), }); if (response.ok) { done = true; remember(); } } catch { /* the stored reminder stays as it is */ } }; void sync(); const onVisible = () => { if (document.visibilityState === "visible") void sync(); }; document.addEventListener("visibilitychange", onVisible); return () => document.removeEventListener("visibilitychange", onVisible); }, []); return null; }