This commit is contained in:
frontend perkafean
2024-10-07 07:02:36 +00:00
parent eec9caefd0
commit ae9a34a065
11 changed files with 222 additions and 116 deletions

View File

@@ -70,8 +70,11 @@
z-index: 201; /* Behind the button */
font-size: 3vw;
text-align: center;
transition: all 0.5s ease-in-out;
}
.bussinessName h2 {
color: inherit; /* Ensures that it inherits the color from the parent */
}
.bussinessQR {
position: absolute;
height: 25vh;

View File

@@ -1,6 +1,5 @@
import React, { useState, useRef, useEffect } from "react";
import styles from "./Item.module.css";
const Item = ({
blank,
forCart,
@@ -13,8 +12,10 @@ const Item = ({
onPlusClick,
onNegativeClick,
handleCreateItem,
handleUpdateItem,
onRemoveClick,
isAvailable,
isBeingEdit,
}) => {
const [selectedImage, setSelectedImage] = useState(null);
const [previewUrl, setPreviewUrl] = useState(imageUrl);
@@ -24,6 +25,8 @@ const Item = ({
const fileInputRef = useRef(null);
useEffect(() => {
console.log(imageUrl);
console.log(selectedImage);
if (selectedImage) {
const reader = new FileReader();
reader.onloadend = () => {
@@ -48,7 +51,10 @@ const Item = ({
};
const handleCreate = () => {
handleCreateItem(itemName, itemPrice, itemQty, selectedImage);
handleCreateItem(itemName, itemPrice, selectedImage, previewUrl);
};
const handleUpdate = () => {
handleUpdateItem(itemName, itemPrice, selectedImage, previewUrl);
};
const handleRemoveClick = () => {
@@ -86,7 +92,11 @@ const Item = ({
{!forInvoice && (
<div className={styles.imageContainer}>
<img
src={previewUrl}
src={
blank || previewUrl || isBeingEdit
? previewUrl
: "https://png.pngtree.com/png-vector/20221125/ourmid/pngtree-no-image-available-icon-flatvector-illustration-pic-design-profile-vector-png-image_40966566.jpg"
}
onError={({ currentTarget }) => {
currentTarget.onerror = null; // prevents looping
currentTarget.src =
@@ -98,9 +108,12 @@ const Item = ({
}}
className={styles.itemImage}
/>
{blank && (
{(isBeingEdit || blank) && (
<div className={styles.overlay} onClick={handleImageClick}>
<span>Click To Add Image</span>
<span>
{previewUrl ? "Click To Change Image" : "Click To Add Image"}
</span>
</div>
)}
<input
@@ -117,13 +130,13 @@ const Item = ({
<input
className={`${
forInvoice ? styles.itemInvoiceName : styles.itemName
} ${blank ? styles.blank : styles.notblank} ${
} ${isBeingEdit || blank ? styles.blank : styles.notblank} ${
!isAvailable ? styles.disabled : ""
}`}
value={itemName}
placeholder="name"
onChange={handleNameChange}
disabled={!blank}
disabled={!blank && !isBeingEdit}
/>
{forInvoice && (
@@ -135,17 +148,17 @@ const Item = ({
{!forInvoice && (
<input
className={`${styles.itemPrice} ${
blank ? styles.blank : styles.notblank
isBeingEdit || blank ? styles.blank : styles.notblank
} ${!isAvailable ? styles.disabled : ""}`}
value={itemPrice}
placeholder="price"
onChange={handlePriceChange}
disabled={!blank}
disabled={!blank && !isBeingEdit}
/>
)}
{!forInvoice &&
(itemQty != 0 ? (
(!isBeingEdit && itemQty != 0 ? (
<div className={styles.itemQty}>
<svg
className={styles.plusNegative}
@@ -162,14 +175,14 @@ const Item = ({
fillRule="nonzero"
/>
</svg>
{!blank ? (
{!blank && !isBeingEdit ? (
<p className={styles.itemQtyValue}>{itemQty}</p>
) : (
<input
className={styles.itemQtyInput}
value={itemQty}
onChange={handleQtyChange}
disabled={!blank}
disabled={!blank && !isBeingEdit}
/>
)}
<svg
@@ -188,7 +201,7 @@ const Item = ({
/>
</svg>
</div>
) : !blank ? (
) : !blank && !isBeingEdit ? (
<div className={styles.itemQty}>
<button
className={styles.addButton}
@@ -207,9 +220,9 @@ const Item = ({
backgroundColor: "#4da94d",
width: "150px",
}}
onClick={handleCreate}
onClick={isBeingEdit ? handleUpdate : handleCreate}
>
+
{isBeingEdit ? "save" : "+"}
</button>
</div>
))}

View File

@@ -9,7 +9,6 @@ import {
} from "../helpers/cartHelpers.js";
import {
getImageUrl,
createItem,
updateItemAvalilability,
updateItemType,
deleteItemType,
@@ -27,6 +26,8 @@ const ItemLister = ({
forInvoice,
isEditMode,
raw,
handleCreateItem,
handleUpdateItem,
}) => {
const [items, setItems] = useState(
itemList.map((item) => ({
@@ -45,6 +46,7 @@ const ItemLister = ({
}, [itemList]);
const [isEdit, setIsEditing] = useState(false);
const [onEditItem, setOnEditItem] = useState(0);
const [isAddingNewItem, setIsAddingNewItem] = useState(false);
const [editedTypeName, setEditedTypeName] = useState(typeName);
const typeNameInputRef = useRef(null);
@@ -122,6 +124,11 @@ const ItemLister = ({
const toggleAddNewItem = () => {
setIsAddingNewItem((prev) => !prev);
setOnEditItem(0);
};
const editItem = (itemId) => {
setIsAddingNewItem(false);
setOnEditItem(itemId);
};
const handleChange = async (itemId) => {
// Find the item in the current items array
@@ -165,6 +172,10 @@ const ItemLister = ({
setItems(updatedItems);
}
};
const onCreateItem = (itemName, itemPrice, selectedImage, previewUrl) => {
handleCreateItem(itemName, itemPrice, selectedImage, previewUrl);
setIsAddingNewItem(false);
};
return (
<>
@@ -238,52 +249,62 @@ const ItemLister = ({
>
</button>
<Item
blank={true}
handleCreateItem={(name, price, qty, selectedImage) =>
createItem(
shopId,
name,
price,
qty,
selectedImage,
itemTypeId
)
}
/>
<Item blank={true} handleCreateItem={onCreateItem} />
</>
)}
</>
)}
{items.map((item) => {
return !forCart || (forCart && item.qty > 0) ? (
<div className={styles["itemWrapper"]}>
{isEditMode && (
<div className={styles["editModeLayout"]}>
{isEditMode && (
<Switch
onChange={() => handleChange(item.itemId)}
checked={item.availability}
/>
)}
<h3>{item.availability ? "available" : "unavailable"}</h3>
</div>
<>
{onEditItem == item.itemId && (
<button
className={styles["add-item-button"]}
onClick={() => editItem(0)}
style={{ display: "inline-block" }}
>
</button>
)}
<Item
key={item.itemId}
forCart={forCart}
forInvoice={forInvoice}
name={item.name}
price={item.price}
qty={item.qty}
imageUrl={getImageUrl(item.image)}
onPlusClick={() => handlePlusClick(item.itemId)}
onNegativeClick={() => handleNegativeClick(item.itemId)}
onRemoveClick={() => handleRemoveClick(item.itemId)}
isEditMode={isEditMode}
isAvailable={item.availability}
/>
</div>
<div className={styles["itemWrapper"]}>
{isEditMode && onEditItem != item.itemId && (
<div className={styles["editModeLayout"]}>
{isEditMode && (
<Switch
onChange={() => handleChange(item.itemId)}
checked={item.availability}
/>
)}
<h3>
{item.availability ? "available" : "unavailable"}
</h3>
<button onClick={() => editItem(item.itemId)}>
edit
</button>
</div>
)}
<Item
key={item.itemId}
forCart={forCart}
forInvoice={forInvoice}
name={item.name}
price={item.price}
qty={item.qty}
imageUrl={
itemTypeId ? getImageUrl(item.image) : item.image
}
onPlusClick={() => handlePlusClick(item.itemId)}
onNegativeClick={() => handleNegativeClick(item.itemId)}
onRemoveClick={() => handleRemoveClick(item.itemId)}
isBeingEdit={onEditItem == item.itemId}
isAvailable={item.availability}
handleUpdateItem={(name, price, image) =>
handleUpdateItem(item.itemId, name, price, image)
}
/>
</div>
</>
) : null;
})}

View File

@@ -4,6 +4,7 @@
width: 100%;
padding: 10px; /* Adjust padding as needed */
box-sizing: border-box; /* Ensure padding doesn't affect width */
white-space: break-spaces;
}
.item-lister:last-child {

View File

@@ -1,6 +1,5 @@
import React, { useRef, useEffect, useState } from "react";
import styles from "./ItemType.module.css";
import { getImageUrl } from "../helpers/itemHelper";
export default function ItemType({
onClick,
@@ -26,12 +25,13 @@ export default function ItemType({
if (selectedImage) {
const reader = new FileReader();
reader.onloadend = () => {
setPreviewUrl(reader.result);
onClick(reader.result);
// setPreviewUrl(reader.result);
};
reader.readAsDataURL(selectedImage);
} else {
setPreviewUrl(getImageUrl(imageUrl));
onClick(getImageUrl(imageUrl));
setPreviewUrl(imageUrl);
// onClick(getImageUrl(imageUrl));
}
}, [selectedImage, imageUrl]);
@@ -66,7 +66,9 @@ export default function ItemType({
style={{ zIndex: blank ? 301 : "inherit" }}
>
<div
onClick={rectangular ?( blank? null:() => onClick(imageUrl)) : onClick}
onClick={
rectangular ? (blank ? null : () => onClick(imageUrl)) : onClick
}
className={styles["item-type-rect"]}
style={{
top: selected ? "-10px" : "initial",
@@ -86,24 +88,15 @@ export default function ItemType({
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
ref={inputRef}
className={`${styles["item-type-name"]} ${
blank ? styles.border : styles.noborder
}`}
className={`${styles["item-type-name"]} ${styles.noborder}`}
value={name}
onChange={handleNameChange}
disabled={!blank}
disabled={true}
style={{
top: selected ? "-5px" : "initial",
borderBottom: selected ? "1px solid #000" : "none",

View File

@@ -58,7 +58,7 @@
.item-type-image {
width: 100%;
height: 100%;
object-fit: contain;
object-fit: cover;
border-radius: 15px;
}

View File

@@ -29,11 +29,19 @@
flex-direction: column;
}
.inline-container {
display: grid;
grid-template-columns: repeat(4, 1fr); /* Always 4 columns */
gap: 10px; /* Spacing between grid items */
padding: 10px; /* Padding inside grid */
overflow-y: auto; /* Allow scrolling if items overflow */
}
.grid-container {
display: grid;
grid-template-columns: repeat(4, 1fr); /* Always 4 columns */
gap: 10px; /* Spacing between grid items */
padding: 10px; /* Padding inside grid */
max-height: calc(3 * (25vw - 20px) + 20px); /* 3 items + gaps */
overflow-y: auto; /* Allow scrolling if items overflow */
}

View File

@@ -4,6 +4,7 @@ import "./ItemTypeLister.css";
import ItemType from "./ItemType";
import { createItemType } from "../helpers/itemHelper.js";
import { getImageUrl } from "../helpers/itemHelper";
import ItemLister from "./ItemLister";
const ItemTypeLister = ({
shopId,
@@ -16,6 +17,21 @@ const ItemTypeLister = ({
}) => {
const [isAddingNewItem, setIsAddingNewItem] = useState(false);
const newItemDivRef = useRef(null);
const [items, setItems] = useState([]);
const handleCreateItem = (name, price, selectedImage, previewUrl) => {
console.log(previewUrl);
const newItem = {
itemId: items.length + 1,
name,
price,
selectedImage,
image: previewUrl,
availability: true,
};
// Update the items state with the new item
setItems((prevItems) => [...prevItems, newItem]);
};
// Effect to handle changes to isAddingNewItem
useEffect(() => {
@@ -72,7 +88,11 @@ const ItemTypeLister = ({
className="item-type-lister"
style={{ overflowX: isAddingNewItem ? "hidden" : "" }}
>
<div ref={newItemDivRef} className="item-type-list" style={{display: isAddingNewItem?'block':'inline-flex'}}>
<div
ref={newItemDivRef}
className="item-type-list"
style={{ display: isAddingNewItem ? "block" : "inline-flex" }}
>
{isEditMode &&
!isAddingNewItem &&
user &&
@@ -81,7 +101,7 @@ const ItemTypeLister = ({
<ItemType
onClick={toggleAddNewItem}
name={"create"}
imageUrl={"uploads/addnew.png"}
imageUrl={getImageUrl("uploads/addnew.png")}
/>
)}
{user &&
@@ -92,110 +112,122 @@ const ItemTypeLister = ({
<ItemType
blank={true}
imageUrl={previewUrl}
name={"blank"}
name={" "}
onCreate={handleCreate}
/>
<div className="rect-creator">
<div
className="grid-container"
className="inline-container"
style={{ visibility: "hidden" }}
>
<ItemType
onClick={() => onFilterChange(0)}
imageUrl={"uploads/1718732420960.png"}
imageUrl={getImageUrl("uploads/1718732420960.png")}
/>
<input></input>
{/* <ItemType
onClick={() => onFilterChange(0)}
imageUrl={getImageUrl("uploads/1718732420960.png")}
/>
<ItemType
onClick={() => onFilterChange(0)}
imageUrl={"uploads/1718732420960.png"}
imageUrl={getImageUrl("uploads/1718732420960.png")}
/>
<ItemType
onClick={() => onFilterChange(0)}
imageUrl={"uploads/1718732420960.png"}
/>
<ItemType
onClick={() => onFilterChange(0)}
imageUrl={"uploads/1718732420960.png"}
/>
imageUrl={getImageUrl("uploads/1718732420960.png")}
/> */}
</div>
<div className="grid-container" style={{ paddingTop: "15px" }}>
<ItemType
rectangular={true}
blank={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/beverage1.png"}
imageUrl={getImageUrl("uploads/addnew.png")}
/>
<ItemType
rectangular={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/beverage2.png"}
imageUrl={getImageUrl("uploads/beverage1.png")}
/>
<ItemType
rectangular={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/beverage3.png"}
imageUrl={getImageUrl("uploads/beverage2.png")}
/>
<ItemType
rectangular={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/dessert1.png"}
imageUrl={getImageUrl("uploads/beverage3.png")}
/>
<ItemType
rectangular={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/dessert2.jpg"}
imageUrl={getImageUrl("uploads/dessert1.png")}
/>
<ItemType
rectangular={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/food1.png"}
imageUrl={getImageUrl("uploads/dessert2.jpg")}
/>
<ItemType
rectangular={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/food2.jpg"}
imageUrl={getImageUrl("uploads/food1.png")}
/>
<ItemType
rectangular={true}
onClick={(e) => handleImageChange(e)}
imageUrl={getImageUrl("uploads/food2.jpg")}
/>
<ItemType
rectangular={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/food3.png"}
imageUrl={getImageUrl("uploads/food3.png")}
/>
<ItemType
rectangular={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/packet1.png"}
imageUrl={getImageUrl("uploads/packet1.png")}
/>
<ItemType
rectangular={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/packet2.png"}
imageUrl={getImageUrl("uploads/packet2.png")}
/>
<ItemType
rectangular={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/snack1.png"}
imageUrl={getImageUrl("uploads/snack1.png")}
/>
<ItemType
rectangular={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/snack2.png"}
imageUrl={getImageUrl("uploads/snack2.png")}
/>
<ItemType
rectangular={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/snack3.png"}
imageUrl={getImageUrl("uploads/snack3.png")}
/>
<ItemType
rectangular={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/snack4.png"}
/>
<ItemType
rectangular={true}
blank={true}
onClick={(e) => handleImageChange(e)}
imageUrl={"uploads/addnew.png"}
imageUrl={getImageUrl("uploads/snack4.png")}
/>
</div>
<ItemLister
shopId={shopId}
shopOwnerId={shopOwnerId}
user={user}
typeName={"add new"}
itemList={items}
isEditMode={true}
raw={true}
handleCreateItem={handleCreateItem}
/>
<button onClick={toggleAddNewItem} className="add-button">
back
</button>
@@ -208,7 +240,7 @@ const ItemTypeLister = ({
<ItemType
name={"All"}
onClick={() => onFilterChange(0)}
imageUrl={"uploads/1718732420960.png"}
imageUrl={getImageUrl("uploads/1718732420960.png")}
/>
)}
{itemTypes &&
@@ -219,7 +251,7 @@ const ItemTypeLister = ({
<ItemType
key={itemType.itemTypeId}
name={itemType.name}
imageUrl={itemType.image}
imageUrl={getImageUrl(itemType.image)}
onClick={() => onFilterChange(itemType.itemTypeId)}
selected={filterId === itemType.itemTypeId}
/>

View File

@@ -1,5 +1,5 @@
// src/config.js
const API_BASE_URL = "https://fmcf2m-5000.csb.app"; // Replace with your actual backend URL
const API_BASE_URL = "https://3nvnzs-5000.csb.app"; // Replace with your actual backend URL
export default API_BASE_URL;

View File

@@ -64,7 +64,6 @@ export async function createItem(
shopId,
name,
price,
qty,
selectedImage,
itemTypeId
) {
@@ -73,7 +72,6 @@ export async function createItem(
const formData = new FormData();
formData.append("name", name);
formData.append("price", price);
formData.append("stock", qty);
formData.append("image", selectedImage);
formData.append("itemTypeId", itemTypeId);
@@ -98,6 +96,35 @@ export async function createItem(
}
}
export async function updateItem(itemId, name, price, selectedImage) {
try {
console.log(selectedImage);
const formData = new FormData();
formData.append("name", name);
formData.append("price", price);
formData.append("image", selectedImage);
const response = await fetch(`${API_BASE_URL}/item/set-item/${itemId}`, {
method: "PUT",
headers: {
Authorization: `Bearer ${getAuthToken()}`,
},
body: formData,
});
if (!response.ok) {
const errorMessage = await response.text();
throw new Error(`Error: ${errorMessage}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error("Failed to create item type:", error);
throw error;
}
}
export async function updateItemAvalilability(itemId, isAvailable) {
try {
const response = await fetch(

View File

@@ -10,7 +10,7 @@ import {
import "../App.css";
import { getImageUrl } from "../helpers/itemHelper.js";
import { getImageUrl, createItem, updateItem } from "../helpers/itemHelper.js";
import SearchInput from "../components/SearchInput";
import ItemTypeLister from "../components/ItemTypeLister";
import { MusicPlayer } from "../components/MusicPlayer";
@@ -20,11 +20,7 @@ import Header from "../components/Header";
import { ThreeDots } from "react-loader-spinner";
import { getItemTypesWithItems } from "../helpers/itemHelper.js";
import {
getLocalStorage,
updateLocalStorage,
} from "../helpers/localStorageHelpers";
import { updateLocalStorage } from "../helpers/localStorageHelpers";
import { unsubscribeUser } from "../helpers/subscribeHelpers.js";
import WelcomePage from "./WelcomePage.js";
@@ -218,6 +214,18 @@ function CafePage({
itemList={itemType.itemList}
isEditMode={isEditMode}
raw={isEditMode || filterId == 0 ? false : true}
handleCreateItem={(name, price, selectedImage) =>
createItem(
shopId,
name,
price,
selectedImage,
itemType.itemTypeId
)
}
handleUpdateItem={(itemId, name, price, selectedImage) =>
updateItem(itemId, name, price, selectedImage)
}
/>
))}
</body>