diff --git a/public/sw.js b/public/sw.js new file mode 100644 index 0000000..32f36cb --- /dev/null +++ b/public/sw.js @@ -0,0 +1,12 @@ +if ("serviceWorker" in navigator) { + window.addEventListener("load", () => { + navigator.serviceWorker + .register("/service-worker.js") + .then((registration) => { + console.log( + "Service Worker registered with scope:", + registration.scope + ); + }); + }); +} diff --git a/src/App.js b/src/App.js index ceb1dc5..02c8425 100644 --- a/src/App.js +++ b/src/App.js @@ -9,6 +9,8 @@ import { useLocation, } from "react-router-dom"; import socket from "./services/socketService"; +import { SubscriptionService } from "./services/subscriptionService"; +import { NotificationService } from "./services/notificationService"; import Dashboard from "./pages/Dashboard"; import ScanMeja from "./pages/ScanMeja"; @@ -77,19 +79,48 @@ function App() { if (tableCode) if (table.length == 0) { - const gettable = await getTableByCode(tableCode); + const gettable = await getTableByCode(shopId, tableCode); if (gettable) setTable(gettable); } }; useEffect(() => { - async function fetchData() { + const fetchData = async () => { console.log("gettingItems"); try { const { response, cafe, data } = await getItemTypesWithItems(shopId); if (response.status === 200) { setShop(cafe); setShopItems(data); + + // Filter out unavailable items + const filteredData = data + .map((itemType) => ({ + ...itemType, + itemList: itemType.itemList.filter((item) => item.availability), + })) + .filter((itemType) => itemType.itemList.length > 0); // Remove empty itemTypes + + // Update local storage by removing unavailable items + const updatedLocalStorage = + JSON.parse(localStorage.getItem("cart")) || []; + const newLocalStorage = updatedLocalStorage.map((cafe) => { + if (cafe.cafeId === shopId) { + return { + ...cafe, + items: cafe.items.filter((item) => + filteredData.some((filtered) => + filtered.itemList.some( + (i) => i.itemId === item.itemId && i.availability + ) + ) + ), + }; + } + return cafe; + }); + localStorage.setItem("cart", JSON.stringify(newLocalStorage)); + socket.on("transaction_created", () => { console.log("transaction created"); }); @@ -97,7 +128,7 @@ function App() { } catch (error) { console.error("Error fetching shop items:", error); } - } + }; if (shopId !== "") fetchData(); }, [shopId]); @@ -107,6 +138,20 @@ function App() { setGuestSides(sessionLeft.guestSideList); }; + const checkNotifications = async (userId) => { + try { + const permissionGranted = + await NotificationService.requestNotificationPermission(setModal); + if (permissionGranted) { + await SubscriptionService.subscribeUserToNotifications(userId); + } else { + setModal("blocked_notification"); + console.log("req notif"); + } + } catch (error) { + console.error("Error handling notifications:", error); + } + }; useEffect(() => { if (socket == null) return; @@ -129,7 +174,7 @@ function App() { }); socket.on("transaction_confirmed", async (data) => { - console.log("transaction notification"); + console.log("transaction notification" + data); setModal("transaction_confirmed", data); }); @@ -153,6 +198,11 @@ function App() { setModal("transaction_failed", data); }); + socket.on("transaction_canceled", async (data) => { + console.log("transaction notification"); + setModal("transaction_canceled", data); + }); + //for clerk socket.on("transaction_created", async (data) => { console.log("transaction notification"); @@ -175,6 +225,8 @@ function App() { setGuestSides(connectedGuestSides.sessionDatas); console.log("getting guest side"); setDeviceType("clerk"); + + checkNotifications(data.data.user.userId); } else { setDeviceType("guestDevice"); } diff --git a/src/components/ButtonWithReplica.css b/src/components/ButtonWithReplica.css new file mode 100644 index 0000000..ce6980f --- /dev/null +++ b/src/components/ButtonWithReplica.css @@ -0,0 +1,49 @@ +.container { + position: relative; + display: flex; + justify-content: center; + align-items: center; +} + +.button { + position: relative; + z-index: 99; /* Make sure the button is above the replica */ + + font-family: "Poppins", sans-serif; + font-weight: 500; + font-style: normal; + font-size: 70%; /* Adjusted for better readability */ + padding: 12px 24px; /* Added padding for a better look */ + border-radius: 50px; + background-color: rgba(88, 55, 50, 1); + color: white; + border: none; + margin: 0 auto; + cursor: pointer; + display: block; /* Centering the button */ + text-align: center; +} + +.replica { + height: 40px; + width: 140px; + border-radius: 30px; + position: absolute; + background-color: rgb(146, 146, 146); /* Semi-transparent blue */ + border: none; + transition: all 0.5s ease-in-out; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 98; /* Behind the button */ +} + +.replica.active { + width: 200vw; /* Full screen */ + height: 200vh; /* Full screen */ + position: absolute; + overflow-y: hidden; + top: 30%; + z-index: 200; + border-radius: 0px; +} diff --git a/src/components/ButtonWithReplica.js b/src/components/ButtonWithReplica.js new file mode 100644 index 0000000..dbaa995 --- /dev/null +++ b/src/components/ButtonWithReplica.js @@ -0,0 +1,24 @@ +import React, { useState } from "react"; +import "./ButtonWithReplica.css"; + +const ButtonWithReplica = ({ children }) => { + const [isActive, setIsActive] = useState(false); + + const handleClick = () => { + setIsActive(true); + setTimeout(() => { + setIsActive(false); + }, 1000); // Duration of the animation + }; + + return ( +