"use client"; /** * PushPrompt — a gentle on-load invitation to enable browser notifications, * shown to signed-in users who haven't decided yet. * * Browsers require a user gesture to request notification permission, so this * is a *soft* ask: the real `Notification.requestPermission()` only fires * when the user taps "Enable". We show it when push is supported, the server * has push configured, permission is still "default", the user isn't already * subscribed, and they haven't recently dismissed it (7-day cooldown). */ import { useEffect, useState } from "react"; import { Bell, X } from "lucide-react"; import { toast } from "sonner"; import { useAuth } from "@/components/auth/auth-provider"; import { enablePush, isPushEnabled, pushConfigured, pushPermission, pushSupported, } from "@/lib/push"; const DISMISS_KEY = "push.prompt.dismissedAt"; const COOLDOWN_MS = 7 * 24 * 60 * 60 * 1000; export function PushPrompt() { const { user, loading } = useAuth(); const [show, setShow] = useState(false); const [busy, setBusy] = useState(false); const userId = user?.id; useEffect(() => { if (loading || !userId) return; let cancelled = false; // Async eligibility check — never setState synchronously in the effect. (async () => { if (!pushSupported() || pushPermission() !== "default") return; const dismissed = Number(window.localStorage.getItem(DISMISS_KEY) || 0); if (dismissed && Date.now() - dismissed < COOLDOWN_MS) return; if (!(await pushConfigured())) return; if (await isPushEnabled()) return; if (!cancelled) setShow(true); })(); return () => { cancelled = true; }; }, [userId, loading]); function dismiss() { window.localStorage.setItem(DISMISS_KEY, String(Date.now())); setShow(false); } async function enable() { setBusy(true); try { await enablePush(); toast.success("Notifications enabled 🙏"); setShow(false); } catch (err) { toast.error(err instanceof Error ? err.message : "Couldn't enable notifications."); // A denial / dismissal shouldn't keep re-prompting. dismiss(); } finally { setBusy(false); } } if (!show) return null; return (

Stay with your sādhana

Turn on notifications for daily reminders, follow requests, and more — even when the app is closed.

); }