Skip to content

Commit

Permalink
Merge pull request #2723 from daostack/CW-firebase-messaging-for-web
Browse files Browse the repository at this point in the history
Firebase Cloud messaging for Web
  • Loading branch information
pvm-code authored Sep 3, 2024
2 parents 7f25bb8 + 69c4a85 commit 8f5238c
Show file tree
Hide file tree
Showing 12 changed files with 219 additions and 0 deletions.
82 changes: 82 additions & 0 deletions public/firebase-messaging-sw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/* eslint-disable */
// firebase-messaging-sw.js
importScripts(
"https://www.gstatic.com/firebasejs/10.7.1/firebase-app-compat.js",
);
importScripts(
"https://www.gstatic.com/firebasejs/10.7.1/firebase-messaging-compat.js",
);

const ENV = {
LOCAL: "http://localhost:3000",
DEV: "https://web-dev.common.io",
STAGE: "https://web-staging.common.io",
PRODUCTION: "https://common.io",
};

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);
});
Binary file added public/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export const local: Configuration = {
deadSeaCommonId: "958dca85-7bc1-4714-95bd-1fc6343f0654",
parentsForClimateCommonId: "958dca85-7bc1-4714-95bd-1fc6343f0654",
saadiaCommonId: "958dca85-7bc1-4714-95bd-1fc6343f0654",
vapidKey:
"BHVFyNetSC6oA2uFejnUFuDcSUYcas2R5lwW80z6gZc6zODp7rRdh2t8bht3LygJWjyI1toV165EYgdZqxCS_Y4",
};

const dev: Configuration = {
Expand All @@ -44,6 +46,8 @@ const dev: Configuration = {
deadSeaCommonId: "958dca85-7bc1-4714-95bd-1fc6343f0654",
parentsForClimateCommonId: "958dca85-7bc1-4714-95bd-1fc6343f0654",
saadiaCommonId: "958dca85-7bc1-4714-95bd-1fc6343f0654",
vapidKey:
"BHVFyNetSC6oA2uFejnUFuDcSUYcas2R5lwW80z6gZc6zODp7rRdh2t8bht3LygJWjyI1toV165EYgdZqxCS_Y4",
};

const stage: Configuration = {
Expand All @@ -62,6 +66,8 @@ const stage: Configuration = {
deadSeaCommonId: "a55a1e9b-104a-4866-9f4f-3e017bbae281",
parentsForClimateCommonId: "a55a1e9b-104a-4866-9f4f-3e017bbae281",
saadiaCommonId: "a55a1e9b-104a-4866-9f4f-3e017bbae281",
vapidKey:
"BBvr8z8QaPSJJfIRxmjBrq5Vs49BY95uZK_6QFyR7gKWgwrs5toDy-hvwWEtk-rbkVHBgOu9l2orK45u1n--9M0",
};

const production: Configuration = {
Expand All @@ -80,6 +86,8 @@ const production: Configuration = {
deadSeaCommonId: "6cfbfae6-2e5c-4b3b-ba70-e8fd871f48e2",
parentsForClimateCommonId: "04ac2ec2-5cb2-4ab9-ae3f-5f223f482768",
saadiaCommonId: "7c8c8996-b678-44df-9a57-e291431eb00f",
vapidKey:
"BKJ324iR-B5SoDG42bMrC_Q_poAv7BO-Z3AuMh5Grrg6TxO1QnN6mgzt2KyFFax0JSuuUhUKP-OrcTUPfboVqns",
};

const config: ConfigurationObject = {
Expand Down
2 changes: 2 additions & 0 deletions src/pages/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
ThemeHandler,
UserNotificationsAmountHandler,
WebViewLoginHandler,
NotificationsHandler,
} from "./handlers";
import { Router } from "./router";

Expand All @@ -34,6 +35,7 @@ const App = () => {
<ThemeHandler />
<UserNotificationsAmountHandler />
<WebViewLoginHandler />
<NotificationsHandler />
<LoginContainer />
<Router />
</ReactRouter>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { FC, useEffect, useState } from "react";
import { useSelector } from "react-redux";
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(() => {
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("/firebase-messaging-sw.js")
.then((registration) => {
setIsRegistered(true);
return registration;
})
.catch((err) => {
console.log("ServiceWorker registration failed: ", err);
});
}
}, []);

useEffect(() => {
if (!userId && !isRegistered) {
return;
}

let unsubscribeOnMessage;
(async () => {
const hasPermissions = await NotificationService.requestPermissions();
if (hasPermissions) {
await NotificationService.saveFCMToken();

unsubscribeOnMessage = NotificationService.onForegroundMessage();
}
})();

return () => {
unsubscribeOnMessage && unsubscribeOnMessage();
};
}, [userId, isRegistered]);

return null;
};

export default NotificationsHandler;
1 change: 1 addition & 0 deletions src/pages/App/handlers/NotificationsHandler/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as NotificationsHandler } from "./NotificationsHandler";
1 change: 1 addition & 0 deletions src/pages/App/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from "./TextDirectionHandler";
export * from "./UserNotificationsAmountHandler";
export * from "./WebViewLoginHandler";
export * from "./ThemeHandler";
export * from "./NotificationsHandler";
73 changes: 73 additions & 0 deletions src/services/Notification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
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<boolean> => {
try {
if(Notification.permission === NOTIFICATIONS_PERMISSIONS.GRANTED) {
return true;
}
const permission = await Notification.requestPermission();
if (permission === NOTIFICATIONS_PERMISSIONS.GRANTED) {
return true;
} else {
return false;
}
} catch (err) {
return false;
}
}

public saveFCMToken = async (): Promise<void> => {
try {
const token = await firebase.messaging().getToken({ vapidKey: firebaseConfig.vapidKey });
if (token) {

await Api.post(
this.endpoints.setFCMToken,
{
token,
}
);
}
} catch (error) {
console.error("An error occurred while retrieving token. ", error);
}
}

public onForegroundMessage = () => {
const unsubscribe = firebase.messaging().onMessage((payload) => {

const { title, body } = payload.notification;
if (Notification.permission === 'granted') {
new Notification(title, {
body,
data: payload?.data,
icon: "/logo.png",
});
}
});

return unsubscribe;
}
}

export default new NotificationService();
1 change: 1 addition & 0 deletions src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
1 change: 1 addition & 0 deletions src/shared/interfaces/Configuration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface Configuration {
deadSeaCommonId: string;
parentsForClimateCommonId: string;
saadiaCommonId: string;
vapidKey: string;
}

export type ConfigurationObject = Record<Environment, Configuration>;
1 change: 1 addition & 0 deletions src/shared/utils/firebase.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down
1 change: 1 addition & 0 deletions src/shared/utils/tests/mockConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
})
);

0 comments on commit 8f5238c

Please sign in to comment.