From 4dd12f383546d378281723a7172b5f02f1c8c5ad Mon Sep 17 00:00:00 2001 From: Samsudin Taufik Date: Fri, 11 Oct 2024 23:40:48 +0000 Subject: [PATCH] ok --- src/App.js | 2 +- src/components/ItemLister.js | 444 ++++++++++++++++++++------- src/components/ItemLister.module.css | 15 +- src/components/ItemType.js | 8 +- src/components/ItemTypeLister.js | 148 +-------- src/components/RouletteWheel.js | 1 - src/config.js | 2 +- src/helpers/itemHelper.js | 48 ++- src/pages/CafePage.js | 12 +- 9 files changed, 416 insertions(+), 264 deletions(-) diff --git a/src/App.js b/src/App.js index de226cf..208766d 100644 --- a/src/App.js +++ b/src/App.js @@ -423,7 +423,7 @@ function App() { { const [items, setItems] = useState( itemList.map((item) => ({ @@ -50,11 +53,14 @@ const ItemLister = ({ ); }, [itemList]); - const [isEdit, setIsEditing] = useState(false); - const [onEditItem, setOnEditItem] = useState(0); - const [isAddingNewItem, setIsAddingNewItem] = useState(false); + const [isVisible, setIsVisible] = useState(typeVisibility); + const [isEdit, setIsEditing] = useState(alwaysEdit); + const [isEditItem, setisEditItem] = useState(0); + const [isAddingNewItem, setIsAddingNewItem] = useState(alwaysEdit); const [editedTypeName, setEditedTypeName] = useState(typeName); const typeNameInputRef = useRef(null); + const [itemsToCreate, setItemsToCreate] = useState([]); + const [itemsToUpdate, setItemsToUpdate] = useState([]); const handlePlusClick = (itemId) => { const updatedItems = items.map((item) => { @@ -103,15 +109,6 @@ const ItemLister = ({ setIsEditing((prev) => !prev); }; - const handleSaveType = async () => { - try { - await updateItemType(shopId, itemTypeId, typeNameInputRef.current.value); - setIsEditing(false); - } catch (error) { - console.error("Failed to save item type:", error); - } - }; - const handleRemoveType = async () => { try { await deleteItemType(shopId, itemTypeId); @@ -125,22 +122,80 @@ const ItemLister = ({ useEffect(() => { if (beingEditedType == itemTypeId) return; - setOnEditItem(0); + setisEditItem(0); setIsAddingNewItem(false); }, [beingEditedType]); const toggleAddNewItem = () => { setBeingEditedType(itemTypeId); setIsAddingNewItem((prev) => !prev); - setOnEditItem(0); + setisEditItem(0); }; const editItem = (itemId) => { setBeingEditedType(itemTypeId); setIsAddingNewItem(false); - setOnEditItem(itemId); + setisEditItem(itemId); }; - const handleChange = async (itemId) => { - // Find the item in the current items array + + const [selectedImage, setSelectedImage] = useState(null); + const [previewUrl, setPreviewUrl] = useState(getImageUrl(typeImage)); + // useEffect(() => { + // if (!selectedImage) { + // setPreviewUrl(getImageUrl(typeImage)); + // } else { + // setPreviewUrl(selectedImage); + // } + // console.log(selectedImage); + // }, [selectedImage]); + + const handleImageChange = (previewUrl, selectedImage) => { + setSelectedImage(selectedImage); + console.log(selectedImage); + setPreviewUrl(previewUrl); + }; + + const onCreateItem = (itemName, itemPrice, selectedImage, previewUrl) => { + if (isEdit) + setItemsToCreate((prevItems) => [ + ...prevItems, + { + itemId: -(prevItems.length + 1), + name: itemName, + price: itemPrice, + selectedImage, + image: previewUrl, + }, + ]); + else handleCreateItem(itemTypeId, itemName, itemPrice, selectedImage); + + console.log(items); + console.log(itemsToCreate); + + setIsAddingNewItem(false); + }; + const updateItemInCreate = ( + itemId, + name, + price, + selectedImage, + previewUrl + ) => { + setItemsToCreate((prevItems) => + prevItems.map((item) => + item.itemId === itemId + ? { ...item, name, price, selectedImage, image: previewUrl } + : item + ) + ); + }; + const onUpdateItem = (itemId, name, price, image) => { + if (isEdit) + setItemsToUpdate((prev) => [...prev, { itemId, name, price, image }]); + else handleUpdateItem(itemId, name, price, image); + console.log(itemsToUpdate); + }; + + const handleChange = (itemId) => { console.log(itemId); const itemIndex = items.findIndex((item) => item.itemId === itemId); if (itemIndex === -1) return; // Item not found @@ -159,13 +214,33 @@ const ItemLister = ({ // Update the state with the local change setItems(updatedItems); - try { - // Wait for the updateItemAvailability response - const response = await updateItemAvalilability(itemId, newAvailability); + if (isEdit) { + // If isEdit, add item to the list of items to update + setItemsToUpdate((prev) => [...prev, { itemId, newAvailability }]); + } else { + // If not isEdit, immediately execute the update + executeUpdateAvailability( + itemId, + newAvailability, + updatedItems, + itemIndex + ); + } + console.log(itemsToUpdate); + }; - // Assuming response contains the updated item data + const executeUpdateAvailability = async ( + itemId, + newAvailability, + updatedItems, + itemIndex + ) => { + try { + console.log(itemId + newAvailability); + const response = await updateItemAvalilability(itemId, newAvailability); const updatedItem = response; console.log(updatedItem); + // Update only the specified item in the state setItems((prevItems) => prevItems.map((prevItem) => @@ -173,31 +248,85 @@ const ItemLister = ({ ) ); } 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 + updatedItems[itemIndex].availability = !newAvailability; // revert back setItems(updatedItems); } }; - const onCreateItem = (itemName, itemPrice, selectedImage, previewUrl) => { - handleCreateItem(itemName, itemPrice, selectedImage, previewUrl); - setIsAddingNewItem(false); - }; - console.log(getImageUrl(typeImage)); - const [selectedImage, setSelectedImage] = useState(null); - const [previewUrl, setPreviewUrl] = useState(""); - useEffect(() => { - if (selectedImage) { - setPreviewUrl(selectedImage); - } else { - setPreviewUrl(getImageUrl(typeImage)); + + const handleSaveType = async () => { + try { + console.log(isVisible); + if (itemTypeId) { + await updateItemType( + shopId, + itemTypeId, + typeNameInputRef.current.value, + previewUrl, + selectedImage, + isVisible + ); + + // Iterate through itemsToUpdate and call the API + for (const { + itemId, + newAvailability, + name, + price, + image, + } of itemsToUpdate) { + if (newAvailability != undefined) + await executeUpdateAvailability( + itemId, + newAvailability, + items, + items.findIndex((item) => item.itemId === itemId) + ); + else await handleUpdateItem(itemId, name, price, image); + } + for (const { name, price, selectedImage } of itemsToCreate) { + handleCreateItem(itemTypeId, name, price, selectedImage); + } + } else { + const itemType = await createItemType( + shopId, + editedTypeName, + selectedImage + ); + console.log(itemType); + for (const { name, price, selectedImage } of itemsToCreate) { + handleCreateItem(itemType.itemTypeId, name, price, selectedImage); + } + } + // Clear the itemsToUpdate after saving + setItemsToUpdate([]); + setIsEditing(false); + } catch (error) { + console.error("Failed to save item type:", error); } - }, [selectedImage]); - const handleImageChange = (e) => { - setSelectedImage(e); }; + + const resetItems = () => { + // Create a copy of the current items to revert + const updatedItems = [...items]; + + // Iterate over itemsToUpdate and reset the availability + itemsToUpdate.forEach(({ itemId, newAvailability }) => { + const itemIndex = updatedItems.findIndex( + (item) => item.itemId === itemId + ); + if (itemIndex !== -1) { + updatedItems[itemIndex].availability = !newAvailability; // revert back to original + } + }); + + // Update the items state and clear itemsToUpdate + setItems(updatedItems); + setItemsToUpdate([]); + setIsEditing(false); + if (handleUnEdit) handleUnEdit(); + }; + return ( <> {(items.length > 0 || @@ -206,117 +335,168 @@ const ItemLister = ({ className={`${styles["item-lister"]} ${ isEdit ? styles["fullscreen"] : "" }`} - style={{ paddingBottom: isEdit ? "25vh" : "" }} + style={{ paddingBottom: isEdit ? "28vh" : "" }} > - {!raw && ( -
- {isEdit && } - setEditedTypeName(e.target.value)} - disabled={!isEdit} - /> - {isEditMode && !isEdit && ( - <> - - - )} -
- )} +
+ {isEdit && } + setEditedTypeName(e.target.value)} + disabled={!isEdit} + /> + {isEditMode && !isEdit && ( + <> + + + )} +
{isEdit && (
handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/addnew.png")} /> - {typeImage != null && !previewUrl.includes(typeImage) && ( + {/* {typeImage != null && !previewUrl.includes(typeImage) && ( handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl(typeImage)} /> - )} + )} */} handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } + imageUrl={getImageUrl("uploads/beverage4.jpg")} + /> + + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/beverage1.png")} /> handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/beverage2.png")} /> handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/beverage3.png")} /> handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } + imageUrl={getImageUrl("uploads/snack5.jpg")} + /> + + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/dessert1.png")} /> handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/dessert2.jpg")} /> handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } + imageUrl={getImageUrl("uploads/food4.jpg")} + /> + + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/food1.png")} /> handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/food2.jpg")} /> handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/food3.png")} /> handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/packet1.png")} /> handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/packet2.png")} /> handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/snack1.png")} /> handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/snack2.png")} /> handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/snack3.png")} /> handleImageChange(e)} + onClick={(previewUrl, selectedImage) => + handleImageChange(previewUrl, selectedImage) + } imageUrl={getImageUrl("uploads/snack4.png")} />
@@ -355,10 +535,11 @@ const ItemLister = ({ )} )} - {items.map((item) => { + + {itemsToCreate.map((item) => { return !forCart || (forCart && item.qty > 0) ? ( <> - {onEditItem == item.itemId && ( + {isEditItem == item.itemId && ( )}
- {isEditMode && onEditItem != item.itemId && ( + {isEditMode && isEditItem != item.itemId && ( +
+ {isEditMode && ( + handleChange(item.itemId)} + checked={item.availability} + /> + )} +

+ {item.availability ? "available" : "unavailable"} +

+ +
+ )} + + handlePlusClick(item.itemId)} + onNegativeClick={() => handleNegativeClick(item.itemId)} + onRemoveClick={() => handleRemoveClick(item.itemId)} + isBeingEdit={isEditItem == item.itemId} + isAvailable={item.availability} + handleUpdateItem={(name, price, image) => + updateItemInCreate(item.itemId, name, price, image) + } + /> +
+ + ) : null; + })} + + {items.map((item) => { + return !forCart || (forCart && item.qty > 0) ? ( + <> + {isEditItem == item.itemId && ( + + )} +
+ {isEditMode && isEditItem != item.itemId && (
{isEditMode && ( handlePlusClick(item.itemId)} onNegativeClick={() => handleNegativeClick(item.itemId)} onRemoveClick={() => handleRemoveClick(item.itemId)} - isBeingEdit={onEditItem == item.itemId} + isBeingEdit={isEditItem == item.itemId} isAvailable={item.availability} handleUpdateItem={(name, price, image) => - handleUpdateItem(item.itemId, name, price, image) + onUpdateItem(item.itemId, name, price, image) } />
@@ -427,34 +660,25 @@ const ItemLister = ({
Pengaturan - - - - - - - - - +
- -
setIsEditing(false)} - > +
Kembali
diff --git a/src/components/ItemLister.module.css b/src/components/ItemLister.module.css index d0347a4..265bb0d 100644 --- a/src/components/ItemLister.module.css +++ b/src/components/ItemLister.module.css @@ -102,7 +102,7 @@ .PaymentOption { overflow-x: hidden; - background-color: white; + background-color: #e9e9e9; display: flex; flex-direction: column; justify-content: center; @@ -130,7 +130,18 @@ padding: 10px 0; margin-bottom: 17px; } - +.OptionContainer { + display: flex; + justify-content: space-between; + width: 80vw; + margin: 0 auto; + font-family: "Poppins", sans-serif; + font-weight: 600; + font-style: normal; + font-size: 0.9em; + padding: 10px 0; + margin-bottom: 17px; +} .PayButton { font-family: "Poppins", sans-serif; font-weight: 500; diff --git a/src/components/ItemType.js b/src/components/ItemType.js index aa17ce4..8197b8c 100644 --- a/src/components/ItemType.js +++ b/src/components/ItemType.js @@ -25,7 +25,7 @@ export default function ItemType({ if (selectedImage) { const reader = new FileReader(); reader.onloadend = () => { - onClick(reader.result); + onClick(reader.result, selectedImage); // setPreviewUrl(reader.result); }; reader.readAsDataURL(selectedImage); @@ -37,6 +37,8 @@ export default function ItemType({ const handleImageChange = (e) => { setSelectedImage(e.target.files[0]); + console.log(e.target.files[0]); + e.target.value = null; // This clears the input }; const handleNameChange = (e) => { @@ -83,7 +85,7 @@ export default function ItemType({
)}
- {(!rectangular && !blank) && ( + {!rectangular && !blank && ( -
- - setItemTypeName(e.target.value)} - placeholder="type name" - style={{ marginLeft: "10px" }} // Adjust spacing as needed - /> -
-
-
- onFilterChange(0)} - imageUrl={getImageUrl("uploads/1718732420960.png")} - /> - {/* onFilterChange(0)} - imageUrl={getImageUrl("uploads/1718732420960.png")} - /> - onFilterChange(0)} - imageUrl={getImageUrl("uploads/1718732420960.png")} - /> - onFilterChange(0)} - imageUrl={getImageUrl("uploads/1718732420960.png")} - /> */} -
-
- handleImageChange(e)} - imageUrl={getImageUrl("uploads/addnew.png")} - /> - handleImageChange(e)} - imageUrl={getImageUrl("uploads/beverage1.png")} - /> - handleImageChange(e)} - imageUrl={getImageUrl("uploads/beverage2.png")} - /> - handleImageChange(e)} - imageUrl={getImageUrl("uploads/beverage3.png")} - /> - handleImageChange(e)} - imageUrl={getImageUrl("uploads/dessert1.png")} - /> - handleImageChange(e)} - imageUrl={getImageUrl("uploads/dessert2.jpg")} - /> - handleImageChange(e)} - imageUrl={getImageUrl("uploads/food1.png")} - /> - handleImageChange(e)} - imageUrl={getImageUrl("uploads/food2.jpg")} - /> - - handleImageChange(e)} - imageUrl={getImageUrl("uploads/food3.png")} - /> - handleImageChange(e)} - imageUrl={getImageUrl("uploads/packet1.png")} - /> - handleImageChange(e)} - imageUrl={getImageUrl("uploads/packet2.png")} - /> - handleImageChange(e)} - imageUrl={getImageUrl("uploads/snack1.png")} - /> - handleImageChange(e)} - imageUrl={getImageUrl("uploads/snack2.png")} - /> - handleImageChange(e)} - imageUrl={getImageUrl("uploads/snack3.png")} - /> - handleImageChange(e)} - imageUrl={getImageUrl("uploads/snack4.png")} - /> -
- - - -
- -

