ok
This commit is contained in:
@@ -28,6 +28,15 @@
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<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>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
@@ -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");
|
||||
html,
|
||||
body {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
|
||||
.App {
|
||||
/* overflow-x: hidden; */
|
||||
}
|
||||
|
||||
.Cafe {
|
||||
|
||||
@@ -135,6 +135,7 @@ function App() {
|
||||
return;
|
||||
}
|
||||
|
||||
setModal('transaction_confirmed',{transactionId: lastTransaction.transactionId})
|
||||
const myLastTransaction = await checkIsMyTransaction(lastTransaction.transactionId);
|
||||
console.log(myLastTransaction)
|
||||
if (myLastTransaction.isMyTransaction) {
|
||||
@@ -771,6 +772,7 @@ function App() {
|
||||
sendParam={handleSetParam}
|
||||
deviceType={deviceType}
|
||||
paymentUrl={shop.qrPayment}
|
||||
setModal={setModal}
|
||||
/>
|
||||
{/* <Footer
|
||||
shopId={shopIdentifier}
|
||||
|
||||
@@ -77,17 +77,28 @@ function CafePage({
|
||||
|
||||
const [beingEditedType, setBeingEditedType] = useState(0);
|
||||
|
||||
const checkWelcomePageConfig = () => {
|
||||
const parsedConfig = JSON.parse(welcomePageConfig);
|
||||
if (parsedConfig.isWelcomePageActive == "true") {
|
||||
const clicked = sessionStorage.getItem("getStartedClicked");
|
||||
if (!clicked) {
|
||||
sessionStorage.setItem("getStartedClicked", true);
|
||||
document.body.style.overflow = "hidden";
|
||||
setIsStarted(true);
|
||||
}
|
||||
// const checkWelcomePageConfig = () => {
|
||||
// const parsedConfig = JSON.parse(welcomePageConfig);
|
||||
// if (parsedConfig.isWelcomePageActive == "true") {
|
||||
// const clicked = sessionStorage.getItem("getStartedClicked");
|
||||
// if (!clicked) {
|
||||
// sessionStorage.setItem("getStartedClicked", true);
|
||||
// document.body.style.overflow = "hidden";
|
||||
// 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(() => {
|
||||
if (welcomePageConfig) {
|
||||
@@ -100,7 +111,7 @@ function CafePage({
|
||||
isActive: parsedConfig.isWelcomePageActive === "true",
|
||||
});
|
||||
}
|
||||
checkWelcomePageConfig();
|
||||
// checkWelcomePageConfig();
|
||||
}, [welcomePageConfig]);
|
||||
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ const RoundedRectangle = ({
|
||||
};
|
||||
|
||||
const percentageStyle = {
|
||||
fontSize: "16px",
|
||||
fontSize: "14px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
textAlign: "right",
|
||||
@@ -282,11 +282,11 @@ const App = ({ forCafe = true, cafeId = -1,
|
||||
if (amount >= 1_000_000_000) {
|
||||
// Format for billions
|
||||
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) {
|
||||
// Format for millions
|
||||
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) {
|
||||
// Format for thousands
|
||||
const thousands = amount / 1_000;
|
||||
|
||||
@@ -192,7 +192,7 @@ export default function Transactions({
|
||||
))}
|
||||
</ul>
|
||||
|
||||
{transaction.payment_type != 'paylater/cash' && transaction.payment_type != 'paylater/cashless' &&
|
||||
{(transaction.payment_type != 'paylater/cash' && transaction.payment_type != 'paylater/cashless') &&
|
||||
<div
|
||||
onClick={() => {
|
||||
localStorage.setItem('lastTransaction', JSON.stringify(transaction));
|
||||
|
||||
@@ -18,7 +18,7 @@ import ButtonWithReplica from "../components/ButtonWithReplica";
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(timezone);
|
||||
|
||||
export default function Transactions({ shop, shopId, propsShopId, sendParam, deviceType, paymentUrl }) {
|
||||
export default function Transactions({ shop, shopId, propsShopId, sendParam, deviceType, paymentUrl, setModal }) {
|
||||
const { shopIdentifier, tableId } = useParams();
|
||||
if (sendParam) sendParam({ shopIdentifier, tableId });
|
||||
|
||||
@@ -26,13 +26,13 @@ export default function Transactions({ shop, shopId, propsShopId, sendParam, dev
|
||||
const [isPaymentLoading, setIsPaymentLoading] = useState(false);
|
||||
const [isPaymentOpen, setIsPaymentOpen] = useState(false);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [matchedItems, setMatchedItems] = useState([]);
|
||||
const [matchedItems, setMatchedItems] = useState([]);
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMatchedItems(searchAndAggregateItems(transactions, searchTerm));
|
||||
}, [searchTerm, transactions]);
|
||||
useEffect(() => {
|
||||
setMatchedItems(searchAndAggregateItems(transactions, searchTerm));
|
||||
}, [searchTerm, transactions]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
@@ -43,6 +43,10 @@ useEffect(() => {
|
||||
|
||||
setLoading(false);
|
||||
if (response) setTransactions(response);
|
||||
|
||||
|
||||
// response = await getMyTransactions(shopId || propsShopId, 5);
|
||||
// setMyTransactions(response);
|
||||
} catch (error) {
|
||||
console.error("Error fetching transactions:", error);
|
||||
}
|
||||
@@ -62,38 +66,38 @@ useEffect(() => {
|
||||
return grandTotal + calculateTotalPrice(transaction.DetailedTransactions);
|
||||
}, 0);
|
||||
};
|
||||
const searchAndAggregateItems = (transactions, searchTerm) => {
|
||||
if (!searchTerm.trim()) return [];
|
||||
const searchAndAggregateItems = (transactions, searchTerm) => {
|
||||
if (!searchTerm.trim()) return [];
|
||||
|
||||
const normalizedTerm = searchTerm.trim().toLowerCase();
|
||||
const aggregatedItems = new Map();
|
||||
const normalizedTerm = searchTerm.trim().toLowerCase();
|
||||
const aggregatedItems = new Map();
|
||||
|
||||
transactions.forEach(transaction => {
|
||||
transaction.DetailedTransactions.forEach(detail => {
|
||||
const itemName = detail.Item.name;
|
||||
const itemNameLower = itemName.toLowerCase();
|
||||
transactions.forEach(transaction => {
|
||||
transaction.DetailedTransactions.forEach(detail => {
|
||||
const itemName = detail.Item.name;
|
||||
const itemNameLower = itemName.toLowerCase();
|
||||
|
||||
if (itemNameLower.includes(normalizedTerm)) {
|
||||
const key = detail.itemId;
|
||||
if (itemNameLower.includes(normalizedTerm)) {
|
||||
const key = detail.itemId;
|
||||
|
||||
if (!aggregatedItems.has(key)) {
|
||||
aggregatedItems.set(key, {
|
||||
itemId: detail.itemId,
|
||||
name: itemName,
|
||||
totalQty: 0,
|
||||
totalPrice: 0,
|
||||
});
|
||||
if (!aggregatedItems.has(key)) {
|
||||
aggregatedItems.set(key, {
|
||||
itemId: detail.itemId,
|
||||
name: itemName,
|
||||
totalQty: 0,
|
||||
totalPrice: 0,
|
||||
});
|
||||
}
|
||||
|
||||
const current = aggregatedItems.get(key);
|
||||
current.totalQty += detail.qty;
|
||||
current.totalPrice += detail.qty * (detail.promoPrice || detail.price);
|
||||
}
|
||||
|
||||
const current = aggregatedItems.get(key);
|
||||
current.totalQty += detail.qty;
|
||||
current.totalPrice += detail.qty * (detail.promoPrice || detail.price);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return Array.from(aggregatedItems.values());
|
||||
};
|
||||
return Array.from(aggregatedItems.values());
|
||||
};
|
||||
|
||||
|
||||
const handleConfirm = async (transactionId) => {
|
||||
@@ -103,7 +107,7 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
||||
if (result) {
|
||||
setTransactions(prev =>
|
||||
prev.map(t =>
|
||||
t.transactionId === transactionId ? { ...t, confirmed: 1 } : t
|
||||
t.transactionId === transactionId ? result : t
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -148,35 +152,35 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
||||
</h2>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Cari nama item..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
style={{ border:'0px',height: '42px',borderRadius: '15px', margin: '7px auto 10px', width: '88%', paddingLeft: '8px' }}
|
||||
/>
|
||||
type="text"
|
||||
placeholder="Cari nama item..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
style={{ border: '0px', height: '42px', borderRadius: '15px', margin: '7px auto 10px', width: '88%', paddingLeft: '8px' }}
|
||||
/>
|
||||
|
||||
|
||||
|
||||
{/* Existing Transactions List (keep all your JSX below unchanged) */}
|
||||
<div className={styles.TransactionListContainer} style={{ padding: '0 8px' }}>
|
||||
|
||||
{matchedItems.length > 0 && matchedItems.map(item => (
|
||||
<div
|
||||
key={item.itemId}
|
||||
className={styles.RoundedRectangle}
|
||||
style={{ overflow: "hidden" }}
|
||||
>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>{item.name}</strong> x {item.totalQty}
|
||||
</li>
|
||||
</ul>
|
||||
<div className={styles.TotalContainer}>
|
||||
<span>Total:</span>
|
||||
<span>Rp {item.totalPrice}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{matchedItems.length > 0 && matchedItems.map(item => (
|
||||
<div
|
||||
key={item.itemId}
|
||||
className={styles.RoundedRectangle}
|
||||
style={{ overflow: "hidden" }}
|
||||
>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>{item.name}</strong> x {item.totalQty}
|
||||
</li>
|
||||
</ul>
|
||||
<div className={styles.TotalContainer}>
|
||||
<span>Total:</span>
|
||||
<span>Rp {item.totalPrice}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{transactions &&
|
||||
transactions.map((transaction) => (
|
||||
<div
|
||||
@@ -188,7 +192,7 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
||||
<div className={styles['receipt-header']}>
|
||||
{transaction.confirmed === 1 ? (
|
||||
<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' }}>
|
||||
<svg
|
||||
style={{ width: '60px', transform: 'Rotate(45deg)' }}
|
||||
@@ -205,9 +209,9 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
) : transaction.confirmed === 2 ? (
|
||||
) : transaction.confirmed === 2 && !transaction.is_paid ? (
|
||||
<ColorRing className={styles['receipt-logo']} />
|
||||
) : transaction.confirmed === 3 ? (
|
||||
) : transaction.confirmed === 3 || transaction.is_paid ? (
|
||||
<div>
|
||||
<svg
|
||||
height="60px"
|
||||
@@ -242,15 +246,15 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
||||
|
||||
<div className={styles['receipt-info']}>
|
||||
{deviceType == 'clerk' ?
|
||||
<h3>{transaction.confirmed === 1 ? (
|
||||
<h3>{transaction.confirmed === 1 && !transaction.is_paid ? (
|
||||
"Silahkan Cek Pembayaran"
|
||||
) : transaction.confirmed === -1 ? (
|
||||
) : transaction.confirmed === -1 && !transaction.is_paid ? (
|
||||
"Dibatalkan Oleh Kasir"
|
||||
) : transaction.confirmed === -2 ? (
|
||||
) : transaction.confirmed === -2 && !transaction.is_paid ? (
|
||||
"Dibatalkan Oleh Pelanggan"
|
||||
) : transaction.confirmed === 2 ? (
|
||||
) : transaction.confirmed === 2 && !transaction.is_paid ? (
|
||||
"Sedang Diproses"
|
||||
) : transaction.confirmed === 3 ? (
|
||||
) : transaction.confirmed === 3 || transaction.is_paid ? (
|
||||
"Transaksi Sukses"
|
||||
) : (
|
||||
"Silahkan Cek Ketersediaan"
|
||||
@@ -299,6 +303,20 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
||||
</li>
|
||||
))}
|
||||
</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"]}>
|
||||
{transaction.serving_type === "pickup"
|
||||
? "Self pickup"
|
||||
@@ -331,7 +349,7 @@ const searchAndAggregateItems = (transactions, searchTerm) => {
|
||||
</div>
|
||||
|
||||
<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
|
||||
className={styles.PayButton}
|
||||
onClick={() => handleConfirm(transaction.transactionId)}
|
||||
|
||||
Reference in New Issue
Block a user