diff --git a/src/App.js b/src/App.js index 86d38e7..1087aef 100644 --- a/src/App.js +++ b/src/App.js @@ -58,6 +58,7 @@ function App() { const [shopItems, setShopItems] = useState([]); const [isModalOpen, setIsModalOpen] = useState(false); const [modalContent, setModalContent] = useState(null); + const [nextModalContent, setNextModalContent] = useState(null); useEffect(() => { const calculateTotalsFromLocalStorage = () => { @@ -115,9 +116,9 @@ function App() { items: cafe.items.filter((item) => filteredData.some((filtered) => filtered.itemList.some( - (i) => i.itemId === item.itemId && i.availability, - ), - ), + (i) => i.itemId === item.itemId && i.availability + ) + ) ), }; } @@ -221,13 +222,11 @@ function App() { }); socket.on("checkUserTokenRes", async (data) => { - console.log(data) if (data.status !== 200) { removeLocalStorage("auth"); setDeviceType("guestDevice"); } else { setUser(data.data.user); - console.log('setting user') if ( data.data.user.password == "unsetunsetunset" && localStorage.getItem("settings") @@ -290,7 +289,10 @@ function App() { // Function to open the modal const setModal = (content, params = {}) => { - // Prepare query parameters + if (modalContent) { + setNextModalContent(content); + return; + } // Prepare query parameters const queryParams = new URLSearchParams(location.search); // Update the modal and any additional params @@ -312,8 +314,9 @@ function App() { // Function to close the modal const closeModal = (closeTheseContent = []) => { if ( - closeTheseContent.length === 0 || - closeTheseContent.includes(modalContent) + Array.isArray(closeTheseContent) && + (closeTheseContent.length === 0 || + closeTheseContent.includes(modalContent)) ) { setIsModalOpen(false); document.body.style.overflow = "auto"; @@ -322,9 +325,13 @@ function App() { // Remove the 'modal' parameter queryParams.delete("modal"); + queryParams.delete("transactionId"); // Update the URL without the 'modal' parameter navigate({ search: queryParams.toString() }, { replace: true }); + + if (nextModalContent) setModal(nextModalContent); + setNextModalContent(""); } }; @@ -366,11 +373,9 @@ function App() { } }; const handleLoad = async () => { - while (modalContent !== "transaction_pending" || modalContent !== "transaction_confirmed") { if (user != null && (user.roleId < 3 || user.roleId > 2)) { await askNotificationPermission(); } - } }; handleLoad(); if ("serviceWorker" in navigator) { diff --git a/src/components/ButtonWithReplica.css b/src/components/ButtonWithReplica.css index 9ce255d..9249d5f 100644 --- a/src/components/ButtonWithReplica.css +++ b/src/components/ButtonWithReplica.css @@ -7,7 +7,7 @@ .button { position: relative; - z-index: 99; /* Make sure the button is above the replica */ + z-index: 201; /* Make sure the button is above the replica */ font-family: "Poppins", sans-serif; font-weight: 500; @@ -47,4 +47,91 @@ z-index: 200; border-radius: 0px; background-color: white; + pointer-events: none; /* Allow interactions */ +} +.bussinessName { + position: absolute; + top: 50%; + left: 50%; + color: rgba(0, 0, 0, 0); + transform: translate(-50%, -50%); + z-index: 98; /* Behind the button */ + transition: all 0.5s ease-in-out; + font-size: 3vw; + text-align: center; +} + +.bussinessName.active { + top: -700%; + position: absolute; + color: rgb(0, 0, 0); + width: 60vw; + right: 50%; + z-index: 201; /* Behind the button */ + font-size: 3vw; + text-align: center; +} + +.bussinessQR { + position: absolute; + height: 25vh; + width: 25vh; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 98; /* Behind the button */ + transition: all 0.5s ease-in-out; +} + +.bussinessQR.active { + position: absolute; + top: -250%; + transform: translate(-50%, -80%); + + transition: all 0.5s ease-in-out; + z-index: 201; /* Behind the button */ +} + +.price { + position: absolute; + top: 50%; + left: 50%; + color: rgba(0, 0, 0, 0); + transform: translate(-50%, -50%); + z-index: 98; /* Behind the button */ + transition: all 0.5s ease-in-out; + font-size: 3vw; + text-align: center; +} + +.price.active { + position: absolute; + color: rgb(0, 0, 0); + transform: translate(-50%, -150%); + z-index: 201; /* Behind the button */ + font-size: 3vw; + text-align: center; +} + +.ClaimButton { + visibility: hidden; + position: absolute; +} + +.ClaimButton.active { + visibility: visible; + 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; + z-index: 201; } diff --git a/src/components/ButtonWithReplica.js b/src/components/ButtonWithReplica.js index 65465a4..225322a 100644 --- a/src/components/ButtonWithReplica.js +++ b/src/components/ButtonWithReplica.js @@ -1,22 +1,153 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import "./ButtonWithReplica.css"; +import styles from "../pages/Transactions.module.css"; +import { QRCodeSVG } from "qrcode.react"; +import API_BASE_URL from "../config.js"; +import jsqr from "jsqr"; -const ButtonWithReplica = ({ children }) => { +const ButtonWithReplica = ({ + children, + price, + paymentUrl, + handleClick, + Open, + isPaymentOpen, +}) => { const [isActive, setIsActive] = useState(false); + const [fgColor, setFgColor] = useState("transparent"); + const [QRValue, setQRValue] = useState(""); + const [qrisComponent, setQrisComponent] = useState({ + merchantName: "", + nmid: "", + }); + useEffect(() => { + const decodeQRCodeFromUrl = async (imageUrl) => { + const img = new Image(); + img.crossOrigin = "Anonymous"; // Handle CORS if needed + img.src = API_BASE_URL + "/" + imageUrl; - const handleClick = () => { + return new Promise((resolve, reject) => { + img.onload = () => { + const canvas = document.createElement("canvas"); + const context = canvas.getContext("2d"); + canvas.width = img.width; + canvas.height = img.height; + context.drawImage(img, 0, 0); + const imageData = context.getImageData( + 0, + 0, + canvas.width, + canvas.height + ); + const code = jsqr(imageData.data, canvas.width, canvas.height); + + if (code) { + resolve(code.data); // This is your QRValue + } else { + reject("No QR code found."); + } + }; + + img.onerror = (error) => { + reject("Failed to load image: " + error); + }; + }); + }; + + const fetchQRCodeValue = async () => { + if (paymentUrl) { + try { + console.log(paymentUrl); + const qrv = await decodeQRCodeFromUrl(paymentUrl); + setQRValue(qrv); + } catch (error) { + console.error(error); + } + } + }; + + fetchQRCodeValue(); + }, [paymentUrl]); // Run effect when paymentUrl changes + + useEffect(() => { + function extractMerchantName(qrisCode) { + const tagPrefix = "ID59"; + const startIndex = qrisCode.indexOf(tagPrefix); + + if (startIndex !== -1) { + const lengthIndex = startIndex + tagPrefix.length; + const nameLength = parseInt(qrisCode.substr(lengthIndex, 2), 10); // Length of the name + const merchantNameStart = lengthIndex + 2; // Move past the length characters + const merchantNameEnd = merchantNameStart + nameLength; // Calculate the end index + + const merchantName = qrisCode.substr(merchantNameStart, nameLength); + return merchantName; + } + + return null; // Return null if the tag is not found + } + + function extractNMID(qrisCode) { + const startTag = "WWW0215"; + const endTag = "0303"; + + const startIndex = qrisCode.indexOf(startTag); + if (startIndex !== -1) { + const nmStartIndex = startIndex + startTag.length; // Start after WWW0215 + const endIndex = qrisCode.indexOf(endTag, nmStartIndex); // Find the next 0303 + + if (endIndex !== -1) { + const nmid = qrisCode.substring(nmStartIndex, endIndex); + return nmid; // This will include the ID prefix + } + } + + return null; // Return null if NMID is not found + } + + const parsedMerchantName = extractMerchantName(QRValue); + const parsedNMID = extractNMID(QRValue); + + setQrisComponent({ merchantName: parsedMerchantName, nmid: parsedNMID }); + + console.log("Parsed Merchant Name:", parsedMerchantName); + console.log("Parsed NMID:", parsedNMID); + }, [QRValue]); + + useEffect(() => { + setIsActive(isPaymentOpen); + if (isPaymentOpen == false) setFgColor("transparent"); // Change color to black on click + }, [isPaymentOpen]); + + const handleOpen = () => { setIsActive(true); - setTimeout(() => { - // setIsActive(false); - }, 10000); // Duration of the animation + setFgColor("black"); // Change color to black on click + console.log(qrisComponent.nmid); // Log the QR value + Open(); }; return (
-
+ +
+

{qrisComponent.merchantName}

+ {qrisComponent.nmid != "" &&

NMID : {qrisComponent.nmid}

} +
+
+

{price}

+
); }; diff --git a/src/components/Modal.js b/src/components/Modal.js index 71285c6..83eaa21 100644 --- a/src/components/Modal.js +++ b/src/components/Modal.js @@ -29,11 +29,10 @@ const Modal = ({ shop, isOpen, onClose, modalContent }) => { // Prevent click event from propagating to the overlay event.stopPropagation(); }; - console.log(shop.qrPayment); return (
- {modalContent === "req_notification" && } diff --git a/src/components/MusicPlayer.css b/src/components/MusicPlayer.css index 771dcf4..1d1796e 100644 --- a/src/components/MusicPlayer.css +++ b/src/components/MusicPlayer.css @@ -24,7 +24,7 @@ /* Center the background image */ filter: blur(1.5px); -webkit-filter: blur(1.5px); - border-radius: 15px 15px 0 0; + border-radius: 23px 23px 0 0; background-color: rgb(95 121 89); /* Rounded corners at the top */ text-align: right; @@ -106,7 +106,7 @@ right: 0; background-color: rgb(108, 255, 128); /* background-color: rgb(218 163 99); */ - border-radius: 0 0 15px 15px; + border-radius: 0 0 23px 23px; /* Rounded corners at the bottom */ cursor: pointer; text-align: center; diff --git a/src/config.js b/src/config.js index 8b740ee..d2c38df 100644 --- a/src/config.js +++ b/src/config.js @@ -1,5 +1,5 @@ // src/config.js -const API_BASE_URL = "https://sswsts-5000.csb.app"; // Replace with your actual backend URL +const API_BASE_URL = "https://2jtmkn-5000.csb.app"; // Replace with your actual backend URL export default API_BASE_URL; diff --git a/src/helpers/transactionHelpers.js b/src/helpers/transactionHelpers.js index 1dfc62e..b833a5a 100644 --- a/src/helpers/transactionHelpers.js +++ b/src/helpers/transactionHelpers.js @@ -13,7 +13,7 @@ export async function confirmTransaction(transactionId) { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - }, + } ); if (!response.ok) { return false; @@ -37,7 +37,7 @@ export async function declineTransaction(transactionId) { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - }, + } ); if (!response.ok) { @@ -61,7 +61,7 @@ export async function cancelTransaction(transactionId) { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - }, + } ); console.log(response); @@ -86,14 +86,14 @@ export async function handleClaimHasPaid(transactionId) { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - }, + } ); if (!response.ok) { return false; } - return true; + return await response.json(); } catch (error) { console.error("Error:", error); } @@ -111,7 +111,7 @@ export async function handleConfirmHasPaid(transactionId) { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - }, + } ); if (!response.ok) { @@ -135,7 +135,7 @@ export async function getTransaction(transactionId) { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - }, + } ); if (!response.ok) { @@ -160,7 +160,7 @@ export async function getTransactions(shopId, demand) { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, - }, + } ); if (!response.ok) { @@ -179,7 +179,7 @@ export const handlePaymentFromClerk = async ( user_email, payment_type, serving_type, - tableNo, + tableNo ) => { try { const token = getLocalStorage("auth"); @@ -208,7 +208,7 @@ export const handlePaymentFromClerk = async ( tableNo, transactions: structuredItems, }), - }, + } ); if (response.ok) { @@ -233,7 +233,7 @@ export const handlePaymentFromGuestSide = async ( user_email, payment_type, serving_type, - tableNo, + tableNo ) => { try { const token = getLocalStorage("authGuestSide"); @@ -262,7 +262,7 @@ export const handlePaymentFromGuestSide = async ( tableNo, transactions: structuredItems, }), - }, + } ); const res = await response.json(); console.log(res); @@ -289,7 +289,7 @@ export const handlePaymentFromGuestDevice = async ( serving_type, tableNo, notes, - socketId, + socketId ) => { try { const token = getLocalStorage("auth"); @@ -319,7 +319,7 @@ export const handlePaymentFromGuestDevice = async ( notes: notes, socketId, }), - }, + } ); if (response.ok) { @@ -364,7 +364,7 @@ const getHeaders = (method = "GET") => { export const getFavourite = async (cafeId) => { const response = await fetch( `${API_BASE_URL}/transaction/get-favourite/${cafeId}`, - getHeaders(), + getHeaders() ); return response.json(); }; @@ -377,7 +377,7 @@ export const getAnalytics = async (cafeId, filter) => { headers: { "Content-Type": "application/json", }, - }, + } ); return response.json(); }; @@ -385,7 +385,7 @@ export const getAnalytics = async (cafeId, filter) => { export const getIncome = async (cafeId) => { const response = await fetch( `${API_BASE_URL}/transaction/get-income/${cafeId}`, - getHeaders(), + getHeaders() ); return response.json(); }; diff --git a/src/pages/Payment_claimed.js b/src/pages/Payment_claimed.js index 31cb0a3..0e121c1 100644 --- a/src/pages/Payment_claimed.js +++ b/src/pages/Payment_claimed.js @@ -106,6 +106,12 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) { setSelectedTable(transaction.Table || { tableId: 0 }) } > + {transaction.paymentClaimed && transaction.confirmed < 2 && ( +
+ +

payment claimed

+
+ )}

Transaction ID: {transaction.transactionId}

@@ -127,7 +133,7 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) { transaction.Table ? transaction.Table.tableNo : "N/A" }`} - {transaction.notes != null && ( + {transaction.notes != "" && ( <>
Note : diff --git a/src/pages/Transaction.js b/src/pages/Transaction.js index d96575c..e5537ab 100644 --- a/src/pages/Transaction.js +++ b/src/pages/Transaction.js @@ -169,7 +169,11 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {