diff --git a/assets/js/main.js b/assets/js/main.js
index d57339c..c19ac91 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -1,4 +1,8 @@
+console.log('POS Script Loading...');
+
document.addEventListener('DOMContentLoaded', () => {
+ console.log('POS Script DOMContentLoaded');
+
// SweetAlert2 Toast Mixin
const Toast = (typeof Swal !== 'undefined') ? Swal.mixin({
toast: true,
@@ -89,7 +93,7 @@ document.addEventListener('DOMContentLoaded', () => {
let currentCustomer = null;
const paymentModalEl = document.getElementById('paymentSelectionModal');
- const paymentSelectionModal = paymentModalEl ? new bootstrap.Modal(paymentSelectionModal) : null;
+ const paymentSelectionModal = paymentModalEl ? new bootstrap.Modal(paymentModalEl) : null;
const paymentMethodsContainer = document.getElementById('payment-methods-container');
const productSearchInput = document.getElementById('product-search');
@@ -103,7 +107,7 @@ document.addEventListener('DOMContentLoaded', () => {
const symbol = settings.currency_symbol || '$';
const decimals = parseInt(settings.currency_decimals || 2);
const position = settings.currency_position || 'before';
- const formatted = parseFloat(Math.abs(amount)).toFixed(decimals);
+ const formatted = parseFloat(Math.abs(amount || 0)).toFixed(decimals);
if (position === 'after') {
return formatted + ' ' + symbol;
@@ -117,15 +121,14 @@ document.addEventListener('DOMContentLoaded', () => {
items.forEach(item => {
const matchesCategory = (currentCategory == 'all' || item.dataset.category == currentCategory);
const name = (item.dataset.name || '').toLowerCase();
- const name_ar = (item.dataset.nameAr || '').toLowerCase();
const sku = (item.dataset.sku || '').toLowerCase();
- const matchesSearch = name.includes(currentSearchQuery) || name_ar.includes(currentSearchQuery) || sku.includes(currentSearchQuery);
+ const matchesSearch = name.includes(currentSearchQuery) || sku.includes(currentSearchQuery);
item.style.display = (matchesCategory && matchesSearch) ? 'block' : 'none';
});
}
- function filterCategory(categoryId, btnElement) { window.filterCategory = filterCategory;
+ function filterCategory(categoryId, btnElement) {
currentCategory = categoryId;
document.querySelectorAll('.category-btn').forEach(btn => btn.classList.remove('active'));
if (btnElement) {
@@ -135,7 +138,8 @@ document.addEventListener('DOMContentLoaded', () => {
if (btn) btn.classList.add('active');
}
filterProducts();
- };
+ }
+ window.filterCategory = filterCategory;
document.querySelectorAll('.category-btn').forEach(btn => {
btn.addEventListener('click', () => {
@@ -150,11 +154,28 @@ document.addEventListener('DOMContentLoaded', () => {
});
}
- function openRecallOrderModal() { window.openRecallOrderModal = openRecallOrderModal;
+ const productGrid = document.getElementById('product-grid');
+ if (productGrid) {
+ productGrid.addEventListener('click', (e) => {
+ const item = e.target.closest('.product-item');
+ if (item) {
+ try {
+ const product = JSON.parse(item.dataset.product);
+ const variants = JSON.parse(item.dataset.variants);
+ handleProductClick(product, variants);
+ } catch (err) {
+ console.error('Error parsing product data:', err);
+ }
+ }
+ });
+ }
+
+ function openRecallOrderModal() {
if (!recallModal) return;
fetchRecallOrders();
recallModal.show();
- };
+ }
+ window.openRecallOrderModal = openRecallOrderModal;
function fetchRecallOrders() {
if (!recallList) return;
@@ -357,7 +378,7 @@ document.addEventListener('DOMContentLoaded', () => {
item.innerHTML = `
${h.reason}
-
${h.points_change > 0 ? '+' : ''}${h.points_change}
+
${(h.points_change > 0 ? '+' : '') + h.points_change}
${h.created_at}
`;
@@ -416,11 +437,12 @@ document.addEventListener('DOMContentLoaded', () => {
});
}
- function openTableSelectionModal() { window.openTableSelectionModal = openTableSelectionModal;
+ function openTableSelectionModal() {
if (!tableSelectionModal) return;
fetchTables();
tableSelectionModal.show();
- };
+ }
+ window.openTableSelectionModal = openTableSelectionModal;
function fetchTables() {
const grid = document.getElementById("tables-grid");
@@ -477,7 +499,7 @@ document.addEventListener('DOMContentLoaded', () => {
}
}
- function selectTable(id, name) { window.selectTable = selectTable;
+ function selectTable(id, name) {
currentTableId = id;
currentTableName = name;
const nameDisplay = document.getElementById("selected-table-name");
@@ -489,9 +511,10 @@ document.addEventListener('DOMContentLoaded', () => {
dineInInput.checked = true;
checkOrderType();
}
- };
-
- function checkOrderType() { window.checkOrderType = checkOrderType;
+ }
+ window.selectTable = selectTable;
+
+ function checkOrderType() {
const checked = document.querySelector('input[name="order_type"]:checked');
if (!checked) return;
const selected = checked.value;
@@ -501,25 +524,28 @@ document.addEventListener('DOMContentLoaded', () => {
} else {
if (tableDisplay) tableDisplay.style.display = 'none';
}
- };
+ }
+ window.checkOrderType = checkOrderType;
document.querySelectorAll('input[name="order_type"]').forEach(input => {
input.addEventListener('change', checkOrderType);
});
- function handleProductClick(product, variants) { window.handleProductClick = handleProductClick;
+ function handleProductClick(product, variants) {
+ console.log('Product Clicked:', product.name);
if (variants && variants.length > 0) {
openVariantModal(product, variants);
} else {
addToCart({
id: product.id, name: product.name, name_ar: product.name_ar || "",
- price: parseFloat(product.price), base_price: parseFloat(product.price),
+ price: parseFloat(product.price || 0), base_price: parseFloat(product.price || 0),
hasVariants: false, quantity: 1, variant_id: null, variant_name: null,
is_loyalty: parseInt(product.is_loyalty) === 1,
vat_percent: parseFloat(product.vat_percent || settings.vat_rate || 0)
});
}
- };
+ }
+ window.handleProductClick = handleProductClick;
function openVariantModal(product, variants) {
if (!variantSelectionModal) return;
@@ -531,13 +557,13 @@ document.addEventListener('DOMContentLoaded', () => {
variants.forEach(v => {
const btn = document.createElement('button');
btn.className = 'list-group-item list-group-item-action d-flex justify-content-between align-items-center';
- const finalPrice = parseFloat(product.price) + parseFloat(v.price_adjustment);
+ const finalPrice = parseFloat(product.price || 0) + parseFloat(v.price_adjustment || 0);
const vName = (LANG === 'ar' && v.name_ar) ? v.name_ar : v.name;
btn.innerHTML = `${vName}${formatCurrency(finalPrice)}`;
btn.onclick = () => {
addToCart({
id: product.id, name: product.name, name_ar: product.name_ar || "",
- price: finalPrice, base_price: parseFloat(product.price),
+ price: finalPrice, base_price: parseFloat(product.price || 0),
hasVariants: true, quantity: 1, variant_id: v.id, variant_name: v.name,
is_loyalty: parseInt(product.is_loyalty) === 1,
vat_percent: parseFloat(product.vat_percent || settings.vat_rate || 0)
@@ -549,37 +575,51 @@ document.addEventListener('DOMContentLoaded', () => {
variantSelectionModal.show();
}
- function addToCart(product) { window.addToCart = addToCart;
+ function addToCart(product) {
+ console.log('Adding to cart:', product);
const existing = cart.find(item => item.id === product.id && item.variant_id === product.variant_id);
- if (existing) existing.quantity++;
- else cart.push({...product});
+ if (existing) {
+ existing.quantity++;
+ console.log('Incremented quantity for:', product.name);
+ } else {
+ cart.push({...product});
+ console.log('Added new item to cart:', product.name);
+ }
updateCart();
- };
+ }
+ window.addToCart = addToCart;
- function changeQuantity(index, delta) { window.changeQuantity = changeQuantity;
+ function changeQuantity(index, delta) {
if (cart[index]) {
cart[index].quantity += delta;
if (cart[index].quantity <= 0) cart.splice(index, 1);
updateCart();
}
- };
+ }
+ window.changeQuantity = changeQuantity;
- function removeFromCart(index) { window.removeFromCart = removeFromCart;
+ function removeFromCart(index) {
cart.splice(index, 1);
updateCart();
- };
+ }
+ window.removeFromCart = removeFromCart;
- function clearCart() { window.clearCart = clearCart;
+ function clearCart() {
if (cart.length === 0) return;
cart = [];
currentOrderId = null;
isLoyaltyRedemption = false;
updateCart();
showToast("Cart cleared", "success");
- };
+ }
+ window.clearCart = clearCart;
function updateCart() {
- if (!cartItemsContainer) return;
+ console.log('Updating cart UI, item count:', cart.length);
+ if (!cartItemsContainer) {
+ console.error('Cart items container not found!');
+ return;
+ }
updateLoyaltyUI();
@@ -600,8 +640,8 @@ document.addEventListener('DOMContentLoaded', () => {
let subtotal = 0;
let totalVat = 0;
cart.forEach((item, index) => {
- const itemTotal = item.price * item.quantity;
- const itemVat = itemTotal * (item.vat_percent / 100);
+ const itemTotal = (item.price || 0) * (item.quantity || 0);
+ const itemVat = itemTotal * ((item.vat_percent || 0) / 100);
subtotal += itemTotal;
totalVat += itemVat;
@@ -612,9 +652,9 @@ document.addEventListener('DOMContentLoaded', () => {
row.innerHTML = `
-
${itemName}
+
${itemName || 'Product'}
${otherName ? `
${otherName}
` : ''}
-
${formatCurrency(item.price)} ${item.vat_percent > 0 ? `${item.vat_percent}% VAT` : ''}
+
${formatCurrency(item.price)} ${((item.vat_percent || 0) > 0 ? `${item.vat_percent}% VAT` : '')}
@@ -670,7 +710,7 @@ document.addEventListener('DOMContentLoaded', () => {
}
}
- function processOrder(paymentTypeId, paymentTypeName) { window.processOrder = processOrder;
+ function processOrder(paymentTypeId, paymentTypeName) {
const orderTypeInput = document.querySelector('input[name="order_type"]:checked');
const orderType = orderTypeInput ? orderTypeInput.value : 'takeaway';
@@ -764,10 +804,11 @@ document.addEventListener('DOMContentLoaded', () => {
// For now, let's keep it cleared but show the error.
}
});
- };
+ }
+ window.processOrder = processOrder;
- function triggerNetworkPrint(orderId, type) { window.triggerNetworkPrint = triggerNetworkPrint;
- if (!orderId) return;
+ function triggerNetworkPrint(orderId, type) {
+ if (!orderId) return;
const printerIp = (type === 'kitchen') ? CURRENT_OUTLET.kitchen_printer_ip : CURRENT_OUTLET.cashier_printer_ip;
if (!printerIp) return;
@@ -787,9 +828,10 @@ document.addEventListener('DOMContentLoaded', () => {
}
})
.catch(err => console.error(`Network Print Fetch Error (${type}):`, err));
- };
+ }
+ window.triggerNetworkPrint = triggerNetworkPrint;
- function printThermalReceipt(data) { window.printThermalReceipt = printThermalReceipt;
+ function printThermalReceipt(data) {
let iframe = document.getElementById('print-iframe');
if (!iframe) {
iframe = document.createElement('iframe');
@@ -847,8 +889,7 @@ document.addEventListener('DOMContentLoaded', () => {
const loyaltyHtml = data.loyaltyRedeemed ? `
* Loyalty Reward Applied *
` : '';
// We skip logo in receipt for absolute speed unless it's already cached.
- // If users really want the logo, we can re-enable it.
- const logoHtml = ''; // settings.logo_url ? `

` : '';
+ const logoHtml = '';
const vatRate = settings.vat_rate || 0;
@@ -929,9 +970,10 @@ document.addEventListener('DOMContentLoaded', () => {
// Print immediately without waiting for resources
iframe.contentWindow.focus();
iframe.contentWindow.print();
- };
+ }
+ window.printThermalReceipt = printThermalReceipt;
- function openRatingQRModal() { window.openRatingQRModal = openRatingQRModal;
+ function openRatingQRModal() {
const qrContainer = document.getElementById('rating-qr-container');
const ratingUrl = BASE_URL + '/rate.php';
const qrCodeUrl = "https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=" + encodeURIComponent(ratingUrl);
@@ -940,5 +982,6 @@ document.addEventListener('DOMContentLoaded', () => {
const modal = new bootstrap.Modal(document.getElementById('qrRatingModal'));
modal.show();
- };
-});
\ No newline at end of file
+ }
+ window.openRatingQRModal = openRatingQRModal;
+});
diff --git a/pos.php b/pos.php
index 2e876be..93a0dcf 100644
--- a/pos.php
+++ b/pos.php
@@ -247,7 +247,8 @@ $vat_rate = (float)($settings['vat_rate'] ?? 0);
data-category="= $product['category_id'] ?>"
data-name="= htmlspecialchars(strtolower($product['name'])) ?>"
data-sku="= htmlspecialchars(strtolower($product['sku'] ?? '')) ?>"
- onclick="handleProductClick(= htmlspecialchars(json_encode($product), ENT_QUOTES) ?>, = htmlspecialchars(json_encode($variants_by_product[$product['id']] ?? []), ENT_QUOTES) ?>)">
+ data-product='= htmlspecialchars(json_encode($product), ENT_QUOTES) ?>'
+ data-variants='= htmlspecialchars(json_encode($variants_by_product[$product['id']] ?? []), ENT_QUOTES) ?>'>