diff --git a/Web/templates/library_table.html b/Web/templates/library_table.html index 0651bf9..bbefe13 100644 --- a/Web/templates/library_table.html +++ b/Web/templates/library_table.html @@ -1042,465 +1042,460 @@ } - async function returnByCode(code) { - if (!code) return; - setScanStatus('Verarbeite Rückgabe...', 'warn'); - try { - const resp = await fetch('/api/library_return_by_code', { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({item_code: code}) - }); - const result = await resp.json(); - if (!resp.ok || !result.ok) { - setScanStatus(result.message || 'Rückgabe fehlgeschlagen.', 'error'); - showSmallConfirm(result.message || 'Rückgabe fehlgeschlagen.', 'error'); - return false; - } - setScanStatus(result.message || `Zurückgegeben: ${result.item_name || ''}`, 'ok'); - showSmallConfirm(result.message || `Zurückgegeben: ${result.item_name || ''}`, 'ok'); - await loadLibraryItems(); - return true; - } catch (err) { - console.error('Return by code failed:', err); - setScanStatus('Fehler bei Rückgabe.', 'error'); - showSmallConfirm('Fehler bei Rückgabe.', 'error'); - return false; - } + async function returnByCode(code) { + if (!code) return; + setScanStatus('Verarbeite Rückgabe...', 'warn'); + try { + const resp = await fetch('/api/library_return_by_code', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({ item_code: code }) + }); + const result = await resp.json(); + if (!resp.ok || !result.ok) { + setScanStatus(result.message || 'Rückgabe fehlgeschlagen.', 'error'); + showSmallConfirm(result.message || 'Rückgabe fehlgeschlagen.', 'error'); + return false; + } + setScanStatus(result.message || `Zurückgegeben: ${result.item_name || ''}`, 'ok'); + showSmallConfirm(result.message || `Zurückgegeben: ${result.item_name || ''}`, 'ok'); + await loadLibraryItems(); + return true; + } catch (err) { + console.error('Return by code failed:', err); + setScanStatus('Fehler bei Rückgabe.', 'error'); + showSmallConfirm('Fehler bei Rückgabe.', 'error'); + return false; + } + } + try { + setScanStatus('Verarbeite Mediencode...', 'warn'); + const response = await fetch('/api/library_scan_action', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({ + student_card_id: activeStudentCardId, + item_code: scannedCode + }) + }); + + const result = await response.json(); + if (!response.ok || !result.ok) { + setScanStatus(result.message || 'Scan-Aktion fehlgeschlagen.', 'error'); + return; } - try { - setScanStatus('Verarbeite Mediencode...', 'warn'); - const response = await fetch('/api/library_scan_action', { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({ - student_card_id: activeStudentCardId, - item_code: scannedCode - }) - }); + if (result.action === 'borrowed') { + setScanStatus(`Ausgeliehen: ${result.item_name}`, 'ok'); + showSmallConfirm(`Ausgeliehen: ${result.item_name}`, 'ok'); + } else if (result.action === 'returned') { + setScanStatus(`Zurückgegeben: ${result.item_name}`, 'ok'); + showSmallConfirm(`Zurückgegeben: ${result.item_name}`, 'ok'); + } else { + setScanStatus(result.message || 'Aktion durchgeführt.', 'ok'); + showSmallConfirm(result.message || 'Aktion durchgeführt.', 'ok'); + } - const result = await response.json(); - if (!response.ok || !result.ok) { - setScanStatus(result.message || 'Scan-Aktion fehlgeschlagen.', 'error'); + await loadLibraryItems(); + } catch (err) { + console.error('Quick scan action failed:', err); + setScanStatus('Fehler beim Verarbeiten des Scans.', 'error'); + } + } + + function scanIntoEditCode() { + const scanReaderWrap = document.getElementById('scanReaderWrap'); + const editCodeInput = document.getElementById('edit-code4'); + const scanEditBtn = document.getElementById('scan-edit-code-btn'); + if (!scanReaderWrap || !editCodeInput || !scanEditBtn) { + return; + } + + if (scannerRunning && scanReaderWrap.style.display !== 'none') { + stopScanner(); + scanEditBtn.textContent = 'Barcode scannen'; + return; + } + + scanEditBtn.textContent = 'Scanner schließen'; + + startScanner(function(decodedText) { + editCodeInput.value = decodedText; + if(typeof validateCodeField === "function") { + validateCodeField(editCodeInput, document.getElementById('edit-item-id')?.value || null); + } + scanEditBtn.textContent = 'Barcode scannen'; + }); + } + + // ========================================================================= + // 4. UI INTERACTIONS & UTILITIES + // ========================================================================= + function borrowItem(itemId) { + const selectedItem = (libraryItems || []).find(item => item._id === itemId); + if (selectedItem && selectedItem.LibraryDisplayStatus === 'damaged') { + alert('Dieses Medium ist als defekt/zerstört markiert und kann nicht ausgeliehen werden.'); + return; + } + + const defaultCardId = activeStudentCardId || ''; + const cardId = (window.prompt('Bitte Schülerausweis-ID eingeben:', defaultCardId) || '').trim().toUpperCase(); + if (!cardId) { + alert('Ausleihe abgebrochen: Für Bibliotheksmedien ist eine gültige Schülerausweis-ID erforderlich.'); + return; + } + + setActiveStudentCard(cardId); + + const durationInput = (window.prompt('Ausleihdauer in Tagen (optional):') || '').trim(); + const maxAvailable = Math.max(1, parseInt(selectedItem?.AvailableGroupedCount || selectedItem?.Quantity || 1, 10) || 1); + const countPrompt = (window.prompt(`Anzahl ausleihen? (Standard: 1, verfügbar: ${maxAvailable})`, '1') || '').trim(); + let borrowCount = parseInt(countPrompt || '1', 10); + if (!Number.isFinite(borrowCount) || borrowCount < 1) { + borrowCount = 1; + } + if (borrowCount > maxAvailable) { + alert(`Es sind nur ${maxAvailable} Exemplar(e) verfügbar.`); + return; + } + + const form = document.createElement('form'); + form.method = 'POST'; + form.action = `/ausleihen/${itemId}`; + + const csrfField = document.createElement('input'); + csrfField.type = 'hidden'; + csrfField.name = 'csrf_token'; + csrfField.value = '{{ csrf_token }}'; + form.appendChild(csrfField); + + const cardField = document.createElement('input'); + cardField.type = 'hidden'; + cardField.name = 'borrower_card_id'; + cardField.value = cardId; + form.appendChild(cardField); + + const returnTargetField = document.createElement('input'); + returnTargetField.type = 'hidden'; + returnTargetField.name = 'return_to'; + returnTargetField.value = 'library'; + form.appendChild(returnTargetField); + + if (durationInput) { + const durationField = document.createElement('input'); + durationField.type = 'hidden'; + durationField.name = 'borrow_duration_days'; + durationField.value = durationInput; + form.appendChild(durationField); + } + + const countField = document.createElement('input'); + countField.type = 'hidden'; + countField.name = 'exemplare_count'; + countField.value = String(borrowCount || 1); + form.appendChild(countField); + + document.body.appendChild(form); + form.submit(); + } + + function setScanStatus(message, kind = '') { + const el = document.getElementById('scanStatus'); + if (!el) return; + el.textContent = message; + el.classList.remove('ok', 'warn', 'error'); + if (kind) el.classList.add(kind); + } + + function showSmallConfirm(message, kind='ok') { + // Append the small helper text in German + const helper = 'Sie können fortfahren. Dies ist nur eine kleine Benachrichtigung.'; + const el = document.createElement('div'); + el.className = `small-popup ${kind === 'error' ? 'error' : 'ok'}`; + el.innerHTML = `
${escapeHtml(String(message || ''))}
${helper}
×
`; + document.body.appendChild(el); + // close handler + el.querySelector('.close-x').addEventListener('click', () => { + if (el && el.parentNode) el.parentNode.removeChild(el); + }); + // auto remove after 3 seconds + setTimeout(() => { try { if (el && el.parentNode) el.parentNode.removeChild(el); } catch(e){} }, 3000); + } + + function setActiveStudentCard(cardId) { + activeStudentCardId = (cardId || '').trim().toUpperCase(); + const input = document.getElementById('activeStudentCard'); + if (input) input.value = activeStudentCardId; + } + + function normalizeScannedCode(code) { + return (code || '').trim(); + } + + function getItemTypeLabel(type) { + const labels = { 'book': 'Buch', 'cd': 'CD', 'dvd': 'DVD', 'other': 'Sonstige', 'schoolbook': 'Schulbuch' }; + return labels[type] || type; + } + + function escapeHtml(text) { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } + + // Opens the modal and fetches the data + function showItemDetail(itemId) { + const detailContent = document.getElementById('detailContent'); + const detailModal = document.getElementById('detailModal'); + + // 1. Show the loading state immediately + detailContent.innerHTML = '

Loading details...

'; + detailModal.style.display = 'flex'; + + // 2. Fetch the data + fetch(`/api/item_detail/${itemId}`) + .then(response => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return response.text(); + }) + .then(html => { + // 3. Clean the HTML and display it + detailContent.innerHTML = DOMPurify.sanitize(html); + }) + .catch(err => { + console.error('Error loading detail:', err); + detailContent.innerHTML = '

Sorry, we could not load the item details. Please try again later.

'; + }); + } + + // Closes the modal via the 'x' button + function closeDetailModal() { + document.getElementById('detailModal').style.display = 'none'; + } + + // Closes the modal if the user clicks the dark background overlay + window.onclick = function(event) { + const modal = document.getElementById('detailModal'); + // If the click happened directly on the dark overlay (not the white box) + if (event.target === modal) { + closeDetailModal(); + } + }; + + // ========================================================================= + // 5. EVENT LISTENERS INITIALIZATION & ON-LOAD INITIALIZER + // ========================================================================= + function wireScannerUi() { + const toggleBtn = document.getElementById('toggleScannerBtn'); + const resetBtn = document.getElementById('resetCardBtn'); + const modeSelect = document.getElementById('scanModeSelect'); + const keyboardToggle = document.getElementById('keyboardScannerToggle'); + + if (toggleBtn) { + toggleBtn.addEventListener('click', async () => { + if (scannerRunning) { + await stopScanner(); + } else { + await startScanner(null); + } + }); + } + + if (resetBtn) { + resetBtn.addEventListener('click', () => { + setActiveStudentCard(''); + setScanStatus('Ausweis zurückgesetzt. Bitte neu scannen.', 'warn'); + }); + } + + if (modeSelect) { + modeSelect.addEventListener('change', () => { + if (modeSelect.value === 'quick_toggle' && !activeStudentCardId) { + setScanStatus('Schnellmodus: zuerst Schülerausweis scannen.', 'warn'); + } else if (modeSelect.value === 'card_only') { + setScanStatus('Nur Ausweis-Modus aktiv.', 'warn'); + } + }); + } + + if (keyboardToggle) { + keyboardToggle.addEventListener('change', () => { + keyboardScannerEnabled = !!keyboardToggle.checked; + if (keyboardScannerEnabled) { + document.addEventListener('keydown', keyboardScanKeydownHandler); + setScanStatus('Physischer Scanner aktiv (Schnellmodus empfohlen).', 'ok'); + } else { + document.removeEventListener('keydown', keyboardScanKeydownHandler); + setScanStatus('Physischer Scanner deaktiviert.', 'warn'); + } + }); + } + } + + // Run when DOM structure is entirely ready + document.addEventListener('DOMContentLoaded', async () => { + wireScannerUi(); // Setup scanner control buttons + loadLibraryItems(); // Fetch your database items right away! + + // Safely connect standard Filters and Search inputs inside DOMContentLoaded + const filterToggleBtn = document.getElementById('filterToggleBtn'); + if (filterToggleBtn) { + filterToggleBtn.addEventListener('click', () => { + filterPanelOpen = !filterPanelOpen; + document.getElementById('filterPanel').classList.toggle('open'); + filterToggleBtn.classList.toggle('active'); + }); + } + + const applyFilterBtn = document.getElementById('applyFilterBtn'); + if (applyFilterBtn) { + applyFilterBtn.addEventListener('click', () => { + activeFilters.isbn = document.getElementById('filterISBN').value.toLowerCase(); + activeFilters.type = document.getElementById('filterType').value; + activeFilters.status = document.getElementById('filterStatus').value; + applyFiltersAndSearch(true); + }); + } + + const clearFilterBtn = document.getElementById('clearFilterBtn'); + if (clearFilterBtn) { + clearFilterBtn.addEventListener('click', () => { + document.getElementById('filterISBN').value = ''; + document.getElementById('filterType').value = ''; + document.getElementById('filterStatus').value = ''; + activeFilters = {isbn: '', type: '', status: ''}; + applyFiltersAndSearch(true); + }); + } + + const librarySearch = document.getElementById('librarySearch'); + if (librarySearch) { + librarySearch.addEventListener('input', (e) => { + currentSearchTerm = (e.target.value || '').toLowerCase(); + applyFiltersAndSearch(true); + }); + } + + const loadMoreBtn = document.getElementById('loadMoreBtn'); + if (loadMoreBtn) { + loadMoreBtn.addEventListener('click', () => { + renderedCount = Math.min(renderedCount + RENDER_BATCH_COUNT, visibleItems.length); + renderItems(); + }); + } + + const manualReturnBtn = document.getElementById('manualReturnBtn'); + const manualItemCode = document.getElementById('manualItemCode'); + if (manualReturnBtn && manualItemCode) { + manualReturnBtn.addEventListener('click', async () => { + const code = (manualItemCode.value || '').trim(); + if (!code) { + alert('Bitte einen Mediencode eingeben.'); return; } - - if (result.action === 'borrowed') { - setScanStatus(`Ausgeliehen: ${result.item_name}`, 'ok'); - showSmallConfirm(`Ausgeliehen: ${result.item_name}`, 'ok'); - } else if (result.action === 'returned') { - setScanStatus(`Zurückgegeben: ${result.item_name}`, 'ok'); - showSmallConfirm(`Zurückgegeben: ${result.item_name}`, 'ok'); - } else { - setScanStatus(result.message || 'Aktion durchgeführt.', 'ok'); - showSmallConfirm(result.message || 'Aktion durchgeführt.', 'ok'); - } - - await loadLibraryItems(); - } catch (err) { - console.error('Quick scan action failed:', err); - setScanStatus('Fehler beim Verarbeiten des Scans.', 'error'); - } - } - - function scanIntoEditCode() { - const scanReaderWrap = document.getElementById('scanReaderWrap'); - const editCodeInput = document.getElementById('edit-code4'); - const scanEditBtn = document.getElementById('scan-edit-code-btn'); - if (!scanReaderWrap || !editCodeInput || !scanEditBtn) { - return; - } - - if (scannerRunning && scanReaderWrap.style.display !== 'none') { - stopScanner(); - scanEditBtn.textContent = 'Barcode scannen'; - return; - } - - scanEditBtn.textContent = 'Scanner schließen'; - - startScanner(function (decodedText) { - editCodeInput.value = decodedText; - if (typeof validateCodeField === "function") { - validateCodeField(editCodeInput, document.getElementById('edit-item-id')?.value || null); - } - scanEditBtn.textContent = 'Barcode scannen'; + await returnByCode(code); }); } - // ========================================================================= - // 4. UI INTERACTIONS & UTILITIES - // ========================================================================= - function borrowItem(itemId) { - const selectedItem = (libraryItems || []).find(item => item._id === itemId); - if (selectedItem && selectedItem.LibraryDisplayStatus === 'damaged') { - alert('Dieses Medium ist als defekt/zerstört markiert und kann nicht ausgeliehen werden.'); - return; - } - - const defaultCardId = activeStudentCardId || ''; - const cardId = (window.prompt('Bitte Schülerausweis-ID eingeben:', defaultCardId) || '').trim().toUpperCase(); - if (!cardId) { - alert('Ausleihe abgebrochen: Für Bibliotheksmedien ist eine gültige Schülerausweis-ID erforderlich.'); - return; - } - - setActiveStudentCard(cardId); - - const durationInput = (window.prompt('Ausleihdauer in Tagen (optional):') || '').trim(); - const maxAvailable = Math.max(1, parseInt(selectedItem?.AvailableGroupedCount || selectedItem?.Quantity || 1, 10) || 1); - const countPrompt = (window.prompt(`Anzahl ausleihen? (Standard: 1, verfügbar: ${maxAvailable})`, '1') || '').trim(); - let borrowCount = parseInt(countPrompt || '1', 10); - if (!Number.isFinite(borrowCount) || borrowCount < 1) { - borrowCount = 1; - } - if (borrowCount > maxAvailable) { - alert(`Es sind nur ${maxAvailable} Exemplar(e) verfügbar.`); - return; - } - - const form = document.createElement('form'); - form.method = 'POST'; - form.action = `/ausleihen/${itemId}`; - - const csrfField = document.createElement('input'); - csrfField.type = 'hidden'; - csrfField.name = 'csrf_token'; - csrfField.value = '{{ csrf_token }}'; - form.appendChild(csrfField); - - const cardField = document.createElement('input'); - cardField.type = 'hidden'; - cardField.name = 'borrower_card_id'; - cardField.value = cardId; - form.appendChild(cardField); - - const returnTargetField = document.createElement('input'); - returnTargetField.type = 'hidden'; - returnTargetField.name = 'return_to'; - returnTargetField.value = 'library'; - form.appendChild(returnTargetField); - - if (durationInput) { - const durationField = document.createElement('input'); - durationField.type = 'hidden'; - durationField.name = 'borrow_duration_days'; - durationField.value = durationInput; - form.appendChild(durationField); - } - - const countField = document.createElement('input'); - countField.type = 'hidden'; - countField.name = 'exemplare_count'; - countField.value = String(borrowCount || 1); - form.appendChild(countField); - - document.body.appendChild(form); - form.submit(); - } - - function setScanStatus(message, kind = '') { - const el = document.getElementById('scanStatus'); - if (!el) return; - el.textContent = message; - el.classList.remove('ok', 'warn', 'error'); - if (kind) el.classList.add(kind); - } - - function showSmallConfirm(message, kind = 'ok') { - // Append the small helper text in German - const helper = 'Sie können fortfahren. Dies ist nur eine kleine Benachrichtigung.'; - const el = document.createElement('div'); - el.className = `small-popup ${kind === 'error' ? 'error' : 'ok'}`; - el.innerHTML = `
${escapeHtml(String(message || ''))}
${helper}
×
`; - document.body.appendChild(el); - // close handler - el.querySelector('.close-x').addEventListener('click', () => { - if (el && el.parentNode) el.parentNode.removeChild(el); - }); - // auto remove after 3 seconds - setTimeout(() => { - try { - if (el && el.parentNode) el.parentNode.removeChild(el); - } catch (e) { - } - }, 3000); - } - - function setActiveStudentCard(cardId) { - activeStudentCardId = (cardId || '').trim().toUpperCase(); - const input = document.getElementById('activeStudentCard'); - if (input) input.value = activeStudentCardId; - } - - function normalizeScannedCode(code) { - return (code || '').trim(); - } - - function getItemTypeLabel(type) { - const labels = {'book': 'Buch', 'cd': 'CD', 'dvd': 'DVD', 'other': 'Sonstige', 'schoolbook': 'Schulbuch'}; - return labels[type] || type; - } - - function escapeHtml(text) { - const div = document.createElement('div'); - div.textContent = text; - return div.innerHTML; - } - - // Opens the modal and fetches the data - function showItemDetail(itemId) { - const detailContent = document.getElementById('detailContent'); - const detailModal = document.getElementById('detailModal'); - - // 1. Show the loading state immediately - detailContent.innerHTML = '

Loading details...

'; - detailModal.style.display = 'flex'; - - // 2. Fetch the data - fetch(`/api/item_detail/${itemId}`) - .then(response => { - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - return response.text(); - }) - .then(html => { - // 3. Clean the HTML and display it - detailContent.innerHTML = DOMPurify.sanitize(html); - }) - .catch(err => { - console.error('Error loading detail:', err); - detailContent.innerHTML = '

Sorry, we could not load the item details. Please try again later.

'; - }); - } - - // Closes the modal via the 'x' button - function closeDetailModal() { - document.getElementById('detailModal').style.display = 'none'; - } - - // Closes the modal if the user clicks the dark background overlay - window.onclick = function (event) { - const modal = document.getElementById('detailModal'); - // If the click happened directly on the dark overlay (not the white box) - if (event.target === modal) { - closeDetailModal(); - } - }; - - // ========================================================================= - // 5. EVENT LISTENERS INITIALIZATION & ON-LOAD INITIALIZER - // ========================================================================= - function wireScannerUi() { - const toggleBtn = document.getElementById('toggleScannerBtn'); - const resetBtn = document.getElementById('resetCardBtn'); - const modeSelect = document.getElementById('scanModeSelect'); - const keyboardToggle = document.getElementById('keyboardScannerToggle'); - - if (toggleBtn) { - toggleBtn.addEventListener('click', async () => { - if (scannerRunning) { - await stopScanner(); - } else { - await startScanner(null); - } - }); - } - - if (resetBtn) { - resetBtn.addEventListener('click', () => { - setActiveStudentCard(''); - setScanStatus('Ausweis zurückgesetzt. Bitte neu scannen.', 'warn'); - }); - } - - if (modeSelect) { - modeSelect.addEventListener('change', () => { - if (modeSelect.value === 'quick_toggle' && !activeStudentCardId) { - setScanStatus('Schnellmodus: zuerst Schülerausweis scannen.', 'warn'); - } else if (modeSelect.value === 'card_only') { - setScanStatus('Nur Ausweis-Modus aktiv.', 'warn'); - } - }); - } - - if (keyboardToggle) { - keyboardToggle.addEventListener('change', () => { - keyboardScannerEnabled = !!keyboardToggle.checked; - if (keyboardScannerEnabled) { - document.addEventListener('keydown', keyboardScanKeydownHandler); - setScanStatus('Physischer Scanner aktiv (Schnellmodus empfohlen).', 'ok'); - } else { - document.removeEventListener('keydown', keyboardScanKeydownHandler); - setScanStatus('Physischer Scanner deaktiviert.', 'warn'); - } - }); - } - } - - // Run when DOM structure is entirely ready - document.addEventListener('DOMContentLoaded', () => { - wireScannerUi(); // Setup scanner control buttons - loadLibraryItems(); // Fetch your database items right away! - - // Safely connect standard Filters and Search inputs inside DOMContentLoaded - const filterToggleBtn = document.getElementById('filterToggleBtn'); - if (filterToggleBtn) { - filterToggleBtn.addEventListener('click', () => { - filterPanelOpen = !filterPanelOpen; - document.getElementById('filterPanel').classList.toggle('open'); - filterToggleBtn.classList.toggle('active'); - }); - } - - const applyFilterBtn = document.getElementById('applyFilterBtn'); - if (applyFilterBtn) { - applyFilterBtn.addEventListener('click', () => { - activeFilters.isbn = document.getElementById('filterISBN').value.toLowerCase(); - activeFilters.type = document.getElementById('filterType').value; - activeFilters.status = document.getElementById('filterStatus').value; - applyFiltersAndSearch(true); - }); - } - - const clearFilterBtn = document.getElementById('clearFilterBtn'); - if (clearFilterBtn) { - clearFilterBtn.addEventListener('click', () => { - document.getElementById('filterISBN').value = ''; - document.getElementById('filterType').value = ''; - document.getElementById('filterStatus').value = ''; - activeFilters = {isbn: '', type: '', status: ''}; - applyFiltersAndSearch(true); - }); - } - - const librarySearch = document.getElementById('librarySearch'); - if (librarySearch) { - librarySearch.addEventListener('input', (e) => { - currentSearchTerm = (e.target.value || '').toLowerCase(); - applyFiltersAndSearch(true); - }); - } - - const loadMoreBtn = document.getElementById('loadMoreBtn'); - if (loadMoreBtn) { - loadMoreBtn.addEventListener('click', () => { - renderedCount = Math.min(renderedCount + RENDER_BATCH_COUNT, visibleItems.length); - renderItems(); - }); - } - - const manualReturnBtn = document.getElementById('manualReturnBtn'); - const manualItemCode = document.getElementById('manualItemCode'); - if (manualReturnBtn && manualItemCode) { - manualReturnBtn.addEventListener('click', async () => { - const code = (manualItemCode.value || '').trim(); - if (!code) { - alert('Bitte einen Mediencode eingeben.'); - return; - } - await returnByCode(code); - }); - } - - const editForm = document.getElementById('editLibraryForm'); - if (editForm) { - editForm.addEventListener('submit', async function (e) { - e.preventDefault(); - - const itemId = document.getElementById('editLibraryItemId').value; - const currentItem = libraryItems.find(i => i._id === itemId); - if (!currentItem) return; - - const sharedPayload = { - name: document.getElementById('editLibraryName').value, - item_type: document.getElementById('editLibraryType').value, - isbn: document.getElementById('editLibraryIsbn').value, - ort: document.getElementById('editLibraryLocation').value, - beschreibung: document.getElementById('editLibraryDescription').value, - ansch_jahr: currentItem.Anschaffungsjahr || '', - ansch_kost: currentItem.Anschaffungskosten || '', - reservierbar: currentItem.Reservierbar !== false, + // Edit Modal Form processing + const editForm = document.getElementById('editLibraryForm'); + if (editForm) { + try { + if (isGroupedEdit) { + const payload = { + series_group_id: currentItem.SeriesGroupId, + ...sharedPayload, + items: groupMembers.map(member => ({ + id: member._id, + code_4: codeByItemId.get(member._id) || '' + })) }; - const codeInputs = Array.from(document.querySelectorAll('#editLibraryCodesContainer input[data-item-id]')); - const codeByItemId = new Map(codeInputs.map(input => [input.dataset.itemId, (input.value || '').trim()])); - const groupMembers = editLibraryState.groupMembers.length > 0 ? editLibraryState.groupMembers : [currentItem]; - const isGroupedEdit = Boolean(currentItem.SeriesGroupId) && groupMembers.length > 1; + const response = await fetch('/update_group', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': '{{ csrf_token }}', + 'X-CSRF-Token': '{{ csrf_token }}' + }, + body: JSON.stringify(payload) + }); - try { - if (isGroupedEdit) { - const payload = { - series_group_id: currentItem.SeriesGroupId, - ...sharedPayload, - items: groupMembers.map(member => ({ - id: member._id, - code_4: codeByItemId.get(member._id) || '' - })) - }; - - const response = await fetch('/update_group', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': '{{ csrf_token }}', - 'X-CSRF-Token': '{{ csrf_token }}' - }, - body: JSON.stringify(payload) - }); - - const result = await response.json(); - if (response.ok && result.success) { - alert(result.message || 'Gruppe erfolgreich aktualisiert!'); - closeEditLibraryModal(); - pagingState.loading = false; - await loadLibraryItems(); - } else { - alert(result.message || 'Fehler beim Speichern der Gruppenänderungen.'); - } - } else { - const primaryCodeInput = codeInputs[0]; - const payload = { - name: sharedPayload.name, - item_type: sharedPayload.item_type, - isbn: sharedPayload.isbn, - code_4: primaryCodeInput ? primaryCodeInput.value.trim() : (currentItem.Code_4 || currentItem.Code4 || '').trim(), - ort: sharedPayload.ort, - beschreibung: sharedPayload.beschreibung - }; - - const response = await fetch(`/api/library_item/${itemId}/update`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': '{{ csrf_token }}', - 'X-CSRF-Token': '{{ csrf_token }}' - }, - body: JSON.stringify(payload) - }); - - const result = await response.json(); - if (response.ok && result.ok) { - alert(result.message || 'Medium erfolgreich aktualisiert!'); - closeEditLibraryModal(); - pagingState.loading = false; - await loadLibraryItems(); - } else { - alert(result.message || 'Fehler beim Speichern der Änderungen.'); - } - } - } catch (error) { - console.error('Update failed:', error); - alert('Netzwerkfehler beim Aktualisieren des Mediums.'); + const result = await response.json(); + if (response.ok && result.success) { + alert(result.message || 'Gruppe erfolgreich aktualisiert!'); + closeEditLibraryModal(); + pagingState.loading = false; + await loadLibraryItems(); + } else { + alert(result.message || 'Fehler beim Speichern der Gruppenänderungen.'); } - }); - } - }); + } else { + const primaryCodeInput = codeInputs[0]; + const payload = { + name: sharedPayload.name, + item_type: sharedPayload.item_type, + isbn: sharedPayload.isbn, + code_4: primaryCodeInput ? primaryCodeInput.value.trim() : (currentItem.Code_4 || currentItem.Code4 || '').trim(), + ort: sharedPayload.ort, + beschreibung: sharedPayload.beschreibung + }; - async function fetchLibraryGroupMembers(seriesGroupId) { - if (!seriesGroupId) return []; + const response = await fetch(`/api/library_item/${itemId}/update`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': '{{ csrf_token }}', + 'X-CSRF-Token': '{{ csrf_token }}' + }, + body: JSON.stringify(payload) + }); + + const result = await response.json(); + if (response.ok && result.ok) { + alert(result.message || 'Medium erfolgreich aktualisiert!'); + closeEditLibraryModal(); + pagingState.loading = false; + await loadLibraryItems(); + } else { + alert(result.message || 'Fehler beim Speichern der Änderungen.'); + } + } + } catch (error) { + console.error('Update failed:', error); + alert('Netzwerkfehler beim Aktualisieren des Mediums.'); + } + editForm.addEventListener('submit', async function (e) { + e.preventDefault(); + + const itemId = document.getElementById('editLibraryItemId').value; + const currentItem = libraryItems.find(i => i._id === itemId); + if (!currentItem) return; + + const codeInputs = Array.from(document.querySelectorAll('#editLibraryCodesContainer input[data-item-id]')); + + const sharedPayload = { + name: document.getElementById('editLibraryName').value, + item_type: document.getElementById('editLibraryType').value, + isbn: document.getElementById('editLibraryIsbn').value, + ort: document.getElementById('editLibraryLocation').value, + beschreibung: document.getElementById('editLibraryDescription').value, + ansch_jahr: currentItem.Anschaffungsjahr || '', + ansch_kost: currentItem.Anschaffungskosten || '', + reservierbar: currentItem.Reservierbar !== false, + }; + const codeByItemId = new Map(codeInputs.map(input => [input.dataset.itemId, (input.value || '').trim()])); + const groupMembers = editLibraryState.groupMembers.length > 0 ? editLibraryState.groupMembers : [currentItem]; + const isGroupedEdit = Boolean(currentItem.SeriesGroupId) && groupMembers.length > 1; + + }); + } + }); + + async function fetchLibraryGroupMembers(seriesGroupId) { + if (!seriesGroupId) return []; try { const response = await fetch(`/api/library_group/${encodeURIComponent(seriesGroupId)}`); @@ -1595,9 +1590,9 @@ document.getElementById('editLibraryModal').style.display = 'flex'; }; - function closeEditLibraryModal() { - document.getElementById('editLibraryModal').style.display = 'none'; - } + function closeEditLibraryModal() { + document.getElementById('editLibraryModal').style.display = 'none'; + } }