please select the icon

+ )} {itemTypes && itemTypes.length > 0 && ( diff --git a/src/components/RouletteWheel.js b/src/components/RouletteWheel.js index e37ade8..f54f9d3 100644 --- a/src/components/RouletteWheel.js +++ b/src/components/RouletteWheel.js @@ -88,7 +88,6 @@ const RouletteWheel = ({ isForRegister, onSignIn, onSignUp }) => { }; const handleTouchEnd = (e) => { - e.preventDefault(); handleEnd(); }; diff --git a/src/config.js b/src/config.js index 7335e06..b717ef9 100644 --- a/src/config.js +++ b/src/config.js @@ -1,5 +1,5 @@ // src/config.js -const API_BASE_URL = "https://3nvnzs-5000.csb.app"; // Replace with your actual backend URL +const API_BASE_URL = "https://wxf6vz-5000.csb.app"; // Replace with your actual backend URL export default API_BASE_URL; diff --git a/src/helpers/itemHelper.js b/src/helpers/itemHelper.js index 07aab72..16f8342 100644 --- a/src/helpers/itemHelper.js +++ b/src/helpers/itemHelper.js @@ -4,10 +4,17 @@ import { getItemsByCafeId } from "./cartHelpers.js"; export async function getItemTypesWithItems(shopId) { try { const response = await fetch( - `${API_BASE_URL}/item/get-cafe-items/` + shopId + `${API_BASE_URL}/item/get-cafe-items/` + shopId, + { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${getAuthToken()}`, + }, + } ); - const data = await response.json(); + console.log(data); return { response, cafe: data.cafe, data: data.data }; // Return an object with response and data } catch (error) { console.error("Failed to fetch item types with items:", error); @@ -96,13 +103,20 @@ export async function createItem( } } -export async function updateItem(itemId, name, price, selectedImage) { +export async function updateItem( + itemId, + name, + price, + selectedImage, + isVisible +) { try { console.log(selectedImage); const formData = new FormData(); formData.append("name", name); formData.append("price", price); formData.append("image", selectedImage); + formData.append("isVisible", isVisible); const response = await fetch(`${API_BASE_URL}/item/set-item/${itemId}`, { method: "PUT", @@ -178,18 +192,36 @@ export async function createItemType(shopId, name, selectedImage) { throw error; } } - -export async function updateItemType(shopId, itemTypeId, newName) { +export async function updateItemType( + shopId, + itemTypeId, + newName, + previewUrl, + selectedImage, + isVisible +) { try { + const formData = new FormData(); + formData.append("name", newName); + console.log(selectedImage); + console.log(previewUrl); + // Check if selectedImage contains API_BASE_URL + if (selectedImage == null) { + // Remove the API_BASE_URL and any leading slashes + previewUrl = previewUrl.replace(API_BASE_URL, "").replace(/^\/+/, ""); + formData.append("sampleImage", previewUrl); + } else formData.append("image", selectedImage); + console.log(selectedImage); + formData.append("isVisible", isVisible); + const response = await fetch( - `${API_BASE_URL}/item/updateType/` + shopId + "/" + itemTypeId, + `${API_BASE_URL}/item/updateType/${shopId}/${itemTypeId}`, { method: "PUT", headers: { - "Content-Type": "application/json", Authorization: `Bearer ${getAuthToken()}`, }, - body: JSON.stringify({ newName }), + body: formData, } ); diff --git a/src/pages/CafePage.js b/src/pages/CafePage.js index fff1001..fd8db40 100644 --- a/src/pages/CafePage.js +++ b/src/pages/CafePage.js @@ -84,8 +84,8 @@ function CafePage({ textColor: parsedConfig.textColor || "#000000", isActive: parsedConfig.isWelcomePageActive === "true", }); - checkWelcomePageConfig(); } + checkWelcomePageConfig(); }, [welcomePageConfig]); useEffect(() => { if (user.cafeId != null && user.cafeId !== shopId) { @@ -217,17 +217,23 @@ function CafePage({ typeName={itemType.name} typeImage={itemType.image} itemList={itemType.itemList} + typeVisibility={itemType.visibility} isEditMode={isEditMode} beingEditedType={beingEditedType} setBeingEditedType={setBeingEditedType} raw={isEditMode || filterId == 0 ? false : true} - handleCreateItem={(name, price, selectedImage) => + handleCreateItem={( + itemTypeID, + name, + price, + selectedImage + ) => createItem( shopId, name, price, selectedImage, - itemType.itemTypeId + itemTypeID ) } handleUpdateItem={(itemId, name, price, selectedImage) =>