diff --git a/Web/app.py b/Web/app.py index 3d0365f..5ba7f25 100755 --- a/Web/app.py +++ b/Web/app.py @@ -4064,6 +4064,9 @@ def get_items(): 'Filter3': 1, 'Ort': 1, 'User': 1, + 'BlockedNow': 1, + 'Reservierbar': 1, + 'HasDamage': 1, 'ItemType': 1, } diff --git a/Web/templates/main.html b/Web/templates/main.html index 170b19c..9eacd98 100755 --- a/Web/templates/main.html +++ b/Web/templates/main.html @@ -799,10 +799,8 @@ } function loadItems(offset = 0, append = false) { - // Für Pages nach der ersten: Explizit vollständige Daten laden (light_mode=false) - // Erste Page: light_mode wird automatisch enablet - const lightModeParam = offset > 0 ? '&light_mode=false' : ''; - return fetch(`{{ url_for('get_items') }}?offset=${offset}&limit=${MAIN_ITEMS_PAGE_SIZE}${lightModeParam}`) + // Keep list payload lightweight; full details are fetched on-demand in openItemQuick. + return fetch(`{{ url_for('get_items') }}?offset=${offset}&limit=${MAIN_ITEMS_PAGE_SIZE}&light_mode=true`) .then(response => response.json()) .then(data => { const itemsContainer = document.querySelector('#items-container'); @@ -1073,12 +1071,9 @@ // Stop event from bubbling up e.stopPropagation(); - - // Get full item data with correct image paths - const modalItemData = {...item}; - modalItemData.Images = item.Images ? item.Images.map(img => "{{ url_for('uploaded_file', filename='') }}" + img) : []; - - openItemModal(modalItemData); + + // Always load full, up-to-date item details for the modal. + openItemQuick(item._id); }); } } catch (err) { @@ -1414,6 +1409,76 @@ } function openItemModal(item) { + const escapeHtml = (value) => String(value ?? '') + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + + const formatHistoryDate = (value) => { + if (!value) return '-'; + const dt = new Date(value); + if (Number.isNaN(dt.getTime())) { + return escapeHtml(value); + } + return dt.toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); + }; + + const damageReports = Array.isArray(item.DamageReports) ? item.DamageReports : []; + const damageRepairs = Array.isArray(item.DamageRepairs) ? item.DamageRepairs : []; + const damageHistoryEntries = []; + + damageReports.forEach((report) => { + damageHistoryEntries.push({ + type: 'report', + rawDate: report?.reported_at || null, + dateLabel: formatHistoryDate(report?.reported_at), + actor: escapeHtml(report?.reported_by || '-'), + description: escapeHtml(report?.description || 'Schaden gemeldet'), + meta: '', + }); + }); + + damageRepairs.forEach((repair) => { + const resolvedReports = Array.isArray(repair?.resolved_reports) ? repair.resolved_reports : []; + damageHistoryEntries.push({ + type: 'repair', + rawDate: repair?.repaired_at || null, + dateLabel: formatHistoryDate(repair?.repaired_at), + actor: escapeHtml(repair?.repaired_by || '-'), + description: 'Als repariert markiert', + meta: `${resolvedReports.length} Meldung(en) abgeschlossen`, + }); + }); + + damageHistoryEntries.sort((a, b) => { + const ta = a.rawDate ? new Date(a.rawDate).getTime() : 0; + const tb = b.rawDate ? new Date(b.rawDate).getTime() : 0; + return (Number.isNaN(tb) ? 0 : tb) - (Number.isNaN(ta) ? 0 : ta); + }); + + const damageHistoryHtml = damageHistoryEntries.length + ? damageHistoryEntries.map((entry) => { + const badgeStyle = entry.type === 'repair' + ? 'background:#dcfce7;color:#166534;' + : 'background:#fee2e2;color:#991b1b;'; + const badgeText = entry.type === 'repair' ? 'Repariert' : 'Schaden'; + const metaLine = entry.meta ? `
Thema: ${filter3Display}${filter3More}
Barcode: ${item.Code_4 || '-'}
Anzahl: ${groupedCount}
- ${damageCount > 0 ? `