This commit is contained in:
zadit
2024-12-26 08:58:59 +07:00
parent c6d7ed5aae
commit cf38edac85
17 changed files with 259 additions and 167 deletions

7
package-lock.json generated
View File

@@ -14,6 +14,7 @@
"@testing-library/jest-dom": "^5.17.0", "@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"caniuse-lite": "^1.0.30001690",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"jsqr": "^1.4.0", "jsqr": "^1.4.0",
"qrcode.react": "^3.1.0", "qrcode.react": "^3.1.0",
@@ -6723,9 +6724,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001636", "version": "1.0.30001690",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz",
"integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==", "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",

View File

@@ -2,6 +2,7 @@
"name": "groovebrew-mockup", "name": "groovebrew-mockup",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"homepage": ".",
"dependencies": { "dependencies": {
"@emotion/react": "^11.13.3", "@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0", "@emotion/styled": "^11.13.0",
@@ -9,6 +10,7 @@
"@testing-library/jest-dom": "^5.17.0", "@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"caniuse-lite": "^1.0.30001690",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"jsqr": "^1.4.0", "jsqr": "^1.4.0",
"qrcode.react": "^3.1.0", "qrcode.react": "^3.1.0",

View File

@@ -204,11 +204,6 @@ function App() {
setModal("transaction_failed", data); setModal("transaction_failed", data);
}); });
socket.on("transaction_canceled", async (data) => {
console.log("transaction notification");
setModal("transaction_canceled", data);
});
const checkNotifications = () => { const checkNotifications = () => {
let permission = Notification.permission; let permission = Notification.permission;
@@ -280,24 +275,34 @@ function App() {
socket.off("signout-guest-session"); socket.off("signout-guest-session");
}; };
}, [socket, shopId]); }, [socket, shopId]);
async function checkIfStillViewingOtherTransaction(){
console.log("transaction notification");
console.log(modalContent);
let response;
response = await getTransactionsFromCafe(shopId, 0, true);
transactionList.current = response;
console.log(response);
// Get current URL's search parameters inside the socket event handler
const searchParams = new URLSearchParams(location.search);
let transaction_info = searchParams.get("transactionId") || ''; // Get transactionId or set it to empty string
console.log(transaction_info); // Log the updated transaction_info
// If transaction_info is an empty string, set the modal
if (transaction_info == '') return false;
else return true;
}
useEffect(() => { useEffect(() => {
// 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");
console.log(modalContent); const isViewingOtherTransaction = await checkIfStillViewingOtherTransaction();
let response;
response = await getTransactionsFromCafe(shopId, 0, true);
console.log(data);
transactionList.current = response;
// Get current URL's search parameters inside the socket event handler
const searchParams = new URLSearchParams(location.search);
let transaction_info = searchParams.get("transactionId") || ''; // Get transactionId or set it to empty string
console.log(transaction_info); // Log the updated transaction_info
// If transaction_info is an empty string, set the modal // If transaction_info is an empty string, set the modal
if (transaction_info === '') { if (!isViewingOtherTransaction) {
setModal("new_transaction", data); setModal("new_transaction", data);
} }
@@ -312,9 +317,20 @@ function App() {
}); });
}); });
socket.on("transaction_canceled", async (data) => {
console.log("transaction notification");
const isViewingOtherTransaction = await checkIfStillViewingOtherTransaction();
// If transaction_info is an empty string, set the modal
if (!isViewingOtherTransaction) {
setModal("new_transaction", data);
}
});
// Clean up the socket event listener on unmount or when dependencies change // Clean up the socket event listener on unmount or when dependencies change
return () => { return () => {
socket.off("transaction_created"); socket.off("transaction_created");
socket.off("transaction_canceled");
}; };
}, [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

View File

@@ -190,28 +190,32 @@ const ChildWrapper = styled.div`
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
`; `;
const Child = styled.div` const Child = styled.div`
width: 100%; width: 100%;
height: 40px; height: 40px;
margin: 5px; margin: 5px;
background-color: rgba(88, 55, 50, 0.2);
border-top-left-radius: 5px; border-top-left-radius: 5px;
border-bottom-left-radius: 5px; border-bottom-left-radius: 5px;
padding-top: 10px;
padding-left: 5px; padding-left: 5px;
font-family: "Poppins", sans-serif; font-family: "Poppins", sans-serif;
font-weight: 500; font-weight: 500;
font-style: normal; font-style: normal;
${(props) => ${(props) =>
props.hasChildren && props.hasChildren
` ? `
height: auto; border: 1px solid #ababab;
padding-bottom: 10px; height: auto;
`} padding-bottom: 10px;
`
: `
display: flex;
align-items: center;
background-color: rgb(223 223 223);
`}
`; `;
const Header = ({ const Header = ({
HeaderText, HeaderText,
HeaderSize='6vw', HeaderSize='6vw',
@@ -343,7 +347,7 @@ const Header = ({
{shopName} {shopName}
<Child> <Child>
Mode edit Mode edit &nbsp;
<Switch <Switch
borderRadius={0} borderRadius={0}
checked={isEditMode} checked={isEditMode}

View File

@@ -144,6 +144,7 @@
margin-left: 5px; margin-left: 5px;
color: #d9c61c; color: #d9c61c;
text-align: right; text-align: right;
margin-top: 22px;
} }
.itemQty { .itemQty {

View File

@@ -90,7 +90,7 @@
background-color: #0000008c; background-color: #0000008c;
width: 100%; width: 100%;
top: 7px; top: 7px;
bottom: -10px; bottom: -4px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;

View File

@@ -16,19 +16,22 @@
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
height: 142px; height: 120px;
/* Adjust height as needed */ /* Adjust height as needed */
background-size: cover; background-size: cover;
/* Adjust background image size */ /* Adjust background image size */
background-position: center; background-position: center;
/* Center the background image */ /* Center the background image */
filter: blur(1.5px); /* filter: blur(1.5px);
-webkit-filter: blur(1.5px); -webkit-filter: blur(1.5px); */
border-radius: 13px 13px 0 0; /* border-radius: 13px 13px 0 0; */
background-color: rgb(95 121 89); background-color: rgb(95 121 89);
/* Rounded corners at the top */ /* Rounded corners at the top */
text-align: right; text-align: right;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7); text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
border-radius: 0 0 15px 15px;
z-index: 1;
} }
.current-name { .current-name {
@@ -73,6 +76,8 @@
font-size: 18px; font-size: 18px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7); text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
/* Text shadow for readability */ /* Text shadow for readability */
margin-bottom: -47px;
} }
.progress-container { .progress-container {
@@ -124,6 +129,17 @@
/* Allow vertical scrolling */ /* Allow vertical scrolling */
} }
.expandable-container > div:first-child {
padding-top: 21px;
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
*/ }
.expand-button { .expand-button {
font-size: 20px; font-size: 20px;
position: relative; position: relative;
@@ -138,7 +154,21 @@
text-align: center; text-align: center;
line-height: 40px; line-height: 40px;
/* Center text vertically */ /* Center text vertically */
}
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
outline: none;
transition: padding-top 0.3s ease;
padding-top: 8px;
}
.expand-button h5 { .expand-button h5 {
font-weight: 500; font-weight: 500;
@@ -146,8 +176,8 @@
text-shadow: 0px 0px 6px rgba(0, 0, 0, 0.36); text-shadow: 0px 0px 6px rgba(0, 0, 0, 0.36);
} }
.expand-button:hover { .expand-button.expanded{
background-color: #73a585; padding-top: 0px;
} }
/* Adjust height of the music player container when expanded */ /* Adjust height of the music player container when expanded */
@@ -224,10 +254,6 @@
/* Adjust fill color */ /* Adjust fill color */
} }
/* Add hover effect for the search icon */
.search-box .search-icon:hover {
color: #555;
}
.rectangle { .rectangle {
position: relative; position: relative;
height: 200px; height: 200px;

View File

@@ -284,16 +284,16 @@ export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLo
const handleSetPlayer = () => { const handleSetPlayer = () => {
const token = localStorage.getItem("auth"); const token = localStorage.getItem("auth");
socket.emit("claimPlayer", {
token,
shopId,
});
if (isSpotifyNeedLogin) { if (isSpotifyNeedLogin) {
socket.emit("claimPlayer", {
token,
shopId,
});
} else { } else {
socket.emit("unClaimPlayer", { // socket.emit("unClaimPlayer", {
token, // token,
shopId, // shopId,
}); // });
} }
}; };
@@ -333,9 +333,9 @@ export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLo
}, [expanded]); }, [expanded]);
const [text, setText] = useState("Awaiting the next hit"); const [text, setText] = useState("Menunggu musik favoritmu");
const textIndex = useRef(0); const textIndex = useRef(0);
const [messages, setMessages] = useState(["Awaiting the next hit", "Click to request your fav song"]); const [messages, setMessages] = useState(["Menunggu musik favoritmu", "Klik untuk putar musik favoritmu"]);
useEffect(() => { useEffect(() => {
@@ -343,8 +343,8 @@ export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLo
const newMessages = [ const newMessages = [
currentSong != null && currentSong.item != undefined currentSong != null && currentSong.item != undefined
? `${currentSong.item.artists[0].name} - ${currentSong.item.name}` ? `${currentSong.item.artists[0].name} - ${currentSong.item.name}`
: "Awaiting the next hit", : "Menunggu musik favoritmu",
"Click to request your fav song" "Klik untuk putar musik favoritmu"
]; ];
setMessages(newMessages); setMessages(newMessages);
@@ -374,9 +374,10 @@ export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLo
<div <div
onClick={toggleView} onClick={toggleView}
className="current-bgr" className="current-bgr"
style={{ backgroundImage: `url(${videoSrc != "" ? '' : backgroundImage})` }} style={{ backgroundImage: `url(${backgroundImage})` }}
// style={{ backgroundImage: `url(${videoSrc != "" ? '' : backgroundImage})` }}
> >
<video {/* <video
ref={videoRef} ref={videoRef}
autoPlay autoPlay
loop loop
@@ -385,7 +386,7 @@ export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLo
style={{ height: '100%', width: '100%', objectFit: 'cover', position: 'absolute', top: 0, right: 0, zIndex: -1 }} style={{ height: '100%', width: '100%', objectFit: 'cover', position: 'absolute', top: 0, right: 0, zIndex: -1 }}
> >
{videoSrc && <source src={videoSrc} type="video/mp4" />} {videoSrc && <source src={videoSrc} type="video/mp4" />}
</video> </video> */}
{currentLines.present.map((line, index) => ( {currentLines.present.map((line, index) => (
<div className="present" style={{ <div className="present" style={{
color: subtitleColor, color: subtitleColor,
@@ -419,7 +420,7 @@ export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLo
currentSong.item.album.images[0] && currentSong.item.album.images[0] &&
currentSong.item.artists[0].name currentSong.item.artists[0].name
? currentSong.item.artists[0].name ? currentSong.item.artists[0].name
: "Drop your hits below"} : "Pilih hits terbaikmu dibawah!"}
</div> </div>
<div className="progress-container"> <div className="progress-container">
<div <div
@@ -457,13 +458,13 @@ export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLo
<input <input
type="text" type="text"
placeholder={ placeholder={
isSpotifyNeedLogin ? "Set as music player" : "Unset as music player" isSpotifyNeedLogin ? "Jadikan perangkat sebagai pemutar musik" : "Unset as music player"
} }
onClick={handleSetPlayer} onClick={handleSetPlayer}
/> />
</div> </div>
)} )}
<div className="search-box"> <div className="search-box" style={{}}>
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" viewBox="0 0 24 24"
@@ -473,7 +474,7 @@ export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLo
</svg> </svg>
<input <input
type="text" type="text"
placeholder="Search..." placeholder="cari..."
value={songName} value={songName}
onChange={handleInputChange} onChange={handleInputChange}
/> />
@@ -490,24 +491,24 @@ export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLo
/> />
))} ))}
{ {
songName === "" && songName === "" &&
queue && queue &&
Array.isArray(queue) && Array.isArray(queue) &&
queue.length > 0 && ( queue.length > 0 && (
queue.map((song, index) => ( queue.map((song, index) => (
<MusicComponent <MusicComponent
key={index} key={index}
song={song} song={song}
min={-100} min={-100}
max={100} max={100}
onDecision={(vote) => onDecision(song.trackId, vote)} onDecision={(vote) => onDecision(song.trackId, vote)}
/> />
)) ))
) )
} }
{songName == "" && queue.length < 1 && ( {songName == "" && queue.length < 1 && (
<div className="rectangle"> <div className="rectangle">
<div className="diagonal-text">No Beats Ahead - Drop Your Hits</div> <div className="diagonal-text">Antrian kosong - Pilih musikmu</div>
</div> </div>
)} )}
{songName == "" && queue.length > 0 && queue.length < 3 && ( {songName == "" && queue.length > 0 && queue.length < 3 && (
@@ -516,11 +517,10 @@ export function MusicPlayer({ socket, shopId, user, shopOwnerId, isSpotifyNeedLo
</div> </div>
)} )}
</div> </div>
<div className="expand-button" onClick={toggleExpand}> <div className={`expand-button ${expanded ? "expanded" : ""}`} onClick={toggleExpand}>
<h5> <h5>
{expanded {expanded? '⋀' : 'Lihat antrian musik'}
? "︿"
: "request your song"}
</h5> </h5>
</div></> </div></>
} }

View File

@@ -141,7 +141,7 @@ const SetPaymentQr = ({ shopId }) => {
</button> </button>
</div> </div>
<div style={styles.switchContainer}> <div style={styles.switchContainer}>
<h1>Pengecekan ketersediaan ganda</h1> <h3>Pengecekan ketersediaan ganda</h3>
<p style={styles.description}> <p style={styles.description}>
Nyalakan agar kasir memeriksa kembali ketersediaan produk sebelum pelanggan membayar. Nyalakan agar kasir memeriksa kembali ketersediaan produk sebelum pelanggan membayar.
</p> </p>

View File

@@ -144,9 +144,11 @@ export default function Invoice({ table, sendParam, deviceType, socket }) {
console.log(localStorage.getItem('cart')) console.log(localStorage.getItem('cart'))
console.log(cartItems) console.log(cartItems)
if(localStorage.getItem('cart') == "[]") return;
// Parse the local storage cart // Parse the local storage cart
const localStorageCart = JSON.parse(localStorage.getItem('cart')); const localStorageCart = JSON.parse(localStorage.getItem('cart'));
console.log(localStorageCart)
// Create a set of itemIds from the local storage cart for quick lookup // Create a set of itemIds from the local storage cart for quick lookup
const localStorageItemIds = new Set(localStorageCart[0].items.map(item => item.itemId)); const localStorageItemIds = new Set(localStorageCart[0].items.map(item => item.itemId));

View File

@@ -1,9 +1,8 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { createClerks } from '../helpers/userHelpers'; // Adjust the import path as needed import { createCafe } from '../helpers/cafeHelpers'; // Adjust the import path as needed
const CreateClerk = ({ shopId }) => { const CreateClerk = ({ shopId }) => {
const [username, setUsername] = useState(''); const [name, setName] = useState('');
const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [message, setMessage] = useState(''); const [message, setMessage] = useState('');
@@ -13,16 +12,16 @@ const CreateClerk = ({ shopId }) => {
setMessage(''); setMessage('');
// Basic validation // Basic validation
if (!username || !password) { if (!name) {
setMessage('Username and password are required'); setMessage('name is required');
setLoading(false); setLoading(false);
return; return;
} }
try { try {
const create = await createClerks(shopId, username, password); const create = await createCafe(name);
if (create) setMessage('Clerk created successfully'); if (create) setMessage('Cafe 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');
@@ -37,16 +36,9 @@ const CreateClerk = ({ shopId }) => {
<form onSubmit={handleSubmit} style={styles.form}> <form onSubmit={handleSubmit} style={styles.form}>
<input <input
type="text" type="text"
placeholder="Username" placeholder="Cafe name"
value={username} value={name}
onChange={(e) => setUsername(e.target.value)} onChange={(e) => setName(e.target.value)}
style={styles.input}
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
style={styles.input} style={styles.input}
/> />
<button type="submit" style={styles.button} disabled={loading}> <button type="submit" style={styles.button} disabled={loading}>

View File

@@ -1,7 +1,8 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { createClerks } from '../helpers/userHelpers'; // Adjust the import path as needed import { createCafeOwner } from '../helpers/userHelpers'; // Adjust the import path as needed
const CreateClerk = ({ shopId }) => { const CreateClerk = () => {
const [email, setEmail] = useState('');
const [username, setUsername] = useState(''); const [username, setUsername] = useState('');
const [password, setPassword] = useState(''); const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -20,7 +21,7 @@ const CreateClerk = ({ shopId }) => {
} }
try { try {
const create = await createClerks(shopId, username, password); const create = await createCafeOwner(email, 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');
@@ -33,8 +34,15 @@ const CreateClerk = ({ shopId }) => {
return ( return (
<div style={styles.container}> <div style={styles.container}>
<h2 style={styles.header}>Tambah Kedai</h2> <h2 style={styles.header}>Tambah Tenant</h2>
<form onSubmit={handleSubmit} style={styles.form}> <form onSubmit={handleSubmit} style={styles.form}>
<input
type="text"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
style={styles.input}
/>
<input <input
type="text" type="text"
placeholder="Username" placeholder="Username"
@@ -50,7 +58,7 @@ const CreateClerk = ({ shopId }) => {
style={styles.input} style={styles.input}
/> />
<button type="submit" style={styles.button} disabled={loading}> <button type="submit" style={styles.button} disabled={loading}>
{loading ? 'Creating...' : 'Create Clerk'} {loading ? 'Creating...' : 'Create Tenant'}
</button> </button>
{message && ( {message && (
<p style={{ ...styles.message, color: message.includes('success') ? 'green' : 'red' }}> <p style={{ ...styles.message, color: message.includes('success') ? 'green' : 'red' }}>

View File

@@ -497,7 +497,7 @@
.cafeListWrapper { .cafeListWrapper {
background-color: white; background-color: white;
border-radius: 20px 20px 0 0; border-radius: 20px 20px 0 0;
top: 83vh; bottom: 0;
position: absolute; position: absolute;
width: 100%; width: 100%;
} }

View File

@@ -138,7 +138,7 @@ export default function Transactions({
<div className={styles['receipt-header']}> <div className={styles['receipt-header']}>
<ColorRing className={styles['receipt-logo']} /> <ColorRing className={styles['receipt-logo']} />
<div className={styles['receipt-info']}> <div className={styles['receipt-info']}>
<h3>silahkan bayar ke kasir</h3> {transaction.payment_type == 'cashless' ? <h3>silahkan bayar QR</h3> : <h3>silahkan bayar ke kasir</h3>}
<p>Transaction ID: {transaction.transactionId}</p> <p>Transaction ID: {transaction.transactionId}</p>
<p>Payment Type: {transaction.payment_type}</p> <p>Payment Type: {transaction.payment_type}</p>
</div> </div>

View File

@@ -5,7 +5,7 @@ import { ColorRing } from "react-loader-spinner";
import { import {
getTransaction, getTransaction,
confirmTransaction, confirmTransaction,
declineTransaction, cancelTransaction,
} 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";
@@ -29,12 +29,24 @@ export default function Transactions({ propsShopId, sendParam, deviceType, handl
try { try {
const fetchedTransaction = await getTransaction(transactionId); const fetchedTransaction = await getTransaction(transactionId);
setTransaction(fetchedTransaction); setTransaction(fetchedTransaction);
console.log(transaction); console.log(fetchedTransaction); // Log the fetched transaction
} catch (error) { } catch (error) {
console.error("Error fetching transaction:", error); console.error("Error fetching transaction:", error);
} }
}; };
fetchData();
const waitForLocalStorage = async () => {
while (localStorage.getItem("auth") === null) {
await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second
}
};
const initialize = async () => {
await waitForLocalStorage();
await fetchData();
};
initialize();
}, [searchParams]); }, [searchParams]);
useEffect(() => { useEffect(() => {
@@ -75,7 +87,7 @@ export default function Transactions({ propsShopId, sendParam, deviceType, handl
if (isPaymentLoading) return; if (isPaymentLoading) return;
setIsPaymentLoading(true); setIsPaymentLoading(true);
try { try {
const c = await declineTransaction(transactionId); const c = await cancelTransaction(transactionId);
// if (c) { // if (c) {
// // Update the confirmed status locally // // Update the confirmed status locally
// setTransactions((prevTransactions) => // setTransactions((prevTransactions) =>
@@ -180,7 +192,7 @@ export default function Transactions({ propsShopId, sendParam, deviceType, handl
<div className={styles.TotalContainer}> <div className={styles.TotalContainer}>
<button <button
className={styles.PayButton} className={styles.PayButton}
onClick={() => handleConfirm(transaction.transactionId)} onClick={() => handleDecline(transaction.transactionId)}
disabled={ disabled={
transaction.confirmed === -1 || transaction.confirmed === -1 ||
transaction.confirmed === 3 || transaction.confirmed === 3 ||

View File

@@ -25,9 +25,9 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
const fetchTransactions = async () => { const fetchTransactions = async () => {
try { try {
let response; let response;
response = await getTransactionsFromCafe(shopId || propsShopId, 5, false); response = await getTransactionsFromCafe(shopId || propsShopId, 5, false);
setTransactions(response); setTransactions(response);
response = await getMyTransactions(shopId || propsShopId, 5); response = await getMyTransactions(shopId || propsShopId, 5);
setMyTransactions(response); setMyTransactions(response);
} catch (error) { } catch (error) {
console.error("Error fetching transactions:", error); console.error("Error fetching transactions:", error);
@@ -101,10 +101,10 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
return ( return (
<div className={styles.Transactions}> <div className={styles.Transactions}>
<div style={{ marginTop: "30px" }}></div> <div style={{ marginTop: "30px" }}></div>
<h2 className={styles["Transactions-title"]}>Transactions</h2> <h2 className={styles["Transactions-title"]}>Daftar transaksi</h2>
<div style={{ marginTop: "30px" }}></div> <div style={{ marginTop: "30px" }}></div>
{/* <TableCanvas tables={tables} selectedTable={selectedTable} /> */} {/* <TableCanvas tables={tables} selectedTable={selectedTable} /> */}
<div className={styles.TransactionListContainer}> <div className={styles.TransactionListContainer} style={{ padding: '0 20px 0 20px' }}>
{transactions && {transactions &&
transactions.map((transaction) => ( transactions.map((transaction) => (
<div <div
@@ -114,37 +114,66 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
setSelectedTable(transaction.Table || { tableId: 0 }) setSelectedTable(transaction.Table || { tableId: 0 })
} }
> >
<div className={styles['receipt-header']}> <div className={styles['receipt-header']}>
<div className={styles['receipt-info']}> {transaction.confirmed === 1 ? (
<h3>{transaction.confirmed === 1 ? ( <ColorRing className={styles['receipt-logo']} />
"Silahkan cek pembayaran" ) : transaction.confirmed === -1 || transaction.confirmed === -2 ? (
) : transaction.confirmed === -1 ? ( <div style={{ display: 'flex', justifyContent: 'center' }}>
"Declined" <svg
) : transaction.confirmed === -2 ? ( style={{ width: '60px', transform: 'Rotate(45deg)' }}
"Canceled" clipRule="evenodd"
) : transaction.confirmed === 2 ? ( fillRule="evenodd"
"Sedang diproses" strokeLinejoin="round"
) : transaction.confirmed === 3 ? ( strokeMiterlimit="2"
"Transaction success" viewBox="0 0 24 24"
) : ( xmlns="http://www.w3.org/2000/svg"
"Silahkan cek ketersediaan" >
)}</h3> <path
d="m12.002 2c5.518 0 9.998 4.48 9.998 9.998 0 5.517-4.48 9.997-9.998 9.997-5.517 0-9.997-4.48-9.997-9.997 0-5.518 4.48-9.998 9.997-9.998zm0 1.5c-4.69 0-8.497 3.808-8.497 8.498s3.807 8.497 8.497 8.497 8.498-3.807 8.498-8.497-3.808-8.498-8.498-8.498zm-.747 7.75h-3.5c-.414 0-.75.336-.75.75s.336.75.75.75h3.5v3.5c0 .414.336.75.75.75s.75-.336.75-.75v-3.5h3.5c.414 0 .75-.336.75-.75s-.336-.75-.75-.75h-3.5v-3.5c0-.414-.336-.75-.75-.75s-.75.336-.75.75z"
<p>Transaction ID: {transaction.transactionId}</p> fillRule="nonzero"
<p>Payment Type: {transaction.payment_type}</p> />
</div> </svg>
</div>
<div className={styles['dotted-line']}>
<div className={styles['circle-left']}>
</div> </div>
<div className={styles['line']} ></div> ) : transaction.confirmed === 2 ? (
<div className={styles['circle-right']} > <ColorRing className={styles['receipt-logo']} />
) : transaction.confirmed === 3 ? (
"Transaction success"
) : (
<ColorRing className={styles['receipt-logo']} />
)}
<div className={styles['receipt-info']}>
<h3>{transaction.confirmed === 1 ? (
"Silahkan cek pembayaran"
) : transaction.confirmed === -1 ? (
"Dibatalkan oleh kasir"
) : transaction.confirmed === -2 ? (
"Dibatalkan oleh pelanggan"
) : transaction.confirmed === 2 ? (
"Sedang diproses"
) : transaction.confirmed === 3 ? (
"Transaction success"
) : (
"Silahkan cek ketersediaan"
)}</h3>
<p>Transaction ID: {transaction.transactionId}</p>
<p>Payment Type: {transaction.payment_type}</p>
</div>
</div> </div>
</div> <div className={styles['dotted-line']}>
<div className={styles['circle-left']}>
</div>
<div className={styles['line']} ></div>
<div className={styles['circle-right']} >
</div>
</div>
{transaction.paymentClaimed && transaction.confirmed < 2 && ( {transaction.paymentClaimed && transaction.confirmed < 2 && (
<div className={styles.RibbonBanner}> <div className={styles.RibbonBanner}>
<img src={"https://i.imgur.com/yt6osgL.png"}></img> <img src={"https://i.imgur.com/yt6osgL.png"}></img>
@@ -162,27 +191,26 @@ export default function Transactions({ propsShopId, sendParam, deviceType }) {
<h2 className={styles["Transactions-detail"]}> <h2 className={styles["Transactions-detail"]}>
{transaction.serving_type === "pickup" {transaction.serving_type === "pickup"
? "Self pickup" ? "Self pickup"
: `Serve to ${ : `Serve to ${transaction.Table ? transaction.Table.tableNo : "N/A"
transaction.Table ? transaction.Table.tableNo : "N/A" }`}
}`}
</h2> </h2>
{transaction.notes != "" && (
<>
<div className={styles.NoteContainer}>
<span>Note :</span>
<span></span>
</div>
<div className={styles.NoteContainer}> {transaction.notes != "" && (
<textarea <>
className={styles.NoteInput} <div className={styles.NoteContainer}>
value={transaction.notes} <span>Note :</span>
disabled <span></span>
/> </div>
</div>
</> <div className={styles.NoteContainer}>
)} <textarea
className={styles.NoteInput}
value={transaction.notes}
disabled
/>
</div>
</>
)}
<div className={styles.TotalContainer}> <div className={styles.TotalContainer}>
<span>Total:</span> <span>Total:</span>
<span> <span>

View File

@@ -8,7 +8,7 @@
color: rgba(88, 55, 50, 1); color: rgba(88, 55, 50, 1);
background-color: #e9e9e9; background-color: #e9e9e9;
border-radius: 15px; border-radius: 15px;
max-height: 80vh; max-height: 87vh;
width: 80vw; width: 80vw;
} }
.Transactions { .Transactions {
@@ -226,7 +226,7 @@
.dotted-line .line { .dotted-line .line {
border-top: 13px dotted #dbdbdb; border-top: 13px dotted #dbdbdb;
width: 100%; width: 100%;
margin: 0 20px; margin: 0 18px;
} }
.dotted-line .circle-left { .dotted-line .circle-left {