From eb6376e41b89696ee48df3278de273430969d419 Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 28 Jul 2024 16:24:16 +0530 Subject: [PATCH] initial config --- frontend/public/manifest.json | 4 +- frontend/public/service-worker.js | 53 +++++++++++++ .../notifications/SlideOverNotifications.jsx | 53 +++++++++++-- frontend/src/index.js | 3 + frontend/src/serviceWorkerRegistration.js | 28 +++++++ .../entity/NotificationSubscription.java | 78 +++++++++++++++++++ src/main/resources/application.properties | 6 ++ .../2.8.x.x/notificationsubsriptions.xml | 29 +++++++ 8 files changed, 246 insertions(+), 8 deletions(-) create mode 100644 frontend/public/service-worker.js create mode 100644 frontend/src/serviceWorkerRegistration.js create mode 100644 src/main/java/org/openelisglobal/notifications/entity/NotificationSubscription.java create mode 100644 src/main/resources/liquibase/2.8.x.x/notificationsubsriptions.xml diff --git a/frontend/public/manifest.json b/frontend/public/manifest.json index 302a19a512..d39c65ff48 100644 --- a/frontend/public/manifest.json +++ b/frontend/public/manifest.json @@ -1,6 +1,6 @@ { - "short_name": "React App", - "name": "Create React App Sample", + "short_name": "OpenELIS", + "name": "OpenELIS Global", "icons": [ { "src": "images/favicon-16x16.png", diff --git a/frontend/public/service-worker.js b/frontend/public/service-worker.js new file mode 100644 index 0000000000..1524edc672 --- /dev/null +++ b/frontend/public/service-worker.js @@ -0,0 +1,53 @@ +// Any other custom service worker logic can go here. + +self.addEventListener("push", async function (event) { + if (event.data) { + const data = event.data.json(); + const notificationOptions = { + body: data.body || "Sample Body", + tag: data.external_id || "default-tag", + }; + + event.waitUntil( + self.registration.showNotification("OpenELIS Test Message Received", notificationOptions) + ); + } +}); + +// This allows the web app to trigger skipWaiting via +// registration.waiting.postMessage({type: 'SKIP_WAITING'}) +self.addEventListener("message", (event) => { + if (event.data && event.data.type === "SKIP_WAITING") { + self.skipWaiting(); + } +}); + + +// self.addEventListener('push', (e) => { +// const data = e.data?.json(); +// if (data) { +// self.registration.showNotification(data.title, { +// body: data.body, +// }); +// } +// }); + +// self.addEventListener('notificationclick', (e) => { +// e.notification.close(); +// e.waitUntil(focusOrOpenWindow()); +// }); + +// async function focusOrOpenWindow() { +// const url = new URL('/', self.location.origin).href; + +// const allWindows = await self.clients.matchAll({ +// type: 'window', +// }); +// const appWindow = allWindows.find((w) => w.url === url); + +// if (appWindow) { +// return appWindow.focus(); +// } else { +// return self.clients.openWindow(url); +// } +// } \ No newline at end of file diff --git a/frontend/src/components/notifications/SlideOverNotifications.jsx b/frontend/src/components/notifications/SlideOverNotifications.jsx index b2ed3a4289..fccd9a78ad 100644 --- a/frontend/src/components/notifications/SlideOverNotifications.jsx +++ b/frontend/src/components/notifications/SlideOverNotifications.jsx @@ -3,9 +3,50 @@ import { formatTimestamp } from "../utils/Utils"; import Spinner from "../common/Sprinner"; import { FormattedMessage, useIntl } from "react-intl"; + + + + export default function SlideOverNotifications(props) { const intl = useIntl(); + async function subscribe() { + + + const public_key = "BJDIyXHWK_o9fYNwD3fUie2Ed04-yx5fxz9-GUT1c0QhfdDiGMvVbJwvB_On3XapXqIRR471uh7Snw3bfPt9niw"; + const sw = await navigator.serviceWorker.ready; + const push = await sw.pushManager.subscribe({ + userVisibleOnly: true, + applicationServerKey: public_key, + }); + const p256dh = btoa( + String.fromCharCode.apply( + null, + new Uint8Array(push.getKey("p256dh")), + ), + ); + const auth = btoa( + String.fromCharCode.apply( + null, + new Uint8Array(push.getKey("auth")), + ), + ); + + const data = { + pf_endpoint: push.endpoint, + pf_p256dh: p256dh, + pf_auth: auth, + }; + + console.log("subsription details", data) + + + + + + } + + const { loading, notifications, @@ -80,13 +121,13 @@ export default function SlideOverNotifications(props) { label: intl.formatMessage({ id: "notification.slideover.button.subscribe", }), - onClick: () => {}, + onClick: () => subscribe(), }, { icon: , label: intl.formatMessage({ id: "notification.slideover.button.markallasread", - }), + }), onClick: () => { markAllNotificationsAsRead(); }, @@ -95,11 +136,11 @@ export default function SlideOverNotifications(props) { icon: , label: showRead ? intl.formatMessage({ - id: "notification.slideover.button.hideread", - }) + id: "notification.slideover.button.hideread", + }) : intl.formatMessage({ - id: "notification.slideover.button.showread", - }), + id: "notification.slideover.button.showread", + }), onClick: () => setShowRead(!showRead), }, ].map(({ icon, label, onClick }, index) => ( diff --git a/frontend/src/index.js b/frontend/src/index.js index 211e34a603..2027da061c 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -3,6 +3,9 @@ import ReactDOM from "react-dom"; import "./index.css"; import App from "./App"; import reportWebVitals from "./reportWebVitals"; +import * as ServiceWorker from "./serviceWorkerRegistration" + +ServiceWorker.registerServiceWorker() ReactDOM.render( diff --git a/frontend/src/serviceWorkerRegistration.js b/frontend/src/serviceWorkerRegistration.js new file mode 100644 index 0000000000..70ce591f3f --- /dev/null +++ b/frontend/src/serviceWorkerRegistration.js @@ -0,0 +1,28 @@ +// Function to register the service worker +export function registerServiceWorker() { + if ('serviceWorker' in navigator) { + window.addEventListener('load', () => { + const swUrl = `./service-worker.js`; + + navigator.serviceWorker + .register(swUrl) + .then((registration) => { + console.log('Service Worker registered with scope:', registration.scope); + }) + .catch((error) => { + console.error('Service Worker registration failed:', error); + }); + }); + } +} + +// Function to unregister the service worker +export function unregisterServiceWorker() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready.then((registration) => { + registration.unregister().then((boolean) => { + console.log('Service Worker unregistered:', boolean); + }); + }); + } +} \ No newline at end of file diff --git a/src/main/java/org/openelisglobal/notifications/entity/NotificationSubscription.java b/src/main/java/org/openelisglobal/notifications/entity/NotificationSubscription.java new file mode 100644 index 0000000000..32d95115a1 --- /dev/null +++ b/src/main/java/org/openelisglobal/notifications/entity/NotificationSubscription.java @@ -0,0 +1,78 @@ +package org.openelisglobal.notifications.entity; + +import javax.persistence.*; +import org.openelisglobal.systemuser.valueholder.SystemUser; + +@Entity +@Table(name = "notification_subscriptions") +public class NotificationSubscription { + + @Id + @Column(name = "user_id") + private Long userId; + + @Column(name = "pf_endpoint", nullable = false) + private String pfEndpoint; + + @Column(name = "pf_p256dh", nullable = false) + private String pfP256dh; + + @Column(name = "pf_auth", nullable = false) + private String pfAuth; + + @OneToOne(fetch = FetchType.LAZY) + @MapsId + @JoinColumn(name = "user_id", nullable = false) + private SystemUser user; + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } + + public String getPfEndpoint() { + return pfEndpoint; + } + + public void setPfEndpoint(String pfEndpoint) { + this.pfEndpoint = pfEndpoint; + } + + public String getPfP256dh() { + return pfP256dh; + } + + public void setPfP256dh(String pfP256dh) { + this.pfP256dh = pfP256dh; + } + + public String getPfAuth() { + return pfAuth; + } + + public void setPfAuth(String pfAuth) { + this.pfAuth = pfAuth; + } + + public SystemUser getUser() { + return user; + } + + public void setUser(SystemUser user) { + this.user = user; + } + + @Override + public String toString() { + return "NotificationSubscription{" + + "userId=" + userId + + ", pfEndpoint='" + pfEndpoint + '\'' + + ", pfP256dh='" + pfP256dh + '\'' + + ", pfAuth='" + pfAuth + '\'' + + ", user=" + (user != null ? user.toString() : "null") + + '}'; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index ba6fc4fb5b..02b7c19f20 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -45,3 +45,9 @@ server.ssl.key-password = testtest server.ssl.trust-store=file:/ssl/lf.truststore server.ssl.trust-store-password=testtest +# Push Notification config + +vapid.public.key=BJDIyXHWK_o9fYNwD3fUie2Ed04-yx5fxz9-GUT1c0QhfdDiGMvVbJwvB_On3XapXqIRR471uh7Snw3bfPt9niw +vapid.private.key=FVONpka44MuWq6U8l3X4HY1hAfWM1v1IQB698gsS0KQ + + diff --git a/src/main/resources/liquibase/2.8.x.x/notificationsubsriptions.xml b/src/main/resources/liquibase/2.8.x.x/notificationsubsriptions.xml new file mode 100644 index 0000000000..4d0391eeef --- /dev/null +++ b/src/main/resources/liquibase/2.8.x.x/notificationsubsriptions.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + +