Spaces:
Runtime error
Runtime error
File size: 5,396 Bytes
96027bb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | /**
* TableRenderer.js
* Handles drawing and updating the dining tables in the DOM.
*/
export class TableRenderer {
constructor(containerId) {
this.containerId = containerId;
this.availableTables = [];
this.tableTimers = new Map(); // tableId -> { type: 'countup'|'countdown', startSimTime: 0, limit: 0 }
}
/**
* Clears and redraws the tables based on the simulation config.
*/
draw(tablesCount) {
const container = document.getElementById(this.containerId);
if (!container) return;
container.innerHTML = '';
this.availableTables = [];
this.tableTimers.clear();
for (let i = 0; i < tablesCount; i++) {
container.innerHTML += `
<div class="table" id="table-${i}" data-tooltip="Table is available">
<div class="table__badge" id="badge-table-${i}" style="display: none;">[R]</div>
<div class="table__status" id="status-table-${i}"></div>
</div>
`;
this.availableTables.push(`table-${i}`);
}
}
/**
* Updates the UI based on events
*/
setReserved(tableId, simTime, limit) {
const tableEl = document.getElementById(`table-${tableId}`);
const badgeEl = document.getElementById(`badge-table-${tableId}`);
if (tableEl && badgeEl) {
tableEl.classList.add('table--reserved');
badgeEl.style.display = 'block';
this.tableTimers.set(tableId, { type: 'countdown', startSimTime: simTime, limit: limit });
this._updateTimerDisplay(tableId, simTime);
}
}
setUnreserved(tableId) {
const tableEl = document.getElementById(`table-${tableId}`);
const badgeEl = document.getElementById(`badge-table-${tableId}`);
const statusEl = document.getElementById(`status-table-${tableId}`);
if (tableEl && badgeEl && statusEl) {
tableEl.classList.remove('table--reserved');
badgeEl.style.display = 'none';
statusEl.innerHTML = '';
tableEl.setAttribute('data-tooltip', "Table is available");
this.tableTimers.delete(tableId);
}
}
setOccupied(tableId, simTime, isReservation, state='waiting') {
const tableEl = document.getElementById(`table-${tableId}`);
const badgeEl = document.getElementById(`badge-table-${tableId}`);
if (tableEl) {
if (!isReservation && badgeEl) badgeEl.style.display = 'none';
tableEl.classList.add('table--occupied');
this.tableTimers.set(tableId, { type: 'countup', startSimTime: simTime, state: state });
this._updateTimerDisplay(tableId, simTime);
}
}
setEmpty(tableId) {
const tableEl = document.getElementById(`table-${tableId}`);
const badgeEl = document.getElementById(`badge-table-${tableId}`);
const statusEl = document.getElementById(`status-table-${tableId}`);
if (tableEl && badgeEl && statusEl) {
tableEl.classList.remove('table--occupied');
tableEl.classList.remove('table--reserved');
badgeEl.style.display = 'none';
statusEl.innerHTML = '';
tableEl.setAttribute('data-tooltip', "Table is available");
this.tableTimers.delete(tableId);
}
}
tickTimers(currentSimTime) {
for (const [tableId, _] of this.tableTimers.entries()) {
this._updateTimerDisplay(tableId, currentSimTime);
}
}
_updateTimerDisplay(tableId, currentSimTime) {
const timerData = this.tableTimers.get(tableId);
if (!timerData) return;
const statusEl = document.getElementById(`status-table-${tableId}`);
const tableEl = document.getElementById(`table-${tableId}`);
if (!statusEl || !tableEl) return;
let elapsed = currentSimTime - timerData.startSimTime;
if (elapsed < 0) elapsed = 0;
if (timerData.type === 'countdown') {
let remaining = timerData.limit - elapsed;
if (remaining < 0) remaining = 0;
const mins = Math.floor(remaining / 60);
const secs = Math.floor(remaining % 60).toString().padStart(2, '0');
tableEl.setAttribute('data-tooltip', "Reserved table waiting for customer");
statusEl.innerHTML = `⏳ <span style="font-family: monospace; font-size: 0.8rem;">${mins}:${secs}</span>`;
statusEl.style.color = '#f39c12';
} else if (timerData.type === 'countup') {
const mins = Math.floor(elapsed / 60);
const secs = Math.floor(elapsed % 60).toString().padStart(2, '0');
if (timerData.state === 'waiting') {
tableEl.setAttribute('data-tooltip', "Customer waiting for order");
statusEl.innerHTML = `⏳ <span style="font-family: monospace; font-size: 0.8rem;">${mins}:${secs}</span>`;
statusEl.style.color = '#e94f37';
} else {
tableEl.setAttribute('data-tooltip', "Customer dining at table");
statusEl.innerHTML = `☕ <span style="font-family: monospace; font-size: 0.8rem;">${mins}:${secs}</span>`;
statusEl.style.color = '#4caf50';
}
}
}
}
export const tableRenderer = new TableRenderer('tables');
|