This commit is contained in:
everythingonblack
2025-05-20 17:47:43 +07:00
parent b726ae6919
commit df7c4f737c
7 changed files with 119 additions and 81 deletions

View File

@@ -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>

View File

@@ -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 {

View File

@@ -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}

View File

@@ -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]);

View File

@@ -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;

View File

@@ -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));

View File

@@ -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)}