This commit is contained in:
insvrgent
2025-02-12 15:00:08 +07:00
parent 98ed1fe365
commit e21e0f513f
3 changed files with 358 additions and 85 deletions

View File

@@ -2,14 +2,28 @@ import React, { useState, useEffect, useRef } from "react";
import styles from "./Modal.module.css"; import styles from "./Modal.module.css";
import { getImageUrl } from "../helpers/itemHelper.js"; import { getImageUrl } from "../helpers/itemHelper.js";
const ItemConfig = ({ Item, cancelEdit }) => { const ItemConfig = ({
const [selectedImage, setSelectedImage] = useState(null); name: initialName,
const [previewUrl, setPreviewUrl] = useState(Item.image); description: initialDescription,
price: initialPrice,
promoPrice: initialPromoPrice,
imageUrl,
imageFile,
isBeingEdit,
cancelEdit,
handleCreateItem,
handleUpdateItem
}) => {
const [selectedImage, setSelectedImage] = useState(imageFile);
const [previewUrl, setPreviewUrl] = useState(imageUrl);
const [itemName, setItemName] = useState(initialName);
const [itemPrice, setItemPrice] = useState(initialPrice);
const [itemPromoPrice, setItemPromoPrice] = useState(initialPromoPrice);
const [itemDescription, setItemDescription] = useState(initialDescription);
const fileInputRef = useRef(null); const fileInputRef = useRef(null);
const textareaRef = useRef(null);
useEffect(() => { useEffect(() => {
console.log(Item.image)
// Prevent scrolling when modal is open // Prevent scrolling when modal is open
document.body.style.overflow = "hidden"; document.body.style.overflow = "hidden";
@@ -21,10 +35,9 @@ const ItemConfig = ({ Item, cancelEdit }) => {
}; };
reader.readAsDataURL(selectedImage); reader.readAsDataURL(selectedImage);
} else { } else {
setPreviewUrl(Item.image); setPreviewUrl(imageUrl);
} }
}, [selectedImage, Item]); }, [selectedImage, imageUrl]);
const handleOverlayClick = (event) => { const handleOverlayClick = (event) => {
// Prevent scrolling when modal is open // Prevent scrolling when modal is open
@@ -32,19 +45,15 @@ const ItemConfig = ({ Item, cancelEdit }) => {
cancelEdit(); cancelEdit();
}; };
// Function to handle clicks on the modal content
const handleContentClick = (event) => { const handleContentClick = (event) => {
// Prevent click event from propagating to the overlay // Prevent click event from propagating to the overlay
event.stopPropagation(); event.stopPropagation();
}; };
const handleChangeImage = () => { const handleChangeImage = () => {
fileInputRef.current.click(); fileInputRef.current.click();
}; };
const handleFileChange = (event) => { const handleFileChange = (event) => {
const file = event.target.files[0]; const file = event.target.files[0];
if (file) { if (file) {
@@ -52,13 +61,35 @@ const ItemConfig = ({ Item, cancelEdit }) => {
} }
}; };
return ( useEffect(() => {
<div onClick={handleOverlayClick} style={{ position: 'fixed', width: '100vw', height: '100vh', left: 0, bottom: 0, display: 'flex', flexDirection: 'column-reverse', zIndex: 200, backgroundColor: '#00000061' }}> const textarea = textareaRef.current;
<div onClick={handleContentClick} style={{ display: 'flex', flexDirection: 'column', padding: '15px', height: '40%', backgroundColor: 'white', borderRadius: '20px 20px 0 0' }}>
<div style={{ display: 'flex' }}>
<div style={{ width: '26vw', height: '26vw' }}>
<img style={{ width: '100%', height: '100%', borderRadius: '10px', objectFit: 'cover' }} src={selectedImage ? previewUrl : getImageUrl(previewUrl)}></img>
if (textarea) {
const handleResize = () => {
textarea.style.height = "auto";
textarea.style.height = `${textarea.scrollHeight}px`;
};
handleResize(); // Initial resize
textarea.addEventListener("input", handleResize);
return () => textarea.removeEventListener("input", handleResize);
}
}, [textareaRef.current]);
const handleCreate = () => {
handleCreateItem(itemName, itemPrice, selectedImage, previewUrl);
};
const handleUpdate = () => {
handleUpdateItem(itemName, itemPrice, selectedImage, previewUrl);
};
return (
<div onClick={handleOverlayClick} style={{ position: 'fixed', width: '100vw', height: '100vh', left: 0, bottom: 0, display: 'flex', flexDirection: 'column-reverse', zIndex: 301, backgroundColor: '#00000061' }}>
<div onClick={handleContentClick} style={{ display: 'flex', flexDirection: 'column', padding: '15px', backgroundColor: 'white', borderRadius: '20px 20px 0 0', overflowY: 'auto' }}>
<div style={{ display: 'flex' }}>
<div style={{ width: '26vw', height: '26vw', marginRight: '10px' }}>
<img style={{ width: '100%', height: '100%', borderRadius: '10px', objectFit: 'cover' }} src={previewUrl} />
<input <input
type="file" type="file"
ref={fileInputRef} ref={fileInputRef}
@@ -69,27 +100,106 @@ const ItemConfig = ({ Item, cancelEdit }) => {
/> />
</div> </div>
<div style={{ width: '72%', height: '26vw', display: 'flex', justifyContent: 'center', alignItems: 'center' }}> <div style={{ width: '72%', height: '26vw', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<div onClick={() => handleChangeImage()} style={{ width: '140px', height: '40px', alignContent: 'center', textAlign: 'center', borderRadius: '10px', border: '1px solid #60d37e', color: '#60d37e', backgroundColor: 'white' }}> <div onClick={() => handleChangeImage()} style={{ width: '140px', height: '40px', alignContent: 'center', textAlign: 'center', borderRadius: '10px', border: '1px solid #60d37e', color: '#60d37e', backgroundColor: 'white', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
Ganti gambar {isBeingEdit ? 'Ganti gambar' : 'Tambah gambar'}
</div> </div>
</div> </div>
</div> </div>
<div style={{ display: 'flex', flexDirection: 'column', color: 'black' }}>
<p>Nama item</p> <div style={{ display: 'flex', flexDirection: 'column', color: 'black', marginTop: '10px' }}>
<input value={Item.name}></input> <p style={{ marginBottom: '5px', fontWeight: '500' }}>Nama item</p>
<input
value={itemName}
style={{
padding: '10px',
borderRadius: '8px',
border: '1px solid #ccc',
fontSize: '14px',
width: '100%',
marginBottom: '15px',
outline: 'none',
transition: 'all 0.3s ease',
boxSizing: 'border-box', // Make sure the padding doesn't cause overflow
}}
onChange={(e)=>setItemName(e.target.value)}
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
onBlur={(e) => e.target.style.borderColor = '#ccc'}
/>
</div> </div>
<div style={{ display: 'flex', color: 'black', justifyContent: 'space-between' }}> <div style={{ display: 'flex', color: 'black', justifyContent: 'space-between' }}>
<div> <div style={{ width: '48%' }}>
<p>Harga</p> <p style={{ marginBottom: '5px', fontWeight: '500', marginTop: 0 }}>Harga</p>
<input value={Item.price}></input> <input
</div><div> value={itemPrice}
<p>Harga promo</p> style={{
<input placeholder="Opsional"></input> padding: '10px',
borderRadius: '8px',
border: '1px solid #ccc',
fontSize: '14px',
width: '100%',
marginBottom: '15px',
outline: 'none',
transition: 'all 0.3s ease',
boxSizing: 'border-box',
}}
onChange={(e)=>setItemPrice(e.target.value)}
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
onBlur={(e) => e.target.style.borderColor = '#ccc'}
/>
</div>
<div style={{ width: '48%' }}>
<p style={{ marginBottom: '5px', fontWeight: '500', marginTop: 0 }}>Harga promo</p>
<input
value={itemPromoPrice}
placeholder="Opsional"
style={{
padding: '10px',
borderRadius: '8px',
border: '1px solid #ccc',
fontSize: '14px',
width: '100%',
marginBottom: '15px',
outline: 'none',
transition: 'all 0.3s ease',
boxSizing: 'border-box',
}}
onChange={(e)=>setItemPromoPrice(e.target.value)}
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
onBlur={(e) => e.target.style.borderColor = '#ccc'}
/>
</div> </div>
</div> </div>
<div style={{ display: 'flex', flexDirection: 'column', color: 'black' }}> <div style={{ display: 'flex', flexDirection: 'column', color: 'black' }}>
<p>Deskripsi</p> <p style={{ marginBottom: '5px', fontWeight: '500', marginTop: 0 }}>Deskripsi</p>
<input value={Item.description}></input>
<textarea
ref={textareaRef}
style={{
padding: '10px',
borderRadius: '8px',
border: '1px solid #ccc',
fontSize: '14px',
width: '100%',
marginBottom: '15px',
outline: 'none',
transition: 'all 0.3s ease',
boxSizing: 'border-box',
resize: 'none', // Prevent manual resize that could cause overflow
}}
placeholder="Tambah deskripsi..."
value={initialDescription}
onChange={(e)=>setItemDescription(e.target.value)}
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
onBlur={(e) => e.target.style.borderColor = '#ccc'}
/>
</div>
<div style={{ width: '100%', height: '35px', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<div onClick={() => {isBeingEdit ? handleUpdate() : handleCreate()} } style={{ width: '100%', height: '40px', alignContent: 'center', textAlign: 'center', borderRadius: '10px', border: '1px solid #60d37e', color: '#60d37e', backgroundColor: 'white', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
{isBeingEdit? 'Simpan' : 'Buat Item'}
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,101 @@
/* Modal.module.css */
.overlay {
position: fixed;
width: 100vw;
height: 100vh;
left: 0;
bottom: 0;
display: flex;
flex-direction: column-reverse;
z-index: 200;
background-color: rgba(0, 0, 0, 0.38); /* #00000061 */
}
.content {
display: flex;
flex-direction: column;
padding: 15px;
height: 40%;
background-color: white;
border-radius: 20px 20px 0 0;
overflow-y: auto;
}
.imageContainer {
display: flex;
}
.image {
width: 26vw;
height: 26vw;
margin-right: 10px;
}
.imagePreview {
width: 100%;
height: 100%;
border-radius: 10px;
object-fit: cover;
}
.changeImageButton {
width: 140px;
height: 40px;
align-content: center;
text-align: center;
border-radius: 10px;
border: 1px solid #60d37e;
color: #60d37e;
background-color: white;
display: flex;
justify-content: center;
align-items: center;
}
.inputField {
padding: 10px;
border-radius: 8px;
border: 1px solid #ccc;
font-size: 14px;
width: 100%;
margin-bottom: 15px;
outline: none;
transition: all 0.3s ease;
box-sizing: border-box;
}
.inputField:focus {
border-color: #60d37e;
}
.inputField:blur {
border-color: #ccc;
}
.textarea {
padding: 10px;
border-radius: 8px;
border: 1px solid #ccc;
font-size: 14px;
width: 100%;
margin-bottom: 15px;
outline: none;
transition: all 0.3s ease;
box-sizing: border-box;
resize: none; /* Prevent manual resize that could cause overflow */
}
.saveButton {
width: 100%;
height: 40px;
align-content: center;
text-align: center;
border-radius: 10px;
border: 1px solid #60d37e;
color: #60d37e;
background-color: white;
display: flex;
justify-content: center;
align-items: center;
}

View File

@@ -70,6 +70,9 @@ const ItemLister = ({
const [isFirstStep, setIsFirstStep] = useState(true); const [isFirstStep, setIsFirstStep] = useState(true);
const [randomKey, setRandomKey] = useState(0);
const handlePlusClick = (itemId) => { const handlePlusClick = (itemId) => {
const updatedItems = items.map((item) => { const updatedItems = items.map((item) => {
if (item.itemId === itemId) { if (item.itemId === itemId) {
@@ -220,7 +223,41 @@ const ItemLister = ({
const onUpdateItem = (itemId, name, price, image) => { const onUpdateItem = (itemId, name, price, image) => {
if (isEdit) if (isEdit)
setItemsToUpdate((prev) => [...prev, { itemId, name, price, image }]); setItemsToUpdate((prev) => [...prev, { itemId, name, price, image }]);
else handleUpdateItem(itemId, name, price, image); else {
console.log(itemId, name, price, image)
handleUpdateItem(itemId, name, price, image);
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];
console.log(updatedItems)
// Toggle the availability locally
if(image){
const reader = new FileReader();
reader.onloadend = () => {
updatedItems[itemIndex].image = reader.result;
console.log(reader.result)
};
reader.readAsDataURL(image);
}
const newAvailability = !item.availability;
updatedItems[itemIndex] = {
name,
price,
availability: item.availability
};
console.log(updatedItems)
// Update the state with the local change
setItems(updatedItems);
setRandomKey(randomKey + 1);
}
console.log(itemsToUpdate); console.log(itemsToUpdate);
}; };
@@ -779,13 +816,10 @@ const ItemLister = ({
)} )}
{isAddingNewItem && ( {isAddingNewItem && (
<> <>
<button <ItemConfig
className={styles["add-item-button"]} cancelEdit={() => toggleAddNewItem()}
onClick={toggleAddNewItem} handleCreateItem={onCreateItem}
style={{ display: "inline-block" }} />
>
batal
</button>
<Item blank={true} handleCreateItem={onCreateItem} /> <Item blank={true} handleCreateItem={onCreateItem} />
</> </>
)} )}
@@ -796,17 +830,24 @@ const ItemLister = ({
return !forCart || (forCart && item.qty > 0) ? ( return !forCart || (forCart && item.qty > 0) ? (
<> <>
{isEditItem == item.itemId && ( {isEditItem == item.itemId && (
<button <ItemConfig
className={styles["add-item-button"]} isBeingEdit={true}
onClick={() => editItem(0)} name={item.name}
style={{ display: "inline-block" }} price={item.price}
> promoPrice={item.promoPrice}
batal description={item.description}
</button> imageUrl={item.image}
imageFile={item.selectedImage}
cancelEdit={() => editItem(0)}
handleUpdateItem={(name, price, image) => { updateItemInCreate(item.itemId, name, price, image); setRandomKey(randomKey + 1); console.log(image) }
}
/>
)} )}
<div className={styles["itemWrapper"]}> <div className={styles["itemWrapper"]}>
{isEditMode && isEditItem != item.itemId && ( {isEditMode && isEditItem != item.itemId && (
<div className={styles["editModeLayout"]}> <div className={styles["editModeLayout"]}>
<div style={{ display: 'flex', alignItems: 'center', height: '40px', marginLeft: '7.5vw' }}>
{isEditMode && ( {isEditMode && (
<Switch <Switch
onChange={() => handleChange(item.itemId)} onChange={() => handleChange(item.itemId)}
@@ -814,8 +855,11 @@ const ItemLister = ({
/> />
)} )}
<h3> <h3>
&nbsp;{item.availability ? "Tersedia" : "Tidak tersedia"} &nbsp; &nbsp;{item.availability ? "Tersedia" : "Tidak tersedia"}
</h3> </h3>
</div>
<div onClick={() => editItem(item.itemId)} style={{ display: 'flex', alignItems: 'center', height: '40px', marginRight: '7.5vw' }}>
<div <div
style={{ style={{
width: '32px', width: '32px',
@@ -825,7 +869,6 @@ const ItemLister = ({
alignItems: 'center', // Center vertically alignItems: 'center', // Center vertically
cursor: 'pointer' cursor: 'pointer'
}} }}
onClick={() => editItem(item.itemId)}
> >
<svg <svg
fill="white" fill="white"
@@ -845,6 +888,8 @@ const ItemLister = ({
</g> </g>
</svg> </svg>
</div> </div>
<h3>Edit item</h3>
</div>
</div> </div>
)} )}
@@ -873,7 +918,8 @@ const ItemLister = ({
{items.map((item) => { {items.map((item) => {
return !forCart || (forCart && item.qty > 0) ? ( return !forCart || (forCart && item.qty > 0) ? (
<> <div
key={item.itemId}>
{isEditItem == item.itemId && ( {isEditItem == item.itemId && (
// <button // <button
// className={styles["add-item-button"]} // className={styles["add-item-button"]}
@@ -882,7 +928,23 @@ const ItemLister = ({
// > // >
// batal // batal
// </button> // </button>
<ItemConfig Item={item} cancelEdit={()=>editItem(0)}/> <ItemConfig
isBeingEdit={true}
name={item.name}
price={item.price}
promoPrice={item.promoPrice}
description={item.description}
imageUrl={
itemTypeId ? getImageUrl(item.image) : item.image
}
cancelEdit={() => editItem(0)}
handleCreateItem={onCreateItem}
handleUpdateItem={(name, price, image) => {
onUpdateItem(item.itemId, name, price, image);
setRandomKey(randomKey + 1); console.log(image);
}
}
/>
)} )}
<div className={styles["itemWrapper"]}> <div className={styles["itemWrapper"]}>
{isEditMode && isEditItem != item.itemId && ( {isEditMode && isEditItem != item.itemId && (
@@ -953,7 +1015,7 @@ const ItemLister = ({
} }
/> />
</div> </div>
</> </div>
) : null; ) : null;
})} })}