(function () { "use strict"; const searchInput = document.getElementById("customerSearch"); const searchWrap = document.getElementById("searchWrap"); const suggestionsBox = document.getElementById("suggestions"); const customerChip = document.getElementById("customerChip"); const chipNumber = document.getElementById("chipNumber"); const chipName = document.getElementById("chipName"); const chipReset = document.getElementById("chipReset"); const stepIssue = document.getElementById("stepIssue"); const subjectInput = document.getElementById("subject"); const descriptionInput = document.getElementById("description"); const submitButton = document.getElementById("submitButton"); const feedback = document.getElementById("feedback"); let selectedCustomer = null; let currentResults = []; let activeIndex = -1; let debounceTimer = null; function updateSubmitState() { const subjectOk = subjectInput.value.trim().length >= 5; submitButton.disabled = !(selectedCustomer && subjectOk); } function closeSuggestions() { suggestionsBox.classList.remove("open"); searchInput.setAttribute("aria-expanded", "false"); activeIndex = -1; } function renderSuggestions() { suggestionsBox.innerHTML = ""; if (currentResults.length === 0) { const empty = document.createElement("div"); empty.className = "suggestion-empty"; empty.textContent = "Kein Kunde gefunden. Nummer und Schreibweise prüfen."; suggestionsBox.appendChild(empty); } else { currentResults.forEach((customer, index) => { const item = document.createElement("button"); item.type = "button"; item.className = index === activeIndex ? "suggestion active" : "suggestion"; item.setAttribute("role", "option"); item.innerHTML = ""; const numberSpan = document.createElement("span"); numberSpan.className = "cnum"; numberSpan.textContent = customer.number; const nameSpan = document.createElement("span"); nameSpan.textContent = customer.name; item.appendChild(numberSpan); item.appendChild(nameSpan); item.addEventListener("click", () => selectCustomer(customer)); suggestionsBox.appendChild(item); }); } suggestionsBox.classList.add("open"); searchInput.setAttribute("aria-expanded", "true"); } async function runSearch(query) { try { const response = await fetch("/api/customers?search=" + encodeURIComponent(query)); const payload = await response.json(); currentResults = payload.results; activeIndex = currentResults.length > 0 ? 0 : -1; renderSuggestions(); } catch (error) { currentResults = []; renderSuggestions(); } } function selectCustomer(customer) { selectedCustomer = customer; chipNumber.textContent = customer.number; chipName.textContent = customer.name; customerChip.classList.add("visible"); searchWrap.style.display = "none"; closeSuggestions(); stepIssue.dataset.disabled = "false"; updateSubmitState(); subjectInput.focus(); } function resetCustomer() { selectedCustomer = null; customerChip.classList.remove("visible"); searchWrap.style.display = ""; searchInput.value = ""; stepIssue.dataset.disabled = "true"; updateSubmitState(); searchInput.focus(); } searchInput.addEventListener("input", () => { const query = searchInput.value.trim(); clearTimeout(debounceTimer); if (query.length < 2) { closeSuggestions(); return; } debounceTimer = setTimeout(() => runSearch(query), 200); }); searchInput.addEventListener("keydown", (event) => { const isOpen = suggestionsBox.classList.contains("open"); if (event.key === "ArrowDown" && isOpen) { event.preventDefault(); activeIndex = Math.min(activeIndex + 1, currentResults.length - 1); renderSuggestions(); } else if (event.key === "ArrowUp" && isOpen) { event.preventDefault(); activeIndex = Math.max(activeIndex - 1, 0); renderSuggestions(); } else if (event.key === "Enter" && isOpen && activeIndex >= 0) { event.preventDefault(); selectCustomer(currentResults[activeIndex]); } else if (event.key === "Escape") { closeSuggestions(); } }); document.addEventListener("click", (event) => { if (!searchWrap.contains(event.target)) { closeSuggestions(); } }); chipReset.addEventListener("click", resetCustomer); subjectInput.addEventListener("input", updateSubmitState); submitButton.addEventListener("click", async () => { feedback.className = "feedback"; submitButton.disabled = true; submitButton.textContent = "Wird angelegt ..."; try { const response = await fetch("/api/tickets", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ customerNumber: selectedCustomer.number, subject: subjectInput.value, description: descriptionInput.value, }), }); const payload = await response.json(); if (response.status === 201) { const dryRunHint = payload.dryRun ? " (Trockenlauf, nicht wirklich in Redmine angelegt)" : ""; feedback.className = "feedback success"; feedback.innerHTML = "Ticket #" + payload.issueId + " fuer " + payload.customer.number + " angelegt." + dryRunHint; subjectInput.value = ""; descriptionInput.value = ""; } else { feedback.className = "feedback error"; feedback.textContent = payload.error || "Unbekannter Fehler beim Anlegen des Tickets."; } } catch (error) { feedback.className = "feedback error"; feedback.textContent = "Server nicht erreichbar. Bitte später erneut versuchen."; } finally { submitButton.textContent = "Ticket anlegen"; updateSubmitState(); } }); })();