ok banget

This commit is contained in:
zadit
2024-10-30 03:32:48 +07:00
parent 1ecc6db645
commit 5a2b9b2f86
18 changed files with 244 additions and 130 deletions

View File

@@ -96,7 +96,6 @@ function App() {
if (response.status === 200) { if (response.status === 200) {
setShop(cafe); setShop(cafe);
setShopItems(data); setShopItems(data);
// Filter out unavailable items // Filter out unavailable items
const filteredData = data const filteredData = data
.map((itemType) => ({ .map((itemType) => ({
@@ -220,7 +219,7 @@ function App() {
localStorage.getItem("settings") localStorage.getItem("settings")
) )
setModal("complete_account"); setModal("complete_account");
if (data.data.user.cafeId == shopId) { if (data.data.user.cafeId == shopId || data.data.isTheOwner) {
const connectedGuestSides = await getConnectedGuestSides(); const connectedGuestSides = await getConnectedGuestSides();
setGuestSides(connectedGuestSides.sessionDatas); setGuestSides(connectedGuestSides.sessionDatas);
console.log("getting guest side"); console.log("getting guest side");

View File

@@ -8,6 +8,7 @@ const Item = ({
price: initialPrice, price: initialPrice,
qty: initialQty, qty: initialQty,
imageUrl, imageUrl,
imageFile,
id, id,
onPlusClick, onPlusClick,
onNegativeClick, onNegativeClick,
@@ -17,7 +18,7 @@ const Item = ({
isAvailable, isAvailable,
isBeingEdit, isBeingEdit,
}) => { }) => {
const [selectedImage, setSelectedImage] = useState(null); const [selectedImage, setSelectedImage] = useState(imageFile);
const [previewUrl, setPreviewUrl] = useState(imageUrl); const [previewUrl, setPreviewUrl] = useState(imageUrl);
const [itemQty, setItemQty] = useState(blank ? 0 : initialQty); const [itemQty, setItemQty] = useState(blank ? 0 : initialQty);
const [itemName, setItemName] = useState(initialName); const [itemName, setItemName] = useState(initialName);
@@ -219,6 +220,7 @@ const Item = ({
style={{ style={{
backgroundColor: "white", backgroundColor: "white",
width: "150px", width: "150px",
color: '#73a585'
}} }}
onClick={isBeingEdit ? handleUpdate : handleCreate} onClick={isBeingEdit ? handleUpdate : handleCreate}
> >

View File

@@ -143,12 +143,15 @@
.itemQty { .itemQty {
display: flex; display: flex;
align-items: center; align-items: end;
font-size: 0.9rem; font-size: 0.9rem;
margin-left: 5px; margin-left: 5px;
color: rgb(115, 165, 133);
fill: rgb(115, 165, 133);
} }
.itemQtyValue { .itemQtyValue {
margin-bottom: 8px;
font-family: "Poppins", sans-serif; font-family: "Poppins", sans-serif;
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
@@ -174,7 +177,6 @@
background-color: #ffffff; background-color: #ffffff;
border: 2px solid #73a585; border: 2px solid #73a585;
/* border: none; */ /* border: none; */
color: #73a585;
display: inline-block; display: inline-block;
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;

View File

@@ -188,6 +188,7 @@ const ItemLister = ({
: item : item
) )
); );
setisEditItem(0);
}; };
const onUpdateItem = (itemId, name, price, image) => { const onUpdateItem = (itemId, name, price, image) => {
if (isEdit) if (isEdit)
@@ -350,17 +351,41 @@ const ItemLister = ({
isEdit ? styles.border : styles.noborder isEdit ? styles.border : styles.noborder
}`} }`}
value={editedTypeName} value={editedTypeName}
placeholder="type name"
onChange={(e) => setEditedTypeName(e.target.value)} onChange={(e) => setEditedTypeName(e.target.value)}
disabled={!isEdit} disabled={!isEdit}
/> />
{isEditMode && !isEdit && ( {isEditMode && !isEdit && (
<> <><div
<button style={{
className={styles["edit-typeItem-button"]} width: '32px',
onClick={toggleEditTypeItem} height: '32px', // Add a height to the div
> display: 'flex', // Use flexbox
Edit justifyContent: 'center', // Center horizontally
</button> alignItems: 'center', // Center vertically
cursor: 'pointer'
}}
onClick={toggleEditTypeItem} // Move onClick here for the whole div
>
<svg
fill="#000000"
viewBox="0 0 32 32"
style={{ fillRule: 'evenodd', clipRule: 'evenodd', strokeLinejoin: 'round', strokeMiterlimit: 2 }}
version="1.1"
xmlSpace="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlnsSerif="http://www.serif.com/"
xmlnsXlink="http://www.w3.org/1999/xlink"
>
<g id="SVGRepo_bgCarrier" strokeWidth="0"></g>
<g id="SVGRepo_tracerCarrier" strokeLinecap="round" strokeLinejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<path d="M12.965,5.462c0,-0 -2.584,0.004 -4.979,0.008c-3.034,0.006 -5.49,2.467 -5.49,5.5l0,13.03c0,1.459 0.579,2.858 1.611,3.889c1.031,1.032 2.43,1.611 3.889,1.611l13.003,0c3.038,-0 5.5,-2.462 5.5,-5.5c0,-2.405 0,-5.004 0,-5.004c0,-0.828 -0.672,-1.5 -1.5,-1.5c-0.827,-0 -1.5,0.672 -1.5,1.5l0,5.004c0,1.381 -1.119,2.5 -2.5,2.5l-13.003,0c-0.663,-0 -1.299,-0.263 -1.768,-0.732c-0.469,-0.469 -0.732,-1.105 -0.732,-1.768l0,-13.03c0,-1.379 1.117,-2.497 2.496,-2.5c2.394,-0.004 4.979,-0.008 4.979,-0.008c0.828,-0.002 1.498,-0.675 1.497,-1.503c-0.001,-0.828 -0.675,-1.499 -1.503,-1.497Z"></path>
<path d="M20.046,6.411l-6.845,6.846c-0.137,0.137 -0.232,0.311 -0.271,0.501l-1.081,5.152c-0.069,0.329 0.032,0.671 0.268,0.909c0.237,0.239 0.577,0.343 0.907,0.277l5.194,-1.038c0.193,-0.039 0.371,-0.134 0.511,-0.274l6.845,-6.845l-5.528,-5.528Zm1.415,-1.414l5.527,5.528l1.112,-1.111c1.526,-1.527 1.526,-4.001 -0,-5.527c-0.001,-0 -0.001,-0.001 -0.001,-0.001c-1.527,-1.526 -4.001,-1.526 -5.527,-0l-1.111,1.111Z"></path>
</g>
</svg>
</div>
</> </>
)} )}
</div> </div>
@@ -562,11 +587,37 @@ const ItemLister = ({
/> />
)} )}
<h3> <h3>
{item.availability ? "available" : "unavailable"} &nbsp;{item.availability ? "available" : "unavailable"} &nbsp;
</h3> </h3>
<button onClick={() => editItem(item.itemId)}> <div
edit style={{
</button> width: '32px',
height: '32px', // Add a height to the div
display: 'flex', // Use flexbox
justifyContent: 'center', // Center horizontally
alignItems: 'center', // Center vertically
cursor: 'pointer'
}}
onClick={() => editItem(item.itemId)}
>
<svg
fill="white"
viewBox="0 0 32 32"
style={{ fillRule: 'evenodd', clipRule: 'evenodd', strokeLinejoin: 'round', strokeMiterlimit: 2 }}
version="1.1"
xmlSpace="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlnsSerif="http://www.serif.com/"
xmlnsXlink="http://www.w3.org/1999/xlink"
>
<g id="SVGRepo_bgCarrier" strokeWidth="0"></g>
<g id="SVGRepo_tracerCarrier" strokeLinecap="round" strokeLinejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<path d="M12.965,5.462c0,-0 -2.584,0.004 -4.979,0.008c-3.034,0.006 -5.49,2.467 -5.49,5.5l0,13.03c0,1.459 0.579,2.858 1.611,3.889c1.031,1.032 2.43,1.611 3.889,1.611l13.003,0c3.038,-0 5.5,-2.462 5.5,-5.5c0,-2.405 0,-5.004 0,-5.004c0,-0.828 -0.672,-1.5 -1.5,-1.5c-0.827,-0 -1.5,0.672 -1.5,1.5l0,5.004c0,1.381 -1.119,2.5 -2.5,2.5l-13.003,0c-0.663,-0 -1.299,-0.263 -1.768,-0.732c-0.469,-0.469 -0.732,-1.105 -0.732,-1.768l0,-13.03c0,-1.379 1.117,-2.497 2.496,-2.5c2.394,-0.004 4.979,-0.008 4.979,-0.008c0.828,-0.002 1.498,-0.675 1.497,-1.503c-0.001,-0.828 -0.675,-1.499 -1.503,-1.497Z"></path>
<path d="M20.046,6.411l-6.845,6.846c-0.137,0.137 -0.232,0.311 -0.271,0.501l-1.081,5.152c-0.069,0.329 0.032,0.671 0.268,0.909c0.237,0.239 0.577,0.343 0.907,0.277l5.194,-1.038c0.193,-0.039 0.371,-0.134 0.511,-0.274l6.845,-6.845l-5.528,-5.528Zm1.415,-1.414l5.527,5.528l1.112,-1.111c1.526,-1.527 1.526,-4.001 -0,-5.527c-0.001,-0 -0.001,-0.001 -0.001,-0.001c-1.527,-1.526 -4.001,-1.526 -5.527,-0l-1.111,1.111Z"></path>
</g>
</svg>
</div>
</div> </div>
)} )}
@@ -578,6 +629,7 @@ const ItemLister = ({
price={item.price} price={item.price}
qty={item.qty} qty={item.qty}
imageUrl={item.image} imageUrl={item.image}
imageFile={item.selectedImage}
onPlusClick={() => handlePlusClick(item.itemId)} onPlusClick={() => handlePlusClick(item.itemId)}
onNegativeClick={() => handleNegativeClick(item.itemId)} onNegativeClick={() => handleNegativeClick(item.itemId)}
onRemoveClick={() => handleRemoveClick(item.itemId)} onRemoveClick={() => handleRemoveClick(item.itemId)}
@@ -614,11 +666,37 @@ const ItemLister = ({
/> />
)} )}
<h3> <h3>
{item.availability ? "available" : "unavailable"} &nbsp;{item.availability ? "available" : "unavailable"}&nbsp;
</h3> </h3>
<button onClick={() => editItem(item.itemId)}> <div
edit style={{
</button> width: '32px',
height: '32px', // Add a height to the div
display: 'flex', // Use flexbox
justifyContent: 'center', // Center horizontally
alignItems: 'center', // Center vertically
cursor: 'pointer'
}}
onClick={() => editItem(item.itemId)}
>
<svg
fill="white"
viewBox="0 0 32 32"
style={{ fillRule: 'evenodd', clipRule: 'evenodd', strokeLinejoin: 'round', strokeMiterlimit: 2 }}
version="1.1"
xmlSpace="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlnsSerif="http://www.serif.com/"
xmlnsXlink="http://www.w3.org/1999/xlink"
>
<g id="SVGRepo_bgCarrier" strokeWidth="0"></g>
<g id="SVGRepo_tracerCarrier" strokeLinecap="round" strokeLinejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<path d="M12.965,5.462c0,-0 -2.584,0.004 -4.979,0.008c-3.034,0.006 -5.49,2.467 -5.49,5.5l0,13.03c0,1.459 0.579,2.858 1.611,3.889c1.031,1.032 2.43,1.611 3.889,1.611l13.003,0c3.038,-0 5.5,-2.462 5.5,-5.5c0,-2.405 0,-5.004 0,-5.004c0,-0.828 -0.672,-1.5 -1.5,-1.5c-0.827,-0 -1.5,0.672 -1.5,1.5l0,5.004c0,1.381 -1.119,2.5 -2.5,2.5l-13.003,0c-0.663,-0 -1.299,-0.263 -1.768,-0.732c-0.469,-0.469 -0.732,-1.105 -0.732,-1.768l0,-13.03c0,-1.379 1.117,-2.497 2.496,-2.5c2.394,-0.004 4.979,-0.008 4.979,-0.008c0.828,-0.002 1.498,-0.675 1.497,-1.503c-0.001,-0.828 -0.675,-1.499 -1.503,-1.497Z"></path>
<path d="M20.046,6.411l-6.845,6.846c-0.137,0.137 -0.232,0.311 -0.271,0.501l-1.081,5.152c-0.069,0.329 0.032,0.671 0.268,0.909c0.237,0.239 0.577,0.343 0.907,0.277l5.194,-1.038c0.193,-0.039 0.371,-0.134 0.511,-0.274l6.845,-6.845l-5.528,-5.528Zm1.415,-1.414l5.527,5.528l1.112,-1.111c1.526,-1.527 1.526,-4.001 -0,-5.527c-0.001,-0 -0.001,-0.001 -0.001,-0.001c-1.527,-1.526 -4.001,-1.526 -5.527,-0l-1.111,1.111Z"></path>
</g>
</svg>
</div>
</div> </div>
)} )}

View File

@@ -114,7 +114,7 @@ const ItemTypeLister = ({
shopId={shopId} shopId={shopId}
shopOwnerId={shopOwnerId} shopOwnerId={shopOwnerId}
user={user} user={user}
typeName={"add new"} typeName={""}
itemList={items} itemList={items}
isEditMode={true} isEditMode={true}
handleCreateItem={(itemTypeId, name, price, selectedImage) => createItem(shopId, name, price, selectedImage,itemTypeId)} handleCreateItem={(itemTypeId, name, price, selectedImage) => createItem(shopId, name, price, selectedImage,itemTypeId)}

View File

@@ -62,13 +62,13 @@ const Modal = ({ shop, isOpen, onClose, modalContent, setModal }) => {
<PaymentOptions shopId={shop.cafeId} /> <PaymentOptions shopId={shop.cafeId} />
)} )}
{modalContent === "add_material" && ( {modalContent === "add_material" && (
<MaterialList cafeId={shop.cafeId} /> <MaterialList handleClose={handleOverlayClick} cafeId={shop.cafeId} />
)} )}
{modalContent === "update_stock" && ( {modalContent === "update_stock" && (
<MaterialMutationsPage cafeId={shop.cafeId} /> <MaterialMutationsPage handleClose={handleOverlayClick} cafeId={shop.cafeId} />
)} )}
{modalContent === "welcome_config" && <WelcomePageEditor cafeId={shop.cafeId} welcomePageConfig={shop.welcomePageConfig} />} {modalContent === "welcome_config" && <WelcomePageEditor cafeId={shop.cafeId} welcomePageConfig={shop.welcomePageConfig} />}
{modalContent === "reports" && <Reports cafeId={shop.cafeId} />} {modalContent === "reports" && <Reports handleClose={handleOverlayClick} cafeId={shop.cafeId} />}
</div> </div>
</div> </div>
); );

View File

@@ -1,5 +1,5 @@
// src/config.js // src/config.js
const API_BASE_URL = 'https://api.kedaimaster.com'; const API_BASE_URL = 'https://dev.api.kedaimaster.com';
export default API_BASE_URL; export default API_BASE_URL;

View File

@@ -26,6 +26,7 @@ export const createMaterialMutation = async (materialId, data) => {
body: JSON.stringify({ body: JSON.stringify({
newStock: data.get("newStock"), newStock: data.get("newStock"),
reason: data.get("reason"), reason: data.get("reason"),
priceAtp: data.get("priceAtp"),
}), }),
} }
); );

