import { fetchTicket, fetchComments, fetchHistory, createComment, logTime, formatDateTime, formatMinutes, getHistoryIcon } from './ticket-shared.js'; document.addEventListener('DOMContentLoaded', async () => { const ticketId = new URLSearchParams(window.location.search).get('id'); if (!ticketId) return window.location.href = '../admin.html'; const statusSelect = document.getElementById('status-select'); const priorityInput = document.getElementById('priority-text'); const categorySelect = document.getElementById('category-select'); const commentForm = document.getElementById('comment-form'); const titleText = document.getElementById('ticket-title-text'); const titleInput = document.getElementById('ticket-title-input'); const descText = document.getElementById('ticket-description-text'); const descInput = document.getElementById('ticket-description-input'); const commentAuthorInput = document.getElementById('comment-author'); const totalTimeDisplay = document.getElementById('total-time'); const timeForm = document.getElementById('time-booking-form'); let webhookConfig = null; // Fetch Webhook Configuration async function loadWebhookConfig() { try { const response = await fetch('/api/webhooks'); if (response.ok) { webhookConfig = await response.json(); console.log('Webhook configuration loaded:', webhookConfig.configured); } else { console.warn('Failed to load webhook configuration'); webhookConfig = { admin: null, user: null, configured: { admin: false, user: false } }; } } catch (error) { console.error('Error loading webhook configuration:', error); webhookConfig = { admin: null, user: null, configured: { admin: false, user: false } }; } } // Send Webhook Notification async function sendWebhook(message) { if (!webhookConfig?.user) { console.log('User webhook not configured, skipping notification'); return; } try { const res = await fetch(webhookConfig.user, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content: message }) }); if (!res.ok) { console.error('User webhook failed:', res.statusText); } } catch (err) { console.error('Error sending user webhook:', err); } } let originalStatus = '', originalPriority = '', originalTitle = '', originalDesc = '', originalCategory = ''; async function loadPage() { loadWebhookConfig().then(() => { loadTicketDetails(); loadComments(); loadHistory(); }); } async function loadTicketDetails() { const ticket = await fetchTicket(ticketId); if (!ticket) return alert('Ticket not found'); titleText.textContent = ticket.title; descText.textContent = ticket.description; priorityInput.value = ticket.priority; statusSelect.value = ticket.status; categorySelect.value = ticket.category || ''; document.getElementById('ticket-id-val').textContent = ticket.id; document.getElementById('ticket-requester').textContent = ticket.requester; document.getElementById('ticket-created').textContent = formatDateTime(ticket.created_at); document.getElementById('ticket-updated').textContent = formatDateTime(ticket.updated_at); const totalMins = typeof ticket.total_time === 'number' ? ticket.total_time : 0; totalTimeDisplay.textContent = formatMinutes(totalMins); statusSelect.className = 'form-control status-' + (ticket.status || '').toLowerCase().replace(/\s+/g, '-'); originalStatus = ticket.status; originalPriority = ticket.priority; originalTitle = ticket.title; originalDesc = ticket.description; originalCategory = ticket.category || ''; } async function updateTicket({ status, priority, title, description, category, actor = 'Admin' }) { try { const ticket = await fetchTicket(ticketId); // Fetch ticket to get the requester const requester = ticket.requester || ''; // Ensure requester is included in the update request const res = await fetch(`/api/tickets/${ticketId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status, priority, title, description, category, actor, requester }) // Add requester }); if (!res.ok) throw new Error('Failed to update'); alert('Ticket updated successfully'); if (status !== originalStatus) { await sendWebhook(`Ticket #${ticketId} status changed from "${originalStatus}" to "${status}"`); originalStatus = status; } if (priority !== originalPriority) { await sendWebhook(`Ticket #${ticketId} priority changed from "${originalPriority}" to "${priority}"`); originalPriority = priority; } if (title !== originalTitle) { await sendWebhook(`Ticket #${ticketId} title changed by ${actor}`); originalTitle = title; } if (description !== originalDesc) { await sendWebhook(`Ticket #${ticketId} description changed by ${actor}`); originalDesc = description; } if (category !== originalCategory) { await sendWebhook(`Ticket #${ticketId} category changed from "${originalCategory}" to "${category}"`); originalCategory = category; } titleText.textContent = title; descText.textContent = description; await loadPage(); } catch (err) { console.error('Update failed:', err); alert('Error updating ticket'); } } document.getElementById('update-ticket-btn').addEventListener('click', async () => { const isEditingTitle = titleInput.style.display === 'block'; const isEditingDesc = descInput.style.display === 'block'; const newTitle = isEditingTitle ? titleInput.value.trim() : titleText.textContent; const newDesc = isEditingDesc ? descInput.value.trim() : descText.textContent; const newStatus = statusSelect.value; const newPriority = priorityInput.value; const newCategory = categorySelect.value; const confirmed = confirm('Möchten Sie die Änderungen wirklich speichern?'); if (!confirmed) return; await updateTicket({ status: newStatus, priority: newPriority, title: newTitle, description: newDesc, category: newCategory }); titleInput.style.display = 'none'; titleText.style.display = 'block'; descInput.style.display = 'none'; descText.style.display = 'block'; }); document.getElementById('close-ticket-btn').addEventListener('click', async () => { const confirmed = confirm('Möchtest du das Ticket wirklich schließen?'); if (!confirmed) return; const newStatus = 'Closed'; const newPriority = priorityInput.value; const newTitle = titleText.textContent; const newDesc = descText.textContent; const newCategory = categorySelect.value; await updateTicket({ status: newStatus, priority: newPriority, title: newTitle, description: newDesc, category: newCategory }); }); titleText.addEventListener('dblclick', () => { titleInput.value = titleText.textContent; titleText.style.display = 'none'; titleInput.style.display = 'block'; titleInput.focus(); }); descText.addEventListener('dblclick', () => { descInput.value = descText.textContent; descText.style.display = 'none'; descInput.style.display = 'block'; descInput.focus(); }); const savedAuthor = localStorage.getItem('commentAuthor'); if (savedAuthor) commentAuthorInput.value = savedAuthor; async function loadComments() { const comments = await fetchComments(ticketId); const container = document.getElementById('comments-container'); container.innerHTML = comments.map(comment => { const role = comment.role || 'user'; const isAdmin = role === 'admin'; const avatarUrl = isAdmin ? '/assets/admin.jpg' : '/assets/user.jpg'; return `