From 3d1d33c2aac15e07c3b840a1fb9428e3feda8330 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Fri, 3 Oct 2025 02:25:55 -0700 Subject: initial firebase fcm implementation --- site/src/components/NotificationButton.tsx | 196 +++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 site/src/components/NotificationButton.tsx (limited to 'site/src/components/NotificationButton.tsx') diff --git a/site/src/components/NotificationButton.tsx b/site/src/components/NotificationButton.tsx new file mode 100644 index 0000000..8f4fb61 --- /dev/null +++ b/site/src/components/NotificationButton.tsx @@ -0,0 +1,196 @@ +import { useState, useEffect } from "react"; +import { messaging, initializeForegroundNotifications } from "../firebase.ts"; +import { getToken, deleteToken } from "firebase/messaging"; + +const VAPID_KEY = + "BK7tpLF5Loy8Ew8bKxhTi-vOEJdxJSnu-jPyagWecLdD_SrEAt_OQS7nu0Xu3hR7AQpn0cOmgcdeeQd5zq5-Gyo"; + +interface NotificationButtonProps { + className?: string; + isMoe?: boolean; +} + +export default function NotificationButton({ className = "", isMoe = false }: NotificationButtonProps) { + const [permission, setPermission] = useState("default"); + const [isRegistered, setIsRegistered] = useState(false); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + useEffect(() => { + // Check initial permission status + setPermission(Notification.permission); + + // Check if service worker is registered + const checkRegistration = async () => { + if ('serviceWorker' in navigator) { + const registration = await navigator.serviceWorker.getRegistration('/firebase-messaging-sw.js'); + setIsRegistered(!!registration); + + // Initialize foreground notifications if already registered + if (registration && Notification.permission === "granted") { + initializeForegroundNotifications(); + } + } + }; + + checkRegistration(); + }, []); + + const handleEnableNotifications = async () => { + setLoading(true); + setError(null); + + try { + const permissionResult = await Notification.requestPermission(); + setPermission(permissionResult); + + if (permissionResult === "granted") { + // Register service worker + const registration = await navigator.serviceWorker.register('/firebase-messaging-sw.js'); + console.log("Service Worker registered:", registration); + const token = await getToken(messaging, { vapidKey: VAPID_KEY }); + console.log("FCM Token:", token); + // Store token locally (you might want to send this to your server) + localStorage.setItem('fcm_token', token); + + // Initialize foreground notification handler + initializeForegroundNotifications(); + + setIsRegistered(true); + } else { + setError("Notification permission was denied"); + } + } catch (err) { + console.error("Error enabling notifications:", err); + setError("Failed to enable notifications. Please try again."); + } finally { + setLoading(false); + } + }; + + const handleDisableNotifications = async () => { + setLoading(true); + setError(null); + + try { + await deleteToken(messaging); + console.log("FCM token deleted"); + localStorage.removeItem('fcm_token'); + if ('serviceWorker' in navigator) { + const registration = await navigator.serviceWorker.getRegistration('/firebase-messaging-sw.js'); + if (registration) { + await registration.unregister(); + console.log("Service Worker unregistered"); + } + } + + setIsRegistered(false); + } catch (err) { + console.error("Error disabling notifications:", err); + setError("Failed to disable notifications. Please try again."); + } finally { + setLoading(false); + } + }; + + // Determine button state and action + const getButtonContent = () => { + if (loading) { + return ( + <> + + + + + {isRegistered ? "Disabling..." : "Enabling..."} + + ); + } + + if (permission === "denied") { + return ( + <> + + + + Notifications Blocked + + ); + } + + if (isRegistered && permission === "granted") { + return ( + <> + + + + Disable Notifications + + ); + } + + return ( + <> + + + + Enable Notifications + + ); + }; + + const handleClick = () => { + if (permission === "denied") { + // Can't re-request permission if denied + alert("Notifications are blocked. Please enable them in your browser settings."); + return; + } + + if (isRegistered && permission === "granted") { + handleDisableNotifications(); + } else { + handleEnableNotifications(); + } + }; + + // Determine button styles + const getButtonStyles = () => { + if (loading || permission === "denied") { + return isMoe + ? `bg-pink-300 cursor-not-allowed opacity-60` + : `bg-gray-600 cursor-not-allowed opacity-60`; + } + + if (isMoe) { + return isRegistered + ? `bg-pink-600 text-white hover:bg-pink-700` + : `bg-pink-500 text-white hover:bg-pink-600`; + } else { + return isRegistered + ? `bg-purple-700 text-white hover:bg-purple-800` + : `bg-purple-600 text-white hover:bg-purple-700`; + } + }; + + return ( +
+ + {error && ( +

+ {error} +

+ )} + {permission === "denied" && ( +

+ To enable notifications, update your browser settings +

+ )} +
+ ); +} -- cgit v1.2.3