This commit is contained in:
Vassshhh
2025-08-27 21:27:08 +07:00
parent 4fa272875f
commit dcf0455772
12 changed files with 219 additions and 101 deletions

60
package-lock.json generated
View File

@@ -18,7 +18,6 @@
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"html-to-image": "^1.11.11", "html-to-image": "^1.11.11",
"html2canvas": "^1.4.1",
"jsqr": "^1.4.0", "jsqr": "^1.4.0",
"qr-scanner": "^1.4.2", "qr-scanner": "^1.4.2",
"qrcode.react": "^3.1.0", "qrcode.react": "^3.1.0",
@@ -32,6 +31,7 @@
"react-router-dom": "^6.24.0", "react-router-dom": "^6.24.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-switch": "^7.0.0", "react-switch": "^7.0.0",
"react-to-print": "^3.1.1",
"react-youtube": "^10.1.0", "react-youtube": "^10.1.0",
"smooth-scroll-into-view-if-needed": "^2.0.2", "smooth-scroll-into-view-if-needed": "^2.0.2",
"socket.io-client": "^4.7.5", "socket.io-client": "^4.7.5",
@@ -6951,15 +6951,6 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/batch": { "node_modules/batch": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
@@ -7874,15 +7865,6 @@
"postcss": "^8.4" "postcss": "^8.4"
} }
}, },
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"license": "MIT",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/css-loader": { "node_modules/css-loader": {
"version": "6.11.0", "version": "6.11.0",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz",
@@ -11155,19 +11137,6 @@
} }
} }
}, },
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"license": "MIT",
"dependencies": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/htmlparser2": { "node_modules/htmlparser2": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
@@ -18206,6 +18175,15 @@
"react-dom": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" "react-dom": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
} }
}, },
"node_modules/react-to-print": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/react-to-print/-/react-to-print-3.1.1.tgz",
"integrity": "sha512-N0MUMhpl8nkGri13BjP7zusj3B/j+1eMOTt8N8PYuhBYGzA4PqTXqcihJ9cZw996dvhV6mBdwafIQCg3Ap5bKg==",
"license": "MIT",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ~19"
}
},
"node_modules/react-transition-group": { "node_modules/react-transition-group": {
"version": "4.4.5", "version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -20504,15 +20482,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"license": "MIT",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/text-table": { "node_modules/text-table": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -21055,15 +21024,6 @@
"node": ">= 0.4.0" "node": ">= 0.4.0"
} }
}, },
"node_modules/utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"license": "MIT",
"dependencies": {
"base64-arraybuffer": "^1.0.2"
}
},
"node_modules/uuid": { "node_modules/uuid": {
"version": "8.3.2", "version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",

View File

@@ -14,7 +14,6 @@
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"html-to-image": "^1.11.11", "html-to-image": "^1.11.11",
"html2canvas": "^1.4.1",
"jsqr": "^1.4.0", "jsqr": "^1.4.0",
"qr-scanner": "^1.4.2", "qr-scanner": "^1.4.2",
"qrcode.react": "^3.1.0", "qrcode.react": "^3.1.0",
@@ -28,6 +27,7 @@
"react-router-dom": "^6.24.0", "react-router-dom": "^6.24.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-switch": "^7.0.0", "react-switch": "^7.0.0",
"react-to-print": "^3.1.1",
"react-youtube": "^10.1.0", "react-youtube": "^10.1.0",
"smooth-scroll-into-view-if-needed": "^2.0.2", "smooth-scroll-into-view-if-needed": "^2.0.2",
"socket.io-client": "^4.7.5", "socket.io-client": "^4.7.5",

View File

@@ -377,7 +377,7 @@ function App() {
setGuestSides(connectedGuestSides.sessionDatas); setGuestSides(connectedGuestSides.sessionDatas);
console.log("getting guest side"); console.log("getting guest side");
setDeviceType("clerk"); setDeviceType("clerk");
checkNotifications(); // checkNotifications();
} else { } else {
setDeviceType("guestDevice"); setDeviceType("guestDevice");
} }

View File

@@ -29,10 +29,51 @@ const Item = ({
const [itemDescription, setItemDescription] = useState(initialDescription); const [itemDescription, setItemDescription] = useState(initialDescription);
const fileInputRef = useRef(null); const fileInputRef = useRef(null);
const formatToRupiah = (value) => { const formatToRupiah = (value) => {
if (typeof value !== "number") return value; if (typeof value !== "number") return value;
return value.toLocaleString("id-ID"); return value.toLocaleString("id-ID");
// const stringValue = (value || '').toString();
// // Ambil hanya angka
// const cleaned = stringValue.replace(/[^0-9]/g, '');
// // Pastikan cleaned bukan kosong
// if (!cleaned) return 'Rp0';
// // Ubah ke number dan kalikan 1000
// const number = Number(cleaned) * 1000;
// // Kalau gagal parsing, fallback
// if (isNaN(number)) return 'Rp0';
// // Format rupiah tanpa desimal
// return number.toLocaleString('id-ID', {
// style: 'currency',
// currency: 'IDR',
// minimumFractionDigits: 0,
// maximumFractionDigits: 0
// });
}; };
const rupiahFormat = (angka, prefix = "Rp. ") => {
let number_string = angka.toString().replace(/[^,\d]/g, '');
let split = number_string.split(',');
let sisa = split[0].length % 3;
let rupiah = split[0].substr(0, sisa);
let ribuan = split[0].substr(sisa).match(/\d{3}/gi);
// tambahkan titik jika yang di input sudah menjadi angka ribuan
if(ribuan){
let separator = sisa ? '.' : '';
rupiah += separator + ribuan.join('.');
}
rupiah = split[1] != undefined ? rupiah + ',' + split[1] : rupiah;
return rupiah ? prefix + rupiah : "";
}
useEffect(() => { useEffect(() => {
console.log(imageUrl); console.log(imageUrl);
console.log(selectedImage); console.log(selectedImage);
@@ -305,7 +346,9 @@ const formatToRupiah = (value) => {
))} ))}
{forInvoice && ( {forInvoice && (
<p className={styles.itemPriceInvoice}>Rp {itemQty * (promoPrice > 0? formatToRupiah(promoPrice) : formatToRupiah(itemPrice))}</p> <p className={styles.itemPriceInvoice}>Rp {formatToRupiah(itemQty * (promoPrice > 0? promoPrice : itemPrice))}</p>
// <p className={styles.itemPriceInvoice}>{itemQty * (promoPrice > 0? rupiahFormat(promoPrice) : rupiahFormat(itemPrice))}</p>
)} )}
</div> </div>
{forCart && ( {forCart && (

View File

@@ -119,7 +119,7 @@
.TotalContainer { .TotalContainer {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
width: 80vw; /* width: 80vw; */
margin: 0 auto; margin: 0 auto;
font-family: "Plus Jakarta Sans", sans-serif; font-family: "Plus Jakarta Sans", sans-serif;
font-weight: 600; font-weight: 600;

View File

@@ -217,7 +217,8 @@ export const handlePaymentFromClerk = async (
user_email, user_email,
payment_type, payment_type,
serving_type, serving_type,
tableNo tableNo,
notes
) => { ) => {
try { try {
const token = getLocalStorage("auth"); const token = getLocalStorage("auth");
@@ -245,6 +246,7 @@ export const handlePaymentFromClerk = async (
serving_type, serving_type,
tableNo, tableNo,
transactions: structuredItems, transactions: structuredItems,
notes
}), }),
} }
); );

View File

@@ -429,7 +429,7 @@ function CafePage({
} }
/> />
))} ))}
{!isEditMode && !isTablet && (user.username || cartItemsLength > 0) && ( {!isEditMode && (user.username || cartItemsLength > 0) && (
<div <div
style={{ style={{
marginTop: "10px", marginTop: "10px",
@@ -442,7 +442,7 @@ function CafePage({
textAlign: "center", textAlign: "center",
}} }}
> >
{(lastTransaction != null || cartItemsLength > 0) && ( {(!isTablet &&(lastTransaction != null || cartItemsLength > 0)) && (
<div <div
onClick={goToCart} onClick={goToCart}
style={{ style={{

View File

@@ -22,6 +22,11 @@ import { getItemsByCafeId } from "../helpers/cartHelpers.js";
import Dropdown from "./Dropdown.js"; import Dropdown from "./Dropdown.js";
import { useNavigationHelpers } from "../helpers/navigationHelpers"; import { useNavigationHelpers } from "../helpers/navigationHelpers";
const formatToRupiah = (value) => {
if (typeof value !== "number") return value;
return value.toLocaleString("id-ID");
};
export default function Invoice({ export default function Invoice({
shopId, shopId,
setModal, setModal,
@@ -292,8 +297,11 @@ export default function Invoice({
email, email,
orderMethod, orderMethod,
orderType, orderType,
tableNumber tableNumber,
textareaRef.current.value
); );
if (pay) window.location.reload();
} else if (deviceType == "guestSide") { } else if (deviceType == "guestSide") {
const pay = await handlePaymentFromGuestSide( const pay = await handlePaymentFromGuestSide(
shopId, shopId,
@@ -302,6 +310,8 @@ export default function Invoice({
orderType, orderType,
tableNumber tableNumber
); );
if (pay) window.location.reload();
} else if (deviceType == "guestDevice") { } else if (deviceType == "guestDevice") {
const socketId = socket.id; const socketId = socket.id;
const pay = await handlePaymentFromGuestDevice( const pay = await handlePaymentFromGuestDevice(
@@ -312,6 +322,7 @@ export default function Invoice({
textareaRef.current.value, textareaRef.current.value,
socketId socketId
); );
if (pay) window.location.reload();
} }
console.log("transaction from " + deviceType + "success"); console.log("transaction from " + deviceType + "success");
@@ -598,7 +609,7 @@ export default function Invoice({
<span>Pesan</span> <span>Pesan</span>
)} )}
<span>Rp{totalPrice}</span> <span>Rp{formatToRupiah(totalPrice)}</span>
</div> </div>
)} )}
</button> </button>
@@ -654,17 +665,19 @@ export default function Invoice({
<span> <span>
Rp Rp
{transactionData.DetailedTransactions.reduce( {formatToRupiah(
(total, transaction) => { transactionData.DetailedTransactions.reduce(
return ( (total, transaction) => {
total + return (
(transaction.promoPrice == 0 || total +
transaction.promoPrice == null (transaction.promoPrice == 0 ||
? transaction.price * transaction.qty transaction.promoPrice == null
: transaction.promoPrice * transaction.qty) ? transaction.price * transaction.qty
); : transaction.promoPrice * transaction.qty)
}, );
0 },
0
)
)} )}
</span> </span>
</div> </div>
@@ -694,7 +707,7 @@ export default function Invoice({
<span>Pesan</span> <span>Pesan</span>
)} )}
<span>Rp{totalPrice}</span> <span>Rp{formatToRupiah(totalPrice)}</span>
</div> </div>
)} )}
</button> </button>

View File

@@ -69,7 +69,7 @@
.TotalContainer { .TotalContainer {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
width: 80vw; /* width: 80vw; */
margin: 0 auto; margin: 0 auto;
font-family: "Plus Jakarta Sans", sans-serif; font-family: "Plus Jakarta Sans", sans-serif;
font-weight: 600; font-weight: 600;
@@ -466,7 +466,7 @@
.TotalContainer { .TotalContainer {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
width: 80vw; /* width: 80vw; */
margin: 0 auto; margin: 0 auto;
font-family: "Plus Jakarta Sans", sans-serif; font-family: "Plus Jakarta Sans", sans-serif;
font-weight: 600; font-weight: 600;

View File

@@ -67,7 +67,7 @@ export default function Transactions({ propsShopId, sendParam, deviceType, handl
if (c) { if (c) {
console.log(c) console.log(c)
setTransaction(c); setTransaction(c);
setTransactionRefreshKey(transactionRefreshKey+1); setTransactionRefreshKey(transactionRefreshKey + 1);
} }
} catch (error) { } catch (error) {
console.error("Error processing payment:", error); console.error("Error processing payment:", error);
@@ -84,7 +84,7 @@ export default function Transactions({ propsShopId, sendParam, deviceType, handl
if (c) { if (c) {
console.log(c) console.log(c)
setTransaction({ ...transaction, confirmed: c.confirmed }); setTransaction({ ...transaction, confirmed: c.confirmed });
setTransactionRefreshKey(transactionRefreshKey+1); setTransactionRefreshKey(transactionRefreshKey + 1);
} }
// if (c) { // if (c) {
// // Update the confirmed status locally // // Update the confirmed status locally
@@ -115,6 +115,9 @@ export default function Transactions({ propsShopId, sendParam, deviceType, handl
autoResizeTextArea(noteRef.current); autoResizeTextArea(noteRef.current);
} }
}, [transaction?.notes]); }, [transaction?.notes]);
const handlePrint = () => {
window.print();
};
return ( return (
<div key={transactionRefreshKey} className={styles.Transaction}> <div key={transactionRefreshKey} className={styles.Transaction}>
@@ -128,18 +131,17 @@ export default function Transactions({ propsShopId, sendParam, deviceType, handl
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']}> <div className={styles['receipt-info']}>
<h3>{transaction.payment_type == 'cash' ? 'Tunai' : transaction.payment_type == 'cashless' ? 'Non tunai' : transaction.payment_type == 'paylater' ? 'Open bill' :'Close bill' }</h3> <h3>{transaction.payment_type == 'cash' ? 'Tunai' : transaction.payment_type == 'cashless' ? 'Non tunai' : transaction.payment_type == 'paylater' ? 'Open bill' : 'Close bill'}</h3>
<p>Transaction ID: {transaction.transactionId}</p> <p>Transaction ID: {transaction.transactionId}</p>
{ {
transaction.payment_type == 'paylater/cash' ? transaction.payment_type == 'paylater/cash' ?
<p>Cash</p> <p>Cash</p>
: :
(transaction.payment_type == 'paylater/cashless' && (transaction.payment_type == 'paylater/cashless' &&
<p>Non tunai</p> <p>Non tunai</p>
) )
} }
</div> </div>
</div> </div>
@@ -161,8 +163,8 @@ export default function Transactions({ propsShopId, sendParam, deviceType, handl
</svg> </svg>
</div> </div>
{depth > 0 && {depth > 0 &&
<div className={styles.circle}>{depth}</div> <div className={styles.circle}>{depth}</div>
} }
</div> </div>
<div className={styles['line']} ></div> <div className={styles['line']} ></div>
<div className={styles['circle-right']} onClick={() => handleMoveToTransaction('next', transaction.transactionId)}> <div className={styles['circle-right']} onClick={() => handleMoveToTransaction('next', transaction.transactionId)}>
@@ -188,7 +190,7 @@ export default function Transactions({ propsShopId, sendParam, deviceType, handl
<div> <div>
{transaction.DetailedTransactions.map((detail) => ( {transaction.DetailedTransactions.map((detail) => (
<div className={styles['itemContainer']} key={detail.detailedTransactionId}> <div className={styles['itemContainer']} key={detail.detailedTransactionId}>
<div className={styles['plusNegative']} style={{ visibility: transaction.confirmed >= 0 && detail.acceptedStatus == 0 ? 'visible' : 'hidden', margin: transaction.confirmed >= 0 && detail.acceptedStatus == 0 ? '4px 10px 0px 10px' : '4px 0px 0px 0px' }} <div className={styles['plusNegative']} style={{ visibility: transaction.confirmed >= 0 && detail.acceptedStatus == 0 ? 'visible' : 'hidden', margin: transaction.confirmed >= 0 && detail.acceptedStatus == 0 ? '4px 10px 0px 10px' : '4px 0px 0px 0px' }}
onClick={() => onClick={() =>
setNotAcceptedItems(prevState => setNotAcceptedItems(prevState =>
prevState.includes(detail.detailedTransactionId) prevState.includes(detail.detailedTransactionId)
@@ -225,27 +227,27 @@ export default function Transactions({ propsShopId, sendParam, deviceType, handl
overflow: 'hidden', overflow: 'hidden',
textOverflow: 'ellipsis' textOverflow: 'ellipsis'
}}> }}>
{detail.Item.name}</span> - {notAcceptedItems.includes(detail.detailedTransactionId) || detail.qty < 1 ? 'tidak tersedia' : `${detail.qty} x Rp {detail.Item.name}</span> - {notAcceptedItems.includes(detail.detailedTransactionId) || detail.qty < 1 ? 'tidak tersedia' : `${detail.qty} x Rp
${detail.promoPrice ? detail.promoPrice : detail.price}`} ${detail.promoPrice ? detail.promoPrice : detail.price}`}
</div> </div>
))} ))}
</div> </div>
{!transaction.is_paid && transaction.confirmed > -1 && {!transaction.is_paid && transaction.confirmed > -1 &&
<div <div
onClick={() => { onClick={() => {
localStorage.setItem('lastTransaction', JSON.stringify(transaction)); localStorage.setItem('lastTransaction', JSON.stringify(transaction));
setModal("message", { captMessage: 'Silahkan tambahkan pesanan', descMessage: 'Pembayaran akan ditambahkan ke transaksi sebelumnya.' }, null, null); setModal("message", { captMessage: 'Silahkan tambahkan pesanan', descMessage: 'Pembayaran akan ditambahkan ke transaksi sebelumnya.' }, null, null);
// Dispatch the custom event // Dispatch the custom event
window.dispatchEvent(new Event("localStorageUpdated")); window.dispatchEvent(new Event("localStorageUpdated"));
}} }}
className={styles["addNewItem"]} className={styles["addNewItem"]}
> >
Tambah pesanan Tambah pesanan
</div> </div>
} }
<h2 className={styles["Transactions-detail"]}> <h2 className={styles["Transactions-detail"]}>
{transaction.serving_type === "pickup" {transaction.serving_type === "pickup"
@@ -311,9 +313,55 @@ export default function Transactions({ propsShopId, sendParam, deviceType, handl
batalkan batalkan
</h5> </h5>
)} )}
{transaction.confirmed > 1 && (
<h5
className={styles.DeclineButton}
onClick={() => handlePrint()}
>
Cetak struk
</h5>
)}
</div> </div>
)} )}
</div> </div>
{transaction &&
<div id="print-section" className={styles.printContainer}>
<div className="receipt">
<h2 className="center-text">Struk Pembayaran</h2>
<hr />
<p>ID Transaksi: {transaction.transactionId}</p>
<p>Metode: {transaction.payment_type === 'cash' ? 'Tunai' :
transaction.payment_type === 'cashless' ? 'Non Tunai' :
'Open Bill'}</p>
<p>Meja: {transaction.Table?.tableNo || '-'}</p>
<hr />
{transaction.DetailedTransactions.map((detail) => (
<div key={detail.detailedTransactionId} className="item-line">
<p>{detail.Item.name}</p>
<p>{detail.qty} x Rp{detail.promoPrice || detail.price}</p>
</div>
))}
<hr />
<p className="total">Total: Rp {calculateTotalPrice(transaction.DetailedTransactions)}</p>
{transaction.notes && (
<>
<hr />
<p>Catatan:</p>
<p>{transaction.notes}</p>
</>
)}
<hr />
<p className="center-text">Terima Kasih!</p>
</div>
</div>
}
</div> </div>
); );
} }

View File

@@ -198,7 +198,7 @@ console.log(aggregatedItems.values())
<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.is_paid || transaction.confirmed === -2 && !transaction.is_paid ? ( ) : (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)' }}

View File

@@ -395,4 +395,56 @@
text-align: center; text-align: center;
color: white; color: white;
line-height: 27px; line-height: 27px;
} }
/* Transactions.module.css */
.printContainer {
display: none; /* Hidden in normal view */
}
/* Print-specific styles */
@media print {
.Transaction {
display: none; /* Hide everything else when printing */
}
.printContainer {
display: block !important;
position: static;
background: white;
color: black;
font-family: 'Courier New', Courier, monospace;
padding: 20px;
}
.receipt {
width: 100%;
max-width: 400px;
margin: 0 auto;
}
.center-text {
text-align: center;
font-weight: bold;
}
.item-line {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
}
.total {
text-align: right;
font-size: 1.2em;
font-weight: bold;
margin-top: 20px;
}
button, .DeclineButton, .addNewItem {
display: none !important;
}
}