Autosave: 20260218-145439
This commit is contained in:
parent
af4b79251b
commit
2621002fde
@ -137,8 +137,11 @@
|
|||||||
<div class="logo">
|
<div class="logo">
|
||||||
<i class="bi bi-cart4 me-2"></i>Customer Display
|
<i class="bi bi-cart4 me-2"></i>Customer Display
|
||||||
</div>
|
</div>
|
||||||
<div id="customerName" class="badge bg-light text-dark fs-6 fw-normal border">
|
<div class="d-flex align-items-center">
|
||||||
Welcome
|
<div id="debugInfo" class="me-3 badge bg-secondary" style="display: none;">Items: 0</div>
|
||||||
|
<div id="customerName" class="badge bg-light text-dark fs-6 fw-normal border">
|
||||||
|
Welcome
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -181,17 +184,29 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
let lastTimestamp = 0;
|
||||||
|
|
||||||
function formatMoney(amount) {
|
function formatMoney(amount) {
|
||||||
return 'OMR ' + parseFloat(amount).toFixed(3);
|
return 'OMR ' + parseFloat(amount).toFixed(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateDisplay(data) {
|
function updateDisplay(data) {
|
||||||
|
if (!data) return;
|
||||||
|
lastTimestamp = data.timestamp || 0;
|
||||||
|
|
||||||
|
// Debug info
|
||||||
|
const debugEl = document.getElementById('debugInfo');
|
||||||
|
if (debugEl) {
|
||||||
|
debugEl.innerText = 'Items: ' + (data.items ? data.items.length : 0);
|
||||||
|
// debugEl.style.display = 'block'; // Uncomment to show always
|
||||||
|
}
|
||||||
|
|
||||||
// Update Theme
|
// Update Theme
|
||||||
if (data.theme) {
|
if (data.theme) {
|
||||||
document.body.className = data.theme;
|
document.body.className = data.theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data || !data.items || data.items.length === 0) {
|
if (!Array.isArray(data.items) || data.items.length === 0) {
|
||||||
document.getElementById('activeCart').style.display = 'none';
|
document.getElementById('activeCart').style.display = 'none';
|
||||||
document.getElementById('welcomeScreen').style.display = 'flex';
|
document.getElementById('welcomeScreen').style.display = 'flex';
|
||||||
document.getElementById('customerName').innerText = 'Welcome';
|
document.getElementById('customerName').innerText = 'Welcome';
|
||||||
@ -208,43 +223,67 @@
|
|||||||
document.getElementById('customerName').innerText = 'Welcome';
|
document.getElementById('customerName').innerText = 'Welcome';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Items
|
// Update Items (Safer rendering)
|
||||||
const itemsList = document.getElementById('itemsList');
|
const itemsList = document.getElementById('itemsList');
|
||||||
itemsList.innerHTML = data.items.map(item => `
|
if (itemsList) {
|
||||||
<div class="cart-item">
|
itemsList.innerHTML = ''; // Clear existing
|
||||||
<div>
|
|
||||||
<div class="item-name">${item.name}</div>
|
|
||||||
<div class="item-details">
|
|
||||||
${item.qty} x ${formatMoney(item.price)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="item-price">
|
|
||||||
${formatMoney(item.qty * item.price)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`).join('');
|
|
||||||
|
|
||||||
// Scroll to bottom of list
|
data.items.forEach(item => {
|
||||||
itemsList.scrollTop = itemsList.scrollHeight;
|
try {
|
||||||
|
const row = document.createElement('div');
|
||||||
|
row.className = 'cart-item';
|
||||||
|
|
||||||
|
const name = item.name || 'Item';
|
||||||
|
const price = parseFloat(item.price) || 0;
|
||||||
|
const qty = parseFloat(item.qty) || 0;
|
||||||
|
const total = price * qty;
|
||||||
|
|
||||||
|
row.innerHTML = `
|
||||||
|
<div>
|
||||||
|
<div class="item-name"></div>
|
||||||
|
<div class="item-details">
|
||||||
|
${qty} x ${formatMoney(price)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="item-price">
|
||||||
|
${formatMoney(total)}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
// Set text content safely
|
||||||
|
const nameEl = row.querySelector('.item-name');
|
||||||
|
if (nameEl) nameEl.textContent = name;
|
||||||
|
itemsList.appendChild(row);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error rendering item:', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Scroll to bottom of list
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
itemsList.scrollTop = itemsList.scrollHeight;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Update Totals
|
// Update Totals
|
||||||
document.getElementById('displaySubtotal').innerText = formatMoney(data.subtotal);
|
document.getElementById('displaySubtotal').innerText = formatMoney(data.subtotal || 0);
|
||||||
|
|
||||||
if (data.discount > 0) {
|
const discount = parseFloat(data.discount) || 0;
|
||||||
|
if (discount > 0) {
|
||||||
document.getElementById('displayDiscountRow').style.display = 'flex';
|
document.getElementById('displayDiscountRow').style.display = 'flex';
|
||||||
document.getElementById('displayDiscount').innerText = '- ' + formatMoney(data.discount);
|
document.getElementById('displayDiscount').innerText = '- ' + formatMoney(discount);
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('displayDiscountRow').style.display = 'none';
|
document.getElementById('displayDiscountRow').style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.loyalty > 0) {
|
const loyalty = parseFloat(data.loyalty) || 0;
|
||||||
|
if (loyalty > 0) {
|
||||||
document.getElementById('displayLoyaltyRow').style.display = 'flex';
|
document.getElementById('displayLoyaltyRow').style.display = 'flex';
|
||||||
document.getElementById('displayLoyalty').innerText = '- ' + formatMoney(data.loyalty);
|
document.getElementById('displayLoyalty').innerText = '- ' + formatMoney(loyalty);
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('displayLoyaltyRow').style.display = 'none';
|
document.getElementById('displayLoyaltyRow').style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('displayTotal').innerText = formatMoney(data.total);
|
document.getElementById('displayTotal').innerText = formatMoney(data.total || 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for storage events
|
// Listen for storage events
|
||||||
@ -259,6 +298,19 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Polling fallback (every 1 second)
|
||||||
|
setInterval(() => {
|
||||||
|
const stored = localStorage.getItem('pos_cart_update');
|
||||||
|
if (stored) {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(stored);
|
||||||
|
if (data.timestamp && data.timestamp !== lastTimestamp) {
|
||||||
|
updateDisplay(data);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
// Initial check
|
// Initial check
|
||||||
const stored = localStorage.getItem('pos_cart_update');
|
const stored = localStorage.getItem('pos_cart_update');
|
||||||
if (stored) {
|
if (stored) {
|
||||||
|
|||||||
21
index.php
21
index.php
@ -2868,7 +2868,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
<div class="p-3 border-bottom d-flex justify-content-between align-items-center">
|
<div class="p-3 border-bottom d-flex justify-content-between align-items-center">
|
||||||
<h6 class="m-0 fw-bold"><i class="bi bi-cart3 me-2"></i>Cart</h6>
|
<h6 class="m-0 fw-bold"><i class="bi bi-cart3 me-2"></i>Cart</h6>
|
||||||
<div class="d-flex gap-2">
|
<div class="d-flex gap-2">
|
||||||
<button class="btn btn-sm btn-outline-info" onclick="window.open('customer-display.php', 'CustomerDisplay', 'width=1000,height=800')" title="Customer Display"><i class="bi bi-display me-1"></i> Customer Screen</button>
|
<button class="btn btn-sm btn-outline-info" onclick="window.open('customer-display.php?v=<?= time() ?>', 'CustomerDisplay', 'width=1000,height=800')" title="Customer Display"><i class="bi bi-display me-1"></i> Customer Screen</button>
|
||||||
<button class="btn btn-sm btn-outline-warning" onclick="cart.openHeldCartsModal()" title="Held List"><i class="bi bi-list-task"></i></button>
|
<button class="btn btn-sm btn-outline-warning" onclick="cart.openHeldCartsModal()" title="Held List"><i class="bi bi-list-task"></i></button>
|
||||||
<button class="btn btn-sm btn-outline-secondary" onclick="cart.hold()" title="Hold Cart"><i class="bi bi-pause-circle"></i></button>
|
<button class="btn btn-sm btn-outline-secondary" onclick="cart.hold()" title="Hold Cart"><i class="bi bi-pause-circle"></i></button>
|
||||||
<button class="btn btn-sm btn-outline-danger" onclick="cart.clear()" title="Clear Cart"><i class="bi bi-trash"></i></button>
|
<button class="btn btn-sm btn-outline-danger" onclick="cart.clear()" title="Clear Cart"><i class="bi bi-trash"></i></button>
|
||||||
@ -2968,7 +2968,10 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
?>,
|
?>,
|
||||||
broadcast() {
|
broadcast() {
|
||||||
try {
|
try {
|
||||||
const subtotal = this.items.reduce((sum, item) => sum + (parseFloat(item.price) * item.qty), 0);
|
// Ensure items is an array
|
||||||
|
if (!Array.isArray(this.items)) this.items = [];
|
||||||
|
|
||||||
|
const subtotal = this.items.reduce((sum, item) => sum + (parseFloat(item.price) * parseFloat(item.qty)), 0);
|
||||||
let discountAmount = 0;
|
let discountAmount = 0;
|
||||||
if (this.discount) {
|
if (this.discount) {
|
||||||
discountAmount = this.discount.type === 'percentage' ? subtotal * (parseFloat(this.discount.value) / 100) : parseFloat(this.discount.value);
|
discountAmount = this.discount.type === 'percentage' ? subtotal * (parseFloat(this.discount.value) / 100) : parseFloat(this.discount.value);
|
||||||
@ -2983,14 +2986,14 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
items: this.items.map(i => ({
|
items: this.items.map(i => ({
|
||||||
name: (document.documentElement.lang === 'ar' ? (i.nameAr || i.nameEn) : (i.nameEn || i.nameAr)),
|
name: (document.documentElement.lang === 'ar' ? (i.nameAr || i.nameEn) : (i.nameEn || i.nameAr)) || 'Unknown Item',
|
||||||
price: parseFloat(i.price),
|
price: parseFloat(i.price) || 0,
|
||||||
qty: parseFloat(i.qty)
|
qty: parseFloat(i.qty) || 0
|
||||||
})),
|
})),
|
||||||
subtotal: subtotal,
|
subtotal: parseFloat(subtotal) || 0,
|
||||||
discount: discountAmount,
|
discount: parseFloat(discountAmount) || 0,
|
||||||
loyalty: loyaltyRedeemed,
|
loyalty: parseFloat(loyaltyRedeemed) || 0,
|
||||||
total: total,
|
total: parseFloat(total) || 0,
|
||||||
customerName: customerName,
|
customerName: customerName,
|
||||||
theme: document.body.className,
|
theme: document.body.className,
|
||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user