Fehler bei der Terminbuchung behoben
parent
af6c9511d7
commit
1620bf4f89
|
|
@ -86,7 +86,6 @@
|
|||
|
||||
/* Empfehlung kommt aus der JSON-Datei; die Auswahlklasse setzt leistungen.js beim Klick. */
|
||||
.pakete .paket-karte--empfohlen {
|
||||
border-color: 1px solid rgba(248, 250, 252, 0.08);
|
||||
box-shadow: 0 0 0 1px var(--accent-soft);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@
|
|||
position: relative;
|
||||
box-sizing: border-box;
|
||||
width: min(560px, 100%);
|
||||
/* Bei kleinen Fenstern bleibt der gesamte Dialog erreichbar. */
|
||||
max-height: calc(100dvh - 48px);
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
background-color: #111a1e;
|
||||
border: 2px solid rgb(255 255 255 / 9%);
|
||||
border-radius: 16px;
|
||||
|
|
@ -1145,4 +1149,4 @@
|
|||
.tb-overlay * {
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,66 +34,6 @@
|
|||
});
|
||||
})();
|
||||
|
||||
// ----- 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 = `
|
||||
<div class="tb-summary__item">
|
||||
<span class="tb-summary__label">Kein Termin ausgewählt</span>
|
||||
<p class="tb-summary__value" style="font-size: 0.95rem; font-weight: 400;">
|
||||
Du hast noch keinen Termin im Kalender gewählt.
|
||||
Gehe bitte zurück zur <a href="../index.html#berater">Startseite</a> und öffne dort über einen
|
||||
Berater die Terminbuchung.
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
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");
|
||||
|
|
@ -234,6 +174,7 @@
|
|||
|
||||
function allValid() {
|
||||
return (
|
||||
terminIstGueltig() &&
|
||||
fields.art.value !== "" &&
|
||||
fields.format.value !== "" &&
|
||||
fields.gespraech.value !== "" &&
|
||||
|
|
@ -266,25 +207,75 @@
|
|||
});
|
||||
});
|
||||
|
||||
// Termin-Angaben aus der URL für das E-Mail übernehmen.
|
||||
// Nur ein eingetragener, noch zukünftiger Termin darf angefragt werden.
|
||||
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 beraterId = params.get("berater");
|
||||
const datum = params.get("datum");
|
||||
const zeit = params.get("zeit");
|
||||
let termin = null;
|
||||
|
||||
function terminIstGueltig() {
|
||||
return termin !== null && termin.zeitpunkt > Date.now();
|
||||
}
|
||||
|
||||
const elBerater = document.getElementById("tb-berater");
|
||||
function terminFehlerAnzeigen(text) {
|
||||
termin = null;
|
||||
const zusammenfassung = document.getElementById("termin-zusammenfassung");
|
||||
zusammenfassung.classList.add("tb-summary--fehlend");
|
||||
zusammenfassung.innerHTML = `
|
||||
<div class="tb-summary__item">
|
||||
<span class="tb-summary__label">Bitte einen gültigen Termin wählen</span>
|
||||
<p class="tb-summary__value" style="font-size: 0.95rem; font-weight: 400;">
|
||||
Wähle auf der <a href="../index.html#berater">Startseite</a> einen Berater,
|
||||
einen verfügbaren Tag und eine Uhrzeit.
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
pruefBereich.hidden = true;
|
||||
formularBereich.hidden = false;
|
||||
sendenLink.removeAttribute("href");
|
||||
showStatus("error", text);
|
||||
updateSubmitState();
|
||||
}
|
||||
|
||||
async function terminLaden() {
|
||||
if (!beraterId || !datum || !zeit) {
|
||||
terminFehlerAnzeigen("Bitte wähle zuerst einen Termin im Kalender.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const [beraterDaten, terminDaten] = await Promise.all(
|
||||
["../json/berater.json", "../json/terminbuchung.json"].map(async function (url) {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error("HTTP " + response.status);
|
||||
return response.json();
|
||||
})
|
||||
);
|
||||
const berater = beraterDaten.berater.find(function (eintrag) {
|
||||
return String(eintrag.id) === beraterId;
|
||||
});
|
||||
const zeiten = terminDaten[beraterId]?.[datum];
|
||||
const zeitpunkt = new Date(`${datum}T${zeit}:00`).getTime();
|
||||
if (!berater || !Array.isArray(zeiten) || !zeiten.includes(zeit) || !(zeitpunkt > Date.now())) {
|
||||
terminFehlerAnzeigen("Dieser Termin ist nicht verfügbar oder bereits vergangen. Bitte wähle einen neuen Termin.");
|
||||
return;
|
||||
}
|
||||
const datumText = new Intl.DateTimeFormat("de-DE", {
|
||||
weekday: "long", day: "2-digit", month: "2-digit", year: "numeric"
|
||||
}).format(new Date(zeitpunkt));
|
||||
termin = {
|
||||
zeitpunkt,
|
||||
berater: String(berater.name).trim(),
|
||||
text: datumText + " um " + zeit.replace(":", ".") + " Uhr"
|
||||
};
|
||||
document.getElementById("tb-berater").textContent = termin.berater;
|
||||
document.getElementById("tb-datum").textContent = datumText;
|
||||
document.getElementById("tb-zeit").textContent = zeit.replace(":", ".") + " Uhr";
|
||||
updateSubmitState();
|
||||
} catch (error) {
|
||||
terminFehlerAnzeigen("Der Termin konnte nicht geprüft werden. Bitte lade die Seite erneut.");
|
||||
}
|
||||
}
|
||||
|
||||
function labelVon(key) {
|
||||
const select = fields[key];
|
||||
|
|
@ -310,6 +301,11 @@
|
|||
|
||||
sendenLink.addEventListener("click", function (event) {
|
||||
event.preventDefault();
|
||||
if (!terminIstGueltig()) {
|
||||
terminFehlerAnzeigen("Der Termin ist nicht mehr gültig. Bitte wähle einen neuen Termin.");
|
||||
formularBereich.scrollIntoView({ block: "start" });
|
||||
return;
|
||||
}
|
||||
bestaetigungDialog.showModal();
|
||||
window.location.href = sendenLink.href;
|
||||
});
|
||||
|
|
@ -317,6 +313,10 @@
|
|||
form.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
form.dataset.touched = "true";
|
||||
if (!terminIstGueltig()) {
|
||||
terminFehlerAnzeigen("Bitte wähle zuerst einen verfügbaren, zukünftigen Termin.");
|
||||
return;
|
||||
}
|
||||
|
||||
const okArt = validateSelect("art");
|
||||
const okFormat = validateSelect("format");
|
||||
|
|
@ -330,7 +330,8 @@
|
|||
}
|
||||
|
||||
const tagListe = window.TerminbuchungTags ? window.TerminbuchungTags.holen() : [];
|
||||
const beraterText = elBerater ? elBerater.textContent.trim() : "–";
|
||||
const beraterText = termin.berater;
|
||||
const terminText = termin.text;
|
||||
const anfrageDaten = [
|
||||
["Berater/in", beraterText],
|
||||
["Termin", terminText],
|
||||
|
|
@ -379,4 +380,5 @@
|
|||
}
|
||||
|
||||
updateSubmitState();
|
||||
terminLaden();
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -77,18 +77,17 @@
|
|||
const tabelle = terminDaten[String(beraterId)];
|
||||
if (!tabelle || typeof tabelle !== "object") return [];
|
||||
const zeiten = tabelle[schluessel];
|
||||
return Array.isArray(zeiten) ? zeiten : [];
|
||||
// Auch bereits vergangene Uhrzeiten am heutigen Tag ausblenden.
|
||||
return Array.isArray(zeiten)
|
||||
? zeiten.filter((zeit) => new Date(`${schluessel}T${zeit}:00`).getTime() > Date.now())
|
||||
: [];
|
||||
}
|
||||
|
||||
function hatFreieTermine(beraterId) {
|
||||
const tabelle = terminDaten[String(beraterId)];
|
||||
if (!tabelle || typeof tabelle !== "object") return false;
|
||||
|
||||
return Object.entries(tabelle).some(([schluessel, zeiten]) => {
|
||||
const datum = /^(\d{4})-(\d{2})-(\d{2})$/.exec(schluessel);
|
||||
if (!datum || !Array.isArray(zeiten) || zeiten.length === 0) return false;
|
||||
return !istVergangen(Number(datum[1]), Number(datum[2]) - 1, Number(datum[3]));
|
||||
});
|
||||
return Object.keys(tabelle).some((schluessel) => zeitenFuer(beraterId, schluessel).length > 0);
|
||||
}
|
||||
|
||||
function istVerfuegbar(jahr, monat, tag) {
|
||||
|
|
@ -181,7 +180,32 @@
|
|||
if (event.target === overlay) schliessen();
|
||||
});
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (istGeoeffnet && event.key === "Escape") schliessen();
|
||||
if (!istGeoeffnet) return;
|
||||
if (event.key === "Escape") {
|
||||
event.preventDefault();
|
||||
schliessen();
|
||||
return;
|
||||
}
|
||||
if (event.key !== "Tab") return;
|
||||
|
||||
// Tab und Shift+Tab bleiben zwischen den sichtbaren Dialog-Buttons.
|
||||
const buttons = [...overlay.querySelectorAll("button:not(:disabled)")]
|
||||
.filter((button) => button.getClientRects().length > 0);
|
||||
const erster = buttons[0];
|
||||
const letzter = buttons[buttons.length - 1];
|
||||
const fokus = document.activeElement;
|
||||
if (!overlay.contains(fokus) || (event.shiftKey && fokus === erster)) {
|
||||
event.preventDefault();
|
||||
(event.shiftKey ? letzter : erster).focus();
|
||||
} else if (!event.shiftKey && fokus === letzter) {
|
||||
event.preventDefault();
|
||||
erster.focus();
|
||||
}
|
||||
});
|
||||
document.addEventListener("focusin", (event) => {
|
||||
if (istGeoeffnet && !overlay.contains(event.target)) {
|
||||
overlay.querySelector(".tb-close").focus();
|
||||
}
|
||||
});
|
||||
|
||||
// Buchen
|
||||
|
|
@ -273,9 +297,14 @@
|
|||
kalenderZeichnen();
|
||||
zeitenZeichnen();
|
||||
buchButtonAktualisieren();
|
||||
overlay.querySelector(".tb-day--ausgewaehlt")?.focus();
|
||||
}
|
||||
|
||||
function zeitKlicken(zeit) {
|
||||
if (!zeitenFuer(zustand.beraterId, zustand.datum).includes(zeit)) {
|
||||
auswahlAktualisieren();
|
||||
return;
|
||||
}
|
||||
zustand.zeit = zeit;
|
||||
overlay.querySelectorAll(".tb-time-chip").forEach((chip) => {
|
||||
chip.classList.toggle("is-active", chip.dataset.zeit === zeit);
|
||||
|
|
@ -285,6 +314,11 @@
|
|||
|
||||
function buchen() {
|
||||
if (!zustand.datum || !zustand.zeit || zustand.beraterId == null) return;
|
||||
// Die Seite kann seit der Auswahl offen geblieben sein.
|
||||
if (!zeitenFuer(zustand.beraterId, zustand.datum).includes(zustand.zeit)) {
|
||||
auswahlAktualisieren();
|
||||
return;
|
||||
}
|
||||
const ziel =
|
||||
ZIELSEITE +
|
||||
"?berater=" + encodeURIComponent(zustand.beraterId) +
|
||||
|
|
@ -293,6 +327,15 @@
|
|||
window.location.href = ziel;
|
||||
}
|
||||
|
||||
function auswahlAktualisieren() {
|
||||
zustand.zeit = null;
|
||||
kalenderZeichnen();
|
||||
zeitenZeichnen();
|
||||
legendeAktualisieren();
|
||||
buchButtonAktualisieren();
|
||||
overlay.querySelector(".tb-close").focus();
|
||||
}
|
||||
|
||||
// ----- Zeichnen -----
|
||||
|
||||
function kalenderZeichnen() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue