ok
This commit is contained in:
49
src/components/ButtonWithReplica.css
Normal file
49
src/components/ButtonWithReplica.css
Normal file
@@ -0,0 +1,49 @@
|
||||
.container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.button {
|
||||
position: relative;
|
||||
z-index: 99; /* Make sure the button is above the replica */
|
||||
|
||||
font-family: "Poppins", sans-serif;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-size: 70%; /* Adjusted for better readability */
|
||||
padding: 12px 24px; /* Added padding for a better look */
|
||||
border-radius: 50px;
|
||||
background-color: rgba(88, 55, 50, 1);
|
||||
color: white;
|
||||
border: none;
|
||||
margin: 0 auto;
|
||||
cursor: pointer;
|
||||
display: block; /* Centering the button */
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.replica {
|
||||
height: 40px;
|
||||
width: 140px;
|
||||
border-radius: 30px;
|
||||
position: absolute;
|
||||
background-color: rgb(146, 146, 146); /* Semi-transparent blue */
|
||||
border: none;
|
||||
transition: all 0.5s ease-in-out;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 98; /* Behind the button */
|
||||
}
|
||||
|
||||
.replica.active {
|
||||
width: 200vw; /* Full screen */
|
||||
height: 200vh; /* Full screen */
|
||||
position: absolute;
|
||||
overflow-y: hidden;
|
||||
top: 30%;
|
||||
z-index: 200;
|
||||
border-radius: 0px;
|
||||
}
|
||||
24
src/components/ButtonWithReplica.js
Normal file
24
src/components/ButtonWithReplica.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import React, { useState } from "react";
|
||||
import "./ButtonWithReplica.css";
|
||||
|
||||
const ButtonWithReplica = ({ children }) => {
|
||||
const [isActive, setIsActive] = useState(false);
|
||||
|
||||
const handleClick = () => {
|
||||
setIsActive(true);
|
||||
setTimeout(() => {
|
||||
setIsActive(false);
|
||||
}, 1000); // Duration of the animation
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<button className="button" onClick={handleClick}>
|
||||
{children}
|
||||
</button>
|
||||
<div className={`replica ${isActive ? "active" : ""}`}></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ButtonWithReplica;
|
||||
@@ -89,7 +89,7 @@ export default function Footer({
|
||||
<div onClick={goToTransactions} className={styles["footer-icon"]}>
|
||||
<svg viewBox="0 0 512 512">
|
||||
<g
|
||||
transform="translate(0 512) scale(0.1 -0.1)"
|
||||
transform="translate(0 460) scale(0.09 -0.09)"
|
||||
style={{ fill: selectedPage === 3 ? "black" : "#8F8787" }}
|
||||
stroke="none"
|
||||
>
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: height 0.3s ease;
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
.scanMeja.stretched {
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useState, useRef, useEffect } from "react";
|
||||
import styled, { keyframes } from "styled-components";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useNavigationHelpers } from "../helpers/navigationHelpers";
|
||||
import Switch from "react-switch";
|
||||
|
||||
const HeaderBar = styled.div`
|
||||
margin-top: 25px;
|
||||
@@ -11,6 +12,7 @@ const HeaderBar = styled.div`
|
||||
padding: 20px 15px;
|
||||
color: black;
|
||||
background-color: white;
|
||||
z-index: 200;
|
||||
`;
|
||||
|
||||
const Title = styled.h2`
|
||||
@@ -170,6 +172,7 @@ const Rectangle = styled.div`
|
||||
overflow-y: auto; /* Enable vertical scrolling */
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
`;
|
||||
|
||||
const ChildContainer = styled.div`
|
||||
@@ -223,6 +226,7 @@ const Header = ({
|
||||
guestSideOfClerk,
|
||||
removeConnectedGuestSides,
|
||||
setIsEditMode,
|
||||
isEditMode,
|
||||
}) => {
|
||||
const { goToLogin, goToGuestSideLogin, goToAdminCafes } =
|
||||
useNavigationHelpers(shopId, tableCode);
|
||||
@@ -280,9 +284,27 @@ const Header = ({
|
||||
console.log(guestSideOfClerk);
|
||||
}, [guestSideOfClerk]);
|
||||
|
||||
const generateMenuHeader = (cafeName) => {
|
||||
// Check if the name already ends with "'s"
|
||||
if (cafeName.endsWith("'s")) {
|
||||
return `${cafeName} menu`; // Return as-is for already possessive names
|
||||
}
|
||||
if (cafeName.endsWith("s")) {
|
||||
return `${cafeName} menu`; // Return as-is for already possessive names
|
||||
}
|
||||
|
||||
// Otherwise, use the possessive function
|
||||
return `${cafeName}'s menu`;
|
||||
};
|
||||
return (
|
||||
<HeaderBar>
|
||||
<Title>{HeaderText}</Title>
|
||||
<Title>
|
||||
{shopName == null
|
||||
? HeaderText == null
|
||||
? "Groovebrew"
|
||||
: HeaderText
|
||||
: generateMenuHeader(shopName)}
|
||||
</Title>
|
||||
<div style={{ visibility: showProfile ? "visible" : "hidden" }}>
|
||||
<ProfileImage
|
||||
src="https://i.ibb.co.com/fpg1v8J/profile-major-icon-1024x1024-9rtgyx30.png"
|
||||
@@ -321,16 +343,15 @@ const Header = ({
|
||||
</Child> */}
|
||||
<Child hasChildren>
|
||||
{shopName}
|
||||
|
||||
<div class="toggle-switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="toggle-switch-checkbox"
|
||||
// checked={isChecked}
|
||||
onChange={(e) => setIsEditMode(e.target.checked)}
|
||||
/>
|
||||
<label class="toggle-switch-label" for="toggleSwitch">
|
||||
Edit Mode
|
||||
</label>
|
||||
<Switch
|
||||
checked={isEditMode}
|
||||
onChange={() => setIsEditMode(!isEditMode)}
|
||||
/>
|
||||
</div>
|
||||
<Child onClick={() => setModal("add_material")}>
|
||||
stock
|
||||
@@ -372,16 +393,15 @@ const Header = ({
|
||||
user.roleId === 2 && (
|
||||
<Child hasChildren>
|
||||
{shopName}
|
||||
|
||||
<div class="toggle-switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="toggle-switch-checkbox"
|
||||
// checked={isChecked}
|
||||
onChange={(e) => setIsEditMode(e.target.checked)}
|
||||
/>
|
||||
<label class="toggle-switch-label" for="toggleSwitch">
|
||||
Edit Mode
|
||||
</label>
|
||||
<Switch
|
||||
checked={isEditMode}
|
||||
onChange={() => setIsEditMode(!isEditMode)}
|
||||
/>
|
||||
</div>
|
||||
<Child onClick={() => setModal("add_material")}>
|
||||
stock
|
||||
|
||||
@@ -14,6 +14,7 @@ const Item = ({
|
||||
onNegativeClick,
|
||||
handleCreateItem,
|
||||
onRemoveClick,
|
||||
isAvailable,
|
||||
}) => {
|
||||
const [selectedImage, setSelectedImage] = useState(null);
|
||||
const [previewUrl, setPreviewUrl] = useState(imageUrl);
|
||||
@@ -92,6 +93,9 @@ const Item = ({
|
||||
"https://png.pngtree.com/png-vector/20221125/ourmid/pngtree-no-image-available-icon-flatvector-illustration-pic-design-profile-vector-png-image_40966566.jpg";
|
||||
}}
|
||||
alt={itemName}
|
||||
style={{
|
||||
filter: !isAvailable ? "grayscale(100%)" : "none",
|
||||
}}
|
||||
className={styles.itemImage}
|
||||
/>
|
||||
{blank && (
|
||||
@@ -113,8 +117,11 @@ const Item = ({
|
||||
<input
|
||||
className={`${
|
||||
forInvoice ? styles.itemInvoiceName : styles.itemName
|
||||
} ${blank ? styles.blank : styles.notblank}`}
|
||||
} ${blank ? styles.blank : styles.notblank} ${
|
||||
!isAvailable ? styles.disabled : ""
|
||||
}`}
|
||||
value={itemName}
|
||||
placeholder="name"
|
||||
onChange={handleNameChange}
|
||||
disabled={!blank}
|
||||
/>
|
||||
@@ -129,56 +136,83 @@ const Item = ({
|
||||
<input
|
||||
className={`${styles.itemPrice} ${
|
||||
blank ? styles.blank : styles.notblank
|
||||
}`}
|
||||
} ${!isAvailable ? styles.disabled : ""}`}
|
||||
value={itemPrice}
|
||||
placeholder="price"
|
||||
onChange={handlePriceChange}
|
||||
disabled={!blank}
|
||||
/>
|
||||
)}
|
||||
|
||||
{!forInvoice && (
|
||||
<div className={styles.itemQty}>
|
||||
<svg
|
||||
className={styles.plusNegative}
|
||||
onClick={handleNegativeClick}
|
||||
clipRule="evenodd"
|
||||
fillRule="evenodd"
|
||||
strokeLinejoin="round"
|
||||
strokeMiterlimit="2"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="m12.002 2.005c5.518 0 9.998 4.48 9.998 9.997 0 5.518-4.48 9.998-9.998 9.998-5.517 0-9.997-4.48-9.997-9.998 0-5.517 4.48-9.997 9.997-9.997zm0 1.5c-4.69 0-8.497 3.807-8.497 8.497s3.807 8.498 8.497 8.498 8.498-3.808 8.498-8.498-3.808-8.497-8.498-8.497zm4.253 7.75h-8.5c-.414 0-.75.336-.75.75s.336.75.75.75h8.5c.414 0 .75-.336.75-.75s-.336-.75-.75-.75z"
|
||||
fillRule="nonzero"
|
||||
/>
|
||||
</svg>
|
||||
{!blank && <p className={styles.itemQtyValue}>{itemQty}</p>}
|
||||
{blank && (
|
||||
<input
|
||||
className={styles.itemQtyInput}
|
||||
value={itemQty}
|
||||
onChange={handleQtyChange}
|
||||
disabled={!blank}
|
||||
/>
|
||||
)}
|
||||
<svg
|
||||
className={styles.plusNegative}
|
||||
onClick={handlePlusClick}
|
||||
clipRule="evenodd"
|
||||
fillRule="evenodd"
|
||||
strokeLinejoin="round"
|
||||
strokeMiterlimit="2"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="m12.002 2c5.518 0 9.998 4.48 9.998 9.998 0 5.517-4.48 9.997-9.998 9.997-5.517 0-9.997-4.48-9.997-9.997 0-5.518 4.48-9.998 9.997-9.998zm0 1.5c-4.69 0-8.497 3.808-8.497 8.498s3.807 8.497 8.497 8.497 8.498-3.807 8.498-8.497-3.808-8.498-8.498-8.498zm-.747 7.75h-3.5c-.414 0-.75.336-.75.75s.336.75.75.75h3.5v3.5c0 .414.336.75.75.75s.75-.336.75-.75v-3.5h3.5c.414 0 .75-.336.75-.75s-.336-.75-.75-.75h-3.5v-3.5c0-.414-.336-.75-.75-.75s-.75.336-.75.75z"
|
||||
fillRule="nonzero"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
{!forInvoice &&
|
||||
(itemQty != 0 ? (
|
||||
<div className={styles.itemQty}>
|
||||
<svg
|
||||
className={styles.plusNegative}
|
||||
onClick={handleNegativeClick}
|
||||
clipRule="evenodd"
|
||||
fillRule="evenodd"
|
||||
strokeLinejoin="round"
|
||||
strokeMiterlimit="2"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="m12.002 2.005c5.518 0 9.998 4.48 9.998 9.997 0 5.518-4.48 9.998-9.998 9.998-5.517 0-9.997-4.48-9.997-9.998 0-5.517 4.48-9.997 9.997-9.997zm0 1.5c-4.69 0-8.497 3.807-8.497 8.497s3.807 8.498 8.497 8.498 8.498-3.808 8.498-8.498-3.808-8.497-8.498-8.497zm4.253 7.75h-8.5c-.414 0-.75.336-.75.75s.336.75.75.75h8.5c.414 0 .75-.336.75-.75s-.336-.75-.75-.75z"
|
||||
fillRule="nonzero"
|
||||
/>
|
||||
</svg>
|
||||
{!blank ? (
|
||||
<p className={styles.itemQtyValue}>{itemQty}</p>
|
||||
) : (
|
||||
<input
|
||||
className={styles.itemQtyInput}
|
||||
value={itemQty}
|
||||
onChange={handleQtyChange}
|
||||
disabled={!blank}
|
||||
/>
|
||||
)}
|
||||
<svg
|
||||
className={styles.plusNegative}
|
||||
onClick={handlePlusClick}
|
||||
clipRule="evenodd"
|
||||
fillRule="evenodd"
|
||||
strokeLinejoin="round"
|
||||
strokeMiterlimit="2"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="m12.002 2c5.518 0 9.998 4.48 9.998 9.998 0 5.517-4.48 9.997-9.998 9.997-5.517 0-9.997-4.48-9.997-9.997 0-5.518 4.48-9.998 9.997-9.998zm0 1.5c-4.69 0-8.497 3.808-8.497 8.498s3.807 8.497 8.497 8.497 8.498-3.807 8.498-8.497-3.808-8.498-8.498-8.498zm-.747 7.75h-3.5c-.414 0-.75.336-.75.75s.336.75.75.75h3.5v3.5c0 .414.336.75.75.75s.75-.336.75-.75v-3.5h3.5c.414 0 .75-.336.75-.75s-.336-.75-.75-.75h-3.5v-3.5c0-.414-.336-.75-.75-.75s-.75.336-.75.75z"
|
||||
fillRule="nonzero"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
) : !blank ? (
|
||||
<div className={styles.itemQty}>
|
||||
<button
|
||||
className={styles.addButton}
|
||||
style={{ backgroundColor: !isAvailable ? "gray" : "#4da94d" }}
|
||||
onClick={handlePlusClick}
|
||||
disabled={!isAvailable} // Optionally disable the button if not available
|
||||
>
|
||||
Tambah
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles.itemQty}>
|
||||
<button
|
||||
className={styles.addButton}
|
||||
style={{
|
||||
backgroundColor: "#4da94d",
|
||||
width: "150px",
|
||||
}}
|
||||
onClick={handleCreate}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{forInvoice && (
|
||||
<p className={styles.itemPriceInvoice}>Rp {itemQty * itemPrice}</p>
|
||||
@@ -189,11 +223,11 @@ const Item = ({
|
||||
ⓧ
|
||||
</div>
|
||||
)}
|
||||
{blank && (
|
||||
{/* {blank && (
|
||||
<button className={styles.createItem} onClick={handleCreate}>
|
||||
Create Item
|
||||
</button>
|
||||
)}
|
||||
)} */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -166,6 +166,26 @@
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.addButton {
|
||||
background-color: #04aa6d;
|
||||
border: none;
|
||||
color: white;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
width: 95px;
|
||||
height: 35px;
|
||||
margin-left: 5px;
|
||||
margin-top: 5px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.grayscale {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: gray;
|
||||
}
|
||||
.plusNegative {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useRef } from "react";
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import styles from "./ItemLister.module.css";
|
||||
import Item from "./Item";
|
||||
import Switch from "react-switch";
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
import {
|
||||
getImageUrl,
|
||||
createItem,
|
||||
updateItemAvalilability,
|
||||
updateItemType,
|
||||
deleteItemType,
|
||||
} from "../helpers/itemHelper.js";
|
||||
@@ -25,6 +26,7 @@ const ItemLister = ({
|
||||
forCart,
|
||||
forInvoice,
|
||||
isEditMode,
|
||||
raw,
|
||||
}) => {
|
||||
const [items, setItems] = useState(
|
||||
itemList.map((item) => ({
|
||||
@@ -32,6 +34,16 @@ const ItemLister = ({
|
||||
qty: getItemQtyFromCart(shopId, item.itemId),
|
||||
}))
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setItems(
|
||||
itemList.map((item) => ({
|
||||
...item,
|
||||
qty: getItemQtyFromCart(shopId, item.itemId),
|
||||
}))
|
||||
);
|
||||
}, [itemList]);
|
||||
|
||||
const [isEdit, setIsEditing] = useState(false);
|
||||
const [isAddingNewItem, setIsAddingNewItem] = useState(false);
|
||||
const [editedTypeName, setEditedTypeName] = useState(typeName);
|
||||
@@ -111,69 +123,135 @@ const ItemLister = ({
|
||||
const toggleAddNewItem = () => {
|
||||
setIsAddingNewItem((prev) => !prev);
|
||||
};
|
||||
const handleChange = async (itemId) => {
|
||||
// Find the item in the current items array
|
||||
console.log(itemId);
|
||||
const itemIndex = items.findIndex((item) => item.itemId === itemId);
|
||||
if (itemIndex === -1) return; // Item not found
|
||||
|
||||
// Create a copy of the current items array
|
||||
const updatedItems = [...items];
|
||||
const item = updatedItems[itemIndex];
|
||||
|
||||
// Toggle the availability locally
|
||||
const newAvailability = !item.availability;
|
||||
updatedItems[itemIndex] = {
|
||||
...item,
|
||||
availability: newAvailability,
|
||||
};
|
||||
|
||||
// Update the state with the local change
|
||||
setItems(updatedItems);
|
||||
|
||||
try {
|
||||
// Wait for the updateItemAvailability response
|
||||
const response = await updateItemAvalilability(itemId, newAvailability);
|
||||
|
||||
// Assuming response contains the updated item data
|
||||
const updatedItem = response;
|
||||
console.log(updatedItem);
|
||||
// Update only the specified item in the state
|
||||
setItems((prevItems) =>
|
||||
prevItems.map((prevItem) =>
|
||||
prevItem.itemId === itemId ? updatedItem : prevItem
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
// Handle error (e.g., revert the change or show an error message)
|
||||
console.error("Error updating item availability:", error);
|
||||
|
||||
// Optionally revert to the previous availability if needed
|
||||
updatedItems[itemIndex].availability = item.availability; // revert back
|
||||
setItems(updatedItems);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{(items.length > 0 ||
|
||||
(user && user.roleId == 1 && user.userId == shopOwnerId)) && (
|
||||
<div className={styles["item-lister"]}>
|
||||
<div className={styles["title-container"]}>
|
||||
<input
|
||||
ref={typeNameInputRef}
|
||||
className={`${styles.title} ${
|
||||
user && user.roleId == 1 && user.userId == shopOwnerId && isEdit
|
||||
? styles.border
|
||||
: styles.noborder
|
||||
}`}
|
||||
value={editedTypeName}
|
||||
onChange={(e) => setEditedTypeName(e.target.value)}
|
||||
disabled={!isEdit}
|
||||
/>
|
||||
{user && user.roleId == 1 && user.userId == shopOwnerId && (
|
||||
<>
|
||||
<button
|
||||
className={styles["edit-typeItem-button"]}
|
||||
onClick={toggleEditTypeItem}
|
||||
>
|
||||
{isEdit ? "Cancel" : "Edit"}
|
||||
</button>
|
||||
{isEdit && (
|
||||
<button
|
||||
className={styles["edit-typeItem-button"]}
|
||||
onClick={handleSaveType}
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
{!raw && (
|
||||
<div className={styles["title-container"]}>
|
||||
<input
|
||||
ref={typeNameInputRef}
|
||||
className={`${styles.title} ${
|
||||
user &&
|
||||
user.roleId == 1 &&
|
||||
user.userId == shopOwnerId &&
|
||||
isEdit
|
||||
? styles.border
|
||||
: styles.noborder
|
||||
}`}
|
||||
value={editedTypeName}
|
||||
onChange={(e) => setEditedTypeName(e.target.value)}
|
||||
disabled={!isEdit}
|
||||
/>
|
||||
{isEditMode &&
|
||||
user &&
|
||||
user.roleId == 1 &&
|
||||
user.userId == shopOwnerId && (
|
||||
<>
|
||||
<button
|
||||
className={styles["edit-typeItem-button"]}
|
||||
onClick={toggleEditTypeItem}
|
||||
>
|
||||
{isEdit ? "Cancel" : "Edit"}
|
||||
</button>
|
||||
{isEdit && (
|
||||
<button
|
||||
className={styles["edit-typeItem-button"]}
|
||||
onClick={handleSaveType}
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={styles["item-list"]}>
|
||||
{user &&
|
||||
user.roleId == 1 &&
|
||||
user.userId == shopOwnerId &&
|
||||
isEdit && (
|
||||
isEditMode && (
|
||||
<>
|
||||
<button
|
||||
className={styles["add-item-button"]}
|
||||
onClick={toggleAddNewItem}
|
||||
>
|
||||
{isAddingNewItem ? "Cancel" : "Add new Item"}
|
||||
</button>
|
||||
{!isAddingNewItem && (
|
||||
<button
|
||||
className={styles["add-item-button"]}
|
||||
onClick={toggleAddNewItem}
|
||||
style={{
|
||||
display: "inline-block",
|
||||
height: "159px",
|
||||
fontSize: "50px",
|
||||
}}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
)}
|
||||
{isAddingNewItem && (
|
||||
<Item
|
||||
blank={true}
|
||||
handleCreateItem={(name, price, qty, selectedImage) =>
|
||||
createItem(
|
||||
shopId,
|
||||
name,
|
||||
price,
|
||||
qty,
|
||||
selectedImage,
|
||||
itemTypeId
|
||||
)
|
||||
}
|
||||
/>
|
||||
<>
|
||||
<button
|
||||
className={styles["add-item-button"]}
|
||||
onClick={toggleAddNewItem}
|
||||
style={{ display: "inline-block" }}
|
||||
>
|
||||
↩
|
||||
</button>
|
||||
<Item
|
||||
blank={true}
|
||||
handleCreateItem={(name, price, qty, selectedImage) =>
|
||||
createItem(
|
||||
shopId,
|
||||
name,
|
||||
price,
|
||||
qty,
|
||||
selectedImage,
|
||||
itemTypeId
|
||||
)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
@@ -182,8 +260,13 @@ const ItemLister = ({
|
||||
<div className={styles["itemWrapper"]}>
|
||||
{isEditMode && (
|
||||
<div className={styles["editModeLayout"]}>
|
||||
<Switch checked={true} />
|
||||
<h3>available</h3>
|
||||
{isEditMode && (
|
||||
<Switch
|
||||
onChange={() => handleChange(item.itemId)}
|
||||
checked={item.availability}
|
||||
/>
|
||||
)}
|
||||
<h3>{item.availability ? "available" : "unavailable"}</h3>
|
||||
</div>
|
||||
)}
|
||||
<Item
|
||||
@@ -198,6 +281,7 @@ const ItemLister = ({
|
||||
onNegativeClick={() => handleNegativeClick(item.itemId)}
|
||||
onRemoveClick={() => handleRemoveClick(item.itemId)}
|
||||
isEditMode={isEditMode}
|
||||
isAvailable={item.availability}
|
||||
/>
|
||||
</div>
|
||||
) : null;
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
margin-top: 10px;
|
||||
padding: 8px 16px; /* Adjust padding as needed */
|
||||
font-size: 14px;
|
||||
background-color: #007bff;
|
||||
background-color: #359d42d1;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
@@ -66,6 +66,7 @@
|
||||
position: relative;
|
||||
}
|
||||
.editModeLayout {
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
background-color: #0000008c;
|
||||
|
||||
@@ -8,6 +8,7 @@ export default function ItemType({
|
||||
blank,
|
||||
name: initialName = "",
|
||||
imageUrl,
|
||||
selected,
|
||||
}) {
|
||||
const inputRef = useRef(null);
|
||||
const [name, setName] = useState(initialName);
|
||||
@@ -51,7 +52,11 @@ export default function ItemType({
|
||||
|
||||
return (
|
||||
<div className={styles["item-type"]}>
|
||||
<div onClick={onClick} className={styles["item-type-rect"]}>
|
||||
<div
|
||||
onClick={onClick}
|
||||
className={styles["item-type-rect"]}
|
||||
style={{ top: selected ? "-10px" : "initial" }}
|
||||
>
|
||||
<img
|
||||
src={previewUrl}
|
||||
alt={name}
|
||||
@@ -84,6 +89,7 @@ export default function ItemType({
|
||||
value={name}
|
||||
onChange={handleNameChange}
|
||||
disabled={!blank}
|
||||
style={{ top: selected ? "-5px" : "initial" }}
|
||||
/>
|
||||
{blank && (
|
||||
<button className={styles["item-type-create"]} onClick={handleCreate}>
|
||||
|
||||
@@ -3,7 +3,15 @@ import "./ItemTypeLister.css";
|
||||
import ItemType from "./ItemType";
|
||||
import { createItemType } from "../helpers/itemHelper.js";
|
||||
|
||||
const ItemTypeLister = ({ shopId, shopOwnerId, user, itemTypes }) => {
|
||||
const ItemTypeLister = ({
|
||||
shopId,
|
||||
shopOwnerId,
|
||||
user,
|
||||
itemTypes,
|
||||
onFilterChange,
|
||||
filterId,
|
||||
isEditMode,
|
||||
}) => {
|
||||
const [isAddingNewItem, setIsAddingNewItem] = useState(false);
|
||||
|
||||
const toggleAddNewItem = () => {
|
||||
@@ -19,7 +27,11 @@ const ItemTypeLister = ({ shopId, shopOwnerId, user, itemTypes }) => {
|
||||
<div className="item-type-lister">
|
||||
<div className="item-type-list">
|
||||
{itemTypes && itemTypes.length > 1 && (
|
||||
<ItemType name={"All"} imageUrl={"uploads/1718732420960.png"} />
|
||||
<ItemType
|
||||
name={"All"}
|
||||
onClick={() => onFilterChange(0)}
|
||||
imageUrl={"uploads/1718732420960.png"}
|
||||
/>
|
||||
)}
|
||||
{itemTypes &&
|
||||
itemTypes.map(
|
||||
@@ -30,6 +42,8 @@ const ItemTypeLister = ({ shopId, shopOwnerId, user, itemTypes }) => {
|
||||
key={itemType.itemTypeId}
|
||||
name={itemType.name}
|
||||
imageUrl={itemType.image}
|
||||
onClick={() => onFilterChange(itemType.itemTypeId)}
|
||||
selected={filterId == itemType.itemTypeId}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
@@ -39,16 +53,15 @@ const ItemTypeLister = ({ shopId, shopOwnerId, user, itemTypes }) => {
|
||||
isAddingNewItem && (
|
||||
<ItemType blank={true} name={"blank"} onCreate={handleCreate} />
|
||||
)}
|
||||
{!isAddingNewItem &&
|
||||
{isEditMode &&
|
||||
!isAddingNewItem &&
|
||||
user &&
|
||||
user.roleId == 1 &&
|
||||
user.userId == shopOwnerId && (
|
||||
<ItemType
|
||||
onClick={toggleAddNewItem}
|
||||
name={"create"}
|
||||
imageUrl={
|
||||
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQnd07OYAm1f7T6JzziFU7U8X1_IL3bADiVrg&usqp=CAU"
|
||||
}
|
||||
imageUrl={"uploads/addnew.png"}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -13,6 +13,7 @@ import Payment_claimed from "../pages/Payment_claimed";
|
||||
import MaterialList from "../pages/MaterialList.js";
|
||||
import MaterialMutationsPage from "../pages/MaterialMutationsPage.js";
|
||||
import Reports from "../pages/Reports.js";
|
||||
import NotificationBlocked from "../pages/NotificationBlocked.js";
|
||||
|
||||
const Modal = ({ shop, isOpen, onClose, modalContent }) => {
|
||||
if (!isOpen) return null;
|
||||
@@ -35,6 +36,7 @@ const Modal = ({ shop, isOpen, onClose, modalContent }) => {
|
||||
<button onClick={onClose} className={styles.closeButton}>
|
||||
×
|
||||
</button>
|
||||
{modalContent === "req_notification" && <NotificationBlocked />}
|
||||
{modalContent === "edit_tables" && <TablesPage shop={shop} />}
|
||||
{modalContent === "new_transaction" && (
|
||||
<Transaction propsShopId={shop.cafeId} />
|
||||
@@ -53,7 +55,7 @@ const Modal = ({ shop, isOpen, onClose, modalContent }) => {
|
||||
{modalContent === "transaction_end" && <Transaction_end />}
|
||||
{modalContent === "transaction_failed" && <Transaction_failed />}
|
||||
{modalContent === "payment_option" && (
|
||||
<PaymentOptions paymentUrl={shop.qrPayment} shopId={shop.cafeId} />
|
||||
<PaymentOptions shopId={shop.cafeId} />
|
||||
)}
|
||||
{modalContent === "add_material" && (
|
||||
<MaterialList cafeId={shop.cafeId} />
|
||||
|
||||
@@ -12,13 +12,11 @@
|
||||
}
|
||||
|
||||
.modalContent {
|
||||
background: white;
|
||||
border-radius: 5px;
|
||||
width: 90%;
|
||||
height: 80%;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
position: relative;
|
||||
overflow: hidden; /* Add this line to enable scrolling */
|
||||
overflow: visible; /* Add this line to enable scrolling */
|
||||
}
|
||||
|
||||
.closeButton {
|
||||
|
||||
@@ -1,27 +1,43 @@
|
||||
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
|
||||
import {
|
||||
getCafe,
|
||||
saveCafeDetails,
|
||||
setConfirmationStatus,
|
||||
} from "../helpers/cafeHelpers"; // Import the helper function
|
||||
import Switch from "react-switch";
|
||||
|
||||
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 SetPaymentQr = ({ shopId }) => {
|
||||
const [qrPosition, setQrPosition] = useState([50, 50]);
|
||||
const [qrSize, setQrSize] = useState(50);
|
||||
const [qrPayment, setQrPayment] = useState();
|
||||
const [qrCodeDetected, setQrCodeDetected] = useState(false);
|
||||
const qrPaymentInputRef = useRef(null);
|
||||
const overlayTextRef = useRef(null);
|
||||
const qrCodeContainerRef = useRef(null);
|
||||
const [isNeedConfirmation, setIsNeedConfirmation] = useState(false);
|
||||
const [cafe, setCafe] = useState([]);
|
||||
|
||||
// Use useEffect to detect QR code after qrPayment updates
|
||||
useEffect(() => {
|
||||
const fetchCafe = async () => {
|
||||
try {
|
||||
const response = await getCafe(shopId);
|
||||
setCafe(response);
|
||||
setQrPayment(getImageUrl(response.qrPayment));
|
||||
setIsNeedConfirmation(response.needsConfirmation);
|
||||
setQrPosition([response.xposition, response.yposition]);
|
||||
setQrSize(response.scale);
|
||||
console.log(response);
|
||||
} catch (error) {
|
||||
console.error("Error fetching cafe:", error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchCafe();
|
||||
}, [shopId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (qrPayment) {
|
||||
detectQRCodeFromContainer();
|
||||
@@ -77,7 +93,7 @@ const SetPaymentQr = ({
|
||||
};
|
||||
|
||||
// Call saveCafeDetails function with the updated details object
|
||||
saveCafeDetails(shopId, details)
|
||||
saveCafeDetails(cafe.cafeId, details)
|
||||
.then((response) => {
|
||||
console.log("Cafe details saved:", response);
|
||||
// handleQrSave(qrPosition, qrSize, qrPayment);
|
||||
@@ -87,6 +103,24 @@ const SetPaymentQr = ({
|
||||
});
|
||||
};
|
||||
|
||||
const handleChange = async () => {
|
||||
console.log(isNeedConfirmation);
|
||||
setIsNeedConfirmation(!isNeedConfirmation);
|
||||
console.log(!isNeedConfirmation);
|
||||
try {
|
||||
// Wait for the updateItemAvailability response
|
||||
const response = await setConfirmationStatus(
|
||||
cafe.cafeId,
|
||||
!isNeedConfirmation
|
||||
);
|
||||
|
||||
setIsNeedConfirmation(response.needsConfirmation);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
setIsNeedConfirmation(cafe.needsConfirmation);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
@@ -143,6 +177,8 @@ const SetPaymentQr = ({
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Switch onChange={() => handleChange()} checked={isNeedConfirmation} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -163,7 +163,7 @@ const QRCodeWithBackground = ({
|
||||
style={styles.overlayText}
|
||||
onClick={() => qrBackgroundInputRef.current.click()}
|
||||
>
|
||||
Click To Change Image
|
||||
Click To Change Background
|
||||
</div>
|
||||
)}
|
||||
{/* Hidden file input */}
|
||||
@@ -191,7 +191,6 @@ const QRCodeWithBackground = ({
|
||||
onChange={handleSizeChange}
|
||||
style={styles.input}
|
||||
/>
|
||||
<span style={styles.labelEnd}>100%</span>
|
||||
<span style={styles.value}>{qrSize}%</span>
|
||||
</div>
|
||||
</label>
|
||||
@@ -211,7 +210,6 @@ const QRCodeWithBackground = ({
|
||||
onChange={handlePositionChange}
|
||||
style={styles.input}
|
||||
/>
|
||||
<span style={styles.labelEnd}>100%</span>
|
||||
<span style={styles.value}>{qrPosition.left}%</span>
|
||||
</div>
|
||||
</label>
|
||||
@@ -231,7 +229,6 @@ const QRCodeWithBackground = ({
|
||||
onChange={handlePositionChange}
|
||||
style={styles.input}
|
||||
/>
|
||||
<span style={styles.labelEnd}>100%</span>
|
||||
<span style={styles.value}>{qrPosition.top}%</span>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
@@ -74,15 +74,17 @@ export default function SearchInput({
|
||||
let url = "";
|
||||
if (autofocus || songName != "") {
|
||||
url = tableCode
|
||||
? `/${shopId}/${tableCode}/search?query=${encodeURIComponent(songName)}`
|
||||
? `/${shopId}/${tableCode}/search?query=${encodeURIComponent(
|
||||
songName
|
||||
)}`
|
||||
: `/${shopId}/search?query=${encodeURIComponent(songName)}`;
|
||||
navigate(url);
|
||||
}
|
||||
|
||||
if (autofocus) {
|
||||
if (songName == "") {
|
||||
if (tableCode) navigate(`/${shopId}/${tableCode}`);
|
||||
else navigate(`/${shopId}`);
|
||||
if (tableCode) navigate(`/${shopId}/${tableCode}?find=true`);
|
||||
else navigate(`/${shopId}?find=true`);
|
||||
}
|
||||
}
|
||||
if (onSearchChange) onSearchChange(songName);
|
||||
@@ -100,9 +102,18 @@ export default function SearchInput({
|
||||
|
||||
// Focus input when component mounts
|
||||
useEffect(() => {
|
||||
if (autofocus) if (inputRef.current) inputRef.current.focus();
|
||||
const isFinding = searchParams.get("find") || false;
|
||||
if (autofocus || isFinding) if (inputRef.current) inputRef.current.focus();
|
||||
}, []);
|
||||
|
||||
const handleBlur = () => {
|
||||
const isFinding = searchParams.get("find") || false;
|
||||
if (isFinding) {
|
||||
if (tableCode) navigate(`/${shopId}/${tableCode}`);
|
||||
else navigate(`/${shopId}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SearchBox>
|
||||
<SearchContainer>
|
||||
@@ -112,6 +123,7 @@ export default function SearchInput({
|
||||
placeholder="Search..."
|
||||
value={songName}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
/>
|
||||
<SearchIcon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path d="M20.8333 18.3333H19.5167L19.05 17.8833C20.6833 15.9833 21.6667 13.5167 21.6667 10.8333C21.6667 4.85 16.8167 0 10.8333 0C4.85 0 0 4.85 0 10.8333C0 16.8167 4.85 21.6667 10.8333 21.6667C13.5167 21.6667 15.9833 20.6833 17.8833 19.05L18.3333 19.5167V20.8333L26.6667 29.15L29.15 26.6667L20.8333 18.3333ZM10.8333 18.3333C6.68333 18.3333 3.33333 14.9833 3.33333 10.8333C3.33333 6.68333 6.68333 3.33333 10.8333 3.33333C14.9833 3.33333 18.3333 6.68333 18.3333 10.8333C18.3333 14.9833 14.9833 18.3333 10.8333 18.3333Z" />
|
||||
|
||||
Reference in New Issue
Block a user