Spaces:
Sleeping
Sleeping
Aryanshh commited on
Commit ·
3a65d8a
1
Parent(s): 04438ae
feat: Reverse dashboard layout and add inventory requirement validation
Browse files- dashboard/app.js +34 -33
- dashboard/style.css +21 -2
dashboard/app.js
CHANGED
|
@@ -38,50 +38,51 @@ const TUTORIAL_STEPS = [
|
|
| 38 |
|
| 39 |
let currentTutStep = 0;
|
| 40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
// State Management
|
| 42 |
async function updateState() {
|
| 43 |
try {
|
| 44 |
const response = await fetch(`${API_BASE}/state`);
|
| 45 |
if (!response.ok) throw new Error('API Unreachable');
|
| 46 |
const data = await response.json();
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
status.textContent = 'ONLINE';
|
| 50 |
-
status.className = 'status-badge status-online';
|
| 51 |
-
|
| 52 |
-
document.getElementById('carbon-value').textContent = data.carbon.toFixed(0);
|
| 53 |
-
document.getElementById('cash-value').textContent = data.cash.toLocaleString();
|
| 54 |
document.getElementById('chips-count').textContent = data.inventory.chips;
|
| 55 |
document.getElementById('sensors-count').textContent = data.inventory.sensors;
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
if (data.news) {
|
| 59 |
-
document.getElementById('news-text').textContent = data.news;
|
| 60 |
-
newsAlert.classList.remove('hidden');
|
| 61 |
-
} else {
|
| 62 |
-
newsAlert.classList.add('hidden');
|
| 63 |
-
}
|
| 64 |
-
|
| 65 |
-
const container = document.getElementById('shipments-container');
|
| 66 |
-
if (data.orders && data.orders.length > 0) {
|
| 67 |
-
container.innerHTML = data.orders.map(order => `
|
| 68 |
-
<div class="shipment-item">
|
| 69 |
-
<span>${order.product} (Required: ${order.quantity})</span>
|
| 70 |
-
<small>Deadline: Day ${order.due_date}</small>
|
| 71 |
-
</div>
|
| 72 |
-
`).join('');
|
| 73 |
-
} else {
|
| 74 |
-
container.innerHTML = '<p class="placeholder">All orders fulfilled. Environment reset recommended.</p>';
|
| 75 |
-
}
|
| 76 |
-
|
| 77 |
-
} catch (error) {
|
| 78 |
-
console.error('Update failed:', error);
|
| 79 |
-
const status = document.getElementById('connection-status');
|
| 80 |
-
status.textContent = 'RECONNECTING...';
|
| 81 |
-
status.className = 'status-badge';
|
| 82 |
}
|
| 83 |
}
|
| 84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
// UI Controls
|
| 86 |
const modeSelect = document.getElementById('mode-select');
|
| 87 |
|
|
|
|
| 38 |
|
| 39 |
let currentTutStep = 0;
|
| 40 |
|
| 41 |
+
// Global State for UI calculation
|
| 42 |
+
let latestInventory = { chips: 0, sensors: 0 };
|
| 43 |
+
|
| 44 |
+
const RECIPES = {
|
| 45 |
+
"EcoPhone": { chips: 1, sensors: 2 },
|
| 46 |
+
"GreenTab": { chips: 2, sensors: 1 }
|
| 47 |
+
};
|
| 48 |
+
|
| 49 |
// State Management
|
| 50 |
async function updateState() {
|
| 51 |
try {
|
| 52 |
const response = await fetch(`${API_BASE}/state`);
|
| 53 |
if (!response.ok) throw new Error('API Unreachable');
|
| 54 |
const data = await response.json();
|
| 55 |
+
latestInventory = data.inventory;
|
| 56 |
+
...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
document.getElementById('chips-count').textContent = data.inventory.chips;
|
| 58 |
document.getElementById('sensors-count').textContent = data.inventory.sensors;
|
| 59 |
+
updateProducePreview();
|
| 60 |
+
...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
}
|
| 62 |
}
|
| 63 |
|
| 64 |
+
function updateProducePreview() {
|
| 65 |
+
const product = document.getElementById('product-select').value;
|
| 66 |
+
const req = RECIPES[product];
|
| 67 |
+
const preview = document.getElementById('req-preview');
|
| 68 |
+
|
| 69 |
+
const chipClass = latestInventory.chips >= req.chips ? "sufficient" : "shortage";
|
| 70 |
+
const sensorClass = latestInventory.sensors >= req.sensors ? "sufficient" : "shortage";
|
| 71 |
+
|
| 72 |
+
preview.innerHTML = `
|
| 73 |
+
<div class="req-item">
|
| 74 |
+
<span>Chips required: ${req.chips}</span>
|
| 75 |
+
<span class="${chipClass}">Avl: ${latestInventory.chips} ${latestInventory.chips < req.chips ? '(SHORT)' : ''}</span>
|
| 76 |
+
</div>
|
| 77 |
+
<div class="req-item">
|
| 78 |
+
<span>Sensors required: ${req.sensors}</span>
|
| 79 |
+
<span class="${sensorClass}">Avl: ${latestInventory.sensors} ${latestInventory.sensors < req.sensors ? '(SHORT)' : ''}</span>
|
| 80 |
+
</div>
|
| 81 |
+
`;
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
document.getElementById('product-select').addEventListener('change', updateProducePreview);
|
| 85 |
+
|
| 86 |
// UI Controls
|
| 87 |
const modeSelect = document.getElementById('mode-select');
|
| 88 |
|
dashboard/style.css
CHANGED
|
@@ -98,7 +98,7 @@ header {
|
|
| 98 |
|
| 99 |
main {
|
| 100 |
display: grid;
|
| 101 |
-
grid-template-columns:
|
| 102 |
gap: 2rem;
|
| 103 |
}
|
| 104 |
|
|
@@ -109,12 +109,31 @@ main {
|
|
| 109 |
}
|
| 110 |
|
| 111 |
.control-panel {
|
| 112 |
-
background: #
|
| 113 |
height: fit-content;
|
| 114 |
position: sticky;
|
| 115 |
top: 2rem;
|
|
|
|
| 116 |
}
|
| 117 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
.details-section, .log-section, .guide-section {
|
| 119 |
grid-column: 1 / -1;
|
| 120 |
}
|
|
|
|
| 98 |
|
| 99 |
main {
|
| 100 |
display: grid;
|
| 101 |
+
grid-template-columns: 400px 1fr;
|
| 102 |
gap: 2rem;
|
| 103 |
}
|
| 104 |
|
|
|
|
| 109 |
}
|
| 110 |
|
| 111 |
.control-panel {
|
| 112 |
+
background: #F4F7F4;
|
| 113 |
height: fit-content;
|
| 114 |
position: sticky;
|
| 115 |
top: 2rem;
|
| 116 |
+
border-right: 2px solid var(--sage-green);
|
| 117 |
}
|
| 118 |
|
| 119 |
+
.req-preview {
|
| 120 |
+
margin: 1rem 0;
|
| 121 |
+
padding: 0.75rem;
|
| 122 |
+
background: #FFF;
|
| 123 |
+
border: 1px solid var(--border-tan);
|
| 124 |
+
border-radius: 8px;
|
| 125 |
+
font-size: 0.8rem;
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
.req-item {
|
| 129 |
+
display: flex;
|
| 130 |
+
justify-content: space-between;
|
| 131 |
+
margin-bottom: 0.25rem;
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
.shortage { color: #E74C3C; font-weight: 600; }
|
| 135 |
+
.sufficient { color: #27AE60; font-weight: 600; }
|
| 136 |
+
|
| 137 |
.details-section, .log-section, .guide-section {
|
| 138 |
grid-column: 1 / -1;
|
| 139 |
}
|