Daten via SQL (pw muss in .env eingetragen werden), Erweitert-Modus um nach anderen Feldern zu suchen

This commit is contained in:
2026-07-17 11:54:58 +02:00
parent b89dd1be80
commit 5b20729877
10 changed files with 1175 additions and 46 deletions
+64 -3
View File
@@ -4,6 +4,9 @@
const searchInput = document.getElementById("customerSearch");
const searchWrap = document.getElementById("searchWrap");
const suggestionsBox = document.getElementById("suggestions");
const advancedToggle = document.getElementById("advancedToggle");
const advancedFields = document.getElementById("advancedFields");
const fieldToggleButtons = Array.from(document.querySelectorAll(".field-toggle"));
const customerChip = document.getElementById("customerChip");
const chipNumber = document.getElementById("chipNumber");
const chipName = document.getElementById("chipName");
@@ -16,8 +19,42 @@
let selectedCustomer = null;
let currentResults = [];
let currentQuery = "";
let activeIndex = -1;
let debounceTimer = null;
const selectedFields = new Set();
function appendHighlighted(target, text, query) {
const words = (query || "").toLowerCase().split(/\s+/).filter(Boolean);
if (words.length === 0) { target.appendChild(document.createTextNode(text)); return; }
const lowerText = text.toLowerCase();
const mask = new Array(text.length).fill(false);
for (const word of words) {
let fromIndex = 0;
let matchIndex;
while ((matchIndex = lowerText.indexOf(word, fromIndex)) !== -1) {
for (let i = matchIndex; i < matchIndex + word.length; i++) { mask[i] = true; }
fromIndex = matchIndex + 1;
}
}
let i = 0;
while (i < text.length) {
const highlighted = mask[i];
let j = i;
while (j < text.length && mask[j] === highlighted) { j++; }
const chunk = text.slice(i, j);
if (highlighted) {
const strong = document.createElement("strong");
strong.textContent = chunk;
target.appendChild(strong);
} else {
target.appendChild(document.createTextNode(chunk));
}
i = j;
}
}
function updateSubmitState() {
const subjectOk = subjectInput.value.trim().length >= 5;
@@ -46,9 +83,9 @@
item.innerHTML = "";
const numberSpan = document.createElement("span");
numberSpan.className = "cnum";
numberSpan.textContent = customer.number;
appendHighlighted(numberSpan, customer.number, currentQuery);
const nameSpan = document.createElement("span");
nameSpan.textContent = customer.name;
appendHighlighted(nameSpan, customer.name, currentQuery);
item.appendChild(numberSpan);
item.appendChild(nameSpan);
item.addEventListener("click", () => selectCustomer(customer));
@@ -60,8 +97,13 @@
}
async function runSearch(query) {
currentQuery = query;
try {
const response = await fetch("/api/customers?search=" + encodeURIComponent(query));
const params = new URLSearchParams({ search: query });
if (advancedToggle.checked && selectedFields.size > 0) {
params.set("fields", Array.from(selectedFields).join(","));
}
const response = await fetch("/api/customers?" + params.toString());
const payload = await response.json();
currentResults = payload.results;
activeIndex = currentResults.length > 0 ? 0 : -1;
@@ -123,6 +165,25 @@
if (!searchWrap.contains(event.target)) { closeSuggestions(); }
});
advancedToggle.addEventListener("change", () => {
advancedFields.hidden = !advancedToggle.checked;
if (!advancedToggle.checked) {
selectedFields.clear();
fieldToggleButtons.forEach((button) => button.setAttribute("aria-pressed", "false"));
}
if (currentQuery.length >= 2) { runSearch(currentQuery); }
});
fieldToggleButtons.forEach((button) => {
button.addEventListener("click", () => {
const field = button.dataset.field;
const isPressed = button.getAttribute("aria-pressed") === "true";
button.setAttribute("aria-pressed", String(!isPressed));
if (isPressed) { selectedFields.delete(field); } else { selectedFields.add(field); }
if (currentQuery.length >= 2) { runSearch(currentQuery); }
});
});
chipReset.addEventListener("click", resetCustomer);
subjectInput.addEventListener("input", updateSubmitState);