let currentRequests=[];let filteredRequests=[];let currentPage=0;let totalPages=0;let totalRequests=0;let refreshInterval=null;let csrfToken='';function detectApiBaseUrl(){return'';} const API_BASE_URL=detectApiBaseUrl();document.addEventListener('DOMContentLoaded',function(){csrfToken=document.querySelector('meta[name="csrf-token"]')?.getAttribute('content')||'';initEventListeners();loadGuestRequests();startAutoRefresh();console.log('🎯 Admin Guest Requests Management geladen');});function initEventListeners(){const searchInput=document.getElementById('search-requests');if(searchInput){searchInput.addEventListener('input',debounce(handleSearch,300));} const statusFilter=document.getElementById('status-filter');if(statusFilter){statusFilter.addEventListener('change',handleFilterChange);} const sortOrder=document.getElementById('sort-order');if(sortOrder){sortOrder.addEventListener('change',handleSortChange);} const refreshBtn=document.getElementById('refresh-btn');if(refreshBtn){refreshBtn.addEventListener('click',()=>{loadGuestRequests();showNotification('🔄 Gastaufträge aktualisiert','info');});} const exportBtn=document.getElementById('export-btn');if(exportBtn){exportBtn.addEventListener('click',handleExport);} const bulkActionsBtn=document.getElementById('bulk-actions-btn');if(bulkActionsBtn){bulkActionsBtn.addEventListener('click',showBulkActionsModal);} const selectAllCheckbox=document.getElementById('select-all');if(selectAllCheckbox){selectAllCheckbox.addEventListener('change',handleSelectAll);}} async function loadGuestRequests(){try{showLoading(true);const url=`${API_BASE_URL}/api/admin/guest-requests`;const response=await fetch(url,{method:'GET',headers:{'Content-Type':'application/json','X-CSRFToken':csrfToken}});if(!response.ok){throw new Error(`HTTP ${response.status}:${response.statusText}`);} const data=await response.json();if(data.success){currentRequests=data.requests||[];totalRequests=data.total||0;updateStats(data.stats||{});applyFiltersAndSort();console.log(`✅ ${currentRequests.length}Gastaufträge geladen`);}else{throw new Error(data.message||'Fehler beim Laden der Gastaufträge');}}catch(error){console.error('Fehler beim Laden der Gastaufträge:',error);showNotification('❌ Fehler beim Laden der Gastaufträge: '+error.message,'error');showEmptyState();}finally{showLoading(false);}} function updateStats(stats){const elements={'pending-count':stats.pending||0,'approved-count':stats.approved||0,'rejected-count':stats.rejected||0,'total-count':stats.total||0};Object.entries(elements).forEach(([id,value])=>{const element=document.getElementById(id);if(element){animateCounter(element,value);}});} function animateCounter(element,targetValue){const currentValue=parseInt(element.textContent)||0;const difference=targetValue-currentValue;const steps=20;const stepValue=difference/steps;let step=0;const interval=setInterval(()=>{step++;const value=Math.round(currentValue+(stepValue*step));element.textContent=value;if(step>=steps){clearInterval(interval);element.textContent=targetValue;}},50);} function applyFiltersAndSort(){let requests=[...currentRequests];const statusFilter=document.getElementById('status-filter')?.value;if(statusFilter&&statusFilter!=='all'){requests=requests.filter(req=>req.status===statusFilter);} const searchTerm=document.getElementById('search-requests')?.value.toLowerCase();if(searchTerm){requests=requests.filter(req=>req.name?.toLowerCase().includes(searchTerm)||req.email?.toLowerCase().includes(searchTerm)||req.file_name?.toLowerCase().includes(searchTerm)||req.reason?.toLowerCase().includes(searchTerm));} const sortOrder=document.getElementById('sort-order')?.value;requests.sort((a,b)=>{switch(sortOrder){case'oldest':return new Date(a.created_at)-new Date(b.created_at);case'priority':return getPriorityValue(b)-getPriorityValue(a);case'newest':default:return new Date(b.created_at)-new Date(a.created_at);}});filteredRequests=requests;renderRequestsTable();} function getPriorityValue(request){const now=new Date();const created=new Date(request.created_at);const hoursOld=(now-created)/(1000*60*60);let priority=0;if(request.status==='pending')priority+=10;else if(request.status==='approved')priority+=5;if(hoursOld>24)priority+=5;else if(hoursOld>8)priority+=3;else if(hoursOld>2)priority+=1;return priority;} function renderRequestsTable(){const tableBody=document.getElementById('requests-table-body');const emptyState=document.getElementById('empty-state');if(!tableBody)return;if(filteredRequests.length===0){tableBody.innerHTML='';showEmptyState();return;} hideEmptyState();const requestsHtml=filteredRequests.map(request=>createRequestRow(request)).join('');tableBody.innerHTML=requestsHtml;addRowEventListeners();} function createRequestRow(request){const statusColor=getStatusColor(request.status);const priorityLevel=getPriorityLevel(request);const timeAgo=getTimeAgo(request.created_at);return`
${request.name?request.name[0].toUpperCase():'G'}
${escapeHtml(request.name||'Unbekannt')}
${escapeHtml(request.email||'Keine E-Mail')}
${escapeHtml(request.file_name||'Keine Datei')}
${request.duration_minutes?`${request.duration_minutes}Min.`:'Unbekannte Dauer'} ${request.copies?`• ${request.copies}Kopien`:''}
${request.reason?`
${escapeHtml(request.reason)}
`:''}${getStatusText(request.status)}
${timeAgo}
${formatDateTime(request.created_at)}
${getPriorityBadge(priorityLevel)} ${request.is_urgent?'🔥 Dringend':''}
${request.status==='pending'?``:''}
`;} function getStatusColor(status){const colors={'pending':'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-300','approved':'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300','rejected':'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300','expired':'bg-gray-100 text-gray-800 dark:bg-gray-900/30 dark:text-gray-300'};return colors[status]||'bg-gray-100 text-gray-800 dark:bg-gray-900/30 dark:text-gray-300';} function getStatusDot(status){const dots={'pending':'bg-yellow-400 dark:bg-yellow-300','approved':'bg-green-400 dark:bg-green-300','rejected':'bg-red-400 dark:bg-red-300','expired':'bg-gray-400 dark:bg-gray-300'};return dots[status]||'bg-gray-400 dark:bg-gray-300';} function getStatusText(status){const texts={'pending':'Wartend','approved':'Genehmigt','rejected':'Abgelehnt','expired':'Abgelaufen'};return texts[status]||status;} function getPriorityLevel(request){const priority=getPriorityValue(request);if(priority>=15)return'high';if(priority>=8)return'medium';return'low';} function getPriorityBadge(level){const badges={'high':'🔴 Hoch','medium':'🟡 Mittel','low':'🟢 Niedrig'};return badges[level]||badges['low'];} async function approveRequest(requestId){if(!confirm('Möchten Sie diesen Gastauftrag wirklich genehmigen?'))return;try{showLoading(true);const url=`${API_BASE_URL}/api/guest-requests/${requestId}/approve`;const response=await fetch(url,{method:'POST',headers:{'Content-Type':'application/json','X-CSRFToken':csrfToken},body:JSON.stringify({})});const data=await response.json();if(data.success){showNotification('✅ Gastauftrag erfolgreich genehmigt','success');loadGuestRequests();}else{throw new Error(data.message||'Fehler beim Genehmigen');}}catch(error){console.error('Fehler beim Genehmigen:',error);showNotification('❌ Fehler beim Genehmigen: '+error.message,'error');}finally{showLoading(false);}} async function rejectRequest(requestId){const reason=prompt('Grund für die Ablehnung:');if(!reason)return;try{showLoading(true);const url=`${API_BASE_URL}/api/guest-requests/${requestId}/reject`;const response=await fetch(url,{method:'POST',headers:{'Content-Type':'application/json','X-CSRFToken':csrfToken},body:JSON.stringify({reason})});const data=await response.json();if(data.success){showNotification('✅ Gastauftrag erfolgreich abgelehnt','success');loadGuestRequests();}else{throw new Error(data.message||'Fehler beim Ablehnen');}}catch(error){console.error('Fehler beim Ablehnen:',error);showNotification('❌ Fehler beim Ablehnen: '+error.message,'error');}finally{showLoading(false);}} async function deleteRequest(requestId){if(!confirm('Möchten Sie diesen Gastauftrag wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden.'))return;try{showLoading(true);const url=`${API_BASE_URL}/api/guest-requests/${requestId}`;const response=await fetch(url,{method:'DELETE',headers:{'Content-Type':'application/json','X-CSRFToken':csrfToken}});const data=await response.json();if(data.success){showNotification('✅ Gastauftrag erfolgreich gelöscht','success');loadGuestRequests();}else{throw new Error(data.message||'Fehler beim Löschen');}}catch(error){console.error('Fehler beim Löschen:',error);showNotification('❌ Fehler beim Löschen: '+error.message,'error');}finally{showLoading(false);}} function showRequestDetail(requestId){const request=currentRequests.find(req=>req.id===requestId);if(!request)return;const modal=document.getElementById('detail-modal');const content=document.getElementById('modal-content');content.innerHTML=`

Gastauftrag Details

Antragsteller

Name:${escapeHtml(request.name||'Unbekannt')}

E-Mail:${escapeHtml(request.email||'Keine E-Mail')}

Erstellt am:${formatDateTime(request.created_at)}

Auftrag Details

Datei:${escapeHtml(request.file_name||'Keine Datei')}

Dauer:${request.duration_minutes||'Unbekannt'}Minuten

Kopien:${request.copies||1}

Status:${getStatusText(request.status)}

${request.reason?`

BegrĂĽndung

${escapeHtml(request.reason)}

`:''}
${request.status==='pending'?``:''}
`;modal.classList.remove('hidden');} function closeDetailModal(){const modal=document.getElementById('detail-modal');modal.classList.add('hidden');} function showBulkActionsModal(){const selectedIds=getSelectedRequestIds();if(selectedIds.length===0){showNotification('⚠️ Bitte wählen Sie mindestens einen Gastauftrag aus','warning');return;} const modal=document.getElementById('bulk-modal');modal.classList.remove('hidden');} function closeBulkModal(){const modal=document.getElementById('bulk-modal');modal.classList.add('hidden');} async function performBulkAction(action){const selectedIds=getSelectedRequestIds();if(selectedIds.length===0)return;const confirmMessages={'approve':`Möchten Sie ${selectedIds.length}Gastaufträge genehmigen?`,'reject':`Möchten Sie ${selectedIds.length}Gastaufträge ablehnen?`,'delete':`Möchten Sie ${selectedIds.length}Gastaufträge löschen?`};if(!confirm(confirmMessages[action]))return;try{showLoading(true);closeBulkModal();const promises=selectedIds.map(async(id)=>{const url=`${API_BASE_URL}/api/guest-requests/${id}/${action}`;const method=action==='delete'?'DELETE':'POST';return fetch(url,{method,headers:{'Content-Type':'application/json','X-CSRFToken':csrfToken}});});const results=await Promise.allSettled(promises);const successCount=results.filter(r=>r.status==='fulfilled'&&r.value.ok).length;showNotification(`✅ ${successCount}von ${selectedIds.length}Aktionen erfolgreich`,'success');loadGuestRequests();document.getElementById('select-all').checked=false;document.querySelectorAll('.request-checkbox').forEach(cb=>cb.checked=false);}catch(error){console.error('Fehler bei Bulk-Aktion:',error);showNotification('❌ Fehler bei der Bulk-Aktion: '+error.message,'error');}finally{showLoading(false);}} function getSelectedRequestIds(){const checkboxes=document.querySelectorAll('.request-checkbox:checked');return Array.from(checkboxes).map(cb=>parseInt(cb.value));} function handleSearch(){applyFiltersAndSort();} function handleFilterChange(){applyFiltersAndSort();} function handleSortChange(){applyFiltersAndSort();} function handleSelectAll(event){const checkboxes=document.querySelectorAll('.request-checkbox');checkboxes.forEach(checkbox=>{checkbox.checked=event.target.checked;});} function handleExport(){const selectedIds=getSelectedRequestIds();const exportData=selectedIds.length>0?filteredRequests.filter(req=>selectedIds.includes(req.id)):filteredRequests;if(exportData.length===0){showNotification('⚠️ Keine Daten zum Exportieren verfügbar','warning');return;} exportToCSV(exportData);} function exportToCSV(data){const headers=['ID','Name','E-Mail','Datei','Status','Erstellt','Dauer (Min)','Kopien','Begründung'];const rows=data.map(req=>[req.id,req.name||'',req.email||'',req.file_name||'',getStatusText(req.status),formatDateTime(req.created_at),req.duration_minutes||'',req.copies||'',req.reason||'']);const csvContent=[headers,...rows].map(row=>row.map(field=>`"${String(field).replace(/"/g,'""')}"`).join(',')) .join('\n'); const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); if (link.download !== undefined) { const url = URL.createObjectURL(blob); link.setAttribute('href', url); link.setAttribute('download', `gastauftraege_${new Date().toISOString().split('T')[0]}.csv`); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); } showNotification('📄 CSV-Export erfolgreich erstellt', 'success'); } /** * Auto-Refresh */ function startAutoRefresh() { // Refresh alle 30 Sekunden refreshInterval = setInterval(() => { loadGuestRequests(); }, 30000); } function stopAutoRefresh() { if (refreshInterval) { clearInterval(refreshInterval); refreshInterval = null; } } /** * Utility-Funktionen */ function addRowEventListeners() { // Falls notwendig, können hier zusätzliche Event Listener hinzugefügt werden } function showLoading(show) { const loadingElement = document.getElementById('table-loading'); const tableBody = document.getElementById('requests-table-body'); if (loadingElement) { loadingElement.classList.toggle('hidden', !show); } if (show && tableBody) { tableBody.innerHTML = ''; } } function showEmptyState() { const emptyState = document.getElementById('empty-state'); if (emptyState) { emptyState.classList.remove('hidden'); } } function hideEmptyState() { const emptyState = document.getElementById('empty-state'); if (emptyState) { emptyState.classList.add('hidden'); } } function showNotification(message, type = 'info') { const notification = document.createElement('div'); notification.className = `fixed top-4 right-4 px-6 py-4 rounded-xl shadow-2xl z-50 transform transition-all duration-500 translate-x-full ${ type === 'success' ? 'bg-green-500 text-white' : type === 'error' ? 'bg-red-500 text-white' : type === 'warning' ? 'bg-yellow-500 text-black' : 'bg-blue-500 text-white' }`; notification.innerHTML = `
${type === 'success' ? '✅' : type === 'error' ? '❌' : type === 'warning' ? '⚠️' : 'ℹ️'} ${message}
`; document.body.appendChild(notification); // Animation einblenden setTimeout(() => { notification.classList.remove('translate-x-full'); }, 100); // Nach 5 Sekunden entfernen setTimeout(() => { notification.classList.add('translate-x-full'); setTimeout(() => notification.remove(), 5000); }, 5000); } function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } function escapeHtml(text) { const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return text ? String(text).replace(/[&<>"']/g, m => map[m]) : ''; } function formatDateTime(dateString) { if (!dateString) return 'Unbekannt'; const date = new Date(dateString); return date.toLocaleString('de-DE', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); } function getTimeAgo(dateString) { if (!dateString) return 'Unbekannt'; const now = new Date(); const date = new Date(dateString); const diffMs = now - date; const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); const diffDays = Math.floor(diffHours / 24); if (diffDays > 0) { return `vor ${diffDays} Tag${diffDays === 1 ? '' : 'en'}`; } else if (diffHours > 0) { return `vor ${diffHours} Stunde${diffHours === 1 ? '' : 'n'}`; } else { const diffMinutes = Math.floor(diffMs / (1000 * 60)); return `vor ${Math.max(1, diffMinutes)} Minute${diffMinutes === 1 ? '' : 'n'}`; } } // Globale Funktionen für onclick-Handler window.showRequestDetail = showRequestDetail; window.approveRequest = approveRequest; window.rejectRequest = rejectRequest; window.deleteRequest = deleteRequest; window.closeDetailModal = closeDetailModal; window.closeBulkModal = closeBulkModal; window.performBulkAction = performBulkAction; console.log('📋 Admin Guest Requests JavaScript vollständig geladen'