This commit is contained in:
zadit
2025-01-12 18:16:16 +07:00
parent da411bd3d2
commit 2864a00814
4 changed files with 212 additions and 101 deletions

View File

@@ -1,21 +1,18 @@
import React, { useState } from "react"; import React, { useState } from "react";
import styles from "./Carousel.module.css"; // Import CSS module import styles from "./Carousel.module.css"; // Import CSS module
const Carousel = ({ items, onSelect }) => { const Carousel = ({ selectedIndex, items, onSelect }) => {
const [selectedIndex, setSelectedIndex] = useState(0); // Start at the first item
const moveToNext = () => { const moveToNext = () => {
console.log('aa') console.log('aa')
if (selectedIndex < items.length - 1) { if (selectedIndex < items.length - 1) {
console.log('bb') console.log('bb')
setSelectedIndex(selectedIndex + 1);
onSelect(selectedIndex + 1); // Send the next index to the parent onSelect(selectedIndex + 1); // Send the next index to the parent
} }
}; };
const moveToPrev = () => { const moveToPrev = () => {
if (selectedIndex > -1) { if (selectedIndex > -1) {
setSelectedIndex(selectedIndex - 1);
onSelect(selectedIndex - 1); // Send the previous index to the parent onSelect(selectedIndex - 1); // Send the previous index to the parent
} }
}; };
@@ -27,9 +24,9 @@ const Carousel = ({ items, onSelect }) => {
<div <div
className={`${styles.carouselItem} ${styles.prev}`} className={`${styles.carouselItem} ${styles.prev}`}
onClick={moveToPrev} onClick={moveToPrev}
style={{ visibility: selectedIndex === -1 ? "hidden" : "visible" }} style={{ visibility: selectedIndex === -1 && items.length > 0 ? "hidden" : "visible" , backgroundColor: items.length < 1 ? '#919191':'#007bff'}}
> >
{selectedIndex === -1 ? "+" : items[selectedIndex - 1]?.name || "+"} {selectedIndex === -1 ? (items.length > 0 ? "+" : "") : items[selectedIndex - 1]?.name || "+"}
</div> </div>
{/* Current Item */} {/* Current Item */}
@@ -42,7 +39,7 @@ const Carousel = ({ items, onSelect }) => {
className={`${styles.carouselItem} ${styles.next}`} className={`${styles.carouselItem} ${styles.next}`}
onClick={moveToNext} onClick={moveToNext}
style={{ style={{
visibility: selectedIndex === items.length -1 ? "hidden" : "visible", visibility: selectedIndex === items.length -1 && items.length > 0 ? "hidden" : "visible", backgroundColor: items.length < 1 ? '#919191':'#007bff'
}} }}
> >
{selectedIndex < items.length - 1 && items[selectedIndex + 1]?.name} {selectedIndex < items.length - 1 && items[selectedIndex + 1]?.name}

View File

@@ -44,7 +44,6 @@
position: absolute; position: absolute;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
background-color: #007bff;
color: white; color: white;
border: none; border: none;
padding: 10px 20px; padding: 10px 20px;

View File

@@ -354,9 +354,9 @@ const Header = ({
onChange={() => setIsEditMode(!isEditMode)} onChange={() => setIsEditMode(!isEditMode)}
/> />
</Child> </Child>
<Child onClick={() => setModal("reports")}>Laporan</Child> <Child onClick={() => setModal("reports")}>Lihat laporan</Child>
<Child onClick={() => setModal("add_material")}> <Child onClick={() => setModal("add_material")}>
Stok Kelola bahan baku
</Child> </Child>
<Child hasChildren> <Child hasChildren>

View File

@@ -30,14 +30,19 @@ const SetPaymentQr = ({ cafeId }) => {
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState(null); const [error, setError] = useState(null);
const [showForm, setShowForm] = useState(false); const [showForm, setShowForm] = useState(false);
const [selectedMaterialId, setSelectedMaterialId] = useState(null); const [selectedMaterialIndex, setSelectedMaterialIndex] = useState(-1);
const [latestMutation, setLatestMutation] = useState([]); const [latestMutation, setLatestMutation] = useState([]);
const [currentQuantity, setCurrentQuantity] = useState(-1); const [currentQuantity, setCurrentQuantity] = useState(-1);
const [currentPrice, setCurrentPrice] = useState(0); const [currentPrice, setCurrentPrice] = useState(0);
const [quantityChange, setQuantityChange] = useState(0); const [quantityChange, setQuantityChange] = useState(0);
const [sortOrder, setSortOrder] = useState("desc"); const [sortOrder, setSortOrder] = useState("desc");
const [isEditCurrentPrice, setIsEditCurrentPrice] = useState(false); const [isEditCurrentPrice, setIsEditCurrentPrice] = useState(false);
const [isViewingHistory, setIsViewingHistory] = useState(false);
const convertToInteger = (formattedValue) => {
// Remove dots and convert to integer
return parseInt(formattedValue.replace(/\./g, ""), 10);
};
const formatCurrency = (value) => { const formatCurrency = (value) => {
if (!value) return ""; if (!value) return "";
@@ -53,12 +58,14 @@ const SetPaymentQr = ({ cafeId }) => {
useEffect(() => { useEffect(() => {
const fetchMaterials = async () => { const fetchMaterials = async () => {
setLoading(true);
try { try {
const data = await getMaterials(cafeId); const data = await getMaterials(cafeId);
setMaterials(data); setMaterials(data);
console.log(data) console.log(data)
setError(null); setError(null);
if (data.length > 0) {
setSelectedMaterialIndex(0);
}
} catch (error) { } catch (error) {
console.error("Error fetching materials:", error); console.error("Error fetching materials:", error);
setError("Failed to fetch materials."); setError("Failed to fetch materials.");
@@ -69,9 +76,6 @@ const SetPaymentQr = ({ cafeId }) => {
try { try {
const data = await getMaterialMutations(cafeId); const data = await getMaterialMutations(cafeId);
setMutations(data); setMutations(data);
if (data.length > 0) {
setSelectedMaterialId(0);
}
} catch (err) { } catch (err) {
setError(err.message); setError(err.message);
} finally { } finally {
@@ -87,12 +91,10 @@ const SetPaymentQr = ({ cafeId }) => {
setSortOrder(e.target.value); setSortOrder(e.target.value);
}; };
const filteredMutations = selectedMaterialId const filteredMutations = mutations.filter((mutation) => mutation.materialId === materials[selectedMaterialIndex].materialId) || [];
? mutations.filter((mutation) => mutation.materialId === selectedMaterialId)
: [];
const sortedMutations = filteredMutations const sortedMutations = filteredMutations
.filter((mutation) => mutation.materialId === selectedMaterialId) .filter((mutation) => mutation.materialId === materials[selectedMaterialIndex].materialId)
.sort((a, b) => { .sort((a, b) => {
if (sortOrder === "asc") { if (sortOrder === "asc") {
return new Date(a.createdAt) - new Date(b.createdAt); return new Date(a.createdAt) - new Date(b.createdAt);
@@ -122,7 +124,7 @@ const SetPaymentQr = ({ cafeId }) => {
setMaterials(data); setMaterials(data);
setError(null); setError(null);
if (data.length > 0) { if (data.length > 0) {
setSelectedMaterialId(0); setSelectedMaterialIndex(0);
} }
} catch (error) { } catch (error) {
console.error("Error creating material:", error); console.error("Error creating material:", error);
@@ -141,8 +143,8 @@ const SetPaymentQr = ({ cafeId }) => {
); );
setMaterials(updatedMaterials); setMaterials(updatedMaterials);
setError(null); setError(null);
if (selectedMaterialId === materialId) { if (selectedMaterialIndex === materialId) {
setSelectedMaterialId( setSelectedMaterialIndex(
updatedMaterials.length > 0 ? updatedMaterials[0].materialId : null updatedMaterials.length > 0 ? updatedMaterials[0].materialId : null
); );
} }
@@ -155,25 +157,25 @@ const SetPaymentQr = ({ cafeId }) => {
}; };
const handlePrevious = () => { const handlePrevious = () => {
if (selectedMaterialId) { if (selectedMaterialIndex) {
setQuantityChange(0); setQuantityChange(0);
const currentIndex = materials.findIndex( const currentIndex = materials.findIndex(
(material) => material.materialId === selectedMaterialId (material) => material.materialId === selectedMaterialIndex
); );
if (currentIndex > 0) { if (currentIndex > 0) {
setSelectedMaterialId(materials[currentIndex - 1].materialId); setSelectedMaterialIndex(materials[currentIndex - 1].materialId);
} }
} }
}; };
const handleNext = () => { const handleNext = () => {
if (selectedMaterialId) { if (selectedMaterialIndex) {
setQuantityChange(0); setQuantityChange(0);
const currentIndex = materials.findIndex( const currentIndex = materials.findIndex(
(material) => material.materialId === selectedMaterialId (material) => material.materialId === selectedMaterialIndex
); );
if (currentIndex < materials.length - 1) { if (currentIndex < materials.length - 1) {
setSelectedMaterialId(materials[currentIndex + 1].materialId); setSelectedMaterialIndex(materials[currentIndex + 1].materialId);
} }
} }
}; };
@@ -184,10 +186,9 @@ const SetPaymentQr = ({ cafeId }) => {
useEffect(() => { useEffect(() => {
setQuantityChange(0); setQuantityChange(0);
console.log(selectedMaterialId) if (materials.length > 0 || selectedMaterialIndex > -1) {
if (selectedMaterialId > -1) {
const materialMutations = mutations.filter( const materialMutations = mutations.filter(
(mutation) => mutation.materialId === materials[selectedMaterialId]?.materialId (mutation) => mutation.materialId === materials[selectedMaterialIndex]?.materialId
); );
console.log(materialMutations) console.log(materialMutations)
if (materialMutations.length > 0) { if (materialMutations.length > 0) {
@@ -208,19 +209,20 @@ const SetPaymentQr = ({ cafeId }) => {
} }
} }
}, [selectedMaterialId]);
}, [materials, mutations, selectedMaterialIndex]);
const handleUpdateStock = async () => { const handleUpdateStock = async () => {
if (selectedMaterialId) {
setLoading(true); setLoading(true);
try { try {
const newPrice = convertToInteger(currentPrice)
const newStock = currentQuantity + quantityChange; const newStock = currentQuantity + quantityChange;
const formData = new FormData(); const formData = new FormData();
formData.append("newStock", newStock); formData.append("newStock", newStock);
formData.append("priceAtp", currentPrice); formData.append("priceAtp", newPrice);
formData.append("reason", "Stock update"); formData.append("reason", "Stock update");
await createMaterialMutation(selectedMaterialId, formData); await createMaterialMutation(materials[selectedMaterialIndex].materialId, formData);
setQuantityChange(0); setQuantityChange(0);
const updatedMutations = await getMaterialMutations(cafeId); const updatedMutations = await getMaterialMutations(cafeId);
setMutations(updatedMutations); setMutations(updatedMutations);
@@ -232,11 +234,10 @@ const SetPaymentQr = ({ cafeId }) => {
} finally { } finally {
setLoading(false); setLoading(false);
} }
}
}; };
const currentMaterial = materials.find( const currentMaterial = materials.find(
(material) => material.materialId === selectedMaterialId (material) => material.materialId === selectedMaterialIndex
); );
const formatDate = (timestamp) => { const formatDate = (timestamp) => {
const date = new Date(timestamp); const date = new Date(timestamp);
@@ -246,10 +247,30 @@ const SetPaymentQr = ({ cafeId }) => {
return ( return (
<div style={styles.container}> <div style={styles.container}>
<h3 style={styles.title}>Stok</h3> {loading ?
<Carousel items={materials} onSelect={(e)=>setSelectedMaterialId(e)}/> <>
</>
:
<>
<h3 style={styles.title}>Bahan baku</h3>
<Carousel items={materials} onSelect={(e) => setSelectedMaterialIndex(e)} selectedIndex={selectedMaterialIndex} />
{selectedMaterialIndex != -1 ?
<>
<div style={styles.switchContainer}>
<h3>Stok sekarang {currentQuantity}</h3>
</div>
<div style={styles.stokContainer}>
<button onClick={() => handleQuantityChange(currentQuantity + quantityChange > 0 ? -1 : 0)} style={styles.stockButton}>
-
</button>
<p>{currentQuantity + quantityChange}</p>
<button onClick={() => handleQuantityChange(1)} style={styles.stockButton}>
+
</button>
</div>
<div style={styles.uploadMessage}> <div style={styles.uploadMessage}>
<p>harga per {materials && materials[selectedMaterialId]?.unit} sekarang</p> <p>harga per {materials && materials[selectedMaterialIndex]?.unit} sekarang</p>
</div> </div>
<div style={styles.resultMessage}> <div style={styles.resultMessage}>
@@ -260,34 +281,96 @@ const SetPaymentQr = ({ cafeId }) => {
border: isEditCurrentPrice ? "1px solid #ccc" : "1px solid transparent", border: isEditCurrentPrice ? "1px solid #ccc" : "1px solid transparent",
backgroundColor: isEditCurrentPrice ? "white" : "transparent", backgroundColor: isEditCurrentPrice ? "white" : "transparent",
}} }}
disabled={!isEditCurrentPrice} disabled={!isEditCurrentPrice || quantityChange < 1}
value={currentPrice} value={currentPrice}
onChange={handleChange} onChange={handleChange}
placeholder="Enter amount" placeholder="Enter amount"
/> />
<div onClick={() => setIsEditCurrentPrice(!isEditCurrentPrice)} style={styles.uploadButton}>{isEditCurrentPrice ? 'Terapkan' : 'Ganti'}</div> <div onClick={() => quantityChange < 1 ? null : setIsEditCurrentPrice(!isEditCurrentPrice)} style={quantityChange < 1 ? styles.changeButtonDisabled : styles.changeButtonEnabled}>{isEditCurrentPrice ? 'Terapkan' : 'Ganti'}</div>
</div>
<div style={styles.switchContainer}>
<h3>Stok sekarang {currentQuantity}</h3>
</div>
<div style={styles.stokContainer}>
<button onClick={() => handleQuantityChange(currentQuantity + quantityChange > 0 ? -1 : 0)} style={styles.saveButton}>
-
</button>
<p>{currentQuantity + quantityChange}</p>
<button onClick={() => handleQuantityChange(1)} style={styles.saveButton}>
+
</button>
</div> </div>
<div style={styles.buttonContainer}> <div style={styles.buttonContainer}>
<button style={styles.saveButton}> <button onClick={handleUpdateStock} style={styles.saveButton}>
Laporkan {quantityChange > 0 ? 'penambahan' : 'stok sekarang'} {quantityChange < 1 ? currentQuantity + quantityChange : quantityChange} {materials[selectedMaterialId]?.unit} Laporkan {quantityChange > 0 ? 'penambahan' : 'stok sekarang'} {quantityChange < 1 ? currentQuantity + quantityChange : quantityChange} {materials[selectedMaterialIndex]?.unit}
</button> </button>
</div> </div>
<div onClick={() => setIsViewingHistory(!isViewingHistory)} style={styles.historyTab}>
<h3> {isViewingHistory ? '˅' : '˃'} Riwayat stok</h3>
<div style={styles.historyContainer}> <div style={styles.historyContainer}>
<h3> &gt; Riwayat stok</h3> {selectedMaterialIndex != -1 && isViewingHistory && !loading && (
<div style={styles.mutationContainer}>
{sortedMutations.length > 0 ? (
sortedMutations.map((mutation) => (
<div key={mutation.id} style={styles.mutationCard}>
<h4 style={styles.mutationTitle}>
{formatDate(mutation.createdAt)}
</h4>
<p>Details: {mutation.reason}</p>
<p>stok {mutation.newStock}</p>
</div> </div>
))
) : (
<p>No mutations available.</p>
)}
</div>
)}
</div>
</div>
</> :
<>
<div
style={{ display: "flex", alignItems: "center", margin: "10px", marginTop: '17px', marginBottom: '34px' }}
>
<div style={{ marginRight: "5px", fontSize: "1.2em" }}></div>
<h6 style={{ margin: 0, textAlign: "left" }}>
Fitur ini mempermudah mengelola biaya dan memantau pengeluaran bahan.
</h6>
</div>
<div style={styles.switchContainer}>
<h3>Buat bahan baru</h3>
</div>
<div style={styles.resultMessage}>
<input
style={{
width: "100%",
height: '31px',
border: "1px solid #ccc"
}}
value={newMaterialName}
onChange={(event) => setNewMaterialName(event.target.value)}
placeholder="Masukkan nama barang"
/>
</div>
<select
id="materialUnit"
value={newMaterialUnit}
onChange={(e) => setNewMaterialUnit(e.target.value)}
style={styles.unit}
>
<option value="gram">Satuan: gram</option>
<option value="ons">Satuan: ons</option>
<option value="kilogram">Satuan: kilogram</option>
<option value="kuintal">Satuan: kuintal</option>
<option value="liter">Satuan: liter</option>
<option value="piece">Satuan: piece</option>
<option value="meter">Satuan: meter</option>
<option value="pack">Satuan: pack</option>
<option value="sachet">Satuan: sachet</option>
<option value="box">Satuan: box</option>
</select>
<div style={styles.buttonContainer}>
<button style={styles.saveButton}>
Buat bahan baku
</button>
</div>
</>
}
</>
}
</div> </div>
); );
}; };
@@ -296,6 +379,7 @@ const SetPaymentQr = ({ cafeId }) => {
const styles = { const styles = {
container: { container: {
width: '100%', width: '100%',
minHeight: '50vh',
backgroundColor: "white", backgroundColor: "white",
padding: "20px", padding: "20px",
borderRadius: "8px", borderRadius: "8px",
@@ -320,7 +404,7 @@ const styles = {
fontWeight: 600, fontWeight: 600,
textAlign: "left", textAlign: "left",
}, },
uploadButton: { changeButtonEnabled: {
paddingRight: '10px', paddingRight: '10px',
backgroundColor: 'green', backgroundColor: 'green',
borderRadius: '30px', borderRadius: '30px',
@@ -331,6 +415,17 @@ const styles = {
paddingLeft: '10px', paddingLeft: '10px',
paddingHeight: '10px', paddingHeight: '10px',
}, },
changeButtonDisabled: {
paddingRight: '10px',
backgroundColor: '#a1a1a1',
borderRadius: '30px',
color: 'white',
fontWeight: 700,
height: '36px',
lineHeight: '36px',
paddingLeft: '10px',
paddingHeight: '10px',
},
resultMessage: { resultMessage: {
marginTop: "-13px", marginTop: "-13px",
textAlign: "left", textAlign: "left",
@@ -341,15 +436,26 @@ const styles = {
display: 'flex', display: 'flex',
justifyContent: 'space-evenly', justifyContent: 'space-evenly',
alignItems: 'center', alignItems: 'center',
marginTop: '20px', marginTop: '18px',
marginTop: "20px", marginBottom: "6px",
textAlign: "left", textAlign: "left",
}, },
buttonContainer: { buttonContainer: {
marginTop: "20px", marginTop: "11px",
textAlign: "left", textAlign: "left",
}, },
stockButton: {
padding: "10px 20px",
fontSize: "3.5vw",
backgroundColor: "#28a745",
color: "#fff",
border: "none",
borderRadius: "30px",
cursor: "pointer",
transition: "background-color 0.3s",
},
saveButton: { saveButton: {
width: '100%',
padding: "10px 20px", padding: "10px 20px",
fontSize: "3.5vw", fontSize: "3.5vw",
backgroundColor: "#28a745", backgroundColor: "#28a745",
@@ -363,15 +469,24 @@ const styles = {
marginTop: "20px", marginTop: "20px",
textAlign: "left", textAlign: "left",
}, },
historyContainer: { historyTab: {
marginTop: "20px",
textAlign: "left", textAlign: "left",
}, },
historyContainer: {
textAlign: "left",
maxHeight: '200px',
overflowY: 'auto'
},
description: { description: {
margin: "10px 0", margin: "10px 0",
fontSize: "14px", fontSize: "14px",
color: "#666", color: "#666",
}, },
unit: {
marginTop: '11px',
width: '100%',
height: '31px',
},
}; };
export default SetPaymentQr; export default SetPaymentQr;