pwa manager in settings
This commit is contained in:
227
components/PwaManager.tsx
Normal file
227
components/PwaManager.tsx
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
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/notification', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ subscription })
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<h1>PWA Manager</h1>
|
||||||
|
{!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>App is running in standalone mode!</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;
|
@ -6,6 +6,7 @@ import Link from "next/link";
|
|||||||
import axiosInstance from '../../src/axiosSecure';
|
import axiosInstance from '../../src/axiosSecure';
|
||||||
//import { getDate } from "date-fns";
|
//import { getDate } from "date-fns";
|
||||||
|
|
||||||
|
import PwaManager from "../PwaManager";
|
||||||
import { monthNamesBG, GetTimeFormat, GetDateFormat } from "../../src/helpers/const"
|
import { monthNamesBG, GetTimeFormat, GetDateFormat } from "../../src/helpers/const"
|
||||||
import PublisherSearchBox from './PublisherSearchBox';
|
import PublisherSearchBox from './PublisherSearchBox';
|
||||||
import AvailabilityList from "../availability/AvailabilityList";
|
import AvailabilityList from "../availability/AvailabilityList";
|
||||||
@ -241,16 +242,28 @@ export default function PublisherForm({ item, me }) {
|
|||||||
<input type="text" id="town" name="town" value={publisher.town} onChange={handleChange} className="textbox" placeholder="Град" autoFocus />
|
<input type="text" id="town" name="town" value={publisher.town} onChange={handleChange} className="textbox" placeholder="Град" autoFocus />
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
|
{/* notifications */}
|
||||||
<div className="form-check">
|
<div className="form-check">
|
||||||
<input className="checkbox" type="checkbox" id="isSubscribedToCoverMe" name="isSubscribedToCoverMe" onChange={handleChange} checked={publisher.isSubscribedToCoverMe} autoComplete="off" />
|
<input className="checkbox" type="checkbox" id="isSubscribedToCoverMe" name="isSubscribedToCoverMe" onChange={handleChange} checked={publisher.isSubscribedToCoverMe} autoComplete="off" />
|
||||||
<label className="label" htmlFor="isSubscribedToCoverMe">Абониран за имейли за заместване</label>
|
<label className="label" htmlFor="isSubscribedToCoverMe">Абониран за имейли за заместване</label>
|
||||||
<input className="checkbox" type="checkbox" id="isSubscribedToReminders" name="isSubscribedToReminders" onChange={handleChange} checked={publisher.isSubscribedToReminders} autoComplete="off" />
|
<input className="checkbox" type="checkbox" id="isSubscribedToReminders" name="isSubscribedToReminders" onChange={handleChange} checked={publisher.isSubscribedToReminders} autoComplete="off" />
|
||||||
<label className="label" htmlFor="isSubscribedToReminders">Абониран за напомняния (имейл)</label>
|
<label className="label" htmlFor="isSubscribedToReminders">Абониран за напомняния (имейл)</label>
|
||||||
|
{/* prompt to install PWA */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* button to install PWA */}
|
||||||
|
{/* <div className="mb-4">
|
||||||
|
<button className="button bg-blue-500 hover:bg-blue-700 focus:outline-none focus:shadow-outline" type="button" onClick={() => window.installPWA()}>
|
||||||
|
Инсталирай приложението
|
||||||
|
</div> */}
|
||||||
|
|
||||||
|
|
||||||
{/* ADMINISTRATORS ONLY */}
|
{/* ADMINISTRATORS ONLY */}
|
||||||
<ProtectedRoute allowedRoles={[UserRole.ADMIN]} deniedMessage=" " className="">
|
<ProtectedRoute allowedRoles={[UserRole.ADMIN]} deniedMessage=" " className="">
|
||||||
|
|
||||||
|
<PwaManager />
|
||||||
|
|
||||||
<div className="border border-blue-500 border-solid p-2">
|
<div className="border border-blue-500 border-solid p-2">
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label className="label" htmlFor="type">Тип</label>
|
<label className="label" htmlFor="type">Тип</label>
|
||||||
@ -292,10 +305,7 @@ export default function PublisherForm({ item, me }) {
|
|||||||
{/* Add other roles as needed */}
|
{/* Add other roles as needed */}
|
||||||
</select>
|
</select>
|
||||||
</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>
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
{/* ---------------------------- Actions --------------------------------- */}
|
{/* ---------------------------- Actions --------------------------------- */}
|
||||||
|
Reference in New Issue
Block a user