`;
}
// Render all modifiers (flattened, no nested wrappers)
function renderAllModifiers(modifiers, allItems) {
let html = '
';
// Build path for each leaf modifier
function getModifierPath(mod) {
const path = [];
let current = mod;
// Walk up the tree to build the path
while (current) {
path.unshift(current.ItemName);
const parentId = current.OrderLineItemParentOrderLineItemID;
if (parentId === 0) break;
current = allItems.find(item => item.OrderLineItemID === parentId);
}
return path;
}
// Collect all leaf modifiers with their paths
const leafModifiers = [];
function collectLeafModifiers(mods) {
mods.forEach(mod => {
const children = allItems.filter(item => item.OrderLineItemParentOrderLineItemID === mod.OrderLineItemID);
if (children.length === 0) {
// This is a leaf - no children
const path = getModifierPath(mod);
leafModifiers.push({ mod, path });
} else {
// This has children, recurse into them
collectLeafModifiers(children);
}
});
}
collectLeafModifiers(modifiers);
// Render leaf modifiers with breadcrumb paths
leafModifiers.forEach(({ path }) => {
const displayText = path.join(': ');
html += `
+ ${escapeHtml(displayText)}
`;
});
html += '
';
return html;
}
// Render modifier recursively with indentation
function renderModifierRecursive(modifier, allItems, level) {
const subModifiers = allItems.filter(mod => mod.OrderLineItemParentOrderLineItemID === modifier.OrderLineItemID);
// For KDS MVP: no indentation, just flat list
const indent = 0; // Changed from: level * 20
console.log(`[renderModifierRecursive] Level ${level}: ${modifier.ItemName} (ID: ${modifier.OrderLineItemID}), Sub-modifiers: ${subModifiers.length}`);
let html = `
+ ${escapeHtml(modifier.ItemName)}
`;
// Recursively render sub-modifiers
if (subModifiers.length > 0) {
subModifiers.forEach(sub => {
html += renderModifierRecursive(sub, allItems, level + 1);
});
}
return html;
}
// Render action buttons based on order status
function renderActionButtons(order) {
switch (order.OrderStatusID) {
case STATUS.NEW:
return ``;
case STATUS.PREPARING:
return ``;
case STATUS.READY:
return ``;
default:
return '';
}
}
// Update order status
async function updateOrderStatus(orderId, newStatusId) {
try {
const response = await fetch(`${config.apiBaseUrl}/orders/updateStatus.cfm`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
OrderID: orderId,
StatusID: newStatusId
})
});
const data = await response.json();
if (data.OK) {
// Immediately reload orders to reflect the change
await loadOrders();
} else {
alert(`Failed to update order: ${data.MESSAGE || data.ERROR}`);
}
} catch (error) {
console.error('Failed to update order status:', error);
alert('Failed to update order status. Please try again.');
}
}
// Helper functions
function getStatusClass(statusId) {
switch (statusId) {
case STATUS.NEW: return 'new';
case STATUS.PREPARING: return 'preparing';
case STATUS.READY: return 'ready';
default: return '';
}
}
function getElapsedTime(submittedOn) {
if (!submittedOn) return 0;
const submitted = new Date(submittedOn);
const now = new Date();
return Math.floor((now - submitted) / 1000); // seconds
}
function getTimeClass(seconds) {
if (seconds > 900) return 'critical'; // > 15 min
if (seconds > 600) return 'warning'; // > 10 min
return '';
}
function formatElapsedTime(seconds) {
const minutes = Math.floor(seconds / 60);
const secs = seconds % 60;
return `${minutes}:${secs.toString().padStart(2, '0')}`;
}
function formatSubmitTime(dateString) {
if (!dateString) return '';
const date = new Date(dateString);
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}