Initial commit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 22:27:27 -08:00
parent 4387f6df92
commit 492e1fd68f
32 changed files with 2608 additions and 0 deletions

118
nginx/html/js/history.js Normal file
View File

@@ -0,0 +1,118 @@
let currentData = [];
async function loadHistory() {
const tbody = document.getElementById('history-body');
const tfoot = document.getElementById('history-foot');
const msg = document.getElementById('msg');
const start = document.getElementById('filter-start').value;
const end = document.getElementById('filter-end').value;
let url = '/api/eggs';
const params = new URLSearchParams();
if (start) params.set('start', start);
if (end) params.set('end', end);
if ([...params].length) url += '?' + params.toString();
try {
currentData = await API.get(url);
if (currentData.length === 0) {
tbody.innerHTML = '<tr class="empty-row"><td colspan="4">No entries found.</td></tr>';
tfoot.innerHTML = '';
return;
}
renderTable();
} catch (err) {
showMessage(msg, `Failed to load history: ${err.message}`, 'error');
}
}
function renderTable() {
const tbody = document.getElementById('history-body');
const tfoot = document.getElementById('history-foot');
// Update result count label
const total = currentData.reduce((sum, e) => sum + e.eggs, 0);
const countEl = document.getElementById('result-count');
if (countEl) countEl.textContent = `${currentData.length} entries · ${total} eggs`;
tbody.innerHTML = currentData.map(e => `
<tr data-id="${e.id}">
<td>${fmtDate(e.date)}</td>
<td>${e.eggs}</td>
<td class="notes">${e.notes || ''}</td>
<td class="actions">
<button class="btn btn-ghost btn-sm" onclick="startEdit(${e.id})">Edit</button>
<button class="btn btn-danger btn-sm" onclick="deleteEntry(${e.id})">Delete</button>
</td>
</tr>
`).join('');
// Total row in footer
tfoot.innerHTML = `
<tr class="total-row">
<td colspan="1">Total</td>
<td>${total}</td>
<td colspan="2">${currentData.length} entries</td>
</tr>
`;
}
function startEdit(id) {
const entry = currentData.find(e => e.id === id);
const row = document.querySelector(`tr[data-id="${id}"]`);
row.innerHTML = `
<td><input type="date" value="${entry.date}"></td>
<td><input type="number" min="0" value="${entry.eggs}" style="width:80px;"></td>
<td><input type="text" value="${entry.notes || ''}" placeholder="Notes"></td>
<td class="actions">
<button class="btn btn-primary btn-sm" onclick="saveEdit(${id})">Save</button>
<button class="btn btn-ghost btn-sm" onclick="renderTable()">Cancel</button>
</td>
`;
}
async function saveEdit(id) {
const msg = document.getElementById('msg');
const row = document.querySelector(`tr[data-id="${id}"]`);
const [dateInput, eggsInput, notesInput] = row.querySelectorAll('input');
try {
const updated = await API.put(`/api/eggs/${id}`, {
date: dateInput.value,
eggs: parseInt(eggsInput.value, 10),
notes: notesInput.value.trim() || null,
});
// Update local data and re-render
const idx = currentData.findIndex(e => e.id === id);
currentData[idx] = updated;
renderTable();
showMessage(msg, 'Entry updated.');
} catch (err) {
showMessage(msg, `Error: ${err.message}`, 'error');
}
}
async function deleteEntry(id) {
if (!confirm('Delete this entry?')) return;
const msg = document.getElementById('msg');
try {
await API.del(`/api/eggs/${id}`);
currentData = currentData.filter(e => e.id !== id);
renderTable();
showMessage(msg, 'Entry deleted.');
} catch (err) {
showMessage(msg, `Error: ${err.message}`, 'error');
}
}
function clearFilter() {
document.getElementById('filter-start').value = '';
document.getElementById('filter-end').value = '';
loadHistory();
}
document.addEventListener('DOMContentLoaded', loadHistory);