From cd759f104973f270b91141363721346e1c164e8f Mon Sep 17 00:00:00 2001 From: Pavel Meyer Date: Wed, 14 Aug 2024 15:54:16 +0300 Subject: [PATCH 1/5] CW-firebase-messaging-for-web Added push notification config for web --- public/firebase-messaging-sw.js | 39 +++++++++ public/logo.png | Bin 0 -> 21322 bytes src/config.tsx | 8 ++ src/pages/App/App.tsx | 2 + .../NotificationsHandler.tsx | 58 +++++++++++++ .../handlers/NotificationsHandler/index.ts | 1 + src/pages/App/handlers/index.ts | 1 + src/services/Notification.ts | 78 ++++++++++++++++++ src/services/index.ts | 1 + src/shared/interfaces/Configuration.tsx | 1 + src/shared/utils/firebase.tsx | 1 + src/shared/utils/tests/mockConfig.ts | 1 + 12 files changed, 191 insertions(+) create mode 100644 public/firebase-messaging-sw.js create mode 100644 public/logo.png create mode 100644 src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx create mode 100644 src/pages/App/handlers/NotificationsHandler/index.ts create mode 100644 src/services/Notification.ts diff --git a/public/firebase-messaging-sw.js b/public/firebase-messaging-sw.js new file mode 100644 index 0000000000..8d7336b2eb --- /dev/null +++ b/public/firebase-messaging-sw.js @@ -0,0 +1,39 @@ +/* eslint-disable */ +// firebase-messaging-sw.js +importScripts( + "https://www.gstatic.com/firebasejs/10.1.0/firebase-app-compat.js", +); +importScripts( + "https://www.gstatic.com/firebasejs/10.1.0/firebase-messaging-compat.js", +); + +let firebaseConfig = {}; + +self.addEventListener("message", (event) => { + if (event.data && event.data.type === "INIT_ENV") { + firebaseConfig = event.data.env; + initializeFirebase(); + } +}); + +function initializeFirebase() { + if (firebaseConfig.apiKey) { + firebase.initializeApp(firebaseConfig); + + const messaging = firebase.messaging(); + + messaging.onBackgroundMessage((payload) => { + const notificationTitle = payload.notification.title; + const notificationOptions = { + body: payload.notification.body, + data: payload.data, + icon: "/logo.png", + }; + + self.registration.showNotification( + notificationTitle, + notificationOptions, + ); + }); + } +} diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..94e4735b4d9f056089265ae2b003d2b324fbedfd GIT binary patch literal 21322 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¥(;3@vm6LFN^T8keiynulZy_ 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 { + diff --git a/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx b/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx new file mode 100644 index 0000000000..ba2f8c1cfc --- /dev/null +++ b/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx @@ -0,0 +1,58 @@ +import { FC, useEffect, useState } from "react"; +import { useSelector } from "react-redux"; +import firebaseConfig from "@/config"; +import { selectUser } from "@/pages/Auth/store/selectors"; +import { NotificationService } from "@/services"; + +const NotificationsHandler: FC = () => { + const user = useSelector(selectUser()); + const [isRegistered, setIsRegistered] = useState(false); + const userId = user?.uid; + + useEffect(() => { + NotificationService.requestPermissions(); + }, []); + + useEffect(() => { + if ("serviceWorker" in navigator) { + const unsubscribe = window.addEventListener("load", () => { + navigator.serviceWorker + .register("/firebase-messaging-sw.js") + .then((registration) => { + console.log( + "ServiceWorker registration successful with scope: ", + registration.scope, + ); + registration.active?.postMessage({ + type: "INIT_ENV", + env: firebaseConfig.firebase, + }); + setIsRegistered(true); + return registration; + }) + .catch((err) => { + console.log("ServiceWorker registration failed: ", err); + }); + }); + + return unsubscribe; + } + }, [setIsRegistered]); + + useEffect(() => { + console.log("--userId", userId, "--isRegistered", isRegistered); + if (!userId || !isRegistered) { + return; + } + + NotificationService.saveFCMToken(); + + const unsubscribe = NotificationService.onForegroundMessage(); + + return unsubscribe; + }, [userId, isRegistered]); + + return null; +}; + +export default NotificationsHandler; diff --git a/src/pages/App/handlers/NotificationsHandler/index.ts b/src/pages/App/handlers/NotificationsHandler/index.ts new file mode 100644 index 0000000000..c7c53200f0 --- /dev/null +++ b/src/pages/App/handlers/NotificationsHandler/index.ts @@ -0,0 +1 @@ +export { default as NotificationsHandler } from "./NotificationsHandler"; \ No newline at end of file diff --git a/src/pages/App/handlers/index.ts b/src/pages/App/handlers/index.ts index 712e7a4d41..37e8eb0fb0 100644 --- a/src/pages/App/handlers/index.ts +++ b/src/pages/App/handlers/index.ts @@ -3,3 +3,4 @@ export * from "./TextDirectionHandler"; export * from "./UserNotificationsAmountHandler"; export * from "./WebViewLoginHandler"; export * from "./ThemeHandler"; +export * from "./NotificationsHandler"; diff --git a/src/services/Notification.ts b/src/services/Notification.ts new file mode 100644 index 0000000000..47e03a088e --- /dev/null +++ b/src/services/Notification.ts @@ -0,0 +1,78 @@ +import firebase from "@/shared/utils/firebase"; +import firebaseConfig from "@/config"; +import Api from "./Api"; + +enum NOTIFICATIONS_PERMISSIONS { + DEFAULT = "default", + DENIED = "denied", + GRANTED = "granted" +} + + +class NotificationService { + private endpoints: { + setFCMToken: string; + }; + + constructor() { + this.endpoints = { + setFCMToken: '/users/auth/google/set-fcm-token', + }; + } + + public requestPermissions = async (): Promise => { + try { + const permission = await Notification.requestPermission(); + if (permission === NOTIFICATIONS_PERMISSIONS.GRANTED) { + console.log('Notification permission granted.'); + return true; + } else { + return false; + } + } catch (err) { + return false; + } + } + + public saveFCMToken = async (): Promise => { + try { + console.log('-hastPermissions', firebaseConfig.vapidKey); + const token = await firebase.messaging().getToken({ vapidKey: firebaseConfig.vapidKey }); + if (token) { + try { + console.log("FCM Token:", token); + + await Api.post( + this.endpoints.setFCMToken, + { + token, + } + ); + } catch (error) { + console.error("An error occurred while retrieving token. ", error); + } + } else { + console.log("No registration token available. Request permission to generate one."); + } + } catch (error) { + console.error("An error occurred while retrieving token. ", error); + } + } + + public onForegroundMessage = () => { + return firebase.messaging().onMessage((payload) => { + console.log('Message received. ', payload); + + const { title, body } = payload.notification; + if (Notification.permission === 'granted') { + new Notification(title, { + body, + data: payload.data, + icon: '/logo.png', // Replace with your icon + }); + } + }); + } +} + +export default new NotificationService(); diff --git a/src/services/index.ts b/src/services/index.ts index 03d9bf706f..bf6d10f1ef 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -25,3 +25,4 @@ export { } from "./DiscussionMessage"; export { default as NotionService } from "./Notion"; export { default as FeatureFlagService } from "./FeatureFlag"; +export { default as NotificationService } from "./Notification"; diff --git a/src/shared/interfaces/Configuration.tsx b/src/shared/interfaces/Configuration.tsx index 94c71bcfce..73f6e96ef6 100644 --- a/src/shared/interfaces/Configuration.tsx +++ b/src/shared/interfaces/Configuration.tsx @@ -15,6 +15,7 @@ export interface Configuration { deadSeaCommonId: string; parentsForClimateCommonId: string; saadiaCommonId: string; + vapidKey: string; } export type ConfigurationObject = Record; diff --git a/src/shared/utils/firebase.tsx b/src/shared/utils/firebase.tsx index 3db4544c9a..a7f790cf01 100644 --- a/src/shared/utils/firebase.tsx +++ b/src/shared/utils/firebase.tsx @@ -1,6 +1,7 @@ import firebase from "firebase/compat/app"; import "firebase/compat/auth"; import "firebase/compat/firestore"; +import "firebase/compat/messaging"; import "firebase/compat/performance"; import "firebase/compat/storage"; import { getPerformance } from "firebase/performance"; diff --git a/src/shared/utils/tests/mockConfig.ts b/src/shared/utils/tests/mockConfig.ts index 502ef3bcfd..8f9410f5a9 100644 --- a/src/shared/utils/tests/mockConfig.ts +++ b/src/shared/utils/tests/mockConfig.ts @@ -18,5 +18,6 @@ jest.mock( deadSeaCommonId: "958dca85-7bc1-4714-95bd-1fc6343f0654", parentsForClimateCommonId: "958dca85-7bc1-4714-95bd-1fc6343f0654", saadiaCommonId: "958dca85-7bc1-4714-95bd-1fc6343f0654", + vapidKey: "VAPID_KEY", }) ); From 6b7537e27f47786c8615832ba6cea2845a85f104 Mon Sep 17 00:00:00 2001 From: Pavel Meyer Date: Thu, 15 Aug 2024 13:34:04 +0300 Subject: [PATCH 2/5] CW-firebase-messaging-for-web Update settings --- public/firebase-messaging-sw.js | 7 +- .../NotificationsHandler.tsx | 117 ++++++++++++------ src/services/Notification.ts | 11 +- 3 files changed, 94 insertions(+), 41 deletions(-) diff --git a/public/firebase-messaging-sw.js b/public/firebase-messaging-sw.js index 8d7336b2eb..29db6ca46e 100644 --- a/public/firebase-messaging-sw.js +++ b/public/firebase-messaging-sw.js @@ -1,15 +1,16 @@ /* eslint-disable */ // firebase-messaging-sw.js importScripts( - "https://www.gstatic.com/firebasejs/10.1.0/firebase-app-compat.js", + "https://www.gstatic.com/firebasejs/10.7.1/firebase-app-compat.js", ); importScripts( - "https://www.gstatic.com/firebasejs/10.1.0/firebase-messaging-compat.js", + "https://www.gstatic.com/firebasejs/10.7.1/firebase-messaging-compat.js", ); let firebaseConfig = {}; self.addEventListener("message", (event) => { + console.log("--INIT_ENV", event); if (event.data && event.data.type === "INIT_ENV") { firebaseConfig = event.data.env; initializeFirebase(); @@ -18,11 +19,13 @@ self.addEventListener("message", (event) => { function initializeFirebase() { if (firebaseConfig.apiKey) { + console.log("--firebaseConfig", firebaseConfig); firebase.initializeApp(firebaseConfig); const messaging = firebase.messaging(); messaging.onBackgroundMessage((payload) => { + console.log("--notif-back", payload); const notificationTitle = payload.notification.title; const notificationOptions = { body: payload.notification.body, diff --git a/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx b/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx index ba2f8c1cfc..4cde6340fd 100644 --- a/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx +++ b/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx @@ -1,4 +1,4 @@ -import { FC, useEffect, useState } from "react"; +import { FC, useEffect } from "react"; import { useSelector } from "react-redux"; import firebaseConfig from "@/config"; import { selectUser } from "@/pages/Auth/store/selectors"; @@ -6,51 +6,94 @@ import { NotificationService } from "@/services"; const NotificationsHandler: FC = () => { const user = useSelector(selectUser()); - const [isRegistered, setIsRegistered] = useState(false); const userId = user?.uid; - useEffect(() => { - NotificationService.requestPermissions(); - }, []); - - useEffect(() => { - if ("serviceWorker" in navigator) { - const unsubscribe = window.addEventListener("load", () => { - navigator.serviceWorker - .register("/firebase-messaging-sw.js") - .then((registration) => { - console.log( - "ServiceWorker registration successful with scope: ", - registration.scope, - ); - registration.active?.postMessage({ - type: "INIT_ENV", - env: firebaseConfig.firebase, - }); - setIsRegistered(true); - return registration; - }) - .catch((err) => { - console.log("ServiceWorker registration failed: ", err); - }); - }); - - return unsubscribe; - } - }, [setIsRegistered]); + // useEffect(() => { + // NotificationService.requestPermissions(); + // }, []); useEffect(() => { - console.log("--userId", userId, "--isRegistered", isRegistered); - if (!userId || !isRegistered) { + if (!userId) { return; } - NotificationService.saveFCMToken(); + let unsubscribeOnMessage; + let unsubscribeLoad; + (async () => { + const hasPermissions = await NotificationService.requestPermissions(); + console.log("-hasPermissions", hasPermissions); + if (hasPermissions) { + await NotificationService.saveFCMToken(); + + unsubscribeOnMessage = NotificationService.onForegroundMessage(); + + if ("serviceWorker" in navigator) { + console.log("--here"); + navigator.serviceWorker + .register("/firebase-messaging-sw.js") + .then((registration) => { + console.log( + "ServiceWorker registration successful with scope: ", + registration.scope, + ); + // registration.active?.postMessage({ + // type: "INIT_ENV", + // env: firebaseConfig.firebase, + // }); + + console.log("---registration", registration); + if (registration.active) { + registration.active.postMessage({ + type: "INIT_ENV", + env: firebaseConfig.firebase, + }); + } else if (registration?.installing) { + registration.installing.addEventListener("statechange", () => { + if (registration?.installing?.state === "activated") { + registration.installing.postMessage({ + type: "INIT_ENV", + env: firebaseConfig.firebase, + }); + } + }); + } else if (registration?.waiting) { + registration.waiting.addEventListener("statechange", () => { + if (registration?.waiting?.state === "activated") { + registration.waiting.postMessage({ + type: "INIT_ENV", + env: firebaseConfig.firebase, + }); + } + }); + } + return registration; + }) + .catch((err) => { + console.log("ServiceWorker registration failed: ", err); + }); + unsubscribeLoad = window.addEventListener("load", () => {}); + } + } + })(); + + return () => { + unsubscribeLoad && unsubscribeLoad(); + unsubscribeOnMessage && unsubscribeOnMessage(); + }; + }, [userId]); + + // useEffect(() => { + // console.log("--userId", userId, "--isRegistered", isRegistered); + // if (!userId || !isRegistered) { + // return; + // } + + // NotificationService.saveFCMToken(); - const unsubscribe = NotificationService.onForegroundMessage(); + // const unsubscribe = NotificationService.onForegroundMessage(); - return unsubscribe; - }, [userId, isRegistered]); + // return unsubscribe; + // }, [userId, isRegistered]); return null; }; diff --git a/src/services/Notification.ts b/src/services/Notification.ts index 47e03a088e..f5cf00a7a5 100644 --- a/src/services/Notification.ts +++ b/src/services/Notification.ts @@ -1,6 +1,7 @@ import firebase from "@/shared/utils/firebase"; import firebaseConfig from "@/config"; import Api from "./Api"; +import { NODATA } from "dns"; enum NOTIFICATIONS_PERMISSIONS { DEFAULT = "default", @@ -22,6 +23,9 @@ class NotificationService { public requestPermissions = async (): Promise => { try { + if(Notification.permission === NOTIFICATIONS_PERMISSIONS.GRANTED) { + return true; + } const permission = await Notification.requestPermission(); if (permission === NOTIFICATIONS_PERMISSIONS.GRANTED) { console.log('Notification permission granted.'); @@ -60,18 +64,21 @@ class NotificationService { } public onForegroundMessage = () => { - return firebase.messaging().onMessage((payload) => { + console.log('-subscribe'); + const unsubscribe = firebase.messaging().onMessage((payload) => { console.log('Message received. ', payload); const { title, body } = payload.notification; if (Notification.permission === 'granted') { new Notification(title, { body, - data: payload.data, + data: payload?.data, icon: '/logo.png', // Replace with your icon }); } }); + + return unsubscribe; } } From 92e2dfc771851b95dcdd27ebbed2c1e232cc4aad Mon Sep 17 00:00:00 2001 From: Pavel Meyer Date: Thu, 15 Aug 2024 16:09:33 +0300 Subject: [PATCH 3/5] CW-firebase-messaging-for-web Updated config --- public/firebase-messaging-sw.js | 59 ++++++++++--------- .../NotificationsHandler.tsx | 8 +-- src/services/Notification.ts | 2 +- 3 files changed, 37 insertions(+), 32 deletions(-) diff --git a/public/firebase-messaging-sw.js b/public/firebase-messaging-sw.js index 29db6ca46e..0b5d824165 100644 --- a/public/firebase-messaging-sw.js +++ b/public/firebase-messaging-sw.js @@ -7,36 +7,41 @@ importScripts( "https://www.gstatic.com/firebasejs/10.7.1/firebase-messaging-compat.js", ); -let firebaseConfig = {}; +let firebaseConfig = { + apiKey: "AIzaSyDbTFuksgOkIVWDiFe_HG7-BE8X6Dwsg-0", + authDomain: "common-dev-34b09.firebaseapp.com", + databaseURL: "https://common-dev-34b09.firebaseio.com", + projectId: "common-dev-34b09", + storageBucket: "common-dev-34b09.appspot.com", + messagingSenderId: "870639147922", + appId: "1:870639147922:web:9ee954bb1dd52e25cb7f4b", +}; -self.addEventListener("message", (event) => { - console.log("--INIT_ENV", event); - if (event.data && event.data.type === "INIT_ENV") { - firebaseConfig = event.data.env; - initializeFirebase(); - } -}); +// self.addEventListener("message", (event) => { +// console.log("--INIT_ENV", event); +// if (event.data && event.data.type === "INIT_ENV") { +// firebaseConfig = event.data.env; +// initializeFirebase(); +// } +// }); -function initializeFirebase() { - if (firebaseConfig.apiKey) { - console.log("--firebaseConfig", firebaseConfig); - firebase.initializeApp(firebaseConfig); +// function initializeFirebase() { +if (firebaseConfig.apiKey) { + console.log("--firebaseConfig", firebaseConfig); + firebase.initializeApp(firebaseConfig); - const messaging = firebase.messaging(); + const messaging = firebase.messaging(); - messaging.onBackgroundMessage((payload) => { - console.log("--notif-back", payload); - const notificationTitle = payload.notification.title; - const notificationOptions = { - body: payload.notification.body, - data: payload.data, - icon: "/logo.png", - }; + messaging.onBackgroundMessage((payload) => { + console.log("--notif-back", payload); + const notificationTitle = payload.notification.title; + const notificationOptions = { + body: payload.notification.body, + data: payload.data, + icon: "/logo.png", + }; - self.registration.showNotification( - notificationTitle, - notificationOptions, - ); - }); - } + self.registration.showNotification(notificationTitle, notificationOptions); + }); } +// } diff --git a/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx b/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx index 4cde6340fd..db19bce431 100644 --- a/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx +++ b/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx @@ -76,10 +76,10 @@ const NotificationsHandler: FC = () => { } })(); - return () => { - unsubscribeLoad && unsubscribeLoad(); - unsubscribeOnMessage && unsubscribeOnMessage(); - }; + // return () => { + // unsubscribeLoad && unsubscribeLoad(); + // unsubscribeOnMessage && unsubscribeOnMessage(); + // }; }, [userId]); // useEffect(() => { diff --git a/src/services/Notification.ts b/src/services/Notification.ts index f5cf00a7a5..ad86ad403b 100644 --- a/src/services/Notification.ts +++ b/src/services/Notification.ts @@ -64,7 +64,7 @@ class NotificationService { } public onForegroundMessage = () => { - console.log('-subscribe'); + console.log('-subscribe', firebase.messaging().onMessage); const unsubscribe = firebase.messaging().onMessage((payload) => { console.log('Message received. ', payload); From a71b7cadee0dbea073162c406c14650845685068 Mon Sep 17 00:00:00 2001 From: Pavel Meyer Date: Fri, 16 Aug 2024 13:34:45 +0300 Subject: [PATCH 4/5] CW-firebase-messaging-for-web Fixed env issue for service worker --- public/firebase-messaging-sw.js | 105 ++++++++++++------ .../NotificationsHandler.tsx | 93 ++++------------ src/services/Notification.ts | 26 ++--- 3 files changed, 97 insertions(+), 127 deletions(-) diff --git a/public/firebase-messaging-sw.js b/public/firebase-messaging-sw.js index 0b5d824165..6d0bd55e61 100644 --- a/public/firebase-messaging-sw.js +++ b/public/firebase-messaging-sw.js @@ -7,41 +7,76 @@ importScripts( "https://www.gstatic.com/firebasejs/10.7.1/firebase-messaging-compat.js", ); -let firebaseConfig = { - apiKey: "AIzaSyDbTFuksgOkIVWDiFe_HG7-BE8X6Dwsg-0", - authDomain: "common-dev-34b09.firebaseapp.com", - databaseURL: "https://common-dev-34b09.firebaseio.com", - projectId: "common-dev-34b09", - storageBucket: "common-dev-34b09.appspot.com", - messagingSenderId: "870639147922", - appId: "1:870639147922:web:9ee954bb1dd52e25cb7f4b", +const ENV = { + LOCAL: "http://localhost:3000", + DEV: "https://web-dev.common.io", + STAGE: "https://web-staging.common.io", + PRODUCTION: "https://common.io", }; -// self.addEventListener("message", (event) => { -// console.log("--INIT_ENV", event); -// if (event.data && event.data.type === "INIT_ENV") { -// firebaseConfig = event.data.env; -// initializeFirebase(); -// } -// }); - -// function initializeFirebase() { -if (firebaseConfig.apiKey) { - console.log("--firebaseConfig", firebaseConfig); - firebase.initializeApp(firebaseConfig); - - const messaging = firebase.messaging(); - - messaging.onBackgroundMessage((payload) => { - console.log("--notif-back", payload); - const notificationTitle = payload.notification.title; - const notificationOptions = { - body: payload.notification.body, - data: payload.data, - icon: "/logo.png", - }; - - self.registration.showNotification(notificationTitle, notificationOptions); - }); +const FIREBASE_CONFIG_ENV = { + DEV: { + apiKey: "AIzaSyDbTFuksgOkIVWDiFe_HG7-BE8X6Dwsg-0", + authDomain: "common-dev-34b09.firebaseapp.com", + databaseURL: "https://common-dev-34b09.firebaseio.com", + projectId: "common-dev-34b09", + storageBucket: "common-dev-34b09.appspot.com", + messagingSenderId: "870639147922", + appId: "1:870639147922:web:9ee954bb1dd52e25cb7f4b", + }, + STAGE: { + apiKey: "AIzaSyBASCWJMV64mZJObeFEitLmdUC1HqmtjJk", + authDomain: "common-staging-1d426.firebaseapp.com", + databaseURL: "https://common-staging-1d426.firebaseio.com", + projectId: "common-staging-1d426", + storageBucket: "common-staging-1d426.appspot.com", + messagingSenderId: "701579202562", + appId: "1:701579202562:web:5729d8a875f98f6709571b", + }, + PRODUCTION: { + apiKey: "AIzaSyAlYrKLd6KNKVkhmNEMKfb0cWHSWicCBOY", + authDomain: "common-production-67641.firebaseapp.com", + databaseURL: "https://common-production-67641.firebaseio.com", + projectId: "common-production-67641", + storageBucket: "common-production-67641.appspot.com", + messagingSenderId: "461029494046", + appId: "1:461029494046:web:4e2e4afbbeb7b487b48d0f", + }, +}; + +let firebaseConfig = {}; + +switch (location.origin) { + case ENV.LOCAL: + case ENV.DEV: { + firebaseConfig = FIREBASE_CONFIG_ENV.DEV; + break; + } + case ENV.STAGE: { + firebaseConfig = FIREBASE_CONFIG_ENV.STAGE; + break; + } + case ENV.PRODUCTION: { + firebaseConfig = FIREBASE_CONFIG_ENV.PRODUCTION; + break; + } + default: { + firebaseConfig = FIREBASE_CONFIG_ENV.DEV; + break; + } } -// } + +firebase.initializeApp(firebaseConfig); + +const messaging = firebase.messaging(); + +messaging.onBackgroundMessage((payload) => { + const notificationTitle = payload.notification.title; + const notificationOptions = { + body: payload.notification.body, + data: payload.data, + icon: "/logo.png", + }; + + self.registration.showNotification(notificationTitle, notificationOptions); +}); diff --git a/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx b/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx index db19bce431..885102c75c 100644 --- a/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx +++ b/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx @@ -1,99 +1,46 @@ -import { FC, useEffect } from "react"; +import { FC, useEffect, useState } from "react"; import { useSelector } from "react-redux"; -import firebaseConfig from "@/config"; import { selectUser } from "@/pages/Auth/store/selectors"; import { NotificationService } from "@/services"; const NotificationsHandler: FC = () => { const user = useSelector(selectUser()); const userId = user?.uid; + const [isRegistered, setIsRegistered] = useState(false); - // useEffect(() => { - // NotificationService.requestPermissions(); - // }, []); + useEffect(() => { + if ("serviceWorker" in navigator) { + navigator.serviceWorker + .register("/firebase-messaging-sw-dev.js") + .then((registration) => { + setIsRegistered(true); + return registration; + }) + .catch((err) => { + console.log("ServiceWorker registration failed: ", err); + }); + } + }, []); useEffect(() => { - if (!userId) { + if (!userId && !isRegistered) { return; } let unsubscribeOnMessage; - let unsubscribeLoad; (async () => { const hasPermissions = await NotificationService.requestPermissions(); - console.log("-hasPermissions", hasPermissions); if (hasPermissions) { await NotificationService.saveFCMToken(); unsubscribeOnMessage = NotificationService.onForegroundMessage(); - - if ("serviceWorker" in navigator) { - console.log("--here"); - navigator.serviceWorker - .register("/firebase-messaging-sw.js") - .then((registration) => { - console.log( - "ServiceWorker registration successful with scope: ", - registration.scope, - ); - // registration.active?.postMessage({ - // type: "INIT_ENV", - // env: firebaseConfig.firebase, - // }); - - console.log("---registration", registration); - if (registration.active) { - registration.active.postMessage({ - type: "INIT_ENV", - env: firebaseConfig.firebase, - }); - } else if (registration?.installing) { - registration.installing.addEventListener("statechange", () => { - if (registration?.installing?.state === "activated") { - registration.installing.postMessage({ - type: "INIT_ENV", - env: firebaseConfig.firebase, - }); - } - }); - } else if (registration?.waiting) { - registration.waiting.addEventListener("statechange", () => { - if (registration?.waiting?.state === "activated") { - registration.waiting.postMessage({ - type: "INIT_ENV", - env: firebaseConfig.firebase, - }); - } - }); - } - return registration; - }) - .catch((err) => { - console.log("ServiceWorker registration failed: ", err); - }); - unsubscribeLoad = window.addEventListener("load", () => {}); - } } })(); - // return () => { - // unsubscribeLoad && unsubscribeLoad(); - // unsubscribeOnMessage && unsubscribeOnMessage(); - // }; - }, [userId]); - - // useEffect(() => { - // console.log("--userId", userId, "--isRegistered", isRegistered); - // if (!userId || !isRegistered) { - // return; - // } - - // NotificationService.saveFCMToken(); - - // const unsubscribe = NotificationService.onForegroundMessage(); - - // return unsubscribe; - // }, [userId, isRegistered]); + return () => { + unsubscribeOnMessage && unsubscribeOnMessage(); + }; + }, [userId, isRegistered]); return null; }; diff --git a/src/services/Notification.ts b/src/services/Notification.ts index ad86ad403b..25e7597b3c 100644 --- a/src/services/Notification.ts +++ b/src/services/Notification.ts @@ -1,7 +1,6 @@ import firebase from "@/shared/utils/firebase"; import firebaseConfig from "@/config"; import Api from "./Api"; -import { NODATA } from "dns"; enum NOTIFICATIONS_PERMISSIONS { DEFAULT = "default", @@ -28,7 +27,6 @@ class NotificationService { } const permission = await Notification.requestPermission(); if (permission === NOTIFICATIONS_PERMISSIONS.GRANTED) { - console.log('Notification permission granted.'); return true; } else { return false; @@ -40,23 +38,15 @@ class NotificationService { public saveFCMToken = async (): Promise => { try { - console.log('-hastPermissions', firebaseConfig.vapidKey); const token = await firebase.messaging().getToken({ vapidKey: firebaseConfig.vapidKey }); if (token) { - try { - console.log("FCM Token:", token); - await Api.post( - this.endpoints.setFCMToken, - { - token, - } - ); - } catch (error) { - console.error("An error occurred while retrieving token. ", error); - } - } else { - console.log("No registration token available. Request permission to generate one."); + await Api.post( + this.endpoints.setFCMToken, + { + token, + } + ); } } catch (error) { console.error("An error occurred while retrieving token. ", error); @@ -64,16 +54,14 @@ class NotificationService { } public onForegroundMessage = () => { - console.log('-subscribe', firebase.messaging().onMessage); const unsubscribe = firebase.messaging().onMessage((payload) => { - console.log('Message received. ', payload); const { title, body } = payload.notification; if (Notification.permission === 'granted') { new Notification(title, { body, data: payload?.data, - icon: '/logo.png', // Replace with your icon + icon: "/logo.png", }); } }); From 69c4a85896bafe426f9d432cb30c74c4f051990d Mon Sep 17 00:00:00 2001 From: Pavel Meyer Date: Fri, 16 Aug 2024 20:07:28 +0300 Subject: [PATCH 5/5] CW-firebase-messaging-for-web Fix service-worker naming --- .../App/handlers/NotificationsHandler/NotificationsHandler.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx b/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx index 885102c75c..de144355b3 100644 --- a/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx +++ b/src/pages/App/handlers/NotificationsHandler/NotificationsHandler.tsx @@ -11,7 +11,7 @@ const NotificationsHandler: FC = () => { useEffect(() => { if ("serviceWorker" in navigator) { navigator.serviceWorker - .register("/firebase-messaging-sw-dev.js") + .register("/firebase-messaging-sw.js") .then((registration) => { setIsRegistered(true); return registration;