This commit is contained in:
frontend perkafean
2024-09-10 09:21:16 +00:00
parent 762bee40bb
commit f46639e05c
10 changed files with 768 additions and 337 deletions

View File

@@ -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>
);
}