229 lines
8.6 KiB
TypeScript
229 lines
8.6 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
||
import common from '../src/helpers/common'; // Ensure this path is correct
|
||
|
||
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);
|
||
|
||
// 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) => {
|
||
|
||
e.preventDefault();
|
||
if (deferredPrompt) {
|
||
deferredPrompt.prompt();
|
||
const { outcome } = await deferredPrompt.userChoice;
|
||
if (outcome === 'accepted') {
|
||
setIsPWAInstalled(true);
|
||
}
|
||
setDeferredPrompt(null);
|
||
}
|
||
};
|
||
|
||
// Utility function for converting base64 string to Uint8Array
|
||
const base64ToUint8Array = base64 => {
|
||
const padding = '='.repeat((4 - (base64.length % 4)) % 4);
|
||
const b64 = (base64 + padding).replace(/-/g, '+').replace(/_/g, '/');
|
||
const rawData = window.atob(b64);
|
||
const outputArray = new Uint8Array(rawData.length);
|
||
for (let i = 0; i < rawData.length; ++i) {
|
||
outputArray[i] = rawData.charCodeAt(i);
|
||
}
|
||
return outputArray;
|
||
};
|
||
|
||
const subscribeToNotifications = async (e) => {
|
||
|
||
try {
|
||
e.preventDefault();
|
||
if (!registration) {
|
||
console.error('Service worker registration not found.');
|
||
registration
|
||
return;
|
||
}
|
||
const sub = await registration.pushManager.subscribe({
|
||
userVisibleOnly: true,
|
||
applicationServerKey: base64ToUint8Array(process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY)
|
||
});
|
||
// Call your API to save subscription data 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);
|
||
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={subscribeToNotifications}
|
||
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-green-500 hover:bg-green-700 text-white'
|
||
}`}
|
||
>
|
||
Subscribe to Notifications
|
||
</button>
|
||
<button
|
||
onClick={unsubscribeFromNotifications}
|
||
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-red-500 hover:bg-red-700 text-white'
|
||
}`}
|
||
>
|
||
Unsubscribe from 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>
|
||
<
|
||
</>
|
||
);
|
||
|
||
}
|
||
|
||
export default PwaManager;
|