Compare commits
10 Commits
b726ae6919
...
ba896106d4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba896106d4 | ||
|
|
e039fc8acc | ||
|
|
dd0227ab80 | ||
|
|
67cf759b31 | ||
|
|
53e091d3a4 | ||
|
|
3a431b1b14 | ||
|
|
69a07be3cd | ||
|
|
b012517568 | ||
|
|
3e35468f2c | ||
|
|
df7c4f737c |
10978
package-lock.json
generated
10978
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -28,6 +28,15 @@
|
|||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<title>KedaiMaster</title>
|
<title>KedaiMaster</title>
|
||||||
|
|
||||||
|
<!-- Google tag (gtag.js) -->
|
||||||
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-2SKSCVFB2N"></script>
|
||||||
|
<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag(){ dataLayer.push(arguments); }
|
||||||
|
gtag('js', new Date());
|
||||||
|
gtag('config', 'G-2SKSCVFB2N');
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
|||||||
@@ -3,17 +3,17 @@
|
|||||||
"name": "jangan pernah ragukan pelanggan",
|
"name": "jangan pernah ragukan pelanggan",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "favicon.ico",
|
"src": "kedai.png",
|
||||||
"sizes": "64x64 32x32 24x24 16x16",
|
"sizes": "64x64 32x32 24x24 16x16",
|
||||||
"type": "image/x-icon"
|
"type": "image/x-icon"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "logo192.png",
|
"src": "kedai.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "192x192"
|
"sizes": "192x192"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "logo512.png",
|
"src": "kedai.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "512x512"
|
"sizes": "512x512"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,10 @@
|
|||||||
@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@200;300;400;500;600;700;800&ital,wght@0,200..800;1,200..800&display=swap");
|
@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@200;300;400;500;600;700;800&ital,wght@0,200..800;1,200..800&display=swap");
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
|
||||||
scrollbar-width: none; /* Firefox */
|
scrollbar-width: none; /* Firefox */
|
||||||
}
|
}
|
||||||
|
|
||||||
.App {
|
.App {
|
||||||
/* overflow-x: hidden; */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.Cafe {
|
.Cafe {
|
||||||
|
|||||||
132
src/App.js
132
src/App.js
@@ -71,6 +71,12 @@ function App() {
|
|||||||
const [depth, setDepth] = useState(-1);
|
const [depth, setDepth] = useState(-1);
|
||||||
const [queue, setQueue] = useState([]);
|
const [queue, setQueue] = useState([]);
|
||||||
|
|
||||||
|
const [newTransaction, setNewTransaction] = useState({});
|
||||||
|
|
||||||
|
|
||||||
|
const queryParams = new URLSearchParams(location.search);
|
||||||
|
const tokenParams = queryParams.get("token");
|
||||||
|
if(tokenParams) localStorage.setItem('auth', tokenParams)
|
||||||
|
|
||||||
const validTransactionStates = [
|
const validTransactionStates = [
|
||||||
'new_transaction',
|
'new_transaction',
|
||||||
@@ -109,6 +115,10 @@ function App() {
|
|||||||
|
|
||||||
const handleStorageChange = () => {
|
const handleStorageChange = () => {
|
||||||
calculateTotalsFromLocalStorage();
|
calculateTotalsFromLocalStorage();
|
||||||
|
|
||||||
|
if (!localStorage.getItem("lastTransaction")) {
|
||||||
|
setLastTransaction(null);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener("localStorageUpdated", handleStorageChange);
|
window.addEventListener("localStorageUpdated", handleStorageChange);
|
||||||
@@ -135,6 +145,7 @@ function App() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setModal('transaction_confirmed', { transactionId: lastTransaction.transactionId })
|
||||||
const myLastTransaction = await checkIsMyTransaction(lastTransaction.transactionId);
|
const myLastTransaction = await checkIsMyTransaction(lastTransaction.transactionId);
|
||||||
console.log(myLastTransaction)
|
console.log(myLastTransaction)
|
||||||
if (myLastTransaction.isMyTransaction) {
|
if (myLastTransaction.isMyTransaction) {
|
||||||
@@ -219,7 +230,7 @@ function App() {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
socket.emit("checkUserToken", {
|
socket.emit("checkUserToken", {
|
||||||
token: getLocalStorage("auth"),
|
token: getLocalStorage("auth") || tokenParams,
|
||||||
shopId,
|
shopId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -236,24 +247,23 @@ function App() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on("transaction_confirmed", async (data) => {
|
socket.on("transaction_confirmed", async (data) => {
|
||||||
console.log("transaction notification: " + data);
|
console.log(JSON.stringify(data));
|
||||||
setModal("transaction_confirmed", data);
|
setModal("transaction_confirmed", data);
|
||||||
|
|
||||||
localStorage.setItem('cart', []);
|
localStorage.setItem('cart', []);
|
||||||
|
|
||||||
const startTime = Date.now(); // Capture the start time
|
// const startTime = Date.now(); // Capture the start time
|
||||||
const timeout = 10000; // 10 seconds timeout in milliseconds
|
// const timeout = 10000; // 10 seconds timeout in milliseconds
|
||||||
|
|
||||||
calculateTotalsFromLocalStorage();
|
calculateTotalsFromLocalStorage();
|
||||||
|
|
||||||
while (localStorage.getItem("lastTransaction") === null) {
|
// while (localStorage.getItem("lastTransaction") === null) {
|
||||||
if (Date.now() - startTime > timeout) {
|
// if (Date.now() - startTime > timeout) {
|
||||||
return; // Exit the function and don't proceed further
|
// return; // Exit the function and don't proceed further
|
||||||
}
|
// }
|
||||||
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second
|
||||||
|
// }
|
||||||
|
|
||||||
// If 'lastTransaction' exists, proceed
|
// If 'lastTransaction' exists, proceed
|
||||||
const lastTransaction = JSON.parse(localStorage.getItem("lastTransaction"));
|
const lastTransaction = JSON.parse(localStorage.getItem("lastTransaction"));
|
||||||
@@ -270,17 +280,23 @@ function App() {
|
|||||||
setModal("transaction_success", data);
|
setModal("transaction_success", data);
|
||||||
|
|
||||||
// If 'lastTransaction' exists, proceed
|
// If 'lastTransaction' exists, proceed
|
||||||
localStorage.removeItem("lastTransaction");
|
if (localStorage.getItem("lastTransaction")) {
|
||||||
|
|
||||||
if (lastTransaction != null) {
|
|
||||||
setLastTransaction(null);
|
setLastTransaction(null);
|
||||||
console.log('remove last transaction')
|
localStorage.removeItem("lastTransaction");
|
||||||
|
window.dispatchEvent(new Event("localStorageUpdated"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("transaction_end", async (data) => {
|
socket.on("transaction_end", async (data) => {
|
||||||
console.log("transaction notification");
|
console.log("transaction notification");
|
||||||
setModal("transaction_end", data);
|
setModal("transaction_end", data);
|
||||||
|
|
||||||
|
// If 'lastTransaction' exists, proceed
|
||||||
|
if (localStorage.getItem("lastTransaction")) {
|
||||||
|
setLastTransaction(null);
|
||||||
|
localStorage.removeItem("lastTransaction");
|
||||||
|
window.dispatchEvent(new Event("localStorageUpdated"));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("payment_claimed", async (data) => {
|
socket.on("payment_claimed", async (data) => {
|
||||||
@@ -289,8 +305,15 @@ function App() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on("transaction_failed", async (data) => {
|
socket.on("transaction_failed", async (data) => {
|
||||||
console.log("transaction notification");
|
console.log(JSON.stringify(data));
|
||||||
setModal("transaction_failed", data);
|
setModal("transaction_failed", data);
|
||||||
|
|
||||||
|
// If 'lastTransaction' exists, proceed
|
||||||
|
if (localStorage.getItem("lastTransaction")) {
|
||||||
|
setLastTransaction(null);
|
||||||
|
localStorage.removeItem("lastTransaction");
|
||||||
|
window.dispatchEvent(new Event("localStorageUpdated"));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -324,7 +347,7 @@ function App() {
|
|||||||
setDeviceType("guestDevice");
|
setDeviceType("guestDevice");
|
||||||
} else {
|
} else {
|
||||||
console.log(data)
|
console.log(data)
|
||||||
if(data.data.user.cafeId != null) navigate(`/${data.data.user.cafeIdentityName}`, { replace: true });
|
if (data.data.user.cafeId != null) navigate(`/${data.data.user.cafeIdentityName}`, { replace: true });
|
||||||
setUser(data.data.user);
|
setUser(data.data.user);
|
||||||
if (data.data.latestOpenBillTransaction != null) localStorage.setItem('lastTransaction', JSON.stringify(data.data.latestOpenBillTransaction))
|
if (data.data.latestOpenBillTransaction != null) localStorage.setItem('lastTransaction', JSON.stringify(data.data.latestOpenBillTransaction))
|
||||||
if (
|
if (
|
||||||
@@ -378,30 +401,32 @@ function App() {
|
|||||||
};
|
};
|
||||||
}, [socket, shopId]);
|
}, [socket, shopId]);
|
||||||
|
|
||||||
async function checkIfStillViewingOtherTransaction() {
|
async function checkIfStillViewingOtherTransaction(data) {
|
||||||
|
|
||||||
console.log("transaction notification");
|
console.log("transaction notification");
|
||||||
console.log(modalContent);
|
console.log(modalContent);
|
||||||
|
|
||||||
let response;
|
let response;
|
||||||
response = await getTransactionsFromCafe(shopId, 0, true);
|
response = await getTransactionsFromCafe(shopId, 0, true);
|
||||||
transactionList.current = response;
|
|
||||||
console.log(response);
|
console.log(response);
|
||||||
|
|
||||||
// Get current URL's search parameters inside the socket event handler
|
// Get current URL's search parameters inside the socket event handler
|
||||||
const searchParams = new URLSearchParams(location.search);
|
const searchParams = new URLSearchParams(location.search);
|
||||||
let transaction_info = searchParams.get("transactionId") || ''; // Get transactionId or set it to empty string
|
let transaction_info = searchParams.get("transactionId") || ''; // Get transactionId or set it to empty string
|
||||||
console.log(transaction_info); // Log the updated transaction_info
|
|
||||||
|
|
||||||
|
if(response[0].transactionId != transaction_info) transactionList.current = response;
|
||||||
|
|
||||||
let depthh = transactionList.current.findIndex(
|
let depthh = transactionList.current.findIndex(
|
||||||
item => item.transactionId.toString() === transaction_info.toString()
|
item => item.transactionId.toString() === transaction_info.toString()
|
||||||
);
|
);
|
||||||
if(depthh == 0 && transaction_info.toString() != '') depthh = 1;
|
|
||||||
|
if (transaction_info != response[0].transactionId)
|
||||||
setDepth(depthh);
|
setDepth(depthh);
|
||||||
|
else setModal("new_transaction", data);
|
||||||
|
|
||||||
console.log(transaction_info == response[0].transactionId)
|
console.log(transaction_info == response[0].transactionId)
|
||||||
// If transaction_info is an empty string, set the modal
|
// If transaction_info is an empty string, set the modal
|
||||||
if (transaction_info.toString() == '' || transaction_info.toString() == response[0].transactionId) return false;
|
if (transaction_info.toString() == '') return false;
|
||||||
else return true;
|
else return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,12 +434,15 @@ function App() {
|
|||||||
// This will ensure that searchParams and transaction_info get updated on each render
|
// This will ensure that searchParams and transaction_info get updated on each render
|
||||||
socket.on("transaction_created", async (data) => {
|
socket.on("transaction_created", async (data) => {
|
||||||
console.log("transaction notification");
|
console.log("transaction notification");
|
||||||
const isViewingOtherTransaction = await checkIfStillViewingOtherTransaction();
|
setNewTransaction(data);
|
||||||
|
|
||||||
|
if(!location.pathname.endsWith('/transactions')){
|
||||||
|
const isViewingOtherTransaction = await checkIfStillViewingOtherTransaction(data);
|
||||||
// If transaction_info is an empty string, set the modal
|
// If transaction_info is an empty string, set the modal
|
||||||
if (!isViewingOtherTransaction) {
|
if (!isViewingOtherTransaction) {
|
||||||
setModal("new_transaction", data);
|
setModal("new_transaction", data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Show browser notification
|
// Show browser notification
|
||||||
let permission = Notification.permission;
|
let permission = Notification.permission;
|
||||||
if (permission !== "granted") return;
|
if (permission !== "granted") return;
|
||||||
@@ -429,12 +457,15 @@ function App() {
|
|||||||
socket.on("transaction_canceled", async (data) => {
|
socket.on("transaction_canceled", async (data) => {
|
||||||
console.log("transaction notification");
|
console.log("transaction notification");
|
||||||
|
|
||||||
const isViewingOtherTransaction = await checkIfStillViewingOtherTransaction();
|
setNewTransaction(data);
|
||||||
|
if(location.pathname != '/transactions'){
|
||||||
|
const isViewingOtherTransaction = await checkIfStillViewingOtherTransaction(data);
|
||||||
// If transaction_info is an empty string, set the modal
|
// If transaction_info is an empty string, set the modal
|
||||||
if (!isViewingOtherTransaction) {
|
if (!isViewingOtherTransaction) {
|
||||||
setModal("new_transaction", data);
|
setModal("new_transaction", data);
|
||||||
navigate(`?transactionId=${data.transactionId}`, { replace: true });
|
navigate(`?transactionId=${data.transactionId}`, { replace: true });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Clean up the socket event listener on unmount or when dependencies change
|
// Clean up the socket event listener on unmount or when dependencies change
|
||||||
@@ -444,17 +475,6 @@ function App() {
|
|||||||
};
|
};
|
||||||
}, [socket, shopId, location]); // Ensure location is in the dependencies to respond to changes in the URL
|
}, [socket, shopId, location]); // Ensure location is in the dependencies to respond to changes in the URL
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (user.cafeId != null && user.cafeId !== shopId) {
|
|
||||||
// // Preserve existing query parameters
|
|
||||||
// const currentParams = new URLSearchParams(location.search).toString();
|
|
||||||
|
|
||||||
// // Navigate to the new cafeId while keeping existing params
|
|
||||||
// navigate(`/${user.cafeId}?${currentParams}`, { replace: true });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }, [user, shopId]);
|
|
||||||
|
|
||||||
function handleMoveToTransaction(direction, from) {
|
function handleMoveToTransaction(direction, from) {
|
||||||
console.log(direction);
|
console.log(direction);
|
||||||
console.log(from);
|
console.log(from);
|
||||||
@@ -472,7 +492,7 @@ function App() {
|
|||||||
: from; // If already at the end, stay on the current transactionId
|
: from; // If already at the end, stay on the current transactionId
|
||||||
} else if (direction === 'previous') {
|
} else if (direction === 'previous') {
|
||||||
|
|
||||||
setDepth(currentIndex -1);
|
setDepth(currentIndex - 1);
|
||||||
// If we're not at the first transaction, get the previous transactionId
|
// If we're not at the first transaction, get the previous transactionId
|
||||||
newTransactionId = currentIndex > 0
|
newTransactionId = currentIndex > 0
|
||||||
? transactionList.current[currentIndex - 1].transactionId
|
? transactionList.current[currentIndex - 1].transactionId
|
||||||
@@ -683,36 +703,6 @@ function App() {
|
|||||||
totalPrice={totalPrice}
|
totalPrice={totalPrice}
|
||||||
lastTransaction={lastTransaction}
|
lastTransaction={lastTransaction}
|
||||||
/>
|
/>
|
||||||
{/* <Footer
|
|
||||||
showTable={true}
|
|
||||||
shopId={shopIdentifier}
|
|
||||||
table={table}
|
|
||||||
cartItemsLength={totalItemsCount}
|
|
||||||
selectedPage={0}
|
|
||||||
/> */}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="/:shopIdentifier/:tableCode?/search"
|
|
||||||
element={
|
|
||||||
<>
|
|
||||||
<SearchResult
|
|
||||||
cafeId={shopId}
|
|
||||||
sendParam={handleSetParam}
|
|
||||||
user={user}
|
|
||||||
shopItems={shopItems}
|
|
||||||
guestSides={guestSides}
|
|
||||||
guestSideOfClerk={guestSideOfClerk}
|
|
||||||
removeConnectedGuestSides={rmConnectedGuestSides}
|
|
||||||
setModal={setModal} // Pass the function to open modal
|
|
||||||
/>
|
|
||||||
{/* <Footer
|
|
||||||
shopId={shopIdentifier}
|
|
||||||
table={table}
|
|
||||||
cartItemsLength={totalItemsCount}
|
|
||||||
selectedPage={1}
|
|
||||||
/> */}
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -732,12 +722,6 @@ function App() {
|
|||||||
shopItems={shopItems}
|
shopItems={shopItems}
|
||||||
setShopItems={setShopItems}
|
setShopItems={setShopItems}
|
||||||
/>
|
/>
|
||||||
{/* <Footer
|
|
||||||
shopId={shopIdentifier}
|
|
||||||
table={table}
|
|
||||||
cartItemsLength={totalItemsCount}
|
|
||||||
selectedPage={2}
|
|
||||||
/> */}
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -771,6 +755,8 @@ function App() {
|
|||||||
sendParam={handleSetParam}
|
sendParam={handleSetParam}
|
||||||
deviceType={deviceType}
|
deviceType={deviceType}
|
||||||
paymentUrl={shop.qrPayment}
|
paymentUrl={shop.qrPayment}
|
||||||
|
setModal={setModal}
|
||||||
|
newTransaction={newTransaction}
|
||||||
/>
|
/>
|
||||||
{/* <Footer
|
{/* <Footer
|
||||||
shopId={shopIdentifier}
|
shopId={shopIdentifier}
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ const App = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const shopId = window.location.pathname.split('/')[1]; // Get shopId from the URL
|
const shopId = window.location.pathname.split('/')[1]; // Get shopId from the URL
|
||||||
const userId = localStorage.getItem('userId');
|
const user_id = localStorage.getItem('user_id');
|
||||||
|
|
||||||
// Connect to Socket.IO if userId is present
|
// Connect to Socket.IO if user_id is present
|
||||||
// if (userId) {
|
// if (user_id) {
|
||||||
// connectSocket(shopId, 1);
|
// connectSocket(shopId, 1);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|||||||
@@ -23,41 +23,50 @@ const DailyCharts = ({ incomeGraph, transactionGraph, materialGraph, colors, typ
|
|||||||
"21-24",
|
"21-24",
|
||||||
];
|
];
|
||||||
console.log(dayData)
|
console.log(dayData)
|
||||||
|
const sumSold = (transactions) =>
|
||||||
|
Array.isArray(transactions) ? transactions.reduce((acc, t) => acc + t.sold, 0) : transactions.transaction || 0;
|
||||||
|
|
||||||
|
const sumTotal = (transactions) =>
|
||||||
|
Array.isArray(transactions) ? transactions.reduce((acc, t) => acc + t.totalPrice, 0) : transactions.income || 0;
|
||||||
|
|
||||||
|
const sumOutcome = (transactions) =>
|
||||||
|
Array.isArray(transactions) ? transactions.reduce((acc, t) => acc + t.materialOutcome || t.price, 0) : transactions.outcome || 0;
|
||||||
|
|
||||||
let seriesData = []
|
let seriesData = []
|
||||||
if(graphFilter == 'transactions'){
|
if (graphFilter == 'transactions') {
|
||||||
seriesData = [
|
seriesData = [
|
||||||
dayData.hour0To3Transactions.reduce((acc, t) => acc + t.sold, 0),
|
sumSold(dayData?.hour0To3Transactions),
|
||||||
dayData.hour3To6Transactions.reduce((acc, t) => acc + t.sold, 0),
|
sumSold(dayData?.hour3To6Transactions),
|
||||||
dayData.hour6To9Transactions.reduce((acc, t) => acc + t.sold, 0),
|
sumSold(dayData?.hour6To9Transactions),
|
||||||
dayData.hour9To12Transactions.reduce((acc, t) => acc + t.sold, 0),
|
sumSold(dayData?.hour9To12Transactions),
|
||||||
dayData.hour12To15Transactions.reduce((acc, t) => acc + t.sold, 0),
|
sumSold(dayData?.hour12To15Transactions),
|
||||||
dayData.hour15To18Transactions.reduce((acc, t) => acc + t.sold, 0),
|
sumSold(dayData?.hour15To18Transactions),
|
||||||
dayData.hour18To21Transactions.reduce((acc, t) => acc + t.sold, 0),
|
sumSold(dayData?.hour18To21Transactions),
|
||||||
dayData.hour21To24Transactions.reduce((acc, t) => acc + t.sold, 0),
|
sumSold(dayData?.hour21To24Transactions),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
else if(graphFilter == 'income'){
|
else if (graphFilter == 'income') {
|
||||||
seriesData = [
|
seriesData = [
|
||||||
dayData.hour0To3Transactions.reduce((acc, t) => acc + t.totalPrice, 0),
|
sumTotal(dayData?.hour0To3Transactions),
|
||||||
dayData.hour3To6Transactions.reduce((acc, t) => acc + t.totalPrice, 0),
|
sumTotal(dayData?.hour3To6Transactions),
|
||||||
dayData.hour6To9Transactions.reduce((acc, t) => acc + t.totalPrice, 0),
|
sumTotal(dayData?.hour6To9Transactions),
|
||||||
dayData.hour9To12Transactions.reduce((acc, t) => acc + t.totalPrice, 0),
|
sumTotal(dayData?.hour9To12Transactions),
|
||||||
dayData.hour12To15Transactions.reduce((acc, t) => acc + t.totalPrice, 0),
|
sumTotal(dayData?.hour12To15Transactions),
|
||||||
dayData.hour15To18Transactions.reduce((acc, t) => acc + t.totalPrice, 0),
|
sumTotal(dayData?.hour15To18Transactions),
|
||||||
dayData.hour18To21Transactions.reduce((acc, t) => acc + t.totalPrice, 0),
|
sumTotal(dayData?.hour18To21Transactions),
|
||||||
dayData.hour21To24Transactions.reduce((acc, t) => acc + t.totalPrice, 0),
|
sumTotal(dayData?.hour21To24Transactions),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
else if(graphFilter == 'outcome'){
|
else if (graphFilter == 'outcome') {
|
||||||
seriesData = [
|
seriesData = [
|
||||||
dayData.hour3To6MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0),
|
sumOutcome(dayData?.hour0To3MaterialIds),
|
||||||
dayData.hour6To9MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0),
|
sumOutcome(dayData?.hour3To6MaterialIds),
|
||||||
dayData.hour0To3MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0),
|
sumOutcome(dayData?.hour6To9MaterialIds),
|
||||||
dayData.hour9To12MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0),
|
sumOutcome(dayData?.hour9To12MaterialIds),
|
||||||
dayData.hour12To15MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0),
|
sumOutcome(dayData?.hour12To15MaterialIds),
|
||||||
dayData.hour15To18MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0),
|
sumOutcome(dayData?.hour15To18MaterialIds),
|
||||||
dayData.hour18To21MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0),
|
sumOutcome(dayData?.hour18To21MaterialIds),
|
||||||
dayData.hour21To24MaterialIds.reduce((acc, t) => acc + t.materialOutcome, 0),
|
sumOutcome(dayData?.hour21To24MaterialIds),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -119,13 +128,13 @@ const DailyCharts = ({ incomeGraph, transactionGraph, materialGraph, colors, typ
|
|||||||
key={indexx}
|
key={indexx}
|
||||||
className={`${styles.dateSelector} ${index === indexx ? styles.dateSelectorActive : styles.dateSelectorInactive
|
className={`${styles.dateSelector} ${index === indexx ? styles.dateSelectorActive : styles.dateSelectorInactive
|
||||||
}`}
|
}`}
|
||||||
style={{position: 'relative' }}
|
style={{ position: 'relative' }}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
type == 'yesterday' && selectedIndex == -1 || type != 'yesterday' && selectedIndex !== index ? setSelectedIndex(index) : setSelectedIndex(-1)
|
type == 'yesterday' && selectedIndex == -1 || type != 'yesterday' && selectedIndex !== index ? setSelectedIndex(index) : setSelectedIndex(-1)
|
||||||
}
|
}
|
||||||
// style={{ backgroundColor: index === indexx ? colors[index % colors.length] : 'transparent' }}
|
// style={{ backgroundColor: index === indexx ? colors[index % colors.length] : 'transparent' }}
|
||||||
>
|
>
|
||||||
<div style={{position: 'absolute', bottom: 0, left: '10%', right: '10%', borderBottom: index == indexx ? `2px solid ${colors[index % colors.length]}` : 'none'}}></div>
|
<div style={{ position: 'absolute', bottom: 0, left: '10%', right: '10%', borderBottom: index == indexx ? `2px solid ${colors[index % colors.length]}` : 'none' }}></div>
|
||||||
<div
|
<div
|
||||||
style={{ color: index === indexx ? 'black' : 'transparent' }}>
|
style={{ color: index === indexx ? 'black' : 'transparent' }}>
|
||||||
{indexx !== chartData.length - 1 ? (
|
{indexx !== chartData.length - 1 ? (
|
||||||
@@ -134,7 +143,7 @@ const DailyCharts = ({ incomeGraph, transactionGraph, materialGraph, colors, typ
|
|||||||
{(indexx === 0 || (formatDate(chartData[indexx - 1].date).month !== month && type != 'weekly')) && month}
|
{(indexx === 0 || (formatDate(chartData[indexx - 1].date).month !== month && type != 'weekly')) && month}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
'Kemarin'
|
'Hari ini'
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ const ProfileImage = styled.img`
|
|||||||
width: 60px;
|
width: 60px;
|
||||||
height: 60px;
|
height: 60px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
object-fit: contain;
|
object-fit: cover;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
z-index: 199;
|
z-index: 199;
|
||||||
animation: ${(props) => {
|
animation: ${(props) => {
|
||||||
@@ -359,7 +359,7 @@ const Header = ({
|
|||||||
{shopId && user.roleId == 1 && (
|
{shopId && user.roleId == 1 && (
|
||||||
<Child onClick={goToAdminCafes}>Dashboard</Child>)}
|
<Child onClick={goToAdminCafes}>Dashboard</Child>)}
|
||||||
{shopId &&
|
{shopId &&
|
||||||
user.userId == shopOwnerId &&
|
user.user_id == shopOwnerId &&
|
||||||
user.username !== undefined &&
|
user.username !== undefined &&
|
||||||
user.roleId === 1 && (
|
user.roleId === 1 && (
|
||||||
<>
|
<>
|
||||||
@@ -368,7 +368,7 @@ const Header = ({
|
|||||||
{shopName}
|
{shopName}
|
||||||
</Child>
|
</Child>
|
||||||
<Child>
|
<Child>
|
||||||
Mode pengembangan
|
Mode Edit
|
||||||
<Switch
|
<Switch
|
||||||
borderRadius={0}
|
borderRadius={0}
|
||||||
checked={isEditMode}
|
checked={isEditMode}
|
||||||
@@ -377,7 +377,7 @@ const Header = ({
|
|||||||
</Child>
|
</Child>
|
||||||
<Child onClick={() => setModal("reports")}>Lihat laporan</Child>
|
<Child onClick={() => setModal("reports")}>Lihat laporan</Child>
|
||||||
<Child onClick={() => setModal("add_material")}>
|
<Child onClick={() => setModal("add_material")}>
|
||||||
Kelola bahan baku
|
Kelola stok
|
||||||
</Child>
|
</Child>
|
||||||
|
|
||||||
<Child hasChildren>
|
<Child hasChildren>
|
||||||
@@ -423,7 +423,7 @@ const Header = ({
|
|||||||
<Child>{shopName}</Child>
|
<Child>{shopName}</Child>
|
||||||
|
|
||||||
<Child>
|
<Child>
|
||||||
Mode pengembangan
|
Mode Edit
|
||||||
<Switch
|
<Switch
|
||||||
borderRadius={0}
|
borderRadius={0}
|
||||||
checked={isEditMode}
|
checked={isEditMode}
|
||||||
@@ -431,7 +431,7 @@ const Header = ({
|
|||||||
/>
|
/>
|
||||||
</Child>
|
</Child>
|
||||||
<Child onClick={() => setModal("add_material")}>
|
<Child onClick={() => setModal("add_material")}>
|
||||||
Kelola bahan baku
|
Kelola stok
|
||||||
</Child>
|
</Child>
|
||||||
|
|
||||||
<Child hasChildren>
|
<Child hasChildren>
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ const Item = ({
|
|||||||
lineHeight: '1rem',
|
lineHeight: '1rem',
|
||||||
justifyContent: 'center'
|
justifyContent: 'center'
|
||||||
}}>
|
}}>
|
||||||
Promo {(((initialPrice - promoPrice) / initialPrice) * 100).toFixed(0)}%
|
Promo
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: 'flex' }}>
|
<div style={{ display: 'flex' }}>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useEffect, useRef } from "react";
|
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 { ThreeDots } from "react-loader-spinner";
|
||||||
|
|
||||||
|
|
||||||
const ItemConfig = ({
|
const ItemConfig = ({
|
||||||
name: initialName,
|
name: initialName,
|
||||||
@@ -24,11 +25,14 @@ const ItemConfig = ({
|
|||||||
const fileInputRef = useRef(null);
|
const fileInputRef = useRef(null);
|
||||||
const textareaRef = useRef(null);
|
const textareaRef = useRef(null);
|
||||||
|
|
||||||
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
// Prevent scrolling when modal is open
|
// Prevent scrolling when modal is open
|
||||||
document.body.style.overflow = "hidden";
|
document.body.style.overflow = "hidden";
|
||||||
if(selectedImage){
|
if (selectedImage) {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onloadend = () => {
|
reader.onloadend = () => {
|
||||||
setPreviewUrl(reader.result);
|
setPreviewUrl(reader.result);
|
||||||
@@ -79,18 +83,27 @@ const ItemConfig = ({
|
|||||||
return () => textarea.removeEventListener("input", handleResize);
|
return () => textarea.removeEventListener("input", handleResize);
|
||||||
}
|
}
|
||||||
}, [textareaRef.current]);
|
}, [textareaRef.current]);
|
||||||
|
const handleCreate = async () => {
|
||||||
|
setIsSaving(true);
|
||||||
|
try {
|
||||||
|
await handleCreateItem(itemName, itemPrice, selectedImage, previewUrl, itemDescription, itemPromoPrice);
|
||||||
|
document.body.style.overflow = "auto";
|
||||||
|
} finally {
|
||||||
|
setIsSaving(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleCreate = () => {
|
const handleUpdate = async () => {
|
||||||
console.log(itemPromoPrice)
|
setIsSaving(true);
|
||||||
handleCreateItem(itemName, itemPrice, selectedImage, previewUrl, itemDescription, itemPromoPrice);
|
try {
|
||||||
document.body.style.overflow = "auto";
|
await handleUpdateItem(itemName, itemPrice, selectedImage, itemDescription, itemPromoPrice);
|
||||||
};
|
|
||||||
const handleUpdate = () => {
|
|
||||||
console.log(itemName, itemPrice, selectedImage, itemDescription, itemPromoPrice)
|
|
||||||
handleUpdateItem(itemName, itemPrice, selectedImage, itemDescription, itemPromoPrice);
|
|
||||||
document.body.style.overflow = "auto";
|
document.body.style.overflow = "auto";
|
||||||
|
} finally {
|
||||||
|
setIsSaving(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
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={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 onClick={handleContentClick} style={{ display: 'flex', flexDirection: 'column', padding: '15px', backgroundColor: 'white', borderRadius: '20px 20px 0 0', overflowY: 'auto' }}>
|
||||||
@@ -131,7 +144,7 @@ const ItemConfig = ({
|
|||||||
transition: 'all 0.3s ease',
|
transition: 'all 0.3s ease',
|
||||||
boxSizing: 'border-box', // Make sure the padding doesn't cause overflow
|
boxSizing: 'border-box', // Make sure the padding doesn't cause overflow
|
||||||
}}
|
}}
|
||||||
onChange={(e)=>setItemName(e.target.value)}
|
onChange={(e) => setItemName(e.target.value)}
|
||||||
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
|
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
|
||||||
onBlur={(e) => e.target.style.borderColor = '#ccc'}
|
onBlur={(e) => e.target.style.borderColor = '#ccc'}
|
||||||
/>
|
/>
|
||||||
@@ -153,7 +166,7 @@ const ItemConfig = ({
|
|||||||
transition: 'all 0.3s ease',
|
transition: 'all 0.3s ease',
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
}}
|
}}
|
||||||
onChange={(e)=>setItemPrice(e.target.value)}
|
onChange={(e) => setItemPrice(e.target.value)}
|
||||||
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
|
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
|
||||||
onBlur={(e) => e.target.style.borderColor = '#ccc'}
|
onBlur={(e) => e.target.style.borderColor = '#ccc'}
|
||||||
/>
|
/>
|
||||||
@@ -174,7 +187,7 @@ const ItemConfig = ({
|
|||||||
transition: 'all 0.3s ease',
|
transition: 'all 0.3s ease',
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
}}
|
}}
|
||||||
onChange={(e)=>setItemPromoPrice(e.target.value)}
|
onChange={(e) => setItemPromoPrice(e.target.value)}
|
||||||
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
|
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
|
||||||
onBlur={(e) => e.target.style.borderColor = '#ccc'}
|
onBlur={(e) => e.target.style.borderColor = '#ccc'}
|
||||||
/>
|
/>
|
||||||
@@ -200,17 +213,40 @@ const ItemConfig = ({
|
|||||||
}}
|
}}
|
||||||
placeholder="Tambah deskripsi..."
|
placeholder="Tambah deskripsi..."
|
||||||
value={itemDescription}
|
value={itemDescription}
|
||||||
onChange={(e)=>setItemDescription(e.target.value)}
|
onChange={(e) => setItemDescription(e.target.value)}
|
||||||
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
|
onFocus={(e) => e.target.style.borderColor = '#60d37e'}
|
||||||
onBlur={(e) => e.target.style.borderColor = '#ccc'}
|
onBlur={(e) => e.target.style.borderColor = '#ccc'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
if (!isSaving) {
|
||||||
|
isBeingEdit ? handleUpdate() : handleCreate();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '40px',
|
||||||
|
alignContent: 'center',
|
||||||
|
textAlign: 'center',
|
||||||
|
borderRadius: '10px',
|
||||||
|
border: '1px solid #60d37e',
|
||||||
|
color: isSaving ? '#aaa' : '#60d37e',
|
||||||
|
backgroundColor: 'white',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
cursor: isSaving ? 'not-allowed' : 'pointer'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isSaving ? (
|
||||||
|
|
||||||
<div style={{ width: '100%', height: '35px', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
<ThreeDots height={20} width={20} />
|
||||||
<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'}
|
isBeingEdit ? 'Simpan' : 'Buat Item'
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -598,7 +598,7 @@ const ItemLister = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{(items.length > 0 ||
|
{(items.length > 0 ||
|
||||||
(user && (user.cafeId == shopId || user.userId == shopOwnerId))) && (
|
(user && (user.cafeId == shopId || user.user_id == shopOwnerId))) && (
|
||||||
<div
|
<div
|
||||||
key={itemTypeId}
|
key={itemTypeId}
|
||||||
className={`${styles["item-lister"]} ${isEdit ? styles["fullscreen"] : ""
|
className={`${styles["item-lister"]} ${isEdit ? styles["fullscreen"] : ""
|
||||||
@@ -713,15 +713,6 @@ const ItemLister = ({
|
|||||||
}
|
}
|
||||||
imageUrl={getImageUrl("uploads/assets/addnew.png")}
|
imageUrl={getImageUrl("uploads/assets/addnew.png")}
|
||||||
/>
|
/>
|
||||||
{/* {typeImage != null && !previewUrl.includes(typeImage) && (
|
|
||||||
<ItemType
|
|
||||||
rectangular={true}
|
|
||||||
onClick={(previewUrl, selectedImage) =>
|
|
||||||
handleImageChange(previewUrl, selectedImage)
|
|
||||||
}
|
|
||||||
imageUrl={getImageUrl(typeImage)}
|
|
||||||
/>
|
|
||||||
)} */}
|
|
||||||
|
|
||||||
<ItemType
|
<ItemType
|
||||||
rectangular={true}
|
rectangular={true}
|
||||||
@@ -857,7 +848,6 @@ const ItemLister = ({
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<button onClick={() => setIsFirstStep(false)} style={{ width: '100%', height: '40px', borderRadius: '20px' }}>selanjutnya</button>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{(isEdit && !isFirstStep || !isEdit) &&
|
{(isEdit && !isFirstStep || !isEdit) &&
|
||||||
@@ -866,7 +856,7 @@ const ItemLister = ({
|
|||||||
<h2 className={styles["item-list-title"]}>{items && items.length < 1 ? 'Buat item' : 'Daftar item'}</h2></div>}
|
<h2 className={styles["item-list-title"]}>{items && items.length < 1 ? 'Buat item' : 'Daftar item'}</h2></div>}
|
||||||
<div className={styles["item-list"]}>
|
<div className={styles["item-list"]}>
|
||||||
{user && (
|
{user && (
|
||||||
user.userId == shopOwnerId || user.cafeId == shopId) &&
|
user.user_id == shopOwnerId || user.cafeId == shopId) &&
|
||||||
isEditMode && (
|
isEditMode && (
|
||||||
<>
|
<>
|
||||||
{!isAddingNewItem && (
|
{!isAddingNewItem && (
|
||||||
@@ -1113,7 +1103,7 @@ const ItemLister = ({
|
|||||||
|
|
||||||
{user &&
|
{user &&
|
||||||
user.roleId == 1 &&
|
user.roleId == 1 &&
|
||||||
user.userId == shopOwnerId &&
|
user.user_id == shopOwnerId &&
|
||||||
isEdit && (
|
isEdit && (
|
||||||
<>
|
<>
|
||||||
{/* <button
|
{/* <button
|
||||||
|
|||||||
@@ -24,60 +24,8 @@
|
|||||||
/* padding: 10px; */
|
/* padding: 10px; */
|
||||||
/* max-height: calc(3 * (25vw - 20px) + 20px); */
|
/* max-height: calc(3 * (25vw - 20px) + 20px); */
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
height: calc(49vw - 20px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-height: 0px) {
|
|
||||||
.grid-container {
|
|
||||||
height: 27vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (min-height: 630px) {
|
|
||||||
.grid-container {
|
|
||||||
height: 27vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (min-height: 636px) {
|
|
||||||
.grid-container {
|
|
||||||
height: 29vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (min-height: 650px) {
|
|
||||||
.grid-container {
|
|
||||||
height: 34vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (min-height: 705px) {
|
|
||||||
.grid-container {
|
|
||||||
height: 37vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (min-height: 735px) {
|
|
||||||
.grid-container {
|
|
||||||
height: 38vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (min-height: 759px) {
|
|
||||||
.grid-container {
|
|
||||||
height: 40vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (min-height: 819px) {
|
|
||||||
.grid-container {
|
|
||||||
height: 44vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-height: 830px) {
|
|
||||||
.grid-container {
|
|
||||||
height: 47vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (min-height: 892px) {
|
|
||||||
.grid-container {
|
|
||||||
height: 49vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-container {
|
.title-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ const ItemTypeLister = ({
|
|||||||
{isEditMode &&
|
{isEditMode &&
|
||||||
!isAddingNewItem &&
|
!isAddingNewItem &&
|
||||||
user && (
|
user && (
|
||||||
user.userId == shopOwnerId || user.cafeId == shopId) && (
|
user.user_id == shopOwnerId || user.cafeId == shopId) && (
|
||||||
<ItemType
|
<ItemType
|
||||||
onClick={toggleAddNewItem}
|
onClick={toggleAddNewItem}
|
||||||
name={"buat baru"}
|
name={"buat baru"}
|
||||||
@@ -111,7 +111,7 @@ const ItemTypeLister = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{user &&(
|
{user &&(
|
||||||
user.userId == shopOwnerId || user.cafeId == shopId) &&
|
user.user_id == shopOwnerId || user.cafeId == shopId) &&
|
||||||
isAddingNewItem && (
|
isAddingNewItem && (
|
||||||
<>
|
<>
|
||||||
<ItemLister
|
<ItemLister
|
||||||
@@ -141,7 +141,7 @@ const ItemTypeLister = ({
|
|||||||
itemTypes.map(
|
itemTypes.map(
|
||||||
(itemType) =>
|
(itemType) =>
|
||||||
(
|
(
|
||||||
itemType.itemList.length > 0 || (user && (user.userId == shopOwnerId || user.cafeId == shopId))) && (
|
itemType.itemList.length > 0 || (user && (user.user_id == shopOwnerId || user.cafeId == shopId))) && (
|
||||||
<ItemType
|
<ItemType
|
||||||
key={itemType.itemTypeId}
|
key={itemType.itemTypeId}
|
||||||
name={itemType.name}
|
name={itemType.name}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ const Modal = ({ user, shop, isOpen, onClose, modalContent, deviceType, setModal
|
|||||||
{modalContent === "create_tenant" && <CreateTenant shopId={shop.cafeId} />}
|
{modalContent === "create_tenant" && <CreateTenant shopId={shop.cafeId} />}
|
||||||
{modalContent === "edit_tables" && <TablesPage shop={shop} />}
|
{modalContent === "edit_tables" && <TablesPage shop={shop} />}
|
||||||
{modalContent === "new_transaction" && (
|
{modalContent === "new_transaction" && (
|
||||||
<Transaction propsShopId={shop.cafeId} handleMoveToTransaction={handleMoveToTransaction} depth={depth} shopImg={shopImg} />
|
<Transaction propsShopId={shop.cafeId} handleMoveToTransaction={handleMoveToTransaction} depth={depth} shopImg={shopImg} setModal={setModal}/>
|
||||||
)}
|
)}
|
||||||
{modalContent === "transaction_canceled" && (
|
{modalContent === "transaction_canceled" && (
|
||||||
<Transaction propsShopId={shop.cafeId} />
|
<Transaction propsShopId={shop.cafeId} />
|
||||||
|
|||||||
@@ -36,3 +36,4 @@
|
|||||||
.closeButton:hover {
|
.closeButton:hover {
|
||||||
color: #f44336; /* Change color on hover for better UX */
|
color: #f44336; /* Change color on hover for better UX */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -479,7 +479,7 @@ export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLo
|
|||||||
className={`expandable-container ${expanded ? "expanded" : ""}`}
|
className={`expandable-container ${expanded ? "expanded" : ""}`}
|
||||||
ref={expandableContainerRef}
|
ref={expandableContainerRef}
|
||||||
>
|
>
|
||||||
{user.cafeId == shopId || user.userId == shopOwnerId && (
|
{user.cafeId == shopId || user.user_id == shopOwnerId && (
|
||||||
<>
|
<>
|
||||||
<div className="auth-box">
|
<div className="auth-box">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -106,10 +106,10 @@ export async function getCafeByIdentifier(cafeIdentifyName) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export async function getOwnedCafes(userId) {
|
export async function getOwnedCafes(user_id) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${API_BASE_URL}/cafe/get-cafe-by-ownerId/` + userId,
|
`${API_BASE_URL}/cafe/get-cafe-by-ownerId/` + user_id,
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ import { MusicPlayer } from "../components/MusicPlayer";
|
|||||||
import ItemLister from "../components/ItemLister";
|
import ItemLister from "../components/ItemLister";
|
||||||
import Header from "../components/Header";
|
import Header from "../components/Header";
|
||||||
|
|
||||||
|
import Switch from "react-switch";
|
||||||
|
|
||||||
import { ThreeDots } from "react-loader-spinner";
|
import { ThreeDots } from "react-loader-spinner";
|
||||||
|
|
||||||
import { getLocalStorage, updateLocalStorage, removeLocalStorage } from "../helpers/localStorageHelpers";
|
import { getLocalStorage, updateLocalStorage, removeLocalStorage } from "../helpers/localStorageHelpers";
|
||||||
@@ -77,17 +79,28 @@ function CafePage({
|
|||||||
|
|
||||||
const [beingEditedType, setBeingEditedType] = useState(0);
|
const [beingEditedType, setBeingEditedType] = useState(0);
|
||||||
|
|
||||||
const checkWelcomePageConfig = () => {
|
// const checkWelcomePageConfig = () => {
|
||||||
const parsedConfig = JSON.parse(welcomePageConfig);
|
// const parsedConfig = JSON.parse(welcomePageConfig);
|
||||||
if (parsedConfig.isWelcomePageActive == "true") {
|
// if (parsedConfig.isWelcomePageActive == "true") {
|
||||||
const clicked = sessionStorage.getItem("getStartedClicked");
|
// const clicked = sessionStorage.getItem("getStartedClicked");
|
||||||
if (!clicked) {
|
// if (!clicked) {
|
||||||
sessionStorage.setItem("getStartedClicked", true);
|
// sessionStorage.setItem("getStartedClicked", true);
|
||||||
document.body.style.overflow = "hidden";
|
// document.body.style.overflow = "hidden";
|
||||||
setIsStarted(true);
|
// setIsStarted(true);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (window.gtag && shopIdentifier) {
|
||||||
|
window.gtag('event', 'page_view', {
|
||||||
|
page_title: `Cafe - ${shopIdentifier}`,
|
||||||
|
page_location: window.location.href,
|
||||||
|
page_path: `/` + shopIdentifier,
|
||||||
|
shop_id: shopId || null, // opsional jika kamu mau track ID juga
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}, [shopIdentifier]);
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (welcomePageConfig) {
|
if (welcomePageConfig) {
|
||||||
@@ -100,16 +113,16 @@ function CafePage({
|
|||||||
isActive: parsedConfig.isWelcomePageActive === "true",
|
isActive: parsedConfig.isWelcomePageActive === "true",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
checkWelcomePageConfig();
|
// checkWelcomePageConfig();
|
||||||
}, [welcomePageConfig]);
|
}, [welcomePageConfig]);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function fetchData() {
|
function fetchData() {
|
||||||
console.log(user.userId == shopOwnerId)
|
console.log(user.user_id == shopOwnerId)
|
||||||
setModal("create_item");
|
setModal("create_item");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(getLocalStorage('auth'))
|
console.log(getLocalStorage('auth'))
|
||||||
if (getLocalStorage("auth") != null) {
|
if (getLocalStorage("auth") != null) {
|
||||||
const executeFetch = async () => {
|
const executeFetch = async () => {
|
||||||
@@ -118,7 +131,7 @@ function CafePage({
|
|||||||
}
|
}
|
||||||
console.log(user)
|
console.log(user)
|
||||||
console.log('open')
|
console.log('open')
|
||||||
if (user.length != 0 && user.userId == shopOwnerId && shopItems.length == 0) fetchData();
|
if (user.length != 0 && user.user_id == shopOwnerId && shopItems.length == 0) fetchData();
|
||||||
};
|
};
|
||||||
executeFetch();
|
executeFetch();
|
||||||
}
|
}
|
||||||
@@ -141,7 +154,7 @@ function CafePage({
|
|||||||
socket.on("joined-room", (response) => {
|
socket.on("joined-room", (response) => {
|
||||||
const { isSpotifyNeedLogin, isExceededDeadline } = response;
|
const { isSpotifyNeedLogin, isExceededDeadline } = response;
|
||||||
setNeedSpotifyLogin(isSpotifyNeedLogin);
|
setNeedSpotifyLogin(isSpotifyNeedLogin);
|
||||||
if (isExceededDeadline) setModal("message",{captMessage:'Kafe sedang tidak tersedia'});
|
if (isExceededDeadline) setModal("message", { captMessage: 'Kafe sedang tidak tersedia' });
|
||||||
setIsExceededDeadline(isExceededDeadline);
|
setIsExceededDeadline(isExceededDeadline);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -243,8 +256,31 @@ function CafePage({
|
|||||||
isSpotifyNeedLogin={isSpotifyNeedLogin}
|
isSpotifyNeedLogin={isSpotifyNeedLogin}
|
||||||
queue={queue}
|
queue={queue}
|
||||||
setModal={setModal}
|
setModal={setModal}
|
||||||
|
/>{
|
||||||
|
user.username !== undefined &&
|
||||||
|
(user.cafeId === shopId || user.user_id === shopOwnerId) &&
|
||||||
|
(user.roleId === 1 || user.roleId === 2) && (
|
||||||
|
<div style={{
|
||||||
|
backgroundColor: '#5c7c5c',
|
||||||
|
padding: '7px 28px',
|
||||||
|
margin: '0 10px',
|
||||||
|
borderRadius: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
textShadow: '2px 2px 4px rgba(0, 0, 0, 0.7)',
|
||||||
|
fontSize: '16px'
|
||||||
|
}}>
|
||||||
|
Mode Edit
|
||||||
|
<Switch
|
||||||
|
borderRadius={0}
|
||||||
|
checked={isEditMode}
|
||||||
|
onChange={() => setIsEditMode(!isEditMode)}
|
||||||
/>
|
/>
|
||||||
<div></div>
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
<ItemTypeLister
|
<ItemTypeLister
|
||||||
user={user}
|
user={user}
|
||||||
shopOwnerId={shopOwnerId}
|
shopOwnerId={shopOwnerId}
|
||||||
@@ -369,7 +405,7 @@ function CafePage({
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Watermark/>
|
<Watermark />
|
||||||
</div>
|
</div>
|
||||||
{/* )} */}
|
{/* )} */}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -444,6 +444,18 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className={styles.NoteContainer}>
|
<div className={styles.NoteContainer}>
|
||||||
|
<span>Atas Nama :</span>
|
||||||
|
<span></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.NoteContainer} >
|
||||||
|
<input
|
||||||
|
className={styles.NoteInput}
|
||||||
|
placeholder="Tambahkan catatan..."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.NoteContainer}style={{height: '18px'}}>
|
||||||
<span>Catatan :</span>
|
<span>Catatan :</span>
|
||||||
<span></span>
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const CreateClerk = ({ shopId }) => {
|
|||||||
try {
|
try {
|
||||||
const create = await createClerks(shopId || cafeIdParam, username, password);
|
const create = await createClerks(shopId || cafeIdParam, username, password);
|
||||||
|
|
||||||
if (create) setMessage('Clerk created successfully');
|
if (create) {setMessage('Clerk created successfully');}
|
||||||
else setMessage('Failed to create clerk');
|
else setMessage('Failed to create clerk');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setMessage('Error creating clerk');
|
setMessage('Error creating clerk');
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const Dashboard = ({ user, setModal }) => {
|
|||||||
// Create admin functionality
|
// Create admin functionality
|
||||||
createCafeOwner(newItem.email, newItem.username, newItem.password)
|
createCafeOwner(newItem.email, newItem.username, newItem.password)
|
||||||
.then((newitem) => {
|
.then((newitem) => {
|
||||||
setItems([...items, { userId: newitem.userId, name: newitem.username }]);
|
setItems([...items, { user_id: newitem.user_id, name: newitem.username }]);
|
||||||
setIsCreating(false);
|
setIsCreating(false);
|
||||||
setNewItem({ name: "", type: "" });
|
setNewItem({ name: "", type: "" });
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -71,9 +71,9 @@ const LinktreePage = ({ user, setModal }) => {
|
|||||||
|
|
||||||
// Handle manual coupon code check
|
// Handle manual coupon code check
|
||||||
const handleGetkCoupons = async () => {
|
const handleGetkCoupons = async () => {
|
||||||
const result = await getUserCoupons();
|
// const result = await getUserCoupons();
|
||||||
setCoupons(result.coupons);
|
// setCoupons(result.coupons);
|
||||||
console.log(result)
|
// console.log(result)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle user transactions
|
// Handle user transactions
|
||||||
@@ -95,24 +95,20 @@ const LinktreePage = ({ user, setModal }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle login
|
const handleLogin = () => {
|
||||||
const handleLogin = async () => {
|
const baseUrl = "https://kediritechnopark.com/";
|
||||||
try {
|
const modal = "product";
|
||||||
setError(false);
|
const productId = 1;
|
||||||
setLoading(true);
|
|
||||||
const response = await loginUser(username, password);
|
const authorizedUri = "https://kedaimaster.com?token=";
|
||||||
if (response.success) {
|
const unauthorizedUri = `${baseUrl}?modal=${modal}&product_id=${productId}`;
|
||||||
localStorage.setItem('auth', response.token);
|
|
||||||
console.log(response)
|
const url =
|
||||||
window.location.href = response.cafeIdentifyName ? `/${response.cafeIdentifyName}` : '/';
|
`${baseUrl}?modal=${modal}&product_id=${productId}` +
|
||||||
} else {
|
`&authorized_uri=${encodeURIComponent(authorizedUri)}` +
|
||||||
setError(true);
|
`&unauthorized_uri=${encodeURIComponent(unauthorizedUri)}`;
|
||||||
}
|
|
||||||
} catch (error) {
|
window.location.href = url;
|
||||||
setError(true);
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle logout
|
// Handle logout
|
||||||
@@ -152,7 +148,7 @@ const LinktreePage = ({ user, setModal }) => {
|
|||||||
try {
|
try {
|
||||||
if (user.roleId < 1) {
|
if (user.roleId < 1) {
|
||||||
const newOwner = await createCafeOwner(newItem.email, newItem.username, newItem.password);
|
const newOwner = await createCafeOwner(newItem.email, newItem.username, newItem.password);
|
||||||
setItems([...items, { userId: newOwner.userId, name: newOwner.username }]);
|
setItems([...items, { user_id: newOwner.user_id, name: newOwner.username }]);
|
||||||
} else {
|
} else {
|
||||||
const newCafe = await createCafe(newItem.name);
|
const newCafe = await createCafe(newItem.name);
|
||||||
setItems([...items, { cafeId: newCafe.cafeId, name: newCafe.name }]);
|
setItems([...items, { cafeId: newCafe.cafeId, name: newCafe.name }]);
|
||||||
@@ -202,7 +198,7 @@ const LinktreePage = ({ user, setModal }) => {
|
|||||||
];
|
];
|
||||||
console.log(items)
|
console.log(items)
|
||||||
|
|
||||||
const selectedItems = items?.items?.find(item => (item.userId || item.cafeId) === selectedItemId);
|
const selectedItems = items?.items?.find(item => (item.user_id || item.cafeId) === selectedItemId);
|
||||||
|
|
||||||
// If the selected tenant is found, extract the cafes
|
// If the selected tenant is found, extract the cafes
|
||||||
const selectedSubItems = selectedItems?.subItems || [];
|
const selectedSubItems = selectedItems?.subItems || [];
|
||||||
@@ -278,7 +274,7 @@ const LinktreePage = ({ user, setModal }) => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
gratis 3 bulan pertama
|
gratis 1 bulan pertama
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div className={styles.mainHeading}>
|
<div className={styles.mainHeading}>
|
||||||
@@ -290,57 +286,20 @@ const LinktreePage = ({ user, setModal }) => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
Gratis 3 bulan pertama
|
Gratis 1 bulan pertama
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div className={styles.subHeading}>
|
<div className={styles.subHeading}>
|
||||||
Solusi berbasis web untuk memudahkan pengelolaan kedai, dengan fitur yang mempermudah pemilik, kasir, dan tamu berinteraksi.
|
Solusi berbasis web untuk memudahkan pengelolaan kedai, dengan fitur yang mempermudah pemilik, kasir, dan tamu berinteraksi.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{getLocalStorage('auth') == null && (
|
|
||||||
<div className={styles.LoginForm}>
|
<div className={styles.LoginForm}>
|
||||||
<div className={`${styles.FormUsername} ${inputtingPassword ? styles.animateForm : wasInputtingPassword ? styles.reverseForm : ''}`}>
|
<div className={`${styles.FormUsername} ${inputtingPassword ? styles.animateForm : wasInputtingPassword ? styles.reverseForm : ''}`}>
|
||||||
<label htmlFor="username" className={styles.usernameLabel}>---- Masuk -----------------------------</label>
|
<button onClick={() => handleLogin()} className={styles.claimButton}>
|
||||||
<input
|
<span>Masuk</span>
|
||||||
id="username"
|
|
||||||
placeholder="username"
|
|
||||||
maxLength="30"
|
|
||||||
className={!error ? styles.usernameInput : styles.usernameInputError}
|
|
||||||
value={username}
|
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
|
||||||
/>
|
|
||||||
<button onClick={() => { setInputtingPassword(true); setWasInputtingPassword(true) }} className={styles.claimButton}>
|
|
||||||
<span>➜</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={`${styles.FormPassword} ${inputtingPassword ? styles.animateForm : wasInputtingPassword ? styles.reverseForm : styles.idleForm}`}>
|
|
||||||
<span>
|
|
||||||
<label onClick={() => setInputtingPassword(false)} htmlFor="password" className={styles.usernameLabel}> <--- <-- Kembali </label>
|
|
||||||
<label htmlFor="password" className={styles.usernameLabel}> ----- </label>
|
|
||||||
<label onClick={() => setModal('reset-password', { username: username })} className={styles.usernameLabel}>
|
|
||||||
lupa password?
|
|
||||||
</label>
|
|
||||||
</span>
|
|
||||||
<input
|
|
||||||
id="password"
|
|
||||||
placeholder="password"
|
|
||||||
type="password"
|
|
||||||
maxLength="30"
|
|
||||||
className={!error ? styles.usernameInput : styles.usernameInputError}
|
|
||||||
value={password}
|
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
onClick={handleLogin}
|
|
||||||
className={`${styles.claimButton} ${loading ? styles.loading : ''}`}
|
|
||||||
disabled={loading}
|
|
||||||
>
|
|
||||||
<span>{loading ? 'Loading...' : 'Masuk'}</span>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
|
||||||
<div className={styles.footer}>
|
<div className={styles.footer}>
|
||||||
<div className={styles.footerLinks}>
|
<div className={styles.footerLinks}>
|
||||||
|
|||||||
@@ -191,7 +191,7 @@
|
|||||||
|
|
||||||
.NoteInput {
|
.NoteInput {
|
||||||
width: 78vw;
|
width: 78vw;
|
||||||
height: 12vw;
|
height: 18px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ const LinktreePage = ({ data, setModal }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles.linktreeForm}>
|
<div className={styles.linktreeForm}>
|
||||||
<button onClick={()=>window.open("https://api.whatsapp.com/send?phone=6281318894994&text=Saya%20ingin%20coba%20gratis%203%20bulan")} className={styles.claimButton}>
|
<button onClick={()=>window.open("https://api.whatsapp.com/send?phone=6281318894994&text=Saya%20ingin%20coba%20gratis%203%20bulan")} className={styles.claimButton}>
|
||||||
<span>Dapatkan voucher gratis 3 bulan</span>
|
<span>Dapatkan voucher gratis 1 bulan</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.footer}>
|
<div className={styles.footer}>
|
||||||
|
|||||||
@@ -338,7 +338,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-top: 2rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.footerLinks {
|
.footerLinks {
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ const SetPaymentQr = ({ cafeId }) => {
|
|||||||
<></>
|
<></>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<h3 className={styles.title}>Bahan baku</h3>
|
<h3 className={styles.title}>Stok</h3>
|
||||||
<Carousel items={materials} onSelect={(e) => setSelectedMaterialIndex(e)} selectedIndex={selectedMaterialIndex} />
|
<Carousel items={materials} onSelect={(e) => setSelectedMaterialIndex(e)} selectedIndex={selectedMaterialIndex} />
|
||||||
{selectedMaterialIndex !== -1 ? (
|
{selectedMaterialIndex !== -1 ? (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -13,10 +13,6 @@ import MultiSwitch from "react-multi-switch-toggle";
|
|||||||
import DailyCharts from '../components/DailyCharts.js';
|
import DailyCharts from '../components/DailyCharts.js';
|
||||||
import PeriodCharts from '../components/PeriodCharts.js';
|
import PeriodCharts from '../components/PeriodCharts.js';
|
||||||
|
|
||||||
import Coupon from "../components/Coupon.js";
|
|
||||||
|
|
||||||
import CreateCouponPage from "./CreateCoupon.js";
|
|
||||||
|
|
||||||
const RoundedRectangle = ({
|
const RoundedRectangle = ({
|
||||||
onClick,
|
onClick,
|
||||||
title,
|
title,
|
||||||
@@ -82,7 +78,7 @@ const RoundedRectangle = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const percentageStyle = {
|
const percentageStyle = {
|
||||||
fontSize: "16px",
|
fontSize: "14px",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
textAlign: "right",
|
textAlign: "right",
|
||||||
@@ -282,11 +278,11 @@ const App = ({ forCafe = true, cafeId = -1,
|
|||||||
if (amount >= 1_000_000_000) {
|
if (amount >= 1_000_000_000) {
|
||||||
// Format for billions
|
// Format for billions
|
||||||
const billions = amount / 1_000_000_000;
|
const billions = amount / 1_000_000_000;
|
||||||
return billions.toFixed(0) + "b"; // No decimal places for billions
|
return billions.toFixed(0) + "m"; // No decimal places for billions
|
||||||
} else if (amount >= 1_000_000) {
|
} else if (amount >= 1_000_000) {
|
||||||
// Format for millions
|
// Format for millions
|
||||||
const millions = amount / 1_000_000;
|
const millions = amount / 1_000_000;
|
||||||
return millions.toFixed(2).replace(/\.00$/, "") + "m"; // Two decimal places, remove trailing '.00'
|
return millions.toFixed(2).replace(/\.00$/, "") + "jt"; // Two decimal places, remove trailing '.00'
|
||||||
} else if (amount >= 1_000) {
|
} else if (amount >= 1_000) {
|
||||||
// Format for thousands
|
// Format for thousands
|
||||||
const thousands = amount / 1_000;
|
const thousands = amount / 1_000;
|
||||||
@@ -312,7 +308,7 @@ const App = ({ forCafe = true, cafeId = -1,
|
|||||||
filterTexts[["yesterday", "weekly", "monthly", "yearly"].indexOf(filter)];
|
filterTexts[["yesterday", "weekly", "monthly", "yearly"].indexOf(filter)];
|
||||||
|
|
||||||
const [resetKey, setResetKey] = useState(0); // A key to force re-render
|
const [resetKey, setResetKey] = useState(0); // A key to force re-render
|
||||||
const [texts, setTexts] = useState(['Buat bisnis']); // initially show only first 3 texts
|
const [texts, setTexts] = useState([]); // initially show only first 3 texts
|
||||||
const [fullTexts, setFullTexts] = useState(null); // initially show only first 3 texts
|
const [fullTexts, setFullTexts] = useState(null); // initially show only first 3 texts
|
||||||
const [fullTextsVisible, setFullTextsVisible] = useState(null); // initially show only first 3 texts
|
const [fullTextsVisible, setFullTextsVisible] = useState(null); // initially show only first 3 texts
|
||||||
|
|
||||||
@@ -322,22 +318,20 @@ const App = ({ forCafe = true, cafeId = -1,
|
|||||||
let updatedFullTexts;
|
let updatedFullTexts;
|
||||||
if (otherCafes.length === 0) {
|
if (otherCafes.length === 0) {
|
||||||
// Only include the role-specific option if user.roleId is 1
|
// Only include the role-specific option if user.roleId is 1
|
||||||
updatedFullTexts = user.roleId == 1 ? [["Buat Bisnis", 0]] : [];
|
updatedFullTexts = user.roleId == 1 ? [[0]] : [];
|
||||||
setSelectedCafeId(-1);
|
setSelectedCafeId(-1);
|
||||||
} else if (otherCafes.length === 1) {
|
} else if (otherCafes.length === 1) {
|
||||||
updatedFullTexts = [
|
updatedFullTexts = [
|
||||||
[otherCafes[0].cafeIdentifyName || otherCafes[0].username, otherCafes[0].cafeId || otherCafes[0].userId],
|
[otherCafes[0].cafeIdentifyName || otherCafes[0].username, otherCafes[0].cafeId || otherCafes[0].user_id],
|
||||||
// Only add the "Buat Bisnis" option for user.roleId == 1
|
|
||||||
...(user.roleId == 1 ? [["Buat Bisnis", -1]] : [])
|
|
||||||
];
|
];
|
||||||
|
|
||||||
setSelectedCafeId(otherCafes[0].cafeId); // Get the cafeId (second part of the pair)
|
setSelectedCafeId(otherCafes[0].cafeId); // Get the cafeId (second part of the pair)
|
||||||
} else {
|
} else {
|
||||||
updatedFullTexts = [
|
updatedFullTexts = [
|
||||||
["semua", 0], // First entry is "semua"
|
["semua", 0], // First entry is "semua"
|
||||||
...otherCafes.map(item => [item.cafeIdentifyName || item.username, item.cafeId || item.userId]), // Map over cafes to get name and cafeId pairs
|
...otherCafes.map(item => [item.cafeIdentifyName || item.username, item.cafeId || item.user_id]), // Map over cafes to get name and cafeId pairs
|
||||||
// Only add "Buat Bisnis +" option for user.roleId == 1
|
|
||||||
...(user.roleId == 1 ? [["Buat Bisnis +", -1]] : [])
|
...(user.roleId == 1 ? [] : [])
|
||||||
];
|
];
|
||||||
|
|
||||||
setSelectedCafeId(0);
|
setSelectedCafeId(0);
|
||||||
@@ -411,10 +405,10 @@ const App = ({ forCafe = true, cafeId = -1,
|
|||||||
|
|
||||||
console.log(analytics)
|
console.log(analytics)
|
||||||
if (user && user.roleId === 0 && analytics) {
|
if (user && user.roleId === 0 && analytics) {
|
||||||
// Filter the analytics items based on userId
|
// Filter the analytics items based on user_id
|
||||||
if(selectedItem[1] != 0 && selectedItem[1] != -1){
|
if (selectedItem[1] != 0 && selectedItem[1] != -1) {
|
||||||
const filteredData = analytics.items.filter(
|
const filteredData = analytics.items.filter(
|
||||||
(data) => data.userId === nextSelectedId
|
(data) => data.user_id === nextSelectedId
|
||||||
);
|
);
|
||||||
|
|
||||||
// Extract coupons from the filtered data
|
// Extract coupons from the filtered data
|
||||||
@@ -511,7 +505,7 @@ const App = ({ forCafe = true, cafeId = -1,
|
|||||||
marginTop: '30px'
|
marginTop: '30px'
|
||||||
}}>
|
}}>
|
||||||
<MultiSwitch
|
<MultiSwitch
|
||||||
texts={["Kemarin", "Minggu ini", "Bulan ini", "Tahun ini"]}
|
texts={["Hari ini", "Minggu ini", "Bulan ini", "Tahun ini"]}
|
||||||
selectedSwitch={["yesterday", "weekly", "monthly", "yearly"].indexOf(
|
selectedSwitch={["yesterday", "weekly", "monthly", "yearly"].indexOf(
|
||||||
filter
|
filter
|
||||||
)}
|
)}
|
||||||
@@ -602,7 +596,7 @@ const App = ({ forCafe = true, cafeId = -1,
|
|||||||
{!forCafe && selectedCafeId != -1 && selectedCafeId != 0 && (
|
{!forCafe && selectedCafeId != -1 && selectedCafeId != 0 && (
|
||||||
<RoundedRectangle
|
<RoundedRectangle
|
||||||
title={"Kunjungi bisnis"}
|
title={"Kunjungi bisnis"}
|
||||||
width= {`calc(${'100%'} - 10px)`}
|
width={`calc(${'100%'} - 10px)`}
|
||||||
height='10px'
|
height='10px'
|
||||||
onClick={() => window.location.href = window.location.origin + '/' + otherCafes.find(item => item.cafeId === selectedCafeId).cafeIdentifyName}
|
onClick={() => window.location.href = window.location.origin + '/' + otherCafes.find(item => item.cafeId === selectedCafeId).cafeIdentifyName}
|
||||||
marginBottom={'0px'}
|
marginBottom={'0px'}
|
||||||
@@ -615,9 +609,11 @@ const App = ({ forCafe = true, cafeId = -1,
|
|||||||
>
|
>
|
||||||
<div style={{ marginRight: "5px", fontSize: "1.2em" }}>ⓘ</div>
|
<div style={{ marginRight: "5px", fontSize: "1.2em" }}>ⓘ</div>
|
||||||
<h6 style={{ margin: 0, textAlign: "left", fontSize: '10px', fontWeight: 500 }}>
|
<h6 style={{ margin: 0, textAlign: "left", fontSize: '10px', fontWeight: 500 }}>
|
||||||
{(filter == 'yesterday' || filter == 'weekly') ?
|
{(filter == 'weekly') ?
|
||||||
`Data dihitung dengan membandingkan
|
`Data dihitung dengan membandingkan
|
||||||
${comparisonText} hari terakhir dengan ${comparisonText} hari sebelumnya, dengan penghitungan dimulai dari data kemarin.`
|
7 hari terakhir dengan 7 hari sebelumnya, dengan penghitungan dimulai dari data kemarin.`
|
||||||
|
:
|
||||||
|
(filter == 'yesterday') ? `Data dihitung dengan membandingkan antara hari ini dan kemarin.`
|
||||||
:
|
:
|
||||||
(filter == 'monthly') ? `Data dihitung dengan membandingkan antara awal hingga akhir bulan ini dan bulan lalu, dengan penghitungan berakhir pada data kemarin.` : `Data dihitung dengan membandingkan antara awal hingga akhir tahun ini dan tahun lalu, dengan penghitungan berakhir pada data kemarin.`}
|
(filter == 'monthly') ? `Data dihitung dengan membandingkan antara awal hingga akhir bulan ini dan bulan lalu, dengan penghitungan berakhir pada data kemarin.` : `Data dihitung dengan membandingkan antara awal hingga akhir tahun ini dan tahun lalu, dengan penghitungan berakhir pada data kemarin.`}
|
||||||
</h6>
|
</h6>
|
||||||
@@ -632,7 +628,7 @@ const App = ({ forCafe = true, cafeId = -1,
|
|||||||
}
|
}
|
||||||
style={{ color: 'black', position: 'relative' }}
|
style={{ color: 'black', position: 'relative' }}
|
||||||
>
|
>
|
||||||
<div>Item laku</div>
|
<div>Penjualan</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`${styles.filterSelector} ${circularFilter == 'material' ? '' : styles.filterSelectorInactive}
|
className={`${styles.filterSelector} ${circularFilter == 'material' ? '' : styles.filterSelectorInactive}
|
||||||
@@ -719,77 +715,6 @@ const App = ({ forCafe = true, cafeId = -1,
|
|||||||
<PeriodCharts type={filter} graphFilter={graphFilter} aggregatedCurrentReports={analytics?.aggregatedCurrentReports} aggregatedPreviousReports={analytics?.aggregatedPreviousReports} colors={colors} />
|
<PeriodCharts type={filter} graphFilter={graphFilter} aggregatedCurrentReports={analytics?.aggregatedCurrentReports} aggregatedPreviousReports={analytics?.aggregatedPreviousReports} colors={colors} />
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
{!forCafe && selectedCafeId == -1 && user.roleId == 1 &&
|
|
||||||
<div style={{
|
|
||||||
textAlign: "center",
|
|
||||||
}}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexWrap: "wrap",
|
|
||||||
justifyContent: "center",
|
|
||||||
padding: "20px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
|
|
||||||
<RoundedRectangle
|
|
||||||
title={"Masukkan nama bisnis"}
|
|
||||||
width="calc(100% - 10px)"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
value={itemName}
|
|
||||||
onChange={(e) => setItemName(e.target.value)}
|
|
||||||
style={{
|
|
||||||
width: '70%',
|
|
||||||
fontSize: '25px',
|
|
||||||
borderRadius: '7px',
|
|
||||||
border: '1px solid black'
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</RoundedRectangle>
|
|
||||||
|
|
||||||
|
|
||||||
<RoundedRectangle
|
|
||||||
title={"Buat Bisnis"}
|
|
||||||
width="calc(100% - 10px)"
|
|
||||||
onClick={handleClick}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
{!forCafe &&
|
|
||||||
<>
|
|
||||||
<div className={`${styles.couponContainer}`}>
|
|
||||||
<div>
|
|
||||||
{!forCafe &&
|
|
||||||
<div className={styles.dateSelectorWrapper} style={{ fontSize: '13px' }}>
|
|
||||||
<div
|
|
||||||
className={`${styles.dateSelector} ${styles.dateSelectorActive}`} style={{ position: 'relative', width: 'calc(32vw - 30px)' }}
|
|
||||||
>
|
|
||||||
<div style={{ position: 'absolute', bottom: 0, left: '10%', right: '10%', borderBottom: `1px solid green` }}></div>
|
|
||||||
<div
|
|
||||||
style={{ color: 'black' }}>
|
|
||||||
Voucher
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ padding: '25px', paddingTop: '0', paddingBottom: '0' }}>
|
|
||||||
{/* <h1>{couponList.length}</h1> */}
|
|
||||||
{couponList && couponList.map((coupon) => {
|
|
||||||
return <Coupon
|
|
||||||
code={coupon?.code || null}
|
|
||||||
value={coupon?.discountValue}
|
|
||||||
period={coupon?.discountPeriods}
|
|
||||||
expiration={coupon?.discountEndDate}
|
|
||||||
/>
|
|
||||||
})}
|
|
||||||
<button className={`${styles.addCoupon}`} onClick={() => setModal('claim-coupon')}>Tambahkan Voucher</button>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { getTables } from "../helpers/tableHelper";
|
|||||||
import TableCanvas from "../components/TableCanvas";
|
import TableCanvas from "../components/TableCanvas";
|
||||||
import { useSearchParams } from "react-router-dom";
|
import { useSearchParams } from "react-router-dom";
|
||||||
|
|
||||||
export default function Transactions({ propsShopId, sendParam, deviceType, handleMoveToTransaction, depth, shopImg }) {
|
export default function Transactions({ propsShopId, sendParam, deviceType, handleMoveToTransaction, depth, shopImg, setModal }) {
|
||||||
const { shopId, tableId } = useParams();
|
const { shopId, tableId } = useParams();
|
||||||
if (sendParam) sendParam({ shopId, tableId });
|
if (sendParam) sendParam({ shopId, tableId });
|
||||||
|
|
||||||
@@ -231,13 +231,29 @@ export default function Transactions({ propsShopId, sendParam, deviceType, handl
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{!transaction.is_paid && transaction.confirmed > -1 &&
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
localStorage.setItem('lastTransaction', JSON.stringify(transaction));
|
||||||
|
setModal("message", { captMessage: 'Silahkan tambahkan pesanan', descMessage: 'Pembayaran akan ditambahkan ke transaksi sebelumnya.' }, null, null);
|
||||||
|
|
||||||
|
// Dispatch the custom event
|
||||||
|
window.dispatchEvent(new Event("localStorageUpdated"));
|
||||||
|
}}
|
||||||
|
className={styles["addNewItem"]}
|
||||||
|
>
|
||||||
|
Tambah pesanan
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<h2 className={styles["Transactions-detail"]}>
|
<h2 className={styles["Transactions-detail"]}>
|
||||||
{transaction.serving_type === "pickup"
|
{transaction.serving_type === "pickup"
|
||||||
? "Ambil sendiri"
|
? "Ambil sendiri"
|
||||||
: `Diantar ke ${transaction.Table ? transaction.Table.tableNo : "N/A"
|
: `Diantar ke ${transaction.Table ? transaction.Table.tableNo : "N/A"
|
||||||
}`}
|
}`}
|
||||||
</h2>
|
</h2>
|
||||||
{transaction.notes != null && (
|
{transaction.notes != '' && (
|
||||||
<>
|
<>
|
||||||
<div className={styles.NoteContainer}>
|
<div className={styles.NoteContainer}>
|
||||||
<span>Note :</span>
|
<span>Note :</span>
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ export default function Transactions({
|
|||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{transaction.payment_type != 'paylater/cash' && transaction.payment_type != 'paylater/cashless' &&
|
{(transaction.payment_type != 'paylater/cash' && transaction.payment_type != 'paylater/cashless') &&
|
||||||
<div
|
<div
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
localStorage.setItem('lastTransaction', JSON.stringify(transaction));
|
localStorage.setItem('lastTransaction', JSON.stringify(transaction));
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import ButtonWithReplica from "../components/ButtonWithReplica";
|
|||||||
dayjs.extend(utc);
|
dayjs.extend(utc);
|
||||||
dayjs.extend(timezone);
|
dayjs.extend(timezone);
|
||||||
|
|
||||||
export default function Transactions({ shop, shopId, propsShopId, sendParam, deviceType, paymentUrl }) {
|
export default function Transactions({ shop, shopId, propsShopId, sendParam, deviceType, paymentUrl, setModal, newTransaction }) {
|
||||||
const { shopIdentifier, tableId } = useParams();
|
const { shopIdentifier, tableId } = useParams();
|
||||||
if (sendParam) sendParam({ shopIdentifier, tableId });
|
if (sendParam) sendParam({ shopIdentifier, tableId });
|
||||||
|
|
||||||
@@ -26,20 +26,22 @@ export default function Transactions({ shop, shopId, propsShopId, sendParam, dev
|
|||||||
const [isPaymentLoading, setIsPaymentLoading] = useState(false);
|
const [isPaymentLoading, setIsPaymentLoading] = useState(false);
|
||||||
const [isPaymentOpen, setIsPaymentOpen] = useState(false);
|
const [isPaymentOpen, setIsPaymentOpen] = useState(false);
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [matchedItems, setMatchedItems] = useState([]);
|
const [matchedItems, setMatchedItems] = useState([]);
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMatchedItems(searchAndAggregateItems(transactions, searchTerm));
|
setMatchedItems(searchAndAggregateItems(transactions, searchTerm));
|
||||||
}, [searchTerm, transactions]);
|
}, [searchTerm, transactions]);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchTransactions = async () => {
|
const fetchTransactions = async () => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
// response = await getMyTransactions(shopId || propsShopId, 5);
|
||||||
|
// setMyTransactions(response);
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
let response = await getTransactionsFromCafe(shopId || propsShopId, 5, false);
|
let response = await getTransactionsFromCafe(shopId || propsShopId, -1, false);
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
if (response) setTransactions(response);
|
if (response) setTransactions(response);
|
||||||
@@ -47,34 +49,40 @@ useEffect(() => {
|
|||||||
console.error("Error fetching transactions:", error);
|
console.error("Error fetching transactions:", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
console.log(deviceType)
|
||||||
fetchTransactions();
|
fetchTransactions();
|
||||||
}, [deviceType]);
|
}, [deviceType, newTransaction]);
|
||||||
|
|
||||||
const calculateTotalPrice = (detailedTransactions) => {
|
const calculateTotalPrice = (detailedTransactions) => {
|
||||||
return detailedTransactions.reduce((total, dt) => {
|
return detailedTransactions.reduce((total, dt) => {
|
||||||
return total + dt.qty * (dt.promoPrice ? dt.promoPrice : dt.price);
|
return total + dt.qty * (dt.promoPrice ? dt.promoPrice : dt.price);
|
||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
const calculateAllTransactionsTotal = (transactions) => {
|
||||||
const calculateAllTransactionsTotal = (transactions) => {
|
return transactions
|
||||||
return transactions.reduce((grandTotal, transaction) => {
|
.filter(transaction => transaction.confirmed > 1) // Filter transactions where confirmed > 1
|
||||||
|
.reduce((grandTotal, transaction) => {
|
||||||
return grandTotal + calculateTotalPrice(transaction.DetailedTransactions);
|
return grandTotal + calculateTotalPrice(transaction.DetailedTransactions);
|
||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
const searchAndAggregateItems = (transactions, searchTerm) => {
|
const searchAndAggregateItems = (transactions, searchTerm) => {
|
||||||
if (!searchTerm.trim()) return [];
|
if (!searchTerm.trim()) return [];
|
||||||
|
|
||||||
const normalizedTerm = searchTerm.trim().toLowerCase();
|
const normalizedTerm = searchTerm.trim().toLowerCase();
|
||||||
|
// Map with key = `${itemId}-${confirmedGroup}` to keep confirmed groups separate
|
||||||
const aggregatedItems = new Map();
|
const aggregatedItems = new Map();
|
||||||
|
|
||||||
transactions.forEach(transaction => {
|
transactions.forEach(transaction => {
|
||||||
|
// Determine confirmed group as a string key
|
||||||
|
const confirmedGroup = transaction.confirmed >= 0 && transaction.confirmed > 1 ? 'confirmed_gt_1' : 'confirmed_le_1';
|
||||||
|
|
||||||
transaction.DetailedTransactions.forEach(detail => {
|
transaction.DetailedTransactions.forEach(detail => {
|
||||||
const itemName = detail.Item.name;
|
const itemName = detail.Item.name;
|
||||||
const itemNameLower = itemName.toLowerCase();
|
const itemNameLower = itemName.toLowerCase();
|
||||||
|
|
||||||
if (itemNameLower.includes(normalizedTerm)) {
|
if (itemNameLower.includes(normalizedTerm)) {
|
||||||
const key = detail.itemId;
|
// Combine itemId and confirmedGroup to keep them separated
|
||||||
|
const key = `${detail.itemId}-${confirmedGroup}`;
|
||||||
|
|
||||||
if (!aggregatedItems.has(key)) {
|
if (!aggregatedItems.has(key)) {
|
||||||
aggregatedItems.set(key, {
|
aggregatedItems.set(key, {
|
||||||
@@ -82,6 +90,7 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
|||||||
name: itemName,
|
name: itemName,
|
||||||
totalQty: 0,
|
totalQty: 0,
|
||||||
totalPrice: 0,
|
totalPrice: 0,
|
||||||
|
confirmedGroup, // Keep track of which group this belongs to
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,11 +100,12 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
console.log(aggregatedItems.values())
|
||||||
return Array.from(aggregatedItems.values());
|
return Array.from(aggregatedItems.values());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleConfirm = async (transactionId) => {
|
const handleConfirm = async (transactionId) => {
|
||||||
setIsPaymentLoading(true);
|
setIsPaymentLoading(true);
|
||||||
try {
|
try {
|
||||||
@@ -103,7 +113,7 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
|||||||
if (result) {
|
if (result) {
|
||||||
setTransactions(prev =>
|
setTransactions(prev =>
|
||||||
prev.map(t =>
|
prev.map(t =>
|
||||||
t.transactionId === transactionId ? { ...t, confirmed: 1 } : t
|
t.transactionId === transactionId ? result : t
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -144,7 +154,7 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
|||||||
return (
|
return (
|
||||||
<div className={styles.Transactions}>
|
<div className={styles.Transactions}>
|
||||||
<h2 className={styles["Transactions-title"]}>
|
<h2 className={styles["Transactions-title"]}>
|
||||||
Daftar transaksi Rp {calculateAllTransactionsTotal(transactions)}
|
Transaksi selesai Rp {calculateAllTransactionsTotal(transactions)}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
@@ -152,17 +162,17 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
|||||||
placeholder="Cari nama item..."
|
placeholder="Cari nama item..."
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
style={{ border:'0px',height: '42px',borderRadius: '15px', margin: '7px auto 10px', width: '88%', paddingLeft: '8px' }}
|
style={{ border: '0px', height: '42px', borderRadius: '15px', margin: '7px auto 10px', width: '88%', paddingLeft: '8px' }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/* Existing Transactions List (keep all your JSX below unchanged) */}
|
{/* Existing Transactions List (keep all your JSX below unchanged) */}
|
||||||
<div className={styles.TransactionListContainer} style={{ padding: '0 8px' }}>
|
<div className={styles.TransactionListContainer} style={{ padding: '0 8px' }}>
|
||||||
|
|
||||||
{matchedItems.length > 0 && matchedItems.map(item => (
|
{matchedItems.length > 0 && matchedItems.map(item => (
|
||||||
<div
|
<div
|
||||||
key={item.itemId}
|
key={`${item.itemId}-${item.confirmedGroup}`}
|
||||||
className={styles.RoundedRectangle}
|
className={styles.RoundedRectangle}
|
||||||
style={{ overflow: "hidden" }}
|
style={{ overflow: "hidden" }}
|
||||||
>
|
>
|
||||||
@@ -176,7 +186,7 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
|||||||
<span>Rp {item.totalPrice}</span>
|
<span>Rp {item.totalPrice}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{transactions &&
|
{transactions &&
|
||||||
transactions.map((transaction) => (
|
transactions.map((transaction) => (
|
||||||
<div
|
<div
|
||||||
@@ -188,7 +198,7 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
|||||||
<div className={styles['receipt-header']}>
|
<div className={styles['receipt-header']}>
|
||||||
{transaction.confirmed === 1 ? (
|
{transaction.confirmed === 1 ? (
|
||||||
<ColorRing className={styles['receipt-logo']} />
|
<ColorRing className={styles['receipt-logo']} />
|
||||||
) : transaction.confirmed === -1 || transaction.confirmed === -2 ? (
|
) : transaction.confirmed === -1 && !transaction.is_paid || transaction.confirmed === -2 && !transaction.is_paid ? (
|
||||||
<div style={{ display: 'flex', justifyContent: 'center', margin: '16px 0px' }}>
|
<div style={{ display: 'flex', justifyContent: 'center', margin: '16px 0px' }}>
|
||||||
<svg
|
<svg
|
||||||
style={{ width: '60px', transform: 'Rotate(45deg)' }}
|
style={{ width: '60px', transform: 'Rotate(45deg)' }}
|
||||||
@@ -205,9 +215,9 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
) : transaction.confirmed === 2 ? (
|
) : transaction.confirmed === 2 && !transaction.is_paid ? (
|
||||||
<ColorRing className={styles['receipt-logo']} />
|
<ColorRing className={styles['receipt-logo']} />
|
||||||
) : transaction.confirmed === 3 ? (
|
) : transaction.confirmed === 3 || transaction.is_paid ? (
|
||||||
<div>
|
<div>
|
||||||
<svg
|
<svg
|
||||||
height="60px"
|
height="60px"
|
||||||
@@ -242,15 +252,15 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
|||||||
|
|
||||||
<div className={styles['receipt-info']}>
|
<div className={styles['receipt-info']}>
|
||||||
{deviceType == 'clerk' ?
|
{deviceType == 'clerk' ?
|
||||||
<h3>{transaction.confirmed === 1 ? (
|
<h3>{transaction.confirmed === 1 && !transaction.is_paid ? (
|
||||||
"Silahkan Cek Pembayaran"
|
"Silahkan Cek Pembayaran"
|
||||||
) : transaction.confirmed === -1 ? (
|
) : transaction.confirmed === -1 && !transaction.is_paid ? (
|
||||||
"Dibatalkan Oleh Kasir"
|
"Dibatalkan Oleh Kasir"
|
||||||
) : transaction.confirmed === -2 ? (
|
) : transaction.confirmed === -2 && !transaction.is_paid ? (
|
||||||
"Dibatalkan Oleh Pelanggan"
|
"Dibatalkan Oleh Pelanggan"
|
||||||
) : transaction.confirmed === 2 ? (
|
) : transaction.confirmed === 2 && !transaction.is_paid ? (
|
||||||
"Sedang Diproses"
|
"Sedang Diproses"
|
||||||
) : transaction.confirmed === 3 ? (
|
) : transaction.confirmed === 3 || transaction.is_paid ? (
|
||||||
"Transaksi Sukses"
|
"Transaksi Sukses"
|
||||||
) : (
|
) : (
|
||||||
"Silahkan Cek Ketersediaan"
|
"Silahkan Cek Ketersediaan"
|
||||||
@@ -299,6 +309,20 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
|||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
{!transaction.is_paid && transaction.confirmed > -1 &&
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
localStorage.setItem('lastTransaction', JSON.stringify(transaction));
|
||||||
|
setModal("message", { captMessage: 'Silahkan tambahkan pesanan', descMessage: 'Pembayaran akan ditambahkan ke transaksi sebelumnya.' }, null, null);
|
||||||
|
|
||||||
|
// Dispatch the custom event
|
||||||
|
window.dispatchEvent(new Event("localStorageUpdated"));
|
||||||
|
}}
|
||||||
|
className={styles["addNewItem"]}
|
||||||
|
>
|
||||||
|
Tambah pesanan
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<h2 className={styles["Transactions-detail"]}>
|
<h2 className={styles["Transactions-detail"]}>
|
||||||
{transaction.serving_type === "pickup"
|
{transaction.serving_type === "pickup"
|
||||||
? "Self pickup"
|
? "Self pickup"
|
||||||
@@ -331,7 +355,7 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.TotalContainer}>
|
<div className={styles.TotalContainer}>
|
||||||
{(deviceType == 'clerk' && (transaction.confirmed == 0 || transaction.confirmed == 1 || transaction.confirmed == 2)) &&
|
{(deviceType == 'clerk' && !transaction.is_paid && (transaction.confirmed == 0 || transaction.confirmed == 1 || transaction.confirmed == 2)) &&
|
||||||
<button
|
<button
|
||||||
className={styles.PayButton}
|
className={styles.PayButton}
|
||||||
onClick={() => handleConfirm(transaction.transactionId)}
|
onClick={() => handleConfirm(transaction.transactionId)}
|
||||||
|
|||||||
Reference in New Issue
Block a user