diff --git a/public/service-worker.js b/public/service-worker.js index 9c2c93c..a657dac 100644 --- a/public/service-worker.js +++ b/public/service-worker.js @@ -1,28 +1,29 @@ // public/firebase-messaging-sw.js -self.addEventListener('push', function(event) { - const data = event.data.json(); - const options = { - body: data.body, - icon: 'https://i.pinimg.com/originals/3c/44/67/3c446785968272f79aaac7ace5ded0fe.jpg', // Path to your icon - badge: 'badge.png', // Path to your badge - data: { // Add data to the notification - cafeId: data.cafeId, - transactionId: data.transactionId, - } - }; +self.addEventListener("push", function (event) { + const data = event.data.json(); + const options = { + body: data.body, + icon: "https://i.pinimg.com/originals/3c/44/67/3c446785968272f79aaac7ace5ded0fe.jpg", // Path to your icon + badge: "badge.png", // Path to your badge + data: { + // Add data to the notification + cafeId: data.cafeId, + transactionId: data.transactionId, + }, + }; - event.waitUntil( - self.registration.showNotification(data.title, options) - ); + event.waitUntil(self.registration.showNotification(data.title, options)); }); -self.addEventListener('notificationclick', (event) => { - event.notification.close(); // Close the notification +self.addEventListener("notificationclick", (event) => { + event.notification.close(); // Close the notification - const { cafeId, transactionId } = event.notification.data; // Get the notification data + const { cafeId, transactionId } = event.notification.data; // Get the notification data - // Open the URL with the cafeId and transactionId - event.waitUntil( - clients.openWindow(`https://r7l7gs-3000.csb.app/${cafeId}modal=new_transaction&transactionId=${transactionId}`) - ); + // Open the URL with the cafeId and transactionId + event.waitUntil( + clients.openWindow( + `https://srrk5s-3000.csb.app/${cafeId}?modal=new_transaction&transactionId=${transactionId}` + ) + ); }); diff --git a/src/App.js b/src/App.js index 6936b0f..134907a 100644 --- a/src/App.js +++ b/src/App.js @@ -37,6 +37,10 @@ import { removeLocalStorage, } from "./helpers/localStorageHelpers"; import { calculateTotals } from "./helpers/cartHelpers"; +import { + subscribeUser, + resetNotificationSubscription, +} from "./helpers/subscribeHelpers.js"; import Modal from "./components/Modal"; // Import your modal component function App() { @@ -153,58 +157,28 @@ function App() { // } // }; useEffect(() => { - const getVapidKey = async () => { - const response = await fetch(`${API_BASE_URL}/vapid-key`); - const { publicVapidKey } = await response.json(); - return publicVapidKey; - }; - const askNotificationPermission = async () => { - const permission = await Notification.requestPermission(); - if (permission === 'granted') { - console.log('Notification permission granted.'); - const publicVapidKey = await getVapidKey(); - await subscribeUser(publicVapidKey); - } else { - console.error('Notification permission denied.'); - } + let permission = Notification.permission; + if (permission === "default") { + setModal("req_notification"); + } + if (permission === "granted") await resetNotificationSubscription(); + + permission = await Notification.requestPermission(); + if (permission === "granted") { + await subscribeUser(); + } else if (permission === "denied") { + setModal("blocked_notification"); + console.error("Notification permission denied."); + } }; -// Utility function to convert base64 to Uint8Array -function urlBase64ToUint8Array(base64String) { - const padding = '='.repeat((4 - base64String.length % 4) % 4); - const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/'); - const rawData = window.atob(base64); - return Uint8Array.from([...rawData].map(char => char.charCodeAt(0))); -} - const subscribeUser = async (publicVapidKey) => { - try { - const registration = await navigator.serviceWorker.register('/service-worker.js'); - console.log('Service Worker registered with scope:', registration.scope); - - const subscription = await registration.pushManager.subscribe({ - userVisibleOnly: true, - applicationServerKey: urlBase64ToUint8Array(publicVapidKey), - }); - - await fetch(`${API_BASE_URL}/subscribe`, { - method: 'POST', - body: JSON.stringify(subscription), - headers: { - 'Content-Type': 'application/json', - }, - }); - } catch (error) { - console.error('Subscription failed:', error); - } - }; - - if ('serviceWorker' in navigator) { - window.addEventListener('load', async () => { - await askNotificationPermission(); - }); + if ("serviceWorker" in navigator) { + window.addEventListener("load", async () => { + await askNotificationPermission(); + }); } -}, []); + }, []); useEffect(() => { if (socket == null) return; @@ -333,23 +307,22 @@ function urlBase64ToUint8Array(base64String) { const setModal = (content, params = {}) => { // Prepare query parameters const queryParams = new URLSearchParams(location.search); - + // Update the modal and any additional params queryParams.set("modal", content); Object.entries(params).forEach(([key, value]) => { queryParams.set(key, value); }); - + // Update URL with new parameters navigate(`?${queryParams.toString()}`, { replace: true }); - + // Prevent scrolling when modal is open document.body.style.overflow = "hidden"; - + setIsModalOpen(true); setModalContent(content); }; - // Function to close the modal const closeModal = () => { diff --git a/src/config.js b/src/config.js index 542c831..8b740ee 100644 --- a/src/config.js +++ b/src/config.js @@ -1,5 +1,5 @@ // src/config.js -const API_BASE_URL = "https://p8hlyz-5000.csb.app"; // Replace with your actual backend URL +const API_BASE_URL = "https://sswsts-5000.csb.app"; // Replace with your actual backend URL export default API_BASE_URL; diff --git a/src/helpers/subscribeHelpers.js b/src/helpers/subscribeHelpers.js new file mode 100644 index 0000000..448c7f2 --- /dev/null +++ b/src/helpers/subscribeHelpers.js @@ -0,0 +1,76 @@ +import API_BASE_URL from "../config.js"; + +import { getLocalStorage } from "./localStorageHelpers"; + +const urlBase64ToUint8Array = (base64String) => { + const padding = "=".repeat((4 - (base64String.length % 4)) % 4); + const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/"); + const rawData = window.atob(base64); + return Uint8Array.from([...rawData].map((char) => char.charCodeAt(0))); +}; + +const getVapidKey = async () => { + const response = await fetch(`${API_BASE_URL}/vapid-key`); + const { publicVapidKey } = await response.json(); + return publicVapidKey; +}; + +const subscribeUser = async () => { + try { + const publicVapidKey = await getVapidKey(); + const registration = await navigator.serviceWorker.register( + "/service-worker.js" + ); + console.log("Service Worker registered with scope:", registration.scope); + + const subscription = await registration.pushManager.subscribe({ + userVisibleOnly: true, + applicationServerKey: urlBase64ToUint8Array(publicVapidKey), + }); + + await fetch(`${API_BASE_URL}/subscribe`, { + method: "POST", + body: JSON.stringify({ + subscription, + token: getLocalStorage("auth"), // Ensure this function is defined elsewhere + }), + headers: { + "Content-Type": "application/json", + }, + }); + + return subscription; // Return subscription if needed + } catch (error) { + console.error("Subscription failed:", error); + } +}; + +const unsubscribeUser = async () => { + const registration = await navigator.serviceWorker.getRegistration(); + if (registration) { + const subscription = await registration.pushManager.getSubscription(); + if (subscription) { + await fetch(`${API_BASE_URL}/unsubscribe`, { + method: "POST", + body: JSON.stringify({ + subscription, + token: getLocalStorage("auth"), // Ensure this function is defined elsewhere + }), + headers: { + "Content-Type": "application/json", + }, + }); + + await subscription.unsubscribe(); + console.log("User unsubscribed from notifications."); + } else { + console.log("No subscription found."); + } + } +}; +const resetNotificationSubscription = async () => { + await unsubscribeUser(); // First unsubscribe the user + await subscribeUser(); // Then subscribe the user again +}; + +export { subscribeUser, unsubscribeUser, resetNotificationSubscription }; diff --git a/src/pages/CafePage.js b/src/pages/CafePage.js index 0c601d6..3082697 100644 --- a/src/pages/CafePage.js +++ b/src/pages/CafePage.js @@ -1,7 +1,12 @@ // src/CafePage.js import React, { useState, useEffect } from "react"; -import { useParams, useSearchParams, useNavigate, useLocation } from "react-router-dom"; +import { + useParams, + useSearchParams, + useNavigate, + useLocation, +} from "react-router-dom"; import "../App.css"; import SearchInput from "../components/SearchInput"; @@ -18,6 +23,7 @@ import { getLocalStorage, updateLocalStorage, } from "../helpers/localStorageHelpers"; +import { unsubscribeUser } from "../helpers/subscribeHelpers.js"; function CafePage({ table, @@ -54,12 +60,11 @@ function CafePage({ if (user.cafeId != null && user.cafeId !== shopId) { // Preserve existing query parameters const currentParams = new URLSearchParams(location.search).toString(); - + // Navigate to the new cafeId while keeping existing params navigate(`/${user.cafeId}?${currentParams}`, { replace: true }); } }, [user, shopId]); - useEffect(() => { if (token) { @@ -73,6 +78,7 @@ function CafePage({ const handleLogout = () => { updateLocalStorage("auth", ""); + unsubscribeUser(); navigate(0); }; diff --git a/src/pages/Dashboard.js b/src/pages/Dashboard.js index a704d5f..7a78a7b 100644 --- a/src/pages/Dashboard.js +++ b/src/pages/Dashboard.js @@ -8,6 +8,7 @@ import { getAllCafeOwner, createCafeOwner } from "../helpers/userHelpers"; import { getOwnedCafes, createCafe, updateCafe } from "../helpers/cafeHelpers"; import { ThreeDots } from "react-loader-spinner"; +import { unsubscribeUser } from "../helpers/subscribeHelpers.js"; const Dashboard = ({ user, setModal }) => { const navigate = useNavigate(); @@ -50,6 +51,7 @@ const Dashboard = ({ user, setModal }) => { const handleLogout = () => { updateLocalStorage("auth", ""); + unsubscribeUser(); navigate(0); };