"use client" import { useState, useEffect } from "react" import { Bell, BellOff, Loader2, AlertTriangle } from "lucide-react" import { toast } from "sonner" import { subscribeUser, unsubscribeUser, getVapidPublicKey } from "@/app/actions/subscription" import { Button } from "@/components/ui/button" function urlBase64ToUint8Array(base64String: string) { try { const padding = '='.repeat((4 - base64String.length % 4) % 4) const base64 = (base64String + padding) .replace(/\-/g, '+') .replace(/_/g, '/') const rawData = window.atob(base64) const outputArray = new Uint8Array(rawData.length) for (let i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i) } return outputArray } catch (e) { console.error("VAPID Key conversion failed", e) throw new Error("Invalid VAPID Key format") } } export function PushSubscriptionSettings({ planId }: { planId: string }) { const [isSupported, setIsSupported] = useState(false) const [subscription, setSubscription] = useState(null) const [loading, setLoading] = useState(false) const [debugInfo, setDebugInfo] = useState(null) const [vapidKey, setVapidKey] = useState(null) useEffect(() => { async function checkSupport() { const checks = [] if (!('serviceWorker' in navigator)) checks.push("No Service Worker support") if (!('PushManager' in window)) checks.push("No PushManager support") try { const key = await getVapidPublicKey() if (!key) { checks.push("Missing VAPID Key (Server)") } else { setVapidKey(key) } } catch (e) { checks.push("Failed to fetch VAPID Key") } if (checks.length === 0) { setIsSupported(true) registerServiceWorker() } else { console.warn("Push not supported:", checks.join(", ")) setDebugInfo(checks.join(", ")) } } checkSupport() }, []) async function registerServiceWorker() { try { // Explicitly register the service worker const registration = await navigator.serviceWorker.register('/push-sw.js') // Wait for it to be ready await navigator.serviceWorker.ready const sub = await registration.pushManager.getSubscription() setSubscription(sub) } catch (e: any) { console.error("SW registration error", e) setDebugInfo(`SW Error: ${e.message}`) } } async function subscribe() { if (!vapidKey) { toast.error("VAPID Key missing") return } setLoading(true) setDebugInfo(null) try { console.log("Requesting permission...") const permission = await Notification.requestPermission() console.log("Permission result:", permission) if (permission === 'denied') { toast.error("Notifications are blocked in your browser settings.") setLoading(false) return } if (permission !== 'granted') { toast.error("Notifications permission not granted.") setLoading(false) return } console.log("Waiting for SW ready...") const registration = await navigator.serviceWorker.ready console.log("SW Ready. Subscribing...") const sub = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(vapidKey) }) console.log("Subscribed locally:", sub) setSubscription(sub) await subscribeUser(planId, sub.toJSON()) toast.success("Push Notifications enabled") } catch (error: any) { console.error("Subscription failed", error) setDebugInfo(`Error: ${error.message || "Unknown error"}`) toast.error("Failed to enable notifications. See debug info.") } finally { setLoading(false) } } async function unsubscribe() { setLoading(true) try { if (subscription) { await subscription.unsubscribe() await unsubscribeUser(subscription.endpoint) setSubscription(null) toast.success("Notifications disabled") } } catch (error) { console.error(error) toast.error("Failed to disable.") } finally { setLoading(false) } } if (!isSupported && !debugInfo) return null return (

Device Notifications

Receive updates on this device

{subscription ? ( ) : ( )}
{debugInfo && (
{debugInfo}
)}
) }