diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..7628eaa --- /dev/null +++ b/.env.example @@ -0,0 +1,19 @@ +# Firebase configuration +NEXT_PUBLIC_FIREBASE_API_KEY= +NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN= +NEXT_PUBLIC_FIREBASE_PROJECT_ID= +NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET= +NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID= +NEXT_PUBLIC_FIREBASE_APP_ID= +NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID= + +# Firebase Cloud Messaging VAPID key +NEXT_PUBLIC_FIREBASE_VAPID_KEY= + +# Google OAuth +NEXT_PUBLIC_GOOGLE_CLIENT_ID= +NEXT_PUBLIC_GOOGLE_CLIENT_SECRET= + +# NextAuth +NEXTAUTH_SECRET= +NEXTAUTH_URL= diff --git a/firebase.js b/firebase.js index 6ccdfef..d686f15 100644 --- a/firebase.js +++ b/firebase.js @@ -4,13 +4,13 @@ import { getFirestore } from "firebase/firestore"; import { getAuth } from "firebase/auth"; const firebaseConfig = { - apiKey: "AIzaSyB-bMY0fyMC9XX3QZl_2z4AtjNSphf8pxE", - authDomain: "spreadit-b8b53.firebaseapp.com", - projectId: "spreadit-b8b53", - storageBucket: "spreadit-b8b53.appspot.com", - messagingSenderId: "932668103377", - appId: "1:932668103377:web:37af04c0d79ebfb6f7c3f0", - measurementId: "G-14L5Y6VJ0B", + apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, + authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, + projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, + storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, + messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, + appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, + measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID, }; const app = initializeApp(firebaseConfig); diff --git a/lib/firebase.js b/lib/firebase.js index 6ccdfef..d686f15 100644 --- a/lib/firebase.js +++ b/lib/firebase.js @@ -4,13 +4,13 @@ import { getFirestore } from "firebase/firestore"; import { getAuth } from "firebase/auth"; const firebaseConfig = { - apiKey: "AIzaSyB-bMY0fyMC9XX3QZl_2z4AtjNSphf8pxE", - authDomain: "spreadit-b8b53.firebaseapp.com", - projectId: "spreadit-b8b53", - storageBucket: "spreadit-b8b53.appspot.com", - messagingSenderId: "932668103377", - appId: "1:932668103377:web:37af04c0d79ebfb6f7c3f0", - measurementId: "G-14L5Y6VJ0B", + apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, + authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, + projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, + storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, + messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, + appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, + measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID, }; const app = initializeApp(firebaseConfig); diff --git a/next.config.mjs b/next.config.mjs index 74e494c..e6f3ffc 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -6,6 +6,14 @@ const nextConfig = { // your project has ESLint errors. ignoreDuringBuilds: true, }, + async rewrites() { + return [ + { + source: "/firebase-messaging-sw.js", + destination: "/api/firebase-messaging-sw", + }, + ]; + }, images: { remotePatterns: [ { diff --git a/pages/api/firebase-messaging-sw.js b/pages/api/firebase-messaging-sw.js new file mode 100644 index 0000000..ec52ad9 --- /dev/null +++ b/pages/api/firebase-messaging-sw.js @@ -0,0 +1,94 @@ +export default function handler(req, res) { + const firebaseConfig = { + apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, + authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, + projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, + storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, + messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, + appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, + measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID, + }; + + const serviceWorkerContent = ` +importScripts( + "https://www.gstatic.com/firebasejs/10.5.0/firebase-app-compat.js", +); +importScripts( + "https://www.gstatic.com/firebasejs/10.5.0/firebase-messaging-compat.js", +); + +const firebaseConfig = ${JSON.stringify(firebaseConfig)}; + +firebase.initializeApp(firebaseConfig); + +class CustomPushEvent extends Event { + constructor(data) { + super("push"); + + Object.assign(this, data); + this.custom = true; + } +} + +/* + * Overrides push notification data, to avoid having 'notification' key and firebase blocking + * the message handler from being called + */ +self.addEventListener("push", (e) => { + // Skip if event is our own custom event + if (e.custom) return; + + // Kep old event data to override + const oldData = e.data; + + // Create a new event to dispatch, pull values from notification key and put it in data key, + // and then remove notification key + const newEvent = new CustomPushEvent({ + data: { + ehheh: oldData.json(), + json() { + const newData = oldData.json(); + newData.data = { + ...newData.data, + ...newData.notification, + }; + delete newData.notification; + return newData; + }, + }, + waitUntil: e.waitUntil.bind(e), + }); + + // Stop event propagation + e.stopImmediatePropagation(); + + // Dispatch the new wrapped event + dispatchEvent(newEvent); +}); + +const messaging = firebase.messaging(); + +messaging.onBackgroundMessage((payload) => { + const { title, body, image, icon, ...restPayload } = payload.data; + const notificationOptions = { + body, + icon: image || "/icons/firebase-logo.png", + data: restPayload, + }; + return self.registration.showNotification(title, notificationOptions); +}); + +self.addEventListener("notificationclick", (event) => { + if (event?.notification?.data && event?.notification?.data?.link) { + self.clients.openWindow(event.notification.data.link); + } + + // close notification after click + event.notification.close(); +}); +`; + + res.setHeader("Content-Type", "application/javascript"); + res.setHeader("Cache-Control", "no-cache"); + res.status(200).send(serviceWorkerContent); +} diff --git a/public/firebase-messaging-sw.js b/public/firebase-messaging-sw.js index 3de5aef..c9de35e 100644 --- a/public/firebase-messaging-sw.js +++ b/public/firebase-messaging-sw.js @@ -5,17 +5,9 @@ importScripts( "https://www.gstatic.com/firebasejs/10.5.0/firebase-messaging-compat.js", ); -const firebaseConfig = { - apiKey: "AIzaSyB-bMY0fyMC9XX3QZl_2z4AtjNSphf8pxE", - authDomain: "spreadit-b8b53.firebaseapp.com", - projectId: "spreadit-b8b53", - storageBucket: "spreadit-b8b53.appspot.com", - messagingSenderId: "932668103377", - appId: "1:932668103377:web:37af04c0d79ebfb6f7c3f0", - measurementId: "G-14L5Y6VJ0B", -}; - -firebase.initializeApp(firebaseConfig); +// Firebase configuration is injected at runtime via /api/firebase-messaging-sw. +// This file is kept for reference only and is not used directly. +// See pages/api/firebase-messaging-sw.js for the actual service worker served at this path. class CustomPushEvent extends Event { constructor(data) { diff --git a/src/app/utils/useFCMToken.js b/src/app/utils/useFCMToken.js index 087304f..9850bf1 100644 --- a/src/app/utils/useFCMToken.js +++ b/src/app/utils/useFCMToken.js @@ -21,7 +21,7 @@ const useFcmToken = async (token, permission) => { await navigator.serviceWorker.ready; const currentToken = await getToken(messaging, { vapidKey: - "BDdxkpSfsZfMF7ZyPklut-xQVgp6HH8GkJnTRHXGlsGv6u3oDujnIiqPF9_iqq_POtjU8tLuEISutYyAiyZC7dw", + process.env.NEXT_PUBLIC_FIREBASE_VAPID_KEY, }); if (currentToken) { storeFCM(currentToken);