good
This commit is contained in:
@@ -1,28 +1,29 @@
|
|||||||
// public/firebase-messaging-sw.js
|
// public/firebase-messaging-sw.js
|
||||||
self.addEventListener('push', function(event) {
|
self.addEventListener("push", function (event) {
|
||||||
const data = event.data.json();
|
const data = event.data.json();
|
||||||
const options = {
|
const options = {
|
||||||
body: data.body,
|
body: data.body,
|
||||||
icon: 'https://i.pinimg.com/originals/3c/44/67/3c446785968272f79aaac7ace5ded0fe.jpg', // Path to your icon
|
icon: "https://i.pinimg.com/originals/3c/44/67/3c446785968272f79aaac7ace5ded0fe.jpg", // Path to your icon
|
||||||
badge: 'badge.png', // Path to your badge
|
badge: "badge.png", // Path to your badge
|
||||||
data: { // Add data to the notification
|
data: {
|
||||||
cafeId: data.cafeId,
|
// Add data to the notification
|
||||||
transactionId: data.transactionId,
|
cafeId: data.cafeId,
|
||||||
}
|
transactionId: data.transactionId,
|
||||||
};
|
},
|
||||||
|
};
|
||||||
|
|
||||||
event.waitUntil(
|
event.waitUntil(self.registration.showNotification(data.title, options));
|
||||||
self.registration.showNotification(data.title, options)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
self.addEventListener('notificationclick', (event) => {
|
self.addEventListener("notificationclick", (event) => {
|
||||||
event.notification.close(); // Close the notification
|
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
|
// Open the URL with the cafeId and transactionId
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
clients.openWindow(`https://r7l7gs-3000.csb.app/${cafeId}modal=new_transaction&transactionId=${transactionId}`)
|
clients.openWindow(
|
||||||
);
|
`https://srrk5s-3000.csb.app/${cafeId}?modal=new_transaction&transactionId=${transactionId}`
|
||||||
|
)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
79
src/App.js
79
src/App.js
@@ -37,6 +37,10 @@ import {
|
|||||||
removeLocalStorage,
|
removeLocalStorage,
|
||||||
} from "./helpers/localStorageHelpers";
|
} from "./helpers/localStorageHelpers";
|
||||||
import { calculateTotals } from "./helpers/cartHelpers";
|
import { calculateTotals } from "./helpers/cartHelpers";
|
||||||
|
import {
|
||||||
|
subscribeUser,
|
||||||
|
resetNotificationSubscription,
|
||||||
|
} from "./helpers/subscribeHelpers.js";
|
||||||
import Modal from "./components/Modal"; // Import your modal component
|
import Modal from "./components/Modal"; // Import your modal component
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
@@ -153,58 +157,28 @@ function App() {
|
|||||||
// }
|
// }
|
||||||
// };
|
// };
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const getVapidKey = async () => {
|
|
||||||
const response = await fetch(`${API_BASE_URL}/vapid-key`);
|
|
||||||
const { publicVapidKey } = await response.json();
|
|
||||||
return publicVapidKey;
|
|
||||||
};
|
|
||||||
|
|
||||||
const askNotificationPermission = async () => {
|
const askNotificationPermission = async () => {
|
||||||
const permission = await Notification.requestPermission();
|
let permission = Notification.permission;
|
||||||
if (permission === 'granted') {
|
if (permission === "default") {
|
||||||
console.log('Notification permission granted.');
|
setModal("req_notification");
|
||||||
const publicVapidKey = await getVapidKey();
|
}
|
||||||
await subscribeUser(publicVapidKey);
|
if (permission === "granted") await resetNotificationSubscription();
|
||||||
} else {
|
|
||||||
console.error('Notification permission denied.');
|
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
|
if ("serviceWorker" in navigator) {
|
||||||
function urlBase64ToUint8Array(base64String) {
|
window.addEventListener("load", async () => {
|
||||||
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
await askNotificationPermission();
|
||||||
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();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (socket == null) return;
|
if (socket == null) return;
|
||||||
@@ -333,23 +307,22 @@ function urlBase64ToUint8Array(base64String) {
|
|||||||
const setModal = (content, params = {}) => {
|
const setModal = (content, params = {}) => {
|
||||||
// Prepare query parameters
|
// Prepare query parameters
|
||||||
const queryParams = new URLSearchParams(location.search);
|
const queryParams = new URLSearchParams(location.search);
|
||||||
|
|
||||||
// Update the modal and any additional params
|
// Update the modal and any additional params
|
||||||
queryParams.set("modal", content);
|
queryParams.set("modal", content);
|
||||||
Object.entries(params).forEach(([key, value]) => {
|
Object.entries(params).forEach(([key, value]) => {
|
||||||
queryParams.set(key, value);
|
queryParams.set(key, value);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update URL with new parameters
|
// Update URL with new parameters
|
||||||
navigate(`?${queryParams.toString()}`, { replace: true });
|
navigate(`?${queryParams.toString()}`, { replace: true });
|
||||||
|
|
||||||
// Prevent scrolling when modal is open
|
// Prevent scrolling when modal is open
|
||||||
document.body.style.overflow = "hidden";
|
document.body.style.overflow = "hidden";
|
||||||
|
|
||||||
setIsModalOpen(true);
|
setIsModalOpen(true);
|
||||||
setModalContent(content);
|
setModalContent(content);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Function to close the modal
|
// Function to close the modal
|
||||||
const closeModal = () => {
|
const closeModal = () => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// src/config.js
|
// 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;
|
export default API_BASE_URL;
|
||||||
|
|||||||
76
src/helpers/subscribeHelpers.js
Normal file
76
src/helpers/subscribeHelpers.js
Normal file
@@ -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 };
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
// src/CafePage.js
|
// src/CafePage.js
|
||||||
|
|
||||||
import React, { useState, useEffect } from "react";
|
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 "../App.css";
|
||||||
import SearchInput from "../components/SearchInput";
|
import SearchInput from "../components/SearchInput";
|
||||||
@@ -18,6 +23,7 @@ import {
|
|||||||
getLocalStorage,
|
getLocalStorage,
|
||||||
updateLocalStorage,
|
updateLocalStorage,
|
||||||
} from "../helpers/localStorageHelpers";
|
} from "../helpers/localStorageHelpers";
|
||||||
|
import { unsubscribeUser } from "../helpers/subscribeHelpers.js";
|
||||||
|
|
||||||
function CafePage({
|
function CafePage({
|
||||||
table,
|
table,
|
||||||
@@ -54,12 +60,11 @@ function CafePage({
|
|||||||
if (user.cafeId != null && user.cafeId !== shopId) {
|
if (user.cafeId != null && user.cafeId !== shopId) {
|
||||||
// Preserve existing query parameters
|
// Preserve existing query parameters
|
||||||
const currentParams = new URLSearchParams(location.search).toString();
|
const currentParams = new URLSearchParams(location.search).toString();
|
||||||
|
|
||||||
// Navigate to the new cafeId while keeping existing params
|
// Navigate to the new cafeId while keeping existing params
|
||||||
navigate(`/${user.cafeId}?${currentParams}`, { replace: true });
|
navigate(`/${user.cafeId}?${currentParams}`, { replace: true });
|
||||||
}
|
}
|
||||||
}, [user, shopId]);
|
}, [user, shopId]);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (token) {
|
if (token) {
|
||||||
@@ -73,6 +78,7 @@ function CafePage({
|
|||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
updateLocalStorage("auth", "");
|
updateLocalStorage("auth", "");
|
||||||
|
unsubscribeUser();
|
||||||
navigate(0);
|
navigate(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { getAllCafeOwner, createCafeOwner } from "../helpers/userHelpers";
|
|||||||
import { getOwnedCafes, createCafe, updateCafe } from "../helpers/cafeHelpers";
|
import { getOwnedCafes, createCafe, updateCafe } from "../helpers/cafeHelpers";
|
||||||
|
|
||||||
import { ThreeDots } from "react-loader-spinner";
|
import { ThreeDots } from "react-loader-spinner";
|
||||||
|
import { unsubscribeUser } from "../helpers/subscribeHelpers.js";
|
||||||
|
|
||||||
const Dashboard = ({ user, setModal }) => {
|
const Dashboard = ({ user, setModal }) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -50,6 +51,7 @@ const Dashboard = ({ user, setModal }) => {
|
|||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
updateLocalStorage("auth", "");
|
updateLocalStorage("auth", "");
|
||||||
|
unsubscribeUser();
|
||||||
navigate(0);
|
navigate(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user