import React, { useEffect, useState } from 'react'; import common from '../src/helpers/common'; // Ensure this path is correct //use session to get user role import { useSession } from "next-auth/react" import e from 'express'; import ProtectedRoute from './protectedRoute'; import { UserRole } from '@prisma/client'; function PwaManager({ userId, subs }) { //ToDo: for iOS, try to use apn? https://github.com/node-apn/node-apn/blob/master/doc/apn.markdown const isSupported = () => 'Notification' in window && 'serviceWorker' in navigator && 'PushManager' in window const [inProgress, setInProgress] = useState(false) const [deferredPrompt, setDeferredPrompt] = useState(null); const [isPWAInstalled, setIsPWAInstalled] = useState(false); const [isStandAlone, setIsStandAlone] = useState(false); const [isSubscribed, setIsSubscribed] = useState(false); const [subscription, setSubscription] = useState(null); const [registration, setRegistration] = useState(null); const [notificationPermission, setNotificationPermission] = useState(isSupported() && Notification.permission); const [_subs, setSubs] = useState(subs) const { data: session } = useSession(); // let isAdmin = ProtectedRoute.IsInRole(UserRole.ADMIN); let isAdmin = false; if (session) { isAdmin = session.user.role === UserRole.ADMIN; } // Handle PWA installation useEffect(() => { if (isSupported()) { setNotificationPermission(Notification.permission); getSubscriptionCount(); } // Handle Push Notification Subscription if ('serviceWorker' in navigator && 'PushManager' in window) { navigator.serviceWorker.ready.then(swreg => { swreg.pushManager.getSubscription().then(sub => { if (sub) { setSubscription(sub); setIsSubscribed(true); } }); setRegistration(swreg); }); } // Check if the app is running in standalone mode // const isStandalone = window.matchMedia('(display-mode: standalone)').matches; // if (isStandalone) { // console.log('Running in standalone mode'); // setIsPWAInstalled(true); // } if (window.matchMedia('(display-mode: standalone)').matches) { setIsStandAlone(true); } const handleBeforeInstallPrompt = (e) => { e.preventDefault(); setDeferredPrompt(e); }; const handleAppInstalled = () => { setIsPWAInstalled(true); }; window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt); window.addEventListener('appinstalled', handleAppInstalled); return () => { window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt); window.removeEventListener('appinstalled', handleAppInstalled); }; }, []); const installPWA = async (e) => { console.log('Attempting to install PWA'); e.preventDefault(); // Prevent default button action if (deferredPrompt) { console.log('Prompting install'); deferredPrompt.prompt(); const { outcome } = await deferredPrompt.userChoice; console.log('Installation outcome:', outcome); if (outcome === 'accepted') { console.log('User accepted the A2HS prompt'); setIsPWAInstalled(true); } else { console.log('User dismissed the A2HS prompt'); } setDeferredPrompt(null); // Clear the deferred prompt to manage its lifecycle } else { console.log('No deferred prompt available'); } }; const subscribeToNotifications = async (e) => { try { e.preventDefault(); if (!navigator.serviceWorker) { console.error('Service worker is not supported by this browser.'); return; } const registration = await navigator.serviceWorker.ready; if (!registration) { console.error('Service worker registration not found.'); return; } let vapidPublicKey = process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY; if (!vapidPublicKey) { // Fetch the public key from the server if not present in env variables const response = await fetch('/api/notify', { method: 'GET' }); const responseData = await response.json(); vapidPublicKey = responseData.pk; setSubs(responseData.subs); if (!vapidPublicKey) { throw new Error("Failed to fetch VAPID public key from server."); } } const sub = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: common.base64ToUint8Array(vapidPublicKey) }); // Call your API to save subscription data on server if (session.user?.id != null) { await fetch(`/api/notify`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ subscription: sub, id: session.user.id }) }).then(async response => { if (!response.ok) { //throw new Error('Failed to save subscription data on server.'); console.log('Failed to save subscription data on server.'); } else { console.log('Subscription data saved on server.'); const s = await response.json(); setSubs(s.subs); setSubscription(sub); setIsSubscribed(true); console.log('Web push subscribed!'); } }); } console.log(sub); } catch (error) { console.error('Error subscribing to notifications:', error); } }; const unsubscribeFromNotifications = async (e) => { try { e.preventDefault(); if (subscription) { await subscription.unsubscribe(); // Call your API to delete or invalidate subscription data on server setSubscription(null); setIsSubscribed(false); if (session?.user?.id != null) { await fetch(`/api/notify`, { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, //send the current subscription to be removed body: JSON.stringify({ id: session.user.id, subscriptionId: subscription.endpoint }) } ).then(async (response) => { if (!response.ok) { throw new Error('Failed to delete subscription data on server.'); } else { console.log('Subscription data deleted on server.'); const s = await response.json(); setSubs(s.subs); } }); } console.log('Web push unsubscribed!'); } } catch (error) { console.error('Error unsubscribing from notifications:', error); } }; const getSubscriptionCount = async () => { try { const response = await fetch('/api/notify?id=' + session.user.id, { method: 'GET' }); if (!response.ok) { throw new Error('Failed to fetch subscription data.'); } const result = await response.json(); setSubs(result.subs); } catch (error) { console.error('Error fetching subscription data:', error); } }; // Function to request push notification permission const requestNotificationPermission = async (e) => { e.preventDefault(); if (isSupported()) { const permission = await Notification.requestPermission(); setNotificationPermission(permission); if (permission === "granted") { // User granted permission subscribeToNotifications(null); // Pass the required argument here } else { // User denied or dismissed permission console.log("Push notifications permission denied."); } } else { console.error('Web push not supported'); } }; // Function to toggle push notifications const togglePushNotifications = async (e) => { e.preventDefault(); if (notificationPermission === "granted") { // If already subscribed, unsubscribe unsubscribeFromNotifications(null); // Pass null as the argument } else if (notificationPermission === "default" || notificationPermission === "denied") { // Request permission if not already granted await requestNotificationPermission(e); } }; const sendTestNotification = async (e) => { e.preventDefault(); if (!subscription) { console.error('Web push not subscribed'); return; } await fetch('/api/notify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify( { id: session.user.id, title: "Тестово уведомление", message: "Това е тестово уведомление", actions: [{ action: 'test', title: 'Тест', icon: '✅' }, { action: 'close', title: 'Затвори', icon: '❌' }] }) }); /* await fetch('/api/notify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id: pub.id, message: "Тестово съобщение", title: "Това е тестово съобщение от https://sofia.mwitnessing.com", actions: [ { action: 'OK', title: 'OK', icon: '✅' }, { action: 'close', title: 'Затвори', icon: '❌' } ] // actions: [ // { // title: 'Open URL', // action: 'open_url', // icon: '/images/open-url.png' // }, // { // title: 'Dismiss', // action: 'dismiss', // icon: '/images/dismiss.png' // } // ] }) }) */ }; // async function sendTestReminder(event: MouseEvent): Promise { // event.preventDefault(); // if (!subscription) { // console.error('Web push not subscribed'); // return; // } // await fetch('/api/notify', { // method: 'POST', // headers: { // 'Content-Type': 'application/json' // }, // body: JSON.stringify({ // broadcast: true, // message: "Мили братя, искаме да ви напомним да ни изпратите вашите предпочитания за юни до 25-то число като използвате меню 'Възможности'. Ако имате проблем, моля пишете ни на 'specialnosvidetelstvanesofia@gmail.com'" // }) // }); // } // async function sendTestCoverMe(event: MouseEvent): Promise { // event.preventDefault(); // if (!subscription) { // console.error('Web push not subscribed'); // return; // } // await fetch('/api/notify', { // method: 'POST', // headers: { // 'Content-Type': 'application/json' // }, // body: JSON.stringify({ // id: session.user.id, // message: "Брат ТЕСТ търси заместник за 24-ти май от 10:00 ч. Можеш ли да го покриеш?", // //use fontawesome icons for actions // actions: [{ action: 'covermeaccepted', title: 'Да ', icon: '✅' }] // }) // }); // } async function deleteAllSubscriptions(event: MouseEvent): Promise { event.preventDefault(); await fetch(`/api/notify`, { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, //send the current subscription to be removed body: JSON.stringify({ id: session.user.id }) } ).then(async response => { if (!response.ok) { throw new Error('Failed to delete subscription data on server.'); } else { console.log('ALL subscriptions data deleted on server.'); if (subscription) { await subscription.unsubscribe(); } setSubs(""); setSubscription(null); setIsSubscribed(false); } }); } if (!isSupported()) { return (

Това устройство не поддържа нотификации

); } else { return ( <>

{isAdmin && " PWA (admin)"}

{!isStandAlone && !isPWAInstalled && ( )} {isPWAInstalled &&

Инсталирано!

} {/* {isStandAlone &&

PWA App

} */}
{isAdmin &&
{/* */} {/* */}
} { notificationPermission !== "granted" && ( ) } { isAdmin && } ); } } export default PwaManager; //get server side props - subs count export const getServerSideProps = async (context) => { //ToDo: get the number of subscriptions from the database return { props: { subs: 0 } } }