Phase 4: wire demo lead forms to live n8n webhook

- demo-tier-a / demo-tier-b: forms POST JSON to /webhook/lead-intake
  (hidden client_id + source, named fields), async submit with
  success/error toast.
- lead-intake webhook: enable CORS (allowedOrigins=*) so the static
  demos (different origin) can submit; re-export n8n/lead-intake.json.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-24 14:48:56 +02:00
parent 1e6c46e9f0
commit 4b7e201b91
3 changed files with 77 additions and 13 deletions
+37 -6
View File
@@ -279,14 +279,16 @@
<h2>Rezept einreichen oder Frage stellen</h2>
<p>Schreiben Sie uns — wir melden uns zeitnah und vertraulich zurück.</p>
</div>
<!-- Tier B: in der Live-Version postet dies an einen self-hosted Endpoint -> n8n -> CRM (kein Drittanbieter). -->
<form class="lead" onsubmit="event.preventDefault(); this.querySelector('.toast').style.display='block'; this.reset();">
<div class="field"><label for="b-name">Name</label><input id="b-name" type="text" placeholder="Maria Musterfrau" required /></div>
<div class="field"><label for="b-contact">E-Mail oder Telefon</label><input id="b-contact" type="text" placeholder="maria@example.de" required /></div>
<!-- Tier B: dieses Formular postet an einen n8n-Webhook -> CRM (Leads) + Telegram. -->
<form class="lead" onsubmit="return submitLead(event, this)">
<input type="hidden" name="client_id" value="DEMO-B" />
<input type="hidden" name="source" value="demo-tier-b" />
<div class="field"><label for="b-name">Name</label><input id="b-name" name="name" type="text" placeholder="Maria Musterfrau" required /></div>
<div class="field"><label for="b-contact">E-Mail oder Telefon</label><input id="b-contact" name="contact" type="text" placeholder="maria@example.de" required /></div>
<div class="field"><label for="b-svc">Anliegen</label>
<select id="b-svc"><option>Neuer Termin</option><option>Rezept einreichen</option><option>Manuelle Therapie</option><option>Krankengymnastik</option><option>Sonstiges</option></select>
<select id="b-svc" name="service"><option>Neuer Termin</option><option>Rezept einreichen</option><option>Manuelle Therapie</option><option>Krankengymnastik</option><option>Sonstiges</option></select>
</div>
<div class="field"><label for="b-msg">Nachricht</label><textarea id="b-msg" rows="3" placeholder="Ihr Anliegen, Wunschtermin, Diagnose laut Rezept …"></textarea></div>
<div class="field"><label for="b-msg">Nachricht</label><textarea id="b-msg" name="message" rows="3" placeholder="Ihr Anliegen, Wunschtermin, Diagnose laut Rezept …"></textarea></div>
<div class="field consent"><input type="checkbox" id="b-consent" style="width:auto;margin-top:4px;" required /><label for="b-consent" style="margin:0;">Ich willige ein, dass meine Angaben zur Bearbeitung meiner Anfrage verarbeitet werden. Die Daten werden verschlüsselt in Deutschland gespeichert.</label></div>
<button class="btn" type="submit">Anfrage sicher senden</button>
<div class="toast">✓ Danke! Demo-Formular — in der Live-Version landet Ihre Anfrage verschlüsselt im Praxis-CRM.</div>
@@ -319,5 +321,34 @@
<div class="chat-input"><input type="text" placeholder="Nachricht schreiben …" /><button aria-label="Senden"></button></div>
<div class="chat-foot">Demo — in der Live-Version KI-gestützt (Claude)</div>
</div>
<script>
// Lead-Formular -> n8n Webhook -> CRM (Leads) + Telegram-Benachrichtigung.
const LEAD_WEBHOOK = 'https://n8n.mivanchenko.de/webhook/lead-intake';
async function submitLead(e, form) {
e.preventDefault();
const btn = form.querySelector('button[type=submit]');
const toast = form.querySelector('.toast');
const data = Object.fromEntries(new FormData(form).entries());
const old = btn.textContent;
btn.disabled = true; btn.textContent = 'Senden…';
try {
const r = await fetch(LEAD_WEBHOOK, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
if (!r.ok) throw new Error(r.status);
toast.textContent = '✓ Danke! Ihre Anfrage ist eingegangen — wir melden uns.';
toast.style.display = 'block';
form.reset();
} catch (err) {
toast.textContent = '⚠ Senden fehlgeschlagen — bitte erneut versuchen oder direkt anrufen.';
toast.style.display = 'block';
} finally {
btn.disabled = false; btn.textContent = old;
}
return false;
}
</script>
</body>
</html>