diff --git a/src/App.js b/src/App.js index 92e49ae..ceb1dc5 100644 --- a/src/App.js +++ b/src/App.js @@ -343,6 +343,7 @@ function App() { diff --git a/src/components/TableList.js b/src/components/TableList.js index 523355d..ffabe4d 100644 --- a/src/components/TableList.js +++ b/src/components/TableList.js @@ -9,10 +9,17 @@ const TableList = ({ shop, tables, onSelectTable, selectedTable }) => { const [bgImageUrl, setBgImageUrl] = useState(shop.qrBackground); const shopUrl = window.location.hostname + "/" + shop.cafeId; - const generateQRCodeUrl = (tableCode) => - `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent( - shopUrl + "/" + tableCode - )}`; + const generateQRCodeUrl = (tableCode) => { + if (tableCode != null) { + return `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent( + shopUrl + "/" + tableCode + )}`; + } else { + return `https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent( + shopUrl + )}`; + } + }; const handleBackgroundUrlChange = (newUrl) => { setBgImageUrl(newUrl); @@ -57,7 +64,7 @@ const TableList = ({ shop, tables, onSelectTable, selectedTable }) => { handleQrSave={handleQrSave} setInitialPos={setInitialPos} setInitialSize={setInitialSize} - qrCodeUrl={generateQRCodeUrl("sample")} + qrCodeUrl={generateQRCodeUrl("")} backgroundUrl={bgImageUrl} initialQrPosition={initialPos} initialQrSize={initialSize} diff --git a/src/helpers/transactionHelpers.js b/src/helpers/transactionHelpers.js index 703be3f..1fa44a8 100644 --- a/src/helpers/transactionHelpers.js +++ b/src/helpers/transactionHelpers.js @@ -50,6 +50,30 @@ export async function declineTransaction(transactionId) { } } +export async function cancelTransaction(transactionId) { + try { + console.log(transactionId); + const token = getLocalStorage("auth"); + const response = await fetch( + `${API_BASE_URL}/transaction/claim-transaction/${transactionId}`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + } + ); + + if (!response.ok) { + return false; + } + + return true; + } catch (error) { + console.error("Error:", error); + } +} export async function handleClaimHasPaid(transactionId) { try { console.log(transactionId); @@ -264,6 +288,7 @@ export const handlePaymentFromGuestDevice = async ( payment_type, serving_type, tableNo, + notes, socketId ) => { try { @@ -291,6 +316,7 @@ export const handlePaymentFromGuestDevice = async ( serving_type, tableNo, transactions: structuredItems, + notes: notes, socketId, }), } diff --git a/src/pages/Cart copy.js b/src/pages/Cart copy.js new file mode 100644 index 0000000..5818453 --- /dev/null +++ b/src/pages/Cart copy.js @@ -0,0 +1,266 @@ +import React, { useRef, useEffect, useState } from "react"; +import styles from "./Cart.module.css"; +import ItemLister from "../components/ItemLister"; +import { ThreeDots, ColorRing } from "react-loader-spinner"; +import { useParams } from "react-router-dom"; +import { useNavigationHelpers } from "../helpers/navigationHelpers"; +import { getTable } from "../helpers/tableHelper.js"; +import { getCartDetails } from "../helpers/itemHelper.js"; +import { getItemsByCafeId } from "../helpers/cartHelpers"; // Import getItemsByCafeId +import Modal from "../components/Modal"; // Import the reusable Modal component + +export default function Cart({ + table, + sendParam, + totalItemsCount, + deviceType, +}) { + const { shopId, tableCode } = useParams(); + sendParam({ shopId, tableCode }); + + const { goToShop, goToInvoice } = useNavigationHelpers(shopId, tableCode); + const [cartItems, setCartItems] = useState([]); + const [totalPrice, setTotalPrice] = useState(0); + const [orderType, setOrderType] = useState("serve"); + const [tableNumber, setTableNumber] = useState(""); + const [loading, setLoading] = useState(true); + const [isModalOpen, setIsModalOpen] = useState(false); + const [modalContent, setModalContent] = useState(null); + const [isCheckoutLoading, setIsCheckoutLoading] = useState(false); // State for checkout button loading animation + const [email, setEmail] = useState(""); + + const textareaRef = useRef(null); + + useEffect(() => { + const fetchCartItems = async () => { + try { + setLoading(true); + const items = await getCartDetails(shopId); + setLoading(false); + + if (items) setCartItems(items); + + const initialTotalPrice = items.reduce((total, itemType) => { + return ( + total + + itemType.itemList.reduce((subtotal, item) => { + return subtotal + item.qty * item.price; + }, 0) + ); + }, 0); + setTotalPrice(initialTotalPrice); + } catch (error) { + console.error("Error fetching cart items:", error); + } + }; + + fetchCartItems(); + + const textarea = textareaRef.current; + if (textarea) { + const handleResize = () => { + textarea.style.height = "auto"; + textarea.style.height = `${textarea.scrollHeight}px`; + }; + textarea.addEventListener("input", handleResize); + handleResize(); + return () => textarea.removeEventListener("input", handleResize); + } + }, [shopId]); + + useEffect(() => { + const textarea = textareaRef.current; + + if (textarea) { + const handleResize = () => { + textarea.style.height = "auto"; + textarea.style.height = `${textarea.scrollHeight}px`; + }; + + handleResize(); // Initial resize + + textarea.addEventListener("input", handleResize); + return () => textarea.removeEventListener("input", handleResize); + } + }, [textareaRef.current]); + + const refreshTotal = async () => { + try { + const items = await getItemsByCafeId(shopId); + const updatedTotalPrice = items.reduce((total, localItem) => { + const cartItem = cartItems.find((itemType) => + itemType.itemList.some((item) => item.itemId === localItem.itemId) + ); + + if (cartItem) { + const itemDetails = cartItem.itemList.find( + (item) => item.itemId === localItem.itemId + ); + return total + localItem.qty * itemDetails.price; + } + return total; + }, 0); + + setTotalPrice(updatedTotalPrice); + } catch (error) { + console.error("Error refreshing total price:", error); + } + }; + + const handleOrderTypeChange = (event) => { + setOrderType(event.target.value); + }; + + const handleTableNumberChange = (event) => { + setTableNumber(event.target.value); + }; + + const handleEmailChange = (event) => { + setEmail(event.target.value); + }; + + const handlCloseModal = () => { + setIsModalOpen(false); + setIsCheckoutLoading(false); + }; + + const isValidEmail = (email) => { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailRegex.test(email); + }; + + const handleCheckout = async () => { + setIsCheckoutLoading(true); // Start loading animation + + if (email != "" && !isValidEmail(email)) { + setModalContent(
Please enter a valid email address.
); + setIsModalOpen(true); + setIsCheckoutLoading(false); // Stop loading animation + return; + } + + if (orderType === "serve") { + console.log("serve"); + if (tableNumber !== "" && table.tableNo == undefined) { + console.log("getting with tableNumber"); + const table = await getTable(shopId, tableNumber); + if (!table) { + setModalContent( +
Table not found. Please enter a valid table number.
+ ); + setIsModalOpen(true); + } else { + goToInvoice(orderType, table.tableNo, email); + } + } else if (table.tableNo != undefined) { + console.log("getting with table code" + table.tableNo); + goToInvoice(orderType, null, email); + } else { + setModalContent(
Please enter a table number.
); + setIsModalOpen(true); + } + } else { + console.log("getting with pickup"); + goToInvoice(orderType, tableNumber, email); + } + + setIsCheckoutLoading(false); // Stop loading animation + }; + + if (loading) + return ( +
+
+ +
+
+ ); + else + return ( +
+
+

+ {totalItemsCount} {totalItemsCount !== 1 ? "items" : "item"} in Cart +

+
+ {cartItems.map((itemType) => ( + + ))} + {deviceType != "guestDevice" && ( +
+ + +
+ )} +
+ Order Type: + + {orderType === "serve" && table.length < 1 && ( + + )} +
+ +
+ Note + +
+ +