This commit is contained in:
client perkafean
2024-08-12 09:28:22 +00:00
parent 6102db3f56
commit 9c3a14366c
20 changed files with 725 additions and 196 deletions

View File

@@ -156,19 +156,18 @@ const shrink = keyframes`
border-radius: 50%;
}
`;
const Rectangle = styled.div`
position: absolute;
top: 45px;
right: 15px;
width: 200px;
height: auto;
max-height: 87vh; /* or another appropriate value */
background-color: white;
z-index: 10;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
animation: ${(props) => (props.animate === "grow" ? grow : shrink)} 0.5s
forwards;
overflow: hidden;
overflow-y: auto; /* Enable vertical scrolling */
padding: 10px;
box-sizing: border-box;
`;
@@ -246,6 +245,7 @@ const Header = ({
if (rectangleRef.current && !rectangleRef.current.contains(event.target)) {
setAnimate("shrink");
setTimeout(() => setShowRectangle(false), 500);
rectangleRef.current.style.overflow = "hidden";
}
};
@@ -304,7 +304,9 @@ const Header = ({
<Child onClick={goToLogin}>Click to login</Child>
)}
{user.username !== undefined && (
<Child onClick={() => setModal("edit_account")}>Edit</Child>
<Child onClick={() => setModal("edit_account")}>
Edit profile
</Child>
)}
{shopId &&
user.userId == shopOwnerId &&
@@ -312,59 +314,77 @@ const Header = ({
user.roleId === 1 && (
<>
<Child onClick={goToAdminCafes}>see your other cafes</Child>
<Child onClick={() => setModal("edit_tables")}>
{shopName} table maps
</Child>
<Child hasChildren>
{shopName} clerks
<Child onClick={() => setModal("craete_account_clerk")}>
+ Add clerk
</Child>
{shopClerks &&
shopClerks.map((key, index) => (
<Child key={index}>
{shopClerks[index].username}
<button
onClick={() =>
removeConnectedGuestSides(guestSides[index][3])
}
>
remove
</button>
</Child>
))}
</Child>
<Child onClick={() => setModal("add_material")}>
add material
</Child>
<Child onClick={() => setModal("update_stock")}>
update stock
</Child>
<Child hasChildren>
{shopName}
<Child onClick={() => setModal("edit_tables")}>
table maps
</Child>
<Child hasChildren>
clerks
<Child onClick={() => setModal("craete_account_clerk")}>
+ Add clerk
</Child>
{shopClerks &&
shopClerks.map((key, index) => (
<Child key={index}>
{shopClerks[index].username}
<button
onClick={() =>
removeConnectedGuestSides(
guestSides[index][3]
)
}
>
remove
</button>
</Child>
))}
</Child>
<Child onClick={() => setModal("payment_option")}>
payment options
</Child>
</Child>
</>
)}
{user.username !== undefined &&
((user.userId == shopOwnerId && user.roleId === 1) ||
(user.cafeId == shopId && user.roleId === 2)) && (
<Child onClick={() => setModal("update_stock")}>
update stock
</Child>
)}
{user.username !== undefined &&
user.roleId == 2 &&
user.cafeId == shopId && (
user.cafeId == shopId &&
user.roleId === 2 && (
<Child hasChildren>
connected guest sides
<Child onClick={goToGuestSideLogin}>+ Add guest side</Child>
{guestSides &&
guestSides.map((key, index) => (
<Child key={index}>
guest side {index + 1}
<button
onClick={() =>
removeConnectedGuestSides(guestSides[index][3])
}
>
remove
</button>
{shopName}
<Child onClick={() => setModal("update_stock")}>
update stock
</Child>
{user.username !== undefined &&
user.roleId == 2 &&
user.cafeId == shopId && (
<Child hasChildren>
connected guest sides
<Child onClick={goToGuestSideLogin}>
+ Add guest side
</Child>
{guestSides &&
guestSides.map((key, index) => (
<Child key={index}>
guest side {index + 1}
<button
onClick={() =>
removeConnectedGuestSides(
guestSides[index][3]
)
}
>
remove
</button>
</Child>
))}
</Child>
))}
)}
</Child>
)}
{user.username !== undefined && (

View File

@@ -58,12 +58,22 @@ export default function ItemType({
className={styles["item-type-image"]}
/>
{blank && (
<input
type="file"
accept="image/*"
className={styles["item-type-image-input"]}
onChange={handleImageChange}
/>
<div className={styles["item-type-image-container"]}>
<input
type="file"
accept="image/*"
className={styles["item-type-image-input"]}
onChange={handleImageChange}
id="image-input"
/>
Click to add image
<label
htmlFor="image-input"
className={styles["item-type-image-text"]}
>
Click to add image
</label>
</div>
)}
</div>
<input

View File

@@ -41,16 +41,24 @@
border-radius: 15px;
}
.item-type-image-input {
.item-type-image-container {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.item-type-image-input {
opacity: 0;
position: absolute;
top: 0;
width: 100%;
height: 100%;
}
.item-type-create {
position: absolute;
top: 80%; /* Position below the input */
top: 76%; /* Position below the input */
left: 50%;
transform: translateX(-50%);
margin-top: 10px; /* Space between input and button */

View File

@@ -19,12 +19,7 @@ const ItemTypeLister = ({ shopId, shopOwnerId, user, itemTypes }) => {
<div className="item-type-lister">
<div className="item-type-list">
{itemTypes && itemTypes.length > 1 && (
<ItemType
name={"All"}
imageUrl={
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAY1BMVEX///8BAQEEBAT09PT8/PzFxcWGhobu7u7R0dHLy8uoqKhTU1N7e3tXV1fIyMguLi7d3d08PDyenp41NTWBgYF1dXVHR0dMTEwTExPj4+O6urrp6emWlpasrKy2trZeXl4aGhrSJRZxAAADF0lEQVR4nO3Zi3aiMBCAYQIR71VbtXft+z/lJoFigAkNbYHdPf/X3VPqGeMkwdxIEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT0dGBVaSOe5vuV/4giqR1mXOPXL6M1X4r9Cn5l+kqCx3R2Nq7igjWPYoeWjbPkpg09LdiJ/dyPK3P22O+iIid5ZvtebvJZxGxi/y4Pa9Px5efJvh99i56fVM3q+4RJFv5seHeseVqP/btdYDsY5hE7nZVGqn5/7jvqOHiUASVDsE+NyXsH5UfvLub4qtoP/Hd5lEkYn+Zf+Fb9d7lXAa73/fB2KUryytZvQ9Qgy9pm3TqNbW7WAai72udojqruKwq5sdOMJ4ub51SXNnrp2cxdqH8YHcd7PHnp7J+foebphu9inMl+pAyyQ5i7KE13Nj3ftQ6sDIfvkoNef22U59fmoswKqzaCTurRqz942ILaZZs/j6OVrPS805o6dS8dG3Uz65fAhVUqrG6MROFvkpdaF7ZjT1nvAj5Fm2/b1VxpsSszc+s2d96r+rf2Fv02FP/SeoSl9ildZfmUtLulbxV7kW6+Z3TOBWrVBVqWbdiN3LKxqYVuxbj3CeNUS2PON45D80+zLbBGm6z5lDzEIg0Hzdm9ZIkPHioXTN0/hiMPbfmgF0wlj78be5TxVz+l+/hSZ7vVXMstXuh7rFU14IvwaYbeyztmg/rd6mdD8UZLm3Nhzo8H6rR50N5TWN+rllz2dZjTZPYNU0qr2nkNf2AOtalPleBjnVpy0Uaw8TFwdCkvUVq9xaC6L2F9SG3xuh7C11uVG91c20fuT9UX+wPG7vlNLy1HtDnHr/KojORnnv81LtVXbmT7PHdOU119FL8Crd0/3Mav+RJzmnks7bwAbx/1pb+C2dthZ+cl4aO9l0prfPSCQ/2izPvzQBn3pupz7wL3vOFqEczsc8tkuSveW5RinqcJF/Lwf7TxsmfPcWmoIWrUGjt+eF3Uvolfdq3Pg71ehsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACASfwBIesXINu4PFgAAAAASUVORK5CYII="
}
/>
<ItemType name={"All"} imageUrl={"uploads/1718732420960.png"} />
)}
{itemTypes &&
itemTypes.map(

View File

@@ -1,15 +1,17 @@
import React from "react";
import styles from "./Modal.module.css";
import TablesPage from "./TablesPage.js";
import PaymentOptions from "./PaymentOptions.js";
import TableMaps from "../components/TableMaps";
import Transactions from "../pages/Transactions";
import Transaction_pending from "../pages/Transaction_pending";
import Transaction_confirmed from "../pages/Transaction_confirmed";
import Transaction_success from "../pages/Transaction_success";
import Transaction_failed from "../pages/Transaction_failed";
import MaterialList from "../pages/MaterialList.js";
import MaterialMutationsPage from "../pages/MaterialMutationsPage.js";
const Modal = ({ shopId, isOpen, onClose, modalContent }) => {
const Modal = ({ shop, isOpen, onClose, modalContent }) => {
if (!isOpen) return null;
// Function to handle clicks on the overlay
@@ -30,16 +32,24 @@ const Modal = ({ shopId, isOpen, onClose, modalContent }) => {
<button onClick={onClose} className={styles.closeButton}>
&times;
</button>
{modalContent === "edit_tables" && <TablesPage shopId={shopId} />}
{modalContent === "edit_tables" && <TablesPage shop={shop} />}
{modalContent === "new_transaction" && (
<Transactions propsShopId={shopId} />
<Transactions propsShopId={shop.cafeId} />
)}{" "}
{modalContent === "transaction_pending" && <Transaction_pending />}
{modalContent === "transaction_confirmed" && (
<Transaction_confirmed paymentUrl={shop.qrPayment} />
)}
{modalContent === "transaction_success" && <Transaction_success />}
{modalContent === "transaction_failed" && <Transaction_failed />}
{modalContent === "add_material" && <MaterialList cafeId={shopId} />}
{modalContent === "payment_option" && (
<PaymentOptions paymentUrl={shop.qrPayment} shopId={shop.cafeId} />
)}
{modalContent === "add_material" && (
<MaterialList cafeId={shop.cafeId} />
)}
{modalContent === "update_stock" && (
<MaterialMutationsPage cafeId={shopId} />
<MaterialMutationsPage cafeId={shop.cafeId} />
)}
</div>
</div>

View File

@@ -0,0 +1,165 @@
import React, { useState, useRef, useEffect } from "react";
import jsQR from "jsqr"; // Import jsQR library
import { getImageUrl } from "../helpers/itemHelper";
import { saveCafeDetails } from "../helpers/cafeHelpers"; // Import the helper function
const SetPaymentQr = ({
isConfigure,
tableNo,
qrCodeUrl,
paymentUrl,
initialQrPosition,
initialQrSize,
handleQrSave,
shopId, // Pass cafeId as a prop to identify which cafe to update
}) => {
const [qrPosition, setQrPosition] = useState(initialQrPosition);
const [qrSize, setQrSize] = useState(initialQrSize);
const [qrPayment, setQrPayment] = useState(getImageUrl(paymentUrl));
const [qrCodeDetected, setQrCodeDetected] = useState(false);
const qrPaymentInputRef = useRef(null);
const overlayTextRef = useRef(null);
const qrCodeContainerRef = useRef(null);
// Use useEffect to detect QR code after qrPayment updates
useEffect(() => {
if (qrPayment) {
detectQRCodeFromContainer();
}
}, [qrPayment]);
const handleFileChange = (e) => {
const file = e.target.files[0];
if (file) {
const newqrPayment = URL.createObjectURL(file); // Create a temporary URL for display
setQrPayment(newqrPayment);
}
};
const detectQRCodeFromContainer = () => {
const container = qrCodeContainerRef.current;
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
// Create an image element to load the background image
const img = new Image();
img.crossOrigin = "Anonymous"; // Handle CORS if needed
img.onload = () => {
// Set canvas size
canvas.width = container.offsetWidth;
canvas.height = container.offsetHeight;
// Draw image on canvas
context.drawImage(img, 0, 0, canvas.width, canvas.height);
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
const qrCode = jsQR(imageData.data, canvas.width, canvas.height);
if (qrCode) {
setQrCodeDetected(true);
console.log("QR Code detected:", qrCode.data);
} else {
setQrCodeDetected(false);
console.log("No QR Code detected");
}
};
img.src = qrPayment; // Load the image URL
};
const handleSave = () => {
const qrPaymentFile = qrPaymentInputRef.current.files[0]; // Get the selected file for qrPayment
// Prepare the details object
const details = {
qrPosition,
qrSize,
qrPaymentFile, // Include qrPayment file
};
// Call saveCafeDetails function with the updated details object
saveCafeDetails(shopId, details)
.then((response) => {
console.log("Cafe details saved:", response);
// handleQrSave(qrPosition, qrSize, qrPayment);
})
.catch((error) => {
console.error("Error saving cafe details:", error);
});
};
return (
<div>
<div
id="qr-code-container"
ref={qrCodeContainerRef}
style={{
position: "relative",
width: "300px",
height: "300px",
background: `center center / contain no-repeat url(${qrPayment})`,
backgroundSize: "contain",
overflow: "hidden",
border: "1px solid #ddd",
}}
>
<div
ref={overlayTextRef}
style={styles.overlayText}
onClick={() => qrPaymentInputRef.current.click()}
>
Click To Change Image
</div>
<input
type="file"
accept="image/*"
ref={qrPaymentInputRef}
style={{ display: "none" }}
onChange={handleFileChange}
/>
</div>
<div style={{ marginTop: "20px" }}>
{qrCodeDetected ? <p>QR Code Detected</p> : <p>No QR Code Detected</p>}
<div style={{ marginTop: "20px" }}>
<button
onClick={handleSave}
style={{
padding: "10px 20px",
fontSize: "16px",
backgroundColor: "#28a745",
color: "#fff",
border: "none",
borderRadius: "4px",
cursor: "pointer",
transition: "background-color 0.3s",
}}
onMouseOver={(e) =>
(e.currentTarget.style.backgroundColor = "#218838")
}
onMouseOut={(e) =>
(e.currentTarget.style.backgroundColor = "#28a745")
}
>
Save
</button>
</div>
</div>
</div>
);
};
const styles = {
overlayText: {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
backgroundColor: "rgba(0, 0, 0, 0.5)",
color: "#fff",
padding: "10px",
borderRadius: "5px",
cursor: "pointer",
},
// Other styles omitted for brevity
};
export default SetPaymentQr;

View File

@@ -1,5 +1,7 @@
import React, { useState, useRef } from "react";
import html2canvas from "html2canvas";
import { getImageUrl } from "../helpers/itemHelper";
import { saveCafeDetails } from "../helpers/cafeHelpers"; // Import the helper function
const QRCodeWithBackground = ({
isConfigure,
@@ -9,11 +11,12 @@ const QRCodeWithBackground = ({
initialQrPosition,
initialQrSize,
handleQrSave,
shopId, // Pass cafeId as a prop to identify which cafe to update
}) => {
const [qrPosition, setQrPosition] = useState(initialQrPosition);
const [qrSize, setQrSize] = useState(initialQrSize);
const [bgImage, setBgImage] = useState(backgroundUrl);
const fileInputRef = useRef(null);
const [bgImage, setBgImage] = useState(getImageUrl(backgroundUrl)); // URL or File
const qrBackgroundInputRef = useRef(null);
const overlayTextRef = useRef(null);
const handlePositionChange = (e) => {
@@ -31,13 +34,30 @@ const QRCodeWithBackground = ({
const handleFileChange = (e) => {
const file = e.target.files[0];
if (file) {
const newBgImage = URL.createObjectURL(file);
const newBgImage = URL.createObjectURL(file); // Create a temporary URL for display
setBgImage(newBgImage);
}
};
const handleSave = () => {
handleQrSave(qrPosition, qrSize, bgImage);
const qrBackgroundFile = qrBackgroundInputRef.current.files[0]; // Get the selected file for qrBackground
// Prepare the details object
const details = {
qrPosition,
qrSize,
qrBackgroundFile, // Include qrBackground file
};
// Call saveCafeDetails function with the updated details object
saveCafeDetails(shopId, details)
.then((response) => {
console.log("Cafe details saved:", response);
handleQrSave(qrPosition, qrSize, bgImage);
})
.catch((error) => {
console.error("Error saving cafe details:", error);
});
};
const printQRCode = () => {
@@ -118,7 +138,7 @@ const QRCodeWithBackground = ({
position: "relative",
width: "300px",
height: "300px",
background: `url(${bgImage}) no-repeat center center`,
background: `center center / contain no-repeat url(${bgImage})`,
backgroundSize: "contain",
overflow: "hidden",
border: "1px solid #ddd",
@@ -141,7 +161,7 @@ const QRCodeWithBackground = ({
<div
ref={overlayTextRef}
style={styles.overlayText}
onClick={() => fileInputRef.current.click()}
onClick={() => qrBackgroundInputRef.current.click()}
>
Click To Change Image
</div>
@@ -150,7 +170,7 @@ const QRCodeWithBackground = ({
<input
type="file"
accept="image/*"
ref={fileInputRef}
ref={qrBackgroundInputRef}
style={{ display: "none" }}
onChange={handleFileChange}
/>
@@ -276,16 +296,15 @@ const QRCodeWithBackground = ({
borderRadius: "4px",
cursor: "pointer",
transition: "background-color 0.3s",
marginLeft: "10px",
}}
onMouseOver={(e) =>
(e.currentTarget.style.backgroundColor = "#138496")
(e.currentTarget.style.backgroundColor = "#117a8b")
}
onMouseOut={(e) =>
(e.currentTarget.style.backgroundColor = "#17a2b8")
}
>
Save Image
Save QR Code
</button>
</div>
)}
@@ -293,54 +312,41 @@ const QRCodeWithBackground = ({
);
};
// Styles for the configuration labels and inputs
const styles = {
label: {
display: "block",
fontSize: "16px",
fontWeight: "bold",
marginBottom: "5px",
overlayText: {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
backgroundColor: "rgba(0, 0, 0, 0.5)",
color: "#fff",
padding: "10px",
borderRadius: "5px",
cursor: "pointer",
},
sliderContainer: {
marginBottom: "20px",
},
label: {
display: "block",
marginBottom: "10px",
},
sliderWrapper: {
display: "flex",
alignItems: "center",
gap: "10px",
marginTop: "5px",
},
input: {
flex: "1",
margin: "0 10px",
},
value: {
fontSize: "16px",
minWidth: "50px",
textAlign: "right",
},
labelStart: {
fontSize: "14px",
marginRight: "10px",
},
labelEnd: {
fontSize: "14px",
},
fileInput: {
marginLeft: "10px",
},
overlayText: {
position: "absolute",
fontSize: "70px",
backgroundColor: "rgba(0, 0, 0, 0.7)",
top: "0",
bottom: "0",
color: "white",
width: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
cursor: "pointer", // Indicates it's clickable
zIndex: 10, // Ensure it appears above other elements
value: {
marginLeft: "10px",
},
};

View File

@@ -1,12 +1,13 @@
import React, { useState, useEffect } from "react";
import QRCodeWithBackground from "./QR"; // Adjust path as needed
const TableList = ({ shopUrl, tables, onSelectTable, selectedTable }) => {
const [initialPos, setInitialPos] = useState({ left: 50, top: 50 });
const [initialSize, setInitialSize] = useState(20);
const [bgImageUrl, setBgImageUrl] = useState(
"https://example.com/your-background-image.png"
);
const TableList = ({ shop, tables, onSelectTable, selectedTable }) => {
const [initialPos, setInitialPos] = useState({
left: shop.xposition,
top: shop.yposition,
});
const [initialSize, setInitialSize] = useState(shop.scale);
const [bgImageUrl, setBgImageUrl] = useState(shop.qrBackground);
const shopUrl = window.location.hostname + "/" + shop.cafeId;
const generateQRCodeUrl = (tableCode) =>
`https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=${encodeURIComponent(
@@ -51,6 +52,7 @@ const TableList = ({ shopUrl, tables, onSelectTable, selectedTable }) => {
<div style={{ marginBottom: "10px" }}>configure</div>
{-1 == selectedTable?.tableId && (
<QRCodeWithBackground
shopId={shop.cafeId}
isConfigure={true}
handleQrSave={handleQrSave}
setInitialPos={setInitialPos}
@@ -62,41 +64,43 @@ const TableList = ({ shopUrl, tables, onSelectTable, selectedTable }) => {
/>
)}
</li>
{tables
.filter((table) => table.tableNo !== 0)
.map((table) => (
<li
key={table.tableId}
style={{
backgroundColor:
table.tableId === selectedTable?.tableId
? "lightblue"
: "white",
marginBottom: "10px",
padding: "10px",
borderRadius: "4px",
boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
cursor: "pointer",
}}
onClick={() => onSelectTable(table)}
>
<div style={{ marginBottom: "10px" }}>
Table {table.tableNo}
</div>
{table.tableId === selectedTable?.tableId && (
<>
<QRCodeWithBackground
tableNo={table.tableNo}
qrCodeUrl={generateQRCodeUrl(table.tableCode)}
backgroundUrl={bgImageUrl}
initialQrPosition={initialPos}
initialQrSize={initialSize}
/>
<h5>{shopUrl + "/" + table.tableCode}</h5>
</>
)}
</li>
))}
{tables &&
tables
.filter((table) => table.tableNo !== 0)
.map((table) => (
<li
key={table.tableId}
style={{
backgroundColor:
table.tableId === selectedTable?.tableId
? "lightblue"
: "white",
marginBottom: "10px",
padding: "10px",
borderRadius: "4px",
boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
cursor: "pointer",
}}
onClick={() => onSelectTable(table)}
>
<div style={{ marginBottom: "10px" }}>
Table {table.tableNo}
</div>
{table.tableId === selectedTable?.tableId && (
<>
<QRCodeWithBackground
tableNo={table.tableNo}
qrCodeUrl={generateQRCodeUrl(table.tableCode)}
backgroundUrl={bgImageUrl}
initialQrPosition={initialPos}
initialQrSize={initialSize}
cafeId={shop.cafeId}
/>
<h5>{shopUrl + "/" + table.tableCode}</h5>
</>
)}
</li>
))}
</ul>
</div>
);

View File

@@ -3,7 +3,7 @@ import { getTables, updateTable, createTable } from "../helpers/tableHelper";
import TableCanvas from "./TableCanvas";
import TableList from "./TableList";
const TablesPage = ({ shopId }) => {
const TablesPage = ({ shop }) => {
const [tables, setTables] = useState([]);
const [selectedTable, setSelectedTable] = useState(null);
const [newTable, setNewTable] = useState(null);
@@ -13,7 +13,8 @@ const TablesPage = ({ shopId }) => {
useEffect(() => {
const fetchData = async () => {
try {
const fetchedTables = await getTables(shopId);
console.log(shop);
const fetchedTables = await getTables(shop.cafeId);
setTables(fetchedTables);
setOriginalTables(fetchedTables);
} catch (error) {
@@ -22,7 +23,7 @@ const TablesPage = ({ shopId }) => {
};
fetchData();
}, [shopId]);
}, [shop.cafeId]);
const handleAddTable = () => {
const nextId = Math.random().toString(36).substr(2, 11);
@@ -131,7 +132,7 @@ const TablesPage = ({ shopId }) => {
const handleSave = async () => {
if (newTable) {
try {
const createdTable = await createTable(shopId, {
const createdTable = await createTable(shop.cafeId, {
...newTable,
tableNo,
});
@@ -144,7 +145,7 @@ const TablesPage = ({ shopId }) => {
}
} else if (selectedTable) {
try {
const updatedTable = await updateTable(shopId, {
const updatedTable = await updateTable(shop.cafeId, {
...selectedTable,
tableNo,
});
@@ -202,7 +203,7 @@ const TablesPage = ({ shopId }) => {
tableNo={tableNo}
/> */}
<TableList
shopUrl={window.location.hostname + "/" + shopId}
shop={shop}
tables={tables}
onSelectTable={handleSelect}
selectedTable={selectedTable}