// Online-Terminbuchung – Buchungsseite (html/terminbuchung.html). // Liest den gewählten Termin aus der URL (berater, datum, zeit), füllt die // Zusammenfassung, verwaltet die Anamnese-Tags und prüft das Formular. // Zum Absenden wird wie auf der Kontaktseite das E-Mail-Programm geöffnet. // ----- Scroll-Reveal ----- (function () { const elements = document.querySelectorAll(".terminbuchung-seite .reveal"); if (!elements.length) return; const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; if (reduceMotion || !("IntersectionObserver" in window)) { elements.forEach(function (el) { el.classList.add("visible"); }); return; } const observer = new IntersectionObserver( function (entries) { entries.forEach(function (entry) { if (entry.isIntersecting) { entry.target.classList.add("visible"); observer.unobserve(entry.target); } }); }, { threshold: 0.12, rootMargin: "0px 0px -40px 0px" } ); elements.forEach(function (el) { observer.observe(el); }); })(); // ----- Termin-Zusammenfassung aus der URL ----- (function () { const params = new URLSearchParams(window.location.search); const beraterId = params.get("berater"); const datum = params.get("datum"); const zeit = params.get("zeit"); const elBerater = document.getElementById("tb-berater"); const elDatum = document.getElementById("tb-datum"); const elZeit = document.getElementById("tb-zeit"); const zusammenfassung = document.getElementById("termin-zusammenfassung"); if (!zusammenfassung) return; // Ohne Termin-Parameter (z. B. direkter Seitenaufruf): Hinweis statt Zusammenfassung. if (!beraterId || !datum || !zeit) { zusammenfassung.classList.add("tb-summary--fehlend"); zusammenfassung.innerHTML = `
Kein Termin ausgewählt

Du hast noch keinen Termin im Kalender gewählt. Gehe bitte zurück zur Startseite und öffne dort über einen Berater die Terminbuchung.

