Spaces:
Running
Running
Update ui.js
Browse files
ui.js
CHANGED
|
@@ -16,9 +16,9 @@ export function refreshUI() {
|
|
| 16 |
renderProductInputs();
|
| 17 |
renderInventory();
|
| 18 |
renderProductionLog();
|
| 19 |
-
renderModals();
|
| 20 |
renderReorderList();
|
| 21 |
-
attachAllListeners();
|
| 22 |
}
|
| 23 |
|
| 24 |
export function showToast(message, type = 'info') {
|
|
@@ -127,7 +127,8 @@ function renderProductionHistoryChart() {
|
|
| 127 |
}]
|
| 128 |
},
|
| 129 |
options: {
|
| 130 |
-
responsive: true,
|
|
|
|
| 131 |
plugins: { legend: { display: false } },
|
| 132 |
scales: {
|
| 133 |
y: { beginAtZero: true, grid: { color: 'hsl(220, 13%, 30%)' } },
|
|
@@ -167,7 +168,8 @@ function renderInventoryStatusChart() {
|
|
| 167 |
type: 'doughnut',
|
| 168 |
data: data,
|
| 169 |
options: {
|
| 170 |
-
responsive: true,
|
|
|
|
| 171 |
plugins: { legend: { position: 'top', labels: { color: 'hsl(210, 14%, 66%)' } } }
|
| 172 |
}
|
| 173 |
});
|
|
@@ -175,8 +177,14 @@ function renderInventoryStatusChart() {
|
|
| 175 |
}
|
| 176 |
|
| 177 |
function renderModals() {
|
| 178 |
-
document.getElementById('reset-modal')
|
| 179 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 180 |
}
|
| 181 |
|
| 182 |
export function renderReport(type) {
|
|
@@ -205,6 +213,7 @@ export function renderReport(type) {
|
|
| 205 |
|
| 206 |
function renderProductInputs() {
|
| 207 |
const container = document.getElementById('product-cards');
|
|
|
|
| 208 |
container.innerHTML = '';
|
| 209 |
for (const productName in appState.productRecipes) {
|
| 210 |
const cardHTML = `<div class="dashboard-card p-4 border-l-4 border-l-transparent"><h3 class="font-medium mb-3">${productName}</h3><div class="flex items-center space-x-3"><input type="number" min="0" class="input-field w-20" value="0"><button class="btn btn-primary flex-1 update-btn" data-product-name="${productName}">Produce</button></div></div>`;
|
|
@@ -214,12 +223,13 @@ function renderProductInputs() {
|
|
| 214 |
|
| 215 |
function renderInventory() {
|
| 216 |
const container = document.getElementById('material-cards');
|
|
|
|
| 217 |
container.innerHTML = '';
|
| 218 |
appState.materials.forEach(material => {
|
| 219 |
const stockPercentage = (material.currentStock / material.maxStock) * 100;
|
| 220 |
let statusColor = 'var(--accent-green)';
|
| 221 |
if (stockPercentage <= 50) statusColor = 'var(--accent-yellow)';
|
| 222 |
-
if (
|
| 223 |
const cardHTML = `<div class="dashboard-card p-4 border-l-4" style="border-left-color: ${statusColor}" data-material-name="${material.name}"><div class="flex justify-between items-start mb-1"><h3 class="font-medium text-sm">${material.name}</h3><div class="text-xs text-secondary flex items-center gap-3"><span>MAX:</span><span class="font-semibold max-stock-value">${material.maxStock}</span><i class="fas fa-plus-circle icon-btn restock-icon" title="Restock"></i><i class="fas fa-pencil-alt icon-btn edit-max-stock" title="Edit Max Stock"></i></div></div><div class="flex justify-between items-baseline mb-2"><div class="text-2xl font-bold">${material.currentStock}</div><span class="text-sm text-secondary">${material.unit}</span></div><div class="w-full bg-dark rounded-full h-1.5"><div class="h-1.5 rounded-full" style="width: ${stockPercentage}%; background-color: ${statusColor};"></div></div><div class="restock-form mt-2 hidden"></div></div>`;
|
| 224 |
container.insertAdjacentHTML('beforeend', cardHTML);
|
| 225 |
});
|
|
@@ -227,6 +237,7 @@ function renderInventory() {
|
|
| 227 |
|
| 228 |
function renderProductionLog() {
|
| 229 |
const list = document.getElementById('production-log-list');
|
|
|
|
| 230 |
list.innerHTML = '';
|
| 231 |
if (appState.productionLog.length === 0) { list.innerHTML = `<li class="text-secondary text-center pt-4">No production recorded yet.</li>`; return; }
|
| 232 |
[...appState.productionLog].reverse().forEach(entry => {
|
|
@@ -239,12 +250,26 @@ function renderProductionLog() {
|
|
| 239 |
|
| 240 |
function renderReorderList() {
|
| 241 |
const list = document.getElementById('reorder-list');
|
|
|
|
|
|
|
|
|
|
| 242 |
list.innerHTML = '';
|
|
|
|
|
|
|
| 243 |
const itemsToReorder = appState.materials.filter(m => m.currentStock <= m.reorderPoint);
|
| 244 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
itemsToReorder.forEach(item => {
|
| 246 |
const needed = item.maxStock - item.currentStock;
|
| 247 |
-
const itemHTML = `<li class="p-3 rounded-md text-sm flex justify-between items-center" style="background-color: #f6e05e20;"
|
| 248 |
list.insertAdjacentHTML('beforeend', itemHTML);
|
| 249 |
});
|
| 250 |
}
|
|
|
|
| 16 |
renderProductInputs();
|
| 17 |
renderInventory();
|
| 18 |
renderProductionLog();
|
| 19 |
+
renderModals(); // Still needed to create modal structure initially
|
| 20 |
renderReorderList();
|
| 21 |
+
attachAllListeners(); // Attaches non-persistent listeners
|
| 22 |
}
|
| 23 |
|
| 24 |
export function showToast(message, type = 'info') {
|
|
|
|
| 127 |
}]
|
| 128 |
},
|
| 129 |
options: {
|
| 130 |
+
responsive: true,
|
| 131 |
+
maintainAspectRatio: false, // Important for responsive containers
|
| 132 |
plugins: { legend: { display: false } },
|
| 133 |
scales: {
|
| 134 |
y: { beginAtZero: true, grid: { color: 'hsl(220, 13%, 30%)' } },
|
|
|
|
| 168 |
type: 'doughnut',
|
| 169 |
data: data,
|
| 170 |
options: {
|
| 171 |
+
responsive: true,
|
| 172 |
+
maintainAspectRatio: false, // Important for responsive containers
|
| 173 |
plugins: { legend: { position: 'top', labels: { color: 'hsl(210, 14%, 66%)' } } }
|
| 174 |
}
|
| 175 |
});
|
|
|
|
| 177 |
}
|
| 178 |
|
| 179 |
function renderModals() {
|
| 180 |
+
const resetModal = document.getElementById('reset-modal');
|
| 181 |
+
if (resetModal && resetModal.innerHTML === '') {
|
| 182 |
+
resetModal.innerHTML = `<div class="modal-content dashboard-card p-6 max-w-sm w-full mx-4"><h3 class="text-lg font-semibold mb-2">Confirm Reset</h3><p class="text-secondary mb-4">Are you sure you want to reset all inventory data? This action cannot be undone.</p><div class="flex justify-end space-x-2"><button id="cancel-reset-btn" class="btn btn-secondary">Cancel</button><button id="confirm-reset-btn" class="btn btn-danger">Reset Data</button></div></div>`;
|
| 183 |
+
}
|
| 184 |
+
const reportsModal = document.getElementById('reports-modal');
|
| 185 |
+
if (reportsModal && reportsModal.innerHTML === '') {
|
| 186 |
+
reportsModal.innerHTML = `<div class="modal-content dashboard-card p-6 max-w-2xl w-full mx-4"><div class="flex justify-between items-center mb-4"><h3 class="text-lg font-semibold">Generate Report</h3><button id="close-reports-modal-btn" class="text-secondary hover:text-primary text-2xl">×</button></div><div class="flex gap-4 mb-4"><button id="report-prod-summary" class="flex-1 btn btn-primary">Monthly Production</button><button id="report-mat-usage" class="flex-1 btn btn-primary" style="background-color: var(--accent-green);">Monthly Material Usage</button></div><div id="report-content" class="p-4 border border-border-color rounded bg-dark min-h-[300px]">Select a report to view data.</div></div>`;
|
| 187 |
+
}
|
| 188 |
}
|
| 189 |
|
| 190 |
export function renderReport(type) {
|
|
|
|
| 213 |
|
| 214 |
function renderProductInputs() {
|
| 215 |
const container = document.getElementById('product-cards');
|
| 216 |
+
if (!container) return;
|
| 217 |
container.innerHTML = '';
|
| 218 |
for (const productName in appState.productRecipes) {
|
| 219 |
const cardHTML = `<div class="dashboard-card p-4 border-l-4 border-l-transparent"><h3 class="font-medium mb-3">${productName}</h3><div class="flex items-center space-x-3"><input type="number" min="0" class="input-field w-20" value="0"><button class="btn btn-primary flex-1 update-btn" data-product-name="${productName}">Produce</button></div></div>`;
|
|
|
|
| 223 |
|
| 224 |
function renderInventory() {
|
| 225 |
const container = document.getElementById('material-cards');
|
| 226 |
+
if (!container) return;
|
| 227 |
container.innerHTML = '';
|
| 228 |
appState.materials.forEach(material => {
|
| 229 |
const stockPercentage = (material.currentStock / material.maxStock) * 100;
|
| 230 |
let statusColor = 'var(--accent-green)';
|
| 231 |
if (stockPercentage <= 50) statusColor = 'var(--accent-yellow)';
|
| 232 |
+
if (material.currentStock <= material.reorderPoint) statusColor = 'var(--accent-red)'; // Changed logic to use reorder point for red
|
| 233 |
const cardHTML = `<div class="dashboard-card p-4 border-l-4" style="border-left-color: ${statusColor}" data-material-name="${material.name}"><div class="flex justify-between items-start mb-1"><h3 class="font-medium text-sm">${material.name}</h3><div class="text-xs text-secondary flex items-center gap-3"><span>MAX:</span><span class="font-semibold max-stock-value">${material.maxStock}</span><i class="fas fa-plus-circle icon-btn restock-icon" title="Restock"></i><i class="fas fa-pencil-alt icon-btn edit-max-stock" title="Edit Max Stock"></i></div></div><div class="flex justify-between items-baseline mb-2"><div class="text-2xl font-bold">${material.currentStock}</div><span class="text-sm text-secondary">${material.unit}</span></div><div class="w-full bg-dark rounded-full h-1.5"><div class="h-1.5 rounded-full" style="width: ${stockPercentage}%; background-color: ${statusColor};"></div></div><div class="restock-form mt-2 hidden"></div></div>`;
|
| 234 |
container.insertAdjacentHTML('beforeend', cardHTML);
|
| 235 |
});
|
|
|
|
| 237 |
|
| 238 |
function renderProductionLog() {
|
| 239 |
const list = document.getElementById('production-log-list');
|
| 240 |
+
if (!list) return;
|
| 241 |
list.innerHTML = '';
|
| 242 |
if (appState.productionLog.length === 0) { list.innerHTML = `<li class="text-secondary text-center pt-4">No production recorded yet.</li>`; return; }
|
| 243 |
[...appState.productionLog].reverse().forEach(entry => {
|
|
|
|
| 250 |
|
| 251 |
function renderReorderList() {
|
| 252 |
const list = document.getElementById('reorder-list');
|
| 253 |
+
const header = document.getElementById('reorder-header');
|
| 254 |
+
if (!list || !header) return;
|
| 255 |
+
|
| 256 |
list.innerHTML = '';
|
| 257 |
+
header.querySelector('#generate-full-po-btn')?.remove(); // Remove old button
|
| 258 |
+
|
| 259 |
const itemsToReorder = appState.materials.filter(m => m.currentStock <= m.reorderPoint);
|
| 260 |
+
|
| 261 |
+
if (itemsToReorder.length === 0) {
|
| 262 |
+
list.innerHTML = `<li class="text-secondary text-center pt-4">All stock levels are healthy.</li>`;
|
| 263 |
+
return;
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
// Add the consolidated button
|
| 267 |
+
const poButton = `<button id="generate-full-po-btn" class="btn btn-secondary text-sm">Generate Full Reorder Report</button>`;
|
| 268 |
+
header.insertAdjacentHTML('beforeend', poButton);
|
| 269 |
+
|
| 270 |
itemsToReorder.forEach(item => {
|
| 271 |
const needed = item.maxStock - item.currentStock;
|
| 272 |
+
const itemHTML = `<li class="p-3 rounded-md text-sm flex justify-between items-center" style="background-color: #f6e05e20;"><div class="flex-grow"><span class="font-semibold">${item.name}</span><span class="text-xs text-secondary block">Stock: ${item.currentStock} / ${item.reorderPoint} (Need ${needed})</span></div><div class="text-right"><span class="font-bold">${needed}</span><span class="text-xs text-secondary ml-1">${item.unit}</span></div></li>`;
|
| 273 |
list.insertAdjacentHTML('beforeend', itemHTML);
|
| 274 |
});
|
| 275 |
}
|