(wip) PWA Push Notifications
This commit is contained in:
@ -26,26 +26,47 @@ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'
|
||||
// appleWebApp: true,
|
||||
// }
|
||||
|
||||
// (custom) Service worker registration and push notification logic
|
||||
// function registerServiceWorkerAndPushNotifications() {
|
||||
// useEffect(() => {
|
||||
// const registerServiceWorker = async () => {
|
||||
// if ('serviceWorker' in navigator) {
|
||||
// try {
|
||||
// const registration = await navigator.serviceWorker.register('/worker/index.js')
|
||||
// .then((registration) => console.log('reg: ', registration));
|
||||
// } catch (error) {
|
||||
// console.log('Service Worker registration failed:', error);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
// const askForNotificationPermission = async () => {
|
||||
// if ('serviceWorker' in navigator && 'PushManager' in window) {
|
||||
// try {
|
||||
// const permission = await Notification.requestPermission();
|
||||
// if (permission === 'granted') {
|
||||
// console.log('Notification permission granted.');
|
||||
// // TODO: Subscribe the user to push notifications here
|
||||
// } else {
|
||||
// console.log('Notification permission not granted.');
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('Error during service worker registration:', error);
|
||||
// }
|
||||
// } else {
|
||||
// console.log('Service Worker or Push notifications not supported in this browser.');
|
||||
// }
|
||||
// };
|
||||
|
||||
// registerServiceWorker();
|
||||
// askForNotificationPermission();
|
||||
// }, []);
|
||||
// }
|
||||
|
||||
//function SmwsApp({ Component, pageProps: { locale, messages, session, ...pageProps }, }: AppProps<{ session: Session }>) {
|
||||
function SmwsApp({ Component, pageProps, session, locale, messages }) {
|
||||
// dynamic locale loading using our API endpoint
|
||||
// const [locale, setLocale] = useState(_locale);
|
||||
// const [messages, setMessages] = useState(_messages);
|
||||
// useEffect(() => {
|
||||
// async function loadLocaleData() {
|
||||
// const res = await fetch(`/api/translations/${locale}`);
|
||||
// if (res.ok) {
|
||||
// const localeMessages = await res.json();
|
||||
// console.log("Loaded messages for locale:", locale, localeMessages);
|
||||
// setMessages(localeMessages);
|
||||
// } else {
|
||||
// const localeMessages = await import(`../content/i18n/${locale}.json`); setMessages(localeMessages.default);
|
||||
// }
|
||||
// console.log("locale set to'", locale, "' ",);
|
||||
// }
|
||||
// loadLocaleData();
|
||||
// }, [locale]);
|
||||
|
||||
//registerServiceWorkerAndPushNotifications();
|
||||
|
||||
useEffect(() => {
|
||||
const use = async () => {
|
||||
|
@ -1,6 +1,8 @@
|
||||
|
||||
const webPush = require('web-push')
|
||||
|
||||
import common from '../../src/helpers/common';
|
||||
|
||||
//generate and store VAPID keys in .env.local if not already done
|
||||
if (!process.env.NEXT_PUBLIC_WEB_PUSH_PUBLIC_KEY || !process.env.WEB_PUSH_PRIVATE_KEY) {
|
||||
const { publicKey, privateKey } = webPush.generateVAPIDKeys()
|
||||
@ -28,28 +30,66 @@ const Notification = async (req, res) => {
|
||||
res.end(process.env.NEXT_PUBLIC_WEB_PUSH_PUBLIC_KEY)
|
||||
res.end()
|
||||
}
|
||||
// on PUT store the subscription object in the database
|
||||
if (req.method == 'PUT') {
|
||||
// store the subscription object in the database
|
||||
// publisher.pushSubscription = subscription
|
||||
const prisma = common.getPrismaClient();
|
||||
const { subscription, id } = req.body
|
||||
const publisher = await prisma.publisher.update({
|
||||
where: { id },
|
||||
data: { pushSubscription: subscription }
|
||||
})
|
||||
console.log('Subscription for publisher', id, 'updated:', subscription)
|
||||
res.statusCode = 200
|
||||
res.end()
|
||||
}
|
||||
if (req.method == 'DELETE') {
|
||||
// remove the subscription object from the database
|
||||
// publisher.pushSubscription = null
|
||||
const prisma = common.getPrismaClient();
|
||||
const { id } = req.body
|
||||
const publisher = await prisma.publisher.update({
|
||||
where: { id },
|
||||
data: { pushSubscription: null }
|
||||
})
|
||||
console.log('Subscription for publisher', id, 'deleted')
|
||||
res.statusCode = 200
|
||||
res.end()
|
||||
}
|
||||
|
||||
|
||||
if (req.method == 'POST') {
|
||||
const { subscription } = req.body
|
||||
|
||||
await webPush
|
||||
.sendNotification(
|
||||
subscription,
|
||||
JSON.stringify({ title: 'Hello Web Push', message: 'Your web push notification is here!' })
|
||||
)
|
||||
.then(response => {
|
||||
res.writeHead(response.statusCode, response.headers).end(response.body)
|
||||
})
|
||||
.catch(err => {
|
||||
if ('statusCode' in err) {
|
||||
res.writeHead(err.statusCode, err.headers).end(err.body)
|
||||
} else {
|
||||
console.error(err)
|
||||
res.statusCode = 500
|
||||
res.end()
|
||||
}
|
||||
})
|
||||
const { subscription, id, broadcast, title = 'Hello Web Push', message = 'Your web push notification is here!' } = req.body
|
||||
if (broadcast) {
|
||||
await broadcastPush(title, message)
|
||||
res.statusCode = 200
|
||||
res.end()
|
||||
return
|
||||
}
|
||||
else if (id) {
|
||||
await sendPush(id, title, message)
|
||||
res.statusCode = 200
|
||||
res.end()
|
||||
return
|
||||
} else if (subscription) {
|
||||
await webPush
|
||||
.sendNotification(
|
||||
subscription,
|
||||
JSON.stringify({ title, message })
|
||||
)
|
||||
.then(response => {
|
||||
res.writeHead(response.statusCode, response.headers).end(response.body)
|
||||
})
|
||||
.catch(err => {
|
||||
if ('statusCode' in err) {
|
||||
res.writeHead(err.statusCode, err.headers).end(err.body)
|
||||
} else {
|
||||
console.error(err)
|
||||
res.statusCode = 500
|
||||
res.end()
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
res.statusCode = 405
|
||||
res.end()
|
||||
@ -57,3 +97,48 @@ const Notification = async (req, res) => {
|
||||
}
|
||||
|
||||
export default Notification
|
||||
|
||||
//export pushNotification(userId or email) for use in other files
|
||||
export const sendPush = async (id, title, message) => {
|
||||
const prisma = common.getPrismaClient();
|
||||
const publisher = await prisma.publisher.findUnique({
|
||||
where: { id }
|
||||
})
|
||||
if (!publisher.pushSubscription) {
|
||||
console.log('No push subscription found for publisher', id)
|
||||
return
|
||||
}
|
||||
|
||||
await webPush
|
||||
.sendNotification(
|
||||
publisher.pushSubscription,
|
||||
JSON.stringify({ title, message })
|
||||
)
|
||||
.then(response => {
|
||||
console.log('Push notification sent to publisher', id)
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Error sending push notification to publisher', id, ':', err)
|
||||
})
|
||||
}
|
||||
//export breoadcastNotification for use in other files
|
||||
export const broadcastPush = async (title, message) => {
|
||||
const prisma = common.getPrismaClient();
|
||||
const publishers = await prisma.publisher.findMany({
|
||||
where: { pushSubscription: { not: null } }
|
||||
})
|
||||
|
||||
for (const publisher of publishers) {
|
||||
await webPush
|
||||
.sendNotification(
|
||||
publisher.pushSubscription,
|
||||
JSON.stringify({ title, message })
|
||||
)
|
||||
.then(response => {
|
||||
console.log('Push notification sent to publisher', publisher.id)
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Error sending push notification to publisher', publisher.id, ':', err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ import { toast } from 'react-toastify';
|
||||
import ProtectedRoute from '../../../components/protectedRoute';
|
||||
import ConfirmationModal from '../../../components/ConfirmationModal';
|
||||
import LocalShippingIcon from '@mui/icons-material/LocalShipping';
|
||||
// import notify api
|
||||
import { sendPush, broadcastPush } from '../../api/notify';
|
||||
const { DateTime } = require('luxon');
|
||||
|
||||
// import { FaPlus, FaCogs, FaTrashAlt, FaSpinner } from 'react-icons/fa'; // Import FontAwesome icons
|
||||
@ -734,7 +736,19 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
|
||||
<span title="участия тази седмица" className={`badge py-1 px-2 rounded-full text-xs ${pub.currentWeekAssignments ? 'bg-yellow-500 text-white' : 'bg-yellow-200 text-gray-400'}`}>{pub.currentWeekAssignments || 0}</span>
|
||||
<span title="участия този месец" className={`badge py-1 px-2 rounded-full text-xs ${pub.currentMonthAssignments ? 'bg-green-500 text-white' : 'bg-green-200 text-gray-400'}`}>{pub.currentMonthAssignments || 0}</span>
|
||||
<span tooltip="участия миналия месец" title="участия миналия месец" className={`badge py-1 px-2 rounded-full text-xs ${pub.previousMonthAssignments ? 'bg-blue-500 text-white' : 'bg-blue-200 text-gray-400'}`}>{pub.previousMonthAssignments || 0}</span>
|
||||
<button tooltip="желани участия този месец" title="желани участия" className={`badge py-1 px-2 rounded-md text-xs ${pub.desiredShiftsPerMonth ? 'bg-purple-500 text-white' : 'bg-purple-200 text-gray-400'}`}>{pub.desiredShiftsPerMonth || 0}</button>
|
||||
<button tooltip="желани участия на месец" title="желани участия" className={`badge py-1 px-2 rounded-md text-xs ${pub.desiredShiftsPerMonth ? 'bg-purple-500 text-white' : 'bg-purple-200 text-gray-400'}`}>{pub.desiredShiftsPerMonth || 0}</button>
|
||||
<button tooltip="push" title="push" className={`badge py-1 px-2 rounded-md text-xs bg-red-100`}
|
||||
onClick={async () => {
|
||||
await fetch('/api/notify', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ broadcast: true, message: "Тестово съобщение", title: "Това е тестово съобщение от https://sofia.mwitnessing.com" })
|
||||
})
|
||||
}}
|
||||
>+</button>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
|
@ -226,8 +226,8 @@ export const getServerSideProps = async (context) => {
|
||||
|
||||
// log first availability startTime to verify timezone and UTC conversion
|
||||
|
||||
console.log("First availability startTime: " + items[0].startTime);
|
||||
console.log("First availability startTime: " + items[0].startTime.toLocaleString());
|
||||
console.log("First availability startTime: " + items[0]?.startTime);
|
||||
console.log("First availability startTime: " + items[0]?.startTime.toLocaleString());
|
||||
|
||||
const prisma = common.getPrismaClient();
|
||||
let cartEvents = await prisma.cartEvent.findMany({
|
||||
|
Reference in New Issue
Block a user