trihub-ernaehrung-backseatDevs/src/features/contact/contact-dialog.js

127 lines
5.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { findAdvisor } 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">Berater kontaktieren</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>
<p class="contact-status" role="status" aria-live="polite"></p>
<button class="contact-submit" type="submit" disabled>Anfrage senden & Termin wählen</button>
</form>`;
dialog.querySelector(".contact-advisor").textContent = advisor
? `Deine Anfrage an ${advisor.name}`
: "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.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,
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;
}