From 4fa272875f35391c7c9607f0f6f95d9d6c17e9b6 Mon Sep 17 00:00:00 2001 From: Vassshhh Date: Wed, 27 Aug 2025 10:11:42 +0700 Subject: [PATCH] ok --- src/App.js | 192 +++++---- src/components/Header.js | 291 +++++++------ src/components/Item.js | 13 +- src/components/Item.module.css | 312 +++++++++++++- src/components/ItemConfig.js | 2 +- src/components/ItemType.js | 3 +- src/components/ItemType.module.css | 99 +++++ src/components/ItemTypeLister.css | 2 +- src/components/ItemTypeLister.js | 3 +- src/components/MusicPlayer.js | 6 +- src/pages/CafePage.js | 550 +++++++++++++++++-------- src/pages/Cart.js | 637 +++++++++++++++++------------ src/pages/Invoice.module.css | 277 ++++++++++++- src/pages/Join.module.css | 4 + src/pages/Message.js | 4 +- src/pages/Payment_claimed.js | 12 +- src/pages/Transaction_failed.js | 8 +- 17 files changed, 1694 insertions(+), 721 deletions(-) diff --git a/src/App.js b/src/App.js index 4551f49..6a122b2 100644 --- a/src/App.js +++ b/src/App.js @@ -10,7 +10,6 @@ import { } from "react-router-dom"; import socket from "./services/socketService"; - import Dashboard from "./pages/Dashboard"; import ScanMeja from "./pages/ScanMeja"; import CafePage from "./pages/CafePage"; @@ -27,7 +26,7 @@ import { getTableByCode } from "./helpers/tableHelper.js"; import { getTransactionsFromCafe, - checkIsMyTransaction + checkIsMyTransaction, } from "./helpers/transactionHelpers"; import { getConnectedGuestSides, @@ -45,7 +44,7 @@ import { } from "./helpers/subscribeHelpers.js"; import Modal from "./components/Modal"; // Import your modal component -import { requestNotificationPermission } from './services/notificationService'; // Import the notification service +import { requestNotificationPermission } from "./services/notificationService"; // Import the notification service function App() { const location = useLocation(); @@ -73,35 +72,32 @@ function App() { const [newTransaction, setNewTransaction] = useState({}); - const queryParams = new URLSearchParams(location.search); const tokenParams = queryParams.get("token"); - if(tokenParams) localStorage.setItem('auth', tokenParams) + if (tokenParams) localStorage.setItem("auth", tokenParams); const validTransactionStates = [ - 'new_transaction', - 'transaction_canceled', - 'transaction_pending', - 'transaction_confirmed', - 'payment_claimed', - 'transaction_success', - 'transaction_end', - 'transaction_failed', + "new_transaction", + "transaction_canceled", + "transaction_pending", + "transaction_confirmed", + "payment_claimed", + "transaction_success", + "transaction_end", + "transaction_failed", ]; - const calculateTotalsFromLocalStorage = () => { const { totalCount, totalPrice } = calculateTotals(shopId); setTotalItemsCount(totalCount); setTotalPrice(totalPrice); - // If 'lastTransaction' exists, proceed const lastTransaction = JSON.parse(localStorage.getItem("lastTransaction")); console.log(lastTransaction); if (lastTransaction != null) { - console.log(lastTransaction) + console.log(lastTransaction); setLastTransaction(lastTransaction); } }; @@ -145,9 +141,13 @@ function App() { return; } - setModal('transaction_confirmed', { transactionId: lastTransaction.transactionId }) - const myLastTransaction = await checkIsMyTransaction(lastTransaction.transactionId); - console.log(myLastTransaction) + setModal("transaction_confirmed", { + transactionId: lastTransaction.transactionId, + }); + const myLastTransaction = await checkIsMyTransaction( + lastTransaction.transactionId + ); + console.log(myLastTransaction); if (myLastTransaction.isMyTransaction) { setLastTransaction(lastTransaction); } else { @@ -155,7 +155,6 @@ function App() { } }; - const handleSetParam = async ({ shopIdentifier, tableCode }) => { setShopIdentifier(shopIdentifier); @@ -170,12 +169,14 @@ function App() { const fetchData = async () => { console.log("gettingItems"); try { - const { response, cafe, data } = await getItemTypesWithItems(shopIdentifier); + const { response, cafe, data } = await getItemTypesWithItems( + shopIdentifier + ); if (response.status === 200) { - setShopId(cafe.cafeId) + setShopId(cafe.cafeId); setShop(cafe); setShopItems(data); - console.log(data) + console.log(data); // Filter out unavailable items const filteredData = data .map((itemType) => ({ @@ -241,7 +242,7 @@ function App() { // Call `setModal` with content and parameters setModal("transaction_pending", data); - localStorage.setItem('cart', []); + localStorage.setItem("cart", []); calculateTotalsFromLocalStorage(); }); @@ -250,7 +251,7 @@ function App() { console.log(JSON.stringify(data)); setModal("transaction_confirmed", data); - localStorage.setItem('cart', []); + localStorage.setItem("cart", []); // const startTime = Date.now(); // Capture the start time // const timeout = 10000; // 10 seconds timeout in milliseconds @@ -266,7 +267,9 @@ function App() { // } // If 'lastTransaction' exists, proceed - const lastTransaction = JSON.parse(localStorage.getItem("lastTransaction")); + const lastTransaction = JSON.parse( + localStorage.getItem("lastTransaction") + ); console.log(lastTransaction); if (lastTransaction != null) { @@ -274,7 +277,6 @@ function App() { } }); - socket.on("transaction_success", async (data) => { console.log("transaction notification"); setModal("transaction_success", data); @@ -316,7 +318,6 @@ function App() { } }); - const handleNotificationClick = async () => { const permission = await requestNotificationPermission(); @@ -325,7 +326,7 @@ function App() { // Set up notifications or show a success modal } else { console.error("Notification permission denied."); - setModal('blocked_notification'); // Show modal for blocked notifications + setModal("blocked_notification"); // Show modal for blocked notifications } }; @@ -334,10 +335,21 @@ function App() { // Check current permission const searchParams = new URLSearchParams(location.search); - let searchModal = searchParams.get("modal") || ''; // Get transactionId or set it to empty string + let searchModal = searchParams.get("modal") || ""; // Get transactionId or set it to empty string - if (permission !== "granted" && searchModal == '') { - setModal("message", { captMessage: 'Notifikasi tidak aktif', descMessage: 'Aktifkan notifikasi supaya kamu tetap dapat info pesanan, meski sedang buka aplikasi lain.', yesText: 'Aktifkan', noText: 'Tutup' }, null, handleNotificationClick); + if (permission !== "granted" && searchModal == "") { + setModal( + "message", + { + captMessage: "Notifikasi tidak aktif", + descMessage: + "Aktifkan notifikasi supaya kamu tetap dapat info pesanan, meski sedang buka aplikasi lain.", + yesText: "Aktifkan", + noText: "Tutup", + }, + null, + handleNotificationClick + ); } }; @@ -346,10 +358,15 @@ function App() { removeLocalStorage("auth"); setDeviceType("guestDevice"); } else { - console.log(data) - if (data.data.user.cafeId != null) navigate(`/${data.data.user.cafeIdentityName}`, { replace: true }); + console.log(data); + if (data.data.user.cafeId != null) + navigate(`/${data.data.user.cafeIdentityName}`, { replace: true }); setUser(data.data.user); - if (data.data.latestOpenBillTransaction != null) localStorage.setItem('lastTransaction', JSON.stringify(data.data.latestOpenBillTransaction)) + if (data.data.latestOpenBillTransaction != null) + localStorage.setItem( + "lastTransaction", + JSON.stringify(data.data.latestOpenBillTransaction) + ); if ( data.data.user.password == "unsetunsetunset" && localStorage.getItem("settings") @@ -393,7 +410,6 @@ function App() { socket.on("updateQueue", ({ queue }) => { setQueue(queue); // Only set the queue if it's a valid non-empty array console.log("Updated Queue:", queue); // Log the valid queue - }); return () => { @@ -402,7 +418,6 @@ function App() { }, [socket, shopId]); async function checkIfStillViewingOtherTransaction(data) { - console.log("transaction notification"); console.log(modalContent); @@ -412,21 +427,21 @@ function App() { // Get current URL's search parameters inside the socket event handler const searchParams = new URLSearchParams(location.search); - let transaction_info = searchParams.get("transactionId") || ''; // Get transactionId or set it to empty string + let transaction_info = searchParams.get("transactionId") || ""; // Get transactionId or set it to empty string + + if (response[0].transactionId != transaction_info) + transactionList.current = response; - if(response[0].transactionId != transaction_info) transactionList.current = response; - let depthh = transactionList.current.findIndex( - item => item.transactionId.toString() === transaction_info.toString() + (item) => item.transactionId.toString() === transaction_info.toString() ); - if (transaction_info != response[0].transactionId) - setDepth(depthh); + if (transaction_info != response[0].transactionId) setDepth(depthh); else setModal("new_transaction", data); - console.log(transaction_info == response[0].transactionId) + console.log(transaction_info == response[0].transactionId); // If transaction_info is an empty string, set the modal - if (transaction_info.toString() == '') return false; + if (transaction_info.toString() == "") return false; else return true; } @@ -436,13 +451,14 @@ function App() { console.log("transaction notification"); setNewTransaction(data); - if(!location.pathname.endsWith('/transactions')){ - const isViewingOtherTransaction = await checkIfStillViewingOtherTransaction(data); - // If transaction_info is an empty string, set the modal - if (!isViewingOtherTransaction) { - setModal("new_transaction", data); + if (!location.pathname.endsWith("/transactions")) { + const isViewingOtherTransaction = + await checkIfStillViewingOtherTransaction(data); + // If transaction_info is an empty string, set the modal + if (!isViewingOtherTransaction) { + setModal("new_transaction", data); + } } - } // Show browser notification let permission = Notification.permission; if (permission !== "granted") return; @@ -458,13 +474,14 @@ function App() { console.log("transaction notification"); setNewTransaction(data); - if(location.pathname != '/transactions'){ - const isViewingOtherTransaction = await checkIfStillViewingOtherTransaction(data); - // If transaction_info is an empty string, set the modal - if (!isViewingOtherTransaction) { - setModal("new_transaction", data); - navigate(`?transactionId=${data.transactionId}`, { replace: true }); - } + if (location.pathname != "/transactions") { + const isViewingOtherTransaction = + await checkIfStillViewingOtherTransaction(data); + // If transaction_info is an empty string, set the modal + if (!isViewingOtherTransaction) { + setModal("new_transaction", data); + navigate(`?transactionId=${data.transactionId}`, { replace: true }); + } } }); @@ -473,34 +490,36 @@ function App() { socket.off("transaction_created"); socket.off("transaction_canceled"); }; - }, [socket, shopId, location]); // Ensure location is in the dependencies to respond to changes in the URL + }, [socket, shopId, location]); // Ensure location is in the dependencies to respond to changes in the URL function handleMoveToTransaction(direction, from) { console.log(direction); console.log(from); // Find the current index based on the 'from' transactionId - const currentIndex = transactionList.current.findIndex(item => item.transactionId == from); + const currentIndex = transactionList.current.findIndex( + (item) => item.transactionId == from + ); // Determine the new transactionId based on the direction let newTransactionId; - if (direction === 'next') { - + if (direction === "next") { // If we're not at the last transaction, get the next transactionId - newTransactionId = currentIndex < transactionList.current.length - 1 - ? transactionList.current[currentIndex + 1].transactionId - : from; // If already at the end, stay on the current transactionId - } else if (direction === 'previous') { - + newTransactionId = + currentIndex < transactionList.current.length - 1 + ? transactionList.current[currentIndex + 1].transactionId + : from; // If already at the end, stay on the current transactionId + } else if (direction === "previous") { setDepth(currentIndex - 1); // If we're not at the first transaction, get the previous transactionId - newTransactionId = currentIndex > 0 - ? transactionList.current[currentIndex - 1].transactionId - : from; // If already at the beginning, stay on the current transactionId + newTransactionId = + currentIndex > 0 + ? transactionList.current[currentIndex - 1].transactionId + : from; // If already at the beginning, stay on the current transactionId } // Log the new transactionId - console.log('New Transaction ID:', newTransactionId); + console.log("New Transaction ID:", newTransactionId); // Update the URL with the new transactionId using navigate navigate(`?transactionId=${newTransactionId}`, { replace: true }); @@ -510,7 +529,6 @@ function App() { // setModalContent({ cafeId: shopId, transactionId: newTransactionId }); } - const handleModalFromURL = () => { const queryParams = new URLSearchParams(location.search); const modal = queryParams.get("modal"); @@ -542,8 +560,8 @@ function App() { document.body.style.overflow = "hidden"; setIsModalOpen(true); - setModalContent(content) - console.log(onCloseFunction) + setModalContent(content); + console.log(onCloseFunction); if (onCloseFunction) { setOnModalCloseFunction(() => onCloseFunction); // Store the close function @@ -560,7 +578,8 @@ function App() { const closeModal = (closeTheseContent = []) => { if ( Array.isArray(closeTheseContent) && - (closeTheseContent.length === 0 || closeTheseContent.includes(modalContent)) + (closeTheseContent.length === 0 || + closeTheseContent.includes(modalContent)) ) { setIsModalOpen(false); setModalContent(null); @@ -569,16 +588,16 @@ function App() { const queryParams = new URLSearchParams(location.search); // Clear all query parameters - queryParams.keys() && [...queryParams.keys()].forEach(key => { - queryParams.delete(key); - }); + queryParams.keys() && + [...queryParams.keys()].forEach((key) => { + queryParams.delete(key); + }); // Update the URL without any query parameters navigate({ search: queryParams.toString() }, { replace: true }); } }; - // useEffect(() => { // const askNotificationPermission = async () => { // let permission = Notification.permission; @@ -637,11 +656,15 @@ function App() { useEffect(() => { if ("serviceWorker" in navigator) { - navigator.serviceWorker.register("/service-worker.js") - .then(registration => { - console.log("Service Worker registered with scope:", registration.scope); + navigator.serviceWorker + .register("/service-worker.js") + .then((registration) => { + console.log( + "Service Worker registered with scope:", + registration.scope + ); }) - .catch(error => { + .catch((error) => { console.error("Service Worker registration failed:", error); }); } @@ -702,6 +725,9 @@ function App() { cartItemsLength={totalItemsCount} totalPrice={totalPrice} lastTransaction={lastTransaction} + shop={shop} + totalItemsCount={totalItemsCount} + deviceType={deviceType} /> } diff --git a/src/components/Header.js b/src/components/Header.js index 38ab8a4..c870c80 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -35,11 +35,16 @@ const Title = styled.h2` font-family: "Plus Jakarta Sans", sans-serif; font-weight: 500; font-style: normal; - font-size:${(props) => (props.HeaderSize)}; + font-size: ${(props) => props.HeaderSize}; color: rgba(88, 55, 50, 1); text-transform: uppercase; + + @media (min-width: 768px) { + font-size: 2vw; + } `; + const ProfileName = styled.h2` position: absolute; font-family: "Plus Jakarta Sans", sans-serif; @@ -81,8 +86,8 @@ const gg = keyframes` height: 60px; } 100% { - top: 45px; - right: 51px; + top: 5px; + right: 20px; width: 200px; height: 40px; } @@ -90,8 +95,8 @@ const gg = keyframes` const ss = keyframes` 0% { - top: 45px; - right: 51px; + top: 5px; + right: 20px; width: 200px; height: 40px; } @@ -127,8 +132,8 @@ const g = keyframes` height: 60px; } 100% { - top: 28px; - right: 242px; + top: 34px; + right: 229px; width: 40px; height: 40px; } @@ -137,7 +142,7 @@ const g = keyframes` const s = keyframes` 0% { top: 28px; - right: 242px; + right: 229px; width: 40px; height: 40px; } @@ -151,14 +156,15 @@ const s = keyframes` const grow = keyframes` 0% { - right: 12px; + right: 0px; + top: 0px; width: 60px; height: 60px; border-top-left-radius: 50%; border-bottom-left-radius: 50%; } 100% { - right: 28px; + right: -17px; width: 300px; border-top-left-radius: 15px; border-bottom-left-radius: 15px; @@ -167,13 +173,14 @@ const grow = keyframes` const shrink = keyframes` 0% { - right: 12px; + right: -17px; width: 300px; height: auto; border-radius: 20px; } 100% { - right: 28px; + right: 0px; + top: 0px; width: 60px; height: 60px; border-radius: 50%; @@ -182,7 +189,7 @@ const shrink = keyframes` const Rectangle = styled.div` overflow-y: hidden; position: absolute; - top: 39px; + top: 9px; right: 12px; width: 200px; max-height: 87vh; /* or another appropriate value */ @@ -321,61 +328,107 @@ const Header = ({ // Otherwise, use the possessive function return `${cafeName}'s menu`; }; - return ( + return ( - - - {shopName == null - ? HeaderText == null - ? "kedaimaster" - : HeaderText - : shopName} - -
- - - {showProfile && user.username !== undefined ? user.username : "guest"} - - {showRectangle && ( - - - {guestSideOfClerk && guestSideOfClerk.clerkUsername && ( - - this is the guest side of {guestSideOfClerk.clerkUsername} - - )} - {user.username !== undefined && ( - setModal("edit_account")}> - Kelola akun - - )} - {user.roleId == 0 && ( - setModal('create_coupon', {})}>Buat Voucher)} - {shopId && user.roleId == 1 && ( - Dashboard)} - {shopId && - user.user_id == shopOwnerId && - user.username !== undefined && - user.roleId === 1 && ( - <> - - - {shopName} + + + {shopName == null + ? HeaderText == null + ? "kedaimaster" + : HeaderText + : shopName} + +
+ + + {showProfile && user.username !== undefined ? user.username : "guest"} + + {showRectangle && ( + + + {guestSideOfClerk && guestSideOfClerk.clerkUsername && ( + + this is the guest side of {guestSideOfClerk.clerkUsername} + + )} + {user.username !== undefined && ( + setModal("edit_account")}> + Kelola akun + + )} + {user.roleId == 0 && ( + setModal('create_coupon', {})}>Buat Voucher)} + {shopId && user.roleId == 1 && ( + Dashboard)} + {shopId && + user.user_id == shopOwnerId && + user.username !== undefined && + user.roleId === 1 && ( + <> + + + {shopName} + + setModal("reports")}>Lihat laporan + setModal("add_material")}> + Kelola stok + + + + Konfigurasi + setModal("welcome_config")}> + Desain kafe + + setModal("edit_tables")}> + Identifikasi kedai + + setModal("payment_option")}> + Metode pembayaran + + + + Kasir + setModal("create_clerk")}> + + Tambah + + {shopClerks && + shopClerks.map((key, index) => ( + + {shopClerks[index].username} + + + ))} + + + )} + {user.username !== undefined && + user.cafeId == shopId && + user.roleId === 2 && ( + + {shopName} + - Mode Edit   + Mode Edit  setIsEditMode(!isEditMode)} /> - setModal("reports")}>Lihat laporan setModal("add_material")}> Kelola stok @@ -392,97 +445,43 @@ const Header = ({ Metode pembayaran - - Kasir - setModal("create_clerk")}> - + Tambah - - {shopClerks && - shopClerks.map((key, index) => ( - - {shopClerks[index].username} - + {user.username !== undefined && + user.roleId == 2 && + user.cafeId == shopId && ( + + Tablet tamu + + + Tambah - ))} - - - - )} - {user.username !== undefined && - user.cafeId == shopId && - user.roleId === 2 && ( - - {shopName} - - - Mode Edit  - setIsEditMode(!isEditMode)} - /> - - setModal("add_material")}> - Kelola stok - - - - Konfigurasi - setModal("welcome_config")}> - Desain kafe - - setModal("edit_tables")}> - Identifikasi kedai - - setModal("payment_option")}> - Metode pembayaran - - - {user.username !== undefined && - user.roleId == 2 && - user.cafeId == shopId && ( - - Tablet tamu - - + Tambah + {guestSides && + guestSides.map((key, index) => ( + + guest side {index + 1} + + + ))} - {guestSides && - guestSides.map((key, index) => ( - - guest side {index + 1} - - - ))} - - )} + )} - setModal("reports")}>Laporan - + setModal("reports")}>Laporan + + )} + {user.username !== undefined && ( + Logout )} - {user.username !== undefined && ( - Logout - )} - - - )} -
-
+
+
+ )} +
+
); }; diff --git a/src/components/Item.js b/src/components/Item.js index 1a952da..de6a522 100644 --- a/src/components/Item.js +++ b/src/components/Item.js @@ -29,6 +29,10 @@ const Item = ({ const [itemDescription, setItemDescription] = useState(initialDescription); const fileInputRef = useRef(null); +const formatToRupiah = (value) => { + if (typeof value !== "number") return value; + return value.toLocaleString("id-ID"); +}; useEffect(() => { console.log(imageUrl); console.log(selectedImage); @@ -156,7 +160,6 @@ const Item = ({ {forInvoice && ( <> -

x

{itemQty}

)} @@ -208,12 +211,12 @@ const Item = ({ marginLeft: '1rem', marginRight: '0.5rem', marginTop: '0.125rem' - }}>{promoPrice} + }}>{formatToRupiah(promoPrice)} {initialPrice} + }}>{formatToRupiah(initialPrice)} : @@ -223,7 +226,7 @@ const Item = ({ {initialPrice} + }}>{formatToRupiah(initialPrice)} } @@ -302,7 +305,7 @@ const Item = ({ ))} {forInvoice && ( -

Rp {itemQty * (promoPrice > 0? promoPrice : itemPrice)}

+

Rp {itemQty * (promoPrice > 0? formatToRupiah(promoPrice) : formatToRupiah(itemPrice))}

)} {forCart && ( diff --git a/src/components/Item.module.css b/src/components/Item.module.css index c72de7f..4f0a4a9 100644 --- a/src/components/Item.module.css +++ b/src/components/Item.module.css @@ -13,9 +13,12 @@ margin-bottom: 5px; color: rgba(88, 55, 50, 1); font-size: 32px; - box-sizing: border-box; /* Include padding and border in the element's total width */ - width: 100%; /* Ensure the item does not exceed the parent's width */ - overflow: hidden; /* Prevent internal overflow */ + box-sizing: border-box; + /* Include padding and border in the element's total width */ + width: 100%; + /* Ensure the item does not exceed the parent's width */ + overflow: hidden; + /* Prevent internal overflow */ padding-top: 10px; margin-bottom: 5px; } @@ -24,7 +27,7 @@ /* border-top: 2px solid #00000017; */ } -.notLast{ +.notLast { padding-bottom: 10px; border-bottom: 2px solid #00000017; } @@ -40,7 +43,8 @@ } .itemInvoice:last-child { - margin-bottom: 0; /* Remove margin-bottom for the last child */ + margin-bottom: 0; + /* Remove margin-bottom for the last child */ } .itemImage { @@ -102,7 +106,8 @@ .itemName { font-family: "Plus Jakarta Sans", sans-serif; font-style: normal; - width: calc(100% - 15px); /* Adjust the width to prevent overflow */ + width: calc(100% - 15px); + /* Adjust the width to prevent overflow */ font-size: 5vw; font-weight: 500; margin-top: 0; @@ -131,7 +136,8 @@ font-family: "Plus Jakarta Sans", sans-serif; font-style: normal; font-weight: 600; - width: calc(100% - 15px); /* Adjust the width to prevent overflow */ + width: calc(100% - 15px); + /* Adjust the width to prevent overflow */ font-size: 3.3vw; /* margin-bottom: 35px; */ margin-left: 5px; @@ -175,7 +181,8 @@ font-family: "Plus Jakarta Sans", sans-serif; font-style: normal; font-weight: 600; - width: 30px; /* Adjust the width to prevent overflow */ + width: 30px; + /* Adjust the width to prevent overflow */ font-size: 0.9rem; margin-bottom: 10px; text-align: center; @@ -184,18 +191,19 @@ .addButton { background-color: #ffffff; - border: 2px solid #a8c7a9; - /* border: none; */ - display: inline-block; - font-size: 14px; - font-weight: 600; - cursor: pointer; - width: 87px; - height: 32px; - margin-left: 5px; - margin-top: 5px; - border-radius: 20px; + border: 2px solid #a8c7a9; + /* border: none; */ + display: inline-block; + font-size: 14px; + font-weight: 600; + cursor: pointer; + width: 87px; + height: 32px; + margin-left: 5px; + margin-top: 5px; + border-radius: 20px; } + .grayscale { filter: grayscale(100%); } @@ -203,6 +211,7 @@ .disabled { color: gray; } + .plusNegative { width: 35px; height: 35px; @@ -217,6 +226,7 @@ left: -33px; top: 21px; } + .remove { width: 25px; height: 25px; @@ -249,3 +259,267 @@ left: 15px; right: 15px; } + +@media (min-width: 768px) { + .itemContainer { + display: flex; + flex-direction: column; + /* gap: 10px; */ + } + + .item { + display: flex; + align-items: stretch; + justify-content: space-between; + padding-left: 5px; + margin-top: 5px; + margin-bottom: 5px; + color: rgba(88, 55, 50, 1); + font-size: 32px; + box-sizing: border-box; + /* Include padding and border in the element's total width */ + width: 100%; + /* Ensure the item does not exceed the parent's width */ + overflow: hidden; + /* Prevent internal overflow */ + padding-top: 10px; + margin-bottom: 5px; + } + + .item:not(.itemInvoice) { + /* border-top: 2px solid #00000017; */ + } + + .notLast { + padding-bottom: 10px; + border-bottom: 2px solid #00000017; + } + + .itemInvoice { + flex-direction: row; + align-items: center; + justify-content: space-around; + font-size: 18px; + margin-top: 0px; + margin-bottom: 0px; + padding-top: 0px; + } + + .itemInvoice:last-child { + margin-bottom: 0; + /* Remove margin-bottom for the last child */ + } + + .itemImage { + width: 100%; + height: 100%; + } + + .imageContainer { + position: relative; + width: 20%; + height: 20%; + border-radius: 12px; + object-fit: cover; + } + + .overlay { + position: absolute; + top: 15px; + left: 8px; + right: 8px; + bottom: 15px; + background-color: rgba(0, 0, 0, 0.5); + color: white; + display: flex; + justify-content: center; + align-items: center; + border-radius: 20px; + cursor: pointer; + transition: background-color 0.3s ease; + font-size: 3.3vw; + } + + .overlay:hover { + background-color: rgba(0, 0, 0, 0.7); + } + + .fileInput { + display: none; + } + + .itemDetails { + display: flex; + flex-direction: column; + justify-content: space-between; + margin-left: 10px; + margin-right: 10px; + flex-grow: 1; + } + + .itemInvoiceDetails { + display: flex; + flex-direction: column; + justify-content: space-between; + margin-left: 10px; + margin-top: -15px; + flex-grow: 1; + } + + .itemName { + font-family: "Plus Jakarta Sans", sans-serif; + font-style: normal; + width: calc(100% - 15px); + /* Adjust the width to prevent overflow */ + font-size: 5vw; + font-weight: 500; + margin-top: 0; + margin: 0 5px; + color: rgba(88, 55, 50, 1); + background-color: transparent; + text-transform: capitalize; + } + + .itemInvoiceName { + width: calc(260% - 15px); + background-color: transparent; + font-size: 1.3rem; + font-weight: 500; + } + + .multiplySymbol { + font-weight: 600; + } + + .qtyInvoice { + font-weight: 500; + } + + .itemPrice { + font-family: "Plus Jakarta Sans", sans-serif; + font-style: normal; + font-weight: 600; + width: calc(100% - 15px); + /* Adjust the width to prevent overflow */ + font-size: 3.3vw; + /* margin-bottom: 35px; */ + margin-left: 5px; + color: #3a3a3a; + background-color: transparent; + } + + .itemPriceInvoice { + font-family: "Plus Jakarta Sans", sans-serif; + font-style: normal; + font-weight: 600; + font-size: 0.9rem; + margin-left: 5px; + color: #d9c61c; + text-align: right; + margin-top: 22px; + } + + .itemQty { + display: flex; + align-items: center; + font-size: 0.9rem; + margin-left: 5px; + color: #a8c7a9; + fill: #a8c7a9; + height: 40px; + } + + .itemQtyValue { + font-family: "Plus Jakarta Sans", sans-serif; + font-style: normal; + font-weight: 600; + margin-top: 19px; + margin-left: 1px; + margin-right: 1px; + width: 25px; + text-align: center; + } + + .itemQtyInput { + font-family: "Plus Jakarta Sans", sans-serif; + font-style: normal; + font-weight: 600; + width: 30px; + /* Adjust the width to prevent overflow */ + font-size: 0.9rem; + margin-bottom: 10px; + text-align: center; + background-color: transparent; + } + + .addButton { + background-color: #ffffff; + border: 2px solid #a8c7a9; + /* border: none; */ + display: inline-block; + font-size: 14px; + font-weight: 600; + cursor: pointer; + width: 87px; + height: 32px; + margin-left: 5px; + margin-top: 5px; + border-radius: 20px; + } + + .grayscale { + filter: grayscale(100%); + } + + .disabled { + color: gray; + } + + .plusNegative { + width: 35px; + height: 35px; + margin: 2.5px 0 -0.5px 0px; + } + + .plusNegative2 { + width: 84px; + height: 21px; + position: absolute; + transform: rotate(45deg); + left: -33px; + top: 21px; + } + + .remove { + width: 25px; + height: 25px; + margin-top: -10px; + margin-right: 10px; + } + + .itemInvoice .itemDetails { + flex-direction: row; + justify-content: space-between; + align-items: center; + } + + .itemInvoice .itemName, + .itemInvoice .itemPrice, + .itemInvoice .itemQty .qtyInvoice .multiplySymbol { + font-size: 0.9rem; + } + + .blank { + border: 1px solid #000000; + } + + .notblank { + border: 1px solid #ffffff00; + } + + .createItem { + position: absolute; + left: 15px; + right: 15px; + } +} \ No newline at end of file diff --git a/src/components/ItemConfig.js b/src/components/ItemConfig.js index 8b917f8..fb55f3d 100644 --- a/src/components/ItemConfig.js +++ b/src/components/ItemConfig.js @@ -243,7 +243,7 @@ const ItemConfig = ({ ) : ( - isBeingEdit ? 'Simpan' : 'Buat Item' + isBeingEdit ? 'Simpan' : 'Simpan' )} diff --git a/src/components/ItemType.js b/src/components/ItemType.js index bb931f7..8fc8b7d 100644 --- a/src/components/ItemType.js +++ b/src/components/ItemType.js @@ -9,6 +9,7 @@ export default function ItemType({ imageUrl, selected, rectangular, + typeLength }) { const inputRef = useRef(null); const [namee, setName] = useState(name); @@ -68,7 +69,7 @@ export default function ItemType({ : "item-type-nomargin" ] } - style={{ zIndex: blank ? 301 : "inherit" }} + style={{ zIndex: blank ? 301 : "inherit", width: `calc(${100 / (Math.min(typeLength, 3) + 1)}% - 10px)` }} >
( - itemType.itemList.length > 0 || (user && (user.user_id == shopOwnerId || user.cafeId == shopId))) && ( + onFilterChange(itemType.itemTypeId)} selected={filterId === itemType.itemTypeId} + typeLength={itemTypes.length} /> ) )} diff --git a/src/components/MusicPlayer.js b/src/components/MusicPlayer.js index 811b456..dda39fd 100644 --- a/src/components/MusicPlayer.js +++ b/src/components/MusicPlayer.js @@ -367,7 +367,7 @@ export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLo const [text, setText] = useState("Menunggu musik favoritmu"); const textIndex = useRef(0); - const [messages, setMessages] = useState(["Menunggu musik favoritmu", "Klik untuk putar musik favoritmu"]); + const [messages, setMessages] = useState(["Menunggu musik favoritmu", "Upgrade to use"]); useEffect(() => { @@ -376,7 +376,7 @@ export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLo currentSong != null && currentSong[0]?.trackId != 'kCGs5_oCtBE' && currentSong[0]?.trackId != 'O8eYd7oAZtA' && currentSong[0]?.name != undefined ? `${currentSong[0]?.name} - ${currentSong[0]?.artist}` : "Menunggu musik favoritmu", - "Klik untuk putar musik favoritmu" + "Upgrade to use" ]; setMessages(newMessages); @@ -421,7 +421,7 @@ export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLo return (
= 768); + + useEffect(() => { + const handleResize = () => { + setIsTablet(window.innerWidth >= 768); + }; + + window.addEventListener("resize", handleResize); + return () => window.removeEventListener("resize", handleResize); + }, []); useEffect(() => { if (window.gtag && shopIdentifier) { - window.gtag('event', 'page_view', { + window.gtag("event", "page_view", { page_title: `Cafe - ${shopIdentifier}`, page_location: window.location.href, page_path: `/` + shopIdentifier, @@ -116,22 +137,26 @@ function CafePage({ // checkWelcomePageConfig(); }, [welcomePageConfig]); - useEffect(() => { function fetchData() { - console.log(user.user_id == shopOwnerId) + console.log(user.user_id == shopOwnerId); setModal("create_item"); } - console.log(getLocalStorage('auth')) + console.log(getLocalStorage("auth")); if (getLocalStorage("auth") != null) { const executeFetch = async () => { while (user.length == 0) { await new Promise((resolve) => setTimeout(resolve, 100)); // Wait until the user is not null } - console.log(user) - console.log('open') - if (user.length != 0 && user.user_id == shopOwnerId && shopItems.length == 0) fetchData(); + console.log(user); + console.log("open"); + if ( + user.length != 0 && + user.user_id == shopOwnerId && + shopItems.length == 0 + ) + fetchData(); }; executeFetch(); } @@ -154,13 +179,39 @@ function CafePage({ socket.on("joined-room", (response) => { const { isSpotifyNeedLogin, isExceededDeadline } = response; setNeedSpotifyLogin(isSpotifyNeedLogin); - if (isExceededDeadline) setModal("message", { captMessage: 'Kafe sedang tidak tersedia' }); + if (isExceededDeadline) + setModal("message", { captMessage: "Kafe sedang tidak tersedia" }); setIsExceededDeadline(isExceededDeadline); }); } if (socket) fetchData(); }, [socket]); + useEffect(() => { + const isTablet = window.innerWidth >= 768; + + const handleFirstClick = async () => { + if ( + isTablet && + document.fullscreenEnabled && + !document.fullscreenElement + ) { + try { + await document.documentElement.requestFullscreen(); + document.removeEventListener("click", handleFirstClick); + } catch (err) { + console.warn("Gagal masuk fullscreen:", err); + } + } + }; + + // Tambahkan listener satu kali + document.addEventListener("click", handleFirstClick); + + return () => { + document.removeEventListener("click", handleFirstClick); + }; + }, []); const handleGetStarted = () => { setIsStarted(false); @@ -175,16 +226,19 @@ function CafePage({ const newItems = [...shopItems]; let targetIndex; - if (direction === 'up' && index > 0) { + if (direction === "up" && index > 0) { targetIndex = index - 1; - } else if (direction === 'down' && index < newItems.length - 1) { + } else if (direction === "down" && index < newItems.length - 1) { targetIndex = index + 1; } console.log(index); console.log(targetIndex); if (targetIndex !== undefined) { // Swap items - [newItems[index], newItems[targetIndex]] = [newItems[targetIndex], newItems[index]]; + [newItems[index], newItems[targetIndex]] = [ + newItems[targetIndex], + newItems[index], + ]; newItems[index].order = targetIndex; newItems[targetIndex].order = index; @@ -192,9 +246,14 @@ function CafePage({ // Call the API to move the item type try { - await moveItemType(itemTypeId, previousItems[targetIndex].itemTypeId, index, targetIndex); + await moveItemType( + itemTypeId, + previousItems[targetIndex].itemTypeId, + index, + targetIndex + ); } catch (error) { - console.error('Error moving item type:', error); + console.error("Error moving item type:", error); // Revert the changes if the backend fails setShopItems(previousItems); } @@ -224,156 +283,265 @@ function CafePage({ isFullscreen={true} /> ) : ( */} -
+
+ {API_BASE_URL != "https://dev.api.kedaimaster.com" && + API_BASE_URL != "https://api.kedaimaster.com" && ( +
+ )} +
+
+
setIsEditMode(e)} + isEditMode={isEditMode} + /> + + {user.username !== undefined && + (user.cafeId === shopId || user.user_id === shopOwnerId) && + (user.roleId === 1 || user.roleId === 2) && ( +
+ Mode Edit  + setIsEditMode(!isEditMode)} + /> +
+ )} - {API_BASE_URL != 'https://dev.api.kedaimaster.com' && API_BASE_URL != 'https://api.kedaimaster.com' && -
- } -
-
setIsEditMode(e)} - isEditMode={isEditMode} - /> - { - user.username !== undefined && - (user.cafeId === shopId || user.user_id === shopOwnerId) && - (user.roleId === 1 || user.roleId === 2) && ( -
- Mode Edit  - setIsEditMode(!isEditMode)} - /> -
- ) -} - - setFilterId(e)} - filterId={filterId} - beingEditedType={beingEditedType} - setBeingEditedType={setBeingEditedType} - /> - {/*
*/} -
- {shopItems - .filter( - (itemType) => - filterId == 0 || itemType.itemTypeId === filterId - ) - .map((itemType, index) => ( - moveItemTypeHandler(e, 'up', index)} - moveItemTypeDown={(e) => moveItemTypeHandler(e, 'down', index)} - isEditMode={isEditMode} - beingEditedType={beingEditedType} - setBeingEditedType={setBeingEditedType} - raw={isEditMode || filterId == 0 ? false : true} - handleCreateItem={( - itemTypeID, - name, - price, - selectedImage, - description, - promoPrice, - ) => - createItem( - shopId, + setFilterId(e)} + filterId={filterId} + beingEditedType={beingEditedType} + setBeingEditedType={setBeingEditedType} + /> + {/*
*/} +
+ {shopItems + .filter( + (itemType) => + filterId == 0 || itemType.itemTypeId === filterId + ) + .map((itemType, index) => ( + + moveItemTypeHandler(e, "up", index) + } + moveItemTypeDown={(e) => + moveItemTypeHandler(e, "down", index) + } + isEditMode={isEditMode} + beingEditedType={beingEditedType} + setBeingEditedType={setBeingEditedType} + raw={isEditMode || filterId == 0 ? false : true} + handleCreateItem={( + itemTypeID, name, price, selectedImage, - itemTypeID, description, - promoPrice, - ) - } - handleUpdateItem={(itemId, name, price, selectedImage, description, promoPrice) => - updateItem(itemId, name, price, selectedImage, description, promoPrice) - } - /> - ))} - {!isEditMode && (user.username || cartItemsLength > 0) && -
- {(lastTransaction != null || cartItemsLength > 0) && -
-
{lastTransaction != null && '+'}{cartItemsLength} item
-
- {((lastTransaction == null || lastTransaction?.payment_type != 'paylater')) ? - Rp{totalPrice} - : - Open bill - } -
- - - + promoPrice + ) => + createItem( + shopId, + name, + price, + selectedImage, + itemTypeID, + description, + promoPrice + ) + } + handleUpdateItem={( + itemId, + name, + price, + selectedImage, + description, + promoPrice + ) => + updateItem( + itemId, + name, + price, + selectedImage, + description, + promoPrice + ) + } + /> + ))} + {!isEditMode && !isTablet && (user.username || cartItemsLength > 0) && ( +
+ {(lastTransaction != null || cartItemsLength > 0) && ( +
+
+ {lastTransaction != null && "+"} + {cartItemsLength} item +
+
+ {lastTransaction == null || + lastTransaction?.payment_type != "paylater" ? ( + + Rp{totalPrice} + + ) : ( + + Open bill + + )} +
+ + + +
-
- } - {user.username && -
0 ? '6px' : '0px' }}> -
-
- - - 0 + ? "6px" + : "0px", + }} + > +
+
+ + + - - - + /> + + +
-
- } -
- } + )} +
+ )} +
+ {/* */}
- + {isTablet && +
+ +
+ }
{/* )} */} diff --git a/src/pages/Cart.js b/src/pages/Cart.js index 2780d92..446a6b9 100644 --- a/src/pages/Cart.js +++ b/src/pages/Cart.js @@ -14,7 +14,7 @@ import { handlePaymentFromGuestSide, handlePaymentFromGuestDevice, handleExtendFromGuestDevice, - handleCloseBillFromGuestDevice + handleCloseBillFromGuestDevice, } from "../helpers/transactionHelpers"; import { getItemsByCafeId } from "../helpers/cartHelpers.js"; @@ -22,15 +22,22 @@ import { getItemsByCafeId } from "../helpers/cartHelpers.js"; import Dropdown from "./Dropdown.js"; import { useNavigationHelpers } from "../helpers/navigationHelpers"; - -export default function Invoice({ shopId, setModal, table, sendParam, deviceType, socket, shopItems, setShopItems }) { +export default function Invoice({ + shopId, + setModal, + table, + sendParam, + deviceType, + socket, + shopItems, + setShopItems, + isTablet +}) { const { shopIdentifier, tableCode } = useParams(); sendParam({ shopIdentifier, tableCode }); - const { - goToShop - } = useNavigationHelpers(shopIdentifier, table.tableCode); + const { goToShop } = useNavigationHelpers(shopIdentifier, table.tableCode); const [cartItems, setCartItems] = useState([]); const [totalPrice, setTotalPrice] = useState(0); @@ -51,14 +58,14 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType const fetchPaymentMethods = async () => { try { const methods = await getPaymentMethods(shopId); - console.log(methods) - const lastTransaction = JSON.parse(localStorage.getItem('lastTransaction')); - if (lastTransaction?.payment_type == 'paylater') methods.isOpenBillAvailable = false; - setPaymentMethods(methods) - - } catch (err) { - - } + console.log(methods); + const lastTransaction = JSON.parse( + localStorage.getItem("lastTransaction") + ); + if (lastTransaction?.payment_type == "paylater") + methods.isOpenBillAvailable = false; + setPaymentMethods(methods); + } catch (err) {} }; if (shopId) { @@ -70,29 +77,27 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType const fetchCartItems = async () => { try { const cart = getItemsByCafeId(shopId); - const itemMap = new Map(cart.map(item => [item.itemId, item.qty])); + const itemMap = new Map(cart.map((item) => [item.itemId, item.qty])); // Step 2: Filter and transform shopItems const filteredItems = shopItems - .map(itemType => ({ + .map((itemType) => ({ itemTypeId: itemType.itemTypeId, cafeId: itemType.cafeId, typeName: itemType.name, itemList: itemType.itemList - .filter(item => itemMap.has(item.itemId)) // Keep only items in getItemsByCafeId - .map(item => ({ + .filter((item) => itemMap.has(item.itemId)) // Keep only items in getItemsByCafeId + .map((item) => ({ itemId: item.itemId, - price: (item.promoPrice ? item.promoPrice : item.price), + price: item.promoPrice ? item.promoPrice : item.price, name: item.name, image: item.image, qty: itemMap.get(item.itemId), // Add qty from getItemsByCafeId - availability: item.availability - })) + availability: item.availability, + })), })) - .filter(itemType => itemType.itemList.length > 0); // Remove empty itemTypes - console.log(filteredItems) - - + .filter((itemType) => itemType.itemList.length > 0); // Remove empty itemTypes + console.log(filteredItems); // Update local storage by removing unavailable items const updatedLocalStorage = @@ -120,7 +125,10 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType return ( total + itemType.itemList.reduce((subtotal, item) => { - return subtotal + item.qty * (item.promoPrice ? item.promoPrice : item.price); + return ( + subtotal + + item.qty * (item.promoPrice ? item.promoPrice : item.price) + ); }, 0) ); }, 0); @@ -128,8 +136,8 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType setTimeout(function () { setCartItems(filteredItems); setTotalPrice(totalPrice); - setIsLoading(false) - }, 100); //delay is in milliseconds + setIsLoading(false); + }, 100); //delay is in milliseconds } catch (error) { console.error("Error fetching cart items:", error); // Handle error if needed @@ -138,18 +146,17 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType fetchCartItems(); - const getNewestCartItems = async () => { try { // Fetch items from the cart details (latest state) const items = await getCartDetails(shopId); // Loop through each item type in the items from the cart details - items.forEach(itemType => { - itemType.itemList.forEach(item => { + items.forEach((itemType) => { + itemType.itemList.forEach((item) => { // Loop through the shopItems and find the corresponding itemId - shopItems.forEach(shopItemType => { - shopItemType.itemList.forEach(shopItem => { + shopItems.forEach((shopItemType) => { + shopItemType.itemList.forEach((shopItem) => { if (shopItem.itemId === item.itemId) { // Update shopItems with the new data from items (e.g., availability, price) shopItem.availability = item.availability; @@ -179,7 +186,8 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType }, 100); // delay is in milliseconds // Update local storage by removing unavailable items and updating prices - const updatedLocalStorage = JSON.parse(localStorage.getItem("cart")) || []; + const updatedLocalStorage = + JSON.parse(localStorage.getItem("cart")) || []; const newLocalStorage = updatedLocalStorage.map((cafe) => { if (cafe.cafeId === shopId) { return { @@ -194,8 +202,10 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType // Update the price in the local storage item return { ...item, - price: updatedItem.promoPrice ? updatedItem.promoPrice : updatedItem.price, - availability: updatedItem.availability + price: updatedItem.promoPrice + ? updatedItem.promoPrice + : updatedItem.price, + availability: updatedItem.availability, }; } @@ -231,7 +241,10 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType return ( total + itemType.itemList.reduce((subtotal, item) => { - return subtotal + item.qty * (item.promoPrice ? item.promoPrice : item.price); + return ( + subtotal + + item.qty * (item.promoPrice ? item.promoPrice : item.price) + ); }, 0) ); }, 0); @@ -240,13 +253,12 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType console.error("Error fetching cart items:", error); // Handle error if needed } - }; getNewestCartItems(); - }, [shopId]); + }, [shopId, localStorage.getItem('cart')]); - const handlePayCloseBill = async (orderMethod) =>{ + const handlePayCloseBill = async (orderMethod) => { setIsPaymentLoading(true); console.log("tipe" + deviceType); if (transactionData) { @@ -257,7 +269,7 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType socketId ); } - } + }; const handlePay = async (orderMethod) => { setIsPaymentLoading(true); @@ -271,39 +283,36 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType orderMethod, socketId ); - localStorage.removeItem('lastTransaction') + localStorage.removeItem("lastTransaction"); // Dispatch the custom event window.dispatchEvent(new Event("localStorageUpdated")); + } else if (deviceType == "clerk") { + const pay = await handlePaymentFromClerk( + shopId, + email, + orderMethod, + orderType, + tableNumber + ); + } else if (deviceType == "guestSide") { + const pay = await handlePaymentFromGuestSide( + shopId, + email, + orderMethod, + orderType, + tableNumber + ); + } else if (deviceType == "guestDevice") { + const socketId = socket.id; + const pay = await handlePaymentFromGuestDevice( + shopId, + orderMethod, + orderType, + table.tableNo || tableNumber, + textareaRef.current.value, + socketId + ); } - else - - if (deviceType == "clerk") { - const pay = await handlePaymentFromClerk( - shopId, - email, - orderMethod, - orderType, - tableNumber - ); - } else if (deviceType == "guestSide") { - const pay = await handlePaymentFromGuestSide( - shopId, - email, - orderMethod, - orderType, - tableNumber - ); - } else if (deviceType == "guestDevice") { - const socketId = socket.id; - const pay = await handlePaymentFromGuestDevice( - shopId, - orderMethod, - orderType, - table.tableNo || tableNumber, - textareaRef.current.value, - socketId - ); - } console.log("transaction from " + deviceType + "success"); setIsPaymentLoading(false); @@ -331,26 +340,34 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType }, [table]); useEffect(() => { - console.log(localStorage.getItem('cart')) - console.log(cartItems) + console.log(localStorage.getItem("cart")); + console.log(cartItems); - if (localStorage.getItem('cart') == null || localStorage.getItem('cart') == '' || localStorage.getItem('cart') == '[]') return; + if ( + localStorage.getItem("cart") == null || + localStorage.getItem("cart") == "" || + localStorage.getItem("cart") == "[]" + ) + return; // Parse the local storage cart - const localStorageCart = JSON.parse(localStorage.getItem('cart')); - console.log(localStorageCart) + const localStorageCart = JSON.parse(localStorage.getItem("cart")); + console.log(localStorageCart); // Create a set of itemIds from the local storage cart for quick lookup - const localStorageItemIds = new Set(localStorageCart[0].items.map(item => item.itemId)); + const localStorageItemIds = new Set( + localStorageCart[0].items.map((item) => item.itemId) + ); // Filter out items from cartItems that do not exist in the local storage cart - const updatedCartItems = cartItems.map(itemType => ({ + const updatedCartItems = cartItems.map((itemType) => ({ ...itemType, - itemList: itemType.itemList.filter(item => localStorageItemIds.has(item.itemId)) + itemList: itemType.itemList.filter((item) => + localStorageItemIds.has(item.itemId) + ), })); setCartItems(updatedCartItems); - const totalPrice = updatedCartItems.reduce((total, itemType) => { return ( total + @@ -360,8 +377,7 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType ); }, 0); setTotalPrice(totalPrice); - }, [localStorage.getItem('cart')]); - + }, [localStorage.getItem("cart")]); const handleOrderTypeChange = (event) => { setOrderType(event.target.value); @@ -379,44 +395,81 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType setEmail(event.target.value); }; - const transactionData = JSON.parse(localStorage.getItem('lastTransaction')); + const transactionData = JSON.parse(localStorage.getItem("lastTransaction")); return ( -
0 ? '' : '100vh'), minHeight: (getItemsByCafeId(shopId).length > 0 ? '100vh' : '') }}> +
0 ? "" : "100vh", + minHeight: getItemsByCafeId(shopId).length > 0 ? "100vh" : "", + }} + > +
+ {!isTablet && + + + +} + Keranjang +
-
Keranjang
- - {(transactionData == null && getItemsByCafeId(shopId).length < 1) ? -
-
- + {transactionData == null && getItemsByCafeId(shopId).length < 1 ? ( +
+
+
-

Tidak ada item di keranjang

+

+ Tidak ada item di keranjang +

- : - (isLoading ? <> : - <> - {getItemsByCafeId(shopId).length > 0 && -
- {cartItems.map((itemType) => ( - - ))} + ) : isLoading ? ( + <> + ) : ( + <> + {getItemsByCafeId(shopId).length > 0 && ( +
+ {cartItems.map((itemType) => ( + + ))} - {table.tableNo != null && ( -
- Diantar ke {table.tableNo} - {/* Pickup {table == null && } */} -
- )} - - {orderType === "serve" && table.length < 1 && ( -
- Serve to: - -
- )} - -
- Atas Nama : -
+ )} -
+ {orderType === "serve" && table.length < 1 && ( +
+ Serve to:
+ )} -
- Catatan : - -
- -
-