This commit is contained in:
frontend perkafean
2024-08-09 13:00:10 +00:00
parent 76741e304f
commit 6102db3f56
18 changed files with 271 additions and 141 deletions

View File

@@ -23,6 +23,7 @@ import Footer from "./components/Footer";
import GuestSideLogin from "./pages/GuestSideLogin"; import GuestSideLogin from "./pages/GuestSideLogin";
import GuestSide from "./pages/GuestSide"; import GuestSide from "./pages/GuestSide";
import { getItemTypesWithItems } from "./helpers/itemHelper.js"; import { getItemTypesWithItems } from "./helpers/itemHelper.js";
import { getTableByCode } from "./helpers/tableHelper.js";
import { import {
getConnectedGuestSides, getConnectedGuestSides,
@@ -44,7 +45,7 @@ function App() {
const [guestSideOfClerk, setGuestSideOfClerk] = useState(null); const [guestSideOfClerk, setGuestSideOfClerk] = useState(null);
const [guestSides, setGuestSides] = useState([]); const [guestSides, setGuestSides] = useState([]);
const [shopId, setShopId] = useState(""); const [shopId, setShopId] = useState("");
const [tableId, setTableId] = useState(""); const [table, setTable] = useState([]);
const [totalItemsCount, setTotalItemsCount] = useState(0); const [totalItemsCount, setTotalItemsCount] = useState(0);
const [deviceType, setDeviceType] = useState(""); const [deviceType, setDeviceType] = useState("");
const [shop, setShop] = useState([]); const [shop, setShop] = useState([]);
@@ -71,10 +72,13 @@ function App() {
}; };
}, [shopId]); }, [shopId]);
const handleSetParam = ({ shopId, tableId }) => { const handleSetParam = async ({ shopId, tableCode }) => {
console.log(shopId, tableId);
setShopId(shopId); setShopId(shopId);
setTableId(tableId);
if (table.length == 0) {
const gettable = await getTableByCode(tableCode);
if (gettable) setTable(gettable);
}
}; };
useEffect(() => { useEffect(() => {
@@ -121,11 +125,17 @@ function App() {
console.log("transaction notification"); console.log("transaction notification");
setModal("transaction_pending"); setModal("transaction_pending");
}); });
socket.on("transaction_success", async (data) => { socket.on("transaction_success", async (data) => {
console.log("transaction notification"); console.log("transaction notification");
setModal("transaction_success"); setModal("transaction_success");
}); });
socket.on("transaction_failed", async (data) => {
console.log("transaction notification");
setModal("transaction_failed");
});
//for clerk //for clerk
socket.on("transaction_created", async (data) => { socket.on("transaction_created", async (data) => {
console.log("transaction notification"); console.log("transaction notification");
@@ -138,7 +148,10 @@ function App() {
setDeviceType("guestDevice"); setDeviceType("guestDevice");
} else { } else {
setUser(data.data.user); setUser(data.data.user);
if (data.data.user.password == "unsetunsetunset") if (
data.data.user.password == "unsetunsetunset" &&
localStorage.getItem("settings")
)
setModal("complete_account"); setModal("complete_account");
if (data.data.user.cafeId == shopId) { if (data.data.user.cafeId == shopId) {
const connectedGuestSides = await getConnectedGuestSides(); const connectedGuestSides = await getConnectedGuestSides();
@@ -190,7 +203,7 @@ function App() {
}, [shopId]); }, [shopId]);
useEffect(() => { useEffect(() => {
console.log(shopId + tableId); console.log(shopId + table?.tableCode);
}, [navigate]); }, [navigate]);
// Function to open the modal // Function to open the modal
@@ -247,10 +260,11 @@ function App() {
} }
/> />
<Route <Route
path="/:shopId/:tableId?" path="/:shopId/:tableCode?"
element={ element={
<> <>
<CafePage <CafePage
table={table}
sendParam={handleSetParam} sendParam={handleSetParam}
shopName={shop.name} shopName={shop.name}
shopOwnerId={shop.ownerId} shopOwnerId={shop.ownerId}
@@ -264,8 +278,9 @@ function App() {
setModal={setModal} // Pass the function to open modal setModal={setModal} // Pass the function to open modal
/> />
<Footer <Footer
showTable={true}
shopId={shopId} shopId={shopId}
tableId={tableId} table={table}
cartItemsLength={totalItemsCount} cartItemsLength={totalItemsCount}
selectedPage={0} selectedPage={0}
/> />
@@ -273,7 +288,7 @@ function App() {
} }
/> />
<Route <Route
path="/:shopId/:tableId?/search" path="/:shopId/:tableCode?/search"
element={ element={
<> <>
<SearchResult <SearchResult
@@ -288,7 +303,7 @@ function App() {
/> />
<Footer <Footer
shopId={shopId} shopId={shopId}
tableId={tableId} table={table}
cartItemsLength={totalItemsCount} cartItemsLength={totalItemsCount}
selectedPage={1} selectedPage={1}
/> />
@@ -296,17 +311,18 @@ function App() {
} }
/> />
<Route <Route
path="/:shopId/:tableId?/cart" path="/:shopId/:tableCode?/cart"
element={ element={
<> <>
<Cart <Cart
table={table}
sendParam={handleSetParam} sendParam={handleSetParam}
totalItemsCount={totalItemsCount} totalItemsCount={totalItemsCount}
deviceType={deviceType} deviceType={deviceType}
/> />
<Footer <Footer
shopId={shopId} shopId={shopId}
tableId={tableId} table={table}
cartItemsLength={totalItemsCount} cartItemsLength={totalItemsCount}
selectedPage={2} selectedPage={2}
/> />
@@ -314,17 +330,18 @@ function App() {
} }
/> />
<Route <Route
path="/:shopId/:tableId?/invoice" path="/:shopId/:tableCode?/invoice"
element={ element={
<> <>
<Invoice <Invoice
table={table}
sendParam={handleSetParam} sendParam={handleSetParam}
socket={socket} socket={socket}
deviceType={deviceType} deviceType={deviceType}
/> />
<Footer <Footer
shopId={shopId} shopId={shopId}
tableId={tableId} table={table}
cartItemsLength={totalItemsCount} cartItemsLength={totalItemsCount}
selectedPage={2} selectedPage={2}
/> />
@@ -332,7 +349,7 @@ function App() {
} }
/> />
<Route <Route
path="/:shopId/:tableId?/transactions" path="/:shopId/:tableCode?/transactions"
element={ element={
<> <>
<Transactions <Transactions
@@ -341,7 +358,7 @@ function App() {
/> />
<Footer <Footer
shopId={shopId} shopId={shopId}
tableId={tableId} table={table}
cartItemsLength={totalItemsCount} cartItemsLength={totalItemsCount}
selectedPage={3} selectedPage={3}
/> />

View File

@@ -3,8 +3,9 @@ import styles from "./Footer.module.css"; // assuming you have a CSS module for
import { useNavigationHelpers } from "../helpers/navigationHelpers"; import { useNavigationHelpers } from "../helpers/navigationHelpers";
export default function Footer({ export default function Footer({
showTable,
shopId, shopId,
tableId, table,
cartItemsLength, cartItemsLength,
selectedPage, selectedPage,
}) { }) {
@@ -15,13 +16,13 @@ export default function Footer({
goToTransactions, goToTransactions,
goToScan, goToScan,
goToNonTable, goToNonTable,
} = useNavigationHelpers(shopId, tableId); } = useNavigationHelpers(shopId, table.tableCode);
const [isStretched, setIsStretched] = useState(false); const [isStretched, setIsStretched] = useState(false);
const scanMejaRef = useRef(null); const scanMejaRef = useRef(null);
const handleScanMejaClick = () => { const handleScanMejaClick = () => {
if (tableId) { if (table) {
setIsStretched(true); setIsStretched(true);
} else { } else {
goToTransactions(); goToTransactions();
@@ -98,25 +99,27 @@ export default function Footer({
</div> </div>
{/* Rounded Rectangle with "Scan Meja" and QR Icon */} {/* Rounded Rectangle with "Scan Meja" and QR Icon */}
{shopId && ( {showTable && shopId && (
<div <div
ref={scanMejaRef} ref={scanMejaRef}
onClick={!tableId ? goToScan : handleScanMejaClick} onClick={table.length == 0 ? goToScan : handleScanMejaClick}
className={`${styles.scanMeja} ${ className={`${styles.scanMeja} ${
isStretched ? styles.stretched : "" isStretched ? styles.stretched : ""
}`} }`}
> >
<span> <span>
{tableId ? `Diantar ke meja ${tableId}` : `Scan Meja\u00A0`} {table.length != 0
? `Diantar ke meja ${table.tableNo}`
: `Scan Meja\u00A0`}
</span> </span>
{!tableId && ( {table.length == 0 && (
<img <img
src="https://static-00.iconduck.com/assets.00/qr-scan-icon-2048x2048-aeh36n7y.png" src="https://static-00.iconduck.com/assets.00/qr-scan-icon-2048x2048-aeh36n7y.png"
alt="QR Code" alt="QR Code"
className={styles.qrIcon} className={styles.qrIcon}
/> />
)} )}
{tableId && isStretched && ( {table.length != 0 && isStretched && (
<button onClick={handleHapusMeja} className={styles.hapusMejaBtn}> <button onClick={handleHapusMeja} className={styles.hapusMejaBtn}>
Hapus Meja Hapus Meja
</button> </button>

View File

@@ -215,7 +215,7 @@ const Header = ({
shopName, shopName,
shopOwnerId, shopOwnerId,
shopClerks, shopClerks,
tableId, tableCode,
showProfile, showProfile,
user, user,
setModal, setModal,
@@ -225,7 +225,7 @@ const Header = ({
removeConnectedGuestSides, removeConnectedGuestSides,
}) => { }) => {
const { goToLogin, goToGuestSideLogin, goToAdminCafes } = const { goToLogin, goToGuestSideLogin, goToAdminCafes } =
useNavigationHelpers(shopId, tableId); useNavigationHelpers(shopId, tableCode);
const [showRectangle, setShowRectangle] = useState(false); const [showRectangle, setShowRectangle] = useState(false);
const [animate, setAnimate] = useState(""); const [animate, setAnimate] = useState("");
const rectangleRef = useRef(null); const rectangleRef = useRef(null);

View File

@@ -5,6 +5,7 @@ import TableMaps from "../components/TableMaps";
import Transactions from "../pages/Transactions"; import Transactions from "../pages/Transactions";
import Transaction_pending from "../pages/Transaction_pending"; import Transaction_pending from "../pages/Transaction_pending";
import Transaction_success from "../pages/Transaction_success"; import Transaction_success from "../pages/Transaction_success";
import Transaction_failed from "../pages/Transaction_failed";
import MaterialList from "../pages/MaterialList.js"; import MaterialList from "../pages/MaterialList.js";
import MaterialMutationsPage from "../pages/MaterialMutationsPage.js"; import MaterialMutationsPage from "../pages/MaterialMutationsPage.js";
@@ -35,6 +36,7 @@ const Modal = ({ shopId, isOpen, onClose, modalContent }) => {
)}{" "} )}{" "}
{modalContent === "transaction_pending" && <Transaction_pending />} {modalContent === "transaction_pending" && <Transaction_pending />}
{modalContent === "transaction_success" && <Transaction_success />} {modalContent === "transaction_success" && <Transaction_success />}
{modalContent === "transaction_failed" && <Transaction_failed />}
{modalContent === "add_material" && <MaterialList cafeId={shopId} />} {modalContent === "add_material" && <MaterialList cafeId={shopId} />}
{modalContent === "update_stock" && ( {modalContent === "update_stock" && (
<MaterialMutationsPage cafeId={shopId} /> <MaterialMutationsPage cafeId={shopId} />

View File

@@ -8,9 +8,7 @@ const QRCodeWithBackground = ({
backgroundUrl, backgroundUrl,
initialQrPosition, initialQrPosition,
initialQrSize, initialQrSize,
setInitialPos, handleQrSave,
setInitialSize,
onBackgroundUrlChange,
}) => { }) => {
const [qrPosition, setQrPosition] = useState(initialQrPosition); const [qrPosition, setQrPosition] = useState(initialQrPosition);
const [qrSize, setQrSize] = useState(initialQrSize); const [qrSize, setQrSize] = useState(initialQrSize);
@@ -22,12 +20,12 @@ const QRCodeWithBackground = ({
const { name, value } = e.target; const { name, value } = e.target;
setQrPosition((prevPosition) => ({ setQrPosition((prevPosition) => ({
...prevPosition, ...prevPosition,
[name]: value, [name]: parseFloat(value).toFixed(2),
})); }));
}; };
const handleSizeChange = (e) => { const handleSizeChange = (e) => {
setQrSize(e.target.value); setQrSize(parseFloat(e.target.value).toFixed(2));
}; };
const handleFileChange = (e) => { const handleFileChange = (e) => {
@@ -35,14 +33,11 @@ const QRCodeWithBackground = ({
if (file) { if (file) {
const newBgImage = URL.createObjectURL(file); const newBgImage = URL.createObjectURL(file);
setBgImage(newBgImage); setBgImage(newBgImage);
onBackgroundUrlChange(newBgImage);
} }
}; };
const handleSave = () => { const handleSave = () => {
setInitialPos(qrPosition); handleQrSave(qrPosition, qrSize, bgImage);
setInitialSize(qrSize);
onBackgroundUrlChange(bgImage);
}; };
const printQRCode = () => { const printQRCode = () => {
@@ -142,13 +137,15 @@ const QRCodeWithBackground = ({
}} }}
/> />
{/* Overlay text that triggers file input */} {/* Overlay text that triggers file input */}
<div {isConfigure && (
ref={overlayTextRef} <div
style={styles.overlayText} ref={overlayTextRef}
onClick={() => fileInputRef.current.click()} style={styles.overlayText}
> onClick={() => fileInputRef.current.click()}
Click To Change Image >
</div> Click To Change Image
</div>
)}
{/* Hidden file input */} {/* Hidden file input */}
<input <input
type="file" type="file"

View File

@@ -44,7 +44,7 @@ const SearchIcon = styled.svg`
export default function SearchInput({ export default function SearchInput({
shopId, shopId,
tableId, tableCode,
autofocus, autofocus,
onSearchChange, onSearchChange,
}) { }) {
@@ -73,15 +73,15 @@ export default function SearchInput({
//Start the timer //Start the timer
let url = ""; let url = "";
if (autofocus || songName != "") { if (autofocus || songName != "") {
url = tableId url = tableCode
? `/${shopId}/${tableId}/search?query=${encodeURIComponent(songName)}` ? `/${shopId}/${tableCode}/search?query=${encodeURIComponent(songName)}`
: `/${shopId}/search?query=${encodeURIComponent(songName)}`; : `/${shopId}/search?query=${encodeURIComponent(songName)}`;
navigate(url); navigate(url);
} }
if (autofocus) { if (autofocus) {
if (songName == "") { if (songName == "") {
if (tableId) navigate(`/${shopId}/${tableId}`); if (tableCode) navigate(`/${shopId}/${tableCode}`);
else navigate(`/${shopId}`); else navigate(`/${shopId}`);
} }
} }

View File

@@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useState, useEffect } from "react";
import QRCodeWithBackground from "./QR"; // Adjust path as needed import QRCodeWithBackground from "./QR"; // Adjust path as needed
const TableList = ({ shopUrl, tables, onSelectTable, selectedTable }) => { const TableList = ({ shopUrl, tables, onSelectTable, selectedTable }) => {
@@ -17,12 +17,17 @@ const TableList = ({ shopUrl, tables, onSelectTable, selectedTable }) => {
setBgImageUrl(newUrl); setBgImageUrl(newUrl);
}; };
const handleQrSave = (qrPosition, qrSize, bgImage) => {
setInitialPos(qrPosition);
setInitialSize(qrSize);
setBgImageUrl(bgImage);
};
return ( return (
<div <div
style={{ style={{
width: "100%", width: "100%",
marginTop: "20px", marginTop: "20px",
maxHeight: "400px",
overflowY: "auto", overflowY: "auto",
}} }}
> >
@@ -47,53 +52,51 @@ const TableList = ({ shopUrl, tables, onSelectTable, selectedTable }) => {
{-1 == selectedTable?.tableId && ( {-1 == selectedTable?.tableId && (
<QRCodeWithBackground <QRCodeWithBackground
isConfigure={true} isConfigure={true}
handleQrSave={handleQrSave}
setInitialPos={setInitialPos} setInitialPos={setInitialPos}
setInitialSize={setInitialSize} setInitialSize={setInitialSize}
qrCodeUrl={generateQRCodeUrl("sample")} qrCodeUrl={generateQRCodeUrl("sample")}
backgroundUrl={bgImageUrl} backgroundUrl={bgImageUrl}
initialQrPosition={initialPos} initialQrPosition={initialPos}
initialQrSize={initialSize} initialQrSize={initialSize}
onBackgroundUrlChange={handleBackgroundUrlChange}
/> />
)} )}
</li> </li>
{tables.map((table) => ( {tables
<li .filter((table) => table.tableNo !== 0)
key={table.tableId} .map((table) => (
style={{ <li
backgroundColor: key={table.tableId}
table.tableId === selectedTable?.tableId style={{
? "lightblue" backgroundColor:
: "white", table.tableId === selectedTable?.tableId
marginBottom: "10px", ? "lightblue"
padding: "10px", : "white",
borderRadius: "4px", marginBottom: "10px",
boxShadow: "0 2px 4px rgba(0,0,0,0.1)", padding: "10px",
cursor: "pointer", borderRadius: "4px",
}} boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
onClick={() => onSelectTable(table)} cursor: "pointer",
> }}
<div style={{ marginBottom: "10px" }}> onClick={() => onSelectTable(table)}
{table.tableNo === 0 ? "Clerk" : `Table ${table.tableNo}`} - >
Position: ({table.xposition}, {table.yposition}) <div style={{ marginBottom: "10px" }}>
</div> Table {table.tableNo}
{table.tableNo != 0 && table.tableId == selectedTable?.tableId && ( </div>
<> {table.tableId === selectedTable?.tableId && (
<QRCodeWithBackground <>
tableNo={table.tableNo} <QRCodeWithBackground
setInitialPos={setInitialPos} tableNo={table.tableNo}
setInitialSize={setInitialSize} qrCodeUrl={generateQRCodeUrl(table.tableCode)}
qrCodeUrl={generateQRCodeUrl(table.tableCode)} backgroundUrl={bgImageUrl}
backgroundUrl={bgImageUrl} initialQrPosition={initialPos}
initialQrPosition={initialPos} initialQrSize={initialSize}
initialQrSize={initialSize} />
onBackgroundUrlChange={handleBackgroundUrlChange} <h5>{shopUrl + "/" + table.tableCode}</h5>
/> </>
<h2>{shopUrl + "/" + table.tableCode}</h2> )}
</> </li>
)} ))}
</li>
))}
</ul> </ul>
</div> </div>
); );

View File

@@ -184,9 +184,10 @@ const TablesPage = ({ shopId }) => {
justifyContent: "center", justifyContent: "center",
fontSize: "calc(10px + 2vmin)", fontSize: "calc(10px + 2vmin)",
color: "rgba(88, 55, 50, 1)", color: "rgba(88, 55, 50, 1)",
height: "100%",
}} }}
> >
<TableCanvas {/* <TableCanvas
isAdmin={true} isAdmin={true}
tables={tables} tables={tables}
selectedTable={selectedTable} selectedTable={selectedTable}
@@ -199,7 +200,7 @@ const TablesPage = ({ shopId }) => {
handleCancel={handleCancel} handleCancel={handleCancel}
handleSetTableNo={handleSetTableNo} handleSetTableNo={handleSetTableNo}
tableNo={tableNo} tableNo={tableNo}
/> /> */}
<TableList <TableList
shopUrl={window.location.hostname + "/" + shopId} shopUrl={window.location.hostname + "/" + shopId}
tables={tables} tables={tables}

View File

@@ -5,7 +5,7 @@ import { useNavigate } from "react-router-dom";
* @param {string} shopId - The shop ID for constructing URLs. * @param {string} shopId - The shop ID for constructing URLs.
* @returns {Object} - Navigation functions. * @returns {Object} - Navigation functions.
*/ */
export const useNavigationHelpers = (shopId, tableId) => { export const useNavigationHelpers = (shopId, tableCode) => {
const navigate = useNavigate(); const navigate = useNavigate();
const goToLogin = () => { const goToLogin = () => {
@@ -15,7 +15,7 @@ export const useNavigationHelpers = (shopId, tableId) => {
// Append query parameters conditionally // Append query parameters conditionally
const queryParams = new URLSearchParams(); const queryParams = new URLSearchParams();
if (shopId) queryParams.append("next", shopId); if (shopId) queryParams.append("next", shopId);
if (tableId) queryParams.append("table", tableId); if (tableCode) queryParams.append("table", tableCode);
// Set the URL with query parameters // Set the URL with query parameters
if (queryParams.toString()) { if (queryParams.toString()) {
@@ -53,9 +53,9 @@ export const useNavigationHelpers = (shopId, tableId) => {
// Construct the base URL for the shop // Construct the base URL for the shop
let url = `/${shopId}`; let url = `/${shopId}`;
// Append the tableId if it's provided // Append the tableCode if it's provided
if (tableId) { if (tableCode) {
url += `/${tableId}`; url += `/${tableCode}`;
} }
// Perform the navigation // Perform the navigation
@@ -64,8 +64,8 @@ export const useNavigationHelpers = (shopId, tableId) => {
const goToSearch = () => { const goToSearch = () => {
let url = `/${shopId}`; let url = `/${shopId}`;
if (tableId) { if (tableCode) {
url += `/${tableId}`; url += `/${tableCode}`;
} }
url += "/search"; url += "/search";
navigate(url); navigate(url);
@@ -73,8 +73,8 @@ export const useNavigationHelpers = (shopId, tableId) => {
const goToCart = () => { const goToCart = () => {
let url = `/${shopId}`; let url = `/${shopId}`;
if (tableId) { if (tableCode) {
url += `/${tableId}`; url += `/${tableCode}`;
} }
url += "/cart"; url += "/cart";
navigate(url); navigate(url);
@@ -82,8 +82,8 @@ export const useNavigationHelpers = (shopId, tableId) => {
const goToInvoice = (orderType, tableNumber, email) => { const goToInvoice = (orderType, tableNumber, email) => {
let url = `/${shopId}`; let url = `/${shopId}`;
if (tableId) { if (tableCode) {
url += `/${tableId}`; url += `/${tableCode}`;
} }
url += `/invoice?orderType=${orderType}`; url += `/invoice?orderType=${orderType}`;
if (tableNumber) { if (tableNumber) {
@@ -97,8 +97,8 @@ export const useNavigationHelpers = (shopId, tableId) => {
const goToTransactions = () => { const goToTransactions = () => {
let url = `/${shopId}`; let url = `/${shopId}`;
if (tableId) { if (tableCode) {
url += `/${tableId}`; url += `/${tableCode}`;
} }
url += "/transactions"; url += "/transactions";
navigate(url); navigate(url);
@@ -106,8 +106,8 @@ export const useNavigationHelpers = (shopId, tableId) => {
const goToGuestSideLogin = () => { const goToGuestSideLogin = () => {
let url = `/${shopId}`; let url = `/${shopId}`;
if (tableId) { if (tableCode) {
url += `/${tableId}`; url += `/${tableCode}`;
} }
url += "/guest-side-login"; url += "/guest-side-login";
navigate(url); navigate(url);

View File

@@ -25,6 +25,31 @@ export async function confirmTransaction(transactionId) {
console.error("Error:", error); console.error("Error:", error);
} }
} }
export async function declineTransaction(transactionId) {
try {
const token = getLocalStorage("auth");
const response = await fetch(
`${API_BASE_URL}/transaction/decline-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 getTransactions(shopId, demand) { export async function getTransactions(shopId, demand) {
try { try {
const token = getLocalStorage("auth"); const token = getLocalStorage("auth");

View File

@@ -20,6 +20,7 @@ import {
} from "../helpers/localStorageHelpers"; } from "../helpers/localStorageHelpers";
function CafePage({ function CafePage({
table,
sendParam, sendParam,
shopName, shopName,
shopOwnerId, shopOwnerId,
@@ -34,8 +35,8 @@ function CafePage({
}) { }) {
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const token = searchParams.get("token"); const token = searchParams.get("token");
const { shopId, tableId } = useParams(); const { shopId, tableCode } = useParams();
sendParam({ shopId, tableId }); sendParam({ shopId, tableCode });
const navigate = useNavigate(); const navigate = useNavigate();
@@ -103,14 +104,14 @@ function CafePage({
shopName={shopName} shopName={shopName}
shopOwnerId={shopOwnerId} shopOwnerId={shopOwnerId}
shopClerks={shopClerks} shopClerks={shopClerks}
tableId={tableId} tableCode={table.tableCode}
user={user} user={user}
guestSides={guestSides} guestSides={guestSides}
guestSideOfClerk={guestSideOfClerk} guestSideOfClerk={guestSideOfClerk}
removeConnectedGuestSides={removeConnectedGuestSides} removeConnectedGuestSides={removeConnectedGuestSides}
/> />
<div style={{ marginTop: "5px" }}></div> <div style={{ marginTop: "5px" }}></div>
<SearchInput shopId={shopId} tableId={tableId} /> <SearchInput shopId={shopId} tableCode={table.tableCode} />
<div style={{ marginTop: "15px" }}></div> <div style={{ marginTop: "15px" }}></div>
<ItemTypeLister <ItemTypeLister
user={user} user={user}

View File

@@ -9,11 +9,16 @@ import { getCartDetails } from "../helpers/itemHelper.js";
import { getItemsByCafeId } from "../helpers/cartHelpers"; // Import getItemsByCafeId import { getItemsByCafeId } from "../helpers/cartHelpers"; // Import getItemsByCafeId
import Modal from "../components/Modal"; // Import the reusable Modal component import Modal from "../components/Modal"; // Import the reusable Modal component
export default function Cart({ sendParam, totalItemsCount, deviceType }) { export default function Cart({
const { shopId, tableId } = useParams(); table,
sendParam({ shopId, tableId }); sendParam,
totalItemsCount,
deviceType,
}) {
const { shopId, tableCode } = useParams();
sendParam({ shopId, tableCode });
const { goToShop, goToInvoice } = useNavigationHelpers(shopId, tableId); const { goToShop, goToInvoice } = useNavigationHelpers(shopId, tableCode);
const [cartItems, setCartItems] = useState([]); const [cartItems, setCartItems] = useState([]);
const [totalPrice, setTotalPrice] = useState(0); const [totalPrice, setTotalPrice] = useState(0);
const [orderType, setOrderType] = useState("serve"); const [orderType, setOrderType] = useState("serve");
@@ -84,12 +89,12 @@ export default function Cart({ sendParam, totalItemsCount, deviceType }) {
const items = await getItemsByCafeId(shopId); const items = await getItemsByCafeId(shopId);
const updatedTotalPrice = items.reduce((total, localItem) => { const updatedTotalPrice = items.reduce((total, localItem) => {
const cartItem = cartItems.find((itemType) => const cartItem = cartItems.find((itemType) =>
itemType.itemList.some((item) => item.itemId === localItem.itemId), itemType.itemList.some((item) => item.itemId === localItem.itemId)
); );
if (cartItem) { if (cartItem) {
const itemDetails = cartItem.itemList.find( const itemDetails = cartItem.itemList.find(
(item) => item.itemId === localItem.itemId, (item) => item.itemId === localItem.itemId
); );
return total + localItem.qty * itemDetails.price; return total + localItem.qty * itemDetails.price;
} }
@@ -135,22 +140,28 @@ export default function Cart({ sendParam, totalItemsCount, deviceType }) {
} }
if (orderType === "serve") { if (orderType === "serve") {
if (tableNumber !== "" || tableId != null) { console.log("serve");
const table = await getTable(shopId, tableNumber || tableId); if (tableNumber !== "" && table.tableNo == undefined) {
console.log("getting with tableNumber");
const table = await getTable(shopId, tableNumber);
if (!table) { if (!table) {
setModalContent( setModalContent(
<div>Table not found. Please enter a valid table number.</div>, <div>Table not found. Please enter a valid table number.</div>
); );
setIsModalOpen(true); setIsModalOpen(true);
} else { } else {
goToInvoice(orderType, tableNumber || tableId, email); goToInvoice(orderType, table.tableNo, email);
} }
} else if (table.tableNo != undefined) {
console.log("getting with table code" + table.tableNo);
goToInvoice(orderType, null, email);
} else { } else {
setModalContent(<div>Please enter a table number.</div>); setModalContent(<div>Please enter a table number.</div>);
setIsModalOpen(true); setIsModalOpen(true);
} }
} else { } else {
goToInvoice(orderType, tableNumber || tableId, email); console.log("getting with pickup");
goToInvoice(orderType, tableNumber, email);
} }
setIsCheckoutLoading(false); // Stop loading animation setIsCheckoutLoading(false); // Stop loading animation
@@ -202,15 +213,15 @@ export default function Cart({ sendParam, totalItemsCount, deviceType }) {
value={orderType} value={orderType}
onChange={handleOrderTypeChange} onChange={handleOrderTypeChange}
> >
{tableId != null && ( {table != null && (
<option value="serve">Serve to table {tableId}</option> <option value="serve">Serve to table {table.tableNo}</option>
)} )}
<option value="pickup">Pickup</option> <option value="pickup">Pickup</option>
{tableId == null && <option value="serve">Serve</option>} {table == null && <option value="serve">Serve</option>}
{/* tableId harus di check terlebih dahulu untuk mendapatkan tableNo */} {/* tableId harus di check terlebih dahulu untuk mendapatkan tableNo */}
</select> </select>
{orderType === "serve" && tableId == null && ( {orderType === "serve" && table.length < 1 && (
<input <input
type="text" type="text"
placeholder="Table Number" placeholder="Table Number"

View File

@@ -11,9 +11,9 @@ import {
handlePaymentFromGuestDevice, handlePaymentFromGuestDevice,
} from "../helpers/transactionHelpers"; } from "../helpers/transactionHelpers";
export default function Invoice({ sendParam, deviceType, socket }) { export default function Invoice({ table, sendParam, deviceType, socket }) {
const { shopId, tableId } = useParams(); const { shopId, tableCode } = useParams();
sendParam({ shopId, tableId }); sendParam({ shopId, tableCode });
const location = useLocation(); // Use useLocation hook instead of useSearchParams const location = useLocation(); // Use useLocation hook instead of useSearchParams
const searchParams = new URLSearchParams(location.search); // Pass location.search directly const searchParams = new URLSearchParams(location.search); // Pass location.search directly
@@ -76,7 +76,7 @@ export default function Invoice({ sendParam, deviceType, socket }) {
shopId, shopId,
isCash ? "cash" : "cashless", isCash ? "cash" : "cashless",
orderType, orderType,
tableNumber, table.tableNo || tableNumber,
socketId socketId
); );
} }
@@ -103,7 +103,7 @@ export default function Invoice({ sendParam, deviceType, socket }) {
<h2 className={styles["Invoice-detail"]}> <h2 className={styles["Invoice-detail"]}>
{orderType === "pickup" {orderType === "pickup"
? "Diambil di kasir" ? "Diambil di kasir"
: `Diantar ke meja nomor ${tableNumber}`} : `Diantar ke meja nomor ${table.tableNo || tableNumber || "-"}`}
</h2> </h2>
<div className={styles.TotalContainer}> <div className={styles.TotalContainer}>
<span>Total:</span> <span>Total:</span>

View File

@@ -1,3 +1,4 @@
// src/CafePage.js // src/CafePage.js
import React, { useState } from "react"; import React, { useState } from "react";
import { useParams, useSearchParams, useNavigate } from "react-router-dom"; import { useParams, useSearchParams, useNavigate } from "react-router-dom";
@@ -11,9 +12,9 @@ import { updateLocalStorage } from "../helpers/localStorageHelpers";
function SearchResult({ user, shopItems, sendParam }) { function SearchResult({ user, shopItems, sendParam }) {
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const { shopId, tableId } = useParams(); const { shopId, tableCode } = useParams();
const navigate = useNavigate(); const navigate = useNavigate();
sendParam({ shopId, tableId }); sendParam({ shopId, tableCode });
const [searchValue, setSearchValue] = useState( const [searchValue, setSearchValue] = useState(
"dwadawa vvwqd21qb13 4kfawfdwa dhawldhawr dliawbdjawndlks" "dwadawa vvwqd21qb13 4kfawfdwa dhawldhawr dliawbdjawndlks"
@@ -47,7 +48,7 @@ function SearchResult({ user, shopItems, sendParam }) {
<div style={{ marginTop: "5px" }}></div> <div style={{ marginTop: "5px" }}></div>
<SearchInput <SearchInput
shopId={shopId} shopId={shopId}
tableId={tableId} tableCode={tableCode}
autofocus={true} autofocus={true}
onSearchChange={handleSearchChange} onSearchChange={handleSearchChange}
/> />
@@ -68,4 +69,4 @@ function SearchResult({ user, shopItems, sendParam }) {
); );
} }
export default SearchResult; export default SearchResult;

View File

@@ -0,0 +1,29 @@
import React from "react";
import { ColorRing } from "react-loader-spinner";
import styles from "./Transactions.module.css";
export default function Transaction_pending() {
const containerStyle = {
display: "flex",
justifyContent: "center",
alignItems: "center",
width: "100%",
height: "100%", // This makes the container stretch to the bottom of the viewport
backgroundColor: "#000", // Optional: Set a background color if you want to see the color ring clearly
};
return (
<div className={styles.Transactions}>
<div className={containerStyle}>
<div style={{ marginTop: "30px", textAlign: "center" }}>
<h2>transaction failed</h2>
<img
className={styles.expression}
src="https://i.imgur.com/5j3yIw6.png"
alt="Failed"
/>
</div>
</div>
</div>
);
}

View File

@@ -17,7 +17,11 @@ export default function Transaction_pending() {
<div className={containerStyle}> <div className={containerStyle}>
<div style={{ marginTop: "30px", textAlign: "center" }}> <div style={{ marginTop: "30px", textAlign: "center" }}>
<h2>transaction success</h2> <h2>transaction success</h2>
<img src="https://ibb.co.com/X7CD2f6" alt="Success" /> <img
className={styles.expression}
src="https://i.imgur.com/sgvMI02.pngs"
alt="Success"
/>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -5,6 +5,7 @@ import { ColorRing } from "react-loader-spinner";
import { import {
getTransactions, getTransactions,
confirmTransaction, confirmTransaction,
declineTransaction,
} 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";
@@ -13,8 +14,6 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
const { shopId, tableId } = useParams(); const { shopId, tableId } = useParams();
if (sendParam) sendParam({ shopId, tableId }); if (sendParam) sendParam({ shopId, tableId });
const [confirmed, setConfirmed] = useState(false);
const [message, setMessage] = useState("");
const [tables, setTables] = useState([]); const [tables, setTables] = useState([]);
const [selectedTable, setSelectedTable] = useState(null); const [selectedTable, setSelectedTable] = useState(null);
const [transactions, setTransactions] = useState([]); const [transactions, setTransactions] = useState([]);
@@ -56,9 +55,37 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
setIsPaymentLoading(true); setIsPaymentLoading(true);
try { try {
const c = await confirmTransaction(transactionId); const c = await confirmTransaction(transactionId);
if (c) setMessage("success"); if (c) {
else setMessage("not confirmed"); // Update the confirmed status locally
setConfirmed(true); setTransactions((prevTransactions) =>
prevTransactions.map((transaction) =>
transaction.transactionId === transactionId
? { ...transaction, confirmed: 1 } // Set to confirmed
: transaction
)
);
}
} catch (error) {
console.error("Error processing payment:", error);
} finally {
setIsPaymentLoading(false);
}
};
const handleDecline = async (transactionId) => {
setIsPaymentLoading(true);
try {
const c = await declineTransaction(transactionId);
if (c) {
// Update the confirmed status locally
setTransactions((prevTransactions) =>
prevTransactions.map((transaction) =>
transaction.transactionId === transactionId
? { ...transaction, confirmed: -1 } // Set to confirmed
: transaction
)
);
}
} catch (error) { } catch (error) {
console.error("Error processing payment:", error); console.error("Error processing payment:", error);
} finally { } finally {
@@ -113,17 +140,22 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
<button <button
className={styles.PayButton} className={styles.PayButton}
onClick={() => handleConfirm(transaction.transactionId)} onClick={() => handleConfirm(transaction.transactionId)}
disabled={transaction.confirmed || isPaymentLoading} // Disable button if confirmed or loading disabled={transaction.confirmed !== 0 || 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" />
) : transaction.confirmed ? ( ) : transaction.confirmed === 1 ? (
"Confirmed" // Display "Confirmed" if the transaction is confirmed "Confirmed" // Display "Confirmed" if the transaction is confirmed (1)
) : transaction.confirmed === -1 ? (
"Declined" // Display "Declined" if the transaction is declined (-1)
) : ( ) : (
"Confirm" // Display "Confirm" otherwise "Confirm" // Display "Confirm" if the transaction is not confirmed (0)
)} )}
</button> </button>
</div> </div>
<h5 onClick={() => handleDecline(transaction.transactionId)}>
decline
</h5>
</div> </div>
))} ))}
</div> </div>

View File

@@ -73,3 +73,7 @@
margin: 26px; margin: 26px;
background-color: #f9f9f9; background-color: #f9f9f9;
} }
.expression {
width: 100%;
}