265 lines
10 KiB
TypeScript
265 lines
10 KiB
TypeScript
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"
|
||
|
||
function PwaManager() {
|
||
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(Notification.permission);
|
||
|
||
const { data: session } = useSession();
|
||
|
||
// Handle PWA installation
|
||
useEffect(() => {
|
||
|
||
setNotificationPermission(Notification.permission);
|
||
|
||
// Handle Push Notification Subscription
|
||
if ('serviceWorker' in navigator && 'PushManager' in window) {
|
||
navigator.serviceWorker.ready.then(reg => {
|
||
reg.pushManager.getSubscription().then(sub => {
|
||
if (sub) {
|
||
setSubscription(sub);
|
||
setIsSubscribed(true);
|
||
}
|
||
});
|
||
setRegistration(reg);
|
||
});
|
||
}
|
||
|
||
|
||
|
||
// Check if the app is running in standalone mode
|
||
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('installing PWA');
|
||
e.preventDefault();
|
||
if (deferredPrompt) {
|
||
deferredPrompt.prompt();
|
||
const { outcome } = await deferredPrompt.userChoice;
|
||
if (outcome === 'accepted') {
|
||
setIsPWAInstalled(true);
|
||
}
|
||
setDeferredPrompt(null);
|
||
}
|
||
};
|
||
|
||
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' });
|
||
vapidPublicKey = await response.text();
|
||
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(response => {
|
||
if (!response.ok) {
|
||
throw new Error('Failed to save subscription data on server.');
|
||
}
|
||
else {
|
||
console.log('Subscription data saved on server.');
|
||
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();
|
||
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'
|
||
},
|
||
body: JSON.stringify({ id: session?.user.id }),
|
||
}
|
||
).then(response => {
|
||
if (!response.ok) {
|
||
throw new Error('Failed to delete subscription data on server.');
|
||
}
|
||
else {
|
||
console.log('Subscription data deleted on server.');
|
||
}
|
||
});
|
||
}
|
||
console.log('Web push unsubscribed!');
|
||
} catch (error) {
|
||
console.error('Error unsubscribing from notifications:', error);
|
||
}
|
||
};
|
||
|
||
// Function to request push notification permission
|
||
const requestNotificationPermission = async (e) => {
|
||
e.preventDefault();
|
||
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.");
|
||
}
|
||
};
|
||
|
||
// 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({ subscription })
|
||
});
|
||
};
|
||
|
||
return (
|
||
<>
|
||
<div>
|
||
<h1>PWA Manager</h1>
|
||
{!isStandAlone && !isPWAInstalled && (
|
||
<button
|
||
onClick={installPWA}
|
||
className="bg-blue-500 hover:bg-blue-700 text-white text-xs py-1 px-2 rounded-full focus:outline-none focus:shadow-outline transition duration-150 ease-in-out"
|
||
>
|
||
Install PWA
|
||
</button>
|
||
)}
|
||
{isPWAInstalled && <p>App is installed!</p>}
|
||
{isStandAlone && <p>PWA App</p>}
|
||
<button
|
||
onClick={isSubscribed ? unsubscribeFromNotifications : subscribeToNotifications}
|
||
disabled={false} // Since the button itself acts as a toggle, the disabled attribute might not be needed
|
||
className={`text-xs py-1 px-2 rounded-full focus:outline-none transition duration-150 ease-in-out ${isSubscribed ? 'bg-red-500 hover:bg-red-700 text-white' : 'bg-green-500 hover:bg-green-700 text-white'
|
||
}`}
|
||
>
|
||
{isSubscribed ? 'Unsubscribe from Notifications' : 'Subscribe to Notifications'}
|
||
</button>
|
||
|
||
</div >
|
||
<div>
|
||
<button
|
||
onClick={sendTestNotification}
|
||
disabled={!isSubscribed}
|
||
className={`text-xs py-1 px-2 rounded-full focus:outline-none transition duration-150 ease-in-out ${!isSubscribed ? 'cursor-not-allowed bg-gray-300 text-gray-500' : 'bg-yellow-500 hover:bg-yellow-600 text-white'
|
||
}`}
|
||
>
|
||
Send Test Notification
|
||
</button>
|
||
|
||
{notificationPermission !== "granted" && (
|
||
<button
|
||
onClick={togglePushNotifications}
|
||
className={`text-xs py-1 px-2 rounded-full focus:outline-none transition duration-150 ease-in-out ${notificationPermission === "denied" ? 'bg-red-500 hover:bg-red-700 text-white' : 'bg-green-500 hover:bg-green-700 text-white'
|
||
}`}
|
||
>
|
||
{notificationPermission === "denied" ? 'Notifications Denied!' : 'Enable Notifications'}
|
||
</button>
|
||
)}
|
||
</div>
|
||
<div>
|
||
<a href="https://t.me/mwhitnessing_bot" className="inline-flex items-center ml-4" target="_blank">
|
||
<img src="/content/icons/telegram-svgrepo-com.svg" alt="Телеграм" width="32" height="32" className="align-middle" />
|
||
<span className="align-middle">Телеграм</span>
|
||
</a>
|
||
</div>
|
||
<div>
|
||
<a href="/api/auth/apple-signin" className="inline-flex items-center ml-4" target="_blank">
|
||
<span className="align-middle">Apple sign-in</span>
|
||
</a>
|
||
</div>
|
||
</>
|
||
);
|
||
|
||
}
|
||
|
||
export default PwaManager;
|