View File

@@ -173,11 +173,11 @@ export async function getMyTransactions(shopId, demand) {
console.error("Error:", error); console.error("Error:", error);
} }
} }
export async function getTransactions(shopId, demand) { export async function getTransactionsFromCafe(shopId, demand) {
try { try {
const token = getLocalStorage("auth"); const token = getLocalStorage("auth");
const response = await fetch( const response = await fetch(
`${API_BASE_URL}/transaction/get-transactions/${shopId}?demandLength=${demand}`, `${API_BASE_URL}/transaction/get-transactions-from-cafe/${shopId}?demandLength=${demand}`,
{ {
method: "GET", method: "GET",
headers: { headers: {

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import './GuidePage.css'; import './GuidePage.css';
import API_BASE_URL from '../config.js';
const GuidePage = ({ guideType }) => { const GuidePage = ({ guideType }) => {
const renderGuideContent = () => { const renderGuideContent = () => {
switch (guideType) { switch (guideType) {
@@ -10,7 +10,7 @@ const GuidePage = ({ guideType }) => {
<h2>Setup Guide</h2> <h2>Setup Guide</h2>
<p>1. Turn on edit mode and create item type</p> <p>1. Turn on edit mode and create item type</p>
<video <video
src="https://api.kedaimaster.com/uploads/create_item_guide_1.mkv" src={`${API_BASE_URL}/uploads/create_item_guide_1.mkv`}
autoPlay autoPlay
muted muted
loop loop

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect, useRef } from "react";
import API_BASE_URL from "../config.js"; import API_BASE_URL from "../config.js";
import { import {
getMaterials, getMaterials,
@@ -10,7 +10,7 @@ import {
getMaterialMutations, getMaterialMutations,
} from "../helpers/materialMutationHelpers"; } from "../helpers/materialMutationHelpers";
const MaterialList = ({ cafeId }) => { const MaterialList = ({ cafeId, handleClose }) => {
const [materials, setMaterials] = useState([]); const [materials, setMaterials] = useState([]);
const [mutations, setMutations] = useState([]); const [mutations, setMutations] = useState([]);
const [newMaterialName, setNewMaterialName] = useState(""); const [newMaterialName, setNewMaterialName] = useState("");
@@ -21,9 +21,12 @@ const MaterialList = ({ cafeId }) => {
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 [selectedMaterialId, setSelectedMaterialId] = useState(null);
const [latestMutation, setLatestMutation] = useState([]);
const [currentQuantity, setCurrentQuantity] = useState(0); const [currentQuantity, setCurrentQuantity] = 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 priceInputRef = useRef(null);
useEffect(() => { useEffect(() => {
const fetchMaterials = async () => { const fetchMaterials = async () => {
@@ -69,9 +72,13 @@ const MaterialList = ({ cafeId }) => {
: latest, : latest,
materialMutations[0] materialMutations[0]
); );
setLatestMutation(latestMutation);
setCurrentQuantity(latestMutation.newStock); setCurrentQuantity(latestMutation.newStock);
setCurrentPrice(latestMutation.priceAtp);
} else { } else {
setCurrentQuantity(0); // Default value if no mutations exist setCurrentQuantity(0); // Default value if no mutations exist
setLatestMutation({newStock: 0});
setCurrentPrice(0);
} }
} }
}, [selectedMaterialId, mutations]); }, [selectedMaterialId, mutations]);
@@ -174,6 +181,10 @@ const MaterialList = ({ cafeId }) => {
const handleQuantityChange = (change) => { const handleQuantityChange = (change) => {
setQuantityChange((prev) => prev + change); setQuantityChange((prev) => prev + change);
}; };
// useEffect to log the latest quantityChange value
useEffect(() => {
if(quantityChange >= latestMutation.newStock) priceInputRef.current.focus();
}, [quantityChange]);
const handleUpdateStock = async () => { const handleUpdateStock = async () => {
if (selectedMaterialId) { if (selectedMaterialId) {
@@ -182,6 +193,7 @@ const MaterialList = ({ cafeId }) => {
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("reason", "Stock update"); formData.append("reason", "Stock update");
await createMaterialMutation(selectedMaterialId, formData); await createMaterialMutation(selectedMaterialId, formData);
@@ -209,7 +221,7 @@ const MaterialList = ({ cafeId }) => {
return ( return (
<div style={styles.container}> <div style={styles.container}>
<h1 style={styles.heading}>Materials List</h1> <h1 style={styles.heading}>Stok barang</h1>
{error && <p style={styles.error}>{error}</p>} {error && <p style={styles.error}>{error}</p>}
{loading && <p>Loading materials and mutations...</p>} {loading && <p>Loading materials and mutations...</p>}
@@ -220,7 +232,7 @@ const MaterialList = ({ cafeId }) => {
style={styles.toggleButton} style={styles.toggleButton}
disabled={loading} disabled={loading}
> >
{showForm ? "Hide Form" : "Add New Material"} {showForm ? "Batalkan" : "Tambah barang"}
</button> </button>
)} )}
@@ -291,7 +303,13 @@ const MaterialList = ({ cafeId }) => {
(material) => material.materialId === selectedMaterialId (material) => material.materialId === selectedMaterialId
) === 0 ) === 0
} }
style={styles.navigationButton} style={{...styles.navigationButton,
backgroundColor:
!selectedMaterialId ||
materials.findIndex((material) => material.materialId === selectedMaterialId) === 0
? '#a3a3a3'
: '#5b81ff',
}}
> >
{"<"} {"<"}
</button> </button>
@@ -319,6 +337,7 @@ const MaterialList = ({ cafeId }) => {
<button style={styles.quantityDisplay}> <button style={styles.quantityDisplay}>
{currentQuantity + quantityChange} {currentQuantity + quantityChange}
</button> </button>
<button <button
onClick={() => handleQuantityChange(1)} onClick={() => handleQuantityChange(1)}
style={styles.quantityButton} style={styles.quantityButton}
@@ -326,6 +345,8 @@ const MaterialList = ({ cafeId }) => {
+ +
</button> </button>
</div> </div>
<p>harga per {currentMaterial.unit}</p>
<input ref={priceInputRef} disabled={(currentQuantity+quantityChange) <= latestMutation.newStock} value={currentPrice} onChange={(e)=>setCurrentPrice(e.target.value)} style={styles.priceAtp}/>
<button <button
onClick={handleUpdateStock} onClick={handleUpdateStock}
style={styles.updateMutation} style={styles.updateMutation}
@@ -357,7 +378,13 @@ const MaterialList = ({ cafeId }) => {
) === ) ===
materials.length - 1 materials.length - 1
} }
style={styles.navigationButton} style={{...styles.navigationButton,
backgroundColor:
!selectedMaterialId ||
materials.findIndex((material) => material.materialId === selectedMaterialId) === materials.length - 1
? '#a3a3a3'
: '#5b81ff',
}}
> >
{">"} {">"}
</button> </button>
@@ -394,19 +421,19 @@ const MaterialList = ({ cafeId }) => {
)} )}
</div> </div>
)} )}
<div class="ItemLister_PaymentOption__YZlDL"><div style={{marginTop:'20px'}} onClick={handleClose} class="ItemLister_Pay2Button__+MIxX">Kembali</div></div>
</div> </div>
); );
}; };
const styles = { const styles = {
container: { container: {
paddingLeft: "10px", position: 'fixed',
paddingRight: "10px", height: '100vh',
maxWidth: "800px", width: '100vw',
margin: "0 auto", top: 0,
height: "100%", // Adjust height based on your needs right: 0,
overflowY: "auto", // Enables vertical scrolling backgroundColor: 'rgb(207, 207, 207)'
backgroundColor: "white",
}, },
heading: { heading: {
textAlign: "center", textAlign: "center",
@@ -569,6 +596,16 @@ const styles = {
textAlign: "center", textAlign: "center",
margin: "0 5px", margin: "0 5px",
}, },
priceAtp: {
padding: "8px 12px",
border: "1px solid #ddd",
borderRadius: "5px",
textAlign: 'left',
backgroundColor: "#fff",
color: "#000",
fontSize: "16px",
margin: "0 5px",
},
updateMutation: { updateMutation: {
marginTop: "10px", marginTop: "10px",
padding: "12px 20px", padding: "12px 20px",

View File

@@ -141,7 +141,7 @@ const styles = {
}, },
}; };
const MaterialMutationPage = ({ cafeId }) => { const MaterialMutationPage = ({ cafeId, handleClose }) => {
const [materials, setMaterials] = useState([]); const [materials, setMaterials] = useState([]);
const [mutations, setMutations] = useState([]); const [mutations, setMutations] = useState([]);
const [selectedMaterialId, setSelectedMaterialId] = useState(""); const [selectedMaterialId, setSelectedMaterialId] = useState("");
@@ -331,6 +331,8 @@ const MaterialMutationPage = ({ cafeId }) => {
</div> </div>
))} ))}
</div> </div>
<div class="ItemLister_PaymentOption__YZlDL"><div style={{marginTop:'20px'}} onClick={handleClose} class="ItemLister_Pay2Button__+MIxX">Kembali</div></div>
</div> </div>
); );
}; };

View File

@@ -17,6 +17,7 @@ const RoundedRectangle = ({
title, title,
value, value,
percentage, percentage,
invert,
fontSize = "15px", fontSize = "15px",
loading = false, loading = false,
children, // Assuming this is a React component or JSX children, // Assuming this is a React component or JSX
@@ -73,7 +74,7 @@ const RoundedRectangle = ({
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
textAlign: "right", textAlign: "right",
color: loading ? "black" : percentage > 0 ? "#007bff" : "red", color: loading ? "black" : percentage >= 0 ? (invert ? "red" : "#2fd45e") : (invert ? "#2fd45e" : "red"),
}; };
const arrowStyle = { const arrowStyle = {
@@ -102,7 +103,8 @@ const RoundedRectangle = ({
); );
}; };
const App = ({ cafeId }) => { const App = ({ cafeId,
handleClose }) => {
const [favouriteItems, setFavouriteItems] = useState([]); const [favouriteItems, setFavouriteItems] = useState([]);
const [analytics, setAnalytics] = useState({}); const [analytics, setAnalytics] = useState({});
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
@@ -128,7 +130,7 @@ const App = ({ cafeId }) => {
}, [filter]); }, [filter]);
const [sold, percentage] = analytics[filter] || [0, 0]; const [sold, percentage] = analytics[filter] || [0, 0];
const filteredItems = analytics.currentFavoriteItems || []; const filteredItems = analytics.items || [];
const totalSold = filteredItems.reduce((sum, item) => sum + item.count, 0); const totalSold = filteredItems.reduce((sum, item) => sum + item.count, 0);
const colors = [ const colors = [
@@ -187,7 +189,7 @@ const App = ({ cafeId }) => {
setFilter(filterMap[selectedItem]); setFilter(filterMap[selectedItem]);
} }
const filterTexts = ["1 day", "7 days", "30 days", "365 days"]; const filterTexts = ["1", "7", "30", "365"];
const comparisonText = const comparisonText =
filterTexts[["daily", "weekly", "monthly", "yearly"].indexOf(filter)]; filterTexts[["daily", "weekly", "monthly", "yearly"].indexOf(filter)];
const formatDate = (isoDateString) => { const formatDate = (isoDateString) => {
@@ -201,11 +203,18 @@ const App = ({ cafeId }) => {
}; };
return ( return (
<div className={styles.Transactions} style={{ backgroundColor: "#cfcfcf" }}> <div style={{
position: 'fixed',
height: '100vh',
width: '100vw',
top: 0,
right: 0,
backgroundColor: 'rgb(207, 207, 207)'}}
>
<h2 className={styles["Transactions-title"]}>Reports</h2> <h2 className={styles["Transactions-title"]}>Reports</h2>
<div style={{ textAlign: "center" }}> <div style={{ textAlign: "center" }}>
<MultiSwitch <MultiSwitch
texts={["Yesterday", "Last 7", "Last 30", "Last 365"]} texts={["Yesterday", "This week", "This Month", "This year"]}
selectedSwitch={["daily", "weekly", "monthly", "yearly"].indexOf( selectedSwitch={["daily", "weekly", "monthly", "yearly"].indexOf(
filter filter
)} )}
@@ -229,62 +238,56 @@ const App = ({ cafeId }) => {
> >
<RoundedRectangle <RoundedRectangle
bgColor="#E3F5FF" bgColor="#E3F5FF"
title="Transactions" title="Pendapatan"
value={analytics.transactionCount} fontSize="12px"
percentage={roundToInteger(analytics.transactionGrowth)} value={!loading && "Rp" + formatIncome(analytics?.totalIncome)}
percentage={roundToInteger(analytics.growthIncome)}
invert={false}
loading={loading}
/>
<RoundedRectangle
bgColor="#E5ECF6"
title="Pengeluaran"
fontSize="12px"
value={!loading && "Rp" + formatIncome(analytics?.currentOutcome)}
percentage={roundToInteger(analytics.growthOutcome)}
invert={true}
loading={loading} loading={loading}
/> />
<RoundedRectangle <RoundedRectangle
bgColor="#E5ECF6" bgColor="#E5ECF6"
title="Income" title="Transaksi"
fontSize="12px" value={analytics.totalTransactions}
value={!loading && "Rp" + formatIncome(analytics?.totalIncome)} percentage={roundToInteger(analytics.growthTransactions)}
percentage={roundToInteger(analytics.incomeGrowth)} invert={false}
loading={loading} loading={loading}
/> />
{analytics?.items &&
{analytics?.currentFavoriteItems && analytics?.items.length > 0 && (
analytics?.currentFavoriteItems.length > 0 && (
<RoundedRectangle <RoundedRectangle
bgColor="#E5ECF6" bgColor="#E3F5FF"
title={"Fav item"} title={"Item favorit"}
value={analytics?.currentFavoriteItems[0]?.name} value={analytics?.items[0]?.name}
loading={loading}
/>
)}
{(!analytics?.items ||
analytics?.items.length === 0) && (
<RoundedRectangle
bgColor="#E5ECF6"
title={"Item favorit"}
value={"-"}
loading={loading} loading={loading}
/> />
)} )}
{(!analytics?.currentFavoriteItems ||
analytics?.currentFavoriteItems.length === 0) && (
<RoundedRectangle
bgColor="#E5ECF6"
title={"No fav item"}
value={"-"}
loading={loading}
/>
)}
{analytics?.previousFavoriteItem !== null && (
<RoundedRectangle
bgColor="#E3F5FF"
title={"Fav before"}
value={analytics?.previousFavoriteItem?.name}
loading={loading}
/>
)}
{analytics?.previousFavoriteItem === null && (
<RoundedRectangle
bgColor="#E3F5FF"
title={"No fav item"}
value={"-"}
loading={loading}
/>
)}
<div <div
style={{ display: "flex", alignItems: "center", margin: "10px" }} style={{ display: "flex", alignItems: "center", margin: "10px" }}
> >
<div style={{ marginRight: "5px", fontSize: "1.2em" }}></div> <div style={{ marginRight: "5px", fontSize: "1.2em" }}></div>
<h6 style={{ margin: 0, textAlign: "left" }}> <h6 style={{ margin: 0, textAlign: "left" }}>
Growth percentages are based on comparing the last{" "} Persentase pertumbuhan dihitung dengan membandingkan periode{" "}
{comparisonText} with the preceding {comparisonText}. {comparisonText} terakhir dengan {comparisonText} hari sebelumnya.
</h6> </h6>
</div> </div>
</div> </div>
@@ -324,36 +327,8 @@ const App = ({ cafeId }) => {
</div> </div>
</div> </div>
<h3 className={styles["Transactions-title"]}>Stock changes</h3>
{analytics.materialMutations?.length > 0 &&
analytics?.materialMutations.map((item, index) => (
<RoundedRectangle
key={index}
bgColor="rgb(59 59 59 / 41%)"
title={item.name}
>
<div
style={{
display: "flex",
flexWrap: "wrap",
justifyContent: "left",
padding: "20px",
}}
>
{item.mutations.map((mutation, mutationIndex) => (
<RoundedRectangle
bgColor="rgb(59 59 59 / 41%)"
key={mutationIndex}
isChildren={true}
title={`from ${mutation.oldStock} to ${mutation.newStock}`}
value={formatDate(mutation.changeDate)}
/>
))}
</div>
</RoundedRectangle>
))}
</div> </div>
<div class="ItemLister_PaymentOption__YZlDL"><div style={{marginTop:'20px'}} onClick={handleClose} class="ItemLister_Pay2Button__+MIxX">Kembali</div></div>
</div> </div>
); );
}; };

View File

@@ -4,9 +4,9 @@ import { useParams } from "react-router-dom";
import { ColorRing } from "react-loader-spinner"; import { ColorRing } from "react-loader-spinner";
import { import {
getMyTransactions, getMyTransactions,
getTransactions,
confirmTransaction, confirmTransaction,
declineTransaction, declineTransaction,
getTransactionsFromCafe,
} from "../helpers/transactionHelpers"; } from "../helpers/transactionHelpers";
import { getTables } from "../helpers/tableHelper"; import { getTables } from "../helpers/tableHelper";
import TableCanvas from "../components/TableCanvas"; import TableCanvas from "../components/TableCanvas";
@@ -18,17 +18,17 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
const [tables, setTables] = useState([]); const [tables, setTables] = useState([]);
const [selectedTable, setSelectedTable] = useState(null); const [selectedTable, setSelectedTable] = useState(null);
const [transactions, setTransactions] = useState([]); const [transactions, setTransactions] = useState([]);
const [myTransactions, setMyTransactions] = useState([]);
const [isPaymentLoading, setIsPaymentLoading] = useState(false); const [isPaymentLoading, setIsPaymentLoading] = useState(false);
useEffect(() => { useEffect(() => {
const fetchTransactions = async () => { const fetchTransactions = async () => {
try { try {
let response; let response;
if (deviceType == "clerk") response = await getTransactionsFromCafe(shopId || propsShopId, 5);
response = await getTransactions(shopId || propsShopId, 5); setTransactions(response);
else if (deviceType == "guestDevice")
response = await getMyTransactions(shopId || propsShopId, 5); response = await getMyTransactions(shopId || propsShopId, 5);
setTransactions(response); setMyTransactions(response);
} catch (error) { } catch (error) {
console.error("Error fetching transactions:", error); console.error("Error fetching transactions:", error);
} }

View File

@@ -17,6 +17,10 @@
margin-bottom: 20px; margin-bottom: 20px;
} }
.fileInput {
display: none;
}
.circular-image { .circular-image {
width: 100%; width: 100%;
height: 100%; height: 100%;

View File

@@ -1,5 +1,5 @@
// WelcomePage.js // WelcomePage.js
import React from "react"; import React,{useRef} from "react";
import "./WelcomePage.css"; import "./WelcomePage.css";
const WelcomePage = ({ const WelcomePage = ({
@@ -9,7 +9,12 @@ const WelcomePage = ({
welcomingText, welcomingText,
backgroundColor, backgroundColor,
textColor, textColor,
onImageChange
}) => { }) => {
const fileInputRef = useRef(null);
const handleImageClick = () => {
fileInputRef.current.click();
};
return ( return (
<div <div
className={`welcome-page ${isFullscreen ? "fullscreen" : ""}`} // Corrected the className syntax className={`welcome-page ${isFullscreen ? "fullscreen" : ""}`} // Corrected the className syntax
@@ -19,11 +24,20 @@ const WelcomePage = ({
> >
<div <div
style={{ style={{
backgroundColor: image ? "transparent" : "black", backgroundColor: image ? "transparent" : "black",position:'relative'
}} }}
className="image-container" className="image-container"
> >
{image && <img src={image} alt="Welcome" className="circular-image" />} {/* Added conditional rendering */} {!isFullscreen &&
<div onClick={handleImageClick} style={{width: '100%', height: '100%', position:'absolute'}}>
<h1 style={{textAlign:'left'}}>
{image ? "Click To Change Image" : "Click To Add Image"}
</h1>
<input
ref={fileInputRef} style={{display: 'none', width:'100%', height: '100%'}}type="file" accept="image/*" onChange={onImageChange} />
</div>
}
{image && <img src={image} alt="Welcome" className="circular-image" />} {/* Added conditional rendering */}
</div> </div>
<h1 className="welcoming-text" style={{ color: textColor }}> <h1 className="welcoming-text" style={{ color: textColor }}>
{welcomingText} {welcomingText}

View File

@@ -7,7 +7,7 @@
padding: 20px; padding: 20px;
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 8px; border-radius: 8px;
background-color: #f9f9f9; background-color: rgb(207, 207, 207);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
overflow: hidden; overflow: hidden;
} }

View File

@@ -79,7 +79,6 @@ const WelcomePageEditor = ({ cafeId, welcomePageConfig }) => {
> >
<h2>Edit Welcome Page</h2> <h2>Edit Welcome Page</h2>
<div style={{ display: "flex", flexDirection: "column" }}> <div style={{ display: "flex", flexDirection: "column" }}>
<input type="file" accept="image/*" onChange={handleImageChange} />
<textarea <textarea
value={welcomingText} value={welcomingText}
onChange={handleTextChange} onChange={handleTextChange}
@@ -120,7 +119,7 @@ const WelcomePageEditor = ({ cafeId, welcomePageConfig }) => {
</button> </button>
</div> </div>
<div <div
style={{ width: "100%", height: "100%", position: "relative", flex: 1 }} style={{ width: "100%", height: "100%", position: "relative", flex: 1, borderRadius: '15px' }}
> >
<WelcomePage <WelcomePage
image={image} image={image}
@@ -129,6 +128,7 @@ const WelcomePageEditor = ({ cafeId, welcomePageConfig }) => {
textColor={textColor} textColor={textColor}
onGetStarted={() => setIsFullscreen(false)} onGetStarted={() => setIsFullscreen(false)}
isFullscreen={isFullscreen} isFullscreen={isFullscreen}
onImageChange={handleImageChange}
/> />
<div style={{ position: "absolute", bottom: 0, right: 0 }}> <div style={{ position: "absolute", bottom: 0, right: 0 }}>
<svg <svg