function updateSortArrows() { const arrows = { sensorNr: document.getElementById('sortArrowSensorNr'), espId: document.getElementById('sortArrowEspId'), date: document.getElementById('sortArrowDate') }; Object.entries(arrows).forEach(([key, el]) => { if (!el) return; // Aktiver Pfeil fett, andere ausgegraut el.textContent = currentSort.key === key ? (currentSort.asc ? '↑' : '↓') : '↑'; el.style.fontWeight = currentSort.key === key ? 'bold' : 'normal'; el.style.opacity = currentSort.key === key ? '1' : '0.3'; }); } // Tab-Wechsel Funktion aus index.pug function showTab(tab) { document.getElementById('tabInputContent').style.display = tab === 'input' ? '' : 'none'; document.getElementById('tabListContent').style.display = tab === 'list' ? '' : 'none'; document.getElementById('tabInput').classList.toggle('active', tab === 'input'); document.getElementById('tabList').classList.toggle('active', tab === 'list'); } document.addEventListener('DOMContentLoaded', () => { const saveBtn = document.getElementById('saveBtn'); const refreshBtn = document.getElementById('refreshBtn'); const espIdInput = document.getElementById('espId'); const sensorNumberInput = document.getElementById('sensorNumber'); const nameInput = document.getElementById('name'); const descriptionInput = document.getElementById('description'); const addressInput = document.getElementById('address'); const pageInput = document.getElementById('page'); const limitInput = document.getElementById('limit'); const resultDiv = document.getElementById('result'); const tableBody = document.querySelector('#entriesTable tbody'); const tabInput = document.getElementById('tabInput'); const tabList = document.getElementById('tabList'); let editId = null; // Modal für Fehleranzeige function showModal(message, showCancelButton, callback) { // Remove previous modals document.querySelectorAll('.custom-modal-popup').forEach(m => m.remove()); let modal = document.createElement('div'); modal.className = 'custom-modal-popup'; let box = document.createElement('div'); box.className = 'custom-modal-box'; let msg = document.createElement('div'); msg.className = 'custom-modal-msg'; msg.textContent = message; box.appendChild(msg); let btndiv = document.createElement('div') btndiv.className = 'twobuttons' // Cancel Button (only if showCancelButton is true) if (showCancelButton) { let btnCancel = document.createElement('button'); btnCancel.className = 'custom-modal-btn'; btnCancel.textContent = 'Abbruch'; btnCancel.onclick = () => { if (modal.parentNode) { modal.parentNode.removeChild(modal); } if (callback) callback(false); // Pass false for Cancel }; btndiv.appendChild(btnCancel); } // OK Button let btnOk = document.createElement('button'); btnOk.className = 'custom-modal-btn'; btnOk.textContent = 'OK'; btnOk.onclick = () => { if (modal.parentNode) { modal.parentNode.removeChild(modal); } if (callback) callback(true); // Pass true for OK }; btndiv.appendChild(btnOk); box.appendChild(btndiv) modal.appendChild(box); document.body.appendChild(modal); // Optional: Close modal when clicking outside modal.onclick = (e) => { if (e.target === modal) { if (modal.parentNode) { modal.parentNode.removeChild(modal); } if (callback) callback(false); // Treat as cancel } }; } // Sensornummer nur Zahlen erlauben sensorNumberInput.addEventListener('input', () => { sensorNumberInput.value = sensorNumberInput.value.replace(/\D/g, ''); }); // Adresse vom Server holen, wenn Enter oder Feld verlassen async function fetchAddressIfValid() { const value = sensorNumberInput.value.trim(); if (value.length > 0) { try { const res = await fetch(`/api/address/${value}`); const data = await res.json(); console.dir(data) if (!data.error && data.address) { addressInput.value = data.address; // Felder automatisch füllen, wenn props vorhanden if (!data.props.error) { if (data.props.erg.chip !== undefined) { let pp = data.props.erg.chip espIdInput.value = pp.id || '' nameInput.value = pp.name || '' descriptionInput.value = pp.description || '' // Weitere Felder nach Bedarf } } } else { addressInput.value = ''; sensorNumberInput.disabled = true; showModal('Sensor unbekannt', false, () => { sensorNumberInput.disabled = false; sensorNumberInput.focus(); }); } } catch (err) { console.error('Fehler beim Abrufen der Adresse:', err); addressInput.value = ''; sensorNumberInput.disabled = true; showModal('Sensor unbekannt', false, () => { sensorNumberInput.disabled = false; sensorNumberInput.focus(); }); } } } // Enter-Taste sensorNumberInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); fetchAddressIfValid(); } }); // Feld verlassen sensorNumberInput.addEventListener('blur', fetchAddressIfValid); async function saveEntry() { const espId = espIdInput.value.trim(); const sensorNumber = sensorNumberInput.value.trim(); const name = nameInput.value.trim(); const description = descriptionInput.value.trim(); const address = addressInput.value.trim(); if (!espId || !sensorNumber) { resultDiv.textContent = 'ESP-ID und Sensornummer sind Pflichtfelder.'; return; } try { const url = '/api/save'; const method = 'POST'; const res = await fetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ espId, sensorNumber, name, description, address }) }); const data = await res.json(); if (data.error) { resultDiv.textContent = data.error; } else { resultDiv.textContent = 'OK!'; setTimeout(() => { resultDiv.textContent = '' saveBtn.textContent = 'Speichern'; }, 5000) clearForm(false); await loadEntries(); } } catch (err) { console.error(err); resultDiv.textContent = 'Fehler beim Speichern.'; } } function clearForm(mitButton) { espIdInput.value = ''; sensorNumberInput.value = ''; nameInput.value = ''; descriptionInput.value = ''; addressInput.value = ''; editId = null; if (mitButton) { saveBtn.textContent = 'Speichern'; } } // Globale Sortier-Variable window.currentSort = window.currentSort || { key: null, asc: true }; async function loadEntries() { const page = parseInt(pageInput.value) || 1; const limit = parseInt(limitInput.value) || 50; try { const res = await fetch(`/api/list?page=${page}&limit=${limit}`); const erg = await res.json(); const items = erg.items const gz = document.getElementById('gzahl'); gz.innerHTML = `Gesamtzahl: ${erg.anzahl}` let currentSort = window.currentSort || { key: null, asc: true }; function renderTable(sortedItems) { tableBody.innerHTML = ''; sortedItems.forEach(item => { const date = new Date(item.chip.lastUpdatedAt).toISOString().split('T')[0]; const tr = document.createElement('tr'); tr.innerHTML = ` ${item._id} ${item.chip.id} ${item.chip.name || ''} ${item.chip.description || ''} ${date}
`; tableBody.appendChild(tr); }); } function sortItems(items, key, asc) { return items.slice().sort((a, b) => { let valA, valB; if (key === 'sensorNr') { valA = a._id; valB = b._id; } else if (key === 'espId') { valA = a.chip.id; valB = b.chip.id; } else if (key === 'date') { valA = new Date(a.chip.lastUpdatedAt); valB = new Date(b.chip.lastUpdatedAt); } if (valA < valB) return asc ? -1 : 1; if (valA > valB) return asc ? 1 : -1; return 0; }); } // Initial render: Standard nach SensorNr, ESP-ID oder Datum aufsteigend // Ändere hier die Spalte für die Standardsortierung: const defaultSortKey = window.currentSort && window.currentSort.key ? window.currentSort.key : 'sensorNr'; const defaultSortAsc = window.currentSort && typeof window.currentSort.asc === 'boolean' ? window.currentSort.asc : true; currentSort.key = defaultSortKey; currentSort.asc = defaultSortAsc; window.currentSort = currentSort; renderTable(sortItems(items, defaultSortKey, defaultSortAsc)); updateSortArrows(); // Add sort listeners document.getElementById('thSensorNr').onclick = () => { currentSort.asc = currentSort.key === 'sensorNr' ? !currentSort.asc : true; currentSort.key = 'sensorNr'; window.currentSort = currentSort; renderTable(sortItems(items, 'sensorNr', currentSort.asc)); updateSortArrows(); }; document.getElementById('thEspId').onclick = () => { currentSort.asc = currentSort.key === 'espId' ? !currentSort.asc : true; currentSort.key = 'espId'; window.currentSort = currentSort; renderTable(sortItems(items, 'espId', currentSort.asc)); updateSortArrows(); }; document.getElementById('thDate').onclick = () => { currentSort.asc = currentSort.key === 'date' ? !currentSort.asc : true; currentSort.key = 'date'; window.currentSort = currentSort; renderTable(sortItems(items, 'date', currentSort.asc)); updateSortArrows(); }; document.querySelectorAll('.deleteBtn').forEach(btn => { btn.addEventListener('click', async () => { const id = btn.getAttribute('data-id'); await deleteEntry(id); }); }); document.querySelectorAll('.editBtn').forEach(btn => { btn.addEventListener('click', async () => { const id = btn.getAttribute('data-id'); const res = await fetch(`/api/list?page=1&limit=1&id=${id}`); const items = await res.json(); const item = items.find(e => e._id === parseInt(id)); if (item) { espIdInput.value = item.chip.id; sensorNumberInput.value = item._id; nameInput.value = item.chip.name || ''; descriptionInput.value = item.chip.description || ''; addressInput.value = ''; editId = id; try { const rt = await fetch(`api/holAdresse/${item._id}`) const data = await rt.json(); console.dir(data) if (!data.error && data.address) { addressInput.value = data.address; } } catch (e) { console.log("Fehler beim Adresse holen", e) } saveBtn.textContent = 'Aktualisieren'; showTab('input') } }); }); } catch (err) { console.error(err); resultDiv.textContent = 'Fehler beim Laden.'; } } async function deleteEntry(id) { showModal('Wirklich löschen?', true, async (confirmed) => { if (confirmed) { try { const res = await fetch(`/api/delete/${id}`, { method: 'DELETE' }); const data = await res.json(); if (data.success) { await loadEntries(); resultDiv.textContent = 'Eintrag gelöscht.'; setTimeout(() => resultDiv.textContent = '', 3000); } else { resultDiv.textContent = 'Fehler beim Löschen.'; } } catch (err) { console.error(err); resultDiv.textContent = 'Fehler beim Löschen.'; } } }); } saveBtn.addEventListener('click', saveEntry); refreshBtn.addEventListener('click', loadEntries); cancelBtn.addEventListener('click', () => clearForm(true)); tabInput.addEventListener('click', () => showTab('input')) tabList.addEventListener('click', () => showTab('list')) loadEntries(); });