good
This commit is contained in:
25
src/App.js
25
src/App.js
@@ -58,6 +58,7 @@ function App() {
|
|||||||
const [shopItems, setShopItems] = useState([]);
|
const [shopItems, setShopItems] = useState([]);
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
const [modalContent, setModalContent] = useState(null);
|
const [modalContent, setModalContent] = useState(null);
|
||||||
|
const [nextModalContent, setNextModalContent] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const calculateTotalsFromLocalStorage = () => {
|
const calculateTotalsFromLocalStorage = () => {
|
||||||
@@ -115,9 +116,9 @@ function App() {
|
|||||||
items: cafe.items.filter((item) =>
|
items: cafe.items.filter((item) =>
|
||||||
filteredData.some((filtered) =>
|
filteredData.some((filtered) =>
|
||||||
filtered.itemList.some(
|
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) => {
|
socket.on("checkUserTokenRes", async (data) => {
|
||||||
console.log(data)
|
|
||||||
if (data.status !== 200) {
|
if (data.status !== 200) {
|
||||||
removeLocalStorage("auth");
|
removeLocalStorage("auth");
|
||||||
setDeviceType("guestDevice");
|
setDeviceType("guestDevice");
|
||||||
} else {
|
} else {
|
||||||
setUser(data.data.user);
|
setUser(data.data.user);
|
||||||
console.log('setting user')
|
|
||||||
if (
|
if (
|
||||||
data.data.user.password == "unsetunsetunset" &&
|
data.data.user.password == "unsetunsetunset" &&
|
||||||
localStorage.getItem("settings")
|
localStorage.getItem("settings")
|
||||||
@@ -290,7 +289,10 @@ function App() {
|
|||||||
|
|
||||||
// Function to open the modal
|
// Function to open the modal
|
||||||
const setModal = (content, params = {}) => {
|
const setModal = (content, params = {}) => {
|
||||||
// Prepare query parameters
|
if (modalContent) {
|
||||||
|
setNextModalContent(content);
|
||||||
|
return;
|
||||||
|
} // 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
|
||||||
@@ -312,8 +314,9 @@ function App() {
|
|||||||
// Function to close the modal
|
// Function to close the modal
|
||||||
const closeModal = (closeTheseContent = []) => {
|
const closeModal = (closeTheseContent = []) => {
|
||||||
if (
|
if (
|
||||||
closeTheseContent.length === 0 ||
|
Array.isArray(closeTheseContent) &&
|
||||||
closeTheseContent.includes(modalContent)
|
(closeTheseContent.length === 0 ||
|
||||||
|
closeTheseContent.includes(modalContent))
|
||||||
) {
|
) {
|
||||||
setIsModalOpen(false);
|
setIsModalOpen(false);
|
||||||
document.body.style.overflow = "auto";
|
document.body.style.overflow = "auto";
|
||||||
@@ -322,9 +325,13 @@ function App() {
|
|||||||
|
|
||||||
// Remove the 'modal' parameter
|
// Remove the 'modal' parameter
|
||||||
queryParams.delete("modal");
|
queryParams.delete("modal");
|
||||||
|
queryParams.delete("transactionId");
|
||||||
|
|
||||||
// Update the URL without the 'modal' parameter
|
// Update the URL without the 'modal' parameter
|
||||||
navigate({ search: queryParams.toString() }, { replace: true });
|
navigate({ search: queryParams.toString() }, { replace: true });
|
||||||
|
|
||||||
|
if (nextModalContent) setModal(nextModalContent);
|
||||||
|
setNextModalContent("");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -366,11 +373,9 @@ function App() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleLoad = async () => {
|
const handleLoad = async () => {
|
||||||
while (modalContent !== "transaction_pending" || modalContent !== "transaction_confirmed") {
|
|
||||||
if (user != null && (user.roleId < 3 || user.roleId > 2)) {
|
if (user != null && (user.roleId < 3 || user.roleId > 2)) {
|
||||||
await askNotificationPermission();
|
await askNotificationPermission();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
handleLoad();
|
handleLoad();
|
||||||
if ("serviceWorker" in navigator) {
|
if ("serviceWorker" in navigator) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
.button {
|
.button {
|
||||||
position: relative;
|
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-family: "Poppins", sans-serif;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -47,4 +47,91 @@
|
|||||||
z-index: 200;
|
z-index: 200;
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
background-color: white;
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,153 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import "./ButtonWithReplica.css";
|
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 [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);
|
setIsActive(true);
|
||||||
setTimeout(() => {
|
setFgColor("black"); // Change color to black on click
|
||||||
// setIsActive(false);
|
console.log(qrisComponent.nmid); // Log the QR value
|
||||||
}, 10000); // Duration of the animation
|
Open();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<button className="button" onClick={handleClick}>
|
<button
|
||||||
|
className="button"
|
||||||
|
onClick={() => (isPaymentOpen ? handleClick() : handleOpen())}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</button>
|
</button>
|
||||||
<div className={`replica ${isActive ? "active" : ""}`}></div>
|
<div className={`replica ${isActive ? "active" : ""}`}></div>
|
||||||
|
<QRCodeSVG
|
||||||
|
className={`bussinessQR ${isActive ? "active" : ""}`}
|
||||||
|
bgColor={"transparent"}
|
||||||
|
fgColor={fgColor}
|
||||||
|
value={QRValue}
|
||||||
|
/>
|
||||||
|
<div className={`bussinessName ${isActive ? "active" : ""}`}>
|
||||||
|
<h2>{qrisComponent.merchantName}</h2>
|
||||||
|
{qrisComponent.nmid != "" && <h4>NMID : {qrisComponent.nmid}</h4>}
|
||||||
|
</div>
|
||||||
|
<div className={`price ${isActive ? "active" : ""}`}>
|
||||||
|
<h1>{price}</h1>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,11 +29,10 @@ const Modal = ({ shop, isOpen, onClose, modalContent }) => {
|
|||||||
// Prevent click event from propagating to the overlay
|
// Prevent click event from propagating to the overlay
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
};
|
};
|
||||||
console.log(shop.qrPayment);
|
|
||||||
return (
|
return (
|
||||||
<div onClick={handleOverlayClick} className={styles.modalOverlay}>
|
<div onClick={handleOverlayClick} className={styles.modalOverlay}>
|
||||||
<div className={styles.modalContent} onClick={handleContentClick}>
|
<div className={styles.modalContent} onClick={handleContentClick}>
|
||||||
<button onClick={onClose} className={styles.closeButton}>
|
<button onClick={() => onClose()} className={styles.closeButton}>
|
||||||
×
|
×
|
||||||
</button>
|
</button>
|
||||||
{modalContent === "req_notification" && <NotificationBlocked />}
|
{modalContent === "req_notification" && <NotificationBlocked />}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
/* Center the background image */
|
/* Center the background image */
|
||||||
filter: blur(1.5px);
|
filter: blur(1.5px);
|
||||||
-webkit-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);
|
background-color: rgb(95 121 89);
|
||||||
/* Rounded corners at the top */
|
/* Rounded corners at the top */
|
||||||
text-align: right;
|
text-align: right;
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
background-color: rgb(108, 255, 128);
|
background-color: rgb(108, 255, 128);
|
||||||
/* background-color: rgb(218 163 99); */
|
/* background-color: rgb(218 163 99); */
|
||||||
border-radius: 0 0 15px 15px;
|
border-radius: 0 0 23px 23px;
|
||||||
/* Rounded corners at the bottom */
|
/* Rounded corners at the bottom */
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// src/config.js
|
// 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;
|
export default API_BASE_URL;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export async function confirmTransaction(transactionId) {
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
return false;
|
return false;
|
||||||
@@ -37,7 +37,7 @@ export async function declineTransaction(transactionId) {
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -61,7 +61,7 @@ export async function cancelTransaction(transactionId) {
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(response);
|
console.log(response);
|
||||||
@@ -86,14 +86,14 @@ export async function handleClaimHasPaid(transactionId) {
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return await response.json();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error:", error);
|
console.error("Error:", error);
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ export async function handleConfirmHasPaid(transactionId) {
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -135,7 +135,7 @@ export async function getTransaction(transactionId) {
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -160,7 +160,7 @@ export async function getTransactions(shopId, demand) {
|
|||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -179,7 +179,7 @@ export const handlePaymentFromClerk = async (
|
|||||||
user_email,
|
user_email,
|
||||||
payment_type,
|
payment_type,
|
||||||
serving_type,
|
serving_type,
|
||||||
tableNo,
|
tableNo
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const token = getLocalStorage("auth");
|
const token = getLocalStorage("auth");
|
||||||
@@ -208,7 +208,7 @@ export const handlePaymentFromClerk = async (
|
|||||||
tableNo,
|
tableNo,
|
||||||
transactions: structuredItems,
|
transactions: structuredItems,
|
||||||
}),
|
}),
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
@@ -233,7 +233,7 @@ export const handlePaymentFromGuestSide = async (
|
|||||||
user_email,
|
user_email,
|
||||||
payment_type,
|
payment_type,
|
||||||
serving_type,
|
serving_type,
|
||||||
tableNo,
|
tableNo
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const token = getLocalStorage("authGuestSide");
|
const token = getLocalStorage("authGuestSide");
|
||||||
@@ -262,7 +262,7 @@ export const handlePaymentFromGuestSide = async (
|
|||||||
tableNo,
|
tableNo,
|
||||||
transactions: structuredItems,
|
transactions: structuredItems,
|
||||||
}),
|
}),
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
const res = await response.json();
|
const res = await response.json();
|
||||||
console.log(res);
|
console.log(res);
|
||||||
@@ -289,7 +289,7 @@ export const handlePaymentFromGuestDevice = async (
|
|||||||
serving_type,
|
serving_type,
|
||||||
tableNo,
|
tableNo,
|
||||||
notes,
|
notes,
|
||||||
socketId,
|
socketId
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const token = getLocalStorage("auth");
|
const token = getLocalStorage("auth");
|
||||||
@@ -319,7 +319,7 @@ export const handlePaymentFromGuestDevice = async (
|
|||||||
notes: notes,
|
notes: notes,
|
||||||
socketId,
|
socketId,
|
||||||
}),
|
}),
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
@@ -364,7 +364,7 @@ const getHeaders = (method = "GET") => {
|
|||||||
export const getFavourite = async (cafeId) => {
|
export const getFavourite = async (cafeId) => {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${API_BASE_URL}/transaction/get-favourite/${cafeId}`,
|
`${API_BASE_URL}/transaction/get-favourite/${cafeId}`,
|
||||||
getHeaders(),
|
getHeaders()
|
||||||
);
|
);
|
||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
@@ -377,7 +377,7 @@ export const getAnalytics = async (cafeId, filter) => {
|
|||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
@@ -385,7 +385,7 @@ export const getAnalytics = async (cafeId, filter) => {
|
|||||||
export const getIncome = async (cafeId) => {
|
export const getIncome = async (cafeId) => {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${API_BASE_URL}/transaction/get-income/${cafeId}`,
|
`${API_BASE_URL}/transaction/get-income/${cafeId}`,
|
||||||
getHeaders(),
|
getHeaders()
|
||||||
);
|
);
|
||||||
return response.json();
|
return response.json();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -106,6 +106,12 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
|
|||||||
setSelectedTable(transaction.Table || { tableId: 0 })
|
setSelectedTable(transaction.Table || { tableId: 0 })
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
{transaction.paymentClaimed && transaction.confirmed < 2 && (
|
||||||
|
<div className={styles.RibbonBanner}>
|
||||||
|
<img src={"https://i.imgur.com/yt6osgL.png"}></img>
|
||||||
|
<h1>payment claimed</h1>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<h2 className={styles["Transactions-detail"]}>
|
<h2 className={styles["Transactions-detail"]}>
|
||||||
Transaction ID: {transaction.transactionId}
|
Transaction ID: {transaction.transactionId}
|
||||||
</h2>
|
</h2>
|
||||||
@@ -127,7 +133,7 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
|
|||||||
transaction.Table ? transaction.Table.tableNo : "N/A"
|
transaction.Table ? transaction.Table.tableNo : "N/A"
|
||||||
}`}
|
}`}
|
||||||
</h2>
|
</h2>
|
||||||
{transaction.notes != null && (
|
{transaction.notes != "" && (
|
||||||
<>
|
<>
|
||||||
<div className={styles.NoteContainer}>
|
<div className={styles.NoteContainer}>
|
||||||
<span>Note :</span>
|
<span>Note :</span>
|
||||||
|
|||||||
@@ -169,7 +169,11 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
|
|||||||
<button
|
<button
|
||||||
className={styles.PayButton}
|
className={styles.PayButton}
|
||||||
onClick={() => handleConfirm(transaction.transactionId)}
|
onClick={() => handleConfirm(transaction.transactionId)}
|
||||||
disabled={isPaymentLoading} // Disable button if confirmed (1) or declined (-1) or loading
|
disabled={
|
||||||
|
transaction.confirmed === -1 ||
|
||||||
|
transaction.confirmed === 3 ||
|
||||||
|
isPaymentLoading
|
||||||
|
} // Disable button if confirmed (1) or declined (-1) or
|
||||||
>
|
>
|
||||||
{isPaymentLoading ? (
|
{isPaymentLoading ? (
|
||||||
<ColorRing height="50" width="50" color="white" />
|
<ColorRing height="50" width="50" color="white" />
|
||||||
|
|||||||
@@ -14,7 +14,12 @@ import { getTables } from "../helpers/tableHelper";
|
|||||||
import TableCanvas from "../components/TableCanvas";
|
import TableCanvas from "../components/TableCanvas";
|
||||||
import { useSearchParams } from "react-router-dom";
|
import { useSearchParams } from "react-router-dom";
|
||||||
|
|
||||||
export default function Transactions({ propsShopId, sendParam, deviceType }) {
|
export default function Transactions({
|
||||||
|
propsShopId,
|
||||||
|
sendParam,
|
||||||
|
deviceType,
|
||||||
|
paymentUrl,
|
||||||
|
}) {
|
||||||
const { shopId, tableId } = useParams();
|
const { shopId, tableId } = useParams();
|
||||||
if (sendParam) sendParam({ shopId, tableId });
|
if (sendParam) sendParam({ shopId, tableId });
|
||||||
|
|
||||||
@@ -24,6 +29,7 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
|
|||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const [transaction, setTransaction] = useState(null);
|
const [transaction, setTransaction] = useState(null);
|
||||||
const noteRef = useRef(null);
|
const noteRef = useRef(null);
|
||||||
|
const [isPaymentOpen, setIsPaymentOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const transactionId = searchParams.get("transactionId") || "";
|
const transactionId = searchParams.get("transactionId") || "";
|
||||||
@@ -63,9 +69,14 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
|
|||||||
if (isPaymentLoading) return;
|
if (isPaymentLoading) return;
|
||||||
setIsPaymentLoading(true);
|
setIsPaymentLoading(true);
|
||||||
try {
|
try {
|
||||||
const c = await confirmTransaction(transactionId);
|
const c = await handleClaimHasPaid(transactionId);
|
||||||
if (c) {
|
if (c) {
|
||||||
setTransaction({ ...transaction, confirmed: c.confirmed });
|
setTransaction({
|
||||||
|
...transaction,
|
||||||
|
confirmed: c.confirmed,
|
||||||
|
paymentClaimed: true,
|
||||||
|
});
|
||||||
|
console.log(transaction);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error processing payment:", error);
|
console.error("Error processing payment:", error);
|
||||||
@@ -112,7 +123,14 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
setSelectedTable(transaction.Table || { tableId: 0 })
|
setSelectedTable(transaction.Table || { tableId: 0 })
|
||||||
}
|
}
|
||||||
|
style={{ overflow: isPaymentOpen ? "hidden" : "" }}
|
||||||
>
|
>
|
||||||
|
{transaction.paymentClaimed && transaction.confirmed < 2 && (
|
||||||
|
<div className={styles.RibbonBanner}>
|
||||||
|
<img src={"https://i.imgur.com/yt6osgL.png"}></img>
|
||||||
|
<h1>payment claimed</h1>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<h2 className={styles["Transactions-detail"]}>
|
<h2 className={styles["Transactions-detail"]}>
|
||||||
Transaction ID: {transaction.transactionId}
|
Transaction ID: {transaction.transactionId}
|
||||||
</h2>
|
</h2>
|
||||||
@@ -134,14 +152,24 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
|
|||||||
transaction.Table ? transaction.Table.tableNo : "N/A"
|
transaction.Table ? transaction.Table.tableNo : "N/A"
|
||||||
}`}
|
}`}
|
||||||
</h2>
|
</h2>
|
||||||
{transaction.notes != "" && (
|
{(transaction.notes !== "" || isPaymentOpen) && (
|
||||||
<>
|
<>
|
||||||
<div className={styles.NoteContainer}>
|
<div
|
||||||
|
className={styles.NoteContainer}
|
||||||
|
style={{
|
||||||
|
visibility: transaction.notes == "" ? "hidden" : "visible",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<span>Note :</span>
|
<span>Note :</span>
|
||||||
<span></span>
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.NoteContainer}>
|
<div
|
||||||
|
className={styles.NoteContainer}
|
||||||
|
style={{
|
||||||
|
visibility: transaction.notes == "" ? "hidden" : "visible",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<textarea
|
<textarea
|
||||||
className={styles.NoteInput}
|
className={styles.NoteInput}
|
||||||
value={transaction.notes}
|
value={transaction.notes}
|
||||||
@@ -159,29 +187,36 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles.PaymentContainer}>
|
<div className={styles.PaymentContainer}>
|
||||||
<ButtonWithReplica
|
<ButtonWithReplica
|
||||||
|
paymentUrl={paymentUrl}
|
||||||
|
price={
|
||||||
|
"Rp" + calculateTotalPrice(transaction.DetailedTransactions)
|
||||||
|
}
|
||||||
disabled={isPaymentLoading}
|
disabled={isPaymentLoading}
|
||||||
onClick={() => handleConfirm(transaction.transactionId)}
|
isPaymentLoading={isPaymentLoading}
|
||||||
|
handleClick={() => handleConfirm(transaction.transactionId)}
|
||||||
|
Open={() => setIsPaymentOpen(true)}
|
||||||
|
isPaymentOpen={isPaymentOpen}
|
||||||
>
|
>
|
||||||
{isPaymentLoading ? (
|
{isPaymentLoading ? (
|
||||||
<ColorRing height="50" width="50" color="white" />
|
<ColorRing height="50" width="50" color="white" />
|
||||||
) : transaction.confirmed === 1 ? (
|
) : isPaymentOpen ? (
|
||||||
"Show payment" // Display "Confirm has paid" if the transaction is confirmed (1)
|
"Claim has paid" // Display "Confirm has paid" if the transaction is confirmed (1)
|
||||||
) : transaction.confirmed === -1 ? (
|
|
||||||
"Declined" // Display "Declined" if the transaction is declined (-1)
|
|
||||||
) : transaction.confirmed === 2 ? (
|
|
||||||
"Confirm item has ready" // Display "Item ready" if the transaction is ready (2)
|
|
||||||
) : transaction.confirmed === 3 ? (
|
|
||||||
"Transaction success" // Display "Item ready" if the transaction is ready (2)
|
|
||||||
) : (
|
) : (
|
||||||
"Confirm availability" // Display "Confirm availability" if the transaction is not confirmed (0)
|
"Show payment" // Display "Confirm availability" if the transaction is not confirmed (0)
|
||||||
)}
|
)}
|
||||||
</ButtonWithReplica>
|
</ButtonWithReplica>
|
||||||
</div>
|
</div>
|
||||||
<h5
|
<h5
|
||||||
className={styles.DeclineButton}
|
className={`${styles.DeclineButton} ${
|
||||||
onClick={() => handleDecline(transaction.transactionId)}
|
isPaymentOpen ? styles.active : ""
|
||||||
|
}`}
|
||||||
|
onClick={() =>
|
||||||
|
isPaymentOpen
|
||||||
|
? setIsPaymentOpen(false)
|
||||||
|
: handleDecline(transaction.transactionId)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
cancel
|
{isPaymentOpen ? "back" : "cancel"}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
} from "../helpers/transactionHelpers";
|
} from "../helpers/transactionHelpers";
|
||||||
import { getTables } from "../helpers/tableHelper";
|
import { getTables } from "../helpers/tableHelper";
|
||||||
import TableCanvas from "../components/TableCanvas";
|
import TableCanvas from "../components/TableCanvas";
|
||||||
import ButtonWithReplica from "../components/ButtonWithReplica";
|
|
||||||
|
|
||||||
export default function Transactions({ propsShopId, sendParam, deviceType }) {
|
export default function Transactions({ propsShopId, sendParam, deviceType }) {
|
||||||
const { shopId, tableId } = useParams();
|
const { shopId, tableId } = useParams();
|
||||||
@@ -110,7 +109,7 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
|
|||||||
setSelectedTable(transaction.Table || { tableId: 0 })
|
setSelectedTable(transaction.Table || { tableId: 0 })
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{transaction.paymentClaimed && (
|
{transaction.paymentClaimed && transaction.confirmed < 2 && (
|
||||||
<div className={styles.RibbonBanner}>
|
<div className={styles.RibbonBanner}>
|
||||||
<img src={"https://i.imgur.com/yt6osgL.png"}></img>
|
<img src={"https://i.imgur.com/yt6osgL.png"}></img>
|
||||||
<h1>payment claimed</h1>
|
<h1>payment claimed</h1>
|
||||||
@@ -144,11 +143,14 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.TotalContainer}>
|
<div className={styles.TotalContainer}>
|
||||||
<ButtonWithReplica />
|
|
||||||
<button
|
<button
|
||||||
className={styles.PayButton}
|
className={styles.PayButton}
|
||||||
onClick={() => handleConfirm(transaction.transactionId)}
|
onClick={() => handleConfirm(transaction.transactionId)}
|
||||||
disabled={transaction.confirmed !== 0 || isPaymentLoading} // Disable button if confirmed (1) or declined (-1) or loading
|
disabled={
|
||||||
|
transaction.confirmed === -1 ||
|
||||||
|
transaction.confirmed === 3 ||
|
||||||
|
isPaymentLoading
|
||||||
|
} // Disable button if confirmed (1) or declined (-1) or loading
|
||||||
>
|
>
|
||||||
{isPaymentLoading ? (
|
{isPaymentLoading ? (
|
||||||
<ColorRing height="50" width="50" color="white" />
|
<ColorRing height="50" width="50" color="white" />
|
||||||
|
|||||||
@@ -98,6 +98,24 @@
|
|||||||
text-align: center; /* Center the text within the button */
|
text-align: center; /* Center the text within the button */
|
||||||
margin-bottom: 23px; /* Space at the bottom to match the PayButton */
|
margin-bottom: 23px; /* Space at the bottom to match the PayButton */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.DeclineButton.active {
|
||||||
|
position: relative;
|
||||||
|
z-index: 201;
|
||||||
|
font-family: "Poppins", sans-serif;
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 20px;
|
||||||
|
padding: 12px 24px; /* Add some padding for spacing */
|
||||||
|
color: rgba(88, 55, 50, 1);
|
||||||
|
background-color: transparent; /* No background */
|
||||||
|
border: none; /* No border */
|
||||||
|
margin: 0 auto; /* Center horizontally */
|
||||||
|
cursor: pointer;
|
||||||
|
display: block; /* Center the text horizontally */
|
||||||
|
text-align: center; /* Center the text within the button */
|
||||||
|
margin-bottom: 23px; /* Space at the bottom to match the PayButton */
|
||||||
|
}
|
||||||
.RoundedRectangle {
|
.RoundedRectangle {
|
||||||
position: relative;
|
position: relative;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
|
|||||||
Reference in New Issue
Block a user