From 260569e6ab928e213b59feeaa4766dd315f80985 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Tue, 25 Jun 2024 01:02:10 +0300 Subject: [PATCH] allow sending push to unanswered publishers; comment dangerous admin functions --- components/PwaManager.tsx | 107 +++++++++++++++++++------------ components/survey/SurveyForm.tsx | 43 +++++++++++++ pages/api/notify.ts | 23 ++++--- pages/cart/calendar/index.tsx | 29 +++++---- 4 files changed, 143 insertions(+), 59 deletions(-) diff --git a/components/PwaManager.tsx b/components/PwaManager.tsx index 5fe808f..464afda 100644 --- a/components/PwaManager.tsx +++ b/components/PwaManager.tsx @@ -35,6 +35,7 @@ function PwaManager({ subs }) { useEffect(() => { if (isSupported()) { setNotificationPermission(Notification.permission); + getSubscriptionCount(); } // Handle Push Notification Subscription @@ -77,6 +78,10 @@ function PwaManager({ subs }) { window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt); window.removeEventListener('appinstalled', handleAppInstalled); }; + + + + }, []); @@ -127,6 +132,7 @@ function PwaManager({ subs }) { throw new Error("Failed to fetch VAPID public key from server."); } } + const sub = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: common.base64ToUint8Array(vapidPublicKey) @@ -197,6 +203,19 @@ function PwaManager({ subs }) { } }; + 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(); @@ -243,48 +262,56 @@ function PwaManager({ subs }) { headers: { 'Content-Type': 'application/json' }, - //sends test notification to the current subscription - // body: JSON.stringify({ subscription }) - //sends test notification to all subscriptions of this user - body: JSON.stringify({ id: session.user.id, title: "Тестово уведомление", message: "Това е тестово уведомление" }) + body: JSON.stringify( + { + id: session.user.id, + title: "Тестово уведомление", + message: "Това е тестово уведомление", + actions: [{ action: 'test', title: 'Тест', icon: '✅' }, + { action: 'close', title: 'Затвори', icon: '❌' }] + }) }); }; - async function sendTestReminder(event: MouseEvent): Promise { - event.preventDefault(); - if (!subscription) { - console.error('Web push not subscribed'); - return; - } + // 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'" }) - }); - } + // 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; - } + // 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({ - broadcast: true, message: "Брат ТЕСТ търси заместник за 24-ти май от 10:00 ч. Можеш ли да го покриеш?", - //use fontawesome icons for actions - actions: [{ action: 'covermeaccepted', title: 'Да ', icon: '✅' }] - }) - }); - } + // 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(); @@ -358,22 +385,22 @@ function PwaManager({ subs }) { {isAdmin &&
- - + */}
} {notificationPermission !== "granted" && ( diff --git a/components/survey/SurveyForm.tsx b/components/survey/SurveyForm.tsx index 60c3ace..25f4373 100644 --- a/components/survey/SurveyForm.tsx +++ b/components/survey/SurveyForm.tsx @@ -203,6 +203,29 @@ const SurveyForm: React.FC = ({ existingItem }) => { (err) => alert('Не успяхме да копираме имената: ', err) ); }; + const sendIndividualNotification = async (id, message) => { + const response = await fetch('/api/notify', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + id, + title: 'Нямаме отговор', + message: `${message}`, + }) + }); + + if (response.ok) { + console.log(`Notification sent successfully to ${name}`); + } else { + console.error(`Failed to send notification to ${name}`); + } + }; + + const handleSendNotificationsToAllUnanswered = async (message) => { + getIdsForUnanswered().forEach((id, index) => sendIndividualNotification(id, message)); + }; return (
@@ -281,6 +304,26 @@ const SurveyForm: React.FC = ({ existingItem }) => { {item.messages ? item.messages.filter((message) => !message.answer).length : 0}
+ +
+ {getIdsForUnanswered().map((id) => { + const pub = pubs.find((p) => p.id === id); + const name = pub ? `${pub.firstName} ${pub.lastName}` : '???'; + return ( + + ); + })} +
)} diff --git a/pages/api/notify.ts b/pages/api/notify.ts index f554728..e97bde5 100644 --- a/pages/api/notify.ts +++ b/pages/api/notify.ts @@ -33,19 +33,21 @@ const Notification = async (req, res) => { select: { pushSubscription: true } }); subs = Array.isArray(publisher.pushSubscription) ? publisher.pushSubscription.length : (publisher.pushSubscription ? 1 : 0); + res.send({ subs }) res.end() return + } else { + // send the public key in the response headers + //res.setHeader('Content-Type', 'text/plain') + res.send({ pk: process.env.NEXT_PUBLIC_WEB_PUSH_PUBLIC_KEY, subs }) + res.end() } - // send the public key in the response headers - //res.setHeader('Content-Type', 'text/plain') - res.send({ pk: process.env.NEXT_PUBLIC_WEB_PUSH_PUBLIC_KEY, subs }) - res.end() } if (req.method == 'PUT') { // store the subscription object in the database // publisher.pushSubscription = subscription const prisma = common.getPrismaClient(); - const { subscription, id } = req.body + const { subscription, id, name } = req.body const publisher = await prisma.publisher.findUnique({ where: { id }, select: { pushSubscription: true } @@ -105,14 +107,19 @@ const Notification = async (req, res) => { if (req.method == 'POST') {//title = "ССС", message = "Ще получите уведомление по този начин.") - const { subscription, id, broadcast, title = 'ССОМ', message = 'Ще получавате уведомления така.', actions } = req.body + const { subscription, id, ids, broadcast, title = 'ССОМ', message = 'Ще получавате уведомления така.', actions } = req.body if (broadcast) { await broadcastPush(title, message, actions) res.statusCode = 200 res.end() return - } - else if (id) { + } else if (ids && ids.length) { + console.log('Sending push notifications to publishers ', ids); + await Promise.all(ids.map(_id => sendPush(_id, title, message, actions))); + res.statusCode = 200; + res.end(); + return; + } else if (id) { console.log('Sending push notification to publisher ', id) await sendPush(id, title, message, actions) res.statusCode = 200 diff --git a/pages/cart/calendar/index.tsx b/pages/cart/calendar/index.tsx index 4a04176..6148d6e 100644 --- a/pages/cart/calendar/index.tsx +++ b/pages/cart/calendar/index.tsx @@ -834,18 +834,25 @@ export default function CalendarPage({ initialEvents, initialShifts }) { 'Content-Type': 'application/json' }, body: JSON.stringify({ - id: pub.id, message: "Тестово съобщение", title: "Това е тестово съобщение от https://sofia.mwitnessing.com", actions: [ - { - action: 'open_url', - title: 'Open URL', - icon: '/images/open-url.png' - }, - { - action: 'dismiss', - title: 'Dismiss', - icon: '/images/dismiss.png' - } + 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' + // } + // ] }) }) }}