`; return; } // Datum lesbar formatieren, z. B. "Montag, 05.10.2026" const [jahr, monat, tag] = datum.split("-").map(Number); if (!jahr || !monat || !tag) return; const datumObjekt = new Date(jahr, monat - 1, tag); const formatiert = new Intl.DateTimeFormat("de-DE", { weekday: "long", day: "2-digit", month: "2-digit", year: "numeric" }).format(datumObjekt); elDatum.textContent = formatiert; elZeit.textContent = zeit.replace(":", ".") + " Uhr"; // Berater-Namen aus json/berater.json auflösen (ID stammt aus dem Kalender). fetch("../json/berater.json") .then(function (response) { if (!response.ok) throw new Error("HTTP " + response.status); return response.json(); }) .then(function (daten) { const treffer = (daten.berater || []).find(function (b) { return String(b.id) === String(beraterId); }); elBerater.textContent = treffer ? String(treffer.name).trim() : "Unbekannter Berater"; }) .catch(function () { elBerater.textContent = "Unbekannter Berater"; }); })(); // ----- Anamnese-Tags (Allergien & Unverträglichkeiten) ----- (function () { const input = document.getElementById("tag-input"); const addButton = document.getElementById("tag-add"); const liste = document.getElementById("tag-list"); if (!input || !addButton || !liste) return; const tags = []; const MAX_TAGS = 20; function tagHinzufuegen() { let wert = input.value.trim().replace(/^#+/, "").trim(); if (!wert) return; if (tags.length >= MAX_TAGS) { input.value = ""; return; } // Doppelte Einträge (groß/kleinschreibungsgleich) werden nicht aufgenommen. const existiert = tags.some(function (t) { return t.toLowerCase() === wert.toLowerCase(); }); if (!existiert) { tags.push(wert); } input.value = ""; zeichnen(); } function tagEntfernen(index) { tags.splice(index, 1); zeichnen(); } function zeichnen() { liste.innerHTML = ""; tags.forEach(function (wert, index) { const li = document.createElement("li"); li.className = "tb-tag"; const text = document.createElement("span"); text.textContent = wert; const entfernen = document.createElement("button"); entfernen.type = "button"; entfernen.setAttribute("aria-label", "Tag entfernen: " + wert); entfernen.innerHTML = "×"; entfernen.addEventListener("click", function () { tagEntfernen(index); }); li.appendChild(text); li.appendChild(entfernen); liste.appendChild(li); }); } addButton.addEventListener("click", tagHinzufuegen); input.addEventListener("keydown", function (event) { if (event.key === "Enter") { event.preventDefault(); tagHinzufuegen(); } }); // Für das E-Mail-Body: aktuelle Tag-Liste als Text. window.TerminbuchungTags = { holen: function () { return tags.slice(); }, leeren: function () { tags.length = 0; zeichnen(); } }; })(); // ----- Formularprüfung und Absenden ----- (function () { const form = document.getElementById("terminbuchung-formular"); if (!form) return; const EMAIL_TARGET = "info@trihub.de"; const bestaetigungDialog = document.getElementById("anfrage-bestaetigung"); const fields = { art: form.querySelector("[name='art']"), format: form.querySelector("[name='format']"), gespraech: form.querySelector("[name='gespraech']"), beschreibung: form.querySelector("[name='beschreibung']"), name: form.querySelector("[name='name']"), email: form.querySelector("[name='email']"), phone: form.querySelector("[name='phone']") }; const statusEl = document.getElementById("form-status"); const formularBereich = document.getElementById("formular"); const pruefBereich = document.getElementById("anfrage-pruefen"); const pruefDetails = document.getElementById("anfrage-pruefen-details"); const bearbeitenButton = document.getElementById("anfrage-bearbeiten"); const sendenLink = document.getElementById("anfrage-senden"); function wrap(el) { return el.closest(".field"); } function setFieldState(el, state) { const box = wrap(el); if (!box) return; box.classList.remove("has-error", "is-ok"); el.classList.remove("invalid", "valid"); if (state === "error") { box.classList.add("has-error"); el.classList.add("invalid"); } else if (state === "ok") { box.classList.add("is-ok"); el.classList.add("valid"); } } function validateName() { const ok = fields.name.value.trim().length > 0; setFieldState(fields.name, ok ? null : "error"); return ok; } function validateEmail() { const value = fields.email.value.trim(); const ok = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(value); setFieldState(fields.email, ok ? null : "error"); return ok; } function validateSelect(key) { const ok = fields[key].value !== ""; setFieldState(fields[key], ok ? null : "error"); return ok; } function allValid() { return ( fields.art.value !== "" && fields.format.value !== "" && fields.gespraech.value !== "" && fields.name.value.trim().length > 0 && /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(fields.email.value.trim()) ); } function updateSubmitState() { const submit = form.querySelector("[type='submit']"); if (submit) { submit.disabled = !allValid(); } } form.addEventListener("input", updateSubmitState); form.addEventListener("change", updateSubmitState); ["name", "email"].forEach(function (key) { fields[key].addEventListener("blur", function () { if (fields[key].value.trim() !== "" || form.dataset.touched === "true") { ({ name: validateName, email: validateEmail })[key](); } }); }); ["art", "format", "gespraech"].forEach(function (key) { fields[key].addEventListener("change", function () { validateSelect(key); }); }); // Termin-Angaben aus der URL für das E-Mail übernehmen. const params = new URLSearchParams(window.location.search); const datumRoh = params.get("datum") || ""; const zeitRoh = params.get("zeit") || ""; let terminText = "–"; if (datumRoh && zeitRoh) { const [jahr, monat, tag] = datumRoh.split("-").map(Number); if (jahr && monat && tag) { const formatiert = new Intl.DateTimeFormat("de-DE", { weekday: "long", day: "2-digit", month: "2-digit", year: "numeric" }).format(new Date(jahr, monat - 1, tag)); terminText = formatiert + " um " + zeitRoh.replace(":", ".") + " Uhr"; } } const elBerater = document.getElementById("tb-berater"); function labelVon(key) { const select = fields[key]; return select.options[select.selectedIndex].text; } function werteAnzeigen(werte) { pruefDetails.replaceChildren(); werte.forEach(function (eintrag) { const label = document.createElement("dt"); label.textContent = eintrag[0]; const wert = document.createElement("dd"); wert.textContent = eintrag[1] || "–"; pruefDetails.append(label, wert); }); } bearbeitenButton.addEventListener("click", function () { pruefBereich.hidden = true; formularBereich.hidden = false; formularBereich.scrollIntoView({ behavior: "smooth", block: "start" }); }); sendenLink.addEventListener("click", function (event) { event.preventDefault(); bestaetigungDialog.showModal(); window.location.href = sendenLink.href; }); form.addEventListener("submit", function (event) { event.preventDefault(); form.dataset.touched = "true"; const okArt = validateSelect("art"); const okFormat = validateSelect("format"); const okGespraech = validateSelect("gespraech"); const okName = validateName(); const okEmail = validateEmail(); if (!(okArt && okFormat && okGespraech && okName && okEmail)) { showStatus("error", "Bitte überprüfe die markierten Felder und versuche es erneut."); return; } const tagListe = window.TerminbuchungTags ? window.TerminbuchungTags.holen() : []; const beraterText = elBerater ? elBerater.textContent.trim() : "–"; const anfrageDaten = [ ["Berater/in", beraterText], ["Termin", terminText], ["Art der Ernährungsberatung", labelVon("art")], ["Beratungsformat", labelVon("format")], ["Gesprächsart", labelVon("gespraech")], ["Kurzbeschreibung", fields.beschreibung.value.trim() || "–"], ["Anamnese (Allergien & Unverträglichkeiten)", tagListe.length ? tagListe.join(", ") : "–"], ["Name", fields.name.value.trim()], ["E-Mail", fields.email.value.trim()], ["Telefon", fields.phone.value.trim() || "–"] ]; const body = [ "Terminanfrage – Trainingsplan & Beratung", "", "Termin: " + terminText, "Berater/in: " + beraterText, "Art der Ernährungsberatung: " + labelVon("art"), "Beratungsformat: " + labelVon("format"), "Gesprächsart: " + labelVon("gespraech"), "", "Kurzbeschreibung: " + (fields.beschreibung.value.trim() || "–"), "Anamnese (Allergien & Unverträglichkeiten): " + (tagListe.length ? tagListe.join(", ") : "–"), "", "Name: " + fields.name.value.trim(), "E-Mail: " + fields.email.value.trim(), "Telefon: " + (fields.phone.value.trim() || "–") ].join("\n"); werteAnzeigen(anfrageDaten); sendenLink.href = "mailto:" + EMAIL_TARGET + "?subject=" + encodeURIComponent("Terminanfrage: " + terminText) + "&body=" + encodeURIComponent(body); formularBereich.hidden = true; pruefBereich.hidden = false; pruefBereich.scrollIntoView({ behavior: "smooth", block: "start" }); }); function showStatus(kind, text) { if (!statusEl) return; statusEl.textContent = kind === "ok" ? "✓ " + text : "✗ " + text; statusEl.className = "form-status is-visible " + (kind === "ok" ? "form-status--ok" : "form-status--error"); } updateSubmitState(); })();