134 lines
5.8 KiB
JavaScript
134 lines
5.8 KiB
JavaScript
import { findAdvisor, advisorDisplayName } from "../../shared/berater.js";
|
||
import {
|
||
contactReasons,
|
||
contactNotice,
|
||
contactBookingUrl,
|
||
} from "../../shared/contact.js";
|
||
import "./contact.css";
|
||
|
||
// Auf Profilseiten: openContactDialog({ advisorId: profile.id }).
|
||
export function openContactDialog({
|
||
advisorId,
|
||
navigate = (url) => window.location.assign(url),
|
||
} = {}) {
|
||
const advisor = findAdvisor(advisorId);
|
||
const returnFocus = document.activeElement;
|
||
const dialog = document.createElement("dialog");
|
||
dialog.className = "contact-dialog";
|
||
dialog.setAttribute("aria-labelledby", "contact-title");
|
||
dialog.innerHTML = `
|
||
<button class="contact-close" type="button" aria-label="Kontaktfenster schließen">×</button>
|
||
<p class="contact-eyebrow">DEIN NÄCHSTER SCHRITT</p>
|
||
<h2 id="contact-title"></h2>
|
||
<p class="contact-advisor"></p>
|
||
<form class="contact-form">
|
||
<div><label for="contact-email">Deine Buchungs-E-Mail</label>
|
||
<input id="contact-email" name="email" type="email" autocomplete="email" maxlength="254" required aria-describedby="contact-email-help">
|
||
<p id="contact-email-help" class="contact-help">Verwende die E-Mail-Adresse, mit der du dein Paket gebucht hast.</p>
|
||
</div>
|
||
<div><label for="contact-reason">Grund für den Kontakt</label>
|
||
<select id="contact-reason" name="reason" required><option value="">Bitte auswählen</option></select>
|
||
</div>
|
||
<label class="contact-consent"><input name="simulationAccepted" type="checkbox" required><span></span></label>
|
||
<label class="contact-consent"><input name="consent" type="checkbox" required><span>Ich akzeptiere die <a href="https://www.tri-hub.de/datenschutz" target="_blank" rel="noopener noreferrer">Datenschutzbestimmungen</a> (Pflichtfeld).</span></label>
|
||
<p class="contact-status" role="status" aria-live="polite"></p>
|
||
<button class="contact-submit" type="submit" disabled>Anfrage senden & Termin wählen</button>
|
||
</form>`;
|
||
const advisorName = advisorDisplayName(advisor);
|
||
dialog.querySelector("#contact-title").textContent = advisorName
|
||
? `${advisorName} kontaktieren`
|
||
: "Berater nicht gefunden";
|
||
dialog.querySelector(".contact-advisor").textContent = advisor
|
||
? "Sende deine Kontaktanfrage."
|
||
: "Die Berater-ID fehlt oder ist unbekannt. Bitte öffne das Fenster über ein Beraterprofil.";
|
||
dialog.querySelector(".contact-consent span").textContent = contactNotice;
|
||
const form = dialog.querySelector("form");
|
||
const email = form.elements.email;
|
||
const reason = form.elements.reason;
|
||
for (const [value, label] of Object.entries(contactReasons)) {
|
||
reason.add(new Option(label, value));
|
||
}
|
||
const status = dialog.querySelector(".contact-status");
|
||
const submit = dialog.querySelector(".contact-submit");
|
||
const close = dialog.querySelector(".contact-close");
|
||
let busy = false;
|
||
let sent = false;
|
||
function update() {
|
||
submit.disabled = busy || sent || !advisor;
|
||
close.disabled = busy;
|
||
email.disabled = busy || sent;
|
||
reason.disabled = busy || sent;
|
||
form.elements.consent.disabled = busy || sent;
|
||
form.elements.simulationAccepted.disabled = busy || sent;
|
||
}
|
||
async function post(path, input) {
|
||
const response = await fetch(path, {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(input),
|
||
});
|
||
const result = await response.json();
|
||
if (!response.ok)
|
||
throw new Error(
|
||
result.error?.message || "Die Anfrage ist fehlgeschlagen.",
|
||
);
|
||
return result;
|
||
}
|
||
email.addEventListener("input", () => {
|
||
status.textContent = "";
|
||
});
|
||
form.addEventListener("submit", async (event) => {
|
||
event.preventDefault();
|
||
if (submit.disabled || !form.reportValidity()) return;
|
||
const input = {
|
||
email: email.value,
|
||
advisorId,
|
||
reason: reason.value,
|
||
consent: form.elements.consent.checked,
|
||
simulationAccepted: form.elements.simulationAccepted.checked,
|
||
};
|
||
busy = true;
|
||
update();
|
||
status.textContent =
|
||
"E-Mail wird geprüft und simulierte Anfrage gesendet …";
|
||
try {
|
||
const result = await post("/api/contact", input);
|
||
if (result.redirectUrl !== contactBookingUrl)
|
||
throw new Error("Die Weiterleitungsadresse ist ungültig.");
|
||
sent = true;
|
||
status.textContent =
|
||
"Beide Bestätigungen wurden in Mailpit angenommen. Microsoft Bookings wird geöffnet. ";
|
||
const link = document.createElement("a");
|
||
link.href = contactBookingUrl;
|
||
link.textContent = "Weiter zur Terminwahl";
|
||
status.append(link);
|
||
navigate(contactBookingUrl);
|
||
} catch (error) {
|
||
status.textContent = `${error.message} Bei einem Verbindungsfehler bitte vor erneutem Senden Mailpit prüfen.`;
|
||
} finally {
|
||
busy = false;
|
||
update();
|
||
}
|
||
});
|
||
close.addEventListener("click", () => dialog.close());
|
||
dialog.addEventListener("cancel", (event) => {
|
||
if (busy) event.preventDefault();
|
||
});
|
||
const previousOverflow = document.body.style.overflow;
|
||
dialog.addEventListener(
|
||
"close",
|
||
() => {
|
||
document.body.style.overflow = previousOverflow;
|
||
dialog.remove();
|
||
returnFocus?.focus();
|
||
},
|
||
{ once: true },
|
||
);
|
||
document.body.append(dialog);
|
||
document.body.style.overflow = "hidden";
|
||
update();
|
||
dialog.showModal();
|
||
email.focus();
|
||
return dialog;
|
||
}
|