ok
This commit is contained in:
@@ -1,46 +1,44 @@
|
||||
import React, { useRef, useEffect, useState } from "react";
|
||||
import styles from "./Cart.module.css";
|
||||
import ItemLister from "../components/ItemLister";
|
||||
import styles from "./Invoice.module.css";
|
||||
import { useParams, useLocation } from "react-router-dom"; // Changed from useSearchParams to useLocation
|
||||
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,
|
||||
}) {
|
||||
import ItemLister from "../components/ItemLister";
|
||||
import { getCartDetails } from "../helpers/itemHelper";
|
||||
import {
|
||||
handlePaymentFromClerk,
|
||||
handlePaymentFromGuestSide,
|
||||
handlePaymentFromGuestDevice,
|
||||
} from "../helpers/transactionHelpers";
|
||||
|
||||
export default function Invoice({ table, sendParam, deviceType, socket }) {
|
||||
const { shopId, tableCode } = useParams();
|
||||
sendParam({ shopId, tableCode });
|
||||
|
||||
const { goToShop, goToInvoice } = useNavigationHelpers(shopId, tableCode);
|
||||
const location = useLocation(); // Use useLocation hook instead of useSearchParams
|
||||
const searchParams = new URLSearchParams(location.search); // Pass location.search directly
|
||||
|
||||
// const email = searchParams.get("email");
|
||||
// const orderType = searchParams.get("orderType");
|
||||
// const tableNumber = searchParams.get("tableNumber");
|
||||
|
||||
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 [isPaymentLoading, setIsPaymentLoading] = useState(false); // State for payment button loading animation
|
||||
|
||||
const textareaRef = useRef(null);
|
||||
const [orderType, setOrderType] = useState("serve");
|
||||
const [tableNumber, setTableNumber] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const fetchCartItems = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const items = await getCartDetails(shopId);
|
||||
setLoading(false);
|
||||
setCartItems(items);
|
||||
|
||||
if (items) setCartItems(items);
|
||||
|
||||
const initialTotalPrice = items.reduce((total, itemType) => {
|
||||
// Calculate total price based on fetched cart items
|
||||
const totalPrice = items.reduce((total, itemType) => {
|
||||
return (
|
||||
total +
|
||||
itemType.itemList.reduce((subtotal, item) => {
|
||||
@@ -48,26 +46,51 @@ export default function Cart({
|
||||
}, 0)
|
||||
);
|
||||
}, 0);
|
||||
setTotalPrice(initialTotalPrice);
|
||||
setTotalPrice(totalPrice);
|
||||
} catch (error) {
|
||||
console.error("Error fetching cart items:", error);
|
||||
// Handle error if needed
|
||||
}
|
||||
};
|
||||
|
||||
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]);
|
||||
|
||||
const handlePay = async (isCash) => {
|
||||
setIsPaymentLoading(true);
|
||||
console.log("tipe" + deviceType);
|
||||
if (deviceType == "clerk") {
|
||||
const pay = await handlePaymentFromClerk(
|
||||
shopId,
|
||||
email,
|
||||
isCash ? "cash" : "cashless",
|
||||
orderType,
|
||||
tableNumber
|
||||
);
|
||||
} else if (deviceType == "guestSide") {
|
||||
const pay = await handlePaymentFromGuestSide(
|
||||
shopId,
|
||||
email,
|
||||
isCash ? "cash" : "cashless",
|
||||
orderType,
|
||||
tableNumber
|
||||
);
|
||||
} else if (deviceType == "guestDevice") {
|
||||
const socketId = socket.id;
|
||||
const pay = await handlePaymentFromGuestDevice(
|
||||
shopId,
|
||||
isCash ? "cash" : "cashless",
|
||||
orderType,
|
||||
table.tableNo || tableNumber,
|
||||
textareaRef.current.value,
|
||||
socketId
|
||||
);
|
||||
}
|
||||
|
||||
console.log("transaction from " + deviceType + "success");
|
||||
setIsPaymentLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const textarea = textareaRef.current;
|
||||
|
||||
@@ -84,29 +107,6 @@ export default function Cart({
|
||||
}
|
||||
}, [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);
|
||||
};
|
||||
@@ -118,94 +118,22 @@ export default function Cart({
|
||||
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(<div>Please enter a valid email address.</div>);
|
||||
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(
|
||||
<div>Table not found. Please enter a valid table number.</div>
|
||||
);
|
||||
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(<div>Please enter a table number.</div>);
|
||||
setIsModalOpen(true);
|
||||
}
|
||||
} else {
|
||||
console.log("getting with pickup");
|
||||
goToInvoice(orderType, tableNumber, email);
|
||||
}
|
||||
|
||||
setIsCheckoutLoading(false); // Stop loading animation
|
||||
};
|
||||
|
||||
if (loading)
|
||||
return (
|
||||
<div className="Loader">
|
||||
<div className="LoaderChild">
|
||||
<ThreeDots />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
else
|
||||
return (
|
||||
<div className={styles.Cart}>
|
||||
<div style={{ marginTop: "30px" }}></div>
|
||||
<h2 className={styles["Cart-title"]}>
|
||||
{totalItemsCount} {totalItemsCount !== 1 ? "items" : "item"} in Cart
|
||||
</h2>
|
||||
<div style={{ marginTop: "-45px" }}></div>
|
||||
return (
|
||||
<div className={styles.Invoice}>
|
||||
<div style={{ marginTop: "30px" }}></div>
|
||||
<h2 className={styles["Invoice-title"]}>Cart</h2>
|
||||
<div style={{ marginTop: "30px" }}></div>
|
||||
<div className={styles.RoundedRectangle}>
|
||||
{cartItems.map((itemType) => (
|
||||
<ItemLister
|
||||
key={itemType.itemTypeId}
|
||||
refreshTotal={refreshTotal}
|
||||
shopId={shopId}
|
||||
forCart={true}
|
||||
forInvoice={true}
|
||||
key={itemType.id}
|
||||
typeName={itemType.typeName}
|
||||
itemList={itemType.itemList}
|
||||
/>
|
||||
))}
|
||||
{deviceType != "guestDevice" && (
|
||||
<div className={styles.EmailContainer}>
|
||||
<label htmlFor="email">Email:</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
placeholder="log this transaction (optional)"
|
||||
value={email}
|
||||
onChange={handleEmailChange}
|
||||
className={styles.EmailInput}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={styles.OrderTypeContainer}>
|
||||
<span htmlFor="orderType">Order Type:</span>
|
||||
<select
|
||||
@@ -221,7 +149,10 @@ export default function Cart({
|
||||
|
||||
{/* tableId harus di check terlebih dahulu untuk mendapatkan tableNo */}
|
||||
</select>
|
||||
{orderType === "serve" && table.length < 1 && (
|
||||
</div>
|
||||
{orderType === "serve" && table.length < 1 && (
|
||||
<div className={styles.OrderTypeContainer}>
|
||||
<span htmlFor="orderType">Serve to:</span>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Table Number"
|
||||
@@ -229,38 +160,47 @@ export default function Cart({
|
||||
onChange={handleTableNumberChange}
|
||||
className={styles.TableNumberInput}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={styles.NoteContainer}>
|
||||
<span>Note</span>
|
||||
<span>Note :</span>
|
||||
<span></span>
|
||||
</div>
|
||||
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
className={styles.NoteInput}
|
||||
placeholder="Add a note..."
|
||||
/>
|
||||
|
||||
<div className={styles.NoteContainer}>
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
className={styles.NoteInput}
|
||||
placeholder="Add a note..."
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.TotalContainer}>
|
||||
<span>Total:</span>
|
||||
<span>Rp {totalPrice}</span>
|
||||
</div>
|
||||
<button onClick={handleCheckout} className={styles.CheckoutButton}>
|
||||
{isCheckoutLoading ? (
|
||||
</div>
|
||||
<div className={styles.PaymentOption}>
|
||||
<div className={styles.TotalContainer}>
|
||||
<span>Payment Option</span>
|
||||
<span></span>
|
||||
</div>
|
||||
<button className={styles.PayButton} onClick={() => handlePay(false)}>
|
||||
{isPaymentLoading ? (
|
||||
<ColorRing height="50" width="50" color="white" />
|
||||
) : (
|
||||
"Checkout"
|
||||
"Cashless"
|
||||
)}
|
||||
</button>
|
||||
<div onClick={goToShop} className={styles.BackToMenu}>
|
||||
Back to menu
|
||||
<div className={styles.Pay2Button} onClick={() => handlePay(true)}>
|
||||
{isPaymentLoading ? (
|
||||
<ColorRing height="12" width="12" color="white" />
|
||||
) : (
|
||||
"Cash"
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Modal isOpen={isModalOpen} onClose={() => handlCloseModal()}>
|
||||
{modalContent}
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
<div className={styles.PaymentOptionMargin}></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user